changeset 170:e45226d3deae

Context menu services not applicable to the current type can now be hidden. Added files missing from previous commits.
author Diggory Hardy <diggory.hardy@gmail.com>
date Mon, 29 Jun 2009 21:20:16 +0200
parents bc1cf73dc835
children 7f7b2011b759
files codeDoc/jobs.txt data/L10n/en-GB.mtt data/conf/guiDemo.mtt mde/content/AStringContent.d mde/content/Content.d mde/content/ContentLoader.d mde/content/Debug.d mde/content/IContent.d mde/content/ServiceContent.d mde/content/Services.d mde/font/FontTexture.d mde/gui/WidgetManager.d mde/gui/widget/AChildWidget.d mde/gui/widget/ParentContent.d mde/gui/widget/TextWidget.d mde/gui/widget/contentFunctions.d mde/gui/widget/miscContent.d mde/mainLoop.d mde/menus.d mde/setup/Init.d
diffstat 20 files changed, 243 insertions(+), 91 deletions(-) [+]
line wrap: on
line diff
--- a/codeDoc/jobs.txt	Mon Jun 29 18:55:50 2009 +0200
+++ b/codeDoc/jobs.txt	Mon Jun 29 21:20:16 2009 +0200
@@ -9,6 +9,7 @@
 To do (importance 0-5: 0 pointless, 1 no obvious impact now, 2 todo sometime, 3 useful, 4 important, 5 urgent):
 Also search for FIXME/NOTE/BUG/WARNING comment marks.
 4   Should only have one instance of context menu widgets. Service menu callbacks don't get removed!
+3   Closing menus when release-click is not on menu or parent (ordinary & context).
 3   Dragging and dropping of editable data: should content immediately appear as being dragged?
 3   Dragging from anything other than AStringContentWidget.
 3   Single-line edit: pressing return should lose keyboard focus and change value
--- a/data/L10n/en-GB.mtt	Mon Jun 29 18:55:50 2009 +0200
+++ b/data/L10n/en-GB.mtt	Mon Jun 29 21:20:16 2009 +0200
@@ -5,11 +5,15 @@
 <entry|main.quit={0:"Quit"}>
 <entry|debug={0:"Debug",1:"Debug-mode menu of debugging functions"}>
 <entry|debug.guiDemo={0:"GUI Demo"}>
+<entry|debug.guiDemo.logWidgetSize={0:"Log widget sizes"}>
 <entry|help={0:"Help"}>
 <entry|help.about={0:"About",1:"Show author and copyright information"}>
 <entry|services={0:"Services"}>
 <entry|services.copy={0:"Copy",1:"Copy selected content to clipboard"}>
 <entry|services.paste={0:"Paste",1:"Paste clipboard contents into selected content object"}>
+<entry|services.calculator={0:"Calculator"}>
+<entry|services.calculator.increment={0:"Increment"}>
+<entry|services.calculator.decrement={0:"Decrement"}>
 {Font}
 <entry|lcdFilter={0:"LCD filtering",1:"Filtering used with LCD rendering."}>
 <entry|lcdFilter.none={0:"None",1:"Leaves big colour fringes."}>
--- a/data/conf/guiDemo.mtt	Mon Jun 29 18:55:50 2009 +0200
+++ b/data/conf/guiDemo.mtt	Mon Jun 29 21:20:16 2009 +0200
@@ -45,8 +45,11 @@
 <WidgetData|sliderW={0:[0x4044]}>
 
 <WidgetData|context={0:[0x4204, 1],1:["contextLayout"]}>
-<WidgetData|contextLayout={0:[0x4100,4,2,1],1:["optDBox","contextServices"]}>
-<WidgetData|contextServices={0:[0x2031],1:["menus.services","contextMenu"]}>
-<WidgetData|contextMenu={0:[0x6030,0,1],1:["contextMenu"]}>
+<WidgetData|contextLayout={0:[0x4100,4,2,1],1:["optDesc","contextServices"]}>
+<WidgetData|contextServices={0:[0x2031],1:["menus.services","contextMenuCollapse"]}>
+<WidgetData|contextMenuCollapse={0:[0x4214],1:["contextMenu"]}>
+<WidgetData|contextMenu={0:[0x6030,0,1],1:["contextMenuCollapse2"]}>
+<WidgetData|contextMenuCollapse2={0:[0x4214],1:["contextMenu2"]}>
+<WidgetData|contextMenu2={0:[0x6033,0,1],1:["contextMenuCollapse2"]}>
 {Basic}
 <WidgetData|root={0:[0x21,0x90D970],1:["A string!"]}>
