/*
    ####             #    #     # #
    #   #            #    #       #          The FreeWare C library for
    #   #  ##   ###  #  # #     # ###             RISC OS machines
    #   # #  # #     # #  #     # #  #   ___________________________________
    #   # ####  ###  ##   #     # #  #
    #   # #        # # #  #     # #  #    Please refer to the accompanying
    ####   ### ####  #  # ##### # ###    documentation for conditions of use
    ________________________________________________________________________

    File:    Dialog2.OpenClose.c
    Author:  Copyright  1994 Julian Smith
    Version: 1.03 (13 Mar 1995)
    Purpose: Dialogue box handling
*/


#include <stdlib.h>

#include "Desk.Window.h"
#include "Desk.WimpSWIs.h"
#include "Desk.Event.h"
#include "Desk.Error.h"
#include "Desk.Handler.h"
#include "Desk.Sound.h"
#include "Desk.Template.h"
#include "Desk.Dialog2.h"
#include "Desk.Debug.h"

#include "Defs.h"


/*
We don't use Desk__making_SDLS_staticglobal because Desk_dialog2_menublock is used by other
files within the Dialog2 library.
*/
Desk_dialog2_block	*Desk_dialog2_menublock = NULL;


#ifdef _DLL
Desk_dialog2_block	**Desk_Dialog2__Ref_menublock( void)	{ return &Desk_dialog2_menublock;	}
#endif


static void	Desk_Dialog2__ClaimOrReleaseStandardHandlers(
	Desk_event_claimorreleasefn	fn, 
	Desk_dialog2_block		*dialog2
	);
	/* The actual function is later on...	*/





void	Desk_Dialog2__CloseDialogInternal( 
	Desk_dialog2_block	*dialog2, 
	Desk_bool		closemenu, 	/* If Desk_bool_TRUE, close the current menu if dialog is a menu	*/
	Desk_bool		deletewindow	/* If Desk_bool_TRUE, delete the window if dialog2 allows.	*/
	)
{
Desk_Debug_Assert( dialog2);
if ( dialog2->flags.data.type == Desk_dialog2_type_CLOSED)	{
	Desk_Debug_Printf( "Desk_Dialog2__CloseDialogInternal - dialog already closed.\n");
	}

if ( dialog2->window)	{

	Desk_Dialog2__ClaimOrReleaseStandardHandlers( Desk_Event_Release, dialog2);

	if (	   dialog2->flags.data.type == Desk_dialog2_type_MENU
		|| dialog2->flags.data.type == Desk_dialog2_type_MENULEAF
		)
		{
		if (closemenu)	Desk_Wimp_CreateMenu( (Desk_menu_block *) -1, 0, 0);
		}
	
	else	Desk_Wimp_CloseWindow( dialog2->window);
	
	if ( !dialog2->flags.data.keepwindow)	{
		if ( deletewindow)	{
			Desk_Window_Delete( dialog2->window);
			dialog2->window = NULL;
			}
		else	Desk_Event_ReleaseWindow( dialog2->window);
		}
	}

dialog2->flags.data.type = Desk_dialog2_type_CLOSED;

if ( dialog2->flags.data.notifyclose && dialog2->openfn)
	dialog2->openfn( dialog2);

if ( Desk_dialog2_menublock == dialog2)	Desk_dialog2_menublock = NULL;
	/* So we know whether a menu-dialog2 is open.	*/

return;
}




void	Desk_Dialog2_CloseDialog( Desk_dialog2_block *dialog2)
{
Desk_Dialog2__CloseDialogInternal( 
	dialog2, 
	Desk_bool_TRUE, 	/* close menu if dialog2 is part of a menu;		*/
	Desk_bool_TRUE	/* delete window if !dialog2->flags.data.keepwindow	*/
	);
}




Desk_SDLS_PtrFn( 
	static,
	Desk_bool, 
	Desk_Dialog2__MenusDeletedHandler( Desk_event_pollblock *event, void *reference)
	)
