Clean-up: sort out further leftovers from the GTK-2 UI

After the Dummy-Player (interface and prototype implementation)
is removed, some further bits of debris can be sorted out.
The first version of the Timeline was mostly rewritten and
the obsolete parts were removed in 2023, yet a small number
of files was kept around as reference for later.

Some of these are no longer considered of any information value,
other ones were moved into the widget package (and further problematic
parts were annotated, but can be still used with GTK-3)
This commit is contained in:
Fischlurch 2025-05-15 23:41:54 +02:00
parent 017ba5f160
commit ee6e720d00
18 changed files with 480 additions and 875 deletions

View file

@ -1,77 +0,0 @@
/*
CairoUtil - utility functions for Cairo
Copyright (C)
2010, Stefan Kangas <skangas@skangas.se>
  **Lumiera** 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. See the file COPYING for further details.
* *****************************************************************/
/** @file cairo-util.cpp
** Implementation of helper functions to support working with lib Cairo
*/
#include "stage/draw/cairo-util.hpp"
namespace stage {
namespace draw {
RefPtr<SolidPattern>
CairoUtil::pattern_set_red (const RefPtr<SolidPattern> color, double red)
{
double old_red;
double blue;
double green;
double alpha;
color->get_rgba (old_red, blue, green, alpha);
return Cairo::SolidPattern::create_rgba (red, blue, green, alpha);
}
RefPtr<SolidPattern>
CairoUtil::pattern_set_green (const RefPtr<SolidPattern> color, double blue)
{
double red;
double old_blue;
double green;
double alpha;
color->get_rgba (red, old_blue, green, alpha);
return Cairo::SolidPattern::create_rgba (red, blue, green, alpha);
}
RefPtr<SolidPattern>
CairoUtil::pattern_set_blue (const RefPtr<SolidPattern> color, double green)
{
double red;
double blue;
double old_green;
double alpha;
color->get_rgba (red, blue, old_green, alpha);
return Cairo::SolidPattern::create_rgba (red, blue, green, alpha);
}
RefPtr<SolidPattern>
CairoUtil::pattern_set_alpha (const RefPtr<SolidPattern> color, double alpha)
{
double red;
double blue;
double green;
double old_alpha;
color->get_rgba (red, blue, green, old_alpha);
return Cairo::SolidPattern::create_rgba (red, blue, green, alpha);
}
}}// namespace stage::draw

View file

