Mercurial > projects > mde
view mde/content/Content.d @ 167:620d4ea30228
Context menus: added a clipboard (functions accessible from main menu rather than context menu).
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Sat, 27 Jun 2009 11:57:26 +0200 |
parents | bb2f1a76346d |
children | da8d3091fdaf |
line wrap: on
line source
/* 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/>. */ /****************************************************************************** * The content system − interfaces and base Content class. *****************************************************************************/ module mde.content.Content; public import mde.content.IContent; import mde.content.Translation; // loading strings import mde.content.ValueCache; // saving/loading content values import util = mde.util; // fp -> dlg import mde.exception; import mde.setup.logger; import tango.util.log.Log : Log, Logger; private Logger logger; static this () { logger = Log.getLogger ("mde.gui.content.Content"); } /** Content lists. Impemented by EnumContent as well as ContentList. */ interface IContentList : IContent { /** Return all sub-contents. */ Content[] list (); /** Append x to the content list. * * Done automatically in creation, from symbol name, so don't call * externally. */ void append (Content x); } /****************************************************************************** * The base for most or all content classes. * * Includes generic callback support, toString implementation and symbol access. * * Derived classes should impement: * --- * this (char[] symbol, T val = /+ default value +/); * void opAssign (T val); // assign val, calling callbacks * T opCall (); // return value * alias opCall opCast; * void endEvent (); // extend to set new value in changed (if Content has a value) * --- *****************************************************************************/ class Content : IContent { protected this (char[] symbol) { //debug logger.trace ("Creating a {}: {}", this, symbol); if (symbol in allContent) throw new ContentException ("Multiple content with symbol "~ symbol); allContent[symbol] = this; this.symbol = symbol; // Name: auto l10nP = symbol in translations; if (l10nP) name (*l10nP); else name_ = symbol; // provide a temporary name // Add to a parent list: ptrdiff_t i = symbol.length-1; while (i >= 0 && symbol[i] != '.') --i; IContentList parent; if (i <= 0) { if (symbol.length == 0) return; // special case: is tree (content tree root) parent = tree; // otherwise, use tree as root } else { char[] parentSym = symbol[0..i]; Content* parObj = parentSym in allContent; if (parObj) { // existing object parent = cast(IContentList) *parObj; if (parent is null) { // it's not an IContentList! logger.warn ("{} is not an IContentList, but a child, {}, exists!", parentSym, symbol); return; } } else // no existing object parent = new ContentList (parentSym); } parent.append (this); //logger.trace ("Created: {}\t{}", symbol, this); } void name (Translation.Entry e) { name_ = e.name; desc_ = e.desc; } /** Add a callback. Callbacks are called on a change or event, in the order * added. */ Content addCallback (void delegate (Content) cb) { this.cb ~= cb; return this; } /// ditto Content addCallback (void function (Content) cb) { this.cb ~= util.toDg (cb); return this; } /** End of an event, e.g. a button release or end of an edit (calls callbacks). * * Content holding a value should override this, setting its new value in * changed as well as calling callbacks, e.g.: * --- * Content.changed.boolData[symbol] = val; * super(); * --- */ final void endEvent () { foreach (dg; cb) dg (this); } override char[] toString (uint i) { return i == 0 ? "No value" : i == 1 ? name_ : i == 2 ? desc_ : null; } /** A naive implementation which assumes the passed content is * incompatible. */ override bool set (IContent) { return false; } /// ditto override void opAssign (char[]) {} protected: char[] symbol; char[] name_, desc_; // translated name and description void delegate (Content) cb[]; public static: /** Get Content with _symbol name symbol from the list of all content, or * null if no such Content exists. */ Content get (char[] symbol) { auto p = symbol in allContent; if (p) return *p; logger.warn ("Content {} does not exist",symbol); return null; } // Would use tango.container.HashMap, but mde.workaround2371 doesn't work here. Content[char[]] allContent; // all content hashed by symbol name ContentList tree; // tree of all content. static this () { tree = new ContentList (""); } package static: // Kept to set the value of other content as it is created: ValueCache loaded; // loaded values not matching any content created yet // The values in changed are what is written to file when saving: ValueCache changed; // changed values and values from local config file Translation.Entry[char[]] translations; } /** A generic way to handle a list of type IContent. */ class ContentList : Content, IContentList { this (char[] symbol) { super (symbol); } override Content[] list () { return list_; } override void append (Content x) { list_ ~= x; } override bool set (IContent c) { IContentList cl = cast (IContentList) c; if (cl !is null) { list_ = cl.list(); return true; } return false; } protected: final Content[] list_; } /** Created on errors to display and log a message. */ class ErrorContent : Content { this (char[] symbol, char[] msg) { super (symbol); this.msg = msg; logger.error (symbol ~ ": " ~ msg); } override char[] toString (uint i) { return i == 0 ? msg : i == 1 ? name_ : null; } protected: char[] msg; }