view mde/gui/widget/Ifaces.d @ 78:79a1809421aa

Widget data saving reimplemented for the new data system. (Now grid layout widgets remember their row & column sizes.)
author Diggory Hardy <diggory.hardy@gmail.com>
date Tue, 29 Jul 2008 18:14:53 +0100
parents 3dfd934100f7
children ea58f277f487
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.renderer.IRenderer;


/** Widget ID type. Each ID is unique under this window.
 *
 * Type is int since this is the widget data type. */
alias char[] widgetID;

/** Window coordinate and dimension/size type (int).
 *
 * Used to disambiguate between general integers and coordinates; all widget positions/sizes should
 * use this type (or one of the aliases below).
 * 
 * ---
 * typedef int wdim;    // Declared in IRenderer to avoid a circular import.
 * ---
 * 
 * Aliases of wdim providing extra information about what their contents hold: absolute position,
 * position relative to the containing widget (wdrel should not be used if relative to anything
 * else), or size. Their use instead of wdim is optional (and in some cases wdim values aren't of
 * any of these types). Also don't use these aliases for variables which may also be used to other
 * effects, e.g. if they can have special values with special meanings. */
alias wdim	wdabs;
alias wdim	wdrel;	/// ditto
alias wdim	wdsize;	/// ditto

/** A pair of wdim variables, and strictly no other data (methods may be added if deemed useful).
 *
 * Potentially usable to return two wdim variables, e.g. width and height, from a function.
 * However, the current usage of out variables looks like it's better. */
struct wdimPair {
    wdim x, y;	/// data
}


/*************************************************************************************************
 * 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 : IParentWidget
{
    // Loading/saving:
    /** Create a widget by ID.
     *
     * 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).
     * 
     * Note: this method is only for "named" widgets; generic widgets instanciated in lists are
     * created differently. */
    IChildWidget makeWidget (widgetID id);
    
    /** Record some changes, for saving. */
    void setData (widgetID id, WidgetData);
    
    // 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);
    
    // FIXME: keyboard callback (letter only, for text input? Also used for setting keybindings though...)
    
    /** 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 parent widgets, including the gui manager.
 *
 * A widget may call these methods on its parent, and on the gui manager.
 *************************************************************************************************/
interface IParentWidget : IWidget
{
    // NOTE: Likely some day this interface will really be used.
    // NOTE: What widget is NOT going to implement this? It will probably be inherited.
}


/*************************************************************************************************
 * 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 parent/child widgets as necessary.
 *
 * If a widget is to be creatable by IWidgetManager.makeWidget, it must be listed in the
 * createWidget module, have a constructor of the following form, and should update it's
 * creation data as necessary via 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);
 * ----------------------------------
 * 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.
 *
 * A parent widget is responsible for setting the size of its children widgets, however it must
 * satisfy their minimal sizes as available from minWidth() and minHeight(). setWidth() and
 * setHeight() are called on all widgets after creation.
 *************************************************************************************************/
//NOTE: add another this() without the data for default initialization, for the GUI editor?
interface IChildWidget : IWidget
{
//BEGIN Load and save
    /** 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 (widgetID id);
    
    /** 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?
     *
     * If not, the widget has fixed dimensions equal the output of getMinimalSize. */
    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.
     * 
     * Deprecated: is it needed now?
     */
    deprecated void getCurrentSize (out wdim w, out wdim h);
    
    /** 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.
     *
     * If called with dimensions less than minWidth/minHeight return: the widget may set its size
     * to either the dimension given or its minimal dimension (even though this is larger). If the
     * larger size is set, events won't be received in the extra area. FIXME: sort out rendering.
     * Otherwise, the dimensions should always be set exactly.
     *
     * 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.
     *
     * See mde.input.input.Input.MouseClickCallback for parameters. However, cx and cy are adjusted
     * to the Widget's local coordinates.
     *
     * Widget may assume coordinates are on the widget (caller must check). */
    void clickEvent (wdabs cx, wdabs cy, ubyte b, bool state);
//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 ();
}


/*************************************************************************************************
 * The data type all widgets creatable by the widget manager receive on creation.
 * 
 * Conversion code to/from MT tags is contained in the addTag and writeAll methods of
 * WidgetDataSet and WidgetDataChanges.
 *************************************************************************************************/
struct WidgetData
{
    int[]    ints;
    char[][] strings;
}