Changeset 75:25cb7420dc91
- Timestamp:
- 07/28/08 13:17:48 (6 months ago)
- Files:
-
- codeDoc/gui/GUI notes.txt (modified) (2 diffs)
- codeDoc/jobs.txt (modified) (1 diff)
- codeDoc/todo.txt (modified) (2 diffs)
- data/conf/gui.mtt (modified) (2 diffs)
- mde/gl/basic.d (modified) (2 diffs)
- mde/gl/draw.d (modified) (2 diffs)
- mde/gui/IGui.d (deleted)
- mde/gui/WidgetData.d (added)
- mde/gui/WidgetManager.d (moved) (moved from mde/gui/Gui.d) (4 diffs)
- mde/gui/exception.d (modified) (1 diff)
- mde/gui/renderer/IRenderer.d (modified) (1 diff)
- mde/gui/widget/Ifaces.d (modified) (6 diffs)
- mde/gui/widget/TextWidget.d (modified) (1 diff)
- mde/gui/widget/Widget.d (modified) (4 diffs)
- mde/gui/widget/Window.d (modified) (2 diffs)
- mde/gui/widget/createWidget.d (modified) (2 diffs)
- mde/gui/widget/miscWidgets.d (modified) (8 diffs)
- mde/imde.d (modified) (1 diff)
- mde/lookup/Options.d (modified) (1 diff)
- mde/lookup/Translation.d (modified) (1 diff)
- mde/mde.d (modified) (1 diff)
- mde/mergetag/DefaultData.d (modified) (5 diffs)
- mde/setup/init2.d (modified) (4 diffs)
- mde/setup/paths.d (modified) (4 diffs)
- mde/setup/sdl.d (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
codeDoc/gui/GUI notes.txt
r60 r75 6 6 7 7 GUI: 8 -> Basic OpenGL code to:9 ->* create orthographic projection10 ->* draw boxes11 -> maybe more (text, textures, ...)12 8 -> Windows with size & position 13 9 -> position from Gui … … 16 12 -> no ability to resize yet except from config files 17 13 -> scripted widgets 18 -> Text rendering19 -> text library?20 14 -> Drag & drop 21 15 -> click/drag start triggers a callback on the widget codeDoc/jobs.txt
r74 r75 10 10 To do (importance 0-5: 0 pointless, 1 no obvious impact now, 2 todo sometime, 3 useful, 4 important, 5 urgent): 11 11 Also see todo.txt and FIXME/NOTE comment marks. 12 4 struct (via tuple) support for parseTo/From. Requires rewriting with static if (is T : type). 12 13 4 Try to correlate names of option sections more. (i.e. symbol name, class name, name of i18n translation file) 13 14 4 Not guaranteed to catch up-click ending callback! Appears not to be a problem... codeDoc/todo.txt
r74 r75 3 3 4 4 5 * means done:6 7 5 GUI: 8 6 -> Widgets: 9 7 -> rethink how widgets are created and receive creation data, so that they don't have to be created by the Window 10 ->* minimum size but expandable, auto-set11 ->* grid "layout" widgets12 8 -> scripted widgets 13 9 -> decent rendering/theme system … … 24 20 -> possibilities 25 21 -> per-widget merging (i.e. separate tag(s) for each widget's data)? 26 -> if a widget with sub-widgets is defined in a base file, but redesigned in a derived file, any unused widgets with data res olting are not created22 -> if a widget with sub-widgets is defined in a base file, but redesigned in a derived file, any unused widgets with data resulting are not created 27 23 -> if design changes in a base file, while the old design was modified in a derived file, will the result be sane? 28 24 -> if a locally modified gui is updated upstream (so the base files change), should: data/conf/gui.mtt
r72 r75 1 1 {MT01} 2 !<char[]|Renderer="Simple"> 2 <char[]|Renderer="Simple"> 3 <char[]|Design="Basic"> 4 {Basic} 5 <WidgetData|root=[0x4010,200,200],""> 6 !{ 3 7 {W1} 4 8 <int|x=30> … … 14 18 <int|y=100> 15 19 <int[][int]|widgetData=[0:[0xB005,0,0xB04000]]> 20 } mde/gl/basic.d
r57 r75 14 14 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 15 16 /** Some basic OpenGL code for setting up a projection anddrawing.16 /** Some basic OpenGL code for drawing. 17 17 * 18 18 * Everything here is really intended as makeshift code to enable GUI development. */ … … 22 22 23 23 import tango.time.Time; // TimeSpan (type only; unused) 24 25 //BEGIN GL & window setup26 void glSetup () {27 glDisable(GL_LIGHTING);28 glDisable(GL_DEPTH_TEST);29 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);30 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);31 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);32 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);33 glEnable(GL_TEXTURE_2D);34 glShadeModel(GL_SMOOTH);35 36 glClearColor (0.0f, 0.0f, 0.0f, 0.0f);37 38 glMatrixMode(GL_MODELVIEW);39 glLoadIdentity();40 41 // Used for font rendering:42 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);43 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);44 //NOTE: wrap mode may have an effect, but shouldn't be noticed...45 }46 47 void setProjection (int w, int h) {48 glMatrixMode (GL_PROJECTION);49 glLoadIdentity ();50 51 glViewport (0,0,w,h);52 53 // Make the top-left the origin (see gui/GUI notes.txt):54 // Note that this only affects vertex operations â direct rasterisation operations are55 // unaffected!56 glOrtho (0.0,w, h,0.0, -1.0, 1.0);57 58 glMatrixMode(GL_MODELVIEW);59 }60 //END GL & window setup61 24 62 25 //BEGIN Drawing utils mde/gl/draw.d
r67 r75 14 14 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 15 16 /** The OpenGL draw loop .16 /** The OpenGL draw loop and some basic OpenGL code to set up a projection. 17 17 * 18 18 * Everything here is really intended as makeshift code to enable GUI development. */ 19 19 module mde.gl.draw; 20 20 21 import mde.gui.Gui; 21 import mde.gui.WidgetManager; 22 import mde.imde; 22 23 23 24 import derelict.sdl.sdl; … … 32 33 logger = Log.getLogger ("mde.gl.draw"); 33 34 } 35 36 //BEGIN GL & window setup 37 void glSetup () { 38 glDisable(GL_LIGHTING); 39 glDisable(GL_DEPTH_TEST); 40 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 41 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 42 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 43 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 44 glEnable(GL_TEXTURE_2D); 45 glShadeModel(GL_SMOOTH); 46 47 glClearColor (0.0f, 0.0f, 0.0f, 0.0f); 48 49 glMatrixMode(GL_MODELVIEW); 50 glLoadIdentity(); 51 52 // Used for font rendering: 53 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 54 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 55 //NOTE: wrap mode may have an effect, but shouldn't be noticed... 56 } 57 58 void setProjection (int w, int h) { 59 glMatrixMode (GL_PROJECTION); 60 glLoadIdentity (); 61 62 glViewport (0,0,w,h); 63 64 // Make the top-left the origin (see gui/GUI notes.txt): 65 // Note that this only affects vertex operations â direct rasterisation operations are 66 // unaffected! 67 glOrtho (0.0,w, h,0.0, -1.0, 1.0); 68 69 glMatrixMode(GL_MODELVIEW); 70 71 // The gui is tied to this viewport. 72 gui.setSize (w,h); 73 } 74 //END GL & window setup 34 75 35 76 //BEGIN Drawing loop mde/gui/WidgetManager.d
r74 r75 14 14 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 15 16 /** The Gui class.17 * 18 * This is the module to use externally to create a graphical user interface (likely also with 19 * content modules). 20 * 21 * Possibly add a GuiManager to update all active GUIs and pass coordinates (remapping if necessary).*/22 module mde.gui. Gui;16 /************************************************************************************************* 17 * The gui manager class. 18 * 19 * This is the module to use externally to create a graphical user interface (likely also with 20 * content modules). 21 *************************************************************************************************/ 22 module mde.gui.WidgetManager; 23 23 24 import mde.gui.IGui;24 public import mde.gui.WidgetData; 25 25 import mde.gui.widget.Ifaces; 26 import mde.gui.widget.Window; 27 import mde.gui.exception; 26 import mde.gui.renderer.createRenderer; 28 27 29 28 // For adding the input event callbacks and requesting redraws: … … 32 31 import mde.scheduler.Scheduler; 33 32 34 // For loading from file: 35 import mt = mde.mergetag.DataSet; 36 import mt = mde.mergetag.DefaultData; 37 import mt = mde.mergetag.exception; 38 import mde.mergetag.Reader; 39 import mde.mergetag.Writer; 40 import mde.setup.paths; 41 33 import tango.core.sync.Mutex; 42 34 import tango.util.log.Log : Log, Logger; 43 35 44 36 private Logger logger; 45 37 static this () { 46 logger = Log.getLogger ("mde.gui. gui");47 48 gui = new Gui; // until Guis are handled otherwise, this may as well be the case38 logger = Log.getLogger ("mde.gui.WidgetManager"); 39 40 gui = new WidgetManager ("gui"); 49 41 } 50 42 51 Gui gui; // Currently just one instance; handle differently later. 52 // Handle externally or with a GUI Manager? 43 WidgetManager gui; 53 44 54 /** A GUI handles a bunch of windows, all to be drawn to the same device. */ 55 class Gui : IGui { 56 //BEGIN Methods for external use 57 //BEGIN Loading code 58 /** Load all windows from the file gui. */ 59 void load (char[] fileName) { 60 if (!confDir.exists (fileName)) { 61 logger.error ("Unable to load GUI: no config file!"); 62 return; // not a fatal error (so long as the game can run without a GUI!) 63 } 45 46 /************************************************************************************************* 47 * The widget manager. 48 * 49 * This is responsible for loading and saving an entire gui (although more than one may exist), 50 * controlling the rendering device (e.g. the screen or a texture), and providing user input. 51 * 52 * Currently mouse coordinates are passed to widgets untranslated. It may make sense to translate 53 * them and possibly drop events for some uses, such as if the gui is drawn to a texture. 54 * 55 * Aside from the IWidgetManager methods, this class should be thread-safe. 56 *************************************************************************************************/ 57 class WidgetManager : WidgetLoader { 58 /** Construct a new widget manager. 59 * 60 * params: 61 * fileName = Name of file specifying the gui, excluding path and extension. 62 */ 63 this (char[] file) { 64 super(file); 64 65 65 IReader reader; 66 try { 67 reader = confDir.makeMTReader (fileName, PRIORITY.HIGH_LOW, null, true); 68 reader.dataSecCreator = delegate mt.IDataSection(mt.ID id) { 69 return new Window (id); 70 }; 71 reader.read; 72 } catch (Exception e) { 73 logger.error ("Unable to load GUI: errors parsing config file ("~confDir.getFileName(fileName,PRIORITY.HIGH_LOW)~"):"); 74 logger.error (e.msg); 75 throw new GuiException ("Failure parsing config file"); 76 } 77 78 // Get the renderer 79 char[]* p = "Renderer" in reader.dataset.header.Arg!(char[]); 80 if (p is null || *p is null) { 81 logger.warn ("no renderer specified: defaulting to Simple"); 82 rendName = "Simple"; 83 } 84 else 85 rendName = *p; 86 87 // get list 88 windows.length = reader.dataset.sec.length; // pre-allocate 89 windows.length = 0; 90 foreach (sec; reader.dataset.sec) { 91 Window w = cast(Window) sec; 92 debug if (w is null) { 93 logger.error (__FILE__ ~ "(GUI.load): code error (w is null)"); 94 continue; 95 } 96 try { 97 w.finalise (this); // if this fails, the window (but nothing else) won't work 98 windows ~= w; // only add if load successful 99 } catch (Exception e) { 100 logger.error ("Window failed to load: " ~ e.msg); 101 } 102 } 103 66 // Events we want to know about: 104 67 imde.input.addMouseClickCallback(&clickEvent); 105 68 imde.input.addMouseMotionCallback(&motionEvent); 106 69 } 107 70 108 void save (char[] fileName) {109 mt.DataSet ds = new mt.DataSet;110 111 // Add header:112 ds.header = new mt.DefaultData;113 ds.header.Arg!(char[])["Renderer"] = rendName;114 115 // Add windows to be saved:116 foreach (window; windows)117 ds.sec [window.name] = window;118 119 try { // Save120 IWriter writer;121 writer = confDir.makeMTWriter (fileName, ds);122 writer.write;123 } catch (mt.MTException e) {124 logger.error ("Saving GUI failed:");125 logger.error (e.msg);126 127 return;128 }129 }130 //END Loading code131 71 132 /** Draw each window. 133 * 134 * Currently no concept of how to draw overlapping windows, or how to not bother drawing windows 135 * which don't need redrawing. */ 72 /** Draw the gui. */ 136 73 void draw() { 137 foreach_reverse (w; windows) // Draw, starting with back-most window.138 w.draw;74 synchronized(mutex) 75 child.draw; 139 76 } 140 77 78 141 79 /** For mouse click events. 142 *143 * Sends the event on to the relevant windows and all click callbacks. */80 * 81 * Sends the event on to the relevant windows and all click callbacks. */ 144 82 void clickEvent (ushort cx, ushort cy, ubyte b, bool state) { 145 83 debug scope (failure) 146 logger.warn ("clickEvent: failed!"); 84 logger.warn ("clickEvent: failed!"); 85 mutex.lock; 86 scope(exit) mutex.unlock; 147 87 148 88 // NOTE: buttons receive the up-event even when drag-callbacks are in place. 149 89 foreach (dg; clickCallbacks) 150 if (dg (cast(wdabs)cx, cast(wdabs)cy, b, state)) return; // See IGui.addClickCallback's documentation 90 // See IWidgetManager.addClickCallback's documentation: 91 if (dg (cast(wdabs)cx, cast(wdabs)cy, b, state)) return; 151 92 93 /+ 152 94 foreach (i,w; windows) { 153 95 IWidget widg = w.getWidget (cast(wdabs)cx,cast(wdabs)cy); … … 160 102 return; // only pass to first window 161 103 } 162 } 104 }+/ 163 105 } 164 106 165 107 /** For mouse motion events. 166 *167 * Sends the event on to all motion callbacks. */108 * 109 * Sends the event on to all motion callbacks. */ 168 110 void motionEvent (ushort cx, ushort cy) { 169 111 debug scope (failure) 170 112 logger.warn ("motionEvent: failed!"); 113 mutex.lock; 114 scope(exit) mutex.unlock; 115 171 116 foreach (dg; motionCallbacks) 172 117 dg (cast(wdabs)cx, cast(wdabs)cy); 173 118 } 174 119 175 //END Methods for external use176 120 177 //BEGIN IGui methods 178 char[] rendererName () { 179 return rendName; 121 void setSize (int x, int y) { 122 mutex.lock; 123 scope(exit) mutex.unlock; 124 125 w = cast(wdim) x; 126 h = cast(wdim) y; 127 128 if (child is null) 129 return; // May not have been created before this is first run. 130 child.setWidth (w, -1); 131 child.setHeight (h, -1); 132 child.setPosition (0,0); 133 } 134 135 //BEGIN IWidgetManager methods 136 // These methods are only intended for use within the gui package. They are not necessarily 137 // thread-safe. 138 IRenderer renderer () { 139 assert (rend !is null, "WidgetManager.renderer: rend is null"); 140 return rend; 180 141 } 181 142 … … 190 151 motionCallbacks[dg.ptr] = dg; 191 152 } 192 void removeCallbacks ( void*frame) {193 clickCallbacks.remove( frame);194 motionCallbacks.remove( frame);153 void removeCallbacks (IChildWidget frame) { 154 clickCallbacks.remove(cast(void*) frame); 155 motionCallbacks.remove(cast(void*) frame); 195 156 } 196 //END IGui methods 157 //END IWidgetManager methods 158 159 protected: 160 /* Second stage of widget loading. */ 161 void createRootWidget () { 162 // The renderer needs to be created on the first load, but not after this. 163 if (rend is null) 164 rend = createRenderer (rendName); 165 166 child = makeWidget ("root"); 167 168 child.setWidth (w, -1); 169 child.setHeight (h, -1); 170 child.setPosition (0,0); 171 } 197 172 198 173 private: 199 Window[] windows; // Windows. First window is "on top", others may be obscured.200 201 char[] rendName; // Name of renderer; for saving and creating renderers202 203 174 // callbacks indexed by their frame pointers: 204 175 bool delegate(wdabs cx, wdabs cy, ubyte b, bool state) [void*] clickCallbacks; 205 176 void delegate(wdabs cx, wdabs cy) [void*] motionCallbacks; 177 IRenderer rend; 178 wdim w,h; // area available to the widgets 206 179 } mde/gui/exception.d
r40 r75 30 30 } 31 31 32 /// Thrown when something goes wrong while loading a window (usually a data error).33 class WindowLoadException : GuiException34 {35 this (char[] msg) {36 super(msg);37 }38 }39 40 32 /// Thrown when createWidget or a Widget class's this() is called with invalid data. 41 class WidgetDataException : WindowLoadException33 class WidgetDataException : GuiException 42 34 { 43 35 this () { // Default, by Widget class's this mde/gui/renderer/IRenderer.d
r58 r75 17 17 module mde.gui.renderer.IRenderer; 18 18 19 public import mde.gui.IGui; // wdim type is used by just about everything including this 19 // Put here to avoid circular import. 20 typedef int wdim; 20 21 21 22 /** Interface for renderers. mde/gui/widget/Ifaces.d
r72 r75 14 14 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 15 16 /** Window and widget interfaces. */ 16 /************************************************************************************************* 17 * Widget interfaces. 18 * 19 * Widgets are connected as the nodes of a tree. Widgets know their parent as a IParentWidget 20 * class and their children as IChildWidget classes. The gui manager is a special widget only 21 * implementing IParentWidget; all other widgets must implement IChildWidget and optionally 22 * IParentWidget. 23 *************************************************************************************************/ 17 24 module mde.gui.widget.Ifaces; 18 25 19 26 public import mde.gui.renderer.IRenderer; 20 public import mde.gui.IGui; 21 22 /** Interface for Window, allowing widgets to call some of Window's methods. 23 * 24 * Contains the methods in Window available for widgets to call on their root. 27 28 29 /** Widget ID type. Each ID is unique under this window. 30 * 31 * Type is int since this is the widget data type. */ 32 alias char[] widgetID; 33 34 /** Window coordinate and dimension/size type (int). 35 * 36 * Used to disambiguate between general integers and coordinates; all widget positions/sizes should 37 * use this type (or one of the aliases below). 38 * 39 * --- 40 * typedef int wdim; // Declared in IRenderer to avoid a circular import. 41 * --- 42 * 43 * Aliases of wdim providing extra information about what their contents hold: absolute position, 44 * position relative to the containing widget (wdrel should not be used if relative to anything 45 * else), or size. Their use instead of wdim is optional (and in some cases wdim values aren't of 46 * any of these types). Also don't use these aliases for variables which may also be used to other 47 * effects, e.g. if they can have special values with special meanings. */ 48 alias wdim wdabs; 49 alias wdim wdrel; /// ditto 50 alias wdim wdsize; /// ditto 51 52 /** A pair of wdim variables, and strictly no other data (methods may be added if deemed useful). 53 * 54 * Potentially usable to return two wdim variables, e.g. width and height, from a function. 55 * However, the current usage of out variables looks like it's better. */ 56 struct wdimPair { 57 wdim x, y; /// data 58 } 59 60 61 /************************************************************************************************* 62 * Common interface for all widgets. 25 63 * 26 64 * Notation: 27 65 * Positive/negative direction: along the x/y axis in this direction. 28 * Layout widget: a widget containing multiple sub-widges (which hence controls how they are laid 29 * out). */ 30 interface IWindow : IWidget 31 { 32 /** Widget ID type. Each ID is unique under this window. 33 * 34 * Type is int since this is the widget data type. */ 35 alias int widgetID; 36 37 /** Get a widget by ID. 38 * 39 * Returns the widget with the given ID from the Window's widget list. If the widget hasn't yet 40 * been created, creates it using the Window's widget creation data. */ 41 IWidget makeWidget (widgetID i); 42 43 /** Get a string from the widgetString associative array. */ 44 char[] getWidgetString (int i); 45 46 /** Add widget's saveData to the data to be saved, returning it's widgetID. */ 47 widgetID addCreationData (IWidget widget); 48 49 /** Add a string to the widgetString associative array, returning it's index. */ 50 int addWidgetString (char[] str); 51 52 /** Returns the window's gui. */ 53 IGui gui (); 54 55 /** The widget/window needs redrawing. */ 66 * Layout widget: a widget containing multiple sub-widges (which hence controls how they are 67 * laid out). 68 *************************************************************************************************/ 69 //NOTE: keep this? 70 interface IWidget 71 { 72 } 73 74 75 /************************************************************************************************* 76 * Interface for the widget manager. 77 * 78 * This class handles widget rendering, input, loading and saving. 79 *************************************************************************************************/ 80 interface IWidgetManager : IParentWidget 81 { 82 // Loading/saving: 83 /** Create a widget by ID. 84 * 85 * Creates a widget, using the widget data with index id. Widget data is loaded from files, 86 * and per design (multiple gui layouts, called designs, may exist; data is per design). 87 * 88 * Note: this method is only for "named" widgets; generic widgets instanciated in lists are 89 * created differently. */ 90 IChildWidget makeWidget (widgetID id); 91 92 /** Record some changes, for saving. */ 93 void setData (widgetID id, WidgetData); 94 95 // Rendering: 96 /** For when a widget needs redrawing. 97 * 98 * Must be called because rendering may only be done on events. 99 * 100 * Currently it just causes everything to be redrawn next frame. */ 56 101 void requestRedraw (); 57 102 … … 61 106 * provides the possibility of per-window renderers (if desired). */ 62 107 IRenderer renderer (); 63 } 64 65 /** Interface for widgets. 66 * 67 * Note that Window also implements this interface so that widgets can interact with their parent 68 * in a uniform way. 108 109 110 // User input: 111 /** Add a mouse click callback: delegate will be called for all mouse click events recieved. 112 * 113 * The delegate should return true if it accepts the event and no further processing is 114 * required (i.e. the event should not be handled by anything else), false otherwise. 115 * 116 * Note that this is not a mechanism to prevent unwanted event handling, and in the future 117 * may be removed (so event handling cannot be cut short). */ 118 void addClickCallback (bool delegate (wdabs cx, wdabs cy, ubyte b, bool state) dg); 119 120 /** Add a mouse motion callback: delegate will be called for all motion events recieved. */ 121 void addMotionCallback (void delegate (wdabs cx, wdabs cy) dg); 122 123 // FIXME: keyboard callback (letter only, for text input? Also used for setting keybindings though...) 124 125 /** Remove all event callbacks on this widget (according to the delegate's .ptr). */ 126 void removeCallbacks (IChildWidget frame); 127 } 128 129 130 /************************************************************************************************* 131 * Interface for parent widgets, including the gui manager. 132 * 133 * A widget may call these methods on its parent, and on the gui manager. 134 *************************************************************************************************/ 135 interface IParentWidget : IWidget 136 { 137 // NOTE: Likely some day this interface will really be used. 138 // NOTE: What widget is NOT going to implement this? It will probably be inherited. 139 } 140 141 142 /************************************************************************************************* 143 * Interface for (child) widgets, i.e. all widgets other than the manager. 69 144 * 70 145 * A widget is a region of a GUI window which handles rendering and user-interaction for itself 71 * and is able to communicate with it's window and parent/child widgets as necessary. 72 * 73 * If a widget is to be creatable by Window.makeWidget, it must be listed in the createWidget 74 * module, have a constructor of the following form, and should implement getCreationData(). 75 * Use Ddoc to explain what initialization data is used. 146 * and is able to communicate with its manager and parent/child widgets as necessary. 147 * 148 * If a widget is to be creatable by IWidgetManager.makeWidget, it must be listed in the 149 * createWidget module, have a constructor of the following form, and should update it's 150 * creation data as necessary via IWidgetManager.setData(). 151 * It should use Ddoc to explain what initialization data is used. 76 152 * ---------------------------------- 77 153 * /++ Constructor for a ... widget. … … 80 156 * + [widgetID, x, y] 81 157 * + where x is ... and y is ... +/ 82 * this (IWi ndow window, int[]data);158 * this (IWidgetManager mgr, WidgetData data); 83 159 * ---------------------------------- 84 * Where window is the root window (the window to which the widget belongs) and data is an array of85 * initialisation data. The method should throw a WidgetDataException (created without parameters)86 * if the data has wrong length or is otherwise invalid.87 * 88 * The widget's size should be set either by it's this() method or by the first call to89 * s etSize(). setSize() is called on all widgets immediately after their creation, and throwing an90 * exception at this point (but not on later calls to setSize) is an acceptible method of failure.91 * /160 * Where mgr is the widget manager and data is 161 * initialisation data. The method should throw a WidgetDataException (created without 162 * parameters) if the data has wrong length or is otherwise invalid. 163 * 164 * A parent widget is responsible for setting the size of its children widgets, however it must 165 * satisfy their minimal sizes as available from minWidth() and minHeight(). setWidth() and 166 * setHeight() are called on all widgets after creation. 167 *************************************************************************************************/ 92 168 //NOTE: add another this() without the data for default initialization, for the GUI editor? 93 interface I Widget169 interface IChildWidget : IWidget 94 170 { 95 171 //BEGIN Load and save 96 /** Called after creating widgets to adjust size & other mutable attributes from saved data. 97 * 98 * As for setSize, setPosition should be called afterwards. 99 * 100 * Each widget should call adjust on each of its sub-widgets in turn with data, each time 101 * replacing data by the return value of the call. It should then take its own mutable data 102 * from the beginning of the array and return the remainder of the array. 103 * 104 * Adjust should handle errors gracefully by reverting to default values and not throwing. 105 * This is because the creation data and the user's mutable data may be stored separately and 106 * become out-of-sync during an update. */ 107 int[] adjust (int[] data); 108 109 /** Output data suitible for recreating the widget (data to be passed to this()). 110 * 111 * Function may need to call Window's addCreationData() and addWidgetString() methods to save 112 * other data. 113 * 114 * Creation data is data only changed when the gui is edited. */ 115 int[] getCreationData (); 116 117 /** Output data containing the widget's current adjustments (data to be passed to adjust()). 118 * 119 * Mutable data is data which can be changed during normal gui use, such as the size of 120 * resizible widgets or current tab of a tab widget. 121 * 122 * Should be a concatenation of each sub-widget's mutable data and the widget's own. */ 123 int[] getMutableData (); 172 /** Called when the renderer is changed (at least when the changes affect dimensions). 173 * Also called after widget creation, before any other methods are called. 174 * 175 * Returns: true when widget's dimensions (may) have changed. 176 * 177 * Should be propegated down to all child widgets. */ 178 bool rendererChanged (); 179 180 /+ Use when widget editing is available? Requires widgets to know their parents. 181 /** Called when a child widget's size has changed. 182 * 183 * Should be propegated up to parents. */ 184 void childChanged (); 185 +/ 124 186 //END Load and save 125 187 … … 137 199 wdim minHeight (); /// ditto 138 200 139 /** Get the current size of the widget. */ 140 void getCurrentSize (out wdim w, out wdim h); 201 /** Get the current size of the widget. 202 * 203 * Deprecated: is it needed now? 204 */ 205 deprecated void getCurrentSize (out wdim w, out wdim h); 141 206 142 207 /** Used to adjust the size. … … 149 214 * Most widgets can simply ignore it. 150 215 * 151 * Implementation: 152 * The size should be clamped to the widget's minimal size, i.e. the size set may be larger 153 * than that given by the parameters. Conversely, the size should not be reduced to the 154 * widget's maximal size (if any) but expanded as necessary (alignment to be implemented). 155 * This should be true for both resizable and fixed widgets; fixed widgets may still be scaled 156 * to fill a whole row/column in a layout widget. 157 * 158 * If the actual size is needed, call getCurrentSize afterwards. setPosition must be called 159 * afterwards if the widget might be a layout widget. */ 216 * If called with dimensions less than minWidth/minHeight return: the widget may set its size 217 * to either the dimension given or its minimal dimension (even though this is larger). If the 218 * larger size is set, events won't be received in the extra area. FIXME: sort out rendering. 219 * Otherwise, the dimensions should always be set exactly. 220 * 221 * setPosition must be called after calling either setWidth or setHeight. */ 160 222 void setWidth (wdim nw, int dir); 161 223 void setHeight (wdim nh, int dir); /// ditto … … 192 254 void draw (); 193 255 } 256 257 258 /************************************************************************************************* 259 * The data type all widgets creatable by the widget manager receive on creation. 260 * 261 * Conversion code to/from MT tags is contained in the addTag and writeAll methods of 262 * WidgetDataSet and WidgetDataChanges. 263 *************************************************************************************************/ 264 struct WidgetData 265 { 266 int[] ints; // An array of integer data 267 char[] str; // One string 268 } mde/gui/widget/TextWidget.d
r72 r75 69 69 * where contentID is an ID for the string ID of the contained content 70 70 * and colour is an 8-bit-per-channel RGB colour of the form 0xRRGGBB. */ 71 this (IWi ndow wind, int[]data) {72 if (data.length != 3) throw new WidgetDataException;73 text.set ( wind.getWidgetString(data[1]), data[2]);71 this (IWidgetManager mgr, WidgetData data) { 72 if (data.length != 2) throw new WidgetDataException; 73 text.set (data.str, data[1]); 74 74 text.getDimensions (mw, mh); 75 super ( wind,data);75 super (mgr,data); 76 76 } 77 77 mde/gui/widget/Widget.d
r66 r75 29 29 * useful basic implementation for widgets. Widgets need not inherit these (they only need implement 30 30 * IWidget); they are simply provided for convenience and to promote code reuse. */ 31 abstract class Widget : I Widget31 abstract class Widget : IChildWidget 32 32 { 33 33 //BEGIN Load and save 34 // Base this(). All widgets must check data.length is correct before calling this method. 35 // The widget ID is saved to widgetType, for correct saving. 36 this (IWindow wind, int[] data) { 37 window = wind; 38 widgetType = data[0]; 34 // Base this() for child Widgets. 35 this (IWidgetManager mgr, WidgetData data) { 36 this.mgr = mgr; 39 37 } 40 38 41 // Most widgets don't need to do adjustments based on mutable data, however they usually do 42 // still need to set their size. 43 int[] adjust (int[] data) { 44 setWidth (0,-1); 45 setHeight (0,-1); 46 return data; 47 } 48 49 // Widget type should always be the first value. Any widget using extra creation data will need 50 // to reimplemnt this method. 51 int[] getCreationData () { 52 return [widgetType]; 53 } 54 // Most widgets don't use mutable data. 55 int[] getMutableData () { 56 return []; 39 // Very basic implementation which assumes the renderer cannot affect the widget's size. 40 bool rendererChanged () { 41 return false; 57 42 } 58 43 //END Load and save … … 70 55 } 71 56 72 void getCurrentSize (out wdim cw, out wdim ch) {57 deprecated void getCurrentSize (out wdim cw, out wdim ch) { 73 58 cw = w; 74 59 ch = h; … … 103 88 /* Basic draw method: draw the background (all widgets should do this). */ 104 89 void draw () { 105 window.renderer.drawWidgetBack (x,y, w,h);90 mgr.renderer.drawWidgetBack (x,y, w,h); 106 91 } 107 92 108 93 protected: 109 final int widgetType; // the type (stored for saving) 110 IWindow window; // the enclosing window 94 IWidgetManager mgr; // the enclosing window 111 95 wdim x, y; // position 112 96 wdim w, h; // size … … 123 107 * [widgetID, w, h] 124 108 * where w, h is the fixed size. */ 125 this (IWi ndow wind, int[]data) {126 mw = cast(wdim) data[1];127 m h = cast(wdim) data[2];128 super (wind, data);109 this (IWidgetManager mgr, WidgetData data) { 110 super (mgr, data); 111 mw = cast(wdim) data.ints[1]; 112 mh = cast(wdim) data.ints[2]; 129 113 w = mw; 130 114 h = mh; 131 115 } 132 133 int[] getCreationData () {134 return [widgetType, mw, mh];135 }136 116 } 117 137 118 /** A base for resizable widgets. */ 138 119 class SizableWidget : Widget { 139 120 // Check data.length is at least 1 before calling! 140 121 /// Constructor for a completely resizable [blank] widget. 141 this (IWi ndow wind, int[]data) {142 super ( wind, data);122 this (IWidgetManager mgr, WidgetData data) { 123 super (mgr, data); 143 124 } 144 125 mde/gui/widget/Window.d
r74 r75 98 98 yh = y+h; 99 99 } 100 //BEGIN Mergetag code101 void addTag (char[] tp, mt.ID id, char[] dt) {102 // Priority is HIGH_LOW, so don't overwrite data which has already been loaded.103 if (tp == "int[][int]") {104 if (id == "widgetData" && widgetData == null) {105 widgetData = cast(int[][widgetID]) parseTo!(int[][int]) (dt);106 }107 } else if (tp == "char[][int]") {108 if (id == "widgetStrings" && widgetStrings == null) {109 widgetStrings = parseTo!(char[][int]) (dt);110 }111 } else if (tp == "int[]") {112 if (id == "mutableData" && mutableData == null) {113 mutableData = parseTo!(int[]) (dt);114 }115 } else if (tp == "int") {116 if (id == "x" && x == -1) {117 x = cast(wdim) parseTo!(int) (dt);118 } else if (id == "y" && y == -1) {119 y = cast(wdim) parseTo!(int) (dt);120 }121 }122 }123 void writeAll (ItemDelg dlg)124 in {125 assert (widgetData is null, "Window.writeAll: widgetData !is null");126 } body {127 /+ NOTE: currently editing is impossible...128 if (edited) { // only save the widget creation data if it's been adjusted:129 addCreationData (widget); // generate widget save data
