view mde/content/ServiceContent.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 source

/* 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 : IContent {
    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.
     *
     * Each WidgetManager has it's own instance, but these share one clipboard, etc.
     * 
     * 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 ServiceContentList createItems (char[] name) {
	char[] lName = "menus.services."~name;
	auto ret = new ServiceContentList (lName);
	
	// Many use callbacks on a generic class type. For this, we should be sure of the type.
	(new AStringService(lName~".copy")).addCallback ((IContent c) {
	    debug assert (cast(AStringService)c);
	    with (cast(AStringService)c) {
		if (activeCont !is null)
		    clipboard = activeCont.toString(0);
	    }
	});
	(new AStringService(lName~".paste")).addCallback ((IContent c) {
	    debug assert (cast(AStringService)c);
	    with (cast(AStringService)c) {
		if (activeCont !is null)
		    activeCont = clipboard;
	    }
	});
	
	new ServiceContentList(lName~".calculator");
	(new IntService(lName~".calculator.increment")).addCallback ((IContent c) {
	    debug assert (cast(IntService)c);
	    with (cast(IntService)c) {
		if (activeCont !is null)
		    activeCont = activeCont()+1;
	    }
	});
	(new IntService(lName~".calculator.decrement")).addCallback ((IContent c) {
	    debug assert (cast(IntService)c);
	    with (cast(IntService)c) {
		if (activeCont !is null)
		    activeCont = activeCont()-1;
	    }
	});
	return ret;
    }
    
private:
    static char[] clipboard;
    //TODO: lock on clipboard: static Mutex mutex;
}