

#ifndef _menu_h_ /* Mon Sep 20 21:20:32 1993 */
#define _menu_h_





/*
 *
 *          Copyright (C) 1995, M. A. Sridhar
 *  
 *
 *     This software is Copyright M. A. Sridhar, 1995. You are free
 *     to copy, modify or distribute this software  as you see fit,
 *     and to use  it  for  any  purpose, provided   this copyright
 *     notice and the following   disclaimer are included  with all
 *     copies.
 *
 *                        DISCLAIMER
 *
 *     The author makes no warranties, either expressed or implied,
 *     with respect  to  this  software, its  quality, performance,
 *     merchantability, or fitness for any particular purpose. This
 *     software is distributed  AS IS.  The  user of this  software
 *     assumes all risks  as to its quality  and performance. In no
 *     event shall the author be liable for any direct, indirect or
 *     consequential damages, even if the  author has been  advised
 *     as to the possibility of such damages.
 *
 */





// Menu is an abstract class representing menus. The two concrete classes
// MenuBar and PopupMenu derived from it.
// The  Menu class simply functions as  a container for MenuItem objects,
// and provides convenience functions  for accessing MenuItems.
//
// A Menu  is thought of  as  a labeled tree,   each of whose  nodes is a
// MenuItem object, and the label  of a given node  is the handle of  the
// corresponding MenuItem object. Thus we require that  the labels of the
// MenuItem objects are  all distinct. The  root of the  tree is  a dummy
// node.   MenuItem is derived  from VisualObject,  and therefore supports  an
// event-handling protocol. In particular, it  displays a picture in  its
// view area, which most often is a simple text string, and it provides a
// ``highlighting'' capability for what it displays.
//
// MenuItem instances cannot be created directly by an application. To
// create a MenuItem, the application must use the Menu methods.
//
// The    MenuItem responds to     the  GetFocus,  Select and   LoseFocus
// events.  Its response to the GetFocus  event is to  highlight  its view,
// and notifying  any clients
// that might be interested in that event. Similarly, its response to the
// LoseFocus event is to notify any clients interested in the event.  Its
// response to  the Select event  depends on whether it is  a leaf in the
// tree or not.  If it is not a leaf in the tree, it displays the submenu
// associated with it.  If  it is a leaf,  it simply notifies any clients
// interested in that event.
//
// Since every simple visual object must contain  a model, we use a string as
// model for the  MenuItem. This model is the  value displayed by default
// in  the MenuItem's  view. (Custom  MenuItem   objects that draw  fancy
// graphics  in  their  view might   or might not   use  this string.) An
// assignment to this model changes the picture drawn in the view.
//
// The MenuBar and PopupMenu classes are derived from the Menu class, and
// are simply  two different ways  of representing the ``main'' menu, i.e.,
// the children of the root of the menu tree.
//
// The abstraction of the menu represented by the UI_Menu class is the
// following. The Menu is thought of as a container for MenuItem
// objects. Thus all the contained MenuItems must have
// distinct view id's. This view ``linearizes'' the traditional
// tree-structured view of a menu in which the children of the root are the
// main menu items, and their children are submenu items.
//
// The view id of the root is platform-dependent; the Menu's {\tt RootID}
// method can be used to query the it for the root's view id. All menu items
// must have distinct id's that are greater than 0.


#if defined(__GNUC__)
#pragma interface
#endif

#include "base/tree.h"
#include "base/clntset.h"

#include "ui/simple.h"

#if defined(__X_YACL__)

#    include "ui/support/x_yacl/window.h"
#    include "ui/rectangl.h"
#    include <X11/Xproto.h>
class YACL_UI YVE_Window;
class YACL_UI UI_DrawingSurface;
class YACL_UI UI_DwgSurfaceInMemory;

#endif




class YACL_UI UI_MenuItem;
class YACL_UI UI_PopupMenu;
struct UI_MenuItemDescriptor;
class YACL_UI UI_CompositeVObject;


//[ Global
#define UIMenu_Separator  "---"
// This string is used as label of the MenuItemDescriptor to represent a
// separator.
struct UI_MenuItemDescriptor {
    char*                  label;
    UI_ViewID              id;
    UI_MenuItemDescriptor* submenu;
};

