
/************************************************************************/
/*                                                                      */
/* This file contains code for most of the commands.			*/
/*                                                                      */
/************************************************************************/

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#include "general.h"
#include "globals.h"
#include "intui.h"
#include "spl_math.h"
#include "spl_util.h"
#include "spl_gfx.h"
#include "file.h"
#include "add.h"
#include "move.h"
#include "scale_g.h"
#include "rotate_g.h"
#include "knotinfo.h"
#include "ttddd.h"
#include "commands.h"


static char Current_Object_FileName[File_Name_Length+1] = { '\0' };
static char Current_Object_DirName[Path_Name_Length+1] = { '\0' };

static char Current_TTDDD_FileName[File_Name_Length+1] = { '\0' };
static char Current_TTDDD_DirName[Path_Name_Length+1] = { '\0' };

static char Current_Config_FileName[File_Name_Length+1] = { '\0' };
static char Current_Config_DirName[Path_Name_Length+1] = { '-' };

void Command_Pan_Up()
/************************************************************************/
/*                                                                      */
/* Pan upwards in the current view.					*/
/*                                                                      */
/************************************************************************/
{
    Move_Offset(0, Select_View_Id);
    Compute_Splines();
    Redraw_Mask |= What_All;

} /* Command_Pan_Up */

void Command_Pan_Down()
/************************************************************************/
/*                                                                      */
/* Pan downwards in the current view.					*/
/*                                                                      */
/************************************************************************/
{
    Move_Offset(1, Select_View_Id);
    Compute_Splines();
    Redraw_Mask |= What_All;

} /* Command_Pan_Down */

void Command_Pan_Right()
/************************************************************************/
/*                                                                      */
/* Pan to the right in the current view.				*/
/*                                                                      */
/************************************************************************/
{
    Move_Offset(2, Select_View_Id);
    Compute_Splines();
    Redraw_Mask |= What_All;

} /* Command_Pan_Right */

void Command_Pan_Left()
/************************************************************************/
/*                                                                      */
/* Pan to the left in the current view.					*/		
/*                                                                      */
/************************************************************************/
{
    Move_Offset(3, Select_View_Id);
    Compute_Splines();
    Redraw_Mask |= What_All;

} /* Command_Pan_Left */

void Command_Add()
/************************************************************************/
/*                                                                      */
/* Enter add mode.							*/
/*                                                                      */
/************************************************************************/
{
    Set_Mode_Add();

} /* Command_Add */

void Command_Scale_Group()
/************************************************************************/
/*                                                                      */
/* Show scale group window.						*/
/*                                                                      */
/************************************************************************/
{
    if (Windows[(int)W_Scale_Group].Window == NULL) 
					Window_Open(W_Scale_Group);
    WindowToFront(Windows[W_Scale_Group].Window);

} /* Command_Scale_Group */

void Command_Rotate_Group()
/************************************************************************/
/*                                                                      */
/* Show rotate group window.						*/
/*                                                                      */
/************************************************************************/
{
    if (Windows[(int)W_Rotate_Group].Window == NULL) 
					Window_Open(W_Rotate_Group);
    WindowToFront(Windows[W_Rotate_Group].Window);

} /* Command_Rotate_Group */

void Command_Move_Group()
/************************************************************************/
/*                                                                      */
/* Show move group window.						*/
/*                                                                      */
/************************************************************************/
{
    if (Windows[(int)W_Move_Group].Window == NULL) 
					Window_Open(W_Move_Group);
    WindowToFront(Windows[W_Move_Group].Window);

    if (Select_Point_Id >= 0) 
	Set_Move_Group_Position(Points[Select_Point_Id].Pos);

} /* Command_Move_Group */

void Command_Connect()
/************************************************************************/
/*                                                                      */
/* Try to connect the selected spline to another spline near it.	*/
/* If ok, then enable menu, and return to normal mode.			*/
/*                                                                      */
/************************************************************************/
{
    if (Select_View_Id < 0 || 
	Select_Spline == NULL || Select_Knot == NULL) return;

    if (Splines_Connect(Select_View_Id, Select_Spline, Select_Knot)) {

        Mark_Connected_Segments(Select_Point_Id);
        Draw_Marked_Segments(DM_Erase, What_All); 
        Compute_Marked_Segments();
        Draw_Marked_Segments(DM_Normal, What_All); 

	Set_RMBTrap(FALSE);	/* Enable menu again */

        Set_Mode_Normal();
        Set_Window_Title(NULL);

    } /* if */

} /* Command_Connect */

