UI-top-level: integrate and wire the new InteractionDirector
This commit is contained in:
parent
27c8e78cf5
commit
8a912926ec
9 changed files with 118 additions and 480 deletions
|
|
@ -68,6 +68,14 @@ namespace controller {
|
||||||
// emit administrative code here...
|
// emit administrative code here...
|
||||||
UiBus::~UiBus() { }
|
UiBus::~UiBus() { }
|
||||||
|
|
||||||
|
|
||||||
|
ctrl::BusTerm&
|
||||||
|
UiBus::getAccessPoint()
|
||||||
|
{
|
||||||
|
return *coreService_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace ctrl {
|
namespace ctrl {
|
||||||
|
|
||||||
CoreService::~CoreService() { }
|
CoreService::~CoreService() { }
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,7 @@ namespace gui {
|
||||||
///////////////////////////////////////////////////////////////////////////////////TICKET #959 : scheduled for termination....
|
///////////////////////////////////////////////////////////////////////////////////TICKET #959 : scheduled for termination....
|
||||||
namespace ctrl {
|
namespace ctrl {
|
||||||
class CoreService;
|
class CoreService;
|
||||||
|
class BusTerm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -159,7 +160,8 @@ namespace gui {
|
||||||
public:
|
public:
|
||||||
UiBus();
|
UiBus();
|
||||||
~UiBus();
|
~UiBus();
|
||||||
|
|
||||||
|
ctrl::BusTerm& getAccessPoint();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
interactionDirector - Global UI Manager
|
interactionDirector - Global UI Manager
|
||||||
|
|
||||||
Copyright (C) Lumiera.org
|
Copyright (C) Lumiera.org
|
||||||
2008, Joel Holdsworth <joel@airwebreathe.org.uk>
|
|
||||||
2017, Hermann Vosseler <Ichthyostega@web.de>
|
2017, Hermann Vosseler <Ichthyostega@web.de>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
This program is free software; you can redistribute it and/or
|
||||||
|
|
@ -27,326 +26,49 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "gui/gtk-lumiera.hpp"
|
#include "gui/gtk-base.hpp"
|
||||||
#include "gui/config-keys.hpp"
|
|
||||||
#include "gui/ui-bus.hpp"
|
|
||||||
#include "gui/workspace/interaction-director.hpp"
|
#include "gui/workspace/interaction-director.hpp"
|
||||||
#include "gui/workspace/actions.hpp"
|
#include "gui/ui-bus.hpp"
|
||||||
#include "gui/workspace/window-list.hpp"
|
#include "gui/ctrl/bus-term.hpp"
|
||||||
#include "gui/workspace/workspace-window.hpp"
|
#include "proc/mobject/session/root.hpp"
|
||||||
#include "lib/searchpath.hpp"
|
#include "lib/diff/tree-mutator.hpp"
|
||||||
#include "lib/util.hpp"
|
//#include "gui/ui-bus.hpp"
|
||||||
|
//#include "lib/util.hpp"
|
||||||
|
|
||||||
#include <gtkmm/stylecontext.h>
|
//#include <memory>
|
||||||
#include <boost/filesystem.hpp>
|
//#include <list>
|
||||||
#include <memory>
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
using Gtk::IconSize;
|
//using util::isnil;
|
||||||
using Gtk::IconFactory;
|
//using std::list;
|
||||||
|
//using std::shared_ptr;
|
||||||
using util::cStr;
|
using lib::diff::TreeMutator;
|
||||||
using util::isnil;
|
|
||||||
using std::list;
|
|
||||||
using std::shared_ptr;
|
|
||||||
|
|
||||||
|
|
||||||
namespace gui {
|
namespace gui {
|
||||||
namespace workspace {
|
namespace workspace {
|
||||||
|
|
||||||
namespace fsys = boost::filesystem;
|
|
||||||
|
|
||||||
IconSize UiManager::GiantIconSize = Gtk::ICON_SIZE_INVALID;
|
// emit VTables here...
|
||||||
IconSize UiManager::MenuIconSize = Gtk::ICON_SIZE_INVALID;
|
|
||||||
|
|
||||||
|
|
||||||
// dtors via smart-ptr invoked from here...
|
|
||||||
InteractionDirector::~InteractionDirector()
|
InteractionDirector::~InteractionDirector()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
InteractionDirector::InteractionDirector (UiBus& bus)
|
InteractionDirector::InteractionDirector (UiBus& bus)
|
||||||
: Gtk::UIManager()
|
: model::Controller(proc::mobject::session::Root::getID(), bus.getAccessPoint())
|
||||||
, uiBus_(bus)
|
{ }
|
||||||
, windowList_{new WindowList{*this}}
|
|
||||||
, actions_{new Actions{[this]() ->WorkspaceWindow& { return windowList_->findActiveWindow();}}}
|
|
||||||
, iconSearchPath_{Config::get (KEY_ICON_PATH)}
|
|
||||||
, resourceSerachPath_{Config::get (KEY_UIRES_PATH)}
|
|
||||||
{
|
|
||||||
initGlobalUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise the interface manager on application start.
|
|
||||||
* Register the icon configuration and sizes and lookup
|
|
||||||
* all the icons -- either from the default theme of via
|
|
||||||
* the given Lumiera icon search paths (see \c setup.ini ).
|
|
||||||
* @see lumiera::Config
|
|
||||||
*/
|
|
||||||
void
|
void
|
||||||
UiManager::initGlobalUI ()
|
InteractionDirector::buildMutator (TreeMutator::Handle buffer)
|
||||||
{
|
{
|
||||||
Glib::set_application_name (Config::get (KEY_TITLE));
|
// using Attrib = std::pair<const string,string>;
|
||||||
|
// using lib::diff::collection;
|
||||||
|
|
||||||
registerAppIconSizes();
|
buffer.create (
|
||||||
registerStockItems();
|
TreeMutator::build()
|
||||||
|
);
|
||||||
setTheme (Config::get (KEY_STYLESHEET));
|
UNIMPLEMENTED ("create a sensible binding between root-controller and root-model element");
|
||||||
|
|
||||||
actions_->populateMainActions (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @remarks this function is invoked once from the main application object,
|
|
||||||
* immediately prior to starting the GTK event loop. */
|
|
||||||
void
|
|
||||||
UiManager::createApplicationWindow()
|
|
||||||
{
|
|
||||||
if (windowList_->empty())
|
|
||||||
windowList_->newWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
UiManager::updateWindowFocusRelatedActions()
|
|
||||||
{
|
|
||||||
UNIMPLEMENTED ("how to handle activation of menu entries depending on window focus"); ////////TICKET #1076 find out how to handle this properly
|
|
||||||
//////see Actions::updateActionState()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
UiManager::setTheme (string const& stylesheetName)
|
|
||||||
{
|
|
||||||
auto screen = Gdk::Screen::get_default();
|
|
||||||
auto css_provider = Gtk::CssProvider::create();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
css_provider->load_from_path (lib::resolveModulePath (stylesheetName, resourceSerachPath_));
|
|
||||||
/////////////////////////////////TICKET #953 should detect and notify CSS parsing errors. CssProvider offers a signal for this purpose
|
|
||||||
/////////////////////////////////TICKET #953 ...seems to be supported properly starting with gtkmm 3.18 (Debian/Jessie has 3.14)
|
|
||||||
}
|
|
||||||
catch(Glib::Error const& failure)
|
|
||||||
{
|
|
||||||
WARN(gui, "Failure while loading stylesheet '%s': %s", cStr(stylesheetName), cStr(failure.what()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Gtk::StyleContext::add_provider_for_screen (screen, css_provider,
|
|
||||||
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Cairo::RefPtr<Cairo::SolidPattern>
|
|
||||||
UiManager::readStyleColourProperty (Gtk::Widget& widget
|
|
||||||
,const gchar * property_name
|
|
||||||
,guint16 red, guint16 green, guint16 blue)
|
|
||||||
{
|
|
||||||
REQUIRE (property_name);
|
|
||||||
|
|
||||||
// TODO: Can we get rid of the GdkColor completely here?
|
|
||||||
GdkColor *color;
|
|
||||||
gtk_widget_style_get(widget.gobj(), property_name, &color, NULL);
|
|
||||||
|
|
||||||
Cairo::RefPtr<Cairo::SolidPattern> pattern;
|
|
||||||
// Did the color load successfully?
|
|
||||||
if (color != NULL)
|
|
||||||
{
|
|
||||||
pattern = Cairo::SolidPattern::create_rgb ( (double)color->red / 0xFFFF,
|
|
||||||
(double)color->green / 0xFFFF,
|
|
||||||
(double)color->blue / 0xFFFF);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WARN(gui, "%s style value failed to load", property_name);
|
|
||||||
|
|
||||||
pattern = Cairo::SolidPattern::create_rgb ( red, green, blue );
|
|
||||||
}
|
|
||||||
|
|
||||||
return pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
UiManager::registerAppIconSizes()
|
|
||||||
{
|
|
||||||
if(GiantIconSize == Gtk::ICON_SIZE_INVALID)
|
|
||||||
GiantIconSize = IconSize::register_new ("giant", 48, 48);
|
|
||||||
if(MenuIconSize == Gtk::ICON_SIZE_INVALID)
|
|
||||||
MenuIconSize = IconSize::register_new ("menu", 16, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers application stock items:
|
|
||||||
* icons and labels associated with IDs
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
UiManager::registerStockItems()
|
|
||||||
{
|
|
||||||
Glib::RefPtr<IconFactory> factory = Gtk::IconFactory::create();
|
|
||||||
|
|
||||||
addStockIconSet(factory, "panel-assets", "panel_assets", _("_Assets"));
|
|
||||||
addStockIconSet(factory, "panel-viewer", "panel_viewer", _("_Viewer"));
|
|
||||||
addStockIconSet(factory, "panel-timeline", "panel_timeline",_("_Timeline"));
|
|
||||||
addStockIconSet(factory, "panel-timeline", "panel_timeline_obsolete",_("_ZombieTimeline"));
|
|
||||||
|
|
||||||
addStockIconSet(factory, "window-new", "new_window", _("New _Window"));
|
|
||||||
|
|
||||||
addStockIconSet(factory, "tool-arrow", "tool_arrow", _("_Arrow"));
|
|
||||||
addStockIconSet(factory, "tool-i-beam", "tool_i_beam", _("_I-Beam"));
|
|
||||||
|
|
||||||
addStockIconSet(factory, "track-disabled", "track_disabled",_("Track Disabled"));
|
|
||||||
addStockIconSet(factory, "track-enabled", "track_enabled", _("Track Enabled"));
|
|
||||||
addStockIconSet(factory, "track-locked", "track_locked", _("Track Locked"));
|
|
||||||
addStockIconSet(factory, "track-unlocked", "track_unlocked",_("Track Unlocked"));
|
|
||||||
|
|
||||||
factory->add_default(); //Add factory to list of factories.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
UiManager::addStockIconSet (Glib::RefPtr<IconFactory> const& factory
|
|
||||||
,cuString& icon_name
|
|
||||||
,cuString& id
|
|
||||||
,cuString& label)
|
|
||||||
{
|
|
||||||
Glib::RefPtr<Gtk::IconSet> icon_set = Gtk::IconSet::create();
|
|
||||||
|
|
||||||
// Load all the sizes, wildcarding the first, largest icon to be loaded
|
|
||||||
bool no_icons = true;
|
|
||||||
no_icons &= !addStockIcon(
|
|
||||||
icon_set, icon_name, GiantIconSize, no_icons);
|
|
||||||
no_icons &= !addStockIcon(
|
|
||||||
icon_set, icon_name, Gtk::ICON_SIZE_BUTTON, no_icons);
|
|
||||||
no_icons &= !addStockIcon(
|
|
||||||
icon_set, icon_name, Gtk::ICON_SIZE_MENU, no_icons);
|
|
||||||
no_icons &= !addStockIcon(
|
|
||||||
icon_set, icon_name, Gtk::ICON_SIZE_LARGE_TOOLBAR, no_icons);
|
|
||||||
no_icons &= !addStockIcon(
|
|
||||||
icon_set, icon_name, MenuIconSize, no_icons);
|
|
||||||
|
|
||||||
if(no_icons)
|
|
||||||
{
|
|
||||||
// No icons were loaded
|
|
||||||
ERROR (gui, "Unable to load icon '%s'", cStr(icon_name));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the icon set to the icon factory
|
|
||||||
const Gtk::StockID stock_id(id);
|
|
||||||
factory->add(stock_id, icon_set);
|
|
||||||
Gtk::Stock::add(Gtk::StockItem(stock_id, label)); //////////////////////TICKET #1030 : use "icon names" instead of Gtk::StockItem
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
UiManager::addStockIcon (Glib::RefPtr<Gtk::IconSet> const& icon_set
|
|
||||||
,cuString& icon_name
|
|
||||||
,Gtk::IconSize size
|
|
||||||
,bool wildcard)
|
|
||||||
{
|
|
||||||
// Try the icon theme
|
|
||||||
if (addThemeIconSource(icon_set, icon_name, size, wildcard))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Try to resolve the icon via the configured search path
|
|
||||||
lib::SearchPathSplitter iconLocations (iconSearchPath_);
|
|
||||||
while (iconLocations)
|
|
||||||
if (addNonThemeIconSource (icon_set
|
|
||||||
,iconLocations.next()
|
|
||||||
,icon_name
|
|
||||||
,size
|
|
||||||
,wildcard))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false; // icon not found
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
UiManager::addThemeIconSource (Glib::RefPtr<Gtk::IconSet> const& icon_set
|
|
||||||
,cuString& icon_name
|
|
||||||
,Gtk::IconSize size
|
|
||||||
,bool wildcard)
|
|
||||||
{
|
|
||||||
// Get the size
|
|
||||||
int width = 0, height = 0;
|
|
||||||
if(!IconSize::lookup(size, width, height))
|
|
||||||
return false;
|
|
||||||
REQUIRE(width > 0);
|
|
||||||
|
|
||||||
// Try to load the icon
|
|
||||||
Glib::RefPtr<Gtk::IconTheme> theme = Gtk::IconTheme::get_default();
|
|
||||||
REQUIRE(theme);
|
|
||||||
|
|
||||||
///////////////////////////////////////////TODO find out how IconInfo could be made const. For example, GTKmm 2.10.10 is missing the const on operator bool() in iconinfo.h
|
|
||||||
Gtk::IconInfo info = theme->lookup_icon(icon_name, width, (Gtk::IconLookupFlags)0);
|
|
||||||
|
|
||||||
if (!info) return false; // unable to resolve Icon
|
|
||||||
|
|
||||||
cuString path(info.get_filename());
|
|
||||||
return addStockIconFromPath(path, icon_set, size, wildcard);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
UiManager::addNonThemeIconSource (Glib::RefPtr<Gtk::IconSet> const& icon_set
|
|
||||||
,cuString& base_dir
|
|
||||||
,cuString& icon_name
|
|
||||||
,Gtk::IconSize size
|
|
||||||
,bool wildcard)
|
|
||||||
{
|
|
||||||
// Get the size
|
|
||||||
int width = 0, height = 0;
|
|
||||||
if(!IconSize::lookup(size, width, height))
|
|
||||||
return false;
|
|
||||||
REQUIRE(width > 0);
|
|
||||||
|
|
||||||
// Try to load the icon
|
|
||||||
cuString path(Glib::ustring::compose("%1/%2x%3/%4.png",
|
|
||||||
base_dir, width, height, icon_name));
|
|
||||||
return addStockIconFromPath(path, icon_set, size, wildcard);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
UiManager::addStockIconFromPath (string path
|
|
||||||
,Glib::RefPtr<Gtk::IconSet> const& icon_set
|
|
||||||
,Gtk::IconSize size
|
|
||||||
,bool wildcard)
|
|
||||||
{
|
|
||||||
if (!fsys::exists (path)) return false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Gtk::IconSource source;
|
|
||||||
source.set_pixbuf(Gdk::Pixbuf::create_from_file(path));
|
|
||||||
source.set_size_wildcarded(wildcard);
|
|
||||||
source.set_size(size);
|
|
||||||
|
|
||||||
icon_set->add_source(source);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
catch(Glib::Exception const& ex)
|
|
||||||
{
|
|
||||||
WARN (gui, "Failure when accessing icon '%s'. Problem: %s", cStr(path), cStr(ex.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
UiManager::allowCloseWindow (bool yes)
|
|
||||||
{
|
|
||||||
this->get_action("/MenuBar/WindowMenu/WindowCloseWindow")
|
|
||||||
->set_sensitive (yes);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}}// namespace gui::workspace
|
}}// namespace gui::workspace
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
INTERACTION-DIRECTOR.hpp - Global UI Manager
|
INTERACTION-DIRECTOR.hpp - Global UI Manager
|
||||||
|
|
||||||
Copyright (C) Lumiera.org
|
Copyright (C) Lumiera.org
|
||||||
2008, Joel Holdsworth <joel@airwebreathe.org.uk>
|
|
||||||
2017, Hermann Vosseler <Ichthyostega@web.de>
|
2017, Hermann Vosseler <Ichthyostega@web.de>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
This program is free software; you can redistribute it and/or
|
||||||
|
|
@ -24,15 +23,27 @@
|
||||||
|
|
||||||
/** @file interaction-director.hpp
|
/** @file interaction-director.hpp
|
||||||
** The top-level controller to connect model and user interaction state.
|
** The top-level controller to connect model and user interaction state.
|
||||||
** The central UiManager instance is owned by the GtkLumiera object and initialised in GTK-main.
|
** Within the Lumiera UI, relevant entities from the session model are mapped onto and represented
|
||||||
** It establishes and wires the top-level entities of the UI-Layer and thus, indirectly offers
|
** by corresponding [UI-Elements](\ref model::Tangible). Consequently, there is a hierarchy of
|
||||||
** services to provide Icons and other resources, to open and manage workspace windows, to
|
** interrelated UI elements mirroring the hierarchy within the session model. And, while in the
|
||||||
** form and issue (global) actions and to delve into the UI representation of top-level parts
|
** latter, there is a _conceptual root node_ to correspond to the session itself, within the UI
|
||||||
** of the session model. Notable connections established herein:
|
** there is a top-level controller to mirror and represent that root element: The InteractionDirector.
|
||||||
** - connection to the [UI-Bus](\ref ui-bus.hpp)
|
**
|
||||||
** - the global Actions available though the menu
|
** For one, the InteractionDirector represents and exposes parts of the model as seen from top level.
|
||||||
** - the WindowList
|
** Especially this means that, through the InteractionDirector, it is possible to open and enter the
|
||||||
** - the InteractionDirector (top-level controller)
|
** UI to work with the timeline(s), with the assets and with the global session configuration.
|
||||||
|
** Moreover, this top-level controller allows to issue likewise global actions regarding those
|
||||||
|
** entities:
|
||||||
|
** - create / modify / delete timeline(s)
|
||||||
|
** - create / modify / sequences
|
||||||
|
** - save, close, open and create a session
|
||||||
|
**
|
||||||
|
** And, secondly, beyond those top-level model-related activities, the InteractionDirector serves
|
||||||
|
** as link between model entities, actions to be performed onto them and the transient yet global
|
||||||
|
** user interaction state. The latter means anything related to _the current window_,
|
||||||
|
** _the current focus_, _the current work-site_, the current interface controller technology used etc.
|
||||||
|
** Obviously, the InteractionDirector can not _handle_ all those heavyweight concerns; but it connects
|
||||||
|
** the involved parts and (re)directs the information flow towards the proper recipient to handle it.
|
||||||
**
|
**
|
||||||
** @see gtk-lumiera.hpp
|
** @see gtk-lumiera.hpp
|
||||||
** @see ui-bus.hpp
|
** @see ui-bus.hpp
|
||||||
|
|
@ -42,190 +53,48 @@
|
||||||
#ifndef GUI_WORKSPACE_INTERACTION_DIRECTOR_H
|
#ifndef GUI_WORKSPACE_INTERACTION_DIRECTOR_H
|
||||||
#define GUI_WORKSPACE_INTERACTION_DIRECTOR_H
|
#define GUI_WORKSPACE_INTERACTION_DIRECTOR_H
|
||||||
|
|
||||||
#include "gui/gtk-base.hpp"
|
//#include "gui/gtk-base.hpp"
|
||||||
|
#include "gui/model/controller.hpp"
|
||||||
|
|
||||||
#include <boost/noncopyable.hpp>
|
//#include <boost/noncopyable.hpp>
|
||||||
#include <cairomm/cairomm.h>
|
//#include <cairomm/cairomm.h>
|
||||||
#include <string>
|
//#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
namespace gui {
|
namespace gui {
|
||||||
|
|
||||||
namespace model { class Project; } ////////////////////////////////////////////////////TICKET #1048 : rectify UI lifecycle
|
|
||||||
namespace controller { class Controller; } ////////////////////////////////////////////////////TICKET #1048 : rectify UI lifecycle
|
|
||||||
|
|
||||||
class UiBus;
|
class UiBus;
|
||||||
|
|
||||||
namespace workspace {
|
namespace workspace {
|
||||||
|
|
||||||
using std::unique_ptr;
|
//using std::string;
|
||||||
using std::string;
|
|
||||||
|
|
||||||
class Actions;
|
//class Actions;
|
||||||
class WindowList;
|
//class WindowList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manage global concerns regarding a coherent user interface.
|
* Top-level controller to establish a link between the model
|
||||||
* Offers access to some global UI resources, and establishes
|
* and transient user interaction state (focus, current window)
|
||||||
* further global services to create workspace windows, to bind
|
|
||||||
* menu / command actions and to enter the top-level model parts.
|
|
||||||
*/
|
*/
|
||||||
class InteractionDirector
|
class InteractionDirector
|
||||||
: public Gtk::UIManager
|
: public model::Controller
|
||||||
, boost::noncopyable
|
|
||||||
{
|
{
|
||||||
UiBus& uiBus_;
|
|
||||||
|
|
||||||
unique_ptr<WindowList> windowList_;
|
////TODO: what is the model equivalent represented here???
|
||||||
unique_ptr<Actions> actions_;
|
|
||||||
|
|
||||||
string iconSearchPath_;
|
/** set up a binding to allow some top-level UI state
|
||||||
string resourceSerachPath_;
|
* to be treated as part of the session model
|
||||||
|
* @see tree-mutator.hpp
|
||||||
|
*/
|
||||||
|
void buildMutator (lib::diff::TreeMutator::Handle) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** The registered icon size for giant 48x48 px icons.
|
|
||||||
* @remarks This value is set to BuiltinIconSize::ICON_SIZE_INVALID
|
|
||||||
* until register_giant_icon_size is called.
|
|
||||||
*/
|
|
||||||
static Gtk::IconSize GiantIconSize;
|
|
||||||
|
|
||||||
/** The registered icon size for giant 16x16 px icons.
|
|
||||||
* @remarks This value is set to BuiltinIconSize::ICON_SIZE_INVALID
|
|
||||||
* until register_app_icon_sizes is called.
|
|
||||||
*/
|
|
||||||
static Gtk::IconSize MenuIconSize;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* There is one global UiManager instance,
|
|
||||||
* which is created by [the Application](\ref GtkLumiera)
|
|
||||||
* and allows access to the UI-Bus backbone. The UiManager itself
|
|
||||||
* is _not a ctrl::Controller,_ and thus not directly connected to the Bus.
|
|
||||||
* Rather, supports the top-level windows for creating a consistent interface.
|
|
||||||
*/
|
|
||||||
InteractionDirector (UiBus& bus);
|
InteractionDirector (UiBus& bus);
|
||||||
~InteractionDirector ();
|
~InteractionDirector ();
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the first top-level application window.
|
|
||||||
* This triggers the build-up of the user interface widgets.
|
|
||||||
*/
|
|
||||||
void createApplicationWindow();
|
|
||||||
|
|
||||||
/** @todo find a solution how to enable/disable menu entries according to focus
|
|
||||||
* /////////////////////////////////////////////////TICKET #1076 find out how to handle this properly
|
|
||||||
*/
|
|
||||||
void updateWindowFocusRelatedActions();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the theme to use for the Lumiera GUI.
|
|
||||||
* @param stylesheetName GTK CSS stylesheet to load from the resourceSearchPath_
|
|
||||||
* @throw error::Config if this stylesheet can't be resolved on the searchpath
|
|
||||||
* @see #init
|
|
||||||
* @see lumiera::Config
|
|
||||||
*/
|
|
||||||
void setTheme (string const& stylesheetName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A utility function which reads a colour style from the GTK Style.
|
|
||||||
* @param widget The widget to load the style out of.
|
|
||||||
* @param property_name The name of the style property to load.
|
|
||||||
* @param red The fallback red intensity.
|
|
||||||
* @param green The fallback green intensity.
|
|
||||||
* @param blue The fallback blue intensity.
|
|
||||||
* @return The loaded colour.
|
|
||||||
*/
|
|
||||||
static Cairo::RefPtr<Cairo::SolidPattern>
|
|
||||||
readStyleColourProperty (Gtk::Widget &widget, const gchar *property_name,
|
|
||||||
guint16 red, guint16 green, guint16 blue);
|
|
||||||
|
|
||||||
void allowCloseWindow (bool yes);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void initGlobalUI ();
|
|
||||||
|
|
||||||
void registerAppIconSizes();
|
|
||||||
void registerStockItems();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an icon (in different sizes) to the icon factory.
|
|
||||||
* @param factory The factory to add the icon to.
|
|
||||||
* @param icon_name The file name of the icon to add.
|
|
||||||
* @param id The id name of the icon.
|
|
||||||
* @param label The user readable icon name for this icon.
|
|
||||||
* @return \c true if the icon was successfully loaded,
|
|
||||||
* returns \c false otherwise.
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
addStockIconSet (Glib::RefPtr<Gtk::IconFactory> const& factory
|
|
||||||
,cuString& icon_name
|
|
||||||
,cuString& id
|
|
||||||
,cuString& label);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads an icon, searching standard icon locations,
|
|
||||||
* and adds it to an icon set.
|
|
||||||
* @param icon_set The icon set to add the icon to.
|
|
||||||
* @param icon_name The file name of the icon to load.
|
|
||||||
* @param size The size of the icon to load.
|
|
||||||
* @param wildcard \c true if this icon is to be wildcarded.
|
|
||||||
* @return \c true if the icon was loaded successfully.
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
addStockIcon (Glib::RefPtr<Gtk::IconSet> const& icon_set
|
|
||||||
,cuString& icon_name
|
|
||||||
,Gtk::IconSize size
|
|
||||||
,bool wildcard);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads an icon from a the icon theme
|
|
||||||
* @param icon_set The icon set to add the icon to.
|
|
||||||
* @param icon_name The name of the icon to load.
|
|
||||||
* @param size The size of the icon to load.
|
|
||||||
* @param wildcard \c true if this icon is to be wildcarded.
|
|
||||||
* @return \c true if the icon was loaded successfully.
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
addThemeIconSource (Glib::RefPtr<Gtk::IconSet> const& icon_set
|
|
||||||
,cuString& icon_name
|
|
||||||
,Gtk::IconSize size
|
|
||||||
,bool wildcard);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads an icon from a non theme set.
|
|
||||||
* @param icon_set The icon set to add the icon to.
|
|
||||||
* @param base_dir The root icons directory to load from.
|
|
||||||
* @param icon_name The file name of the icon to load.
|
|
||||||
* @param size The size of the icon to load.
|
|
||||||
* @param wildcard \c true if this icon is to be wildcarded.
|
|
||||||
* @return \c true if the icon was loaded successfully.
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
addNonThemeIconSource (Glib::RefPtr<Gtk::IconSet> const& icon_set
|
|
||||||
,cuString& base_dir
|
|
||||||
,cuString& icon_name
|
|
||||||
,Gtk::IconSize size
|
|
||||||
,bool wildcard);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads an icon from a specific path and adds it to an icon set.
|
|
||||||
* @param path The path to load from.
|
|
||||||
* @param icon_set The icon set to add the icon to.
|
|
||||||
* @param size The size of the icon to load.
|
|
||||||
* @param wildcard \c true if this icon is to be wildcarded.
|
|
||||||
* @return \c true if the icon was loaded successfully.
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
addStockIconFromPath (string path
|
|
||||||
,Glib::RefPtr<Gtk::IconSet> const& icon_set
|
|
||||||
,Gtk::IconSize size
|
|
||||||
,bool wildcard);
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
#include "gui/workspace/actions.hpp"
|
#include "gui/workspace/actions.hpp"
|
||||||
#include "gui/workspace/window-list.hpp"
|
#include "gui/workspace/window-list.hpp"
|
||||||
#include "gui/workspace/workspace-window.hpp"
|
#include "gui/workspace/workspace-window.hpp"
|
||||||
|
#include "gui/workspace/interaction-director.hpp"
|
||||||
#include "lib/searchpath.hpp"
|
#include "lib/searchpath.hpp"
|
||||||
#include "lib/util.hpp"
|
#include "lib/util.hpp"
|
||||||
|
|
||||||
|
|
@ -71,7 +72,8 @@ namespace workspace {
|
||||||
|
|
||||||
UiManager::UiManager (UiBus& bus)
|
UiManager::UiManager (UiBus& bus)
|
||||||
: Gtk::UIManager()
|
: Gtk::UIManager()
|
||||||
, uiBus_(bus)
|
, uiBus_{bus}
|
||||||
|
, director_{new InteractionDirector{bus}}
|
||||||
, windowList_{new WindowList{*this}}
|
, windowList_{new WindowList{*this}}
|
||||||
, actions_{new Actions{[this]() ->WorkspaceWindow& { return windowList_->findActiveWindow();}}}
|
, actions_{new Actions{[this]() ->WorkspaceWindow& { return windowList_->findActiveWindow();}}}
|
||||||
, iconSearchPath_{Config::get (KEY_ICON_PATH)}
|
, iconSearchPath_{Config::get (KEY_ICON_PATH)}
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ namespace workspace {
|
||||||
|
|
||||||
class Actions;
|
class Actions;
|
||||||
class WindowList;
|
class WindowList;
|
||||||
|
class InteractionDirector;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -79,8 +80,9 @@ namespace workspace {
|
||||||
{
|
{
|
||||||
UiBus& uiBus_;
|
UiBus& uiBus_;
|
||||||
|
|
||||||
unique_ptr<WindowList> windowList_;
|
unique_ptr<InteractionDirector> director_;
|
||||||
unique_ptr<Actions> actions_;
|
unique_ptr<WindowList> windowList_;
|
||||||
|
unique_ptr<Actions> actions_;
|
||||||
|
|
||||||
string iconSearchPath_;
|
string iconSearchPath_;
|
||||||
string resourceSerachPath_;
|
string resourceSerachPath_;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include "common/query/defs-manager.hpp"
|
#include "common/query/defs-manager.hpp"
|
||||||
|
|
||||||
using lumiera::query::DefsManager;
|
using lumiera::query::DefsManager;
|
||||||
|
using lib::idi::EntryID;
|
||||||
|
|
||||||
namespace proc {
|
namespace proc {
|
||||||
namespace mobject {
|
namespace mobject {
|
||||||
|
|
@ -38,6 +39,20 @@ namespace session {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** get an unique ID to identify "the model root".
|
||||||
|
* Actually this ID is statically fixed and will be used by the UI
|
||||||
|
* to connect to and talk to the session model at top-level
|
||||||
|
* @return an embedded LUID tagged with the type of the session::Root.
|
||||||
|
* This ID is suitable to be used in model diff and as ID on
|
||||||
|
* the UI-Bus to address the corresponding representations
|
||||||
|
* in Proc-Layer and UI-Layer
|
||||||
|
*/
|
||||||
|
lib::idi::EntryID<Root>
|
||||||
|
Root::getID()
|
||||||
|
{
|
||||||
|
return EntryID<Root>("session");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** @todo validity self-check of the model root
|
/** @todo validity self-check of the model root
|
||||||
* should do substantial checks; the idea is
|
* should do substantial checks; the idea is
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include "proc/mobject/session/meta.hpp"
|
#include "proc/mobject/session/meta.hpp"
|
||||||
#include "proc/mobject/builder/buildertool.hpp"
|
#include "proc/mobject/builder/buildertool.hpp"
|
||||||
|
#include "lib/idi/entry-id.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace lumiera {
|
namespace lumiera {
|
||||||
|
|
@ -70,6 +71,8 @@ namespace session {
|
||||||
public:
|
public:
|
||||||
Root (lumiera::query::DefsManager&);
|
Root (lumiera::query::DefsManager&);
|
||||||
|
|
||||||
|
static lib::idi::EntryID<Root> getID();
|
||||||
|
|
||||||
DEFINE_PROCESSABLE_BY (builder::BuilderTool);
|
DEFINE_PROCESSABLE_BY (builder::BuilderTool);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1670,7 +1670,8 @@
|
||||||
<node CREATED="1485562029644" ID="ID_1022779645" MODIFIED="1485562063560" TEXT="wieder das Problem mit dem BInden der Actions">
|
<node CREATED="1485562029644" ID="ID_1022779645" MODIFIED="1485562063560" TEXT="wieder das Problem mit dem BInden der Actions">
|
||||||
<arrowlink DESTINATION="ID_530209145" ENDARROW="Default" ENDINCLINATION="-17;-195;" ID="Arrow_ID_626063593" STARTARROW="None" STARTINCLINATION="9;270;"/>
|
<arrowlink DESTINATION="ID_530209145" ENDARROW="Default" ENDINCLINATION="-17;-195;" ID="Arrow_ID_626063593" STARTARROW="None" STARTINCLINATION="9;270;"/>
|
||||||
<icon BUILTIN="messagebox_warning"/>
|
<icon BUILTIN="messagebox_warning"/>
|
||||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1485917478469" ID="ID_1209137422" MODIFIED="1485917483206" TEXT="WIP">
|
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1485917478469" ID="ID_1209137422" MODIFIED="1486768047985" TEXT="WIP">
|
||||||
|
<arrowlink COLOR="#e22029" DESTINATION="ID_596101447" ENDARROW="Default" ENDINCLINATION="42;-201;" ID="Arrow_ID_45514601" STARTARROW="Default" STARTINCLINATION="8;84;"/>
|
||||||
<icon BUILTIN="flag-pink"/>
|
<icon BUILTIN="flag-pink"/>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
|
|
@ -1847,8 +1848,12 @@
|
||||||
<node CREATED="1485904072812" ID="ID_829657223" MODIFIED="1485904083263" TEXT="property_is_active">
|
<node CREATED="1485904072812" ID="ID_829657223" MODIFIED="1485904083263" TEXT="property_is_active">
|
||||||
<icon BUILTIN="help"/>
|
<icon BUILTIN="help"/>
|
||||||
</node>
|
</node>
|
||||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1485917438428" HGAP="23" ID="ID_596101447" MODIFIED="1485917450180" TEXT="Lösung ausarbeiten" VSHIFT="26">
|
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1485917438428" HGAP="23" ID="ID_596101447" MODIFIED="1486768047985" TEXT="Lösung ausarbeiten" VSHIFT="26">
|
||||||
|
<linktarget COLOR="#e22029" DESTINATION="ID_596101447" ENDARROW="Default" ENDINCLINATION="42;-201;" ID="Arrow_ID_45514601" SOURCE="ID_1209137422" STARTARROW="Default" STARTINCLINATION="8;84;"/>
|
||||||
<icon BUILTIN="flag-pink"/>
|
<icon BUILTIN="flag-pink"/>
|
||||||
|
<node CREATED="1486767955575" ID="ID_217312514" MODIFIED="1486767963725" TEXT="InteractionDirector verwenden">
|
||||||
|
<icon BUILTIN="idea"/>
|
||||||
|
</node>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
|
|
@ -1944,6 +1949,8 @@
|
||||||
</node>
|
</node>
|
||||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1486067362505" HGAP="26" ID="ID_264522454" MODIFIED="1486067383244" TEXT="globaler Ui-Kontext (Verdrahtung)" VSHIFT="24">
|
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1486067362505" HGAP="26" ID="ID_264522454" MODIFIED="1486067383244" TEXT="globaler Ui-Kontext (Verdrahtung)" VSHIFT="24">
|
||||||
<icon BUILTIN="flag-yellow"/>
|
<icon BUILTIN="flag-yellow"/>
|
||||||
|
<node CREATED="1486767972445" ID="ID_1855585608" MODIFIED="1486767979672" TEXT="kann UiManager verwenden"/>
|
||||||
|
<node CREATED="1486767980548" ID="ID_921703593" MODIFIED="1486767985503" TEXT="kann InteractionDirector verwenden"/>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1485898796393" ID="ID_1217726538" MODIFIED="1485898814419" TEXT="#1069 how to refer to the current window">
|
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1485898796393" ID="ID_1217726538" MODIFIED="1485898814419" TEXT="#1069 how to refer to the current window">
|
||||||
|
|
@ -1969,7 +1976,7 @@
|
||||||
<node CREATED="1485454263876" ID="ID_543704434" MODIFIED="1485454270615" TEXT="globale Keybindings"/>
|
<node CREATED="1485454263876" ID="ID_543704434" MODIFIED="1485454270615" TEXT="globale Keybindings"/>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1486763185746" HGAP="33" ID="ID_362749694" MODIFIED="1486763255758" TEXT="workspace::InteractionDirector" VSHIFT="21">
|
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1486763185746" HGAP="33" ID="ID_362749694" MODIFIED="1486768064438" TEXT="workspace::InteractionDirector" VSHIFT="21">
|
||||||
<linktarget COLOR="#683c5b" DESTINATION="ID_362749694" ENDARROW="Default" ENDINCLINATION="-394;0;" ID="Arrow_ID_1979576517" SOURCE="ID_113005643" STARTARROW="None" STARTINCLINATION="-24;-159;"/>
|
<linktarget COLOR="#683c5b" DESTINATION="ID_362749694" ENDARROW="Default" ENDINCLINATION="-394;0;" ID="Arrow_ID_1979576517" SOURCE="ID_113005643" STARTARROW="None" STARTINCLINATION="-24;-159;"/>
|
||||||
<icon BUILTIN="pencil"/>
|
<icon BUILTIN="pencil"/>
|
||||||
<node CREATED="1486763268223" ID="ID_199328732" MODIFIED="1486763277392" TEXT="nicht der Meister">
|
<node CREATED="1486763268223" ID="ID_199328732" MODIFIED="1486763277392" TEXT="nicht der Meister">
|
||||||
|
|
@ -1988,6 +1995,11 @@
|
||||||
<node CREATED="1486763391862" ID="ID_1568245541" MODIFIED="1486763397977" TEXT="Zugang zur Konfiguration"/>
|
<node CREATED="1486763391862" ID="ID_1568245541" MODIFIED="1486763397977" TEXT="Zugang zur Konfiguration"/>
|
||||||
<node CREATED="1486763408780" ID="ID_520762274" MODIFIED="1486763417950" TEXT="Zugang zum persistenten Interface-State"/>
|
<node CREATED="1486763408780" ID="ID_520762274" MODIFIED="1486763417950" TEXT="Zugang zum persistenten Interface-State"/>
|
||||||
</node>
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1486768073223" HGAP="38" ID="ID_1457876217" MODIFIED="1486768136745" TEXT="konkret" VSHIFT="16">
|
||||||
|
<icon BUILTIN="flag-pink"/>
|
||||||
|
<node CREATED="1486768080502" ID="ID_1759740464" MODIFIED="1486768086425" TEXT="Binden für globale Aktionen"/>
|
||||||
|
<node CREATED="1486768086869" ID="ID_173538981" MODIFIED="1486768096616" TEXT="Idee/Konzept für kontextabhängige Aktionen"/>
|
||||||
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1485126466520" FOLDED="true" ID="ID_717310004" MODIFIED="1486763253254" TEXT="WindowManager" VSHIFT="34">
|
<node CREATED="1485126466520" FOLDED="true" ID="ID_717310004" MODIFIED="1486763253254" TEXT="WindowManager" VSHIFT="34">
|
||||||
<icon BUILTIN="button_cancel"/>
|
<icon BUILTIN="button_cancel"/>
|
||||||
|
|
@ -2059,12 +2071,12 @@
|
||||||
<icon BUILTIN="yes"/>
|
<icon BUILTIN="yes"/>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1486520281897" ID="ID_827558797" MODIFIED="1486751054587" TEXT="Problem: zwei Inseln">
|
<node COLOR="#338800" CREATED="1486520281897" ID="ID_827558797" MODIFIED="1486768117891" TEXT="Problem: zwei Inseln">
|
||||||
<arrowlink COLOR="#464b68" DESTINATION="ID_1847844548" ENDARROW="Default" ENDINCLINATION="35;-168;" ID="Arrow_ID_1483178089" STARTARROW="Default" STARTINCLINATION="-2;95;"/>
|
<arrowlink COLOR="#464b68" DESTINATION="ID_1847844548" ENDARROW="Default" ENDINCLINATION="35;-168;" ID="Arrow_ID_1483178089" STARTARROW="Default" STARTINCLINATION="-2;95;"/>
|
||||||
<icon BUILTIN="flag-yellow"/>
|
<icon BUILTIN="button_ok"/>
|
||||||
<node CREATED="1486520289382" ID="ID_1944158920" MODIFIED="1486520302679" TEXT="CoreService + UI-Bus"/>
|
<node CREATED="1486520289382" ID="ID_1944158920" MODIFIED="1486520302679" TEXT="CoreService + UI-Bus"/>
|
||||||
<node CREATED="1486520303173" ID="ID_306583765" MODIFIED="1486520321580" TEXT="UiManager, Actions etc"/>
|
<node CREATED="1486520303173" ID="ID_306583765" MODIFIED="1486520321580" TEXT="UiManager, Actions etc"/>
|
||||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1486521232144" HGAP="44" ID="ID_1816242514" MODIFIED="1486751141053" TEXT="Fragen" VSHIFT="16">
|
<node CREATED="1486521232144" HGAP="44" ID="ID_1816242514" MODIFIED="1486767933363" TEXT="Fragen" VSHIFT="16">
|
||||||
<icon BUILTIN="help"/>
|
<icon BUILTIN="help"/>
|
||||||
<node CREATED="1486521810252" ID="ID_728134375" MODIFIED="1486521858401" TEXT="wer verkörpert den Sesison-Root?">
|
<node CREATED="1486521810252" ID="ID_728134375" MODIFIED="1486521858401" TEXT="wer verkörpert den Sesison-Root?">
|
||||||
<icon BUILTIN="help"/>
|
<icon BUILTIN="help"/>
|
||||||
|
|
@ -9973,6 +9985,9 @@
|
||||||
<icon BUILTIN="messagebox_warning"/>
|
<icon BUILTIN="messagebox_warning"/>
|
||||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1485555902731" ID="ID_1913236669" MODIFIED="1485555922185" TEXT="#1070 how to bind session commands into UI actions">
|
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1485555902731" ID="ID_1913236669" MODIFIED="1485555922185" TEXT="#1070 how to bind session commands into UI actions">
|
||||||
<icon BUILTIN="flag-yellow"/>
|
<icon BUILTIN="flag-yellow"/>
|
||||||
|
<node CREATED="1486767998242" ID="ID_1898269374" MODIFIED="1486768004600" TEXT="InteractionDirector verwenden">
|
||||||
|
<icon BUILTIN="idea"/>
|
||||||
|
</node>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue