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

    File:    save.h
    Author:  Copyright  1994 Julian Smith and Jason Howat
    Version: 1.02 (18 Jun 1994)
    Purpose: Automate handling of save-as windows
    Mods:    13-Jun-1994 - JPS - Added filetype handling
             18-Jun-1994 - JDH - See Save.c
*/

#ifndef __dl_save_h
#define __dl_save_h

#ifdef __cplusplus
extern "C" {
#endif


#ifndef __stdlib_h
#include <stdlib.h>
/* For size_t	*/
#endif

#ifndef __dl_event_h
#include "Event.h"
#endif



typedef BOOL (*save_filesaver)(char *f, void *ref);
/* 
This type of function should save data to file given by 'f', using info
in 'ref'. It should return TRUE if it was successful. 'ref' is the (void
*) originally passed to Save_InitSaveWindowHandler
*/

typedef int (*save_ramsaver)(
  task_handle  sourcetask,                  /* our task handle */
  void         *ref,
  task_handle  desttask,
  void         *destbuffer,
  unsigned int buffersize,
  int          progress       /* how many bytes have been transfered so far  */
  );
/*
This type of function should Wimp_TransferBlock data. Note that you can
do this using multiple Wimp_TransferBlock's if this is more convinient.
Should return the total number of bytes transfered into 'destbuffer' -
if less than buffersize, then transfer has finished. If <0, error has
occurred. 'ref' is the (void *) originally passed to
Save_InitSaveWindowHandler
*/




typedef enum
{
  save_SAVEOK    = 0,
  save_RECEIVERFAILED,
  save_FILESAVERFAILED,
  save_RAMSAVERFAILED
} save_result;


typedef void (*save_resulthandler)(save_result result, void *ref);
/* Called after any attempt to save. */

typedef struct
{
  window_handle    window;        /*  Window that the save icons are in */

  union
  {
    unsigned int  value;
    struct
    {
      unsigned int  is_menu         : 1;  /* Savewindow is part of menu  */
      unsigned int  is_save_window  : 1;  /* Close window after save?    */
      unsigned int  we_are_dragging : 1;  /* Are we dragging file icon?  */
      unsigned int  quit_after_save : 1;  /* Click/drag was with Select  */
      unsigned int  release_after   : 1;  /* Release all handlers when   */
                                          /* the window/menu is closed?  */
      unsigned int  padding         : 27;
    } data;
  } flags;

  icon_handle         dragsprite;
  icon_handle         okbutton;
  icon_handle         cancelbutton;
  icon_handle         filenameicon;
  save_filesaver      filesaver;
  save_ramsaver       ramsaver;
  save_resulthandler  resulthandler;
  size_t              estimatedsize;
  int                 filetype;
  void                *ref;
  int                 ram_progress;          /* Num of bytes ram-transfered. */
  unsigned int        last_message_ref;      /* So we know which incoming    */
                                             /* messages are replies to us   */
} save_saveblock;
/*

This struct contains all the info needed to deal with saving using the
RISC OS data transfer protocol.

It is used internally by the Save_* functions - you shouldn't need to
use it normally. It is included here because Save_InitSaveWindowHandler
returns a pointer to it, so that you can call
Save_ReleaseSaveWindowHandler if you are using RO2 and have to detect
menu closing manually, and also you might want to change the field 'ref'
if the user presses a 'Selection' button in the save window (you might
also want to change 'filesaver' and 'ramsaver' in this case).

Also, you could change 'is_menu' if a menu-leaf savewindow changes into
to a free-standing savewindow (this will only work if you have
.flags.data.release_after = FALSE - the saveblock wil be free-ed and all
Event_ handlers released when the menu is closed otherwise.

fn 'filesaver' is called when the data needs to be saved to a file.

fn 'ramsaver' is called when the data needs to be RAM transfered.

'ref' is passed to file/ramsaver - it should enable these functions to
save the right piece of data.

You can change the following things after you have called
Save_InitSaveWindowHandler:

is_menu, is_save_window, filesaver, ramsaver, resulthandler,
estimatedsize, ref.

Don't change any of the icon or window handles, as these will have been
used with Event_Claim, so if you change them, when Save_* calls
Event_Release, DeskLib will complain.

Also, don't change any other fields (there is no reason to anyway) as
these are used internally and are assumed to be const.
*/



save_saveblock *Save_InitSaveWindowHandler(
  window_handle      window,           /* handle of the window to deal with  */
  BOOL               is_menu,          /* is this window part of a menu?     */
                                       /* if TRUE Save_* will close it after */
                                       /* 'Select'-saves                     */
  BOOL               is_save_window,   /* is this window just a save window? */
                                       /* if TRUE Save_* will close it after */
                                       /* 'Select'-saves                     */
  BOOL               release_after,    /* release all Save_ handlers when    */
                                       /* window/menu is closed?             */
  icon_handle        dragsprite,       /* handle of the dragable file-icon   */
  icon_handle        okbutton,         /* handle of 'OK' or 'Save' button    */
  icon_handle        cancelbutton,     /* handle of the 'Cancel' button      */
  icon_handle        filenameicon,     /* handle of the writable fname icon  */
  save_filesaver     filesaver,        /* fn which saves data to a file      */
  save_ramsaver      ramsaver,         /* fn which does Wimp_TransferBlocks  */
  save_resulthandler resulthandler,    /* fn to report success of save to    */
  size_t             estimatedsize,    /* size of data  (estimate)           */
  int                filetype,
  void      *ref                       /* ref passed to all saver functions  */
  );
/*

To implement RISC OS saving, call this function - it does all the
message handling needed, and calls 'filesaver' or 'ramsaver' when
needed, passing 'ref' to them so that they know what needs saving.

'ismenu' should be TRUE if 'window' is part of a menu tree, and FALSE if
'window' is normal window. This is used to know when to stop handling
the save, e.g. when menu is closed, or when save-window is closed.


Things you need to do:

Create a conventional save-window with icons for Save, Cancel, and
dragging, and an *indirected* text icon for the filename. (e.g. put this
in a 'Templates' file). The filename icon *must* be indirected.

Put a default file/leafname in to the filename icon.

Make the dragable icon be whatever file-icon is appropriate

Write a function which can save the data to a file.  *Required*

Write a function which can Wimp_TransferBlock the data.  *Optional*

Write a function to be called with result of any save  *Optional*

Create a reference, 'ref', to the data so that the saver functions know
what data to save.

Call Save_InitSaveWindowHandler You can do this anytime - e.g. just
before/after you create a menu that includes the save window, when you
open the save box in response to (for e.g.) a F3 keypress, or when you
receive a message_MENUWARNING which heralds the opening of your
save-window.


YOU are responsible for opening the savewindow and dealing with menu
handling. All Save_* does is handle the sprite-drgging, button pressing
and data transfer protocol which originate in the save window.

Then, when the user tries to save the data, the only thing which you get
to know about is that either your 'filesaver' or 'ramsaver' is called,
with the 'ref' you originally passed to Save_InitSaveWindowHandler. If a
save is attempted, 'resulthandler' will be called, with the
success/failure of the save.

Thats it.


Notes:

The 'filenameicon' may be altered by Save_InitSaveWindowHandler - it
replaces the first control chr by ASCII 0, as this works with standard C
functions, and some template text icons seem to be terminated by ASCII
13.

if you use 'release_after = FALSE', the Event_ handlers will still be in
place after the window/menu has closed. This is so you can keep a single
window for all saves, and register it with Save_ just once when your
application starts up. If your application deals with different pieces
of data, you'll have to update the 'ref' field in the Save_saveblock
returned by Save_InitSaveWindowHandler each time the window is opened.

Save_* registers a handler for when the save window is closed, which
Event_Release's all of the Save_* handlers for drag/click/message
handling etc. This means you can have a save window with a close icon as
well as/instead of the 'cancel' icon, and makes the whole thing a bit
more robust.

You can miss out any of the icons in the window by using a negative icon
handle. This will prevent any Event_Claim's for the icon.

If 'ramsaver' == NULL, then 'filesaver' will always be used. If
'resulthandler' == NULL, a default handler will be used, which will do
an 'Error_Report' if a save fails.

If 'resulthandler' != NULL, it will be called after any attempt to save
the data, with 'ref' and one of the following flags:

save_SAVEOK = 0    receiver signals the save went OK
save_SAVERECEIVERFAILED  receiver didn't signal it has received the data
save_SAVESAVERFAILED  your 'filesaver' function signalled an error
save_SAVERAMFAILED  your 'ramsaver'  function signalled an error

This is so that your app doesn't go away thinking data has been saved
when it hasn't. Note that your saver functions will not be aware of any
problem in the second case, where the receiver fails to load the scrap
file.

If you want to implement a 'Selection' button in the save window, you
should register a separate handler for event_CLICK on the 'Selection'
button in the save window, and when it is pressed, modify the saveblock
previously returned by Save_InitSaveWindowHandler, so that
save_saveblock.ref points to the selction data. You could also change
the writable icon contents and the 'file/ramsave' functions etc etc.

*/



void Save_ReleaseSaveHandlers(save_saveblock *saveblock);
/*
You shouldn't need this normally because menu/window closing is detected
by SaveBoxHandler, 'cos it detects message_MENUSDELEATED and
event_CLOSE. NB, in RO2, there is no message_MENUSDELEATED, so you will
have to call this function when you next open a menu, or something...

Also, if you want to close a free-standing (i.e. not in a menu)
save-window when <Escape> is pressed, you will need this function.

*/

void Save_SetFiletype(save_saveblock *saveblock, int filetype);
/*
Sets the sprite in the savewindow to be "file_..." and also alters the
saveblock so that the filetype is used whenever date is saved to the
filer  or another application.	
					
NB this function changes the dragsprite icon is an *undirected* sprite-
-only icon. If it was previously an indirected icon, the pointer to the 
indirected data is lost forever!					
*/

#ifdef __cplusplus
}
#endif


#endif