// MenuItemDescriptor describes a MenuItem. The Menu constructors need an
// array of MenuItemDescriptors as parameter. If the MenuItem is to
// represent a separator, the {\tt label} field must be set to {\tt
// UIMenu_Separator}; if this is done, the Menu ignores the remaining fields
// of the MenuItemDescriptor.
//
//] Global


class YACL_UI UI_Menu: public UI_VisualObject {

public:

    UI_MenuItem* operator[] (UI_ViewID id);
    // Return a pointer to the menu item with the given id. The returned
    // object remains owned by the Menu, and may not be destroyed by the
    // caller. This method returns NULL if no such id exists in the menu.


    virtual bool Add (UI_ViewID id, const char* label,
              UI_ViewID parent_id = 0, short rank = 32000);
    // Add a new menu item, with view id {\tt id} and label {\tt label}, as
    // a child of the item with id {\tt parent_id}. The new item is added
    // immediately to the right of the child at position {\tt rank}.
    // Specifying a rank that is too large causes the item to be added as
    // the rightmost child; specifying $-1$ causes it to become the leftmost
    // child.
    //
    // The method returns TRUE if the addition was successful, FALSE
    // otherwise (e.g., a duplicate view id or an invalid parent id was
    // specified).
    
    virtual bool AddSeparator (UI_ViewID parent_id, short rank = 32000);
    // Add a separator as a part of the sub-menu whose root is {\tt
    // parent_id}. The value of {\tt rank} is as in the {\tt Add} method. If
    // the rank is larger than the number of children of the specified menu
    // item, the separator is appended to the menu item's submenu.

    virtual bool Remove (UI_ViewID id);
    // Remove the menu item with view id {\tt id}, along with all its
    // descendants in the menu tree. Return TRUE if successful, FALSE if an
    // invalid item was specified.

    virtual bool RemoveSeparator (UI_ViewID parent_id, short r);
    // Remove the separator that is immediately after the MenuItem of rank r
    // that is a child of the MenuItem with view id parent_id. Return TRUE
    // on success, FALSE if there is no such separator.
    
    UI_ViewID RootID () const;
    // Return the view id of the dummy MenuItem at the root of the menu
    // tree. This method is only needed for menu tree traversal.
    
    short ChildCount (UI_ViewID id) const;
    // Return the number of children of the item with the given id. This
    // method returns $-1$ if there is no MenuItem with the given id in the
    // menu.

    UI_MenuItem* Child (UI_ViewID id, short i) const;
    // Return a pointer to the child $i$ of the menu item with view id {\tt
    // id}. The value $i$ must be between 0 and $n-1$, where $n$ is the
    // number of children of
    // the specified menu item. If this is not the case, or if there is no
    // menu item with the given id, this method returns NULL.

    UI_MenuItem* ParentItem (UI_ViewID id) const;
    // Return the menu item that is the parent of the one with the
    // given view id. Return NULL if this is the root id, or if there
    // is no such menu item.

    short Index (UI_ViewID id) const;
    // Return the rank of the menu item with the given id among its
    // siblings; for example, if it is the first child, this method returns
    // 0. This method returns $-1$ if there is no menu item with the given id.


    UI_WindowClass WindowClass () const;
    
    bool IsTabStop () const {return FALSE;};
    // Return FALSE unconditionally, since menus cannot be tab stops.

    const char* ClassName     () const { return "UI_Menu";};

protected:

    UI_Menu  (UI_CompositeVObject* parent, UI_MenuItemDescriptor* item);
    // The constructor is protected, since the Menu is never instantiated
    // directly. Only the derived classes MenuBar and PopupMenu are
    // instantiated by an application.
    
    ~UI_Menu ();


    short _BuildMenuSubtree (UI_MenuItemDescriptor* items, UI_ViewID id);
    // Build the menu subtree described by the given MenuItemDescriptor
    // array as the subtree rooted at the item with view id {\tt id}.
    
    bool  _CreateMenuItemVisual (CL_IntegerTreeNode&);
    // Create the visual element associated with the menu item at the given
    // menu tree node.

