Timeline: reorganise widget structure within body pane to accommodate time ruler

After thinking the whole concept over several times, it occurred to me that
a separate implementation of a time ruler would be quite redundant with the
envisioned feature of per-track overview rulers. Following this line of thought,
the time ruler would just be some specifically configured overview ruler.

This has the somewhat unfortunate consequence, that it becomes the responsibility
of the body canvas to render the overview ruler, thereby somehow delegating
to a common renderer implementation. Which makes the whole setup of the body canvas
way more complex, because now we get *two* canvas like painting areas, one
always visible at top, and the second one, the content area, fully scrollable
within the lower part.
This commit is contained in:
Fischlurch 2019-04-13 17:55:20 +02:00
parent bd13df2308
commit 7ee0baa241
3 changed files with 187 additions and 49 deletions

View file

@ -39,7 +39,7 @@
//#include "lib/format-string.hpp"
//#include "lib/format-cout.hpp"
//#include "lib/util.hpp"
#include "lib/util.hpp"
//#include <algorithm>
//#include <vector>
@ -48,6 +48,7 @@
//using util::_Fmt;
using util::max;
//using util::contains;
//using Gtk::Widget;
using Gdk::Rectangle;
@ -65,6 +66,9 @@ namespace timeline {
namespace { // details of track background painting
const int INITIAL_TIMERULER_HEIGHT_px = 30;
class TrackGroundingRenderer
: public ProfileInterpreter
{
@ -142,11 +146,10 @@ namespace timeline {
TimelineCanvas::TimelineCanvas (DisplayManager& displayManager)
TimelineCanvas::TimelineCanvas (_RenderFactory groundingFac, _RenderFactory overlayFac)
: Gtk::Layout{}
, layout_{displayManager}
, rootBody_{nullptr}
, profile_{}
, getGroundingRenderer_{groundingFac}
, getOverlayRenderer_{overlayFac}
{ }
@ -155,17 +158,29 @@ namespace timeline {
BodyCanvasWidget::BodyCanvasWidget (DisplayManager& displayManager)
: Gtk::ScrolledWindow{}
, canvas_{displayManager}
: Gtk::Box{Gtk::ORIENTATION_VERTICAL}
, contentArea_{}
, rulerCanvas_{std::function<Renderer&()>(), std::function<Renderer&()>()} ///////////TODO dummy placeholder factories.... need to build the real thing
, mainCanvas_{std::function<Renderer&()>(), std::function<Renderer&()>()}
, layout_{displayManager}
, profile_{}
, rootBody_{nullptr}
{
this->set_shadow_type(Gtk::SHADOW_IN);
this->set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC); // always need a horizontal scrollbar
this->property_expand() = true; // dynamically grab any available additional space
this->add(canvas_);
this->set_border_width (0);
this->property_expand() = true; // dynamically grab any available additional space
this->pack_start (rulerCanvas_);
this->pack_start (contentArea_);
contentArea_.set_shadow_type (Gtk::SHADOW_NONE);
contentArea_.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC); // always need a horizontal scrollbar
contentArea_.property_expand() = true; // dynamically grab additional space
contentArea_.add (mainCanvas_);
{ // for the initial empty canvas -- use all space the enclosing scrolled window got.
auto currSize = get_allocation();
canvas_.set_size (currSize.get_width(), currSize.get_height());
int height = currSize.get_height();
rulerCanvas_.set_size (currSize.get_width(), INITIAL_TIMERULER_HEIGHT_px);
mainCanvas_.set_size (currSize.get_width(), max(0, height-INITIAL_TIMERULER_HEIGHT_px));
}
// realise all initially configured elements....
@ -185,7 +200,23 @@ namespace timeline {
void
BodyCanvasWidget::installForkRoot (TrackBody& rootTrackBody)
{
canvas_.rootBody_ = &rootTrackBody;
rootBody_ = &rootTrackBody;
}
/**
*
*/
TrackProfile&
BodyCanvasWidget::establishTrackProfile()
{
if (rootBody_)
{
if (not profile_)
rootBody_->establishTrackSpace (profile_);
// TrackGroundingRenderer renderer{cox, layout_.getPixSpan()}; //////////TODO TOD-oh
}
}
@ -256,14 +287,7 @@ namespace timeline {
void
TimelineCanvas::drawGrounding (CairoC const& cox)
{
if (rootBody_)
{
if (not profile_)
rootBody_->establishTrackSpace (profile_);
TrackGroundingRenderer renderer{cox, layout_.getPixSpan()};
profile_.performWith (renderer);
}
// profile_.performWith (renderer);
/////////////////////////////////////////////TICKET #1039 : placeholder drawing
cox->set_source_rgb(0.8, 0.0, 0.0);
cox->set_line_width (5.0);

View file

@ -64,6 +64,7 @@
//#include <memory>
//#include <vector>
#include <functional>
@ -72,18 +73,27 @@ namespace timeline {
class DisplayManager;
class TrackBody;
class TimelineCanvas;
class Renderer
{
public:
virtual ~Renderer() { } ///< this is an interface
virtual void drawTo (TimelineCanvas&) =0;
};
class TimelineCanvas
: public Gtk::Layout
{
DisplayManager& layout_;
using _RenderFactory = std::function<Renderer&()>;
_RenderFactory getGroundingRenderer_;
_RenderFactory getOverlayRenderer_;
public:
TrackBody* rootBody_;
TrackProfile profile_;
TimelineCanvas (DisplayManager&);
TimelineCanvas (_RenderFactory groundingFac, _RenderFactory overlayFac);
private:
virtual bool on_draw (Cairo::RefPtr<Cairo::Context> const&) override;
@ -100,9 +110,15 @@ namespace timeline {
* @todo WIP-WIP as of 12/2016
*/
class BodyCanvasWidget
: public Gtk::ScrolledWindow
: public Gtk::Box
{
TimelineCanvas canvas_;
Gtk::ScrolledWindow contentArea_;
TimelineCanvas rulerCanvas_;
TimelineCanvas mainCanvas_;
DisplayManager& layout_;
TrackProfile profile_;
TrackBody* rootBody_;
public:
BodyCanvasWidget (DisplayManager&);
@ -111,8 +127,16 @@ namespace timeline {
/** @internal Initially install the contents corresponding to the root track fork */
void installForkRoot (TrackBody& rootTrackBody);
/** @internal allow the header pane to follow our vertical scrolling movement */
auto
get_vadjustment()
{
return contentArea_.get_vadjustment();
}
private:/* ===== Internals ===== */
TrackProfile& establishTrackProfile();
};

View file

@ -19448,7 +19448,7 @@
</node>
</node>
</node>
<node CREATED="1480607035712" ID="ID_1405339006" MODIFIED="1518487921082" TEXT="Rumpf">
<node CREATED="1480607035712" ID="ID_1405339006" MODIFIED="1518487921082" TEXT="Rumpf" VGAP="5">
<node CREATED="1544835109183" ID="ID_1598364198" MODIFIED="1554996128177" TEXT="Konzept: RulerTrack">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1544849233126" ID="ID_665765482" MODIFIED="1554996286114" TEXT="#1194 Handling of Ruler Tracks">
<icon BUILTIN="flag-yellow"/>
@ -19513,6 +19513,46 @@
<node CREATED="1544838027901" ID="ID_519696967" MODIFIED="1544839199767" TEXT="Header-Pane: Platz &quot;geschickt&quot; nutzen">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1555082395840" ID="ID_104473939" MODIFIED="1555082419611" TEXT="ABER trotzdem separat darzustellen">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1555082433635" ID="ID_1213306272" MODIFIED="1555082440982" TEXT="Time-Ruler &quot;allways on top&quot;"/>
<node CREATED="1555082442705" ID="ID_497245117" MODIFIED="1555082597140">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
Unterscheidung <b>verschoben</b>&#160;in die Darstellung
</p>
</body>
</html>
</richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
anstatt (konventionell) den Time-Ruler separat explizit auszuprogrammieren,
</p>
<p>
bekommen wir nun eine gemeinsame Darstellungs-Mechanik,
</p>
<p>
welche dann aber in zwei getrennten Bereichen jeweils anders parametrisiert
</p>
<p>
zur Anwendung kommt
</p>
</body>
</html>
</richcontent>
</node>
<node COLOR="#435e98" CREATED="1555082487012" ID="ID_217824628" MODIFIED="1555082508617" TEXT="trotzdem sinnvolles Potential zur Vereinheitlichung">
<icon BUILTIN="yes"/>
</node>
</node>
</node>
<node CREATED="1544839243971" ID="ID_1000231823" MODIFIED="1544839267628" TEXT="Ausf&#xfc;hrung obliegt der Session"/>
</node>
@ -19525,10 +19565,73 @@
<node CREATED="1554996306756" ID="ID_1619835790" MODIFIED="1554996324416" TEXT="auf spezielle Konfig eines &quot;Ruler-Tracks&quot; zur&#xfc;ckf&#xfc;hren">
<arrowlink DESTINATION="ID_80922465" ENDARROW="Default" ENDINCLINATION="343;0;" ID="Arrow_ID_630173444" STARTARROW="None" STARTINCLINATION="376;0;"/>
</node>
<node CREATED="1555080526516" ID="ID_1733081392" MODIFIED="1555080551834">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
Problem: <i><font color="#bb4444">mu&#223; immer sichtbar sein</font></i>
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1555080572765" ID="ID_577805455" MODIFIED="1555080639983" TEXT="im Detail etwas komplexer...">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
aber es bleibt bei diesem Prinzip.
</p>
<p>
</p>
<p>
Des Genaueren, es gibt eine jeweils festgesetzte Menge von Elementen
</p>
<p>
am Anfang des Track-Profils, welche immer sichtbar bleiben soll
</p>
</body>
</html>
</richcontent>
</node>
</node>
</node>
<node CREATED="1555082672083" ID="ID_1185653910" MODIFIED="1555082799559" TEXT="BodyCanvasWidget">
<node CREATED="1555082682753" ID="ID_1277383747" MODIFIED="1555082692560" TEXT="verwaltet und organisiert die Struktur"/>
<node CREATED="1555082693273" ID="ID_723726755" MODIFIED="1555082702200" TEXT="hat zwei konkrete TimelineCanvas">
<node CREATED="1555082703199" ID="ID_81861736" MODIFIED="1555082709649" TEXT="oben f&#xfc;r den Time-Ruler"/>
<node CREATED="1555082710728" ID="ID_676334326" MODIFIED="1555082731805" TEXT="unten f&#xfc;r die Track-Struktur"/>
</node>
<node CREATED="1555084648375" ID="ID_483631091" MODIFIED="1555084698950" TEXT="organisiert das Struktur-Profil">
<arrowlink COLOR="#2e66db" DESTINATION="ID_1659558780" ENDARROW="Default" ENDINCLINATION="-889;0;" ID="Arrow_ID_1691760775" STARTARROW="None" STARTINCLINATION="828;0;"/>
</node>
</node>
<node CREATED="1540641317386" ID="ID_151954769" MODIFIED="1554996384127" TEXT="Canvas">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_151954769" ENDARROW="Default" ENDINCLINATION="263;-88;" ID="Arrow_ID_1923805019" SOURCE="ID_18552766" STARTARROW="None" STARTINCLINATION="93;24;"/>
<node CREATED="1540951718734" HGAP="56" ID="ID_179159881" MODIFIED="1540951729689" TEXT="TrackBody" VSHIFT="11">
<node CREATED="1554480347233" HGAP="-16" ID="ID_1408962662" MODIFIED="1555082780585" VSHIFT="-10">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
<u>grunds&#228;tzlich</u>: <i>es zeichnet der Canvas</i>
</p>
</body>
</html>
</richcontent>
<edge COLOR="#a07373" STYLE="linear"/>
<icon BUILTIN="yes"/>
<node CREATED="1555082815168" ID="ID_1445154694" MODIFIED="1555082846519" TEXT="er entscheidet aber nicht &#xfc;ber die Struktur"/>
<node CREATED="1555082847183" ID="ID_822850985" MODIFIED="1555082856733" TEXT="sondern bekommt Struktur-Info hereingereicht"/>
</node>
<node CREATED="1540951718734" HGAP="69" ID="ID_179159881" MODIFIED="1555082878628" TEXT="TrackBody" VSHIFT="-42">
<node CREATED="1540951732747" ID="ID_879954288" MODIFIED="1540951770897" TEXT="kein Widget, sondern eine Hilfs-Struktur"/>
<node CREATED="1540951833141" ID="ID_387631457" MODIFIED="1540951859869" TEXT="erledigt f&#xfc;r den Canvas das Zeichnen f&#xfc;r einen Track"/>
<node CREATED="1540951862399" ID="ID_708158546" MODIFIED="1540951902567" TEXT="relative Koordinaten (und sowiso nur vertikal)"/>
@ -19575,8 +19678,8 @@
</node>
</node>
</node>
<node CREATED="1544839288936" ID="ID_43593052" MODIFIED="1554996355955" TEXT="zwei Ruler-Konfigs in das systematische UI-Modell">
<arrowlink COLOR="#5f84b0" DESTINATION="ID_1083901292" ENDARROW="Default" ENDINCLINATION="-756;-82;" ID="Arrow_ID_1167484185" STARTARROW="None" STARTINCLINATION="-942;0;"/>
<node CREATED="1544839288936" ID="ID_43593052" MODIFIED="1555082891874" TEXT="zwei Ruler-Konfigs in das systematische UI-Modell">
<arrowlink COLOR="#5f84b0" DESTINATION="ID_1083901292" ENDARROW="Default" ENDINCLINATION="-756;-82;" ID="Arrow_ID_1167484185" STARTARROW="None" STARTINCLINATION="-981;0;"/>
<node COLOR="#338800" CREATED="1544849869166" ID="ID_1025477379" MODIFIED="1553911646237" TEXT="Frage: wo ansiedeln?">
<icon BUILTIN="button_ok"/>
<node CREATED="1544849875744" ID="ID_27673928" MODIFIED="1553911580738" TEXT="im TrackPresenter">
@ -19612,20 +19715,6 @@
</node>
</node>
</node>
<node CREATED="1554480347233" HGAP="56" ID="ID_1408962662" MODIFIED="1554480377458" VSHIFT="12">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
<u>grunds&#228;tzlich</u>: <i>es zeichnet der Canvas</i>
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="yes"/>
</node>
<node CREATED="1541861473496" ID="ID_457526663" MODIFIED="1541861480149" TEXT="draw">
<node CREATED="1542309666407" ID="ID_1721729181" MODIFIED="1542309670065" TEXT="initial....">
<node CREATED="1542309671333" ID="ID_1283622298" MODIFIED="1542309937265" TEXT="Gr&#xf6;&#xdf;e des leeren Canvas">
@ -19765,7 +19854,8 @@
<icon BUILTIN="full-3"/>
</node>
</node>
<node CREATED="1554480448693" ID="ID_1659558780" MODIFIED="1554516103872" STYLE="fork" TEXT="Struktur-Profil">
<node CREATED="1554480448693" ID="ID_1659558780" MODIFIED="1555084698950" STYLE="fork" TEXT="Struktur-Profil">
<linktarget COLOR="#2e66db" DESTINATION="ID_1659558780" ENDARROW="Default" ENDINCLINATION="-889;0;" ID="Arrow_ID_1691760775" SOURCE="ID_483631091" STARTARROW="None" STARTINCLINATION="828;0;"/>
<icon BUILTIN="forward"/>
<node CREATED="1554480470481" ID="ID_936706731" MODIFIED="1554516082320" TEXT="Canvas bezieht vom Root-Body eine Verb-Sequenz"/>
<node CREATED="1554516114006" ID="ID_1074831376" MODIFIED="1554516126660" TEXT="diese Verb-Sequenz wird rekursiv aufgebaut"/>
@ -22093,8 +22183,8 @@
<node CREATED="1538956802701" ID="ID_840384156" MODIFIED="1538956809576" TEXT="Sequence{Marker}">
<node CREATED="1538957049292" ID="ID_1955645432" MODIFIED="1538957077700" TEXT="if typeID = &quot;Marker&quot;"/>
</node>
<node CREATED="1544839585279" ID="ID_1083901292" MODIFIED="1554996355955" TEXT="Sequence{Ruler}">
<linktarget COLOR="#5f84b0" DESTINATION="ID_1083901292" ENDARROW="Default" ENDINCLINATION="-756;-82;" ID="Arrow_ID_1167484185" SOURCE="ID_43593052" STARTARROW="None" STARTINCLINATION="-942;0;"/>
<node CREATED="1544839585279" ID="ID_1083901292" MODIFIED="1555082891874" TEXT="Sequence{Ruler}">
<linktarget COLOR="#5f84b0" DESTINATION="ID_1083901292" ENDARROW="Default" ENDINCLINATION="-756;-82;" ID="Arrow_ID_1167484185" SOURCE="ID_43593052" STARTARROW="None" STARTINCLINATION="-981;0;"/>
<node CREATED="1544846037083" ID="ID_667362504" MODIFIED="1544846061300" TEXT="if typeID = &quot;Ruler&quot;"/>
<node CREATED="1544846062288" ID="ID_855083299" MODIFIED="1544846101674" TEXT="storage direkt (nested) im TrackBody"/>
</node>