--- a/mde/content/AStringContent.d	Mon Jun 29 18:55:50 2009 +0200
+++ b/mde/content/AStringContent.d	Mon Jun 29 21:20:16 2009 +0200
@@ -196,7 +196,7 @@
     size_t pos;		// editing position; used by keyStroke
 }
 
-class BoolContent : AStringContent
+class BoolContent : AStringContent, IBoolContent
 {
     /** Create a content with _symbol name symbol. */
     this (char[] symbol) {
@@ -214,11 +214,11 @@
 	if (pos > sv.length) pos = sv.length;
         endEvent;
     }
-    void opAssign (bool val) {
+    override void opAssign (bool val) {
 	assignNoCng (val);
         endCng;
     }
-    bool opCall () {
+    override bool opCall () {
         return v;
     }
     alias opCall opCast;
@@ -532,6 +532,7 @@
      * parent Enum.
      * 
      * Also should not save its value, since the parent stores the value. */
+    //NOTE: Could extend IBoolContent instead of BoolContent now.
     private class EnumValueContent : BoolContent {
         /** New enumeration of parent with index num. */
         this (EnumContent parent, size_t num, char[] symbol) {
--- a/mde/content/Content.d	Mon Jun 29 18:55:50 2009 +0200
+++ b/mde/content/Content.d	Mon Jun 29 21:20:16 2009 +0200
@@ -107,12 +107,12 @@
    
     /** Add a callback. Callbacks are called on a change or event, in the order
      * added. */
-    Content addCallback (void delegate (Content) cb) {
+    override IContent addCallback (void delegate (IContent) cb) {
 	this.cb ~= cb;
 	return this;
     }
     /// ditto
-    Content addCallback (void function (Content) cb) {
+    override IContent addCallback (void function (IContent) cb) {
 	this.cb ~= util.toDg (cb);
 	return this;
     }
@@ -148,7 +148,7 @@
 protected:
     char[] symbol;
     char[] name_, desc_;	// translated name and description
-    void delegate (Content) cb[];
+    void delegate (IContent) cb[];
     
 public static:
     /** Get Content with _symbol name symbol from the list of all content, or
--- a/mde/content/ContentLoader.d	Mon Jun 29 18:55:50 2009 +0200
+++ b/mde/content/ContentLoader.d	Mon Jun 29 21:20:16 2009 +0200
@@ -95,7 +95,7 @@
 private:
     /* Load translations for all content.
      * Hooked as a change callback for l10n. */
-    void translate (Content) {
+    void translate (IContent) {
         logger.info ("loading translations...");
         Translation trl = Translation.get (l10n());
         
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mde/content/Debug.d	Mon Jun 29 21:20:16 2009 +0200
@@ -0,0 +1,34 @@
+/* LICENSE BLOCK
+Part of mde: a Modular D game-oriented Engine
+Copyright © 2007-2009 Diggory Hardy
+
+This program is free software: you can redistribute it and/or modify it under the terms
+of the GNU General Public License as published by the Free Software Foundation, either
+version 2 of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+/******************************************************************************
+ * Options enabling/disabling various debugging facilities.
+ *****************************************************************************/
+module mde.content.Debug;
+
+import mde.content.AStringContent;
+
+/// Wrapper for options
+struct Debug {
+static:
+    /// Log a message everytime the widget under the mouse changes
+    BoolContent logUnderMouse;
+    BoolContent logPopupPositioning;
+    
+    static this () {
+	logUnderMouse = new BoolContent ("options.Debug.logUnderMouse");
+	logPopupPositioning = new BoolContent ("options.Debug.logPopupPositioning");
+    }
+}
--- a/mde/content/IContent.d	Mon Jun 29 18:55:50 2009 +0200
+++ b/mde/content/IContent.d	Mon Jun 29 21:20:16 2009 +0200
@@ -51,6 +51,9 @@
     /** Similarly, try to set the value directly from a string.
      * Doesn't do anything for content not storing a value. */
     void opAssign (char[]);
+    
+    IContent addCallback (void delegate (IContent) cb);
+    IContent addCallback (void function (IContent) cb);
 }
 
 /** Interface for content which should be interacted with as a button.
@@ -59,3 +62,11 @@
  * functions a button is desired. */
 interface IEventContent : IContent {
 }
+
+/// Interface for boolean-value content
+interface IBoolContent : IContent {
+    /// Return the value
+    bool opCall ();
+    /// Directly set the value
+    void opAssign (bool val);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mde/content/ServiceContent.d	Mon Jun 29 21:20:16 2009 +0200
@@ -0,0 +1,140 @@
+/* LICENSE BLOCK
+Part of mde: a Modular D game-oriented Engine
+Copyright © 2007-2009 Diggory Hardy
+
+This program is free software: you can redistribute it and/or modify it under the terms
+of the GNU General Public License as published by the Free Software Foundation, either
+version 2 of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+/** Content services.
+ *
+ * Each is a Content, so it can be used in a menu. Since the content being
+ * acted on is not passed when functions are called like this, it is set when
+ * a context menu is opened, which also allows the services to specify their
+ * compatibility with the content (type) passed (via BoolContent value and
+ * callbacks).
+ */
+module mde.content.ServiceContent;
+
+import mde.content.AStringContent;
+
+/** Interface for ServiceContent and ServiceContentList. */
+interface IServiceContent {
+    void setContent (Content cont);
+}
+
+/** A class for services acting on content.
+ *
+ * Provides services for any content usable as type T, where T is some content
+ * type.
+ * 
+ * The (boolean) value is true to indicate this service can act on the passed
+ * content type, false if not. */
+class ServiceContent(T : Content = AStringContent) : Content, IServiceContent, IBoolContent, IEventContent {
+    this (char[] symbol) {
+	super (symbol);
+    }
+    
+    /** Pass the content this service should prepare for.
+     *
+     * Stores the reference, because it won't be passed later. */
+    override void setContent (Content cont) {
+	activeCont = cast(T)cont;
+    }
+    
+    override bool opCall () {
+	return activeCont is null;
+    }
+    // Doesn't support directly setting the value
+    override void opAssign (bool val) {}
+    
+package:
+    T activeCont;
+}
+
+/** Aliases for common types */
+alias ServiceContent!(AStringContent) AStringService;
+alias ServiceContent!(IntContent) IntService;	///ditto
+
+/** A generic way to handle a list of type IContent. */
+class ServiceContentList : ContentList, IServiceContent, IBoolContent
+{
+    this (char[] symbol) {
+	super (symbol);
+    }
+    
+    void setContent (Content cont) {
+	foreach (child; list_) {
+	    debug assert (cast(IServiceContent)child !is null);
+	    (cast(IServiceContent)child).setContent (cont);
+	}
+    }
+    
+    override bool opCall () {
+	foreach (child; list_) {
+	    debug assert (cast(IBoolContent)child !is null);
+	    if (!(cast(IBoolContent)child)())
+		return false;
+	}
+	return true;
+    }
+    // Doesn't support directly setting the value
+    override void opAssign (bool val) {}
+}
+
+/** Create all services.
+*
+* For now, all are under the menu.
+* 
+* Currently all clipboard operations convert to/from a string.
+* TODO: Possible extensions: multi-item clipboard displaying value in menu,
+* copying without converting everything to/from a string. */
+static this () {
+    // Create ContentLists so they have the correct type.
+    new ServiceContentList ("menus.services");
+    // Many use callbacks on a generic class type. For this, we should be sure of the type.
+    auto copy = new AStringService("menus.services.copy");
+    copy.addCallback ((IContent c) {
+	debug assert (cast(AStringService)c);
+	with (cast(AStringService)c) {
+	    if (activeCont !is null)
+		clipboard = activeCont.toString(0);
+	}
+    });
+    auto paste = new AStringService("menus.services.paste");
+    paste.addCallback ((IContent c) {
+	debug assert (cast(AStringService)c);
+	with (cast(AStringService)c) {
+	    if (activeCont !is null)
+		activeCont = clipboard;
+	}
+    });
+    
+    new ServiceContentList("menus.services.calculator");
+    auto inc = new IntService("menus.services.calculator.increment");
+    inc.addCallback ((IContent c) {
+	debug assert (cast(IntService)c);
+	with (cast(IntService)c) {
+	    if (activeCont !is null)
+		activeCont = activeCont()+1;
+	}
+    });
+    auto dec = new IntService("menus.services.calculator.decrement");
+    dec.addCallback ((IContent c) {
+	debug assert (cast(IntService)c);
+	with (cast(IntService)c) {
+	    if (activeCont !is null)
+		activeCont = activeCont()-1;
+	}
+    });
+}
+private {
+    char[] clipboard;
+}
--- a/mde/content/Services.d	Mon Jun 29 18:55:50 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/* LICENSE BLOCK
-Part of mde: a Modular D game-oriented Engine
-Copyright © 2007-2008 Diggory Hardy
-
-This program is free software: you can redistribute it and/or modify it under the terms
-of the GNU General Public License as published by the Free Software Foundation, either
-version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>. */
-
-// NOTE: This module is currently unused and untested.
-// FIXME: write unittests
-
-/** Content services.
- *
- * Services act on a content, potentially modifying it. They have the form:
- * ---
- * bool service (Content c);
- * ---
- * where c is the content acted on, and the return value is true if the content was changed (useful
- * to know whether caches need updating or not).
- */
-module mde.content.Services;
-
-import mde.content.AStringContent;
-
-union ContentUnion {
-    *Content ;
-}
-
-bool copy (Content c) {
-    // store by type
-    clipboard = c;
-}
-
-bool paste (StringContent c) {
-    if (clipboard)
-    	c = clipboard.toString (0);
-}
-
-bool paste (IntContent c) {
-    
-}
-
-bool link (ref ContentText c) {
-    if (clipboard is null)
-        return false;	// no item on clipboard, so don't do anything
-    c = clipboard;
-    return true;
-}
-
-ContentUnion clipboard;
--- a/mde/font/FontTexture.d	Mon Jun 29 18:55:50 2009 +0200
+++ b/mde/font/FontTexture.d	Mon Jun 29 21:20:16 2009 +0200
@@ -459,7 +459,7 @@
         lcdFilter = new EnumContent ("Font.lcdFilter", ["none"[],"default","light"]);
         defaultSize = new IntContent ("Font.defaultSize");
         defaultFont = new StringContent ("Font.defaultFont");
-        mode.addCallback (delegate void(Content) {
+        mode.addCallback (delegate void(IContent) {
            /* modeFlag should have one of the following values:
             * FT_LOAD_TARGET_NORMAL    (0x00000)
             * FT_LOAD_TARGET_LIGHT     (0x10000)
--- a/mde/gui/WidgetManager.d	Mon Jun 29 18:55:50 2009 +0200
+++ b/mde/gui/WidgetManager.d	Mon Jun 29 21:20:16 2009 +0200
@@ -246,6 +246,8 @@
     
     MenuPosition positionPopup (IChildWidget parent, IChildWidget popup, MenuPosition position = MenuPosition.INACTIVE) {
 	debug assert (parent && popup, "positionPopup: null widget");
+	debug if (Debug.logPopupPositioning())
+	    logger.trace ("Placing popup {} in relation to parent {}; input position: {}", popup, parent, position);
         wdim w = popup.width,
              h = popup.height,
              x, y;
@@ -279,7 +281,8 @@
         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);
+	debug if (Debug.logPopupPositioning())
+	    logger.trace ("Placed popup {}; output position: {}", popup, position);
 	return position;
     }
 
@@ -288,7 +291,7 @@
     }
     //END IWidgetManager methods
     
-    debug void logWidgetSize (Content) {
+    debug void logWidgetSize (IContent) {
         logger.trace ("size: {,4},{,4}; minimal: {,4},{,4} - WidgetManager", w,h, mw,mh);
         child.logWidgetSize;
     }
@@ -340,8 +343,8 @@
 	    serviceContent.setContent (contextContent);
 	    popupContext = makeWidget (this, "context", contextContent);
 	    popupContext.setup (0, 3);
-	    positionPopup (underMouse, popupContext);
-	    menuActive = MenuPosition.ACTIVE;
+	    //NOTE: usually set parentIPPW.menuActive:
+	    menuActive = positionPopup (underMouse, popupContext);
 	    requestRedraw;
 	} else {	// post other button presses to clickEvent
 	    int ret = underMouse.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state);
@@ -385,7 +388,7 @@
     /** A change callback on MiscOptions.l10n content to update widgets.
      *
      * Relies on another callback reloading translations to content first! */
-    void reloadStrings (Content) {
+    void reloadStrings (IContent) {
         synchronized(mutex) {
             if (child is null) return;
             child.setup (++setupN, 2);
--- a/mde/gui/widget/AChildWidget.d	Mon Jun 29 18:55:50 2009 +0200
+++ b/mde/gui/widget/AChildWidget.d	Mon Jun 29 21:20:16 2009 +0200
@@ -22,7 +22,7 @@
 module mde.gui.widget.AChildWidget;
 
 public import mde.gui.widget.Ifaces;
-import mde.content.Content;
+import mde.content.IContent;
 import mde.gui.exception;
 
 debug {
@@ -206,7 +206,7 @@
     /** Hook this function to a Content callback to cause redraws.
      *
      * mgr.requestRedraw could be hooked in directly if the prototype changed. */
-    void contentRedraw (Content) {
+    void contentRedraw (IContent) {
         mgr.requestRedraw;
     }
     
--- a/mde/gui/widget/ParentContent.d	Mon Jun 29 18:55:50 2009 +0200
+++ b/mde/gui/widget/ParentContent.d	Mon Jun 29 21:20:16 2009 +0200
@@ -124,7 +124,7 @@
     }
     
 protected:
-    void updateVal (Content) {	// callback
+    void updateVal (IContent) {	// callback
         adapter.text = content_.toString(cIndex);
         wdim omw = mw, omh = mh;
         adapter.getDimensions (mw, mh);
@@ -186,6 +186,12 @@
         return r;
     }
     
+    override void recursionCheck (widgetID wID, IContent c) {
+	if (wID is id && c is content_)
+	    throw new WidgetRecursionException (wID);
+	parent.recursionCheck (wID, c);
+    }
+    
     override void minWChange (IChildWidget widget, wdim nmw) {
         if (widget !is currentW) return;
         mw = nmw;
@@ -229,7 +235,7 @@
     
 protected:
     // callback on content_
-    void switchWidget (Content) {
+    void switchWidget (IContent) {
         currentW = subWidgets[content_()];
         mw = currentW.minWidth;
         mh = currentW.minHeight;
@@ -249,7 +255,7 @@
     bool isWS, isHS;	// no infrastructure for changing sizability, so need to fix it.
 }
 
-/** A collapsible widget: shows/hides a child dependant on a BoolContent.
+/** A collapsible widget: shows/hides a child dependant on an IBoolContent.
  *
  * Sizability is set once. Min-size is changed (but cannot force size to 0).
  * 
@@ -259,7 +265,7 @@
 {
     this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData data, IContent c) {
         super (mgr, parent, id);
-        content_ = cast(BoolContent) c;
+        content_ = cast(IBoolContent) c;
         WDCCheck (data, 1, 1, content_);
         
         subWidgets = [mgr.makeWidget (this, data.strings[0], c)];
@@ -281,6 +287,12 @@
         return r;
     }
     
+    override void recursionCheck (widgetID wID, IContent c) {
+	if (wID is id && c is content_)
+	    throw new WidgetRecursionException (wID);
+	parent.recursionCheck (wID, c);
+    }
+    
     override IContent content () {
         return content_;
     }
@@ -331,7 +343,7 @@
     
 protected:
     // callback on content_
-    void collapse (Content) {
+    void collapse (IContent) {
         collapsed = content_();
         if (collapsed) {
             mw = mh = 0;
@@ -349,7 +361,7 @@
     }
     
     bool collapsed = false;
-    BoolContent content_;
+    IBoolContent content_;
 }
 
 /** Puts a border around its child widget.
--- a/mde/gui/widget/TextWidget.d	Mon Jun 29 18:55:50 2009 +0200
+++ b/mde/gui/widget/TextWidget.d	Mon Jun 29 21:20:16 2009 +0200
@@ -111,7 +111,7 @@
     }
     
 protected:
-    void updateVal (Content) {	// callback
+    void updateVal (IContent) {	// callback
         adapter.text = content_.toString(cIndex);
         wdim omw = mw, omh = mh;
         adapter.getDimensions (mw, mh);
@@ -192,7 +192,7 @@
     }
     
 protected:
-    void update (Content) {	// callback
+    void update (IContent) {	// callback
         adapter.text = content_.toString(0);
         wdim omw = mw, omh = mh;
         adapter.getDimensions (mw, mh);
--- a/mde/gui/widget/contentFunctions.d	Mon Jun 29 18:55:50 2009 +0200
+++ b/mde/gui/widget/contentFunctions.d	Mon Jun 29 21:20:16 2009 +0200
@@ -54,7 +54,7 @@
     if (cast(AStringContent) c) {
         if (cast(EnumContent) c)	// can be PopupMenuWidget or ContentListWidget
             return new PopupMenuWidget(mgr,parent,id,data,c);
-        if (cast(BoolContent) c)
+        if (cast(IBoolContent) c)
             return new BoolContentWidget(mgr,parent,id,data,c);
         return new AStringContentWidget(mgr,parent,id,data,c);
     }
--- a/mde/gui/widget/miscContent.d	Mon Jun 29 18:55:50 2009 +0200
+++ b/mde/gui/widget/miscContent.d	Mon Jun 29 21:20:16 2009 +0200
@@ -37,7 +37,7 @@
 class BoolContentWidget : AButtonWidget
 {
     this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData, IContent c) {
-	content_ = cast(BoolContent) c;
+	content_ = cast(IBoolContent) c;
         if (content_ is null) throw new ContentException (this);
         super (mgr, parent, id);
         wdimPair s = mgr.renderer.getToggleSize;
@@ -65,7 +65,7 @@
     }
     
 protected:
-    BoolContent content_;
+    IBoolContent content_;
 }
 
 /// A button connected to an EventContent
--- a/mde/mainLoop.d	Mon Jun 29 18:55:50 2009 +0200
+++ b/mde/mainLoop.d	Mon Jun 29 21:20:16 2009 +0200
@@ -14,7 +14,7 @@
 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 /******************************************************************************
- * Adds some basic functionality to the main loop.
+ * Adds some standard functionality to the main loop.
  *****************************************************************************/
 module mde.mainLoop;
 
@@ -29,7 +29,7 @@
     mainSchedule.add (mainSchedule.getNewID, &mde.events.pollEvents).frame = true;
     // Polling interval of main loop; use old name to save renaming:
     pollInterval = new DoubleContent ("MiscOptions.pollInterval");
-    pollInterval.addCallback (delegate void(Content) {
+    pollInterval.addCallback (delegate void(IContent) {
         if (pollInterval() !<= 0.1 || pollInterval() !>= 0.0)
             pollInterval = 0.01;
         mainInterval = pollInterval();
--- a/mde/menus.d	Mon Jun 29 18:55:50 2009 +0200
+++ b/mde/menus.d	Mon Jun 29 21:20:16 2009 +0200
@@ -30,13 +30,13 @@
 
 static this () {
     auto quit = new EventContent("menus.main.quit");
-    quit.addCallback ((Content){
+    quit.addCallback ((IContent){
         debug logger.trace ("Quit (from menu)");
         run = false;
     });
     
     auto about = new EventContent("menus.help.about");
-    about.addCallback ((Content){
+    about.addCallback ((IContent){
 	//TODO: popup dialog box
 	logger.info ("MDE  Copyright (C) 2007-2009  Diggory Hardy");
 	logger.info ("This program comes with ABSOLUTELY NO WARRANTY; for details see COPYING.");
--- a/mde/setup/Init.d	Mon Jun 29 18:55:50 2009 +0200
+++ b/mde/setup/Init.d	Mon Jun 29 21:20:16 2009 +0200
@@ -402,7 +402,7 @@
         EnumContent logLevel, logOutput;
         
         // Callback on logLevel
-        void setLogLevel (Content = null) {
+        void setLogLevel (IContent = null) {
 	    int level = logLevel();
 	    if (level < Level.Trace || level > Level.None) {
 		logger.error ("incorrect logging level");