    bool  MakeVisualElement () = 0;
    // [Pure virtual] Overrides the inherited method.

    bool  HandleEvent (UI_Event* e);

    bool  DestroyVisualElement ();
    // Destroy the Menu's visual element.

    bool _FontChanged ();
    // The Font of this Menu has changed its value.

    bool PropagateFontChange (UI_VisualObject* init);
    // The Composite parent of this Menu is telling everyone
    // that its font has changed.

    bool _DoRemove (CL_IntegerTreeNode* node);
    // Remove and destroy the menu subtree rooted at the given node.

#if defined(__X_MOTIF__)
    static int OrderProc (_WidgetRec* w);
    // [Specific to X-windows. For internal use only] Used to establish the
    // relative order among menu items.
#elif defined(__X_YACL__)
    bool _isMouseDown ;
    bool _isPtrGrabbed ;

    void _UpdateChildCount() ;

    bool _DrawShadowRect(UI_DrawingSurface&);
    bool _EraseShadowRect();
    UI_MenuItem* _CurrentFocusItem(UI_Point) ;

    UI_Rectangle _ItemShapeRectangle(CL_IntegerTreeNode& node) ;
    UI_Rectangle _ItemWindowRectangle(CL_IntegerTreeNode& node) ;

    void _ChangeMenuItem(CL_IntegerTreeNode& node) ;

    virtual UI_Point _ItemShapeTopLeft(CL_IntegerTreeNode&);
    virtual UI_Point _ItemWindowTopLeft(CL_IntegerTreeNode& node) ;
    virtual UI_Point _ItemWindowTopLeft(UI_MenuItem*);

    bool _GrabMouse(); 
    bool _UngrabMouse(); 
    UI_MenuItem* _MenuItemUnderMouse(int*,int*) ;

#endif
    // Instance data:
    
    CL_IntegerTree _menuTree;
    UI_MenuItem*   _focusItem;

private:
    UI_ViewID _AllocateSeparatorId ();

#if defined(__MS_WINDOWS__) || defined(__MS_WIN32__) || defined(__OS2__) 
public:
    void MoveFocusTo (UI_MenuItem* item);
    // [Specific to MS-Windows and OS/2. Internal use only.]

    UI_MenuItem* Focus () const {return _focusItem;};
    // [Specific to MS-Windows and OS/2. Internal use only.] Return the
    // MenuItem that currently has focus.

    
#endif

#if defined(__X_YACL__)

public:
    void _Processed();
    //Specific to YACL

    void _ButtonDown(bool);
    //Specific to YACL

    bool _isButtonDown();
    //Specific to YACL

    void _SetState() ;

    enum {
        _charHeight                  = 15,
        ITEM_VERT_SPACE              = 12,
        ITEM_LEFT_SPACE              =  9,
        ITEM_RIGHT_SPACE             = 15,
        MENU_BAR_HEIGHT              = 29,
        MENU_ITEM_TOP_SPACE          =  6,
        SEPARATOR_HEIGHT             =  4,
        SEPARATOR_LSPACE             =  1,
        SEPARATOR_VERT_SPACE         =  5, //always less than ITEM_VERT_SPACE
        SHADOW_ITEM_SPACE            =  6,
        SHADOW_ITEM_TOP_SPACE        =  6,
        SHADOW_WINDOW_SPACE          =  3,
        TRIANGLE_HEIGHT              =  9,
        TRIANGLE_LFROMR              =  8,
        TRIANGLE_SPACE_AFTER_ITEM    =  3,
        TRIANGLE_TOP                 =  4,
        TRIANGLE_WIDTH               =  9,
        WINDOW_XTRA_HT               =  5
    } ;


#endif

    
};


// The MenuItem class represents a single item in a Menu. A MenuItem may be
// ``checked,'' i.e., a check mark can be placed beside it. This is
// represented programmatically by the {\tt CheckState} enumeration. The
// visual representation of this check mark is platform-dependent. By
// default, a MenuItem is initially in NotCheckable state. Only MenuItems
// that are leaves of the menu tree are checkable.

class YACL_UI UI_MenuItem: public UI_SimpleVObject {

public:

    bool Enable ();
    // Enable the MenuItem.

