XV-Display: establish wiring for the controller and verify logic

Here we face the problem that the buttons in the play control panel
need to be connected to the controller, which sits in the viewer panel.

Obviously a direct connection is not correct, since there could be
several panels, and furthermore the controller should be a service and
addressed by commands via UI-Bus.

But this is an experiment, and we'll have to figure out anyway
how the playback-display-connection works, as one of the next tasks
for the »Playback Vertical Slice«

Thus we'll use the PanelManager to fetch the first viewer panel,
and then forward to the controller calls. With this setup,
the controller logic can be verified by printing to STDOUT.

TODO: we are not yet invoking any XVideo code....
This commit is contained in:
Fischlurch 2025-05-06 03:54:03 +02:00
parent b0e8fa2ff6
commit 02ac4a169b
8 changed files with 175 additions and 43 deletions

View file

@ -140,7 +140,7 @@ namespace interact {
return injectTimeline (spec);
}))
.mutateAttrib(ATTR_fork, [&](TreeMutator::Handle buff)
{ // »Attribute Mutator« : how enter an object field as nested scope
{ // »Attribute Mutator« : how to enter an object field as nested scope
REQUIRE (assets_);
assets_->buildMutator(buff);
}));

View file

@ -110,7 +110,7 @@ namespace model {
* UI-Coordinates. Rather we have to deal with a small set of possible base interfaces,
* and thus the actual [access function](\ref #performAccessTo) returns a _variant record_
* holding a pointer, and internally tagged with the base interface type to apply. Now the
* public API functions are templated to the _result type as expected by the invoking clinent_
* public API functions are templated to the _result type as expected by the invoking client_
* and thus we get a matrix of possible cases; when the expected result type is _reachable by
* dynamic downcast_ from the actual base interface type returned by the internal access function,
* we can perform this `dynamic_cast`. Otherwise the returned result proxy object is marked as empty.

View file

@ -1,8 +1,8 @@
/*
PlayPanel - Dockable panel to hold the video display widgets and controls
PlayPanel - Dockable panel to hold the play control and switchboard
Copyright (C)
2008, Joel Holdsworth <joel@airwebreathe.org.uk>
2025, Hermann Vosseler <Ichthyostega@web.de>
  **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
@ -14,31 +14,41 @@
/** @file play-panel.cpp
** Implementation of a dockable panel for player control and timecode display
**
** @todo 5/2025 This is an experiment or demo to find out if our XV-Widget is still usable.
** The actual solution obviously should not use a direct wired connection to the ViewerPanel,
** but rather communicate with the »Player« subsystem down in Steam-Layer
** ///////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1403 : try to port XvDisplayer to GTK-3
*/
#include "stage/gtk-base.hpp"
#include "stage/panel/play-panel.hpp"
#include "stage/panel/viewer-panel.hpp"
#include "stage/workspace/workspace-window.hpp"
#include "stage/ui-bus.hpp" ///////////////////////////////////TODO why are we forced to include this after workspace-window.hpp ?? Ambiguity between std::ref and boost::reference_wrapper
#include "stage/display-service.hpp"
using namespace Gtk; ///////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
using namespace stage::widget; ///////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
using namespace stage::controller; ///////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
namespace stage {
namespace panel {
using Gtk::StockID;
using sigc::mem_fun;
PlayPanel::PlayPanel (workspace::PanelManager& panelManager
,Gdl::DockItem& dockItem)
,Gdl::DockItem& dockItem)
: Panel{panelManager, dockItem, getTitle(), getStockID()}
, display_{}
, demoPlayback_{[this](void * const buffer){ display_.pushFrame(buffer); }}
, buttons_{}
, buttonStop_{StockID(GTK_STOCK_MEDIA_STOP)}
, buttonPlay_{StockID(GTK_STOCK_MEDIA_PLAY)}
, buttonPause_{StockID(GTK_STOCK_MEDIA_PAUSE)} ////////////////////////TICKET #1030 : Stock-items are deprecated and will be removed with GTK-4
{
//----- Pack in the Widgets -----//
pack_start(display_, PACK_EXPAND_WIDGET);
buttons_.append (buttonPlay_, mem_fun(*this, &PlayPanel::dispatchPlay));
buttons_.append (buttonPause_, mem_fun(*this, &PlayPanel::dispatchPause));
buttons_.append (buttonStop_, mem_fun(*this, &PlayPanel::dispatchStop));
pack_start(buttons_, Gtk::PACK_SHRINK);
}
const char*
@ -54,4 +64,47 @@ namespace panel {
}
/* === create an internal wiring to the Controller === */
// Preliminary workaround -- use a shortcut /////////////////////////////////////////////////////TICKET #1105 : need a generic scheme to access UI components
// Directly grab into the first ViewerPanel we can get hold off
// The real solution should use the UI-Bus!
PlayPanel::ViewLink&
PlayPanel::accessViewer()
{
if (not viewer_)
{
int panelID = workspace::PanelManager::findPanelID<ViewerPanel>();
if (panelManager_.hasPanel (panelID))
viewer_.connect (dynamic_cast<ViewerPanel&> (panelManager_.showPanel (panelID)));
}
return viewer_;
}
void
PlayPanel::dispatchStop()
{
auto& view{accessViewer()};
if (view)
view->demoPlayback_.stop();
}
void
PlayPanel::dispatchPlay()
{
auto& view{accessViewer()};
if (view)
view->demoPlayback_.play();
}
void
PlayPanel::dispatchPause()
{
auto& view{accessViewer()};
if (view)
view->demoPlayback_.pause();
}
}}// namespace stage::panel

View file

@ -1,8 +1,8 @@
/*
VIEWER-PANEL.hpp - Dockable panel to hold the video display widgets and controls
PLAY-PANEL.hpp - Dockable panel to hold the play control and switchboard
Copyright (C)
2008, Joel Holdsworth <joel@airwebreathe.org.uk>
2025, Hermann Vosseler <Ichthyostega@web.de>
  **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
@ -21,26 +21,41 @@
#include "stage/panel/panel.hpp"
#include "stage/widget/video-display-widget.hpp"
#include "stage/ctrl/demo-controller.hpp"
#include "stage/widget/button-bar.hpp"
#include "stage/model/w-link.hpp"
namespace stage {
namespace panel {
class ViewerPanel;
/**
* A panel to display the video output.
* A »media player« panel.
*/
class PlayPanel
: public Panel
{
widget::VideoDisplayWidget display_;
ctrl::DemoController demoPlayback_;
widget::ButtonBar buttons_;
widget::MiniButton buttonStop_;
widget::MiniButton buttonPlay_;
widget::MiniButton buttonPause_;
public:
PlayPanel (workspace::PanelManager&, Gdl::DockItem&);
static const char* getTitle();
static const gchar* getStockID();
private:
void dispatchStop();
void dispatchPlay();
void dispatchPause();
using ViewLink = model::WLink<ViewerPanel>;
ViewLink viewer_;
ViewLink& accessViewer();
};
}}// namespace stage::panel