/* static Desk_bool	Desk_Dialog2__MenusDeletedHandler( Desk_event_pollblock *event, void *reference)*/
/* Handler for Desk_message_MENUSDELETED - sent if the menu closes.	*/
/* cc warns about extern ... not declared in header in SDLS compiles	*/
{
Desk_UNUSED( reference);

if ( event->data.message.header.action == Desk_message_MENUSDELETED && Desk_dialog2_menublock)	{
	
	if	( 
		Desk_dialog2_menublock->flags.data.type == Desk_dialog2_type_MENU
		&&
		(Desk_window_handle) event->data.message.data.words[0] != Desk_dialog2_menublock->window
		)
		return Desk_bool_FALSE;
		/* The menu being deleted isn't our dialog2 box - eg the user	*/
		/* has opened the Desk_dialog2_menublock from another menu for which	*/
		/* we are now getting a Desk_message_MENUSDELETED, *after* we've 	*/
		/* opened our dialog2 as a menu-window.				*/
		
	Desk_Dialog2_CloseDialog( Desk_dialog2_menublock);
	}
return Desk_bool_FALSE;
}






Desk_SDLS_PtrFn(
	static,
	Desk_bool, 
	Desk_Dialog2__OKCancelHandler( Desk_event_pollblock *event, void *reference)
	)
/*static Desk_bool	Desk_Dialog2__OKCancelHandler( Desk_event_pollblock *event, void *reference)*/
/* Handler for click on OK or Cancel buttons.	*/
/* cc warns about extern ... not declared in header in SDLS compiles	*/
{
Desk_dialog2_block *dialog2 = (Desk_dialog2_block *) reference;

Desk_Debug_Assert( dialog2->flags.data.type != Desk_dialog2_type_CLOSED);	/* Click for closed dialog2.	*/

if ( dialog2->okfn && event->data.mouse.icon == dialog2->flags.data.okbutton)
	dialog2->okfn( dialog2);
	

if	( 
	event->data.mouse.button.data.select
	&&
		(
		   event->data.mouse.icon == dialog2->flags.data.okbutton
		|| event->data.mouse.icon == dialog2->flags.data.cancelbutton
		)
	)
	{
	Desk_Dialog2_CloseDialog( dialog2);
	}

return Desk_bool_FALSE;
}


Desk_SDLS_PtrFn(
	static,
	Desk_bool, 
	Desk_Dialog2__CloseHandler( Desk_event_pollblock *event, void *reference)
	)
/*static Desk_bool	Desk_Dialog2__CloseHandler( Desk_event_pollblock *event, void *reference)*/
/* Handler for Desk_event_CLOSE.	*/
/* cc warns about extern ... not declared in header in SDLS compiles	*/
{
Desk_UNUSED( event);
Desk_Dialog2_CloseDialog( (Desk_dialog2_block *) reference);
return Desk_bool_FALSE;
}





#define Desk_keycode_RETURN	13
#define Desk_keycode_ESCAPE	0x1B

Desk_SDLS_PtrFn(
	static,
	Desk_bool, 
	Desk_Dialog2__KeyHandler( Desk_event_pollblock *event, void *reference)
	)
/*static Desk_bool	Desk_Dialog2__KeyHandler( Desk_event_pollblock *event, void *reference)*/

/* This sends our application an Desk_event_CLICK on the ok/cancel button	*/
/* when Return/Escape is pressed in the dialog box. Would be better to 	*/
/* have an Desk_Event_FakeEvent function or something...			*/
/* cc warns about extern ... not declared in header in SDLS compiles	*/
{
Desk_dialog2_block *dialog2 = (Desk_dialog2_block *) reference;

Desk_Debug_Assert( dialog2->flags.data.type != Desk_dialog2_type_CLOSED);	/* Keypress in closed dialog2.	*/

if ( event->data.key.code == Desk_keycode_RETURN && dialog2->flags.data.okbutton != -1)	{
	Desk_event_data	clickeventdata;
	clickeventdata.mouse.button.value	= 0;
	clickeventdata.mouse.button.data.select	= Desk_bool_TRUE;
	clickeventdata.mouse.window		= dialog2->window;
	clickeventdata.mouse.icon		= dialog2->flags.data.okbutton;
	Desk_Wimp_SendMessage( 
		Desk_event_CLICK, 
		(Desk_message_block *) &clickeventdata, 
		Desk_Event_taskhandle, 			/* Us	*/
		dialog2->flags.data.okbutton
		);
	return Desk_bool_TRUE;
	}

else if ( event->data.key.code == Desk_keycode_ESCAPE && dialog2->flags.data.cancelbutton != -1)	{
	Desk_event_data	clickeventdata;
	clickeventdata.mouse.button.value	= 0;
	clickeventdata.mouse.button.data.select	= Desk_bool_TRUE;
	clickeventdata.mouse.window		= dialog2->window;
	clickeventdata.mouse.icon		= dialog2->flags.data.cancelbutton;
	Desk_Wimp_SendMessage( 
		Desk_event_CLICK, 
		(Desk_message_block *) &clickeventdata, 
		Desk_Event_taskhandle, 			/* Us	*/
		dialog2->flags.data.cancelbutton
		);
	return Desk_bool_TRUE;
	}

else Desk_Wimp_ProcessKey( event->data.key.code);

return Desk_bool_FALSE;
}