void Command_Combine()
/************************************************************************/
/*                                                                      */
/* Try to combine the selected spline with another spline near it.	*/
/*                                                                      */
/************************************************************************/
{
    if (Select_View_Id < 0 || 
	Select_Spline == NULL || Select_Knot == NULL) return;

    if (Splines_Combine(Select_View_Id, Select_Spline, Select_Knot)) {

        Mark_Connected_Segments(Select_Point_Id);
        Draw_Marked_Segments(DM_Erase, What_All); 
        Compute_Marked_Segments();
        Deselect_All();

        Set_Window_Title(NULL);
        Draw_Marked_Segments(DM_Normal, What_All); 

    } /* if */

} /* Command_Combine */

void Command_Delete_Point()
/************************************************************************/
/*                                                                      */
/* Delete all knots which references the selected point			*/
/*                                                                      */
/************************************************************************/
{
    Spline_T 	*Spline, *Next_Spline;
    Knot_T	*Knot;
    short	Point_Id;
    int		i;

    if (Select_Point_Id < 0) return;

    Point_Id = Select_Point_Id;

    if (!Group_Mode) Deselect_All();

    for (Spline = Splines; Spline != NULL; Spline = Next_Spline) {

	/* Get next spline now as 'Spline' may be deleted below.	*/
	Next_Spline = Spline->Next;

	for (i = 0, Knot = Spline->First; i < Spline->Nbr_Knots;
						i++, Knot = Knot->Next) {

	    if (Knot->Point_Id != Point_Id) continue;

		/* We've found a knot which references the point to be	*/
		/* deleted.						*/

	    i = Spline->Nbr_Knots; /* Stop inner loop */

		/* Undraw the spline, it will be modified */
            if (!Group_Mode) Draw_Spline(Spline, DM_Erase, What_All);

            if (Spline->Nbr_Knots < 3) Spline_Free(Spline);
            else {

		Knot_Delete(Spline, Knot);

		/* Recompute, and draw the modified spline again */
    		if (!Group_Mode) {
		    Compute_Spline(Spline);
    		    Draw_Spline(Spline, DM_Normal, What_All);
 		} /* if */

    	    } /* if .. else .. */


	} /* for */

    } /* for */

    if (!Group_Mode) {

    	Set_Move_Group_Position(Current_Pos);
    	KnotInfo_Show_Info(Select_Spline, Select_Knot);
    	Set_Window_Title(NULL);

    } /* if */
	
} /* Command_Delete_Point */

void Command_Delete()
/************************************************************************/
/*                                                                      */
/* Delete all knots which references the selected point, or if in group	*/
/* mode: Delete all selected points					*/
/*                                                                      */
/************************************************************************/
{
    short	Point_Id;

    if (!Group_Mode) {
	Command_Delete_Point();
	return;
    }

    Set_Window_Title("Deleting points");

    for (Point_Id = 0; Point_Id < Max_Nbr_Points; Point_Id++) {

	if (Is_Selected(Points[Point_Id])) {

	    Select_Point_Id = Point_Id;
	    Command_Delete_Point();

        } /* if */

    } /* for */

    Deselect_All();
    Compute_Splines();

    Set_Move_Group_Position(Current_Pos);
    KnotInfo_Show_Info(Select_Spline, Select_Knot);
    Set_Window_Title(NULL);

    Redraw_Mask = What_All;

} /* Command_Delete */

void Command_Cut()
/************************************************************************/
/*                                                                      */
/* Cut the selected spline at the selected knot.			*/
/*                                                                      */
/************************************************************************/
{
    Spline_T *Spline;
    Spline_T *New_Spline;
    Knot_T   *Knot;

    if (Select_Spline == NULL || Select_Knot == NULL) return;

    Spline = Select_Spline;
    Knot   = Select_Knot;
    Deselect_All();

	/* Undraw the spline, it will be modified */
    Draw_Spline(Spline, DM_Erase, What_All);

    New_Spline = Spline_Cut(Spline, Knot);

    Compute_Spline(Spline);
    Draw_Spline(Spline, DM_Normal, What_All);

    if (New_Spline != NULL && New_Spline != Spline) {
        Compute_Spline(New_Spline);
    	Draw_Spline(New_Spline, DM_Normal, What_All);
    }

    Set_Move_Group_Position(Current_Pos);
    KnotInfo_Show_Info(Select_Spline, Select_Knot);
    Set_Window_Title(NULL);
	
} /* Command_Cut */