@ -13,61 +13,97 @@
/** @file cairo-util.hpp
** Utility functions for working with elements from the Cairo
** vector drawing library.
** Utility functions for working with elements from the Cairo vector drawing library.
*/
#include <cairomm/cairomm.h>
#ifndef STAGE_DRAW_CAIRO_H
#define STAGE_DRAW_CAIRO_H
using Cairo::RefPtr;
using Cairo::SolidPattern;
#include "stage/gtk-base.hpp"
#include "lib/util.hpp"
namespace stage {
namespace stage{
namespace draw {
/**
* @todo this is not a real entity; consider to turn this into a set of free functions!
*/
class CairoUtil
{
public:
/**
* Make a new SolidPattern from an old one, changing the red component of the colour.
* @param The new value for the red component of the colour.
* @return The new pattern.
*/
static RefPtr<SolidPattern>
pattern_set_red (const RefPtr<SolidPattern> color, double red);
using Cairo::SolidPattern;
using Cairo::RefPtr;
/**
* Make a new SolidPattern from an old one, changing the green component of the colour.
* @param The new value for the green component of the colour.
* @return The new pattern.
*/
static RefPtr<SolidPattern>
pattern_set_green (const RefPtr<SolidPattern>, double green);
/**
* Make a new SolidPattern from an old one, changing the blue component of the colour.
* @param The new value for the blue component of the colour.
* @return The new pattern.
*/
static RefPtr<SolidPattern>
pattern_set_blue (const RefPtr<SolidPattern>, double blue);
inline RefPtr<SolidPattern>
pattern_set_red (RefPtr<SolidPattern> const& color, double red)
{
double _red_ignored;
double green;
double blue;
double alpha;
/**
* Make a new SolidPattern from an old one, changing the alpha component of the colour.
* @param The new value for the alpha component of the colour.
* @return The new pattern.
*/
static RefPtr<SolidPattern>
pattern_set_alpha (const RefPtr<SolidPattern>, double alpha);
};
color->get_rgba (_red_ignored, green, blue, alpha);
return Cairo::SolidPattern::create_rgba (red, green, blue, alpha);
}
inline RefPtr<SolidPattern>
pattern_set_green (RefPtr<SolidPattern> const& color, double green)
{
double red;
double _green_ignored;
double blue;
double alpha;
color->get_rgba (red, _green_ignored, blue, alpha);
return Cairo::SolidPattern::create_rgba (red, green, blue, alpha);
}
inline RefPtr<SolidPattern>
pattern_set_blue (RefPtr<SolidPattern> const& color, double blue)
{
double red;
double green;
double _blue_ignored;
double alpha;
color->get_rgba (red, green, _blue_ignored, alpha);
return Cairo::SolidPattern::create_rgba (red, green, blue, alpha);
}
inline RefPtr<SolidPattern>
pattern_set_alpha (RefPtr<SolidPattern> const& color, double alpha)
{
double red;
double green;
double blue;
double _alpha_ignored;
color->get_rgba (red, green, blue, _alpha_ignored);
return Cairo::SolidPattern::create_rgba (red, green, blue, alpha);
}
inline bool
pt_in_rect (Gdk::Point const& point, Gdk::Rectangle const& rect)
{
return (point.get_x() >= rect.get_x()
and point.get_x() < rect.get_x() + rect.get_width()
and point.get_y() >= rect.get_y()
and point.get_y() < rect.get_y() + rect.get_height());
}
inline bool
rects_overlap (Gdk::Rectangle const& recA, Gdk::Rectangle const& recB)
{
return (
util::max (recA.get_x(), recB.get_x())
< util::min (recA.get_x() + recA.get_width(), recB.get_x() + recB.get_width())
and
util::max (recA.get_y(), recB.get_y())
< util::min (recA.get_y() + recA.get_height(), recB.get_y() + recB.get_height())
);
}
}}// namespace stage::draw
#endif /*STAGE_DRAW_CAIRO_H*/

View file

@ -1,53 +0,0 @@
/*
Rectangle - utility functions for GDK rectangles
Copyright (C)
2008, Joel Holdsworth <joel@airwebreathe.org.uk>
  **Lumiera** 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. See the file COPYING for further details.
* *****************************************************************/
/** @file rectangle.cpp
** Implementation of functions to work with rectangular screen ranges
** @todo 3/23 this is leftover code from the old GKT-2 Lumiera GUI.
** This code should be consolidated into some kind of Cairo drawing utils!
*/
#include "stage/draw/rectangle.hpp"
#include <algorithm>
using std::max;
using std::min;
namespace stage {
namespace draw{
bool
pt_in_rect(const Gdk::Point &point, const Gdk::Rectangle &rect)
{
return (point.get_x() >= rect.get_x() &&
point.get_x() < rect.get_x() + rect.get_width() &&
point.get_y() >= rect.get_y() &&
point.get_y() < rect.get_y() + rect.get_height());
}
bool
rects_overlap (Gdk::Rectangle const& a, Gdk::Rectangle const& b)
{
return (
max(a.get_x(), b.get_x()) <
min(a.get_x() + a.get_width(), b.get_x() + b.get_width())
&&
max(a.get_y(), b.get_y()) <
min(a.get_y() + a.get_height(), b.get_y() + b.get_height())
);
}
}}// namespace stage::draw

View file

@ -1,39 +0,0 @@
/*
RECTANGLE.hpp - utility functions for GDK rectangles
Copyright (C)
2008, Joel Holdsworth <joel@airwebreathe.org.uk>
  **Lumiera** 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. See the file COPYING for further details.
* *****************************************************************/
/** @file rectangle.hpp
** Helper functions to work with rectangular screen ranges
** @todo 3/23 this is leftover code from the old GKT-2 Lumiera GUI.
** This code should be consolidated into some kind of Cairo drawing utils!
*/
#ifndef STAGE_DRAW_RECTANGLE_H
#define STAGE_DRAW_RECTANGLE_H
#include "stage/gtk-base.hpp"
namespace stage {
namespace draw {
/** determine whether point is within the bounding box of a rectangle */
bool pt_in_rect(Gdk::Point const& point, Gdk::Rectangle const& rect);
/** determine whether two rectangles overlap */
bool rects_overlap(Gdk::Rectangle const& a, Gdk::Rectangle const& b);
}}// namespace stage::draw
#endif /*STAGE_DRAW_RECTANGLE_H*/

View file

@ -26,6 +26,8 @@
**
** @todo as of 10/2016 this is WIP-WIP-WIP : canvas widgets experiment
** @todo as of 10/2018 we start to build a new timeline widget, connected to the UI-Bus
** @todo as of 03/2023 the backbone of the new structure is in place (see #1042)
** @todo as of 05/2025 we need actual editing functionality in the core to continue building here.... //////TICKET #305
*/

View file

@ -84,7 +84,7 @@ namespace widget {
* @todo 9/2018 dummy placeholder code, later to be transformed into a framework /////////////////////TICKET #1168 : find a way to manage style of custom extended UI elements
*/
inline void
populateStandardTextTags (Glib::RefPtr<TextBuffer::TagTable> tagTable)
populateStandardTextTags (Glib::RefPtr<Gtk::TextBuffer::TagTable> tagTable)
{
Tag errorTag = Gtk::TextBuffer::Tag::create (cuString{TAG_ERROR});
errorTag->property_background() = "Yellow"; ////////////////////////////////////////////TICKET #1168 : should be retrieved from a central location

View file

@ -20,53 +20,49 @@
#include "stage/widget/menu-button.hpp"
using namespace Gtk; ///////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
using namespace Glib; ///////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
using namespace sigc; ///////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
#define POPUP_SLUG "TheMenu"
#define POPUP_PATH "/" POPUP_SLUG
namespace stage {
namespace widget {
namespace widget{
namespace {
const int CaptionPadding = 4;
const ArrowType arrowType = ARROW_DOWN;
const ShadowType shadowType = SHADOW_NONE;
const int CAPTION_PADDING = 4;
const Gtk::ArrowType ARROW_TYPE = Gtk::ARROW_DOWN;
const Gtk::ShadowType SHADOW_TYPE = Gtk::SHADOW_NONE;
}
MenuButton::MenuButton()
: ToggleButton()
, arrow(arrowType, shadowType)
, uimanager(UIManager::create())
, actions(ActionGroup::create())
, arrow_{ARROW_TYPE, SHADOW_TYPE}
, uimanager_{Gtk::UIManager::create()}
, actions_{Gtk::ActionGroup::create()}
{
setupButton();
}
MenuButton::MenuButton (StockID const& stock_id)
: ToggleButton()
, image(stock_id, ICON_SIZE_MENU)
, caption()
, arrow(arrowType, shadowType)
MenuButton::MenuButton (Gtk::StockID const& stock_id)
: ToggleButton{}
, image_{stock_id, Gtk::ICON_SIZE_MENU}
, caption_{}
, arrow_{ARROW_TYPE, SHADOW_TYPE}
{
StockItem stock_item;
REQUIRE (StockItem::lookup (stock_id, stock_item));
caption.set_text_with_mnemonic (stock_item.get_label());
hBox.pack_start (image);
Gtk::StockItem stock_item;
REQUIRE (Gtk::StockItem::lookup (stock_id, stock_item));
caption_.set_text_with_mnemonic (stock_item.get_label());
hBox_.pack_start (image_);
setupButton();
}
MenuButton::MenuButton (cuString& label, bool mnemonic)
: ToggleButton()
, caption(label, mnemonic)
, arrow(arrowType, shadowType)
, caption_(label, mnemonic)
, arrow_(ARROW_TYPE, SHADOW_TYPE)
{
setupButton();
}
@ -79,36 +75,40 @@ namespace widget {
//TODO: if (slug == "Menu") return &get_menu();
uString path (POPUP_PATH);
path.append("/");
return uimanager->get_widget(path.append(slug));
return uimanager_->get_widget(path.append(slug));
}
Menu&
Gtk::Menu&
MenuButton::get_menu()
{
uString path ("/");
uString path{"/"};
path.append (POPUP_SLUG);
Menu* p_menu = dynamic_cast<Menu*>(
uimanager->get_widget(path));
auto* p_menu = dynamic_cast<Gtk::Menu*> (uimanager_->get_widget(path));
REQUIRE (p_menu);
return *p_menu;
}
void
MenuButton::append (uString &slug, uString &title,
sigc::slot<void> &callback, bool toggle)
MenuButton::append (uString& slug, uString &title,
sigc::slot<void>& callback, bool toggle)
{
if (!toggle)
actions->add(Action::create(slug, title,""), callback);
if (not toggle)
actions_->add (Gtk::Action::create (slug, title,""), callback);
else
actions->add(ToggleAction::create(slug, title,"",false), callback);
actions_->add (Gtk::ToggleAction::create (slug, title,"",false), callback);
uimanager->add_ui(uimanager->new_merge_id(),
ustring("ui/").append(POPUP_SLUG),
slug, slug, Gtk::UI_MANAGER_AUTO,
false);
uimanager->ensure_update();
/////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1181 based on Interface-builder // @deprecated
uimanager_->add_ui (uimanager_->new_merge_id() // ID for the merged UI, see gtk_ui_manager_new_merge_id().
,uString{"ui/"}.append(POPUP_SLUG) // schematic path in the UI
,slug // name for the added UI element
,slug // name for the action to be proxied
,Gtk::UI_MANAGER_AUTO // type of the UI element to add
,false // if the UI element is added before its siblings (otherwise added after them)
);
uimanager_->ensure_update();
}
@ -125,9 +125,9 @@ namespace widget {
void
MenuButton::appendSeparator()
{
uimanager->add_ui_separator(
uimanager->new_merge_id(),
ustring("ui/").append(POPUP_SLUG),
uimanager_->add_ui_separator(
uimanager_->new_merge_id(),
uString{"ui/"}.append(POPUP_SLUG),
"Separator", Gtk::UI_MANAGER_SEPARATOR,
false);
}
@ -136,34 +136,37 @@ namespace widget {
void
MenuButton::popup()
{
get_menu().popup(mem_fun(this, &MenuButton::on_menu_position),
0, gtk_get_current_event_time());
set_active();
get_menu().popup (sigc::mem_fun (this, &MenuButton::on_menu_position)
,0 // The mouse button which was pressed to initiate the event
,gtk_get_current_event_time()); // activate_time The time at which the activation event occurred.
this->set_active();
}
void
MenuButton::setupButton()
{
uimanager = UIManager::create();
actions = ActionGroup::create();
uimanager->insert_action_group(actions);
uimanager_ = Gtk::UIManager::create();
actions_ = Gtk::ActionGroup::create();
uimanager_->insert_action_group(actions_);
// Setup the UIManager with a popup menu
const guint rootId = uimanager->new_merge_id();
uimanager->add_ui(rootId, "ui",
POPUP_SLUG, POPUP_SLUG,
Gtk::UI_MANAGER_POPUP);
const guint rootId = uimanager_->new_merge_id();
uimanager_->add_ui (rootId
,"ui"
,POPUP_SLUG
,POPUP_SLUG
,Gtk::UI_MANAGER_POPUP
);
get_menu().signal_deactivate().connect(
sigc::mem_fun (this, &MenuButton::on_menu_deactivated));
get_menu().signal_deactivate().connect(mem_fun(
this, &MenuButton::on_menu_deactivated));
arrow_.set (Gtk::ARROW_DOWN, Gtk::SHADOW_NONE);
arrow.set(ARROW_DOWN, SHADOW_NONE);
hBox_.pack_start (caption_, Gtk::PACK_EXPAND_WIDGET, CAPTION_PADDING);
hBox_.pack_start (arrow_);
hBox.pack_start(caption, PACK_EXPAND_WIDGET, CaptionPadding);
hBox.pack_start(arrow);
add(hBox);
add (hBox_);
show_all();
}
@ -171,14 +174,14 @@ namespace widget {
void
MenuButton::on_pressed()
{
popup();
this->popup();
}
void
MenuButton::on_menu_deactivated()
{
set_active(false);
this->set_active (false);
}
@ -189,11 +192,11 @@ namespace widget {
REQUIRE(window);
window->get_origin(x, y);
const Allocation allocation = get_allocation();
x += allocation.get_x();
y += allocation.get_y() + allocation.get_height();
auto allocation = get_allocation();
x += allocation.get_x();
y += allocation.get_y() + allocation.get_height();
push_in = true;
push_in = true;
}

View file

@ -14,7 +14,7 @@
/** @file menu-button.hpp
** A button widget that displays a menu when clicked.
** @todo leftover from the old GTK-2 Lumiera UI as of 3/23,
** @todo 2023 leftover from the old GTK-2 Lumiera UI as of 3/23,
** but should be retained and integrated into the reworked GTK-3 UI
*/
@ -29,14 +29,22 @@
namespace stage {
namespace widget {
using namespace Gtk; ////////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
/**
* A button that displays a menu when clicked on.
*/
class MenuButton
: public ToggleButton
: public Gtk::ToggleButton
{
Gtk::HBox hBox_; ///< holds the layout of an image, caption and arrow.
Gtk::Image image_; ///< can optionally display an icon.
Gtk::Label caption_; ///< caption text label to show on the button.
Gtk::Arrow arrow_; ///< arrow widget to be displayed to indicate a drop-down menu
Gtk::Menu menu_; ///< internal menu object which is the popup menu of this widget.
Glib::RefPtr<Gtk::UIManager> uimanager_;
Glib::RefPtr<Gtk::ActionGroup> actions_;
public:
/**
* Create an empty button.
@ -50,9 +58,10 @@ namespace widget {
/**
* Creates a new Button containing the image and text from a stock item.
* @remarks Stock IDs have identifiers like \c Stock::OK and \c Stock::APPLY.
* @remarks Stock IDs have identifiers like `Stock::OK` and `Stock::APPLY`.
* @deprecated Stock-IDs will be removed with GTK-4
*/
MenuButton (StockID const& stock_id);
MenuButton (Gtk::StockID const& stock_id);
/**
* Creates a simple Push Button with label.
@ -67,7 +76,7 @@ namespace widget {
* @return Returns a reference to the menu that will be clicked on.
* This reference can be used to populate the menu with items.
*/
Menu& get_menu();
Gtk::Menu& get_menu();
/**
* Append a Menu Item to the Menu
@ -86,7 +95,7 @@ namespace widget {
* @param callback The signal handler when clicked
* @param toggle
*/
void append (const char *slug, const char* title, sigc::slot<void>& callback, bool toggle=false);
void append (const char* slug, const char* title, sigc::slot<void>& callback, bool toggle=false);
/** Append a Gtk::SeparatorMenuItem to the Menu */
@ -134,31 +143,6 @@ namespace widget {
* pushed in if it collides with the edge of the screen.
*/
void on_menu_position (int& x, int& y, bool& push_in);
private:
/** hBox for the layout of an image, caption and arrow. */
HBox hBox;
/** The image that will optionally display an icon. */
Image image;
/** caption text label to show on the button. */
Label caption;
/**
* The arrow widget that will be displayed to hint the user that this
* button is a drop-down.
*/
Arrow arrow;
/**
* The internal menu object which is the popup menu of this widget.
*/
Menu menu;
Glib::RefPtr<UIManager> uimanager;
Glib::RefPtr<ActionGroup> actions;
};

View file

@ -22,49 +22,53 @@
#include "stage/workspace/workspace-window.hpp"
#include "stage/workspace/panel-manager.hpp"
#include "stage/panel/panel.hpp"
#include "stage/draw/rectangle.hpp"
#include "stage/draw/cairo-util.hpp"
#include "include/logging.h"
#include <boost/foreach.hpp>
#include <algorithm>
using namespace Gtk; ////////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
using namespace Glib; ////////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
using namespace sigc; ////////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
using namespace std; ////////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
using namespace stage::workspace; //////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
namespace stage {
namespace widget {
using sigc::slot;
using sigc::bind;
using sigc::mem_fun;
using stage::workspace::PanelManager;
PanelBar::PanelBar (panel::Panel& owner_panel, const gchar *stock_id)
PanelBar::PanelBar (panel::Panel& owner_panel, gchar const*stock_id)
: Box()
, panel_(owner_panel)
, panelButton_(StockID(stock_id))
, panel_{owner_panel}
, panelButton_{Gtk::StockID(stock_id)} /////////////////////////////////////////////////////TICKET #1030 : Stock-Items must be replaced for GTK-4
, lockItem_(NULL)
{
set_border_width(1);
panelButton_.set_relief(RELIEF_NONE);
panelButton_.set_relief (Gtk::RELIEF_NONE);
panelButton_.set_can_focus(false);
panelButton_.show();
pack_start(panelButton_, PACK_SHRINK);
pack_start (panelButton_, Gtk::PACK_SHRINK);
setupPanelButton();
}
/**
* Sets up panelButton, populating it with menu items.
* @todo still not completely ported to GTK-3 and not used as of 5/2025 /////////////////////////////////TICKET #937 : complete Port to GTK-3
*/
void
PanelBar::setupPanelButton()
{
REQUIRE(lockItem_ == NULL);
REQUIRE (lockItem_ == NULL);
// Add items for each type of panel
for (int i = 0; i < PanelManager::getPanelDescriptionCount(); i++)
{
uString title = uString(PanelManager::getPanelTitle(i));
uString slug (title);
uString title{uString(PanelManager::getPanelTitle(i))};
uString slug {title};
/* Slug should be a char only string, no spaces, numbers, or
* symbols. Currently all panel titles are single words.
@ -76,14 +80,14 @@ namespace widget {
panelButton_.append (slug, title, func);
/** Keeping this snippet for easy reference
* list.push_back( Menu_Helpers::StockMenuElem(
* StockID(PanelManager::get_panel_stock_id(i)),
* bind(mem_fun(*this, &PanelBar::on_panel_type), i) ));
**/
/* Keeping this snippet for easy reference //////////////////////////////////////////TICKET #937 : complete Port to GTK-3
* list.push_back( Menu_Helpers::StockMenuElem(
* StockID(PanelManager::get_panel_stock_id(i)),
* bind(mem_fun(*this, &PanelBar::on_panel_type), i) ));
*/
}
#if false //////////////////////////////////////////////////////////////////TODO Port to GTK-3
#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #937 : complete Port to GTK-3
list.push_back( Menu_Helpers::SeparatorElem() );
#endif
@ -94,58 +98,38 @@ namespace widget {
slot<void> lock = mem_fun(*this, &PanelBar::on_lock);
panelButton_.append ("Lock", "_Lock", lock);
#if false //////////////////////////////////////////////////////////////////TODO Port to GTK-3
#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #937 : complete Port to GTK-3
lockItem_ = dynamic_cast<CheckMenuItem*>(&list.back());
ENSURE (lockItem_);
lockItem_->set_active (panel_.is_locked());
#endif
slot<void> hfunc = bind(mem_fun(*this, &PanelBar::on_split_panel),
ORIENTATION_HORIZONTAL);
slot<void> hfunc = bind (mem_fun(*this, &PanelBar::on_split_panel), Gtk::ORIENTATION_HORIZONTAL);
panelButton_.append("SplitHorizontal", "Split _Horizontal",hfunc);
slot<void> vfunc = bind(mem_fun(*this, &PanelBar::on_split_panel),
ORIENTATION_VERTICAL);
slot<void> vfunc = bind (mem_fun(*this, &PanelBar::on_split_panel), Gtk::ORIENTATION_VERTICAL);
panelButton_.append("SplitVertical", "Split _Vertical", vfunc);
}
/**
* An event handler for when a panel type is chosen.
* @param type_index index of the panel description that will be instantiated.
*/
void
PanelBar::on_panel_type (int type_index)
{
panel_.getPanelManager().switchPanel (panel_, type_index);
}
void
PanelBar::on_hide()
{
panel_.show(false);
}
void
PanelBar::on_lock()
{
REQUIRE(lockItem_);
static bool is_locking = false;
if (!is_locking)
{
is_locking = true;
const bool lock = !panel_.is_locked();
panel_.lock(lock);
lockItem_->set_active(lock);
is_locking = false;
}
}
/**
* Event handler for when the split panel menu item is clicked
* @param split_direction The direction to split in.
*/
void
PanelBar::on_split_panel (Gtk::Orientation split_direction)
{
@ -153,4 +137,24 @@ namespace widget {
}
/** An event handler for when the "Hide" menu item is clicked */
void
PanelBar::on_hide()
{
panel_.show(false);
}
/** Event handler for when the "Lock" menu item is clicked */
void
PanelBar::on_lock()
{
REQUIRE(lockItem_);
bool lockState{not panel_.is_locked()};
panel_.lock (lockState);
lockItem_->set_active(lockState);
}
}}// stage::widget

View file

@ -12,11 +12,11 @@
*/
/** @file panel-bar.hpp
** Custom container widget to allow placing toolbar buttons
** into the active docking header area of GDL docking panels.
** This arrangement allows us to save a significant amount
** of screen real estate
** Custom container widget to allow placing toolbar buttons into the active
** docking header area of GDL docking panels.
** @remark This arrangement allows us to save a significant amount of screen real estate.
**
** @todo still not completely ported to GTK-3 and not used as of 5/2025 /////////////////////////////////TICKET #937 : complete Port to GTK-3
*/
@ -24,10 +24,9 @@
#define STAGE_WIDGET_PANEL_BAR_H
#include "stage/gtk-base.hpp"
#include "stage/widget/menu-button.hpp"
#include <gtkmm.h>
namespace stage {
namespace panel {
@ -73,33 +72,13 @@ namespace stage {
private:
/**
* Sets up panelButton, populating it with menu items.
*/
void setupPanelButton();
/**
* An event handler for when a panel type is chosen.
* @param type_index index of the panel description that will be instantiated.
*/
void on_panel_type (int type_index);
/**
* An event handler for when the "Hide" menu item is clicked
*/
void on_hide();
/**
* Event handler for when the "Lock" menu item is clicked
*/
void on_lock();
/**
* Event handler for when the split panel menu item is clicked
* @param split_direction The direction to split in.
*/
void on_split_panel (Gtk::Orientation split_direction);
void on_hide() override;
void on_lock();
};

View file

@ -18,6 +18,13 @@
/** @file timecode-widget.cpp
** Widget for timecode display and input.
** Ported and adapted from the Ardour DAW
** @todo 2025 this code is here for later referral, but currently not used;
** a complete re-engineering is required to bring this code to current standards
** - magic constants all over the place
** - hard coded wiring instead of using an adapter layer
** - way to much pointer usage and pointer magic
** - direct handling of low-level keyboard events
** - repetitive code with switch-case fan
*/
@ -28,7 +35,7 @@
#include <boost/lexical_cast.hpp>
#include <cmath>
#include <stdint.h>
#include <cstdio> // for sprintf
#include <cstdio> // for sprintf //////////////TODO code smell /////////////////////////////////////////TICKET #750 : integrate Timecode formats
#include <cstdlib>
#include <locale>
#include <string>
@ -46,7 +53,8 @@ using std::string;
namespace stage {
namespace widget {
using namespace Gtk; ////////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
using sigc::bind;
using sigc::mem_fun;
// TODO: frame rate should not be a constant, but instead be per sequence
const float framerate = 25;
@ -227,7 +235,7 @@ namespace widget {
ms_seconds_ebox.set_can_focus(true);
auto connect_motion_event = [=] (EventBox& guiElm, Field fieldID)
auto connect_motion_event = [=](Gtk::EventBox& guiElm, Field fieldID)
{
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_motion_notify_event), fieldID);
guiElm.signal_motion_notify_event().connect (handlerSlot);
@ -245,7 +253,7 @@ namespace widget {
connect_motion_event (ms_seconds_ebox, MS_Seconds);
auto connect_button_press = [=] (EventBox& guiElm, Field fieldID)
auto connect_button_press = [=](Gtk::EventBox& guiElm, Field fieldID)
{
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_button_press_event), fieldID);
guiElm.signal_button_press_event().connect (handlerSlot);
@ -263,7 +271,7 @@ namespace widget {
connect_button_press (ms_seconds_ebox, MS_Seconds);
auto connect_button_release = [=] (EventBox& guiElm, Field fieldID)
auto connect_button_release = [=](Gtk::EventBox& guiElm, Field fieldID)
{
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_button_release_event), fieldID);
guiElm.signal_button_release_event().connect (handlerSlot);
@ -281,7 +289,7 @@ namespace widget {
connect_button_release (ms_seconds_ebox, MS_Seconds);
auto connect_scroll_event = [=] (EventBox& guiElm, Field fieldID)
auto connect_scroll_event = [=](Gtk::EventBox& guiElm, Field fieldID)
{
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_button_scroll_event), fieldID);
guiElm.signal_scroll_event().connect (handlerSlot);
@ -299,7 +307,7 @@ namespace widget {
connect_scroll_event (ms_seconds_ebox, MS_Seconds);
auto connect_key_press = [=] (EventBox& guiElm, Field fieldID)
auto connect_key_press = [=](Gtk::EventBox& guiElm, Field fieldID)
{
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_key_press_event), fieldID);
guiElm.signal_key_press_event().connect (handlerSlot);
@ -317,7 +325,7 @@ namespace widget {
connect_key_press (ms_seconds_ebox, MS_Seconds);
auto connect_key_release = [=] (EventBox& guiElm, Field fieldID)
auto connect_key_release = [=](Gtk::EventBox& guiElm, Field fieldID)
{
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_key_release_event), fieldID);
guiElm.signal_key_release_event().connect (handlerSlot);
@ -335,7 +343,7 @@ namespace widget {
connect_key_release (ms_seconds_ebox, MS_Seconds);
auto connect_focus_gain = [=] (EventBox& guiElm, Field fieldID)
auto connect_focus_gain = [=](Gtk::EventBox& guiElm, Field fieldID)
{
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_focus_gain_event), fieldID);
guiElm.signal_focus_in_event().connect (handlerSlot);
@ -353,7 +361,7 @@ namespace widget {
connect_focus_gain (ms_seconds_ebox, MS_Seconds);
auto connect_focus_loss = [=] (EventBox& guiElm, Field fieldID)
auto connect_focus_loss = [=](Gtk::EventBox& guiElm, Field fieldID)
{
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_focus_loss_event), fieldID);
guiElm.signal_focus_out_event().connect (handlerSlot);
@ -464,7 +472,7 @@ namespace widget {
if (force || hrs != ms_last_hrs)
{
sprintf(buf, "%02d", hrs);
sprintf(buf, "%02d", hrs); ///////////////////////////////////////////////////////////////////TICKET #750 : code smell, integrate Timecode formats
ms_hours_label.set_text(buf);
ms_last_hrs = hrs;
}
@ -574,7 +582,7 @@ namespace widget {
bool
TimeCode::field_key_release_event (GdkEventKey *ev, Field field)
{
Label *label = 0;
Gtk::Label* label = 0;
string new_text;
char new_char = 0;
bool move_on = false;

View file

@ -18,8 +18,18 @@
/** @file timecode-widget.hpp
** Widget for timecode display and input.
** Ported and adapted from the Ardour DAW.
** @todo needs extensive rework to get smooth integration
** @todo 2016 needs extensive rework to get smooth integration
** with Lumiera's timecode handling functions
** @todo 2023 this widget was used in the first GTK-2 based UI.
** While it still works with GTK-3, there are various fine points
** which you wouldn't do this way in a modern GTK UI, like directly
** checking for keyboard modifiers, or processing any kind of formatting
** directly in a event handler, instead of building a set of error-safe
** formatting helpers.
** @todo 2025 ...rather we should invest in generic sub-widgets, and try
** to build some generic pattern how to work with numeric values with
** high precision (e.g. interactive nudging and spinning with a _gear switch_).
** Bottom line: this code is currently unused and should be re-engineered.
*/
@ -29,12 +39,6 @@
#include "stage/gtk-base.hpp"
#include "lib/time/timevalue.hpp"
#include <gtkmm/box.h>
#include <gtkmm/menu.h>
#include <gtkmm/eventbox.h>
#include <gtkmm/label.h>
#include <gtkmm/frame.h>
#include <string>
@ -101,16 +105,16 @@ namespace widget {
// bool is_duration;
bool editable;
Gtk::Menu *ops_menu;
Gtk::Menu* ops_menu;
Gtk::HBox smpte_packer_hbox;
Gtk::HBox smpte_packer;
Gtk::HBox smpte_packer_hbox;
Gtk::HBox smpte_packer;
Gtk::HBox minsec_packer_hbox;
Gtk::HBox minsec_packer;
Gtk::HBox minsec_packer_hbox;
Gtk::HBox minsec_packer;
Gtk::HBox frames_packer_hbox;
Gtk::HBox frames_packer;
Gtk::HBox frames_packer_hbox;
Gtk::HBox frames_packer;
enum Field {
SMPTE_Hours,

View file

@ -15,7 +15,7 @@
/** @file timeline-zoom-scale.cpp
** Widget to control timeline zoom scale
** @warning as of 2016 the entire timeline display is planned to be reworked
** @todo this was the »zoom slider« implementation from the old GTK-2 GUI of Lumiera.
** @todo 2025 this was the »zoom slider« implementation from the old GTK-2 GUI of Lumiera.
** Since 2016, this was deactivated and since 3/23 it is no longer included anywhere,
** just left in tree to be re-integrated into the reworked GKT-3 Timeline UI
*/
@ -23,45 +23,34 @@
#include "stage/widget/timeline-zoom-scale.hpp"
using namespace Gtk; ///////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
namespace stage {
namespace widget {
class TimelineWidget;
namespace timeline {
/**
* @todo The initial adjustment value needs to
* match what the TimelineViewWindow's actual timeScale
* Value is. TimelineViewWindow::get_time_scale() is
* currently a public method, but will soon be private.
* Maybe TimelineViewWindow can have a zoom_adjustment
* that gets passed to this widget's Constructor?
*
* @todo actually there is a more involved problem.
* A widget to control the timeline zoom state.
* @todo 2023 / 2025 the remainder of the old GTK-2 Timeline UI was removed.
* @todo 2025 much is broken and unclear on a design level here...
* The TimelineWidget maintains a TimelineState, which in turn
* owns the TimelineViewWindow. Now, the problem is: when we
* switch to another Sequence (View), then this TimelineState
* gets switched too, causing also a entirely different TimelineViewWindow
* to become effective. Thus
* - how can we managed to be notified from that switch?
* - how can we manage to be notified from that switch?
* - problem is: TimelineZoomScale widget is owned by the TimelinePannel.
* Likewise, TimelineWidget is owned by the TimelinePannel. But the
* state handling/switching logic is embedded within TimelineWidget
* - and finally: how can we translate the actual scale (in time units),
* as maintained within TimelineViewWindow, back into the adjustment
* used here (which uses a relative scale 0...1.0 )
* S
*/
TimelineZoomScale::TimelineZoomScale()
: HBox()
, adjustment(Gtk::Adjustment::create(0.5, 0.0, 1.0, 0.000001))
, slider()
, zoomIn(Stock::ZOOM_IN)
, zoomOut(Stock::ZOOM_OUT)
, zoomIn(Gtk::Stock::ZOOM_IN)
, zoomOut(Gtk::Stock::ZOOM_OUT) /////////////////////////////////////////////////////////////TICKET #1030 StockItems are deprecated and will be removed with GTK-4
, button_step_size(0.03)
{
/* Setup the Slider Control */
@ -83,32 +72,26 @@ namespace timeline {
connect (sigc::mem_fun(this, &TimelineZoomScale::on_zoom));
/* Add Our Widgets and show them */
pack_start (zoomOut,PACK_SHRINK);
pack_start (slider,PACK_SHRINK);
pack_start (zoomIn,PACK_SHRINK);
pack_start (zoomOut,Gtk::PACK_SHRINK);
pack_start (slider, Gtk::PACK_SHRINK);
pack_start (zoomIn, Gtk::PACK_SHRINK);
show_all();
}
void
TimelineZoomScale::wireTimelineState (shared_ptr<TimelineState> currentState
// TimelineWidget::TimelineStateChangeSignal stateChangeSignal ////////////TODO defunct
)
TimelineZoomScale::wireTimelineState (/* TODO what to pass here? */) ////////////////////////////////////TICKET #1264 : how to integrate with the new GTK-3 timeline structure?
{
on_timeline_state_changed (currentState);
// stateChangeSignal.connect (
// sigc::mem_fun(this, &TimelineZoomScale::on_timeline_state_changed));
}
void
TimelineZoomScale::on_timeline_state_changed (shared_ptr<TimelineState> newState)
TimelineZoomScale::on_timeline_state_changed (/* TODO what to pass here? */)
{
REQUIRE (newState);
timelineState = newState;
// adjustment->set_value (getViewWindow().get_smoothed_time_scale());
// adjustment->set_value (/* TODO how to represent the statte? */);
}
@ -142,12 +125,4 @@ namespace timeline {
}
TimelineViewWindow&
TimelineZoomScale::getViewWindow()
{
REQUIRE (timelineState, "lifecycle error");
return timelineState->getViewWindow();
}
}}}// namespace stage::widget::timeline
}}// namespace stage::widget

View file

@ -15,7 +15,7 @@
/** @file timeline-zoom-scale.hpp
** Widget to control timeline zoom scale
** @warning as of 2016 the entire timeline display is planned to be reworked
** @todo this was the »zoom slider« implementation from the old GTK-2 GUI of Lumiera.
** @todo 2025 this was the »zoom slider« implementation from the old GTK-2 GUI of Lumiera.
** Since 2016, this was deactivated and since 3/23 it is no longer included anywhere,
** just left in tree to be re-integrated into the reworked GKT-3 Timeline UI
** ///////////////////////////////////////////////////////////////////////////TICKET #74 : Zoom Slider
@ -29,14 +29,10 @@
#include "stage/gtk-base.hpp"
#include "stage/widget/mini-button.hpp"
#include "stage/widget/timeline/timeline-state.hpp"
using namespace Gtk; ////////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
using namespace stage::widget; ///////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
namespace stage {
namespace widget {
namespace timeline {
class TimelineZoomScale
: public Gtk::HBox
@ -48,9 +44,7 @@ namespace timeline {
void set_value(double val) { adjustment->set_value(val); }
void wireTimelineState (shared_ptr<TimelineState> currentState
// ,TimelineWidget::TimelineStateChangeSignal /////////////////////////////////////TODO old GTK-2 UI is defunct (3/23)
);
void wireTimelineState (/* TODO what to pass here? */); /////////////////////////////////////////////TICKET #1264 : how to integrate with the new GTK-3 timeline structure?
@ -59,7 +53,7 @@ namespace timeline {
/**
* Update the slider position when the timeline state is changed.
*/
void on_timeline_state_changed (shared_ptr<TimelineState> newState);
void on_timeline_state_changed (/* TODO what to pass here? */);
/**
* Event handler for when the zoomIn Button is clicked
@ -76,9 +70,6 @@ namespace timeline {
*/
void on_zoom();
/** access current timeline state */
TimelineViewWindow& getViewWindow();
/* Widgets */
Glib::RefPtr<Gtk::Adjustment> adjustment;
Gtk::HScale slider;
@ -89,9 +80,8 @@ namespace timeline {
private:
sigc::signal<void, double> zoomSignal;
const double button_step_size;
shared_ptr<TimelineState> timelineState;
};
}}}// namespace stage::widget::timeline
}}// namespace stage::widget
#endif /*STAGE_WIDGET_TIMELINE_ZOOM_SCALE_H*/

View file

@ -1,3 +0,0 @@
WARNING: this package is an obsolete leftover from the old GTK-2 UI.
While some code is retained here for future reference at the moment,
the actual Timeline-UI now resides in stage::timeline (as of 2/23)

View file

@ -1,144 +0,0 @@
/*
TimelineState - timeline presentation state holder
Copyright (C)
2008, Joel Holdsworth <joel@airwebreathe.org.uk>
  **Lumiera** 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. See the file COPYING for further details.
* *****************************************************************/
/** @file timeline-state.cpp
** Implementation of presentation state for the first draft of the timeline display.
** @warning as of 2016 the entire timeline display is planned to be reworked
** @deprecated this is defunct code, left over from the old GTK-2 GUI of Lumiera.
** Deactivated since 2016 and no longer included since 3/23 but left in tree
** for later reference
*/
#include "stage/widget/timeline/timeline-state.hpp"
#include "lib/time/timevalue.hpp"
#include "lib/time/mutation.hpp"
#include "lib/time/control.hpp"
using namespace Gtk; ///////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
using namespace sigc; ///////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
namespace stage {
namespace widget {
namespace timeline {
using lib::time::FSecs;
using lib::time::Offset;
using lib::time::Duration;
using lib::time::Mutation;
using lib::time::Control;
using std::shared_ptr;
TimelineState::TimelineState (shared_ptr<model::Sequence> sourceSequence)
: sequence_(sourceSequence)
, viewWindow_(Offset(Time::ZERO), 1)
, selection_(Time::ZERO, Duration::NIL)
, selectionListener_()
, playbackPeriod_(Time::ZERO, Duration::NIL)
, playbackPoint_(Time::ZERO)
, isPlayback_(false)
{
REQUIRE(sequence_);
// Initialise the selection listener
selectionListener_ (TimeSpan (Time::ZERO, Duration::NIL));
selectionListener_.connect(
mem_fun(*this, &TimelineState::on_selection_changed));
////////////////////////////////////////////////////////////TICKET #798: how to handle GUI default state
const int64_t DEFAULT_TIMELINE_SCALE =6400;
NOTREACHED ("3/23: this code is dead and left in-tree for later reference only");
// viewWindow_.set_time_scale(DEFAULT_TIMELINE_SCALE);
setSelection (Mutation::changeTime (Time(FSecs(2))));
setSelection (Mutation::changeDuration (Duration(FSecs(2))));
//////////////////////////////////////////////////////TICKET #797 : this looks cheesy. Should provide a single Mutation to change all
}
shared_ptr<model::Sequence>
TimelineState::getSequence() const
{
return sequence_;
}
TimelineViewWindow&
TimelineState::getViewWindow()
{
return viewWindow_;
}
void
TimelineState::setSelection (Mutation const& change,
bool resetPlaybackPeriod)
{
selection_.accept (change);
if (resetPlaybackPeriod)
setPlaybackPeriod(change);
selectionChangedSignal_.emit();
}
void
TimelineState::setPlaybackPeriod (Mutation const& change)
{
playbackPeriod_.accept (change);
playbackChangedSignal_.emit();
}
void
TimelineState::setPlaybackPoint (Time newPosition)
{
playbackPoint_ = newPosition;
playbackChangedSignal_.emit();
}
void
TimelineState::setSelectionControl (SelectionControl &control)
{
control.disconnect();
selection_.accept (control);
control.connectChangeNotification (selectionListener_);
}
sigc::signal<void>
TimelineState::selectionChangedSignal() const
{
return selectionChangedSignal_;
}
sigc::signal<void>
TimelineState::playbackChangedSignal() const
{
return playbackChangedSignal_;
}
void
TimelineState::on_selection_changed (TimeSpan)
{
selectionChangedSignal_.emit();
}
}}}// namespace stage::widget::timeline

View file

@ -1,240 +0,0 @@
/*
TIMELINE-STATE.hpp - timeline presentation state holder
Copyright (C)
2008, Joel Holdsworth <joel@airwebreathe.org.uk>
  **Lumiera** 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. See the file COPYING for further details.
*/
/** @file timeline-state.hpp
** Presentation state for the first draft of the timeline display. Very likely
** to be replaced by a complete rewrite.
** @warning as of 2016 the entire timeline display is planned to be reworked
** @deprecated this is defunct code, left over from the old GTK-2 GUI of Lumiera.
** Deactivated since 2016 and no longer included since 3/23 but left in tree
** for later reference
*/
#ifndef STAGE_WIDGET_TIMELINE_STATE_H
#define STAGE_WIDGET_TIMELINE_STATE_H
#include "stage/gtk-base.hpp"
//#include "stage/widget/timeline/timeline-view-window.hpp"////////////////////////////TODO : obsolete and removed 3/23
#include "lib/time/timevalue.hpp"
#include "lib/time/mutation.hpp"
#include "lib/time/control.hpp"
#include <memory>
namespace stage {
namespace model {
class Sequence;
}
namespace widget {
namespace timeline {
using lib::time::Time;
using lib::time::Offset;
using lib::time::TimeVar;
using lib::time::TimeSpan;
using lib::time::TimeValue;
using lib::time::Mutation;
using lib::time::Control;
using std::shared_ptr;
typedef Control<TimeSpan> SelectionControl;
///////////////////////////////////////////////////////////////////////////////////////TODO : dummy placeholder to keep the code in-tree (for later reference)
class TimelineViewWindow
{
public:
TimelineViewWindow (Offset offset, int64_t scale)
{
NOTREACHED ("3/23: this code is dead and left in-tree for later reference only");
}
};
///////////////////////////////////////////////////////////////////////////////////////TODO : dummy placeholder to keep the code in-tree (for later reference)
/**
* SelectionListener is a template class which emits a signal when
* the value is changed by it's associated time::Control object.
* SelectionListener wraps a sigc::signal that emits every time
* the selection is changed by the time::Control object.
* SelectionListener does NOT emit the signal if a change to the
* selection is made outside of the Control/Listener partnership.
*/
template<class TI>
class SelectionListener
: util::NonCopyable
{
sigc::signal<void, TI> valueChangedSignal_;
public:
SelectionListener() { }
void
operator() (TI const& changeValue) const
{
valueChangedSignal_.emit (changeValue);
}
void connect (const sigc::slot<void, TI> &connection)
{
valueChangedSignal_.connect (connection);
}
};
/**
* TimelineState is a container for the state data for TimelineWidget.
* @remarks TimelineStates can be swapped out so that TimelineWidget
* can flip between different views.
*/
class TimelineState
{
public:
/**
* @param source_sequence The sequence on which the TimelineWidget
* will operate when this TimelineState is attached.
*/
TimelineState (shared_ptr<model::Sequence> sourceSequence);
public:
/**
* Gets the sequence that is attached to this timeline state object.
* @return Returns a shared_ptr to the sequence object.
*/
shared_ptr<model::Sequence> getSequence() const;
/**
* Gets a reference to the timeline view window object.
* @return Returns the timeline view window object.
*/
timeline::TimelineViewWindow& getViewWindow();
SelectionListener<TimeSpan>&
getSelectionListener() { return selectionListener_; }
Time getSelectionStart() const { return selection_.start();}
Time getSelectionEnd() const { return selection_.end(); }
Time getPlaybackPeriodStart() const { return selection_.start();}
Time getPlaybackPeriodEnd() const { return selection_.end(); }
Time getPlaybackPoint() const { return playbackPoint_; }
/** is there currently any ongoing playback process?
* Otherwise the #getPlaybackPoint() is meaningless */
bool isPlaying() const { return isPlayback_; }
void setSelectionControl (SelectionControl &control);
/**
* Sets the period of the selection.
* @param resetPlaybackPeriod Specifies whether to set the
* playback period to the same as this new selection.
*/
void setSelection(Mutation const& change,
bool resetPlaybackPeriod = true);
void setPlaybackPeriod(Mutation const& change);
/**
* Sets the time which is currently being played back.
* @param point The time index being played.
* @todo do we ever get the situation that we don't have such a position?
* @todo very likely to be handled differently, once
* the GUI is really connected to the Player
*/
void setPlaybackPoint(Time newPos);
/**
* A signal to notify when the selected period has changed.
*/
sigc::signal<void> selectionChangedSignal() const;
/**
* A signal to notify when the playback point or playback periods have
* changed.
*/
sigc::signal<void> playbackChangedSignal() const;
private: /* ========= Event Handlers ========== */
/**
* Event handler for when the selection is changed
*/
void on_selection_changed (TimeSpan selection);
private:
/**
* A pointer to the sequence object which this timeline_widget will represent.
* @remarks This pointer is set by the constructor and is constant, so
* will not change in value during the lifetime of the class.
*/
shared_ptr<model::Sequence> sequence_;
/* == View State == */
/** ViewWindow for the TimelineWidget display */
timeline::TimelineViewWindow viewWindow_;
/* == Selection State == */
/** currently selected time period. */
TimeSpan selection_;
/** listens for a selection change */
SelectionListener<TimeSpan> selectionListener_;
/** current playback period. */
TimeSpan playbackPeriod_;
/** current playback position.
* @todo very likely to be handled differently
* when actually integrated with the Player
*/
TimeVar playbackPoint_;
bool isPlayback_;
/* == Signals == */
/**
* A signal to notify when the selected period has changed.
*/
sigc::signal<void> selectionChangedSignal_;
/**
* A signal to notify when the playback point or playback periods have
* changed.
*/
sigc::signal<void> playbackChangedSignal_;
};
}}}// namespace stage::widget::timeline
#endif /*STAGE_WIDGET_TIMELINE_STATE_H*/

View file

@ -34027,6 +34027,23 @@
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1540639291974" ID="ID_1116103118" MODIFIED="1557498707231" TEXT="Zoom">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1747343336875" ID="ID_380679673" MODIFIED="1747343338533" TEXT="Stand">
<node COLOR="#338800" CREATED="1664058686704" ID="ID_446702745" MODIFIED="1747343364970" TEXT="Basis-Technologie gebaut (ZoomWindow)">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1747343351160" ID="ID_378138637" MODIFIED="1747343420890" TEXT="Integration in das Timeline-UI noch offen">
<arrowlink COLOR="#985f78" DESTINATION="ID_1763437884" ENDARROW="Default" ENDINCLINATION="-1406;-260;" ID="Arrow_ID_297087748" STARTARROW="None" STARTINCLINATION="1272;87;"/>
<icon BUILTIN="hourglass"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1747342638800" ID="ID_616947134" MODIFIED="1747342674483" TEXT="transient-State">
<icon BUILTIN="hourglass"/>
<node CREATED="1747342682778" ID="ID_1446567013" MODIFIED="1747342827585" TEXT="playback position">
<linktarget COLOR="#7f6a74" DESTINATION="ID_1446567013" ENDARROW="Default" ENDINCLINATION="-1578;239;" ID="Arrow_ID_590507558" SOURCE="ID_883853531" STARTARROW="None" STARTINCLINATION="-2460;177;"/>
</node>
<node CREATED="1747342675856" ID="ID_1692322588" MODIFIED="1747342832761" TEXT="time-range selection"/>
<node CREATED="1747342687204" ID="ID_1566825368" MODIFIED="1747342709625" TEXT="expand / collapse"/>
</node>
</node>
<node CREATED="1540638842100" ID="ID_202893866" MODIFIED="1557498707231" TEXT="Track...">
@ -35102,9 +35119,39 @@
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1680564423273" ID="ID_7752918" MODIFIED="1680567145813" TEXT="Video-Display-GUI">
<linktarget COLOR="#f6e1c2" DESTINATION="ID_7752918" ENDARROW="Default" ENDINCLINATION="-612;79;" ID="Arrow_ID_1986887171" SOURCE="ID_1435039515" STARTARROW="None" STARTINCLINATION="-2008;-180;"/>
<icon BUILTIN="flag-yellow"/>
<node CREATED="1747342339657" ID="ID_84701526" MODIFIED="1747342345274" TEXT="bisheriger Stand">
<icon BUILTIN="info"/>
<node CREATED="1747342347190" ID="ID_1130003899" MODIFIED="1747342361984" TEXT="ca 2011 gab es die Architektur-Studie zum Dummy-Player"/>
<node CREATED="1746059132520" ID="ID_150758489" MODIFIED="1747342439335" TEXT="5/2025 habe ich das Video-Display-Widget neu mit GTK-3 aufgebaut">
<arrowlink COLOR="#fdebca" DESTINATION="ID_1819581335" ENDARROW="Default" ENDINCLINATION="-2783;152;" ID="Arrow_ID_421873944" STARTARROW="None" STARTINCLINATION="1417;60;"/>
<node CREATED="1747342457463" ID="ID_937824500" MODIFIED="1747342523372" TEXT="vor allem als Basis zur Unsteruschung von Display-Technologien">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...mit dem Ergebnis
</p>
<ul>
<li>
die XV-Videowidergabe funktioniert immer noch
</li>
<li>
eine einfache Bitmap-basierte Anzeige kann leicht mit Gtk::Image + Gdk::Pixbuf realisiert werden (aber Vorsicht, Pixpuf ist @deprecated)
</li>
</ul>
</body>
</html></richcontent>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1680567169798" ID="ID_1105975184" MODIFIED="1680567175175" TEXT="Play-control">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1747342874978" ID="ID_286658301" MODIFIED="1747343152973" TEXT="neues Panel angelegt (5/2025)">
<arrowlink COLOR="#6f7781" DESTINATION="ID_944511675" ENDARROW="Default" ENDINCLINATION="219;-670;" ID="Arrow_ID_1473472749" STARTARROW="None" STARTINCLINATION="1035;96;"/>
<node CREATED="1747343048767" ID="ID_1933627478" MODIFIED="1747343065384" TEXT="zun&#xe4;chst im alten Schma: eine fest-Verdrahtete neue &#xbb;Gattung&#xab;"/>
<node CREATED="1747343081307" HGAP="34" ID="ID_1956938900" MODIFIED="1747343105355" TEXT="aber hat nun ein sch&#xf6;nes neues Icon &#x2014; und einen Platz im standard-Layout" VSHIFT="-15"/>
</node>
</node>
</node>
<node CREATED="1680567033328" ID="ID_60631732" MODIFIED="1680567036668" TEXT="Infrastruktur">
@ -44266,7 +44313,9 @@
<icon BUILTIN="flag-yellow"/>
<node CREATED="1672883774136" HGAP="85" ID="ID_135908111" MODIFIED="1672883794675" TEXT="anzubinden" VSHIFT="21">
<edge COLOR="#976c6c"/>
<node CREATED="1672883797610" ID="ID_1763437884" MODIFIED="1672883807253" TEXT="Canvas-Scrollbar"/>
<node CREATED="1672883797610" ID="ID_1763437884" MODIFIED="1747343420890" TEXT="Canvas-Scrollbar">
<linktarget COLOR="#985f78" DESTINATION="ID_1763437884" ENDARROW="Default" ENDINCLINATION="-1406;-260;" ID="Arrow_ID_297087748" SOURCE="ID_378138637" STARTARROW="None" STARTINCLINATION="1272;87;"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1667488193842" ID="ID_1347640673" MODIFIED="1667488208549" TEXT="Invarianten">
@ -129648,8 +129697,9 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1746196449003" ID="ID_1070775068" MODIFIED="1746196453932" TEXT="Video-Display">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1746196482500" ID="ID_1819581335" LINK="https://issues.lumiera.org/ticket/1403" MODIFIED="1747012983605" TEXT=" #1403 Invesitgate if XV displayer can be revived ">
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1746196482500" ID="ID_1819581335" LINK="https://issues.lumiera.org/ticket/1403" MODIFIED="1747342428317" TEXT=" #1403 Invesitgate if XV displayer can be revived ">
<linktarget COLOR="#fefeb4" DESTINATION="ID_1819581335" ENDARROW="Default" ENDINCLINATION="-2783;152;" ID="Arrow_ID_1160980366" SOURCE="ID_1219347509" STARTARROW="None" STARTINCLINATION="-4870;297;"/>
<linktarget COLOR="#fdebca" DESTINATION="ID_1819581335" ENDARROW="Default" ENDINCLINATION="-2783;152;" ID="Arrow_ID_421873944" SOURCE="ID_150758489" STARTARROW="None" STARTINCLINATION="1417;60;"/>
<icon BUILTIN="hourglass"/>
<node COLOR="#338800" CREATED="1746196518190" ID="ID_411481779" MODIFIED="1747013174739" TEXT="Research-Setup">
<icon BUILTIN="button_ok"/>
@ -129812,7 +129862,8 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</node>
<node CREATED="1746366566357" ID="ID_669235936" MODIFIED="1746366588141" TEXT="geplant war aber ein Play-Control-Widget"/>
</node>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1746366589535" FOLDED="true" ID="ID_944511675" MODIFIED="1747013218559" TEXT="also ein neues Docking-Panel schaffen">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1746366589535" FOLDED="true" ID="ID_944511675" MODIFIED="1747343152973" TEXT="also ein neues Docking-Panel schaffen">
<linktarget COLOR="#6f7781" DESTINATION="ID_944511675" ENDARROW="Default" ENDINCLINATION="219;-670;" ID="Arrow_ID_1473472749" SOURCE="ID_286658301" STARTARROW="None" STARTINCLINATION="1035;96;"/>
<icon BUILTIN="yes"/>
<node CREATED="1746366642490" ID="ID_997232477" MODIFIED="1746366650524" TEXT="bekommt in erster N&#xe4;herung die Buttons direkt"/>
<node CREATED="1746366651348" ID="ID_1947097226" MODIFIED="1746366715461" TEXT="soll sp&#xe4;ter mal auch den Timecode darstellen"/>
@ -162288,8 +162339,8 @@ Since then others have made contributions, see the log for the history.</font></
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1742175611912" ID="ID_16098937" MODIFIED="1742175617591" TEXT="etwas aufr&#xe4;umen">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1742175611912" ID="ID_16098937" MODIFIED="1747359127313" TEXT="etwas aufr&#xe4;umen">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1742175621250" FOLDED="true" ID="ID_1886919024" MODIFIED="1745860228467" TEXT="boost-filesystem loswerden!">
<icon BUILTIN="button_ok"/>
<node CREATED="1744754918427" ID="ID_368377472" MODIFIED="1745799970522" TEXT="lib/searchpath.hpp">
@ -162368,8 +162419,8 @@ Since then others have made contributions, see the log for the history.</font></
<arrowlink DESTINATION="ID_368377472" ENDARROW="Default" ENDINCLINATION="107;14;" ID="Arrow_ID_1432393919" STARTARROW="None" STARTINCLINATION="74;7;"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1742175872016" ID="ID_1131308211" MODIFIED="1742175881001" TEXT="Untersuchung: einfacher XV-Displayer">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1742175872016" ID="ID_1131308211" MODIFIED="1747359118365" TEXT="Untersuchung: einfacher XV-Displayer">
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1742175882083" ID="ID_846823682" MODIFIED="1745783296480" TEXT="Christian hatte uns im Chat einen Tip gegeben">
<richcontent TYPE="NOTE"><html>
<head>
@ -162530,7 +162581,8 @@ Since then others have made contributions, see the log for the history.</font></
</node>
</node>
</node>
<node CREATED="1746058970157" ID="ID_991442275" MODIFIED="1746058986973" TEXT="Einsch&#xe4;tzung: aktueller Stand">
<node COLOR="#338800" CREATED="1746058970157" FOLDED="true" ID="ID_991442275" MODIFIED="1747359114488" TEXT="Einsch&#xe4;tzung: aktueller Stand">
<icon BUILTIN="back"/>
<node CREATED="1746058988279" ID="ID_1992351880" MODIFIED="1746059009850">
<richcontent TYPE="NODE"><html>
<head/>
@ -162599,15 +162651,139 @@ Since then others have made contributions, see the log for the history.</font></
<node COLOR="#338800" CREATED="1746059663185" ID="ID_473345546" MODIFIED="1747182536693" TEXT="kann der ganze DummyPlayer entfernt werden">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1746059700212" ID="ID_191158269" MODIFIED="1746059710934" TEXT="k&#xf6;nnte auch gleich die alte Timeline mit entfernt werden"/>
<node COLOR="#2a7a90" CREATED="1746059700212" ID="ID_191158269" MODIFIED="1747358935400" TEXT="k&#xf6;nnte auch gleich die alte Timeline mit entfernt werden">
<arrowlink COLOR="#4b94c0" DESTINATION="ID_877133844" ENDARROW="Default" ENDINCLINATION="89;5;" ID="Arrow_ID_1014835150" STARTARROW="None" STARTINCLINATION="89;60;"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#4f171a" CREATED="1747358961060" ID="ID_1229619846" MODIFIED="1747359100154" TEXT="Fazit">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node COLOR="#435e98" CREATED="1747358965085" ID="ID_1159622561" MODIFIED="1747359106297" TEXT="der alte XV-Code konnte wieder zum Laufen gebracht werden"/>
<node COLOR="#435e98" CREATED="1747358980695" ID="ID_1228763349" MODIFIED="1747359106297" TEXT="neuer Bitmap-basierter (fallback)-Displayer dazugebaut"/>
<node BACKGROUND_COLOR="#d3b2a9" COLOR="#5c4d6e" CREATED="1747358995044" ID="ID_1689326228" MODIFIED="1747359081222" TEXT="offen: Handhabung und Eigenschaften von XVideo besser verstehen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
vor allem...
</p>
<ul>
<li>
wie man tats&#228;chlich einen Darstellungsvorgang erzwingt
</li>
<li>
wie das Compositing mit dem Window-Manager integriert wird
</li>
</ul>
</body>
</html></richcontent>
<icon BUILTIN="bell"/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1742176004434" ID="ID_393175435" MODIFIED="1747355570776" TEXT="Reste vom GTK-2-GUI zur&#xfc;ckbauen">
<icon BUILTIN="button_ok"/>
<node COLOR="#984373" CREATED="1746059790896" ID="ID_1458700110" MODIFIED="1747358892480" TEXT="macht den GUI-Code verst&#xe4;ndlicher...">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node>
<node BACKGROUND_COLOR="#b8b6c8" COLOR="#1f2d48" CREATED="1746059809402" ID="ID_252295365" MODIFIED="1747347298791" TEXT="man k&#xf6;nnte auch den DummyPlayer loswerden">
<icon BUILTIN="yes"/>
<node COLOR="#435e98" CREATED="1747355601697" ID="ID_1016070090" MODIFIED="1747355611437" TEXT="ges&#xe4;gt">
<font NAME="SansSerif" SIZE="10"/>
</node>
<node COLOR="#435e98" CREATED="1747355604293" ID="ID_650581088" MODIFIED="1747355611456" TEXT="getan">
<font NAME="SansSerif" SIZE="10"/>
</node>
</node>
<node COLOR="#338800" CREATED="1747318813636" ID="ID_770178888" MODIFIED="1747347203040" TEXT="und die alte GTK-2 timeline">
<icon BUILTIN="yes"/>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1747347206016" ID="ID_877133844" MODIFIED="1747358919513" TEXT="hab 2023 bereits den gr&#xf6;&#xdf;ten Teil wegger&#xe4;umt">
<linktarget COLOR="#4b94c0" DESTINATION="ID_877133844" ENDARROW="Default" ENDINCLINATION="89;5;" ID="Arrow_ID_1014835150" SOURCE="ID_191158269" STARTARROW="None" STARTINCLINATION="89;60;"/>
<icon BUILTIN="idea"/>
</node>
<node COLOR="#435e98" CREATED="1747318826981" ID="ID_349873328" MODIFIED="1747347192250" TEXT="stage/widget/timeline"/>
<node COLOR="#435e98" CREATED="1747341331057" ID="ID_511983400" MODIFIED="1747347193958" TEXT="timeline-state">
<node CREATED="1747341338630" ID="ID_375326380" MODIFIED="1747341345815" TEXT="kann keinen Wert mehr erkennen"/>
<node CREATED="1747341347546" ID="ID_1556587592" MODIFIED="1747341364104" TEXT="GUI-Signal basierte Zustandsbehandlung"/>
<node CREATED="1747341391949" ID="ID_883853531" MODIFIED="1747342827585" TEXT="festzuhalten ist die strukturelle Idee">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
man hat ein time::Control (was auch immer das in Zukunft sein wird), welches mit einem Change-Signal verbunden wird. GUI-seitig verdrahtet man dieses Signal mit dem Code, der die tats&#228;chliche &#196;nderung des Presentation-State macht
</p>
</body>
</html>
</richcontent>
<arrowlink COLOR="#7f6a74" DESTINATION="ID_1446567013" ENDARROW="Default" ENDINCLINATION="-1578;239;" ID="Arrow_ID_590507558" STARTARROW="None" STARTINCLINATION="-2460;177;"/>
</node>
</node>
<node COLOR="#435e98" CREATED="1747347046661" ID="ID_1909627824" MODIFIED="1747347195079" TEXT="timeline-zoom-state">
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1747347052683" ID="ID_1909321007" MODIFIED="1747347075291" TEXT="umwandeln in reines Widget">
<icon BUILTIN="yes"/>
<icon BUILTIN="hourglass"/>
</node>
<node COLOR="#338800" CREATED="1747347058492" ID="ID_1243897701" MODIFIED="1747347069374" TEXT="zun&#xe4;chst einmal: Rest-Funktionalit&#xe4;t entfernt">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1747320207459" ID="ID_1787845536" MODIFIED="1747355564742" TEXT="nebenbei">
<icon BUILTIN="idea"/>
<node COLOR="#338800" CREATED="1747320211058" ID="ID_1715404862" MODIFIED="1747351629662" TEXT="stage/draw/cairo-util">
<icon BUILTIN="button_ok"/>
<node CREATED="1747320223361" ID="ID_1728274505" MODIFIED="1747320227360" TEXT="derzeit nicht verwendet"/>
<node COLOR="#338800" CREATED="1747320251388" ID="ID_1709983182" MODIFIED="1747351626034" TEXT="in einen Utility-Header verwandeln">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#338800" CREATED="1747322279220" ID="ID_105159102" MODIFIED="1747351621473" TEXT="stage/draw/rectangle dort integrieren">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1747322262618" ID="ID_123316480" MODIFIED="1747351634158" TEXT="stage/widget/panel-bar.hpp">
<icon BUILTIN="button_ok"/>
<node CREATED="1747322269934" ID="ID_436403941" MODIFIED="1747322272308" TEXT="aufr&#xe4;umen"/>
<node CREATED="1747324058600" ID="ID_1325990171" MODIFIED="1747324066006" TEXT="dto menu-button.hpp"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#990009" CREATED="1747324088506" ID="ID_1073724702" MODIFIED="1747355543340" TEXT="timecode-widget : mal anschauen">
<icon BUILTIN="smiley-oh"/>
<node CREATED="1747355253615" ID="ID_1827502464" MODIFIED="1747355271723">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
ja ... der code ist <i>anr&#252;chig</i>
</p>
</body>
</html></richcontent>
<icon BUILTIN="smily_bad"/>
</node>
<node CREATED="1747355297554" ID="ID_120093101" MODIFIED="1747355526952" TEXT="jede Menge Anti-Patterns, eigentlich kein Gewinn">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Urspr&#252;nglich war das mal so eine Idee von Code-Reuse. Klingt plausibel, schlie&#223;lich hat Ardour einen guten Ruf....
</p>
<p>
Bei genauerer Betrachtung allerdings zeigt sich, da&#223; die Qualit&#228;t von Ardour auf einer sehr gr&#252;ndlichen QA beruht, ein anderes Projekt (wie Lumiera) aber nicht davon profitieren kann, denn der Code enth&#228;lt keine besonderen strukturell gefa&#223;ten Einsichten; ganz im Gegenteil, man w&#252;rde sich eine Menge ungesunder Strukturmuster einhandeln, wenn man an solchen Code <i>anbauen w&#252;rde. </i>
</p>
<p>
</p>
<p>
Abgesehen davon ist der Code inzwischen auch technologisch &#252;berholt und wird mit GTK-4 nicht mehr funktionieren
</p>
</body>
</html>
</richcontent>
</node>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1747355273449" ID="ID_1703747958" MODIFIED="1747355286397" TEXT="ehrlich gesagt: wegwerfen und neuschreiben">
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1742176004434" ID="ID_393175435" MODIFIED="1746059770010" TEXT="Reste vom GTK-2-GUI zur&#xfc;ckbauen">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1746059790896" ID="ID_1458700110" MODIFIED="1746059808265" TEXT="macht den GUI-Code verst&#xe4;ndlicher"/>
<node CREATED="1746059809402" ID="ID_252295365" MODIFIED="1746059816488" TEXT="man k&#xf6;nnte auch den DummyPlayer loswerden"/>
<node CREATED="1746059817267" ID="ID_1413142939" MODIFIED="1746059824776" TEXT="und einige daran h&#xe4;ngende Library-Helper"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1742249461535" ID="ID_1554376708" MODIFIED="1742256553530" TEXT="Rolle der lib-Gavl &#xfc;berpr&#xfc;fen">
<linktarget COLOR="#a41b18" DESTINATION="ID_1554376708" ENDARROW="Default" ENDINCLINATION="440;-36;" ID="Arrow_ID_608156847" SOURCE="ID_1683248748" STARTARROW="None" STARTINCLINATION="193;12;"/>