    bool Disable ();
    // Show the MenuItem in grayed form.
    
    bool IsTabStop () const {return FALSE;};
    // Return FALSE unconditionally, since MenuItems cannot be tab stops.
        
    CL_Object& Model() {return _title;};
    // Return reference to the string label. This is a synonym for the {\tt
    // Title} method.

    UI_Menu& Container () {return *_container;};
    // Return a reference to the Menu that contains this MenuItem.

    UI_ViewHandle ViewHandle () const;
    // Return the platform-specific view handle for this MenuItem.

    enum CheckState {Checked, NotChecked, NotCheckable};
    
    bool SetCheck (CheckState state);
    // Set the ``checked'' state of this MenuItem according to {\tt
    // state}. If the latter is {\tt Checked}, the MenuItem is displayed in
    // ``checked'' state; if it is {\tt NotChecked}, in ``unchecked'' state.
    // The exact look of this checked MenuItem depends on the platform.

    CheckState CheckValue () const {return _checkState;};
    // Is this MenuItem currently checked?

    bool ToggleCheckState ();
    // If the MenuItem is currently in NotChecked or NoCheck state, put it
    // in Checked state. Otherwise, put it in NotChecked state.
    
    UI_WindowClass WindowClass () const;

    const char* ClassName() const { return "UI_MenuItem";}; 

protected:

    friend UI_Menu;
    friend class UI_MenuBar;
    friend class UI_PopupMenu;
    UI_MenuItem (UI_Menu* container, const char* label, UI_ViewID id);
    // The constructor is protected, since MenuItems cannot be directly
    // instantiated. They are only created by the Menu object.
    
    ~UI_MenuItem();
    // Destructor.

    bool MakeVisualElement ();
    // Override the inherited method. The implementation does very little,
    // because the visual elements of MenuItems are created by the Menu.

    bool _TitleChanged ();
    // Called indirectly by the title to tell this MenuItem that the title's
    // contents have changed.
    
    bool DestroyVisualElement ();
    // Override the inherited method. The implementation destroys the visual
    // element of this MenuItem.
    
    void _PrivateInitialize ();
    // Override the inherited method. Under MS-Windows, this method tells
    // the Controller that the MenuItem has been created.

    bool _FontChanged ();
    // The Font of this MenuItem has changed its value.

    bool PropagateFontChange (UI_VisualObject*);
    // The Composite parent of this MenuItem's Menu is telling everyone
    // that its font has changed.

#if defined(__X_MOTIF__)
    void SetLabel ();
    // [X-windows-specific] Set  the label of the menu item, accounting for
    // the ampersand character as mnemonic.

    void Destroy ();
    // [X-windows-specific, for internal use only]

#elif defined(__X_YACL__)
    bool HandleEvent (UI_Event* e);

    virtual void _DoFocusEmphasis ();
    // [X_YACL specific, YACL internal use only] Called to draw or erase the
    // focus emphasis.

    bool _SetPlatformFont (UI_ViewHandle) {};
    // Override the inherited virtual method with one that does nothing.
    
    bool _DrawUnderLine
           (UI_DrawingSurface&,CL_String,short,UI_Rectangle rect) ;
    UI_MenuItem* _CurrentFocusItem(UI_Point) ;
    UI_Point _ItemWindowTopLeft() ;

    int _childCount ;

    void _ButtonPress(int,int) ;
    void _ButtonRelease(int,int) ;
    void _MouseMove(int,int) ;

#endif
    // 
    // Instance variables
    // 


    UI_Menu*         _container;   // The menu object of which we are a
                                   // part
    CheckState       _checkState;

    
private:
#if defined(__MS_WINDOWS__) || defined(__MS_WIN32__) || defined(__OS2__)
    void _SetState ();
    // [MS-Windows- and OS/2-specific, YACL internal use only.]
    
    UI_ViewHandle    _parentHandle;

#elif defined (__X_MOTIF__)

    struct _WidgetRec* _xitemw;
    static void GetFocusCallback  (struct _WidgetRec*, void *, void *);
    // [X-Windows-specific, for YACL internal use only.]

