Mercurial > projects > mde
diff mde/gui/WidgetManager.d @ 171:7f7b2011b759
Partially complete commit: code runs but context menus don't work.
Moved WMScreen.createRootWidget to WidgetManager.createWidgets.
Put childContext under a popupHandler widget.
TODO: implement IChildWidget.setContent(Content) (see AParentWidget.d:237).
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Sun, 26 Jul 2009 11:04:17 +0200 |
parents | e45226d3deae |
children | a1ba9157510e |
line wrap: on
line diff
--- a/mde/gui/WidgetManager.d Mon Jun 29 21:20:16 2009 +0200 +++ b/mde/gui/WidgetManager.d Sun Jul 26 11:04:17 2009 +0200 @@ -26,6 +26,7 @@ import mde.gui.WidgetDataSet; import mde.gui.widget.Ifaces; +import mde.gui.renderer.createRenderer; import imde = mde.imde; import mde.content.Content; @@ -41,6 +42,7 @@ import mde.gui.widget.miscContent; import mde.gui.widget.Floating; import mde.gui.widget.ParentContent; +import mde.gui.widget.AParentWidget; public import tango.core.sync.Mutex; import tango.util.log.Log : Log, Logger; @@ -75,9 +77,8 @@ assert (p, "MiscOptions.l10n not created!"); p.addCallback (&reloadStrings); - serviceContent = cast (IServiceContent) Content.get ("menus.services"); - assert (Content.get ("menus.services")); - assert (serviceContent !is null, "Content service menu doesn't exist or has wrong type"); + serviceContent = ServiceContentList.createItems (name); + assert (cast (IServiceContent) Content.get ("menus.services."~name)); debug { // add a debug-mode menu auto lWS = new EventContent ("menus.debug."~name~".logWidgetSize"); @@ -92,33 +93,43 @@ final void recursionCheck (widgetID, IContent) {} override void minWChange (IChildWidget widget, wdim nmw) { - if (widget !is child) // Usually because widget is a floating widget - // This may get called from a CTOR, hence we can't check widget is one of popupContext, etc. + if (widget !is childRoot) // Probably because widget is a popup widget + // This may get called from a CTOR, hence we can't check widget is one of childContext, etc. return; mw = nmw; if (w < nmw) { - child.setWidth (nmw, -1); + childRoot.setWidth (nmw, -1); w = nmw; } - child.setPosition (0,0); + childRoot.setPosition (0,0); requestRedraw; } override void minHChange (IChildWidget widget, wdim nmh) { - if (widget !is child) + if (widget !is childRoot) return; mh = nmh; if (h < nmh) { - child.setHeight (nmh, -1); + childRoot.setHeight (nmh, -1); h = nmh; } - child.setPosition (0,0); + childRoot.setPosition (0,0); requestRedraw; } + //END IParentWidget methods + + //BEGIN IWidget methods + override bool saveChanges () { + bool ret = childRoot.saveChanges; + ret |= childContext.saveChanges; + if (childDragged !is null) + ret |= childDragged.saveChanges; + return ret; + } override bool dropContent (IContent content) { return false; } - //END IParentWidget methods + //END IWidget methods //BEGIN IPopupParentWidget methods override IPopupParentWidget getParentIPPW () { @@ -126,10 +137,14 @@ } override void addChildIPPW (IPopupParentWidget ippw) { + requestRedraw; + if (ippw is childContext) { // special handling - a separate IPPW + contextActive = true; + return; + } if (childIPPW) childIPPW.removedIPPW; childIPPW = ippw; - requestRedraw; } override bool removeChildIPPW (IPopupParentWidget ippw) { if (childIPPW !is ippw) return false; @@ -144,6 +159,8 @@ mAIPPW = mA; if (childIPPW) childIPPW.menuActive = mA; + if (contextActive) + childContext.menuActive = mA; } override MenuPosition menuActive () { return mAIPPW; @@ -152,31 +169,24 @@ return MenuPosition.INACTIVE; } - override void menuDone () { - // close context menu, but not childIPPW - if (childIPPW is null) - menuActive = MenuPosition.INACTIVE; - popupContext = null; - requestRedraw; - } + // Note: also triggered by non-popup widgets + override void menuDone () {} override IChildWidget getPopupWidget (wdabs cx, wdabs cy, bool closePopup) { - if (popupContext) { - if (popupContext.onSelf (cx, cy)) - return popupContext.getWidget (cx, cy); - if (closePopup) { - if (childIPPW is null) - menuActive = MenuPosition.INACTIVE; - popupContext = null; - requestRedraw; - } + IChildWidget ret; + // Don't bother with childDragged; it has no interaction + if (contextActive) { + ret = childContext.getPopupWidget (cx, cy, closePopup); + if (ret) return ret; + if (closePopup) { + childContext.removedIPPW; + requestRedraw; + } } if (childIPPW) { - IChildWidget ret = - childIPPW.getPopupWidget (cx, cy, closePopup); + ret = childIPPW.getPopupWidget (cx, cy, closePopup); if (ret) return ret; if (closePopup) { - menuActive = MenuPosition.INACTIVE; removeChildIPPW (childIPPW); } } @@ -184,13 +194,15 @@ } override void drawPopup () { - if (popupContext) - popupContext.draw(); - if (dragContentDisplay) - dragContentDisplay.draw(); + if (contextActive) + childContext.draw(); + if (childDragged) + childDragged.draw(); } debug protected override bool isChild (IPopupParentWidget ippw) { + if (contextActive && ippw is childContext) + return true; return ippw is childIPPW; } @@ -293,16 +305,53 @@ debug void logWidgetSize (IContent) { logger.trace ("size: {,4},{,4}; minimal: {,4},{,4} - WidgetManager", w,h, mw,mh); - child.logWidgetSize; + logger.trace ("childRoot:"); + childRoot.logWidgetSize; + logger.trace ("childContext:"); + childContext.logWidgetSize; + if (childDragged !is null) { + logger.trace ("childDragged:"); + childDragged.logWidgetSize; + } } protected: // These methods are called by derived classes to do the widget-management work //BEGIN WidgetManagement methods + /** Second stage of widget loading. + * + * Widget data should be loaded before this is called. */ + final void createWidgets () { + // The renderer needs to be created on the first load, but not after this. + if (rend is null) + rend = createRenderer (rendName); + + debug (mdeWidgets) logger.trace ("Creating root widget..."); + childRoot = makeWidget (this, "root"); + debug (mdeWidgets) logger.trace ("Setting up root widget..."); + childRoot.setup (0, 3); + + mw = childRoot.minWidth; + mh = childRoot.minHeight; + matchMinimalSize (); + + debug (mdeWidgets) logger.trace ("Setting size and position of root widget..."); + childRoot.setWidth (w, -1); + childRoot.setHeight (h, -1); + childRoot.setPosition (0,0); + debug (mdeWidgets) logger.trace ("Done creating root widget."); + + childContext = new PopupHandlerWidget (this, this, "contextHandler", "context", serviceContent); + childContext.setup (0,3); + debug (mdeWidgets) logger.trace ("Created context handler widget."); + + underMouse = childRoot; // must be something + } + /** Draw all widgets */ - void wmDrawWidgets() { - if (child) - child.draw; + final void wmDrawWidgets() { + if (childRoot) + childRoot.draw; if (childIPPW) childIPPW.drawPopup; drawPopup; @@ -311,8 +360,8 @@ /** For mouse click events. * * Sends the event on to the relevant windows and all click callbacks. */ - void wmMouseClick (wdabs cx, wdabs cy, ubyte b, bool state) { - if (child is null) return; + final void wmMouseClick (wdabs cx, wdabs cy, ubyte b, bool state) { + if (childRoot is null) return; // Update underMouse to get the widget clicked on updateUnderMouse (cx, cy, state); @@ -321,7 +370,7 @@ if (dragStart !is null && b == dragButton && state == false) { IChildWidget dS = dragStart; dragStart = null; - dragContentDisplay = null; + childDragged = null; requestRedraw; if (dS.dragRelease (cx, cy, underMouse)) return; @@ -336,16 +385,11 @@ // Finally, post the actual event: if (b == 3 && state) { // right click - open context menu - if (popupContext !is null) return; Content contextContent = cast(Content)underMouse.content; - if (contextContent is null) return; - // NOTE: Creates new widgets every time; not optimal - serviceContent.setContent (contextContent); - popupContext = makeWidget (this, "context", contextContent); - popupContext.setup (0, 3); - //NOTE: usually set parentIPPW.menuActive: - menuActive = positionPopup (underMouse, popupContext); - requestRedraw; + if (contextContent !is null) { + serviceContent.setContent (contextContent); + childContext.openMenu (underMouse, contextContent); + } } else { // post other button presses to clickEvent int ret = underMouse.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state); if (ret & 1) { // keyboard input requested @@ -358,11 +402,11 @@ if (ret & 4) { IContent c = underMouse.content(); if (c) { // NOTE: creates a new widget, not optimal - dragContentDisplay = new DisplayContentWidget (this, this, "dragContentDisplay", WidgetData ([0], []), c); - dragContentDisplay.setup (0, 3); + childDragged = new DisplayContentWidget (this, this, "dragContentDisplay", WidgetData ([0], []), c); + childDragged.setup (0, 3); dragX = underMouse.xPos - cx; dragY = underMouse.yPos - cy; - dragContentDisplay.setPosition (cx + dragX, cy + dragY); + childDragged.setPosition (cx + dragX, cy + dragY); } } } @@ -372,13 +416,13 @@ /** For mouse motion events. * * Lock on mutex before calling. Pass new mouse coordinates. */ - void wmMouseMotion (wdabs cx, wdabs cy) { + final void wmMouseMotion (wdabs cx, wdabs cy) { updateUnderMouse (cx, cy, false); if (dragStart !is null) { dragStart.dragMotion (cx, cy, underMouse); - if (dragContentDisplay !is null) { - dragContentDisplay.setPosition (cx + dragX, cy + dragY); + if (childDragged !is null) { + childDragged.setPosition (cx + dragX, cy + dragY); requestRedraw; } } @@ -388,25 +432,25 @@ /** A change callback on MiscOptions.l10n content to update widgets. * * Relies on another callback reloading translations to content first! */ - void reloadStrings (IContent) { + final void reloadStrings (IContent) { synchronized(mutex) { - if (child is null) return; - child.setup (++setupN, 2); - child.setWidth (w, -1); - child.setHeight (h, -1); - child.setPosition (0,0); - popupContext.setup (setupN, 2); - //NOTE: does popupContext need to be re-scaled? + if (childRoot is null) return; + childRoot.setup (++setupN, 2); + childRoot.setWidth (w, -1); + childRoot.setHeight (h, -1); + childRoot.setPosition (0,0); + childContext.setup (setupN, 2); + //TODO: possibly childDragged? requestRedraw; } } // for internal use - void updateUnderMouse (wdabs cx, wdabs cy, bool closePopup) { + final void updateUnderMouse (wdabs cx, wdabs cy, bool closePopup) { auto oUM = underMouse; underMouse = getPopupWidget (cx, cy, closePopup); if (underMouse is null) { - debug assert (child.onSelf (cx, cy), "WidgetManager: child doesn't cover whole area"); - underMouse = child.getWidget (cx, cy); + debug assert (childRoot.onSelf (cx, cy), "WidgetManager: childRoot doesn't cover whole area"); + underMouse = childRoot.getWidget (cx, cy); } if (underMouse !is oUM) { debug assert (oUM && underMouse, "no widget under mouse: error"); @@ -417,6 +461,23 @@ } } + /** If possible, the screen-interaction derived class should override to + * make sure the window is at least (mw,mh) in size. In any case, this + * method MUST make sure w >= mw and h >= mh even if the window isn't this + * big. + * + * A resize may not be required when this is called, however. */ + void matchMinimalSize () { + if (w < mw) { + logger.warn ("Min width for gui, {}, not met: {}", mw, w); + w = mw; + } + if (h < mh) { + logger.warn ("Min height for gui, {}, not met: {}", mh, h); + h = mh; + } + } + /// This should be overloaded to set a callback receiving keyboard input. abstract void setLetterCallback(void delegate(ushort, char[])); //END WidgetManagement methods @@ -529,32 +590,47 @@ //END makeWidget metacode protected: - WidgetDataSet curData; // Current data - WidgetDataChanges changes; // Changes for the current design. + // Main child widget: + IChildWidget childRoot; // Root of the main GUI widget tree - char[] rendName; // Name of renderer; for saving and creating renderers - IRenderer rend; - - // Widgets: + // Dimensions and child set-up data (fit to childRoot): wdim w,h; // current widget size; should be at least (mw,mh) even if not displayable wdim mw,mh; // minimal area required by widgets - scope IChildWidget child; // The primary widget. uint setupN; // n to pass to IChildWidget.setup + // IPopupParentWidget stuff for childRoot: MenuPosition mAIPPW; // IPPW variable IPopupParentWidget childIPPW; // child IPPW, if any active - // Popup(s) handled directly by AWidgetManager: - IChildWidget popupContext; // context menu (active if not null) - IServiceContent serviceContent; // context menu content tree - IChildWidget dragContentDisplay; // displays dragged content; no interaction + IChildWidget keyFocus; // widget receiving keyboard input + IChildWidget underMouse; // widget under the mouse pointer + + // Context menu: + // Essentially, we consider childContext a full child IPPW, but handle it separately from + // childIPPW. Instead of providing another ref. for this IPPW, shortcut by using this reference + // and the boolean contextActive: + scope PopupHandlerWidget childContext; // context menu popup (handler) + bool contextActive = false; // If true, consider childContext a child IPPW + scope IServiceContent serviceContent; // context menu content tree + + + // Drag-and-drop data: + //NOTE: could be wrapped with a PopupHandlerWidget, but can't set position then? + scope IChildWidget childDragged; // displays dragged content; no interaction IChildWidget dragStart; // if non-null, this widget should receive motion and click-release events int dragButton; // index of button in use for drag wdrel dragX, dragY; // coordinates of dragged content relative to mouse - IChildWidget keyFocus; // widget receiving keyboard input - IChildWidget underMouse; // widget under the mouse pointer + + // Renderer: + char[] rendName; // Name of renderer; for saving and creating renderers + scope IRenderer rend; + + + // Data loaded/to save: + WidgetDataSet curData; // Current data + WidgetDataChanges changes; // Changes for the current design. Mutex mutex; // lock on methods for use outside the package. }