void Command_Disconnect()
/************************************************************************/
/*                                                                      */
/* Disconnect two splines.						*/
/*                                                                      */
/************************************************************************/
{
    if (Select_Point_Id < 0) return;

    Splines_Disconnect(Select_Point_Id);
    Set_Window_Title(NULL);
    Redraw_Mask |= What_All;

} /* Command_Disconnect */

void Command_Hide()
/************************************************************************/
/*                                                                      */
/* If points are hidden, then show all points and select the previously	*/
/* visible points.							*/
/* If none were hidden, then hide unselected points and deselect all.	*/
/*                                                                      */
/************************************************************************/
{
    if (Points_Hidden) {
	Show_All_Points();
        Compute_Splines();
    } else Hide_Unselected_Points();
    Set_Window_Title(NULL);
    Redraw_Mask |= What_All;

} /* Command_Hide */

void Command_Show()
/************************************************************************/
/*                                                                      */
/* Show all hidden points again.					*/
/*                                                                      */
/************************************************************************/
{
    Show_All_Points();
    Compute_Splines();
    Set_Window_Title(NULL);
    Redraw_Mask |= What_All;

} /* Command_Show */

void Command_Loop()
/************************************************************************/
/*                                                                      */
/* 'Loop' or 'unloop'the current spline.				*/
/*                                                                      */
/************************************************************************/
{
    if (Select_Spline == NULL) return;

	/* Erase the spline, it will be modified	*/
    Draw_Spline(Select_Spline, DM_Erase, What_All);

    Spline_Loop(Select_Spline, !Select_Spline->Loop);
	
	/* Compute the loop segment if necessary	*/
    if (Select_Spline->Loop)
        Compute_Segment(Select_Spline, Select_Spline->Last);

	/* Draw the modified spline	*/
    Draw_Spline(Select_Spline, DM_Normal, What_All);

} /* Command_Loop */


void Command_Select_Next()
/************************************************************************/
/*                                                                      */
/* Select next knot on this point.					*/
/*                                                                      */
/************************************************************************/
{
    Select_Next_Knot();	/* Select next knot at current point */

		/* Draw marked segments in normal color */
    Draw_Marked_Segments(DM_Normal, What_All); 

		/* Mark new selection, and draw it	*/
    Mark_Selected_Segments();
    Draw_Marked_Segments(DM_Normal, What_All);

    KnotInfo_Show_Info(Select_Spline, Select_Knot);
    Set_Window_Title(NULL);

} /* Command_Select_Next */

void Command_Toggle_Select_All()
/************************************************************************/
/*                                                                      */
/* Toggle selection of all visible points.				*/
/*                                                                      */
/************************************************************************/
{
    Toggle_Select_All();

    Draw_All(What_K); 

    KnotInfo_Show_Info(Select_Spline, Select_Knot);
    Set_Window_Title(NULL);

} /* Command_Toggle_Select_All */

void Command_Toggle_Select_Spline()
/************************************************************************/
/*                                                                      */
/* Toggle selection of all visible points.				*/
/*                                                                      */
/************************************************************************/
{
    if (Select_Spline == NULL) return;

    Toggle_Select_Spline(Select_Spline);

    Draw_Spline(Select_Spline, DM_Normal, What_K); 

    KnotInfo_Show_Info(Select_Spline, Select_Knot);
    Set_Window_Title(NULL);

} /* Command_Toggle_Select_Spline */

void Command_Resolution_Down()
/************************************************************************/
/*                                                                      */
/* Change to lower resolution.						*/
/*                                                                      */
/************************************************************************/
{
    if (Spline_Resolution <= 1) return;

    Spline_Resolution--;
    sprintf(Error_Msg, "New resolution: %d", Spline_Resolution);
    Display_Status(Error_Msg);
    Compute_Splines();
    Redraw_Mask |= What_All;

} /* Command_Resolution_Down */

