view mde/content/ServiceContent.d @ 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 mde/content/Services.d@1125ba603af6
children 7f7b2011b759
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 {
    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;
}