/*
 * pawsmenu.h - Author: Ondrej Hurt
 *
 * Copyright (C) 2003 Atomic Blue (info@planeshift.it, http://www.atomicblue.org)
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation (version 2 of the License)
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */


/**
 *
 * When pawsMenu is created, target of notification messages (OnMenuAction) must be set by SetNotify() method.
 * When pawsMenu creates a submenu, it sets the target of notification messages automatically.
 *
 * Events with action name="submenu" are handled by the menu and are not delivered to subscriber.
 *
 * When menu wants to destruct itself, it must not do this directly but
 * it must call DestroyMenu() method. This notifies parent and children of menu about the destruction
 * and then sends MENU_DESTROY_ACTION_NAME event via OnMenuAction(). 
 * The receiving widget is responsible for destruction of the menu.
 * This way the widget which uses the menu knows about its destruction and all references
 * to the menu are dropped.
 *
 * All pawsMenu instances should be added to children of mainWidget.
 *
 *
 *
 * pawsMenuItem XML definition
 * ---------------------------
 * attributes:
 *    image        - name of image (if missing, image is disabled)
 *    label        - text of label
 *    colour       - colour of label
 *    checked      - state of checkbox [yes|no] (if missing, checkbox is disabled)
 *    CheckboxOn   - images of checkbox states (if missing, default is used)
 *    CheckboxOff
 *    LabelWidth   - width of label (if missing, it is set to the width of the letters inside)
 *    spacing      - horizontal spacing between image, label and checkbox (if missing, default is used)
 *    border       - space between border and inner components (if missing, default is used)
 *
 *    action       - name of event that is sent when user activates the item
 *    param1       - arbitrary number of additional variables that are included in the event
 *    param2
 *       .
 *       .
 *       .
 *    paramN
 *
 *
 * pawsMenu XML definition
 * -----------------------
 * attributes:
 *    align     - "left" or "center"
 *    autosize  - if "true", then widget size is calculated and set so its content just fits in
 *    colour    - colour of menu label
 *
 * all widgets inside are added as menu items
 *
 */


#ifndef PAWS_MENU_HEADER
#define PAWS_MENU_HEADER

#include <csutil/parray.h>
#include <iutil/document.h>
#include "pawswidget.h"
#include "pawstextbox.h"
#include "pawsbutton.h"


class pawsIMenu;
class pawsMenu;
class pawsIMenuItem;
class pawsMenuItem;


/**
 * pawsMenuAction - when OnMenuAction event is invoked, this structure is sent to event handler 
 * and tells it what action the handler should take.
 * Content of pawsMenuAction is defined in each regular menu item.
 */ 
class pawsMenuAction
{
public:
    csString name;
    csArray<csString> params;
};

/**
 * value of pawsMenuAction::name when window request its destruction
 */
#define MENU_DESTROY_ACTION_NAME "MenuWantsDestroy"

//-----------------------------------------------------------------------------
//                          interface pawsIMenu
//-----------------------------------------------------------------------------

/**
 * Possible reasons of closing of menu:
 */
enum pawsMenuClose {closeAction, closeSiblingOpened, closeCloseClicked, 
                    closeParentClosed, closeChildClosed};


/** 
 * pawsIMenu is common interface to menus (e.g. pawsMenu)
 */
class pawsIMenu : public pawsWidget
{
public:
    pawsIMenu(){  };

    /**
     * Sets parent menu of submenu:
     */
    virtual void SetParentMenu(pawsIMenu * parentMenu) = 0;

    /**
     * Called when parent menu was closed
     */
    virtual void OnParentMenuDestroyed(pawsMenuClose reason) = 0;
    
    /**
     * Called when child menu was closed
     */
    virtual void OnChildMenuDestroyed(pawsIMenu * child, pawsMenuClose reason) = 0;
    
    /**
     * Called when another submenu of parent menu was opened
     */
    virtual void OnSiblingOpened() = 0;

    /** Processes action invoked by user: 
     *    - according to action type either opens a new menu or sends notification to subscriber
     * 'item' is menu item that was activated
     * 'action' is description of the action that should be taken
     */
    virtual void DoAction(pawsIMenuItem * item) = 0;

    /**
     * Sets widget that should be receiving OnMenuAction events
     */
    virtual void SetNotify(pawsWidget * notifyTarget) = 0;

};


//-----------------------------------------------------------------------------
//                            class pawsMenu
//-----------------------------------------------------------------------------

/**
 * Possible vertical alignments of menu items:
 */
enum pawsMenuAlign {alignLeft, alignCenter};


/**
 * pawsMenu is standard PAWS menu widget
 */
class pawsMenu : public pawsIMenu
{
public:
    pawsMenu();
    ~pawsMenu();
    
    //from pawsWidget:
    virtual bool OnButtonPressed(int button, int keyModifier, pawsWidget* widget);
    virtual bool OnMouseDown(int button, int modifiers, int x, int y);
    virtual bool Setup(iDocumentNode * node);
    virtual bool PostSetup();
    virtual void Draw();

    //from pawsIMenu:
    virtual void SetParentMenu(pawsIMenu * parentMenu);
    virtual void OnParentMenuDestroyed(pawsMenuClose reason);
    virtual void OnChildMenuDestroyed(pawsIMenu * child, pawsMenuClose reason);
    virtual void OnSiblingOpened();
    virtual void DoAction(pawsIMenuItem * item);
    virtual void SetNotify(pawsWidget * notifyTarget);


    /* Adds 'item' to the menu, before the 'nextItem' item.
     * If 'nextItem' is NULL, item is added to the end.
     * OWNERSHIP of 'item' goes to pawsMenu
     */
    void AddItem(pawsIMenuItem * item, pawsIMenuItem * nextItem=NULL);

