Changeset 34:6b4116e6355c
- Timestamp:
- 05/02/08 11:03:52 (8 months ago)
- Files:
-
- codeDoc/gui/GUI notes.txt (modified) (1 diff)
- codeDoc/jobs.txt (modified) (2 diffs)
- data/conf/gui.mtt (modified) (1 diff)
- mde/gl/basic.d (modified) (1 diff)
- mde/gui/Gui.d (modified) (5 diffs)
- mde/gui/IGui.d (modified) (1 diff)
- mde/gui/widget/Ifaces.d (modified) (6 diffs)
- mde/gui/widget/Widget.d (modified) (8 diffs)
- mde/gui/widget/Window.d (modified) (8 diffs)
- mde/gui/widget/createWidget.d (modified) (1 diff)
- mde/gui/widget/layout.d (modified) (5 diffs)
- mde/input/Input.d (modified) (17 diffs)
- mde/scheduler/init2.d (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
codeDoc/gui/GUI notes.txt
r33 r34 18 18 -> Text rendering 19 19 -> text library? 20 -> Drag & drop 21 -> click/drag start triggers a callback on the widget 22 -> when button is released, callback: 23 -> finds release location 24 -> checks if this is a valid drop target 25 -> if so, acts on it 20 26 21 27 codeDoc/jobs.txt
r33 r34 4 4 5 5 In progress: 6 FreeType implementing...7 6 8 7 … … 50 49 51 50 Done (for git log message): 52 Lots of changes to the GUI. Renderer is now used exclusively for rendering and WidgetDecoration is gone. 53 Renamed lots of files to conform to case policies. 51 Implemented getWidget(x,y) to find the widget under this location for IWidgets (but not Gui). 52 Made Window an IWidget and made it work a little more similarly to widgets. 53 Implemented callbacks on the Gui for mouse events (enabling drag & drop, etc.). data/conf/gui.mtt
r32 r34 2 2 <char[]|Renderer="Simple"> 3 3 {W1} 4 <int|x= 0>5 <int|y= 0>4 <int|x=30> 5 <int|y=80> 6 6 <int[][int]|widgetData=[0:[1003,200,200]]> 7 7 {W2} 8 8 <int|x=150> 9 9 <int|y=200> 10 <int[][int]|widgetData=[0:[1002, 3,2,2,2,3,3,2,5],2:[1001,150,150],3:[1003,150,150],5:[1002,2,2,6,6,6,6],6:[1003,73,73]]>10 <int[][int]|widgetData=[0:[1002,1,3,2,3,5],2:[1001,150,150],3:[1003,150,150],5:[1002,2,1,6,7],6:[1003,73,73],7:[1003,73,73]]> mde/gl/basic.d
r31 r34 50 50 } 51 51 void drawBox (int x, int y, int w, int h) { 52 glBegin (GL_QUADS); 53 { 54 glVertex2i (x, y+h); 55 glVertex2i (x+w, y+h); 56 glVertex2i (x+w, y); 57 glVertex2i (x, y); 58 } 59 glEnd(); 52 glRecti(x, y+h, x+w, y); 60 53 } 61 54 //END Drawing utils mde/gui/Gui.d
r32 r34 23 23 24 24 import mde.gui.IGui; 25 import mde.gui.widget.Ifaces; 25 26 import mde.gui.widget.Window; 26 27 import mde.gui.renderer.createRenderer; … … 47 48 48 49 /** A GUI handles a bunch of windows, all to be drawn to the same device. */ 49 /* NOTE: currently GUI just keeps a list of windows and simply calls draw and clickEvent on them all.50 * Coords should be stored here and draw/clickEvent should be called like for widgets.51 * (Also functionality like z-order?) */52 50 class Gui : IGui { 53 51 //BEGIN Methods for external use … … 63 61 try { 64 62 reader = confDir.makeMTReader (fileName, PRIORITY.HIGH_ONLY, null, true); 65 reader.dataSecCreator = delegate mt.IDataSection(mt.ID ) {66 return new Window ;63 reader.dataSecCreator = delegate mt.IDataSection(mt.ID id) { 64 return new Window (id); 67 65 }; 68 66 reader.read; … … 106 104 * which don't need redrawing. */ 107 105 void draw() { 108 foreach (w; windows)109 w.draw ();106 foreach_reverse (w; windows) // Draw, starting with back-most window. 107 w.draw; 110 108 } 111 109 112 /** Send an input event.110 /** For mouse click events. 113 111 * 114 * I.e. send all mouse click events to all active GUIs, which check the coordinates and forward 115 * to any relevent windows. */ 112 * Sends the event on to the relevant windows and all click callbacks. */ 116 113 void clickEvent (ushort cx, ushort cy, ubyte b, bool state) { 117 foreach (w; windows) 118 w.clickEvent (cx,cy,b,state); 114 // NOTE: buttons receive the up-event even when drag-callbacks are in place. 115 foreach (dg; clickCallbacks) 116 dg (cx, cy, b, state); 117 118 foreach (w; windows) { 119 IWidget widg = w.getWidget (cx,cy); 120 if (widg !is null) { 121 widg.clickEvent (cx,cy,b,state); 122 return; // only pass to first window 123 } 124 } 119 125 } 126 127 /** For mouse motion events. 128 * 129 * Sends the event on to all motion callbacks. */ 130 void motionEvent (ushort cx, ushort cy) { 131 foreach (dg; motionCallbacks) 132 dg (cx, cy); 133 } 134 120 135 //END Methods for external use 121 136 … … 127 142 return rend; 128 143 } 144 145 void addClickCallback (void delegate(ushort, ushort, ubyte, bool) dg) { 146 clickCallbacks[dg.ptr] = dg; 147 } 148 void addMotionCallback (void delegate(ushort, ushort) dg) { 149 motionCallbacks[dg.ptr] = dg; 150 } 151 void removeCallbacks (void* frame) { 152 clickCallbacks.remove(frame); 153 motionCallbacks.remove(frame); 154 } 129 155 //END IGui methods 130 156 131 157 private: 132 Window[] windows; 158 Window[] windows; // Windows. First window is "on top", others may be obscured. 133 159 IRenderer rend; 160 // callbacks indexed by their frame pointers: 161 void delegate(ushort cx, ushort cy, ubyte b, bool state) [void*] clickCallbacks; 162 void delegate(ushort cx, ushort cy) [void*] motionCallbacks; 134 163 } mde/gui/IGui.d
r32 r34 14 14 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 15 16 module mde.gui.IGui; 17 18 public import mde.gui.renderer.IRenderer; 19 16 20 /** The Gui interface. 17 21 * 18 22 * This contains the functions for use by Windows, not those for external use (use Gui directly for 19 23 * that). */ 20 module mde.gui.IGui;21 22 public import mde.gui.renderer.IRenderer;23 24 24 interface IGui 25 25 { 26 26 /** Get the Gui's renderer. May be overriden by the window. */ 27 27 IRenderer renderer (); 28 29 /** Add a mouse click callback: delegate will be called for all mouse click events recieved. */ 30 void addClickCallback (void delegate (ushort cx, ushort cy, ubyte b, bool state) dg); 31 /** Add a mouse motion callback: delegate will be called for all motion events recieved. */ 32 void addMotionCallback (void delegate (ushort cx, ushort cy) dg); 33 /** Remove all event callbacks with _frame pointer frame. */ 34 void removeCallbacks (void* frame); 28 35 } mde/gui/widget/Ifaces.d
r32 r34 18 18 19 19 public import mde.gui.renderer.IRenderer; 20 import mde.gui.IGui; 20 21 21 22 /** Interface for Window, allowing widgets to call some of Window's methods. 22 23 * 23 24 * Contains the methods in Window available for widgets to call on their root. */ 24 interface IWindow : I ParentWidget25 interface IWindow : IWidget 25 26 { 26 27 /** Widget ID type. Each ID is unique under this window. … … 32 33 * 33 34 * Returns the widget with the given ID from the Window's widget list. If the widget hasn't yet 34 * been created, creates it using the Window's widget creation data (throws on error; don't 35 * catch the exception). */ 36 IWidget getWidget (widgetID i, IParentWidget parent); 35 * been created, creates it using the Window's widget creation data. 36 * 37 * Widgets should never be used more than once (must have a unique parent and position!), and 38 * this function is only intended for widgets to get child-widgets, hence a warning is logged 39 * if a widget is asked for more than once. */ 40 //NOTE: possibly revise: parent isn't actually used any more 41 IWidget makeWidget (widgetID i, IWidget parent); 42 43 /** Get the managing Gui. */ 44 IGui gui (); 37 45 38 46 /+ Currently draw-on-event isn't used. … … 48 56 } 49 57 50 /** Methods exposed by both Window and Widgets which widgets can call on a parent. */51 interface IParentWidget52 {53 }54 55 58 /** Interface for widgets. 56 59 * … … 63 66 * A widget's constructor should have this prototype: 64 67 * ---------------------------------- 65 * this (IWindow window, I ParentWidget parent, int[] data);68 * this (IWindow window, IWidget parent, int[] data); 66 69 * ---------------------------------- 67 70 * Where window is the root window (the window to which the widget belongs), parent is the parent … … 69 72 * WidgetDataException (created without parameters) if the data has wrong length or is otherwise 70 73 * invalid. */ 71 interface IWidget : IParentWidget74 interface IWidget 72 75 { 73 /** Draw, starting from given x and y. 76 /** Calculate the minimum size the widget could be shrunk to, taking into account 77 * child-widgets. */ 78 void getMinimumSize (out int w, out int h); 79 80 /** Get the current size of the widget. 74 81 * 75 * Maybe later enforce clipping of all sub-widget drawing, particularly for cases where only 76 * part of the widget is visible: scroll bars or a hidden window. */ 77 void draw (int x, int y); 82 * On the first call (during loading), this may be a value saved as part of the config or 83 * something else (e.g. revert to getMinimumSize). */ 84 void getCurrentSize (out int w, out int h); 85 86 /** Set the current position (i.e. called on init and move). */ 87 void setPosition (int x, int y); 88 89 /** Recursively scan the widget tree to find the widget under (x,y). 90 * 91 * If called on a widget, that widget should assume the location is over itself, and so should 92 * either return itself or the result of calling getWidget on the appropriate child widget. 93 * 94 * In the case of Window this may not be the case; it should check and return null if not under 95 * (x,y). 96 * 97 * Note: use global coordinates (x,y) not coordinates relative to the widget. */ 98 IWidget getWidget (int x, int y); 78 99 79 100 /** Receive a mouse click event. … … 85 106 void clickEvent (ushort cx, ushort cy, ubyte b, bool state); 86 107 87 /** Calculate the minimum size the widget could be shrunk to, taking into account 88 * child-widgets. */ 89 void getMinimumSize (out int w, out int h); 90 91 /** Get the current size of the widget. 108 /** Draw, using the stored values of x and y. 92 109 * 93 * On the first call (during loading), this may be a value saved as part of the config or94 * something else (e.g. revert to getMinimumSize). */95 void getCurrentSize (out int w, out int h);110 * Maybe later enforce clipping of all sub-widget drawing, particularly for cases where only 111 * part of the widget is visible: scroll bars or a hidden window. */ 112 void draw (); 96 113 } mde/gui/widget/Widget.d
r32 r34 18 18 19 19 public import mde.gui.widget.Ifaces; 20 import mde.gui.IGui; 20 21 import mde.gui.exception; 21 22 … … 31 32 class Widget : IWidget 32 33 { 33 /** Basic draw method: draw the background */34 void draw (int x, int y) {35 window.renderer.drawWidgetBack (x,y, w,h);36 }37 38 /** Dummy event method (ignore) */39 void clickEvent (ushort cx, ushort cy, ubyte b, bool state) {}40 41 34 /** Minimum size is zero. */ 42 35 void getMinimumSize (out int w, out int h) {} // w,h initialised to 0 … … 47 40 } 48 41 42 void setPosition (int x, int y) { 43 this.x = x; 44 this.y = y; 45 } 46 47 /** Return self, since we don't have child widgets and the method wouldn't have been called 48 * unless the location was over us. Valid for all widgets without children. */ 49 IWidget getWidget (int,int) { 50 return this; 51 } 52 53 /** Dummy event method (widget doesn't respond to events) */ 54 void clickEvent (ushort cx, ushort cy, ubyte b, bool state) {} 55 56 /** Basic draw method: draw the background (all widgets should do this) */ 57 void draw () { 58 window.renderer.drawWidgetBack (x,y, w,h); 59 } 60 49 61 protected: 50 62 IWindow window; // the enclosing window 63 int x, y; // position 51 64 int w, h; // size 52 65 } … … 56 69 class BoxWidget : Widget 57 70 { 58 this (IWindow wind, I ParentWidget, int[] data) {71 this (IWindow wind, IWidget, int[] data) { 59 72 if (data.length != 2) throw new WidgetDataException; 60 73 … … 64 77 h = data[1]; 65 78 } 66 void draw ( int x, int y) {79 void draw () { 67 80 gl.setColor(1f,0f,0f); 68 81 window.renderer.drawBox (x,y, w,h); … … 73 86 class ButtonWidget : Widget 74 87 { 75 bool pushed = false;// true if button is pushed in 88 bool pushed = false; // true if button is pushed in (visually) 89 // pushed is not the same as the button being clicked but not yet released. 90 // it is whether the mouse is over the button after being clicked. 76 91 77 this (IWindow wind, I ParentWidget, int[] data) {92 this (IWindow wind, IWidget, int[] data) { 78 93 if (data.length != 2) throw new WidgetDataException; 79 94 … … 84 99 } 85 100 86 void draw ( int x, int y) {101 void draw () { 87 102 if (pushed) 88 103 gl.setColor (1f, 0f, 1f); … … 98 113 99 114 void clickEvent (ushort, ushort, ubyte b, bool state) { 100 if (b == 1) pushed = state; // very basic 115 if (b == 1 && state == true) { 116 pushed = true; 117 window.gui.addClickCallback (&clickWhileHeld); 118 window.gui.addMotionCallback (&motionWhileHeld); 119 } 120 } 121 // Called when a mouse motion/click event occurs while (held == true) 122 void clickWhileHeld (ushort cx, ushort cy, ubyte b, bool state) { 123 if (cx >= x && cx < x+w && cy >= y && cy < y+h) // button event 124 Stdout ("Button clicked!").newline; 125 126 pushed = false; 127 window.gui.removeCallbacks (cast(void*) this); 128 } 129 void motionWhileHeld (ushort cx, ushort cy) { 130 if (cx >= x && cx < x+w && cy >= y && cy < y+h) pushed = true; 131 else pushed = false; 101 132 } 102 133 } mde/gui/widget/Window.d
r32 r34 28 28 // not yet implemented: 29 29 //import tango.scrapple.text.convert.parseFrom : parseFrom; 30 31 import tango.util.log.Log : Log, Logger; 32 33 private Logger logger; 34 static this () { 35 logger = Log.getLogger ("mde.gui.widget.Window"); 36 } 30 37 31 38 /** GUI Window class … … 40 47 { 41 48 //BEGIN Methods for GUI 49 this (char[] id) { 50 name = id; 51 } 52 42 53 /** Call after loading is finished to setup the window and confirm that it's valid. 43 54 * 44 55 * Throws: WindowLoadException. Do not use the instance in this case! */ 45 void finalise (IGui gui) { 56 void finalise (IGui gui) 57 in { 58 assert (gui !is null, "Window.finalise ("~name~"): gui is null"); 59 } body { 46 60 // Check data was loaded: 47 61 if (widgetData is null) throw new WindowLoadException ("No widget data"); 48 62 49 // Create the renderer:63 gui_ = gui; 50 64 rend = gui.renderer; 51 65 52 66 // Create the primary widget (and indirectly all sub-widgets), throwing on error: 53 widget = getWidget (0, this);// primary widget always has ID 0.67 widget = makeWidget (0, this);// primary widget always has ID 0. 54 68 55 69 widgetData = null; // data is no longer needed: allow GC to collect (cannot safely delete) … … 57 71 widgetX = x + rend.windowBorder; // widget position 58 72 widgetY = y + rend.windowBorder; // must be updated if the window is moved 73 widget.setPosition (widgetX, widgetY); 59 74 60 75 widget.getCurrentSize (w,h);// Find the initial size … … 65 80 yh = y+h; 66 81 } 67 68 void draw () {69 // background70 rend.drawWindow (x,y, w,h);71 72 // Tell the widget to draw itself:73 widget.draw(widgetX, widgetY);74 }75 76 void clickEvent (ushort cx, ushort cy, ubyte b, bool state) {77 if (cx >= x && cx < xw && cy >= y && cy < yh) { // click on window?78 if (cx >= widgetX && cx < xw-rend.windowBorder && cy >= widgetY && cy < yh-rend.windowBorder) // click on widget?79 widget.clickEvent (cx-widgetX, cy-widgetY, b, state);80 // FIXME: else window dragging?81 }82 }83 84 82 //BEGIN Mergetag code 85 83 void addTag (char[] tp, mt.ID id, char[] dt) { … … 105 103 * 106 104 * Should $(I only) be called internally and by sub-widgets! */ 107 IWidget getWidget (widgetID i, IParentWidget parent)105 IWidget makeWidget (widgetID i, IWidget parent) 108 106 in { 109 107 // widgetData is normally left to be garbage collected after widgets have been created: 110 assert (widgetData !is null, " getWidget: widgetData is null");108 assert (widgetData !is null, "Window.makeWidget ("~name~"): widgetData is null"); 111 109 } body { 112 110 // See if it's already been created: 113 111 IWidget* p = i in widgets; 114 if (p !is null) return *p; // yes 115 else { // no 112 if (p !is null) { // yes 113 char[128] tmp; 114 logger.warn (logger.format (tmp, "Window.makeWidget ("~name~"): widget {} has multiple uses!", i)); 115 return *p; 116 } 117 else { // no 116 118 int[]* d = i in widgetData; 117 if (d is null) throw new WindowLoadException ("Wi dget not found");119 if (d is null) throw new WindowLoadException ("Window.makeWidget ("~name~"): Widget not found"); 118 120 119 121 // Throws WidgetDataException (a WindowLoadException) if bad data: … … 124 126 } 125 127 128 IGui gui () { 129 return gui_; 130 } 131 126 132 /+void requestRedraw () { 127 133 }+/ … … 132 138 //END IWindow methods 133 139 134 //BEGIN IParentWidget methods 135 //END IParentWidget methods 140 //BEGIN IWidget methods 141 void getMinimumSize (out int w, out int h) { 142 widget.getMinimumSize (x,y); 143 w += rend.windowBorder * 2; // Adjust for border 144 h += rend.windowBorder * 2; 145 } 146 void getCurrentSize (out int cw, out int ch) { 147 cw = w; 148 ch = h; 149 } 150 151 void setPosition (int x, int y) { 152 /+ Note: this is currently unused. Maybe only use it internally? 153 this.x = x; 154 this.y = y; 155 156 widgetX = x + rend.windowBorder; 157 widgetY = y + rend.windowBorder; 158 159 widget.setPosition (widgetX, widgetY); 160 +/ 161 } 162 163 IWidget getWidget (int cx, int cy) { 164 if (cx < x || cx >= xw || cy < y || cy >= yh) // not over window 165 return null; 166 if (cx >= widgetX && cx < xw-rend.windowBorder && cy >= widgetY && cy < yh-rend.windowBorder) 167 // over the widget 168 return widget.getWidget (cx, cy); 169 else // over the window border 170 return this; 171 } 172 void clickEvent (ushort cx, ushort cy, ubyte b, bool state) { 173 //if (cx >= x && cx < xw && cy >= y && cy < yh) { // click on window? 174 // FIXME: repositioning? 175 } 176 177 void draw () { 178 // background 179 rend.drawWindow (x,y, w,h); 180 181 // Tell the widget to draw itself: 182 widget.draw(); 183 } 184 //END IWidget methods 136 185 137 186 private: 187 char[] name; // The window's name (id from config file) 188 IGui gui_; // The gui managing this window 189 138 190 int[][widgetID] widgetData; // Data for all widgets under this window (deleted after loading) 139 191 IWidget[widgetID] widgets; // List of all widgets under this window (created on demand). … … 141 193 142 194 IRenderer rend; // The window's renderer 195 // FIXME: revise which parameters are stored once Gui knows window position 143 196 int x,y; // Window position 144 197 int w,h; // Window size (calculated from Widgets) mde/gui/widget/createWidget.d
r32 r34 31 31 /** Create a widget of type data[0] (see enum WIDGET_TYPES) for _window window, with initialisation 32 32 * data [1..$]. */ 33 IWidget createWidget (IWindow window, I ParentWidget parent, int[] data)33 IWidget createWidget (IWindow window, IWidget parent, int[] data) 34 34 in { 35 35 assert (window !is null, "createWidget: window is null"); mde/gui/widget/layout.d
r32 r34 23 23 class GridWidget : Widget 24 24 { 25 this (IWindow wind, I ParentWidget, int[] data) {25 this (IWindow wind, IWidget, int[] data) { 26 26 // Get grid size 27 27 if (data.length < 2) throw new WidgetDataException; … … 36 36 subWidgets.length = rows*cols; 37 37 foreach (i, inout subWidget; subWidgets) { 38 subWidget = window. getWidget (data[i+2], this);38 subWidget = window.makeWidget (data[i+2], this); 39 39 } 40 40 … … 58 58 colW.length = cols; //WARNING: code reliant on these being initialised to zero 59 59 for (uint i = 0; i < subWidgets.length; ++i) { 60 uint x= i / cols; // row61 if (rowH[ x] < widgetH[i]) rowH[x] = widgetH[i];62 x= i % cols; // column63 if (colW[ x] < widgetW[i]) colW[x] = widgetW[i];60 uint n = i / cols; // row 61 if (rowH[n] < widgetH[i]) rowH[n] = widgetH[i]; 62 n = i % cols; // column 63 if (colW[n] < widgetW[i]) colW[n] = widgetW[i]; 64 64 } 65 65 … … 83 83 } 84 84 85 void draw (int x, int y) { 86 super.draw (x,y); 85 void setPosition (int x, int y) { 86 this.x = x; 87 this.y = y; 87 88 88 foreach (i,widget; subWidgets) { 89 widget.draw (x + colX[i % cols], y + rowY[i / cols]); 90 } 89 foreach (i,widget; subWidgets) 90 widget.setPosition (x + colX[i % cols], y + rowY[i / cols]); 91 91 } 92 92 93 // Pass event on to relevant widget. Simply return if not on a widget. 94 void clickEvent (ushort cx, ushort cy, ubyte b, bool state) { 95 if (rows*cols == 0) return; // special case 93 // Find the relevant widget. 94 IWidget getWidget (int cx, int cy) { 95 if (rows*cols == 0) return this; // special case 96 97 int lx = cx - x, ly = cy - y; // use coords relative to this widget 96 98 97 99 // Find the column 98 int i = cols - 1; // starting from right...99 while ( cx < colX[i]) {// decrement while left of this column100 if (i == 0) return ;// left of first column100 int i = cols - 1; // starting from right... 101 while (lx < colX[i]) { // decrement while left of this column 102 if (i == 0) return this; // left of first column 101 103 --i; 102 } // now (cx >= colX[i])103 if ( cx >= colX[i] + colW[i]) return;// between columns104 } // now (lx >= colX[i]) 105 if (lx >= colX[i] + colW[i]) return this; // between columns 104 106 105 107 // Find the row; 106 108 int j = rows - 1; 107 while ( cy < rowY[j]) {108 if (j == 0) return ;109 while (ly < rowY[j]) { 110 if (j == 0) return this; 109 111 --j; 110 112 } 111 if ( cy >= rowY[j] + rowH[j]) return;113 if (ly >= rowY[j] + rowH[j]) return this; 112 114 113 115 // Now we know it's in widget (i,j)'s cell (but the widget may not take up the whole cell) 114 cx -= colX[i];115 cy -= rowY[j];116 lx -= colX[i]; 117 ly -= rowY[j]; 116 118 IWidget widg = subWidgets[i + j*cols]; 117 119 widg.getCurrentSize (i,j); 118 if (cx < i && cy < j) 119 widg.clickEvent (cx, cy, b, state); 120 if (lx < i && ly < j) 121 return widg.getWidget (cx, cy); 122 } 123 124 void draw () { 125 super.draw (); 126 127 foreach (widget; subWidgets) 128 widget.draw (); 120 129 } 121 130 … … 127 136 int[] colX; // cumulative colW[i-1] + border and padding 128 137 IWidget[] subWidgets; // all widgets in the grid (by row): 129 /* SubWidget order: [ 2 3]130 * [ 0 1] */138 /* SubWidget order: [ 0 1 ] 139 * [ 2 3 ] */ 131 140 } mde/input/Input.d
r32 r34 31 31 import tango.util.log.Log : Log, Logger; 32 32 33 /// Class encapsulating all input functionality. 33 /** Class encapsulating all input functionality. 34 * 35 * The following methods are provided for Gui mouse input: 36 * --- 37 * void getMouseScreenPos (out uint x, out uint y); 38 * void addMouseClickCallback (MouseClickCallback dg); 39 * void addMouseMotionCallback (MouseMotionCallback dg); 40 * --- 41 * 42 * The following methods are provided for mouse (and joystick ball) relative motion input: 43 * --- 44 * void getRelMotion (inputID id, out real x = 0.0, out real y = 0.0); 45 * void addRelMotionCallback (inputID id, RelMotionCallback dg); 46 * --- 47 * 48 * The following methods are provided for joystick axis input: 49 * --- 50 * short getAxis (inputID id); 51 * real getAxis1 (inputID id); 52 * void addAxisCallback (inputID id, AxisCallback dg); 53 * --- 54 * 55 * The following methods are provided for keyboard, joystick and mouse button input: 56 * --- 57 * bool getButton (inputID id); 58 * void addButtonCallback (inputID id, ButtonCallback dg) 59 * --- 60 * 61 * The following methods are provided for setup & posting events: 62 * --- 63 * bool opCall (ref SDL_Event event); 64 * void frameReset (); 65 * void loadConfig (char[] profile = "Default"); 66 * --- 67 ***************************************************/ 68 // FIXME: remove getMouseScreenPos (no use)? 69 // FIXME: add an Axis1Callback similar to getAxis1? Or remove getAxis1 and provide a conversion 70 // function? 34 71 class Input 35 72 { … … 39 76 alias void delegate(inputID, short) AxisCallback; 40 77 alias void delegate(inputID, real,real) RelMotionCallback; 41 alias void delegate(ushort, ushort, ubyte, bool) MouseClickCallback; 78 alias void delegate(ushort, ushort, ubyte, bool) MouseClickCallback; 79 alias void delegate(ushort, ushort) MouseMotionCallback; 42 80 43 81 /** Get key status at this ID. … … 74 112 * multiple mice, in case future platforms do. 75 113 * Also joystick balls (supported by SDL) can be used in the same way as a mouse for relative 76 * positions. 77 */ 114 * positions. */ 78 115 void getRelMotion (inputID id, out real x = 0.0, out real y = 0.0) { 79 116 RelPair* rp = id in relMotion; … … 86 123 * Window managers only support one mouse, so there will only be one screen coordinate. 87 124 * Unlike nearly everything else, this is not configurable. 88 */ 125 * 126 * Also see addMouseMotionCallback. */ 89 127 void getMouseScreenPos (out uint x, out uint y) { 90 128 x = mouse_x; y = mouse_y; … … 95 133 /** Adds a callback delegate for key events (both DOWN and UP) with this ID. 96 134 * 97 * Delegate receives event status. 98 */ 135 * Delegate receives event status. */ 99 136 void addButtonCallback (inputID id, ButtonCallback dg) { 100 137 buttonCallbacks[id] ~= dg; … … 103 140 /** Adds a callback delegate for axis events with this ID. 104 141 * 105 * Delegate receives event status (as per what getAxis returns). 106 */ 142 * Delegate receives event status (as per what getAxis returns). */ 107 143 void addAxisCallback (inputID id, AxisCallback dg) { 108 144 axisCallbacks[id] ~= dg; … … 116 152 * (A separate callback for mouse screen position changes is not 117 153 * necessary since this will be triggered by the same event - use mouseScreenPos from within the 118 * function to get new screen coordinates.) 119 */ 154 * function to get new screen coordinates.) */ 120 155 void addRelMotionCallback (inputID id, RelMotionCallback dg) { 121 156 relMotionCallbacks[id] ~= dg; … … 130 165 * The point of this over a standard button callback is firstly to avoid mouse configuration for 131 166 * the GUI, and secondly to give the pointer position at the time of the event, not the time the 132 * callback gets called. 133 */ 167 * callback gets called. */ 134 168 void addMouseClickCallback (MouseClickCallback dg) { 135 169 mouseClickCallbacks ~= dg; 136 170 } 171 172 /** Adds a callback delegate for all mouse motion events. 173 * 174 * Really just for graphical user interfaces. Use addRelMotionCallback for relative motion (for 175 * manipulating 3D views, etc.). */ 176 void addMouseMotionCallback (MouseMotionCallback dg) { 177 mouseMotionCallbacks ~= dg; 178 } 137 179 138 180 /** Feed an SDL_Event struct (only uses if it's a key, mouse or joystick event). … … 142 184 * 143 185 * May throw InputClassExceptions (on configuration errors). Catching the exception and continuing should 144 * be fine. 145 */ 186 * be fine. */ 146 187 bool opCall (ref SDL_Event event) { 147 188 /* Non-config events. … … 164 205 mouse_x = event.motion.x - 1; 165 206 mouse_y = event.motion.y - 1; 207 208 foreach (dg; mouseMotionCallbacks) 209 dg (event.motion.x - 1, event.motion.y - 1); 166 210 break; 167 211 … … 171 215 /* No config available, so don't try to access it and segfault. 172 216 * Don't log a message because this function is called per-event (i.e. frequently). 173 * A message should already have been logged by loadConfig anyway. 174 */ 217 * A message should already have been logged by loadConfig anyway. */ 175 218 if (!config) return false; 176 219 … … 287 330 * 288 331 * Should be called once-per-frame if these are used, but must be called after their state has 289 * been read (e.g. just before updating the input). 290 */ 332 * been read (e.g. just before updating the input). */ 291 333 void frameReset () { 292 334 foreach (rp; relMotion) { … … 298 340 * 299 341 * Throws: ConfigLoadException if unable to load any configs or the requested config id wasn't 300 * found. 301 */ 342 * found. */ 302 343 void loadConfig (char[] profile = "Default") { 303 344 Config.load("input"); // FIXME: filename … … 343 384 RelMotionCallback[][inputID] relMotionCallbacks; 344 385 MouseClickCallback[] mouseClickCallbacks; 386 MouseMotionCallback[] mouseMotionCallbacks; 345 387 346 388 //BEGIN Event stream functionality … … 348 390 * functions), and finally output to one (or more) of the state tables (the event stream). 349 391 * 350 * Adjuster and other event functions should have a format to fit the ES_X_Func types, for X is B351 * (button event), A (axis event) or M (mouse relative motion event or joystick ball event).392 * Adjuster and other event functions should have a format to fit the ES_X_Func types, for X is 393 * B (button event), A (axis event) or M (mouse relative motion event or joystick ball event). 352 394 * Adjusters should call one of the xEvent() functions with their output and the remainder of 353 395 * the readOutQueue. 354 396 * 355 * To control which adjusters get called and pass parameters, a stack of sorts is used: outQueue.356 * /397 * To control which adjusters get called and pass parameters, a stack of sorts is used: 398 * outQueue. */ 357 399 //BEGIN ES Definitions 358 400 /* Note: We really want an array, not a stack. We cannot edit the lists, so we can either 359 * copy to a stack or just iterate through it as an array. 360 */ 401 * copy to a stack or just iterate through it as an array. */ 361 402 alias Config.outQueue outQueue; 362 403 struct readOutQueue { // A convenient structure for reading an outQueue item by item. … … 390 431 /* These are the codes allowing the config to specify event functions. 391 432 * 392 * They are organised as defined in doc/input_ID_assignments. 393 */ 433 * They are organised as defined in doc/input_ID_assignments. */ 394 434 enum ES_B : uint { 395 435 OUT = 0x1000u, … … 489 529 * 490 530 * It relies on config loaded from a file (dependant on where input bindings are loaded from; 491 * currently conf/input.mtt). 492 */ 531 * currently conf/input.mtt). */ 493 532 debug (mdeUnitTest) unittest { 494 533 Input ut = new Input(); mde/scheduler/init2.d
r33 r34 70 70 } 71 71 } ); 72 73 // Aught to be added by the gui, but it doesn't know if input exists then. 72 74 global.input.addMouseClickCallback(&gui.clickEvent); 75 global.input.addMouseMotionCallback(&gui.motionEvent); 73 76 } catch (Exception e) { 74 77 logger.fatal ("initInput failed: " ~ e.msg);
