view mde/gui/widget/Ifaces.d @ 91:4d5d53e4f881

Shared alignment for dynamic content lists - finally implemented! Lots of smaller changes too. Some debugging improvements. When multiple .mtt files are read for merging, files with invalid headers are ignored and no error is thrown so long as at least one file os valid.
author Diggory Hardy <diggory.hardy@gmail.com>
date Thu, 16 Oct 2008 17:43:48 +0100
parents b525ff28774b
children 085f2ca31914
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.gui.content.Content; //NOTE - maybe move IContent to a separate module


/*************************************************************************************************
 * 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.
     *  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).
     */
    IChildWidget makeWidget (widgetID id, IContent content = null);
    
    /** Record some changes, for saving. Should only be called from IWidget.saveChanges() to avoid
     * multiple calls for instanced widgets of same id. */
    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 (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.
 *
 * 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). */
    // FIXME - no longer necessary to pass id!
    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?
     *
     * 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.
     * 
     * Note: layout uses these calls to initialize it's alignment device. So, after creating a
     * (layout) widget, minWidth should be the first function called on it! */
    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.
     *
     * 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 ();
}