void Command_Resolution_Up()
/************************************************************************/
/*                                                                      */
/* Change to higher resolution.						*/
/*                                                                      */
/************************************************************************/
{
    if (Spline_Resolution >= Max_Spline_Resolution) return;

    Spline_Resolution++;
    sprintf(Error_Msg, "New resolution: %d", Spline_Resolution);
    Display_Status(Error_Msg);

    Compute_Splines();
    Redraw_Mask |= What_All;

} /* Command_Resolution_Up */

void Command_Deselect_All()
/************************************************************************/
/*                                                                      */
/* Deselect all.							*/
/*                                                                      */
/************************************************************************/
{
    Deselect_All();
    Draw_Marked_Segments(DM_Normal, What_All); 
    Set_Window_Title(NULL);
    Redraw_Mask |= What_K;

} /* Command_Deselect_All */

void Command_Redraw()
/************************************************************************/
/*                                                                      */
/* Redraw all.								*/
/*                                                                      */
/************************************************************************/
{
    Redraw_Mask |= What_All;

} /* Command_Redraw */


void Command_Unexpand()
/************************************************************************/
/*                                                                      */
/* Close big (expanded view) window.					*/
/*                                                                      */
/************************************************************************/
{
    if (Windows[(int)W_ExpandedView].Window == NULL) return;

    Window_Close(W_ExpandedView);

    Id_Active_Window = W_Main;
    Views            = Views_Small;
    What_Mask        = What_All;

    Set_Window_Title(NULL);	/* Reset title */

    Compute_Splines();
    Redraw_Mask |= What_All;

} /* Command_Unexpand */

void Command_X_Expand()
/************************************************************************/
/*                                                                      */
/* Open expanded X window.						*/
/*                                                                      */
/************************************************************************/
{
    if (Windows[W_ExpandedView].Window == NULL) Window_Open(W_ExpandedView);
    else WindowToFront(Windows[W_ExpandedView].Window);

    Id_Active_Window = W_ExpandedView;
    Views            = Views_Big;
    What_Mask        = What_X;

    Set_Window_Title("ICoons    Expanded view: X");

    Compute_Splines();
    Redraw_Mask |= What_All;

} /* Command_X_Expand */

void Command_Y_Expand()
/************************************************************************/
/*                                                                      */
/* Open expanded Y window.						*/
/*                                                                      */
/************************************************************************/
{
    if (Windows[W_ExpandedView].Window == NULL) Window_Open(W_ExpandedView);
    else WindowToFront(Windows[W_ExpandedView].Window);

    Id_Active_Window = W_ExpandedView;
    Views     	     = Views_Big;
    What_Mask 	     = What_Y;

    Set_Window_Title("ICoons    Expanded view: Y");

    Compute_Splines();
    Redraw_Mask |= What_All;

} /* Command_Y_Expand */

void Command_Z_Expand()
/************************************************************************/
/*                                                                      */
/* Open expanded Z window.						*/
/*                                                                      */
/************************************************************************/
{
    if (Windows[W_ExpandedView].Window == NULL) Window_Open(W_ExpandedView);
    else WindowToFront(Windows[W_ExpandedView].Window);

    Id_Active_Window = W_ExpandedView;
    Views            = Views_Big;
    What_Mask        = What_Z;

    Set_Window_Title("ICoons    Expanded view: Z");

    Compute_Splines();
    Redraw_Mask |= What_All;

} /* Command_Z_Expand */

void Command_Persp_Expand()
/************************************************************************/
/*                                                                      */
/* Open expanded perspective window.					*/
/*                                                                      */
/************************************************************************/
{
    if (Windows[W_ExpandedView].Window == NULL) Window_Open(W_ExpandedView);
    else WindowToFront(Windows[W_ExpandedView].Window);

    Id_Active_Window = W_ExpandedView;
    Views     	     = Views_Big;
    What_Mask        = What_P;

    Set_Window_Title("ICoons    Expanded view: Perspective");

    Compute_Splines();
    Redraw_Mask |= What_All;

} /* Command_Persp_Expand */