static void	Desk_Dialog2__ClaimOrReleaseStandardHandlers( 
	Desk_event_claimorreleasefn	fn, 
	Desk_dialog2_block		*dialog2
	)
	/* This calls Desk_Event_Claim/Release for all the 	*/
	/* events in which we are interested in.	*/
	/* Using the same function for claiming and 	*/
	/* releasing events ensures we don't leave any	*/
	/* claims active that we don't use.		*/
{
fn( Desk_event_OPEN,  dialog2->window, Desk_event_ANY, Desk_Handler_OpenWindow,    dialog2);
fn(	Desk_event_CLOSE, dialog2->window, Desk_event_ANY, 
	Desk_SDLS_dllEntry( Desk_Dialog2__CloseHandler), 
	dialog2
	);

if ( dialog2->flags.data.okbutton != -1 || dialog2->flags.data.cancelbutton != -1)	{
	fn(	Desk_event_KEY, dialog2->window, Desk_event_ANY, 
		Desk_SDLS_dllEntry( Desk_Dialog2__KeyHandler),   
		dialog2
		);
	fn(	Desk_event_CLICK, dialog2->window, Desk_event_ANY, 
		Desk_SDLS_dllEntry( Desk_Dialog2__OKCancelHandler), 
		dialog2
		);
	/* Make this icon-unspecific so that the application will get clicks first.	*/
	}

if ( dialog2->flags.data.type == Desk_dialog2_type_MENU
||   dialog2->flags.data.type == Desk_dialog2_type_MENULEAF
)	{
	fn(	Desk_event_USERMESSAGE, Desk_event_ANY, Desk_event_ANY, 
		Desk_SDLS_dllEntry( Desk_Dialog2__MenusDeletedHandler), 
		NULL	  
		);
		/* Closes the dialog2 if the menu is closed by Escape or a 	*/
		/* click outside the menu.					*/
		/* NB this won't work with RO2 - the dialog2 won't be closed	*/
		/* until the next dialog2 is opened as a menu.			*/
	}

}









void	Desk_Dialog2__CommonOpenCode( Desk_dialog2_block *dialog2)
{
Desk_Dialog2_EnsureWindowHandle( dialog2);
Desk_Dialog2__ClaimOrReleaseStandardHandlers( Desk_Event_Claim, dialog2);

if (dialog2->openfn)	dialog2->openfn( dialog2);
	/* Call this after 'Desk_Dialog2__ClaimOrReleaseStandardHandlers' 
	so that any events claimed inside 'openfn' will
	get sent to the application's code first.
	*/

}



void	Desk_Dialog2__CommonOpenMenuCode( Desk_dialog2_block *dialog2)
{
if ( Desk_dialog2_menublock)	{	/* Need to close the existing menu-dialog box.	*/
	if ( Desk_dialog2_menublock == dialog2)
		Desk_Dialog2__CloseDialogInternal( Desk_dialog2_menublock, Desk_bool_FALSE, Desk_bool_FALSE);
			/* This dialog is being re-opened, so don't delete the	*/
			/* window as we will only re-open it anyway.		*/
			
	else	Desk_Dialog2__CloseDialogInternal( Desk_dialog2_menublock, Desk_bool_FALSE, Desk_bool_TRUE);
	}

Desk_dialog2_menublock = dialog2;

}













