view mde/content/Items.d @ 131:9cff74f68b84

Major revisions to popup handling. Buttons can close menus now, plus some smaller impovements. Removed Widget module. Moved Widget.AWidget to AChildWidget.AChildWidget and Widget.AParentWidget to AParentWidget.AParentWidget. Removed ASingleParentWidget to improve code sharing. AChildWidget doesn't implement IParentWidget like AWidget did. New IPopupParentWidget extending IParentWidget for the WM and some widgets to handle popups. Cut old popup management code. New underMouse() function replacing highlight(); called on all widgets. Separate menu-popup and button widgets aren't needed for menus now. Functions returning content widgets have been moved to their own module. Cleaned up jobs.txt. Switched to 80 line length for Ddoc.
author Diggory Hardy <diggory.hardy@gmail.com>
date Wed, 21 Jan 2009 13:01:40 +0000
parents 41582439a42b
children 264028f4115a
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/>. */

/**************************************************************************************************
 * A generic way to access content items. Also loads translations on-demand.
 *************************************************************************************************/
module mde.content.Items;

import mde.content.miscContent;
import mde.gui.exception;

import imde = mde.imde;
import mde.lookup.Options;
import mde.lookup.Translation;

debug {
    import tango.util.log.Log : Log, Logger;
    private Logger logger;
    static this () {
	logger = Log.getLogger ("mde.gui.content.Items");
    }
}

    /** Get a specific content item.
     *
     * loadTranslation() $(B must) be called before this function.
     *
     * E.g. get ("Options.MiscOptions.L10n") returns miscOpts.L10n,
     * Items.get ("Options.MiscOptions") returns a ContentList of all misc options. */
    Content get (char[] item) {
	assert (currentL10n is miscOpts.L10n(), "must call loadTranslation (code error)");
	char[] orig = item;	// item is modified by head()
        
	char[] h = head (item);
	if (h == "Options") {
	    if (item is null)
		return Options.allContentList;
	    
	    h = head (item);
	    auto p = h in Options.optionsClasses;
	    if (p) {
		if (item == null)
		    return p.contentList;
		
		auto q = (h = head (item)) in p.content;
		if (q && item is null)	// enforce item is an exact match
		    return *q;
	    }
	} else if (h == "imde") {
	    h = head (item);
	    if (h == "menu" && item is null)
		return imde.menu;
	    else if (h == "quit" && item is null)
		return imde.quit;
	} else if (h == "dynamic") {
            auto i = head (item) in items;
            if (i) return *i;
        }
        
	return new ErrorContent ("Error: bad content specifier", orig);
    }
    
    /** Creates some content on first run (required by get()).
     *
     * If the correct translation strings are not loaded, this loads them. */
    void loadTranslation () {
	if (currentL10n is miscOpts.L10n()) return;
	
	// Create Option classes' ContentLists if necessary:
	if (Options.allContentList is null) {
	    Content[] list;
	    list.length = Options.optionsClasses.length;
	    size_t i;
	    foreach (n,opts; Options.optionsClasses) {
		opts.contentList = new ContentList (n, opts.content);
		list[i++] = opts.contentList;
	    }
	    Options.allContentList = new ContentList ("Options", list);
	}
	
        Translation trl;
        Translation.Entry trle;
        
	// Translate Options:
	with (Options.allContentList) {
	    trle = Translation.get (symbol).getStruct (symbol);
	    name (trle.name, trle.desc);
	}
	foreach (n,opts; Options.optionsClasses) {
	    trl = Translation.get (n);
	    trle = trl.getStruct (n);
	    opts.contentList.name (trle.name, trle.desc);
	    foreach (s, v; opts.content) {
		trle = trl.getStruct (s);
		v.name (trle.name, trle.desc);
		IContentList cl = cast(IContentList) v;
		if (cl) {
		    foreach (i,c; cl.list) {
			trle = trl.getStruct (c.symbol);
			c.name (trle.name, trle.desc);
		    }
		}
	    }
	}
	
	// Translate imde:
        trl = Translation.get ("imde");
	trle = trl.getStruct ("menu");
	imde.menu.name (trle.name, trle.desc);
	trle = trl.getStruct ("quit");
	imde.quit.name (trle.name, trle.desc);
        
        // Translate dynamic content:
        if (items.length) {
            trl = Translation.get ("dynamic");
            foreach (n,item; items) {
                trle = trl.getStruct (n);
                item.name (trle.name, trle.desc);
                IContentList cl = cast(IContentList) item;
                if (cl) {
                    foreach (i,c; cl.list) {
                        trle = trl.getStruct (c.symbol);
                        c.name (trle.name, trle.desc);
                    }
                }
            }
        }
	
	currentL10n = miscOpts.L10n();
    }
    
    /** Add content c with name c.symbol, so that translations are loaded for it and it can be
     * returned by get ("dynamic."~c.symbol). */
    Content addContent (Content c) {
        items[c.symbol] = c;
        return c;
    }
    
private:
    // NOTE: possibly add all content to this list. Lookups would be faster.
    Content[char[]] items;	// dynamically added content
    
    /** Takes the string "head.tail" where tail may contain '.' but head does not, returns "head",
     * with str set to "tail". */
    char[] head (ref char[] str) {
	size_t i = 0;
	while (i < str.length && str[i] != '.')
	    ++i;
	char[] ret = str[0..i];
	if (i == str.length)
	    str = null;
	else
	    str = str[i+1..$];
	return ret;
    }
    
    char[] currentL10n;	// Strings will be reloaded if this is not miscOpts.L10n().