void Command_About()
/************************************************************************/
/*                                                                      */
/* Show 'about' requester.						*/
/*                                                                      */
/************************************************************************/
{
    char 	Buffer[1000];
    Spline_T	*Spline;
    int		i, Nbr_Points, Nbr_Splines, Nbr_Knots;
    int		Total_Nbr_Knots;

    Nbr_Points = Nbr_Splines = Nbr_Knots = Total_Nbr_Knots = 0;

    for (i = 0; i < Max_Nbr_Points; i++) 
	if (Points[i].Reference_Count > 0) Nbr_Points++;
  
    Spline = Splines;
    while (Spline != NULL) {
	Nbr_Splines++;
	Total_Nbr_Knots += Spline->Nbr_Knots;
	if (Nbr_Knots < Spline->Nbr_Knots) Nbr_Knots = Spline->Nbr_Knots;
	Spline = Spline->Next;
    }

    sprintf(Buffer, 
        "\n"
        "            ICoons v. 1.0            \n"
        "\n"
        "        by Helge E. Rasmussen\n"
        "           her@compel.dk\n"
	"\n"
        "           Statistics:\n"
	"        Points   : %d of %d\n"
	"        Splines  : %d\n"
	"        Knots    : %d\n"
	"        Longest K: %d",
	Nbr_Points, Max_Nbr_Points,
	Nbr_Splines,
	Total_Nbr_Knots,
	Nbr_Knots);

    Display_Message(Buffer);

} /* Command_About */

void Command_New()
/************************************************************************/
/*                                                                      */
/* Delete current object and start a new one.				*/
/*                                                                      */
/************************************************************************/
{
    int Answer;

    Answer = Ask_Question("Start on new object?", "Yes|No");

    if (Answer == 1) {

        Splines_Init();
        Compute_Splines();
        Set_Window_Title(NULL);
        Redraw_Mask |= What_All;

    } /* if */

} /* Command_New */

void Command_Load_Object()
/************************************************************************/
/*                                                                      */
/* Load an object from disk.						*/
/*                                                                      */
/************************************************************************/
{
    struct FileRequester *Requester;
    char   Path[Buffer_Length+1];


    Requester = AllocAslRequestTags(ASL_FileRequest,
	ASL_Hail,	(ULONG) "Load object",
	ASL_Dir,	(ULONG) Current_Object_DirName,
	ASL_File,	(ULONG) Current_Object_FileName,
	ASL_Pattern,	(ULONG) "#?.ic",
	ASL_FuncFlags,	FILF_PATGAD,
	ASL_Window,	Windows[Id_Active_Window].Window,
	TAG_DONE);

    if (Requester == NULL) return;

    if (AslRequest(Requester, NULL)) {

	strncpy(Current_Object_FileName, Requester->rf_File, File_Name_Length);
	Current_Object_FileName[File_Name_Length] = '\0';

	strncpy(Current_Object_DirName, Requester->rf_Dir, Path_Name_Length);
	Current_Object_DirName[Path_Name_Length] = '\0';

	strncpy(Path, Requester->rf_Dir, Buffer_Length);

	if (AddPart(Path, Requester->rf_File, Buffer_Length) != 0) {

            Object_File_Read(Path);
            Compute_Splines();
            Set_Window_Title(NULL);
            Redraw_Mask |= What_All;

	} /* if */

    } /* if */

    FreeAslRequest(Requester); 

} /* Command_Load_Object */

void Command_Save_Object()
/************************************************************************/
/*                                                                      */
/* Save the object to disk.						*/
/*                                                                      */
/************************************************************************/
{
    struct FileRequester *Requester;
    char   Path[Buffer_Length+1];


    Requester = AllocAslRequestTags(ASL_FileRequest,
	ASL_Hail,	(ULONG) "Save object",
	ASL_Dir,	(ULONG) Current_Object_DirName,
	ASL_File,	(ULONG) Current_Object_FileName,
	ASL_Pattern,	(ULONG) "#?.ic",
	ASL_FuncFlags,	FILF_SAVE | FILF_PATGAD,
	ASL_Window,	Windows[Id_Active_Window].Window,
	TAG_DONE);

    if (Requester == NULL) return;

    if (AslRequest(Requester, NULL)) {

	strncpy(Current_Object_FileName, Requester->rf_File, File_Name_Length);
	Current_Object_FileName[File_Name_Length] = '\0';

	strncpy(Current_Object_DirName, Requester->rf_Dir, Path_Name_Length);
	Current_Object_DirName[Path_Name_Length] = '\0';

	strncpy(Path, Requester->rf_Dir, Buffer_Length);

	if (AddPart(Path, Requester->rf_File, Buffer_Length) != 0) {

            Object_File_Write(Path);

	} /* if */

    } /* if */

    FreeAslRequest(Requester); 

} /* Command_Save_Object */

