# HG changeset patch # User Diggory Hardy # Date 1234353612 0 # Node ID 783969f4665cbd5aacce51aa2783a7d0f761b831 # Parent 1048b5c7cab11167eaf021ab98bfedcead34778f Simple, inefficient context menus (displaying content description). diff -r 1048b5c7cab1 -r 783969f4665c data/L10n/en-GB.mtt --- a/data/L10n/en-GB.mtt Tue Feb 10 13:10:53 2009 +0000 +++ b/data/L10n/en-GB.mtt Wed Feb 11 12:00:12 2009 +0000 @@ -28,7 +28,7 @@ - + diff -r 1048b5c7cab1 -r 783969f4665c data/conf/guiDemo.mtt --- a/data/conf/guiDemo.mtt Tue Feb 10 13:10:53 2009 +0000 +++ b/data/conf/guiDemo.mtt Wed Feb 11 12:00:12 2009 +0000 @@ -25,7 +25,7 @@ !{use optBox for no description, optDBox for descriptions under entries} - + @@ -42,5 +42,7 @@ + + {Basic} diff -r 1048b5c7cab1 -r 783969f4665c mde/gui/WMScreen.d --- a/mde/gui/WMScreen.d Tue Feb 10 13:10:53 2009 +0000 +++ b/mde/gui/WMScreen.d Wed Feb 11 12:00:12 2009 +0000 @@ -74,6 +74,7 @@ child.draw; if (childIPPW) childIPPW.drawPopup; + drawPopup; } } @@ -81,8 +82,7 @@ * * Sends the event on to the relevant windows and all click callbacks. */ void clickEvent (ushort usx, ushort usy, ubyte b, bool state) { - debug scope (failure) - logger.warn ("clickEvent: failed!"); + try { mutex.lock; scope(exit) mutex.unlock; if (child is null) return; @@ -102,27 +102,42 @@ keyFocus = null; input.setLetterCallback (null); } + // Finally, post the actual event: + if (b == 3 && state) { // right click - open context menu + IContent contextContent = underMouse.content; + if (contextContent is null) return; + // NOTE: Creates new widgets every time; not optimal + popupContext = makeWidget (this, "context", contextContent); + popupContext.setup (0, 3); + positionPopup (underMouse, popupContext, 0); + requestRedraw; + } else // post other button presses to clickEvent if (underMouse.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state) & 1) { // keyboard input requested keyFocus = underMouse; input.setLetterCallback (&underMouse.keyEvent); } + } catch (Exception e) { + logger.error ("clickEvent: exception processing event: {}", e.msg); + } } /** For mouse motion events. * * Sends the event on to all motion callbacks. */ void motionEvent (ushort scx, ushort scy) { - debug scope (failure) - logger.warn ("motionEvent: failed!"); - mutex.lock; - scope(exit) mutex.unlock; - wdabs cx = cast(wdabs) scx, cy = cast(wdabs) scy; - foreach (dg; motionCallbacks) - dg (cx, cy); - - updateUnderMouse (cx, cy, false); + try { + mutex.lock; + scope(exit) mutex.unlock; + wdabs cx = cast(wdabs) scx, cy = cast(wdabs) scy; + foreach (dg; motionCallbacks) + dg (cx, cy); + + updateUnderMouse (cx, cy, false); + } catch (Exception e) { + logger.error ("motionEvent: exception processing event: {}", e.msg); + } } diff -r 1048b5c7cab1 -r 783969f4665c mde/gui/WidgetManager.d --- a/mde/gui/WidgetManager.d Tue Feb 10 13:10:53 2009 +0000 +++ b/mde/gui/WidgetManager.d Wed Feb 11 12:00:12 2009 +0000 @@ -329,15 +329,30 @@ override void menuDone () {} override IChildWidget getPopupWidget (wdabs cx, wdabs cy, bool closePopup) { - IChildWidget ret; + if (popupContext) { + if (popupContext.onSelf (cx, cy)) + return popupContext; + if (closePopup) { + menuActive = (childIPPW !is null); + popupContext = null; + requestRedraw; + } + } if (childIPPW) { - ret = childIPPW.getPopupWidget (cx, cy, closePopup); - if (closePopup && ret is null) { + IChildWidget ret = + childIPPW.getPopupWidget (cx, cy, closePopup); + if (ret) return ret; + if (closePopup) { menuActive = false; removeChildIPPW (childIPPW); } } - return ret; + return null; + } + + override void drawPopup () { + if (popupContext) + popupContext.draw(); } debug protected override bool isChild (IPopupParentWidget ippw) { @@ -345,7 +360,6 @@ } override void removedIPPW () {} // irrelevant - override void drawPopup () {} //END IPopupParentWidget methods //BEGIN IWidgetManager methods @@ -401,17 +415,20 @@ h = popup.height, x, y; if (flags & 1) { - y = parent.yPos; - if (y+h > this.h) y += parent.height - h; - x = parent.xPos + parent.width; - if (x+w > this.w) x = parent.xPos - w; + y = parent.yPos; // height flush with top + if (y+h > this.h) y += parent.height - h; // or bottom + x = parent.xPos + parent.width; // on right + if (x+w > this.w) x = parent.xPos - w; // or left edge } else { x = parent.xPos; // align on left edge if (x+w > this.w) x += parent.width - w; // align on right edge y = parent.yPos + parent.height; // place below - if (y+h > this.h) y = parent.yPos - h; // place above + if (y+h > this.h) y = parent.yPos - h; // or above } + if (x < 0) x = 0; // may be placed partially off-screen + if (y < 0) y = 0; popup.setPosition (x, y); + //debug logger.trace ("placed popup at {},{}; size: {},{}", x,y, w,h); } void requestRedraw () { @@ -600,6 +617,9 @@ bool mAIPPW; // IPPW variable IPopupParentWidget childIPPW; // child IPPW, if any active + // Popup(s) handled directly by AWidgetManager: + IChildWidget popupContext; // context menu (active if not null) + // callbacks indexed by their frame pointers. Must support removal of elements in foreach: SortedMap!(void*,bool delegate(wdabs cx, wdabs cy, ubyte b, bool state)) clickCallbacks; SortedMap!(void*,void delegate(wdabs cx, wdabs cy)) motionCallbacks; diff -r 1048b5c7cab1 -r 783969f4665c mde/gui/widget/AChildWidget.d --- a/mde/gui/widget/AChildWidget.d Tue Feb 10 13:10:53 2009 +0000 +++ b/mde/gui/widget/AChildWidget.d Wed Feb 11 12:00:12 2009 +0000 @@ -58,6 +58,11 @@ override bool saveChanges () { return false; } + + // Widgets with content need to override this + override IContent content () { + return null; + } //END Load and save //BEGIN Size and position diff -r 1048b5c7cab1 -r 783969f4665c mde/gui/widget/Ifaces.d --- a/mde/gui/widget/Ifaces.d Tue Feb 10 13:10:53 2009 +0000 +++ b/mde/gui/widget/Ifaces.d Wed Feb 11 12:00:12 2009 +0000 @@ -31,7 +31,7 @@ public import mde.gui.types; public import mde.gui.renderer.IRenderer; -import mde.content.IContent; +public import mde.content.IContent; /****************************************************************************** @@ -199,7 +199,7 @@ wdims dimData (widgetID id); /// ditto void dimData (widgetID id, wdims d); /// ditto - /** Position popup left or right of parent, or left or right of parent + /** Position popup below or above parent, or right or left of parent * (flags & 1 == 1). */ void positionPopup (IChildWidget parent, IChildWidget popup, int flags = 0); @@ -240,14 +240,13 @@ /****************************************************************************** * Interface for (child) widgets, i.e. all widgets other than the manager. * - * A widget is a region of a GUI window which handles rendering and user-interaction for itself - * and is able to communicate with its manager and child widgets as necessary. (Passing widgets - * a reference to their parent has not been found useful.) + * A widget is a region of a GUI window which handles rendering and user- + * interaction for itself and is able to communicate with its manager and other + * widgets as necessary. * - * If a widget is to be creatable by IWidgetManager.makeWidget, it must be listed in the - * createWidget module, and have a constructor of the following form. It should also update it's - * creation data if necessary, either when changed or when saveChanges() is called, using - * IWidgetManager.setData(). + * If a widget is to be creatable by IWidgetManager.makeWidget, it must be + * listed in the AWidgetManager WIDGET_TYPE enum and WIDGETS list, and have a + * constructor of the following form. * It should use Ddoc to explain what initialization data is used. * ---------------------------------- * /++ Constructor for a ... widget. @@ -255,17 +254,20 @@ * + Widget uses the initialisation data: * + [widgetID, x, y] * + where x is ... and y is ... +/ - * this (IWidgetManager mgr, widgetID id, WidgetData data); + * this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData data); * * /// The CTOR may take an IContent reference: - * this (IWidgetManager mgr, widgetID id, WidgetData data, IContent content); + * this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData data, IContent content); * ---------------------------------- - * Where mgr is the widget manager, id is the _id passed to makeWidget() and data is - * initialisation data. The method should throw a WidgetDataException (created without - * parameters) if the data has wrong length or is otherwise invalid. + * Where mgr is the widget manager, parent is the widget's _parent (another + * child widget or the widget manager), id is the _id passed to makeWidget() + * and data is initialisation _data. The method should throw a + * WidgetDataException if the data is invalid, and throw other GuiExceptions on + * other errors. * - * All widgets should set their own size in this() or setup() (must be setup() if it could change), - * although some parents may set child-widgets' size during their creation. + * All widgets should set their own size in this() or setup() (must be setup() + * if it could change), although some parents may set child-widgets' size + * during their creation. *****************************************************************************/ //NOTE: add another this() without the data for default initialization, for the GUI editor? interface IChildWidget @@ -304,6 +306,8 @@ void childChanged (); +/ + /** Return the widget's content, or null. */ + IContent content (); //END Load and save //BEGIN Size and position diff -r 1048b5c7cab1 -r 783969f4665c mde/gui/widget/ParentContent.d --- a/mde/gui/widget/ParentContent.d Tue Feb 10 13:10:53 2009 +0000 +++ b/mde/gui/widget/ParentContent.d Wed Feb 11 12:00:12 2009 +0000 @@ -42,26 +42,30 @@ class PopupMenuWidget : APopupParentWidget { this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData data, IContent c) { - content = cast(Content)c; - WDCMinCheck (data, 3,1, content); + content_ = cast(Content)c; + WDCMinCheck (data, 3,1, content_); super (mgr, parent, id); - //popup = mgr.makeWidget (this, data.strings[0], content); + //popup = mgr.makeWidget (this, data.strings[0], content_); popup = new ContentListWidget (mgr, this, id, data, c); subWidgets = [popup]; cIndex = data.ints[2]; if (cIndex == 0) - content.addCallback (&updateVal); + content_.addCallback (&updateVal); adapter = mgr.renderer.getAdapter; - adapter.text = content.toString (cIndex); + adapter.text = content_.toString (cIndex); adapter.getDimensions (mw, mh); w = mw; h = mh; } + override IContent content () { + return content_; + } + override void recursionCheck (widgetID wID, IContent c) { - if (wID is id && c is content) + if (wID is id && c is content_) throw new WidgetRecursionException (wID); parent.recursionCheck (wID, c); } @@ -109,7 +113,7 @@ protected: void updateVal (Content) { // callback - adapter.text = content.toString(cIndex); + adapter.text = content_.toString(cIndex); wdim omw = mw, omh = mh; adapter.getDimensions (mw, mh); if (omw != mw) @@ -119,7 +123,7 @@ } bool pushed = false; IRenderer.TextAdapter adapter; - Content content; + Content content_; int cIndex; } @@ -131,16 +135,20 @@ { this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData data, IContent c) { super (mgr, parent, id); - content = cast(EnumContent) c; - if (content is null || (subWidgets.length = content.list.length) == 0) + content_ = cast(EnumContent) c; + if (content_ is null || (subWidgets.length = content_.list.length) == 0) throw new ContentException (this); WDCheck (data, 1, subWidgets.length); - foreach (i,sc; content.list) + foreach (i,sc; content_.list) subWidgets[i] = mgr.makeWidget (this, data.strings[i], sc); - currentW = subWidgets[content()]; + currentW = subWidgets[content_()]; - content.addCallback (&switchWidget); + content_.addCallback (&switchWidget); + } + + override IContent content () { + return content_; } override bool setup (uint n, uint flags) { @@ -152,7 +160,7 @@ h = currentW.height; static if (SIZABILITY & SIZABILITY_ENUM.START_TRUE) isWS = isHS = true; - foreach (i,sc; content.list) { + foreach (i,sc; content_.list) { static if (SIZABILITY == SIZABILITY_ENUM.ANY_SUBWIDGETS) { isWS |= subWidgets[i].isWSizable; isHS |= subWidgets[i].isHSizable; @@ -207,9 +215,9 @@ } protected: - // callback on content + // callback on content_ void switchWidget (Content) { - currentW = subWidgets[content()]; + currentW = subWidgets[content_()]; mw = currentW.minWidth; mh = currentW.minHeight; parent.minWChange (this, mw); @@ -223,7 +231,7 @@ } IChildWidget currentW; - EnumContent content; + EnumContent content_; bool isWS, isHS; // no infrastructure for changing sizability, so need to fix it. } @@ -238,18 +246,18 @@ { this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData data, IContent c) { super (mgr, parent, id); - content = cast(BoolContent) c; - WDCCheck (data, 1, 1, content); + content_ = cast(BoolContent) c; + WDCCheck (data, 1, 1, content_); subWidgets = [mgr.makeWidget (this, data.strings[0])]; - content.addCallback (&collapse); + content_.addCallback (&collapse); } override bool setup (uint n, uint flags) { bool r = super.setup (n, flags); if (r) { - collapsed = content(); + collapsed = content_(); if (!collapsed) { mw = subWidgets[0].minWidth; mh = subWidgets[0].minHeight; @@ -260,6 +268,10 @@ return r; } + override IContent content () { + return content_; + } + override void minWChange (IChildWidget widget, wdim nmw) { debug assert (widget is subWidgets[0]); mw = nmw; @@ -305,9 +317,9 @@ } protected: - // callback on content + // callback on content_ void collapse (Content) { - collapsed = content(); + collapsed = content_(); if (collapsed) { mw = mh = 0; } else { @@ -324,5 +336,5 @@ } bool collapsed = false; - BoolContent content; + BoolContent content_; } diff -r 1048b5c7cab1 -r 783969f4665c mde/gui/widget/TextWidget.d --- a/mde/gui/widget/TextWidget.d Tue Feb 10 13:10:53 2009 +0000 +++ b/mde/gui/widget/TextWidget.d Wed Feb 11 12:00:12 2009 +0000 @@ -88,27 +88,31 @@ class DisplayContentWidget : ATextWidget { this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData data, IContent c) { - content = cast(Content) c; - WDCMinCheck (data, 1, 0, content); + content_ = cast(Content) c; + WDCMinCheck (data, 1, 0, content_); super (mgr, parent, id); if (data.ints.length >= 3) cIndex = data.ints[2]; // otherwise display '0', the value if (cIndex == 0) - content.addCallback (&updateVal); + content_.addCallback (&updateVal); adapter = mgr.renderer.getAdapter (); } override bool setup (uint n, uint flags) { if (!(flags & 3)) return false; // string or renderer (and possibly font) changed - adapter.text = content.toString(cIndex); + adapter.text = content_.toString(cIndex); return super.setup (n, 3); // force redimensioning } + override IContent content () { + return content_; + } + protected: void updateVal (Content) { // callback - adapter.text = content.toString(cIndex); + adapter.text = content_.toString(cIndex); wdim omw = mw, omh = mh; adapter.getDimensions (mw, mh); if (omw != mw) @@ -116,7 +120,7 @@ if (omh != mh) parent.minHChange (this, mh); } - Content content; + Content content_; int cIndex; } @@ -124,13 +128,17 @@ class AStringContentWidget : ATextWidget { this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData, IContent c) { - content = cast(AStringContent) c; - if (content is null) throw new ContentException (this); + content_ = cast(AStringContent) c; + if (content_ is null) throw new ContentException (this); super (mgr, parent, id); - content.addCallback (&update); + content_.addCallback (&update); adapter = mgr.renderer.getAdapter (); - adapter.text = content.toString(0); + adapter.text = content_.toString(0); + } + + override IContent content () { + return content_; } override bool isWSizable () { @@ -142,15 +150,15 @@ /** On click, request keyboard input. */ override int clickEvent (wdabs cx, wdabs, ubyte, bool) { - //adapter.index = content.editIndex; - content.editIndex = adapter.setIndex (cx - x); + //adapter.index = content_.editIndex; + content_.editIndex = adapter.setIndex (cx - x); mgr.requestRedraw; return 1; // get keyboard input via keyEvent } override void keyEvent (ushort s, char[] i) { - adapter.text = content.keyStroke (s, i); - adapter.index = content.editIndex; + adapter.text = content_.keyStroke (s, i); + adapter.index = content_.editIndex; wdim omw = mw, omh = mh; adapter.getDimensions (mw, mh); if (omw != mw) @@ -160,14 +168,14 @@ mgr.requestRedraw; } override void keyFocusLost () { - adapter.text = content.endEdit; // update other users of content relying on callbacks + adapter.text = content_.endEdit; // update other users of content_ relying on callbacks adapter.index; mgr.requestRedraw; } protected: void update (Content) { // callback - adapter.text = content.toString(0); + adapter.text = content_.toString(0); wdim omw = mw, omh = mh; adapter.getDimensions (mw, mh); if (omw != mw) @@ -175,5 +183,5 @@ if (omh != mh) parent.minHChange (this, mh); } - AStringContent content; + AStringContent content_; } diff -r 1048b5c7cab1 -r 783969f4665c mde/gui/widget/layout.d --- a/mde/gui/widget/layout.d Tue Feb 10 13:10:53 2009 +0000 +++ b/mde/gui/widget/layout.d Wed Feb 11 12:00:12 2009 +0000 @@ -116,6 +116,10 @@ } } + override IContent content () { + return cList; + } + override void recursionCheck (widgetID wID, IContent c) { if (wID is id && c is cList) throw new WidgetRecursionException (wID); diff -r 1048b5c7cab1 -r 783969f4665c mde/gui/widget/miscContent.d --- a/mde/gui/widget/miscContent.d Tue Feb 10 13:10:53 2009 +0000 +++ b/mde/gui/widget/miscContent.d Wed Feb 11 12:00:12 2009 +0000 @@ -37,39 +37,43 @@ class BoolContentWidget : AButtonWidget { this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData, IContent c) { - content = cast(BoolContent) c; - if (content is null) throw new ContentException (this); + content_ = cast(BoolContent) c; + if (content_ is null) throw new ContentException (this); super (mgr, parent, id); wdimPair s = mgr.renderer.getToggleSize; w = mw = s.x; h = mh = s.y; } + override IContent content () { + return content_; + } + override void draw () { - mgr.renderer.drawToggle (x,y, content(), pushed); + mgr.renderer.drawToggle (x,y, content_(), pushed); } override void activated () { - content = !content(); + content_ = !content_(); } protected: - BoolContent content; + BoolContent content_; } /// A button connected to an EventContent class ButtonContentWidget : AButtonWidget { this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData, IContent c) { - content = cast(Content) c; - if (content is null) throw new ContentException (this); + content_ = cast(Content) c; + if (content_ is null) throw new ContentException (this); adapter = mgr.renderer.getAdapter (); super (mgr, parent, id); } override bool setup (uint n, uint flags) { if (!(flags & 3)) return false; // string or renderer (and possibly font) changed - adapter.text = content.toString(1); + adapter.text = content_.toString(1); adapter.getDimensions (mw, mh); if (mw != w || mh != h) { w = mw; @@ -78,18 +82,22 @@ return true; } + override IContent content () { + return content_; + } + override void draw () { super.draw(); adapter.draw (x,y); } override void activated () { - content.endEvent; + content_.endEvent; } protected: IRenderer.TextAdapter adapter; - Content content; + Content content_; int index; } @@ -97,23 +105,27 @@ class SliderContentWidget : AChildWidget { this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData, IContent c) { - content = cast(DoubleContent) c; - if (content is null) throw new ContentException (this); + content_ = cast(DoubleContent) c; + if (content_ is null) throw new ContentException (this); super (mgr, parent, id); wdimPair s = mgr.renderer.getSliderSize; w = mw = s.x; h = mh = s.y; } + override IContent content () { + return content_; + } + override bool isWSizable () { return true; } override void draw () { - mgr.renderer.drawSlider (x,y, w, content()); + mgr.renderer.drawSlider (x,y, w, content_()); } protected: - DoubleContent content; + DoubleContent content_; }