    static void LoseFocusCallback (struct _WidgetRec*, void *, void *);
    // [X-Windows-specific, for YACL internal use only.]
    
    static void SelectionCallback (struct _WidgetRec*, void *, void *);
    // [X-Windows-specific, for YACL internal use only.]

#elif defined(__X_YACL__)

    //YVE_StringWindow* _itemWindow;
    UI_Rectangle _itemShape; 

    bool _ItemGetFocus(UI_MenuItem*) ; 
    bool _ItemLoseFocus() ; 
    bool _ItemEraseShadowRect(UI_MenuItem*) ; 
    bool _DrawItemWindow() ; 
    bool _DrawToggleState(UI_DrawingSurface&,CheckState,UI_Rectangle) ;

    void _NotifyGetFocus();
    void _NotifyLoseFocus();

    UI_MenuItem* _focusItem ;
    
#endif

};




// MenuBar is derived from Menu. It represents a menu bar typically shown
// across the top of an application's main window.


class YACL_UI UI_MenuBar: public UI_Menu {

public:

    UI_MenuBar (UI_CompositeVObject* parent,
                UI_MenuItemDescriptor* item = NULL);
    // The descriptor array {\tt item} points to an array of
    // MenuItemDescriptors; the last entry in this array must have {\tt
    // label == NULL}. {\tt item} can be NULL, or can point to an array
    // with only one entry that has a NULL label.


#if defined(__MS_WINDOWS__) || defined(__MS_WIN32__)
    UI_MenuBar (UI_CompositeVObject* parent, const char* resourceName);
    // [MS-Windows-specific] Construct a MenuBar with the given resource
    // name.

#endif
    
    bool Add (UI_ViewID id, const char* label,
              UI_ViewID parent_id = 0, short rank = 32000);
    // Override the inherited method.

    const char* ClassName() const { return "UI_MenuBar";};

#if defined(__X_YACL__)
    UI_WindowClass WindowClass () const;
    
#endif
    
protected:
    bool MakeVisualElement ();
    // Override the inherited method. The implementation creates the MenuBar
    // and all the MenuItems in the menu tree.

#if defined(__X_YACL__)
    bool _MenuReconfigure(UI_Event&);
    bool HandleEvent(UI_Event*) ;
    UI_Point _ItemShapeTopLeft(CL_IntegerTreeNode&);
    UI_Point _ItemWindowTopLeft(CL_IntegerTreeNode&) ;
    UI_Point _ItemWindowTopLeft(UI_MenuItem*);
#endif


#if defined(__MS_WINDOWS__) || defined(__MS_WIN32__)
    void _BuildFromResource (CL_IntegerTreeNode* node);
    // [MS-Windows-specific] build the items for this menu from a resource
    // specification.
    
    CL_String _resource;
#endif

};


// PopupMenu is derived from Menu. It represents a popup menu usually shown
// at the position of a click of the right mouse button.

class YACL_UI UI_PopupMenu: public UI_Menu {

public:

    UI_PopupMenu (UI_CompositeVObject* parent, UI_MenuItemDescriptor* item);
    // The descriptor array {\tt item} points to an array of
    // MenuItemDescriptors; the last entry in this array must have {\tt
    // label == NULL}. {\tt item} can be NULL, or can point to an array
    // with only one entry that has a NULL label.

    ~UI_PopupMenu ();

    bool ShowAt (const UI_Point& p);
    // Show the popup menu at the given point.
    
    const char* ClassName () const { return "UI_PopupMenu";};

#if defined(__X_YACL__)
    UI_WindowClass WindowClass () const;
    
#endif

protected:
    bool MakeVisualElement ();
    // Override the inherited method. The implementation creates the MenuBar
    // and all the MenuItems in the menu tree.

#if defined (__X_YACL__)

    bool HandleEvent(UI_Event*) ;
    bool _SetState(UI_Point p) ;
    UI_Point _currentPosition ;
    UI_Point _ItemShapeTopLeft(CL_IntegerTreeNode&);
    UI_Point _ItemWindowTopLeft(CL_IntegerTreeNode& node) ;
    UI_Point _ItemWindowTopLeft(UI_MenuItem*);

#endif


};


#endif