void Command_Load_JMan_Object()
/************************************************************************/
/*                                                                      */
/* Load an Journeyman object from disk.					*/
/*                                                                      */
/************************************************************************/
{
    struct FileRequester *Requester;
    char   Path[Buffer_Length+1];


    Requester = AllocAslRequestTags(ASL_FileRequest,
	ASL_Hail,	(ULONG) "Load Journeyman object",
	ASL_Dir,	(ULONG) Current_Object_DirName,
	/* ASL_File,	(ULONG) Current_Object_FileName, */
	ASL_Pattern,	(ULONG) "#?.seg",
	ASL_FuncFlags,	FILF_PATGAD,
	ASL_Window,	Windows[Id_Active_Window].Window,
	TAG_DONE);

    if (Requester == NULL) return;

    if (AslRequest(Requester, NULL)) {

#if 0
	strncpy(Current_Object_FileName, Requester->rf_File, File_Name_Length);
	Current_Object_FileName[File_Name_Length] = '\0';
#endif

	strncpy(Current_Object_DirName, Requester->rf_Dir, Path_Name_Length);
	Current_Object_DirName[Path_Name_Length] = '\0';
	strncpy(Path, Requester->rf_Dir, Buffer_Length);

	if (AddPart(Path, Requester->rf_File, Buffer_Length) != 0) {

	    JMan_File_Read(Path);
            Compute_Splines();
            Set_Window_Title(NULL);
            Redraw_Mask |= What_All;

	} /* if */

    } /* if */

    FreeAslRequest(Requester); 

} /* Command_Load_JMan_Object */

void Command_Generate_TTDDD_File()
/************************************************************************/
/*                                                                      */
/* Generate a TTDDD description of the current object.			*/
/*                                                                      */
/************************************************************************/
{
    struct FileRequester *Requester;
    char   Path[Buffer_Length+1];


    Requester = AllocAslRequestTags(ASL_FileRequest,
	ASL_Hail,	(ULONG) "Save TTDDD object",
	ASL_Dir,	(ULONG) Current_TTDDD_DirName,
	ASL_File,	(ULONG) Current_TTDDD_FileName,
	ASL_Pattern,	(ULONG) "#?.ttddd",
	ASL_FuncFlags,	FILF_SAVE | FILF_PATGAD,
	ASL_Window,	Windows[Id_Active_Window].Window,
	TAG_DONE);

    if (Requester == NULL) return;

    if (AslRequest(Requester, NULL)) {

	strncpy(Current_TTDDD_FileName, Requester->rf_File, File_Name_Length);
	Current_TTDDD_FileName[File_Name_Length] = '\0';

	strncpy(Current_TTDDD_DirName, Requester->rf_Dir, Path_Name_Length);
	Current_TTDDD_DirName[Path_Name_Length] = '\0';

	strncpy(Path, Requester->rf_Dir, Buffer_Length);

	if (AddPart(Path, Requester->rf_File, Buffer_Length) != 0) {

	    Display_Status("Generating TTDDD file...");

            (void) Generate_TTDDD_File(Path);

	    Display_Status(NULL);

	} /* if */

    } /* if */

    FreeAslRequest(Requester); 

} /* Command_Generate_TTDDD_File */