    /**
     * Item is deleted from the menu and destructed.
     */
    void DeleteItem(pawsIMenuItem * item);

    /**
     * Sets action that should be invoked when 'item' is activated by user
     */
    void SetItemAction(pawsIMenuItem * item, const pawsMenuAction & action);

    /**
     * Does menu have any submenus ?
     */
    bool HasSubmenus();
    
protected:
    /**
     * Calculates and sets position of each menu item
     */
    void SetPositionsOfItems();

    /**
     * Sends OnMenuAction event to notification target
     */
    void SendOnMenuAction(const pawsMenuAction & action);

    /**
     * Sends OnMenuAction event that requests destruction of this menu (MENU_DESTROY_ACTION_NAME)
     */
    void SendDestroyAction();

    /**
     * Sends MENU_DESTROY_ACTION_NAME event and notifies its parent and children.
     * Thanks to this all references from parent and children and the widget that is catching
     * menu events are dropped before the destruction.
     */
    void DestroyMenu(pawsMenuClose reason);

    /**
     * Calculates dimensions of menu items
     */
    int GetContentWidth();
    int GetContentHeight();
    
    /**
     * Calculates and sets its size according to size of its content
     */
    void Autosize();
    
    /**
     * Sets appropriate position of a submenu on screen
     */
    void SetSubmenuPos(pawsMenu * submenu, int recommY);
    
    /**
     * Searches for node with attribute "name" equal to parameter in 'node' and its children.
     * If succeeds returns pointer to the node found, or returns NULL.
     */
    csRef<iDocumentNode> FindSubmenuNode(csRef<iDocumentNode> node, const csString & name);
    
    /**
     * Sets positions of the Sticky and Close buttons
     */
    void SetButtonPositions();


    pawsIMenu * parentMenu;
    
    /**
     * list of menu items
     */
    csArray<pawsIMenuItem*> items;
    
    /**
     * list of open submenus
     */
    csArray<pawsIMenu*> submenus;
    
    /**
     * target of OnMenuAction events
     */
    pawsWidget * notifyTarget;        

    pawsButton * stickyButton, * closeButton;
    pawsTextBox * label;

    pawsImage * arrowImage;    // image of right arrow indicating that menu item invokes a submenu
    
    pawsMenuAlign align;
    
    /**
     * should Autosize() method be used ?
     */
    bool autosize;
    
    /**
     * Is the menu "stickied" on screen ?
     * Stickied menu can only be closed by clicking on the closing button 
     */
    bool sticky;
    
    iGraphics2D * graphics2d;
};

CREATE_PAWS_FACTORY(pawsMenu)

//-----------------------------------------------------------------------------
//                            class pawsMenuItem
//-----------------------------------------------------------------------------

class pawsIMenuItem : public pawsWidget
{
public:
   
    /**
     * Makes the menu item send its menu event,
     */
    virtual void Invoke()
    {
    }

    /**
     * Sets/gets content of event that will be sent when the menu item is invoked.
     */
    virtual void SetAction(const pawsMenuAction & action)
    {
    }
    virtual pawsMenuAction GetAction()
    {
        pawsMenuAction action;
        return action;
    }
};

/**
 * class pawsMenuItem - standard menu item with label, checkbox (optional) and image (optional).
 */
class pawsMenuItem : public pawsIMenuItem
{
public:
    pawsMenuItem();
    
    //from pawsWidget:
    virtual bool Load(iDocumentNode * node);
    virtual bool Setup(iDocumentNode * node);
    virtual void Draw();

    //from pawsIMenuItem:
    virtual void Invoke();
    void SetAction(const pawsMenuAction & action);
    pawsMenuAction GetAction() { return action; }
    
    /**
     * Shows or hides checkbox or image:
     */
    void EnableCheckbox(bool enable);
    void EnableImage(bool enable);
    
    void SetImage(const csString & newImage);
    void SetLabel(const csString & newLabel);
    
    /**
     * Sets names of bitmaps:
     */
    void SetCheckboxImages(const csString & on, const csString & off);
    
    /**
     * Sets state of checkbox (true/false)
     */
    void SetCheckboxState(bool checked);
    
    /**
     * Sets layout values:
     * If labelWidth = -1, then sets width of the label so that the text fits right in.
     */
    void SetSizes(int labelWidth, int spacing, int border);

protected:
    /**
     * Calculates and sets positions of the checkbox, label and image.
     * Then sets the width of the whole menu item.
     */
    void SetLayout();

    /**
     * Reads pawsMenuAction data from XML
     */
    virtual void LoadAction(iDocumentNode * node);


    pawsWidget * image;
    pawsTextBox * label;
    pawsButton * checkbox;
    
    pawsMenuAction action;

    /**
     * Is image/checkbox visible ?
     */
    bool imageEnabled, checkboxEnabled;
    
    /**
     * Horizontal distance between parts of the menu item (image, label, checkbox)
     */
    int spacing;
    
    /**
     * Space between content of the menu item (image, label, checkbox) and border of the item.
     */
    int border;
    
    iGraphics2D * graphics2d;
};

CREATE_PAWS_FACTORY(pawsMenuItem)


//-----------------------------------------------------------------------------
//                            menu separator
//-----------------------------------------------------------------------------

/**
 * pawsMenuSeparator - special menu item that visually splits the menu to more parts.
 * No OnMenuAction() event can be invoked with this menu item.
 */

class pawsMenuSeparator : public pawsIMenuItem
{
public:
    pawsMenuSeparator();
    
    // from pawsWidget:
    virtual void Draw();

protected:
    iGraphics2D * graphics2d;
};

CREATE_PAWS_FACTORY(pawsMenuSeparator)


#endif
