view mde/gui/widget/Widget.d @ 41:b3a6ca4516b4

The renderer now controls which parts of the window border allow resizing. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Tue, 13 May 2008 12:02:36 +0100
parents 5132301e9ed7
children 1530d9c04d4d
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/>. */

/// GUI Widget module.
module mde.gui.widget.Widget;

public import mde.gui.widget.Ifaces;
import mde.gui.exception;
import mde.gui.renderer.IRenderer;

import tango.io.Stdout;

/** An abstract base widget class.
*
* This abstract class, and the more concrete FixedWidget and ScalableWidget classes provides a
* useful basic implementation for widgets. Widgets need not inherit these (they only need implement
* IWidget); they are simply provided for convenience and to promote code reuse. */
abstract class Widget : IWidget
{
    // Base this(); all widgets must at least check data.length is correct.
    this (IWindow wind, int[] data) {
        window = wind;
        widgetType = data[0];
    }
    
    // Most widgets don't need to do adjustments based on mutable data, however they usually do
    // still need to set their size.
    int[] adjust (int[] data) {
        setSize (0,0);
        return data;
    }
    
    // Widget type should always be the first value.
    int[] getCreationData () {
        return [widgetType];
    }
    // Most widgets don't use mutable data.
    int[] getMutableData () {
        return [];
    }
    
    void getCurrentSize (out int cw, out int ch) {
        cw = w;
        ch = h;
    }
    
    void setPosition (int nx, int ny) {
        x = nx;
        y = ny;
    }
    
    /* Return self, since we don't have child widgets and the method wouldn't have been called
    * unless the location was over us. Valid for all widgets without children. */
    IWidget getWidget (int,int) {
        return this;
    }
    
    /* Dummy event method (widget doesn't respond to events) */
    void clickEvent (ushort cx, ushort cy, ubyte b, bool state) {}
    
    /* Basic draw method: draw the background (all widgets should do this) */
    void draw () {
        window.renderer.drawWidgetBack (x,y, w,h);
    }
    
protected:
    final int widgetType;   // the type (stored for saving)
    IWindow window;         // the enclosing window
    int x, y;               // position
    int w, h;               // size
}
/** A base for fixed-size widgets. */
class FixedWidget : Widget {
    this (IWindow wind, int[] data) {
        super (wind, data);
        w = wF = data[1];
        h = hF = data[2];
    }
    
    int[] getCreationData () {
        return [widgetType, wF, hF];
    }
    
    bool isWSizable () {    return false;   }
    bool isHSizable () {    return false;   }
    
    /* Not resizable, so return current size. */
    void getMinimalSize (out int mw, out int mh) {
        mw = wF;
        mh = hF;
    }
    
    /* Ignore: a fixed size widget. */
    void setSize (int nw, int nh) {
        w = (nw >= wF ? nw : wF);
        h = (nh >= hF ? nh : hF);
    }
    
protected:
    int wF, hF;             // The "fixed" size, i.e. the preferred & minimal size
}
/** A base for resizable widgets. */
class SizableWidget : Widget {
    this (IWindow wind, int[] data) {
        super (wind, data);
    }
    
    bool isWSizable () {    return true;    }
    bool isHSizable () {    return true;    }
    
    /* Return zero. */
    void getMinimalSize (out int mw, out int mh) {}
    
    /* Set size: a fully resizable widget. */
    void setSize (int nw, int nh) {
        w = (nw >= 0 ? nw : 0);
        h = (nh >= 0 ? nh : 0);
    }
}

//BEGIN Widgets
/// A fixed-size blank widget.
class FixedBlankWidget : FixedWidget
{
    this (IWindow wind, int[] data) {
        if (data.length != 3) throw new WidgetDataException;
        super (wind, data);
    }
}

/// A completely resizable blank widget (initial size zero).
class SizableBlankWidget : SizableWidget
{
    this (IWindow wind, int[] data) {
        if (data.length != 1) throw new WidgetDataException;
        super (wind, data);
    }
}

/// First interactible widget
class ButtonWidget : FixedWidget
{
    bool pushed = false;    // true if button is pushed in (visually)
    // pushed is not the same as the button being clicked but not yet released.
    // it is whether the mouse is over the button after being clicked.
    
    this (IWindow wind, int[] data) {
        if (data.length != 3) throw new WidgetDataException;
        super (wind, data);
    }
    
    void draw () {
        window.renderer.drawButton (x,y, w,h, pushed);
    }
    
    void clickEvent (ushort, ushort, ubyte b, bool state) {
        if (b == 1 && state == true) {
            pushed = true;
            window.requestRedraw;
            window.gui.addClickCallback (&clickWhileHeld);
            window.gui.addMotionCallback (&motionWhileHeld);
        }
    }
    // Called when a mouse motion/click event occurs while (held == true)
    bool clickWhileHeld (ushort cx, ushort cy, ubyte b, bool state) {
        //NOTE: which button? test
        if (cx >= x && cx < x+w && cy >= y && cy < y+h) // button event
            Stdout ("Button clicked!").newline;
        
        pushed = false;
        window.requestRedraw;
        window.gui.removeCallbacks (cast(void*) this);
        
        return false;
    }
    void motionWhileHeld (ushort cx, ushort cy) {
        bool oldPushed = pushed;
        if (cx >= x && cx < x+w && cy >= y && cy < y+h) pushed = true;
        else pushed = false;
        if (oldPushed != pushed)
            window.requestRedraw;
    }
}
//END Widgets