void Command_Load_Config()
/************************************************************************/
/*                                                                      */
/* Load configuration from disk.						*/
/*                                                                      */
/************************************************************************/
{
    struct FileRequester *Requester;
    char   Path[Buffer_Length+1];

    if (*Current_Config_DirName == '-') 
	strcpy(Current_Config_DirName, "s:");
    if (*Current_Config_FileName == '\0') 
	strcpy(Current_Config_FileName, Default_Config_File_Name);

    Requester = AllocAslRequestTags(ASL_FileRequest,
	ASL_Hail,	(ULONG) "Load configuration",
	ASL_Dir,	(ULONG) Current_Config_DirName,
	ASL_File,	(ULONG) Current_Config_FileName,
	ASL_Pattern,	(ULONG) "#?.cfg",
	ASL_FuncFlags,	FILF_PATGAD,
	ASL_Window,	Windows[Id_Active_Window].Window,
	TAG_DONE);

    if (Requester == NULL) return;

    if (AslRequest(Requester, NULL)) {

	strncpy(Current_Config_FileName, Requester->rf_File, File_Name_Length);
	Current_Config_FileName[File_Name_Length] = '\0';

	strncpy(Current_Config_DirName, Requester->rf_Dir, Path_Name_Length);
	Current_Config_DirName[Path_Name_Length] = '\0';

	strncpy(Path, Requester->rf_Dir, Buffer_Length);

	if (AddPart(Path, Requester->rf_File, Buffer_Length) != 0) {

            Config_File_Read(Path);
            Compute_Splines();
            Set_Window_Title(NULL);
            Redraw_Mask |= What_All;

	} /* if */

    } /* if */

    FreeAslRequest(Requester); 

} /* Command_Load_Config */

void Command_Save_Config()
/************************************************************************/
/*                                                                      */
/* Save the configuration to disk.					*/
/*                                                                      */
/************************************************************************/
{
    struct FileRequester *Requester;
    char   Path[Buffer_Length+1];

    if (*Current_Config_DirName == '-') 
	strcpy(Current_Config_DirName, "S:");
    if (*Current_Config_FileName == '\0') 
	strcpy(Current_Config_FileName, Default_Config_File_Name);

    Requester = AllocAslRequestTags(ASL_FileRequest,
	ASL_Hail,	(ULONG) "Save configuration",
	ASL_Dir,	(ULONG) Current_Config_DirName,
	ASL_File,	(ULONG) Current_Config_FileName,
	ASL_Pattern,	(ULONG) "#?.cfg",
	ASL_FuncFlags,	FILF_SAVE | FILF_PATGAD,
	ASL_Window,	Windows[Id_Active_Window].Window,
	TAG_DONE);

    if (Requester == NULL) return;

    if (AslRequest(Requester, NULL)) {

	strncpy(Current_Config_FileName, Requester->rf_File, File_Name_Length);
	Current_Config_FileName[File_Name_Length] = '\0';

	strncpy(Current_Config_DirName, Requester->rf_Dir, Path_Name_Length);
	Current_Config_DirName[Path_Name_Length] = '\0';

	strncpy(Path, Requester->rf_Dir, Buffer_Length);

	if (AddPart(Path, Requester->rf_File, Buffer_Length) != 0) {

            Config_File_Write(Path);

	} /* if */

    } /* if */

    FreeAslRequest(Requester); 

} /* Command_Save_Config */

void Command_Quit()
/************************************************************************/
/*                                                                      */
/* Quit the program.							*/
/*                                                                      */
/************************************************************************/
{
    int Answer;

    Answer = Ask_Question("Do you really want to quit?", "Yes|No");

    if (Answer == 1) Quit_Flag = TRUE;

} /* Command_Quit */

void Command_ZoomIn()
/************************************************************************/
/*                                                                      */
/* Zoom in.								*/
/*                                                                      */
/************************************************************************/
{
    Modify_Scale(1.5);
    Compute_Splines();
    Redraw_Mask |= What_All;

} /* Command_ZoomIn */

void Command_ZoomOut()
/************************************************************************/
/*                                                                      */
/* Zoom out.								*/
/*                                                                      */
/************************************************************************/
{
    Modify_Scale(0.6666666);
    Compute_Splines();
    Redraw_Mask |= What_All;

} /* Command_ZoomOut */

void Command_Show_KnotInfo()
/************************************************************************/
/*                                                                      */
/* Show the knot information window.					*/
/*                                                                      */
/************************************************************************/
{
    if (Windows[(int)W_KnotInfo].Window == NULL) Window_Open(W_KnotInfo);
    WindowToFront(Windows[W_KnotInfo].Window);

    KnotInfo_Show_Info(Select_Spline, Select_Knot);

} /* Command_Show_KnotInfo */