View file

@ -3,6 +3,7 @@
Copyright (C)
2008, Joel Holdsworth <joel@airwebreathe.org.uk>
2025, Hermann Vosseler <Ichthyostega@web.de>
  **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
@ -24,10 +25,6 @@
#include "stage/display-service.hpp"
using namespace Gtk; ///////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
using namespace stage::widget; ///////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
using namespace stage::controller; ///////////////////////////////////////////////////////////////////////////////TICKET #1071 no wildcard includes please!
namespace stage {
namespace panel {
@ -38,7 +35,7 @@ namespace panel {
, demoPlayback_{[this](void * const buffer){ display_.pushFrame(buffer); }}
{
//----- Pack in the Widgets -----//
pack_start(display_, PACK_EXPAND_WIDGET);
pack_start(display_, Gtk::PACK_EXPAND_WIDGET);
}
const char*

View file

@ -34,13 +34,14 @@ namespace panel {
: public Panel
{
widget::VideoDisplayWidget display_;
ctrl::DemoController demoPlayback_;
public:
ViewerPanel (workspace::PanelManager&, Gdl::DockItem&);
static const char* getTitle();
static const gchar* getStockID();
ctrl::DemoController demoPlayback_;
};
}}// namespace stage::panel

View file

@ -36,6 +36,7 @@
#include <functional>
#include <limits>
#include <atomic>
namespace steam {
@ -54,16 +55,17 @@ namespace node {
: lib::ThreadJoinable<>
{
typedef function<void(void)> Tick;
volatile uint timespan_;
std::atomic_uint timespan_;
/** poll interval for new settings in wait state */
static const uint POLL_TIMEOUT = 1000;
static const uint POLL_TIMEOUT = 10000;
public:
TickService (Tick callback)
: ThreadJoinable("Tick generator (dummy)"
, bind (&TickService::timerLoop, this, callback)
)
, timespan_{POLL_TIMEOUT}
{
INFO (steam, "TickService started.");
}
@ -71,8 +73,8 @@ namespace node {
~TickService ()
{
timespan_ = 0;
auto res = this->join();
WARN_IF (res, steam, "Failure in TickService");
if (not this->join())
WARN (steam, "Failure in TickService");
usleep (200000); // additional delay allowing GTK to dispatch the last output
INFO (steam, "TickService shutdown.");
@ -99,15 +101,16 @@ namespace node {
private:
void timerLoop(Tick periodicFun)
{
timespan_ = POLL_TIMEOUT;
while (0 < timespan_)
do
{
if (timespan_ > POLL_TIMEOUT)
periodicFun();
usleep (timespan_);
}
TRACE (proc_dbg, "Tick Thread timer loop exiting...");
while (timespan_); //(possible yet very unlikely race with ctor)
//
TRACE (proc_dbg, "Tick Thread timer loop exiting...");
}
};

View file

@ -129779,7 +129779,8 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1746321706423" ID="ID_476605997" MODIFIED="1746321714046" TEXT="versuche mal 4 FPS"/>
</node>
</node>
<node CREATED="1746237851254" ID="ID_991590991" MODIFIED="1746237873586" TEXT="Widget und Controller-Logik mit Null-Displayer neu aufbauen">
<node COLOR="#338800" CREATED="1746237851254" ID="ID_991590991" MODIFIED="1746503055920" TEXT="Widget und Controller-Logik mit Null-Displayer neu aufbauen">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1746237875118" ID="ID_1626821300" MODIFIED="1746321177564" TEXT="Widget soll erst mal schwarzen Hintergrund zeichnen">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1746321143947" ID="ID_302254163" MODIFIED="1746321175715" TEXT="verwende Gtk::Image">
@ -129795,8 +129796,8 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<icon BUILTIN="idea"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1746237886231" ID="ID_81175326" MODIFIED="1746237894236" TEXT="ein paar Buttons einbinden">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1746237886231" ID="ID_81175326" MODIFIED="1746503049411" TEXT="ein paar Buttons einbinden">
<icon BUILTIN="button_ok"/>
<node CREATED="1746366500471" ID="ID_442660271" MODIFIED="1746366507224" TEXT="blo&#xdf; wo?">
<node CREATED="1746366514666" ID="ID_414805814" MODIFIED="1746366526915" TEXT="k&#xf6;nnte nat&#xfc;rlich eine Button-Bar in den Viewer h&#xe4;ngen"/>
<node CREATED="1746366527794" ID="ID_488665860" MODIFIED="1746366562250" TEXT="aber vertical Screen-Real-Estate ist bereits knapp">
@ -129807,7 +129808,7 @@ 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="#eef0c5" COLOR="#990000" CREATED="1746366589535" ID="ID_944511675" MODIFIED="1746366785144" TEXT="also ein neues Docking-Panel schaffen">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1746366589535" ID="ID_944511675" MODIFIED="1746503051582" TEXT="also ein neues Docking-Panel schaffen">
<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"/>
@ -129852,8 +129853,7 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
Ausgangspunkt sind verschiedene Icons f&#252;r Musik-Player, die eine stilisierte Compact-Kasette zeigen. Das bringt mich auf die Idee, auf die Steenbeck-Schneidemaschinen anzuspielen, mit den gro&#223;en Rollen, bzw. auf eine Magnetton-Maschine ... und dann k&#246;nnte man ein &#187;Playhead&#171; aus einem &#187;Play/Pause&#171;-Symbol erzeugen
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<font NAME="SansSerif" SIZE="8"/>
<icon BUILTIN="idea"/>
</node>
@ -129916,8 +129916,72 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1746321719549" ID="ID_1181117478" MODIFIED="1746321726590" TEXT="Buttons mit controller verdrahten">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1746321719549" ID="ID_1181117478" MODIFIED="1746503040965" TEXT="Buttons mit controller verdrahten">
<icon BUILTIN="button_ok"/>
<node CREATED="1746491309584" ID="ID_136709320" MODIFIED="1746491324787" TEXT="Buttons erst mal vorl&#xe4;ufig in das Player-Panel packen">
<node COLOR="#338800" CREATED="1746491325687" ID="ID_769867914" MODIFIED="1746491618741" TEXT="verwende eine Button-Bar">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#435e98" CREATED="1746491149720" ID="ID_55661240" MODIFIED="1746503014295" TEXT="wirft das n&#xe4;chste Problem auf: Kommunikation">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1746491192817" ID="ID_387749605" MODIFIED="1746491247688" TEXT="es ist noch nicht klar, wie l&#xe4;ngerfristig die Verbindung zum Play-Controller aufgebaut wird"/>
<node CREATED="1746491257764" ID="ID_86692047" MODIFIED="1746491276155" TEXT="allerdings kann man f&#xfc;r eine solches Experiment hier durchaus direkt verdrahten"/>
<node CREATED="1746491277433" ID="ID_597033627" MODIFIED="1746503031902" TEXT="sofern man irgendwie an das Viewer-Panel rankommt">
<arrowlink COLOR="#1d7cba" DESTINATION="ID_652181497" ENDARROW="Default" ENDINCLINATION="-204;162;" ID="Arrow_ID_153772805" STARTARROW="None" STARTINCLINATION="-65;103;"/>
<node CREATED="1746491178444" ID="ID_45035522" MODIFIED="1746493546548" TEXT="der ViewLocator funktioniert bisher nur rudiment&#xe4;r">
<node CREATED="1746493563981" ID="ID_604740347" MODIFIED="1746493620710" TEXT="moment mal ... was macht der InteractionDirector...?">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
siehe <font color="#632d2d" face="Bitstream Vera Sans Mono" size="9pt"><b>InteractionDirector::injectTimeline</b></font>()
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1746493548812" ID="ID_1243095299" MODIFIED="1746493585672" TEXT="Ha! f&#xfc;r Docking-Panels gibts eine Implementierung">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1746493696311" ID="ID_1278234244" MODIFIED="1746494206876" TEXT="dann m&#xfc;&#xdf;te man aber an den WindowLocator rankommen"/>
<node CREATED="1746494209321" ID="ID_121273946" MODIFIED="1746494219485" TEXT="das ist n&#xe4;mlich auch nur ein Workaround...">
<node CREATED="1746494220662" ID="ID_1690344435" MODIFIED="1746494230532" TEXT="und im top-level-Kontext direkt verdrahtet"/>
<node CREATED="1746494231415" ID="ID_1376525419" MODIFIED="1746494240787" TEXT="weshalb der InteractionDirector da einsteigen kann"/>
</node>
</node>
<node CREATED="1746494243403" ID="ID_239599231" MODIFIED="1746494259137" TEXT="aber diese Implementierung verwendet auch nur den PanelManager">
<node CREATED="1746494264689" ID="ID_1488667661" MODIFIED="1746494272098" TEXT="der hat sogar ein statisches Interface"/>
<node CREATED="1746494272644" ID="ID_1041353864" MODIFIED="1746494293488" TEXT="ja genau &#x2014; das ist Teil des Problems">
<icon BUILTIN="smily_bad"/>
</node>
<node CREATED="1746494300207" ID="ID_643613061" MODIFIED="1746494332790" TEXT="und das ElementAccess-Interaface soll das (einmal) alles l&#xf6;sen!!!!">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
ist aber leider nicht implementiert...
</p>
</body>
</html></richcontent>
</node>
</node>
<node CREATED="1746494341646" ID="ID_652181497" MODIFIED="1746503027050" TEXT="ein Docking-Panel hat Zugang zum PanelManager">
<linktarget COLOR="#1d7cba" DESTINATION="ID_652181497" ENDARROW="Default" ENDINCLINATION="-204;162;" ID="Arrow_ID_153772805" SOURCE="ID_597033627" STARTARROW="None" STARTINCLINATION="-65;103;"/>
<node CREATED="1746496222837" ID="ID_1964317767" MODIFIED="1746496237280" TEXT="den bekommt der Konstruktor eines Docking-Panels in die Hand"/>
<node CREATED="1746495051432" ID="ID_1507221393" MODIFIED="1746495062055" TEXT="aber im Konstruktor sollte man noch keine Aufl&#xf6;sung machen"/>
<node CREATED="1746495062853" ID="ID_1030445862" MODIFIED="1746495115103" TEXT="zumal zu dem Zeitpunkt die Panels noch gar nicht zum Dock hinzugef&#xfc;gt wurden"/>
<node CREATED="1746496242736" ID="ID_369538552" MODIFIED="1746496269528" TEXT="aber er ist auch &#xfc;ber die Basis-Klasse Panel::panelManager_ zug&#xe4;nglich">
<icon BUILTIN="idea"/>
</node>
<node COLOR="#338800" CREATED="1746496272938" ID="ID_215870350" MODIFIED="1746503005412" TEXT="also k&#xf6;nnen wir eine Lazy-Aufl&#xf6;sung machen">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1746503059144" ID="ID_1217403537" MODIFIED="1746503069530" TEXT="Testen mit Ausgabe auf STDOUT">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1746313536301" ID="ID_407425498" MODIFIED="1746313654699" TEXT="Infos zu den Low-Level-Zugriffen">
@ -157880,8 +157944,7 @@ unsigned int ThreadIdAsInt = *static_cast&lt;unsigned int*&gt;(static_cast&lt;vo
Das ist essentiell; gute Icons zeichnen ist eine Kunst
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1746488049804" ID="ID_410833116" MODIFIED="1746488064098" TEXT="ggfs tempor&#xe4;r einen farbigen / dunklen HIntergrund dahinter legen"/>
<node CREATED="1746488065232" ID="ID_428636762" MODIFIED="1746488081816" TEXT="Icons m&#xfc;ssen sowohl auf hellem, alsauch auf dunklem HInterrund funktionieren"/>