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

    File:    Menu.h
    Author:  Copyright  1993, 1994, 1995 Jason Williams, Julian Smith,
                                          Brian Scattergood.
             Thanks to Shaun Blackmore, Tim Browse, and others for various
             bits and pieces, menu template ideas, etc, which were mostly
             not used for this simple implementation, but may be used in
             the future.
    Version: 1.03 (Dec 1994)
    Purpose: Equivalent of RISC OS Lib's "menus" functions - Give a simple
             method for creating and showing menus.
    History: 1.03 (Dec 1994)
             1.04 (05 Oct 1995) JS    Added Desk_Menu_AddSubWindow.
             1.05 (31 Oct 1995) JS, BS Added Desk_Menu_SetNotify macro.
             
    Notes:   These are simple menu create and show functions along very
             similar lines to RISC OS Lib's 'menu' functions. However, there
             are major differences -
               + menu items are ALWAYS indexed starting from 0.
               + menu pointers point to real Wimp menu structures, no
                 messing about
               + Desk_Menu_Show is provided to show the menus for you, including
                 placing a menu in the correct position over the icon bar.
*/


#ifndef __Desk_Menu_h
#define __Desk_Menu_h

#ifdef __cplusplus
	extern "C" {
#endif


#ifndef __Desk_Core_h
#include "Desk.Core.h"
#endif

#ifndef __Desk_Wimp_h
#include "Desk.Wimp.h"
#endif

#ifndef __Desk_Event_h
#include "Desk.Event.h"
#endif


extern Desk_menu_ptr Desk_Menu_New( const char *title, const char *description);
  /*
   *  Creates a new menu. "title" should be no more than 12 characters long
   *  (including the terminator). "description" is a RISC OS Lib style
   *  Desk_menu_new() string (Desktop C manual, page 240, but note their syntax
   *  AND their example are both WRONG!), i.e.
   *      opt   :- " "  no special options (i.e. leading spaces are skipped)
   *               "!"  ticked
   *               "~"  shaded
   *               ">"  has submenu/subwindow
   *               "-"  dotted
   *      name  :- any character except ", " and "|"
   *      entry :- {opt}* name
   *      sep   :- ", "  to separate normal items
   *               "|"  to separate items and place a dotted line between them
   *      descr :- entry {sep entry}*
   *
   *      EXAMPLES:
   *        "!Ticked, ~Disabled, >Sub-menu, !~Ticked and disabled, Normal"
   *        ">Info, Create| Quit"         ; info with sublink arrow
   *                                      ; then create, dotted line, quit.
   *
   *  NOTES:
   *    If this call fails (out of malloc memory) then it will call
   *    Desk_Error_OutOfMemory() and then return NULL.
   */


extern Desk_menu_ptr Desk_Menu_Extend(Desk_menu_ptr menu, const char *description);
  /*
   *  Extends (if possible) the menu by appending the items in "description"
   *  onto the menu structure "menu". If the memory reallocation fails, it
   *  returns the pointer to the old, UNCHANGED menu structure.
   *  "description" is the same as for Desk_Menu_New().
   */


extern void Desk_Menu_Show(Desk_menu_ptr menu, int x, int y);
  /*
   *  Shows the given menu on screen, at the given x and y position.
   *  Set (y = -1) to place the menu at the correct position above the
   *  icon bar.
   */


extern void Desk_Menu_ShowLast(void);
  /*
   *  Re-opens the last menu opened (call when a menu item is chosen using
   *  the adjust mouse button to keep the menu open).
   *  Note that if no menu has been opened, or if the last menu opened
   *  has been "dispose"d, this will have bad (dire) results.
   */


extern void Desk_Menu_PopUp(Desk_menu_ptr menu, Desk_window_handle window, Desk_icon_handle icon);
  /*
   *  Shows a menu just beside the given icon, as in the Acorn style guide
   *  for popups (who cares if it's a pain in the ass moving the pointer
   *  all the way over there instead of having the menu pop up in a useful
   *  place, right? ;-)
   */

extern void Desk_Menu_PopUpAuto(Desk_menu_ptr menu);
  /*  PopUpAuto is a variant which determines the icon to use from the
   *  last Wimp event processed (uses Desk_Event_ stuff). Useful in a default
   *  handler. If no icon info can be found from the last event, nothing
   *  happens.
   */



extern void Desk_Menu_AddSubMenu(Desk_menu_ptr menu, int entry, Desk_menu_ptr submenu);
  /*
   *  Adds a menu to an existing menu as a submenu at a particular item.
   */

#define	Desk_Menu_AddSubWindow( menu, entry, window)	\
		Desk_Menu_AddSubMenu( menu, entry, (Desk_menu_ptr) window)
/*
Use this to add a window (eg an info box) to a menu. 'window' should be
the window-handle of the window.
 */

extern void Desk_Menu_MakeIndirected(Desk_menu_ptr menu, int entry,
                                const char *buffer, int size);
  /*
   *  Converts a menu item into an indirected item, setting it to use the
   *  given buffer (thus setting it to use different text)
   *  SeeAlso: Desk_Menu_SetText; Desk_Menu_ReviseWidth
   */

extern void Desk_Menu_MakeWritable(Desk_menu_ptr menu, int entry,
                               const char *buffer, int size, const char *valid);
  /*
   *  Makes a menu item writable. You supply the buffer into which the
   *  menu item data will be written, as well as the size of this buffer
   *  (including terminator), plus the validation string (as in Wimp icons)
   */

extern void Desk_Menu_SetFlags(Desk_menu_ptr menu, int entry, int ticked, int shaded);
  /*
   *  Alters the state of a menu item. Setting ticked/shaded to 0 will
   *  turn off the tick/make the item selectable. Setting them to 1 will
   *  turn on a tick/make the item unselectable. Values other than 0 and 1
   *  are undefined, so ensure the values you use are 0 and 1.
   */


extern void Desk_Menu_GetFlags(Desk_menu_ptr menu, int entry, int *ticked, int *shaded);
  /*
   *  Reads the state of a menu item. If ticked/shaded are non-null
   *  pointers then the ints will be updated to reflect the current
   *  state of the menu entry.
   */


extern void Desk_Menu_SetText(Desk_menu_ptr menu, int entry, const char *text);
  /*
   *  Sets the text for a menu entry.  
   *  SeeAlso: Desk_Menu_MakeIndirected; Desk_Menu_ReviseWidth
   */


extern char *Desk_Menu_GetText(Desk_menu_ptr menu, int entry);
  /*
   *  Finds the address of the text of a menu entry.
   *  NOTE that this is the actual menu item text buffer, so treat it with
   *  care!
   */


extern int Desk_Menu_CalcHeight(Desk_menu_ptr menu);
  /*
   *  Calculates the height of a menu in OS coords. For internal use.
   */


#define Desk_Menu_SysHandle(menu) (menu)
  /*
   *  Returns a pointer to the 'underlying' Wimp menu definition. In DeskLib
   *  this IS the menu definition.
   */


#define Desk_Menu_SDispose(menu) free(menu)
  /*
   *  Frees up the memory used by a menu. Note that this is a simple Dispose
   *  which does not recursively dispose of attached submenus, and does not
   *  dispose of memory used by long (indirected) item text.
   */


extern void Desk_Menu_FullDispose(Desk_menu_ptr menu);
  /*
   *  Frees up the memory used by a menu. Note that this also
   *  does not recursively dispose of attached submenus.
   *  It does, however, dispose of all indirected menu data
   */


extern void Desk_Menu_RemoveItem(Desk_menu_ptr menu, int entry);
  /*
   *
   *  Removes a menu item from a menu, shuffling items following it up the
   *  menu. If there is only one item in the menu, nothing happens.
   */



extern void Desk_Menu_Warn(Desk_menu_ptr menu, int entry, Desk_bool yesno,
                      Desk_event_handler handler, void *reference);
  /*
   *  Sets up the given menu item as needing a message when the user follows
   *  the submenu arrow. If yesno is Desk_bool_TRUE, attaches the given handler to
   *  menuwarnings, else releases the handler. Uses EventMsg.
   */


extern void Desk_Menu_ReviseWidth(Desk_menu_ptr menu);
/*
 *  Revises a menu's width, by scanning through all the items.
 *  The title width is also taken into consideration.
 *  It is assumed that there is AT LEAST ONE item in the menu.
 *
 *  Use it after using Desk_Menu_SetText(), or when updating the
 *  contents of an indirected text menu item, ie when having
 *  used Desk_Menu_MakeIndirected().
 */


#define	Desk_Menu_FirstItem(menu) ((Desk_menu_item *) (((Desk_menu_ptr) (menu) + 1)))
/*
Very useful macro for messing around with Desk_menu_block's. Treat like:

Desk_menu_item *Desk_Menu_FirstItem( Desk_menu_ptr *menu);

You can do things like (for eg)
'Desk_Menu_FirstItem( menu)[5].menuflags.data.shaded = Desk_bool_TRUE;'
- this will shade menu item number 5.
*/




#define Desk_Menu_SetNotify( menu, entry, notify)	\
	Desk_Menu_FirstItem(menu)[entry].menuflags.data.notifysub = (notify)
/*
Treat like:

void Desk_Menu_SetNotify( Desk_menu_ptr* menu, int entry, Desk_bool notify);

Alters the notify bit of a menu item. Setting notify to 0 will inhibit
the generation of notification messages for that item (The default under
DeskLib for submenu items is notification enabled). Values other than 0
and 1 are undefined, so ensure the value you use is 0 or 1.
 */


#define Desk_Menu_FontMenu_NOTICK      0             /* don't tick anything */
#define Desk_Menu_FontMenu_TICKSYSFONT ((char *)1)   /* tick the system font entry */

extern Desk_menu_ptr Desk_Menu_FontMenu(Desk_bool sysfont, const char *tick);
  /*
   *  Returns a pointer to a font menu, or 0 if it couldn't make one.
   *  Set sysfont to Desk_bool_TRUE to add 'System font' at the top of the menu.
   *  Set tick to a font name to tick it, or Desk_Menu_FontMenu_<x> for
   *  something else.
   *  Use Desk_Menu_FontMenu3 if you don't want the RISC OS 2 compatability
   *  code dragged in. Under RISC OS 2, you get a plain list of fonts
   *  without submenus. If the user has RISC OS 2, it's their own fault,
   *  but at least it'll work.
   */

extern Desk_menu_ptr Desk_Menu_FontMenu3(Desk_bool sysfont, const char *tick);
/*
RISC OS 3 version of Desk_Menu_FontMenu.
 */

extern char *Desk_Menu_FontMenuDecode(const int *selection);
  /* return pointers to font name given selection of entries within menu
   * or 0 if an error occured 
   * Use MenuFontMenuDecode3 to avoid RISCOS2 compatability code being included
   */

extern char *Desk_Menu_FontMenuDecode3(const int *selection);




#ifdef Desk__using_SDLS
  extern Desk_menu_ptr   *Desk_Menu__Ref_fontmenu( void);
  extern Desk_wimp_point *Desk_Menu__Ref_currentpos( void);
  extern Desk_menu_ptr   *Desk_Menu__Ref_currentopen( void);
#endif

#if defined( Desk__using_SDLS) && !defined( Desk__making_Menu)

  #define Desk_menu_fontmenu    (*Desk_Menu__Ref_fontmenu())
  #define Desk_menu_currentpos  (*Desk_Menu__Ref_currentpos())
  #define Desk_menu_currentopen (*Desk_Menu__Ref_currentopen())

#else

  extern Desk_menu_ptr   Desk_menu_fontmenu;
/*
only for comparison with Desk_menu_currentopen. This is defined in an
assembler file, so won't work well in the dynamic-linking DeskLib.
*/

  extern Desk_wimp_point Desk_menu_currentpos; 
/*
holds the x, y position where the last menu was opened. If no menu has
been opened, or the last menu has been disposed, then this values will
be invalid - use with care.
*/

  extern Desk_menu_ptr   Desk_menu_currentopen; 
/* pointer to the last menu opened. If no menu has been opened, or the
last menu has been disposed, then this values will be invalid - use with
care.
*/
#endif


#ifdef __cplusplus
}
#endif


#endif
