UI-top-level: invent a new backbone entity to link between model and interaction state
After quite some pondering, it occured to me that we both - need some top-level model::Tangible to correspond to the RootMO in the session - need some Controller to handle globally relevant actions - need a way to link action invocation to transient interaction state (like focus) This leads to the introduction of a new top-level controller, which is better suited to fill that role than the depreacted model-controller or the demoted window-manager looks like we're in management business here ;-) we chop off heads, slaughter the holy cows and then install -- a new manager
This commit is contained in:
parent
eb42db537f
commit
27c8e78cf5
6 changed files with 706 additions and 28 deletions
352
src/gui/workspace/interaction-director.cpp
Normal file
352
src/gui/workspace/interaction-director.cpp
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
interactionDirector - Global UI Manager
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Joel Holdsworth <joel@airwebreathe.org.uk>
|
||||
2017, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
/** @file interaction-director.cpp
|
||||
** Implementation parts of the top-level controller within the UI.
|
||||
*/
|
||||
|
||||
|
||||
#include "gui/gtk-lumiera.hpp"
|
||||
#include "gui/config-keys.hpp"
|
||||
#include "gui/ui-bus.hpp"
|
||||
#include "gui/workspace/interaction-director.hpp"
|
||||
#include "gui/workspace/actions.hpp"
|
||||
#include "gui/workspace/window-list.hpp"
|
||||
#include "gui/workspace/workspace-window.hpp"
|
||||
#include "lib/searchpath.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <gtkmm/stylecontext.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
|
||||
using Gtk::IconSize;
|
||||
using Gtk::IconFactory;
|
||||
|
||||
using util::cStr;
|
||||
using util::isnil;
|
||||
using std::list;
|
||||
using std::shared_ptr;
|
||||
|
||||
|
||||
namespace gui {
|
||||
namespace workspace {
|
||||
|
||||
namespace fsys = boost::filesystem;
|
||||
|
||||
IconSize UiManager::GiantIconSize = Gtk::ICON_SIZE_INVALID;
|
||||
IconSize UiManager::MenuIconSize = Gtk::ICON_SIZE_INVALID;
|
||||
|
||||
|
||||
// dtors via smart-ptr invoked from here...
|
||||
InteractionDirector::~InteractionDirector()
|
||||
{ }
|
||||
|
||||
|
||||
InteractionDirector::InteractionDirector (UiBus& bus)
|
||||
: Gtk::UIManager()
|
||||
, 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
|
||||
UiManager::initGlobalUI ()
|
||||
{
|
||||
Glib::set_application_name (Config::get (KEY_TITLE));
|
||||
|
||||
registerAppIconSizes();
|
||||
registerStockItems();
|
||||
|
||||
setTheme (Config::get (KEY_STYLESHEET));
|
||||
|
||||
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
|
||||
237
src/gui/workspace/interaction-director.hpp
Normal file
237
src/gui/workspace/interaction-director.hpp
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
INTERACTION-DIRECTOR.hpp - Global UI Manager
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Joel Holdsworth <joel@airwebreathe.org.uk>
|
||||
2017, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/** @file interaction-director.hpp
|
||||
** 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.
|
||||
** It establishes and wires the top-level entities of the UI-Layer and thus, indirectly offers
|
||||
** services to provide Icons and other resources, to open and manage workspace windows, to
|
||||
** form and issue (global) actions and to delve into the UI representation of top-level parts
|
||||
** of the session model. Notable connections established herein:
|
||||
** - connection to the [UI-Bus](\ref ui-bus.hpp)
|
||||
** - the global Actions available though the menu
|
||||
** - the WindowList
|
||||
** - the InteractionDirector (top-level controller)
|
||||
**
|
||||
** @see gtk-lumiera.hpp
|
||||
** @see ui-bus.hpp
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GUI_WORKSPACE_INTERACTION_DIRECTOR_H
|
||||
#define GUI_WORKSPACE_INTERACTION_DIRECTOR_H
|
||||
|
||||
#include "gui/gtk-base.hpp"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <cairomm/cairomm.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace gui {
|
||||
|
||||
namespace model { class Project; } ////////////////////////////////////////////////////TICKET #1048 : rectify UI lifecycle
|
||||
namespace controller { class Controller; } ////////////////////////////////////////////////////TICKET #1048 : rectify UI lifecycle
|
||||
|
||||
class UiBus;
|
||||
|
||||
namespace workspace {
|
||||
|
||||
using std::unique_ptr;
|
||||
using std::string;
|
||||
|
||||
class Actions;
|
||||
class WindowList;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Manage global concerns regarding a coherent user interface.
|
||||
* Offers access to some global UI resources, and establishes
|
||||
* further global services to create workspace windows, to bind
|
||||
* menu / command actions and to enter the top-level model parts.
|
||||
*/
|
||||
class InteractionDirector
|
||||
: public Gtk::UIManager
|
||||
, boost::noncopyable
|
||||
{
|
||||
UiBus& uiBus_;
|
||||
|
||||
unique_ptr<WindowList> windowList_;
|
||||
unique_ptr<Actions> actions_;
|
||||
|
||||
string iconSearchPath_;
|
||||
string resourceSerachPath_;
|
||||
|
||||
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 ();
|
||||
|
||||
/**
|
||||
* 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:
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}}// namespace gui::workspace
|
||||
#endif /*GUI_WORKSPACE_INTERACTION_DIRECTOR_H*/
|
||||
|
|
@ -23,7 +23,11 @@
|
|||
|
||||
|
||||
/** @file ui-manager.cpp
|
||||
** Implementation of global UI resource and instance management.
|
||||
** Implementation of global concerns regarding a coherent UI and global state.
|
||||
** Especially, the wiring of top-level components is done here, as is the
|
||||
** basic initialisation of the interface and global configuration on
|
||||
** UI toolkit level.
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,9 +23,16 @@
|
|||
|
||||
|
||||
/** @file ui-manager.hpp
|
||||
** Manager for application resources and similar global state.
|
||||
** Manager for global user interface concerns and global state.
|
||||
** The central UiManager instance is owned by the GtkLumiera object and initialised in GTK-main.
|
||||
** It offers services to provide Icons and other resources and to set and access a general UI theme.
|
||||
** It establishes and wires the top-level entities of the UI-Layer and thus, indirectly offers
|
||||
** services to provide Icons and other resources, to open and manage workspace windows, to
|
||||
** form and issue (global) actions and to delve into the UI representation of top-level parts
|
||||
** of the session model. Notable connections established herein:
|
||||
** - connection to the [UI-Bus](\ref ui-bus.hpp)
|
||||
** - the global Actions available though the menu
|
||||
** - the WindowList
|
||||
** - the InteractionDirector (top-level controller)
|
||||
**
|
||||
** @see gtk-lumiera.hpp
|
||||
** @see ui-bus.hpp
|
||||
|
|
@ -61,7 +68,10 @@ namespace workspace {
|
|||
|
||||
|
||||
/**
|
||||
* The centralised manager of all icons and resources within Lumiera's GUI.
|
||||
* Manage global concerns regarding a coherent user interface.
|
||||
* Offers access to some global UI resources, and establishes
|
||||
* further global services to create workspace windows, to bind
|
||||
* menu / command actions and to enter the top-level model parts.
|
||||
*/
|
||||
class UiManager
|
||||
: public Gtk::UIManager
|
||||
|
|
|
|||
|
|
@ -2800,7 +2800,7 @@ The most fundamental principle is that of ''subsidiarity'': we understand both &
|
|||
Based on these foundations, we shape and form the core part of the interface, which is the [[timeline display|GuiTimelineView]]
|
||||
</pre>
|
||||
</div>
|
||||
<div title="GuiStart" modifier="Ichthyostega" created="200812050525" modified="201701261938" tags="GuiIntegration GuiPattern" changecount="1">
|
||||
<div title="GuiStart" modifier="Ichthyostega" created="200812050525" modified="201702101852" tags="GuiIntegration GuiPattern" changecount="4">
|
||||
<pre>Starting up the GUI is optional and is considered part of the Application start/stop and lifecycle.
|
||||
* main and AppState activate the lifecyle methods on the ~GuiSubsysDescriptor, accessible via the GuiFacade
|
||||
* loading a GuiStarterPlugin actually
|
||||
|
|
@ -2812,13 +2812,13 @@ Based on these foundations, we shape and form the core part of the interface, wh
|
|||
|
||||
!public services
|
||||
The GUI provides a small number of public services, callable through LayerSeparationInterfaces. Besides that, the main purpose of the GUI of course is user interaction. Effectively the behaviour of the whole system is driven by GUI events to a large extent. These events are executed within the event handling thread (~GTK-main-Thread) and may in turn invoke services of the lower layers, again through the respective LayerSeparationInterfaces.
|
||||
But the question of special interest here is how the //public services// of the GUI are implemented and made accessible for the lower Layers. Layer isolation is an issue here. If implemented in a rigorous manner, no facility within one layer may invoke implementation code of another layer directly. In practice, this tends to put quite some additional burden on the implementer, without and obvious benefit. Thus we decided to lower the barrier somewhat: while we still require that all service invoking calls are written against an public LayerSeparationInterface, actually the GUI (shared lib) is //linked// against the respective shared libs of the lower layers, thus especially enabling the exchange of iterators, closures and functor objects.
|
||||
But the question of special interest here is how the //public services// of the GUI are implemented and made accessible for the lower Layers. Layer isolation is an issue here. If implemented in a rigorous manner, no facility within one layer may invoke implementation code of another layer directly. In practice, this tends to put quite some additional burden on the implementer, without any obvious benefit. Thus we decided to lower the barrier somewhat: while we still require that all service invoking calls are written against a public LayerSeparationInterface, actually the GUI (shared lib) is //linked// against the respective shared libs of the lower layers, thus especially enabling the exchange of iterators, closures and functor objects.
|
||||
|
||||
Note that we retain strict isolation in the other direction: no part of the lower layers is allowed to call directly into the GUI. Thus it's especially interesting how access to some GUI public service from the lower layers works in detail.
|
||||
* when the GUI plugin starts, instances of the Services implementing those public service interfaces are created.
|
||||
* these service objects in turn hold an ~InstanceHandle, which cares to register and open the corresponding C Language Interface
|
||||
* additionally this InstanceHandle is configured such as to create an "facade proxy" object, which is implemented within liblumieracommon.so
|
||||
Now, when invoking an operation on some public interface, the code in the lower layers actually executes an implementation of this operation //on the facade proxy,// which in turn forwards the call through the CL interface into the GUI, where it is actually implemented by the corresponding service object instance.
|
||||
* additionally this InstanceHandle is configured such as to create a "facade proxy" object, which is implemented within {{{liblumieracommon.so}}}
|
||||
Now, when invoking an operation on some public interface, the code in the lower layers actually executes an implementation of this operation //on the facade proxy,// which in turn forwards the call through the CL interface into the GUI, where functionality is actually implemented by the corresponding service object instance.
|
||||
|
||||
!!!UI top level
|
||||
Regarding the internal organisation of Lumiera's ~UI-Layer, there is a [[top level structure|GuiTopLevel]] to manage application lifecycle
|
||||
|
|
@ -2922,7 +2922,7 @@ Applying a diff changes the structure, that is, the structure of the local model
|
|||
Together this means we get a fix up stage after model changes, where the display is re-adjusted to fit the new situation. This works in concert with the [[display manager|TimelineDisplayManager]] representing only those elements as actual widgets, which get a real chance to become visible. This way we can build on the assumption that the actual number of widgets to be managed any time remains so small as to get away with simple linear list processing. It remains to be seen how far this assumption can be pushed -- the problem is that the GTK container components don't support anything beyond such simple linear list processing; there isn't even a call to remove all child widgets of a container in a single pass.
|
||||
</pre>
|
||||
</div>
|
||||
<div title="GuiTopLevel" creator="Ichthyostega" modifier="Ichthyostega" created="201701261944" modified="201701261950" tags="GuiPattern spec draft" changecount="4">
|
||||
<div title="GuiTopLevel" creator="Ichthyostega" modifier="Ichthyostega" created="201701261944" modified="201702102010" tags="GuiPattern spec draft" changecount="5">
|
||||
<pre>To a large extent, the Lumiera user interface is built around a //backbone structure,// known as the UI-Bus.
|
||||
But there are some dedicated top-level entities, collaborating to maintain a consistent application lifecycle
|
||||
;Application
|
||||
|
|
@ -2934,8 +2934,11 @@ But there are some dedicated top-level entities, collaborating to maintain a con
|
|||
;UI Manager
|
||||
:maintain a coherent global interface
|
||||
:responsible for all global framework concerns, resources and global application state
|
||||
;Window Manager
|
||||
:manage the top level workspace windows
|
||||
;Interaction Director
|
||||
:establish the connection between global interaction state and global session state
|
||||
:the [[InteractionDirector|UIInteractionDirector]] is the root controller and corresponds to the [[root object in session|ModelRootMO]].
|
||||
;Window List
|
||||
:organise and maintain the top level workspace windows
|
||||
;Notification Façade
|
||||
:attachment point for lower layers and anyone in need to "talk to the UI"
|
||||
:the GuiNotificationFacade is a LayerSeparationInterface and integrated with Lumiera's interface system
|
||||
|
|
@ -3683,10 +3686,10 @@ This observation leads to the idea of using //model port references// as fronten
|
|||
A model port registry, maintained by the builder, is responsible for storing the discovered model ports within a model port table, which is then swapped in after completing the build process. The {{{builder::ModelPortRegistry}}} acts as management interface, while client code accesses just the {{{ModelPort}}} frontend. A link to the actual registry instance is hooked into that frontend when bringing up the builder subsystem.
|
||||
</pre>
|
||||
</div>
|
||||
<div title="ModelRootMO" modifier="Ichthyostega" created="200912080307" modified="201505310113" tags="def" changecount="1">
|
||||
<div title="ModelRootMO" modifier="Ichthyostega" created="200912080307" modified="201702101927" tags="def" changecount="4">
|
||||
<pre>A special kind of MObject, serving as a marker or entry point at the root of the HighLevelModel. As any ~MObject, it is attached to the model by a [[Placement]]. And in this special case, this placement froms the ''root scope'' of the model, thus containing any other PlacementScope (e.g. forks, clips with effects,...)
|
||||
|
||||
This special ''session root object'' provides a link between the model part and the &raquo;bookkeeping&laquo; part of the session, i.e. the [[assets|Asset]]. It is created and maintained by the session (implementation level) &mdash; allowing to store and load the asset definitions as contents of the model root element.
|
||||
This special ''session root object'' provides a link between the model part and the &raquo;bookkeeping&laquo; part of the session, i.e. the [[assets|Asset]]. It is created and maintained by the session (implementation level) &mdash; allowing to store and load the asset definitions as contents of the model root element. Beyond that, this //root scope representation// serves another, closely related purpose: conceptually, structures of the HighLevelModel are mapped into the UI, by virtue of the [[diff framework|TreeDiffModel]]. Corresponding to each relevant entity in the model, there is a widget or a controller in the UI to serve as [[tangible front-end|UI-Element]] to expose this entity. And in accordance to this regime, the session root object is mapped onto the [[InteractionDirector|UI-InteractionDirector]] (top-level controller), which, in conjunction with {{{UiManager}}} and UI-Bus, forms the leading structure of the UI-Layer.
|
||||
|
||||
__Note__: nothing within the PlacementIndex requires the root object to be of a specific type; the index just assumes a {{{Placement<MObject>}}} (or subclass) to exist as root element. And indeed, for several unit tests we create an Index mock with a tree of dummy ~MObjects and temporarily shaddow the "real" PlacementIndex by this mock (&rarr; see SessionServices for the API allowing to access this //mock index//- functionality)
|
||||
|
||||
|
|
@ -5248,10 +5251,11 @@ So the challenge of any major undertaking in software construction is //not to b
|
|||
More specifically, we start building something, and while under way, our understanding sharpens, and we learn that actually we want something entirely different. Yet still we know what we need and we don't want just something arbitrary. There is a constant core in what we're headed at, and we need the ability to //settle matters.// We need a backbone to work against, a skeleton to support us with its firmness, while also offering joints and links, to be bent and remoulded without breakage. The distinctive idea to make such possible is the principle of subsidiarity. The links and joints between autonomous centres can be shaped to be in fact an exchange, a handover based on common understanding of the //specific matters to deal with,// at that given joint.
|
||||
</pre>
|
||||
</div>
|
||||
<div title="Proc-Layer" modifier="Ichthyostega" created="200802031814" tags="def">
|
||||
<pre>The current Lumiera architecture separates functionality into three Layers: __GUI__, __Proc__ and __Backend__.
|
||||
<div title="Proc-Layer" modifier="Ichthyostega" created="200802031814" modified="201702101931" tags="def" changecount="1">
|
||||
<pre>The architecture of the Lumiera application separates functionality into three Layers: __GUI__, __Proc__ and __Backend__.
|
||||
|
||||
While the Backend is responsible for Data access and management and for carrying out the computation intensive media opteratons, the middle Layer or ~Proc-Layer contains [[assets|Asset]] and [[Session]], i.e. the user-visible data model and provides configuration and behaviour for these entities. Besides, he is responsible for [[building and configuring|Builder]] the [[render engine|RenderEngine]] based on the current Session state.</pre>
|
||||
While the Backend is responsible for Data access and management and for carrying out the computation intensive media opteratons, the middle Layer or ~Proc-Layer contains [[assets|Asset]] and [[Session]], i.e. the user-visible data model and provides configuration and behaviour for these entities. Besides, he is responsible for [[building and configuring|Builder]] the [[render engine|RenderEngine]] based on the current Session state.
|
||||
&rarr; UI-Layer</pre>
|
||||
</div>
|
||||
<div title="ProcAsset" modifier="Ichthyostega" created="200709221343" modified="201003140233" tags="def classes img">
|
||||
<pre>All Assets of kind asset::Proc represent //processing algorithms// in the bookkeeping view. They enable loading, browsing and maybe even parametrizing all the Effects, Plugins and Codecs available for use within the Lumiera Session.
|
||||
|
|
@ -9172,6 +9176,21 @@ It is clear by now (9/2016) how shape and content changes are to be represented
|
|||
The dispatch of //diff messages// is directly integrated into the UI-Bus -- which is not just some abstract messaging system, but deliberately made to act as backbone for the kind of operations and collaborations detailed here. This seamless integration helps to overcome several technical (detail) problems. For one, the diff framework itself is //generic,// which allows to apply diff sequences to a wide variety of different target data structures. And, secondly, choose the whole approach of diff messages delivered over a bus system for a very specific, architectural reason: we want to decouple from internal structures, while still allowing low-level collaboration over this abstracted interconnection channel. On both counts, we are thus bound to encapsulate the actual diff at interface level. So the MutationMessage marks the purpose to alter the designated {{{Tangible}}}, while offering an embedded, generic implementation to apply the (hidden) diff message, relying in turn on the interface {{{DiffMutatble}}}, which -- surprise -- is offered by {{{Tangible}}}. Basically this means that each tangible interface element offers the ability to be reshaped, by creating a TreeMutator on demand, internally wired to effect the changes inscribed within the diff.
|
||||
</pre>
|
||||
</div>
|
||||
<div title="UI-Layer" creator="Ichthyostega" modifier="Ichthyostega" created="201702102005" tags="def" changecount="1">
|
||||
<pre>The architecture of the Lumiera application separates functionality into three Layers: __GUI__, __Proc__ and __Backend__.
|
||||
|
||||
The Graphical User interface, the upper layer in this hierarchy, embodies everything of tangible relevance to the user working with the application. The interplay with Proc-Layer, the middle layer below the UI, is organised along the distinction between two realms of equal importance: on one side, there is the immediate //mechanics of the interface,// which is implemented directly within the ~UI-Layer, based on the Graphical User Interface Toolkit. And, on the other side, there are those //core concerns of working with media,// which are cast into the HighLevelModel at the heart of the middle layer.</pre>
|
||||
</div>
|
||||
<div title="UIInteractionDirector" creator="Ichthyostega" modifier="Ichthyostega" created="201702102146" tags="def draft" changecount="1">
|
||||
<pre>//the top-level controller within the UI.//
|
||||
In Lumiera, the structures of the model within the [[Session]] (the so called HighLevelModel) are mapped onto corresponding [[tangible UI entities|UI-Element]], which serve as a front-end to represent those entities towards the user. Within the model, there is a //conceptual root node// -- which logically corresponds to the session itself. This [[root element in model|ModelRootMO]] links together the actual top-level entities, which are the (multiple) timelines, with the asset management and defaults and rules configuration within the session.
|
||||
|
||||
And the counterpart of this root element within the UI is the {{{InteractionDirector}}}, a top-level controller. As a controller, it responds to actions like opening a specific timeline, entering the asset management section, opening and closing of the session as a whole, and even shutdown of the application as a whole. Beyond that, the Interaction Director is the connection joint to that part of the UI which deals with global interaction state: this relates to questions about "the current element", "the focus", "where we are right now" (in what "location" or "room" within the UI) and what tangible interface controller we're actually using (mouse, keyboard, graphics pen, hardware controller, touch screen).
|
||||
|
||||
Why do we need a connection joint between those parts?
|
||||
Because issuing any actions on the model within the session -- i.e. any editing operation -- is like forming a sentence: we need to spell out //what we want to do// and we need to spell out the subject and the object of our activity. And any one of these can, and will in fact, be sometimes derived //from the context of the interaction.// Because, given the right context, it is almost clear what you want to do -- you just need to fill in that tiny little bit of information to actually make it happen. In Lumiera we want to build a good UI, which is an UI well suited to this very human way of interacting with one's environment within a given context.
|
||||
</pre>
|
||||
</div>
|
||||
<div title="ViewConnection" modifier="Ichthyostega" created="201105221854" modified="201501091154" tags="def Model SessionLogic" changecount="3">
|
||||
<pre>For any kind of playback to happen, timeline elements (or similar model objects) need to be attached to a Viewer element through a special kind of [[binding|BindingMO]], called a ''view connection''. In the most general case, this creates an additional OutputMapping (and in the typical standard case, this boils down to a 1:1 association, sending the master bus of each media kind to the standard OutputDesignation for that kind).
|
||||
|
||||
|
|
|
|||
|
|
@ -1779,8 +1779,7 @@
|
|||
Lösung: <i><font color="#27754d">schwebende Bindung</font></i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1485902684454" ID="ID_1435239012" MODIFIED="1485902691584" TEXT="Eventgetriebene Oberfläche"/>
|
||||
<node CREATED="1485902692556" ID="ID_1729615218" MODIFIED="1485902698503" TEXT="wird einmal Verdrahtet"/>
|
||||
|
|
@ -1794,8 +1793,7 @@
|
|||
arbeitet dann <i>freischwebend</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1485902750053" ID="ID_34756513" MODIFIED="1485902754440" TEXT="zentrales Bindeglied">
|
||||
<node CREATED="1485902762284" ID="ID_1542199290" MODIFIED="1485902773701" TEXT="kennt die Applikation"/>
|
||||
|
|
@ -1834,8 +1832,7 @@
|
|||
diesen "aktuellen Kontext" irgendwo <i>aufzufischen</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<node CREATED="1485903041262" ID="ID_997327941" MODIFIED="1485903044082" TEXT="Fokus"/>
|
||||
<node CREATED="1485903046613" ID="ID_1041890737" MODIFIED="1485917548794" TEXT="aktuelles Fenster">
|
||||
<linktarget COLOR="#375a84" DESTINATION="ID_1041890737" ENDARROW="Default" ENDINCLINATION="177;-181;" ID="Arrow_ID_373431525" SOURCE="ID_1089795419" STARTARROW="None" STARTINCLINATION="245;-68;"/>
|
||||
|
|
@ -1886,8 +1883,7 @@
|
|||
und verwendet, und das ist auch gut so
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1486063950103" ID="ID_57649689" MODIFIED="1486063952666" TEXT="zwei Modelle">
|
||||
<node CREATED="1486063954062" FOLDED="true" ID="ID_1174765379" MODIFIED="1486518487102" TEXT="Actions wird insgesamt ein PImpl">
|
||||
|
|
@ -1973,7 +1969,27 @@
|
|||
<node CREATED="1485454263876" ID="ID_543704434" MODIFIED="1485454270615" TEXT="globale Keybindings"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1485126466520" FOLDED="true" ID="ID_717310004" MODIFIED="1485548666258" TEXT="WindowManager">
|
||||
<node CREATED="1486763185746" HGAP="33" ID="ID_362749694" MODIFIED="1486763255758" 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;"/>
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1486763268223" ID="ID_199328732" MODIFIED="1486763277392" TEXT="nicht der Meister">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
|
||||
</node>
|
||||
<node CREATED="1486763278189" ID="ID_330558344" MODIFIED="1486763285944" TEXT="aber ein zentrales Bindeglied"/>
|
||||
<node CREATED="1486763287244" ID="ID_1712681910" MODIFIED="1486763291199" TEXT="zwei Welten">
|
||||
<node CREATED="1486763292028" ID="ID_1224392598" MODIFIED="1486763301742" TEXT="Modell-struktur == Hierarchie"/>
|
||||
<node CREATED="1486763303066" ID="ID_1274975607" MODIFIED="1486763317596" TEXT="Interaktion == Fokus und Kontext"/>
|
||||
</node>
|
||||
<node CREATED="1486763350764" ID="ID_1309124609" MODIFIED="1486763423979" TEXT="Aufgaben">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1486763355739" ID="ID_745725927" MODIFIED="1486763370261" TEXT="Bindung für Aktionen bereitstellen"/>
|
||||
<node CREATED="1486763376960" ID="ID_1618020758" MODIFIED="1486763385091" TEXT="Zugang zu den Timelines"/>
|
||||
<node CREATED="1486763385591" ID="ID_6651258" MODIFIED="1486763391202" TEXT="Zugang zum Asset-Management"/>
|
||||
<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>
|
||||
</node>
|
||||
<node CREATED="1485126466520" FOLDED="true" ID="ID_717310004" MODIFIED="1486763253254" TEXT="WindowManager" VSHIFT="34">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1485457325724" ID="ID_1954589768" MODIFIED="1485457325724" TEXT="nur für die Hauptfenster zuständig"/>
|
||||
<node CREATED="1485457328043" ID="ID_1787642462" MODIFIED="1485457367904" TEXT="wir haben kein ApplicationWindow">
|
||||
|
|
@ -2043,11 +2059,12 @@
|
|||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1486520281897" ID="ID_827558797" MODIFIED="1486520324210" TEXT="Problem: zwei Inseln">
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1486520281897" ID="ID_827558797" MODIFIED="1486751054587" TEXT="Problem: zwei Inseln">
|
||||
<arrowlink COLOR="#464b68" DESTINATION="ID_1847844548" ENDARROW="Default" ENDINCLINATION="35;-168;" ID="Arrow_ID_1483178089" STARTARROW="Default" STARTINCLINATION="-2;95;"/>
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<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 BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1486521232144" HGAP="40" ID="ID_1816242514" MODIFIED="1486521245172" TEXT="Fragen" VSHIFT="33">
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1486521232144" HGAP="44" ID="ID_1816242514" MODIFIED="1486751141053" TEXT="Fragen" VSHIFT="16">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1486521810252" ID="ID_728134375" MODIFIED="1486521858401" TEXT="wer verkörpert den Sesison-Root?">
|
||||
<icon BUILTIN="help"/>
|
||||
|
|
@ -2083,6 +2100,23 @@
|
|||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1486751116251" HGAP="140" ID="ID_113005643" MODIFIED="1486763238179" VSHIFT="61">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Brücke: <i>gemeinsamer</i> Controller
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<arrowlink COLOR="#683c5b" DESTINATION="ID_362749694" ENDARROW="Default" ENDINCLINATION="-394;0;" ID="Arrow_ID_1979576517" STARTARROW="None" STARTINCLINATION="-24;-159;"/>
|
||||
<node CREATED="1486751221990" ID="ID_563286868" MODIFIED="1486751232207" TEXT="ist Bindeglied für globale Aktionen"/>
|
||||
<node CREATED="1486751233315" ID="ID_1611855815" MODIFIED="1486751238982" TEXT="verkörpert den Model-Root"/>
|
||||
<node CREATED="1486751248097" ID="ID_1313868100" MODIFIED="1486751258147" TEXT="ist Vollmitglied am Bus"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1485126481023" ID="ID_943652445" MODIFIED="1485126488201" TEXT="pro Fenster">
|
||||
|
|
@ -2132,8 +2166,30 @@
|
|||
</node>
|
||||
</node>
|
||||
<node CREATED="1480694854057" HGAP="32" ID="ID_577309407" MODIFIED="1480694877355" TEXT="TimelinePane" VSHIFT="7">
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1480694860696" ID="ID_1847844548" MODIFIED="1480694886787" TEXT="entspricht dem Model-Root">
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1480694860696" ID="ID_1847844548" MODIFIED="1486751054587" TEXT="entspricht dem Model-Root">
|
||||
<linktarget COLOR="#464b68" DESTINATION="ID_1847844548" ENDARROW="Default" ENDINCLINATION="35;-168;" ID="Arrow_ID_1483178089" SOURCE="ID_827558797" STARTARROW="Default" STARTINCLINATION="-2;95;"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1486750918553" ID="ID_723234072" MODIFIED="1486750929291" TEXT="wirklich??">
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
<node CREATED="1486750933252" ID="ID_567923045" MODIFIED="1486750967485" TEXT="sollte doch ehr...">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1486750939411" ID="ID_1566629434" MODIFIED="1486750945053" TEXT="ein globaler Controller sein"/>
|
||||
<node CREATED="1486750945521" ID="ID_759126310" MODIFIED="1486750975987">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
der an <i>geeigneter</i> Stelle hängt
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1486750954906" ID="ID_113736248" MODIFIED="1486750962659" TEXT="und in die TimelinePane injiziert wird"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1480694897443" ID="ID_402490324" MODIFIED="1480694916396" TEXT="verwaltet die Timelines"/>
|
||||
<node CREATED="1480694918056" ID="ID_789731200" MODIFIED="1480694948954">
|
||||
|
|
|
|||
Loading…
Reference in a new issue