view mde/gui/widget/Ifaces.d @ 105:08651e8a8c51

Quit button, big changes to content system. Moved mde.gui.content to mde.content to reflect it's not only used by the gui. Split Content module into Content and AStringContent. New AContent and EventContent class. Callbacks are now generic and implemented in AContent. Renamed TextContent to StringContent and ValueContent to AStringContent.
author Diggory Hardy <diggory.hardy@gmail.com>
date Sat, 29 Nov 2008 12:36:39 +0000
parents 42e241e7be3e
children c9fc2d303178
line wrap: on
line source

/* LICENSE BLOCK
Part of mde: a Modular D game-oriented Engine
Copyright © 2007-2008 Diggory Hardy

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, either
version 2 of the License, or (at your option) any later version.

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, see <http://www.gnu.org/licenses/>. */

/*************************************************************************************************
 * Widget interfaces.
 *
 * Widgets are connected as the nodes of a tree. Widgets know their parent as a IParentWidget
 * class and their children as IChildWidget classes. The gui manager is a special widget only
 * implementing IParentWidget; all other widgets must implement IChildWidget and optionally
 * IParentWidget.
 *************************************************************************************************/
module mde.gui.widget.Ifaces;

public import mde.gui.types;
public import mde.gui.renderer.IRenderer;
import mde.content.Content;


/*************************************************************************************************
 * Common interface for all widgets.
 *
 * Notation:
 *  Positive/negative direction: along the x/y axis in this direction.
 *  Layout widget: a widget containing multiple sub-widges (which hence controls how they are
 *  laid out).
 *************************************************************************************************/
//NOTE: keep this?
interface IWidget
{
}


/*************************************************************************************************
 * Interface for the widget manager.
 * 
 * This class handles widget rendering, input, loading and saving.
 *************************************************************************************************/
interface IWidgetManager : IWidget
{
    // Loading/saving:
    /** Create a widget by ID.
     *
     * Params:
     *  id      = Identifier, within data files, of the data for the widget.
     *  data    = Pass this data to the widget, not data looked up via id.
     *  content = An IContent may be passed to some widgets on creation.
     *
     * Creates a widget, using the widget data with index id. Widget data is loaded from files,
     * and per design (multiple gui layouts, called designs, may exist; data is per design).
     * 
     * The function taking a WidgetData is intended for modifier functions and only exists to
     * avoid circular dependencies between the modifier function's module and createWidget. */
    IChildWidget makeWidget (widgetID id, IContent content = null);
    IChildWidget makeWidget (widgetID id, WidgetData data, IContent content = null);
    
    /** Get dimension data for a widget. */
    wdims dimData (widgetID id);
    
    /** Record some changes, for saving. Should only be called from IWidget.saveChanges() to avoid
     * multiple calls for instanced widgets of same id.
     * 
     * WidgetData is for most data, dimensional data (wdims) is for dimensions. */
    void setData (widgetID id, WidgetData);
    void setDimData (widgetID id, wdims d);     /// ditto
    
    // Rendering:
    /** For when a widget needs redrawing.
     * 
     * Must be called because rendering may only be done on events.
     * 
     * Currently it just causes everything to be redrawn next frame. */
    void requestRedraw ();
    
    /** Get the window's renderer.
    *
    * Normally specific to the GUI, but widgets have no direct contact with the GUI and this
    * provides the possibility of per-window renderers (if desired). */
    IRenderer renderer ();
    
    
    // User input:
    /** Add a mouse click callback.
     * 
     * This is a delegate this will be called for all mouse click events recieved by the gui, not
     * simply all click events on the widget (as clickEvent recieves).
     *
     * The delegate should return true if it accepts the event and no further processing is
     * required (i.e. the event should not be handled by anything else), false otherwise.
     * 
     * Note that this is not a mechanism to prevent unwanted event handling, and in the future
     * may be removed (so event handling cannot be cut short). */
    void addClickCallback (bool delegate (wdabs cx, wdabs cy, ubyte b, bool state) dg);
    
    /** Add a mouse motion callback: delegate will be called for all motion events recieved by the
     * gui. */
    void addMotionCallback (void delegate (wdabs cx, wdabs cy) dg);
    
    /** Remove all event callbacks on this widget (according to the delegate's .ptr). */
    // Note: don't try to pass a reference and cast to void* in the function; it's a different address.
    void removeCallbacks (void* frame);
}


