diff mde/gui/Gui.d @ 34:6b4116e6355c

Work on the Gui: some of the framework for drag & drop. Also made Window an IWidget. Implemented getWidget(x,y) to find the widget under this location for IWidgets (but not Gui). Made Window an IWidget and made it work a little more similarly to widgets. Implemented callbacks on the Gui for mouse events (enabling drag & drop, etc.). committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Fri, 02 May 2008 16:03:52 +0100
parents 316b0230a849
children 928db3c75ed3
line wrap: on
line diff
--- a/mde/gui/Gui.d	Thu May 01 10:55:04 2008 +0100
+++ b/mde/gui/Gui.d	Fri May 02 16:03:52 2008 +0100
@@ -22,6 +22,7 @@
 module mde.gui.Gui;
 
 import mde.gui.IGui;
+import mde.gui.widget.Ifaces;
 import mde.gui.widget.Window;
 import mde.gui.renderer.createRenderer;
 import mde.gui.exception;
@@ -46,9 +47,6 @@
 // Handle externally or with a GUI Manager?
 
 /** A GUI handles a bunch of windows, all to be drawn to the same device. */
-/* NOTE: currently GUI just keeps a list of windows and simply calls draw and clickEvent on them all.
-* Coords should be stored here and draw/clickEvent should be called like for widgets.
-* (Also functionality like z-order?) */
 class Gui : IGui {
     //BEGIN Methods for external use
     //BEGIN Loading code
@@ -62,8 +60,8 @@
         IReader reader;
         try {
             reader = confDir.makeMTReader (fileName, PRIORITY.HIGH_ONLY, null, true);
-            reader.dataSecCreator = delegate mt.IDataSection(mt.ID) {
-                return new Window;
+            reader.dataSecCreator = delegate mt.IDataSection(mt.ID id) {
+                return new Window (id);
             };
             reader.read;
         } catch (mt.MTException e) {
@@ -105,18 +103,35 @@
     * Currently no concept of how to draw overlapping windows, or how to not bother drawing windows
     * which don't need redrawing. */
     void draw() {
-        foreach (w; windows)
-            w.draw();
+        foreach_reverse (w; windows)    // Draw, starting with back-most window.
+            w.draw;
     }
     
-    /** Send an input event.
+    /** For mouse click events.
     *
-    * I.e. send all mouse click events to all active GUIs, which check the coordinates and forward
-    * to any relevent windows. */
+    * Sends the event on to the relevant windows and all click callbacks. */
     void clickEvent (ushort cx, ushort cy, ubyte b, bool state) {
-        foreach (w; windows)
-            w.clickEvent (cx,cy,b,state);
+        // NOTE: buttons receive the up-event even when drag-callbacks are in place.
+        foreach (dg; clickCallbacks)
+            dg (cx, cy, b, state);
+        
+        foreach (w; windows) {
+            IWidget widg = w.getWidget (cx,cy);
+            if (widg !is null) {
+                widg.clickEvent (cx,cy,b,state);
+                return;     // only pass to first window
+            }
+        }
     }
+    
+    /** For mouse motion events.
+    *
+    * Sends the event on to all motion callbacks. */
+    void motionEvent (ushort cx, ushort cy) {
+        foreach (dg; motionCallbacks)
+            dg (cx, cy);
+    }
+    
     //END Methods for external use
     
     //BEGIN IGui methods
@@ -126,9 +141,23 @@
     } body {
         return rend;
     }
+    
+    void addClickCallback (void delegate(ushort, ushort, ubyte, bool) dg) {
+        clickCallbacks[dg.ptr] = dg;
+    }
+    void addMotionCallback (void delegate(ushort, ushort) dg) {
+        motionCallbacks[dg.ptr] = dg;
+    }
+    void removeCallbacks (void* frame) {
+        clickCallbacks.remove(frame);
+        motionCallbacks.remove(frame);
+    }
     //END IGui methods
     
 private:
-    Window[] windows;
+    Window[] windows;   // Windows. First window is "on top", others may be obscured.
     IRenderer rend;
+    // callbacks indexed by their frame pointers:
+    void delegate(ushort cx, ushort cy, ubyte b, bool state) [void*] clickCallbacks;
+    void delegate(ushort cx, ushort cy) [void*] motionCallbacks;
 }