Mercurial > projects > mde
comparison mde/gui/WMScreen.d @ 131:9cff74f68b84
Major revisions to popup handling. Buttons can close menus now, plus some smaller impovements. Removed Widget module.
Moved Widget.AWidget to AChildWidget.AChildWidget and Widget.AParentWidget to AParentWidget.AParentWidget.
Removed ASingleParentWidget to improve code sharing.
AChildWidget doesn't implement IParentWidget like AWidget did.
New IPopupParentWidget extending IParentWidget for the WM and some widgets to handle popups.
Cut old popup management code.
New underMouse() function replacing highlight(); called on all widgets.
Separate menu-popup and button widgets aren't needed for menus now.
Functions returning content widgets have been moved to their own module.
Cleaned up jobs.txt.
Switched to 80 line length for Ddoc.
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Wed, 21 Jan 2009 13:01:40 +0000 |
parents | 41582439a42b |
children | 264028f4115a |
comparison
equal
deleted
inserted
replaced
130:c5c38eaadb64 | 131:9cff74f68b84 |
---|---|
11 See the GNU General Public License for more details. | 11 See the GNU General Public License for more details. |
12 | 12 |
13 You should have received a copy of the GNU General Public License | 13 You should have received a copy of the GNU General Public License |
14 along with this program. If not, see <http://www.gnu.org/licenses/>. */ | 14 along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
15 | 15 |
16 /************************************************************************************************* | 16 /****************************************************************************** |
17 * A gui manager class using mde.setup.Screen and mde.input.Input. | 17 * A gui manager class using mde.setup.Screen and mde.input.Input. |
18 * | 18 * |
19 * This is the module to use externally to create a graphical user interface (likely also with | 19 * This is the module to use externally to create a graphical user interface |
20 * content modules). | 20 * (likely also with content modules). |
21 *************************************************************************************************/ | 21 *****************************************************************************/ |
22 module mde.gui.WMScreen; | 22 module mde.gui.WMScreen; |
23 | 23 |
24 import mde.gui.WidgetManager; | 24 import mde.gui.WidgetManager; |
25 import mde.gui.widget.Ifaces; | 25 import mde.gui.widget.Ifaces; |
26 import mde.gui.renderer.createRenderer; | 26 import mde.gui.renderer.createRenderer; |
32 private Logger logger; | 32 private Logger logger; |
33 static this () { | 33 static this () { |
34 logger = Log.getLogger ("mde.gui.WMScreen"); | 34 logger = Log.getLogger ("mde.gui.WMScreen"); |
35 } | 35 } |
36 | 36 |
37 /************************************************************************************************* | 37 /****************************************************************************** |
38 * The widget manager. | 38 * The widget manager. |
39 * | 39 * |
40 * This provides a layer on top of WidgetLoader, handling input and rendering. Other functionality | 40 * This provides a layer on top of WidgetLoader, handling input and rendering. |
41 * is contained in the super class, to simplify supporting new input/graphics libraries. | 41 * Other functionality is contained in the super class, to simplify supporting |
42 * new input/graphics libraries. | |
42 * | 43 * |
43 * Currently mouse coordinates are passed to widgets untranslated. It may make sense to translate | 44 * Currently mouse coordinates are passed to widgets untranslated. It may make |
44 * them and possibly drop events for some uses, such as if the gui is drawn to a texture. | 45 * sense to translate them and possibly drop events for some uses, such as if |
46 * the gui is drawn to a texture. | |
45 * | 47 * |
46 * Aside from the IWidgetManager methods, this class should be thread-safe. | 48 * Public non IWidget* methods should be thread-safe. |
47 *************************************************************************************************/ | 49 *****************************************************************************/ |
48 scope class WMScreen : AWidgetManager, Screen.IDrawable { | 50 scope class WMScreen : AWidgetManager, Screen.IDrawable { |
49 /** Construct a new widget manager. | 51 /** Construct a new widget manager. |
50 * | 52 * |
51 * Must be run after static this. | 53 * Must be run after static this. |
52 * | 54 * |
66 /** Draw the gui. */ | 68 /** Draw the gui. */ |
67 void draw() { | 69 void draw() { |
68 synchronized(mutex) { | 70 synchronized(mutex) { |
69 if (child) | 71 if (child) |
70 child.draw; | 72 child.draw; |
71 foreach (popup; popups) | 73 if (childIPPW) |
72 popup.widget.draw(); | 74 childIPPW.drawPopup; |
73 } | 75 } |
74 } | 76 } |
75 | 77 |
76 /** For mouse click events. | 78 /** For mouse click events. |
77 * | 79 * |
83 scope(exit) mutex.unlock; | 85 scope(exit) mutex.unlock; |
84 if (child is null) return; | 86 if (child is null) return; |
85 | 87 |
86 wdabs cx = cast(wdabs) usx, cy = cast(wdabs) usy; | 88 wdabs cx = cast(wdabs) usx, cy = cast(wdabs) usy; |
87 | 89 |
88 // 1. Callbacks have the highest priority recieving events (e.g. a button release) | 90 // Callbacks have the highest priority receiving events (e.g. a button release) |
89 foreach (dg; clickCallbacks) | 91 foreach (dg; clickCallbacks) |
90 if (dg (cx, cy, b, state)) return; | 92 if (dg (cx, cy, b, state)) return; |
91 | 93 |
92 // 2. Then pop-ups: close from top, depending on click pos | 94 // Update underMouse to get the widget clicked on |
93 // Note: assumes each evaluated popup's parent is not under another still open popup. | 95 updateUnderMouse (cx, cy, state); |
94 // Also assumes popup's parent doesn't have other children in its box. | |
95 size_t removeTo = popups.length; | |
96 bool eventDone; // don't pass clickEvent | |
97 IChildWidget widg; // widget clicked on | |
98 foreach_reverse (i,popup; popups) with (popup) { | |
99 if (cx < x || cx >= x + w || | |
100 cy < y || cy >= y + h) { // on popup | |
101 if (parent.onSelf (cx, cy)) { | |
102 if (parent.popupParentClick()) removeTo = i; | |
103 eventDone = true; | |
104 break; | |
105 } else { | |
106 removeTo = i; | |
107 parent.popupClose; | |
108 } | |
109 } else { | |
110 widg = widget.getWidget (cast(wdabs)cx,cast(wdabs)cy); | |
111 break; | |
112 } | |
113 } | |
114 if (removeTo < popups.length) { | |
115 requestRedraw; | |
116 popups = popups[0..removeTo]; | |
117 } | |
118 if (eventDone) | |
119 return; | |
120 | 96 |
121 // 3. Then the main widget tree | 97 // Disable keyboard input if on another widget: |
122 debug assert (cx < child.width && cy < child.height, "WidgetManager: child doesn't cover whole area (code error)"); | 98 if (keyFocus && keyFocus !is underMouse) { |
123 if (widg is null) | |
124 widg = child.getWidget (cast(wdabs)cx,cast(wdabs)cy); | |
125 if (keyFocus && keyFocus !is widg) { | |
126 keyFocus.keyFocusLost; | 99 keyFocus.keyFocusLost; |
127 keyFocus = null; | 100 keyFocus = null; |
128 imde.input.setLetterCallback (null); | 101 imde.input.setLetterCallback (null); |
129 } | 102 } |
130 if (widg !is null) { | 103 // Finally, post the actual event: |
131 if (widg.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state) & 1) { | 104 if (underMouse.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state) & 1) { |
132 keyFocus = widg; | 105 // keyboard input requested |
133 imde.input.setLetterCallback (&widg.keyEvent); | 106 keyFocus = underMouse; |
134 } | 107 imde.input.setLetterCallback (&underMouse.keyEvent); |
135 } | 108 } |
136 } | 109 } |
137 | 110 |
138 /** For mouse motion events. | 111 /** For mouse motion events. |
139 * | 112 * |
140 * Sends the event on to all motion callbacks. */ | 113 * Sends the event on to all motion callbacks. */ |
144 mutex.lock; | 117 mutex.lock; |
145 scope(exit) mutex.unlock; | 118 scope(exit) mutex.unlock; |
146 wdabs cx = cast(wdabs) scx, cy = cast(wdabs) scy; | 119 wdabs cx = cast(wdabs) scx, cy = cast(wdabs) scy; |
147 foreach (dg; motionCallbacks) | 120 foreach (dg; motionCallbacks) |
148 dg (cx, cy); | 121 dg (cx, cy); |
149 | 122 |
150 IChildWidget ohighlighted = highlighted; | 123 updateUnderMouse (cx, cy, false); |
151 foreach_reverse (popup; popups) with (popup) { | |
152 if (cx >= x && cx < x+w && cy >= y && cy < y+h) { | |
153 highlighted = widget.getWidget (cx,cy); | |
154 goto foundPopup; | |
155 } | |
156 } | |
157 highlighted = null; // not over a popup | |
158 foundPopup: | |
159 if (ohighlighted != highlighted) { | |
160 if (ohighlighted) | |
161 ohighlighted.highlight (false); | |
162 if (highlighted) | |
163 highlighted.highlight (true); | |
164 requestRedraw; | |
165 } | |
166 } | 124 } |
167 | 125 |
168 | 126 |
169 void sizeEvent (int nw, int nh) { // IDrawable function | 127 void sizeEvent (int nw, int nh) { // IDrawable function |
170 mutex.lock; | 128 mutex.lock; |
193 * Note: sizeEvent should be called with window size before this. */ | 151 * Note: sizeEvent should be called with window size before this. */ |
194 final override void createRootWidget () { | 152 final override void createRootWidget () { |
195 // The renderer needs to be created on the first load, but not after this. | 153 // The renderer needs to be created on the first load, but not after this. |
196 if (rend is null) | 154 if (rend is null) |
197 rend = createRenderer (rendName); | 155 rend = createRenderer (rendName); |
198 popups = null; | |
199 | 156 |
200 debug (mdeWidgets) logger.trace ("Creating root widget..."); | 157 debug (mdeWidgets) logger.trace ("Creating root widget..."); |
201 child = makeWidget (this, "root"); | 158 child = makeWidget (this, "root"); |
202 debug (mdeWidgets) logger.trace ("Setting up root widget..."); | 159 debug (mdeWidgets) logger.trace ("Setting up root widget..."); |
203 child.setup (0, 3); | 160 child.setup (0, 3); |