/*************************************************************************************************
 * Interface for (child) widgets, i.e. all widgets other than the manager.
 *
 * A widget is a region of a GUI window which handles rendering and user-interaction for itself
 * and is able to communicate with its manager and child widgets as necessary. (Passing widgets
 * a reference to their parent has not been found useful.)
 *
 * If a widget is to be creatable by IWidgetManager.makeWidget, it must be listed in the
 * createWidget module, and have a constructor of the following form. It should also update it's
 * creation data if necessary, either when changed or when saveChanges() is called, using
 * IWidgetManager.setData().
 * It should use Ddoc to explain what initialization data is used.
 * ----------------------------------
 * /++ Constructor for a ... widget.
 *  +
 *  + Widget uses the initialisation data:
 *  + [widgetID, x, y]
 *  + where x is ... and y is ... +/
 * this (IWidgetManager mgr, WidgetData data);
 * 
 * /// The CTOR may take an IContent reference:
 * this (IWidgetManager mgr, WidgetData data, IContent content);
 * ----------------------------------
 * Where mgr is the widget manager and data is
 * initialisation data. The method should throw a WidgetDataException (created without
 * parameters) if the data has wrong length or is otherwise invalid.
 *
 * All widgets should set their own size in this() or finalize(), although some parents may set
 * child-widgets' size during their creation. Widgets may rely on setPosition() being called after
 * finalize().
 * 
 * Also see finalize().
 *************************************************************************************************/
//NOTE: add another this() without the data for default initialization, for the GUI editor?
interface IChildWidget : IWidget
{
//BEGIN Load and save
    // NOTE - change?
    /** Called on all widgets after all widgets have been created in a deepest first order.
     *
     * finalize must be called before any other methods on the widget, which means this() cannot
     * call sub-widgets' methods, but finalize() can. */
    void prefinalize ();
    void finalize ();   /// ditto
    
    /** Widget should return a list of all its children. */
    IChildWidget[] children ();
    
    /** When this is called, if the widget has any changed data to save it should call
     * IWidgetManager.setData (id, data) to set it and return true. Otherwise it should return
     * false.
     * 
     * If the widget has subwidgets, it should also be recursively called on these (passing their 
     * ids). */
    bool saveChanges ();
    
    /** Called when the renderer is changed (at least when the changes affect dimensions).
     * Also called after widget creation, before any other methods are called.
     * 
     * Returns: true when widget's dimensions (may) have changed.
     * 
     * Should be propegated down to all child widgets. */
    bool rendererChanged ();
    
    /+ Use when widget editing is available? Requires widgets to know their parents.
    /** Called when a child widget's size has changed.
     * 
     * Should be propegated up to parents. */
    void childChanged ();
    +/
//END Load and save
    
//BEGIN Size and position
    /** Is the width / height resizable?
     *
     * This really means does the widget benifit from being enlarged? Any widget should occupy
     * additional area when expanded.
     *
     * If not, the widget has fixed dimensions equal to it's minimal size. */
    bool isWSizable ();
    bool isHSizable (); /// ditto
    
    /** The minimal size the widget could be shrunk to (or its fixed size).
     *
     * Takes into account child-widgets and any other contents. */
    wdim minWidth ();
    wdim minHeight ();	/// ditto
    
    /** Get the current size of the widget. */
    wdim width ();
    wdim height();      /// ditto
    
    /** Used to adjust the size.
     *
     * Params:
     *  nw/nh	= The new width/height
     *  dir	= Direction to resize from. This is only really applicable to layout widgets.
     *  	  It must be either -1 (start resizing from highest row/col index, decreasing the
     *  	  index as necessary), or +1 (resize from the lowest index, i.e. 0).
     *  	  Most widgets can simply ignore it.
     *
     * A widget should never be resized smaller than it's minimal size (if it is, it should assume
     * it's minimal size and print a warning when in debug mode).
     * A "fixed" size widget should enlarge itself as requested.
     *
     * setPosition must be called after calling either setWidth or setHeight. */
    void setWidth (wdim nw, int dir);
    void setHeight (wdim nh, int dir);	/// ditto
    
    /** Set the current position (i.e. called on init and move). */
    void setPosition (wdim x, wdim y);
//END Size and position
    
//BEGIN Events
    /** Recursively scan the widget tree to find the widget under (x,y).
     *
     * If called on a widget, that widget should assume the location is over itself, and so should
     * either return itself or the result of calling getWidget on the appropriate child widget.
     *
     * In the case of Window this may not be the case; it should check and return null if not under
     * (x,y).
     *
     * Note: use global coordinates (x,y) not coordinates relative to the widget. */
    IChildWidget getWidget (wdim x, wdim y);
    
    /** Receive a mouse click event at cx,cy from button b (1-5 correspond to L,M,B, wheel up,down)
     * which is a down-click if state is true.
     *
     * Widget may assume coordinates are on the widget (caller must check).
     *
     * The return value has the following flags: 1 to request keyboard input. */
    int clickEvent (wdabs cx, wdabs cy, ubyte b, bool state);
    
    /** Receives keyboard events when requested.
     *
     * Params:
     *	sym	SDLKey key sym, useful for keys with no character code such as arrow keys
     *	letter	The character input, in UTF-8 */
    void keyEvent (ushort sym, char[] letter);
    
    /** Called when keyboard input focus is lost. */
    void keyFocusLost ();
//END Events
    
    /** Draw, using the stored values of x and y.
     *
     * Maybe later enforce clipping of all sub-widget drawing, particularly for cases where only
     * part of the widget is visible: scroll bars or a hidden window. */
    void draw ();
}