Clip-Drag: refactor into sub-component of TimelineLayout

this allows to avoid multi-step indirection
when translating mouse dragging pixel coordinates
into a time offset for the dragged clip widget.

Moreover this also improves the design,
since the handling of canvas metric is pretty much
a self contained, separate concern
This commit is contained in:
Fischlurch 2021-04-30 19:46:32 +02:00
parent 0fb3aab95b
commit 73740a24e3
9 changed files with 78 additions and 46 deletions

View file

@ -64,6 +64,7 @@ namespace model {
using lib::time::Time;
using lib::time::TimeValue;
using lib::time::TimeSpan;
@ -82,8 +83,11 @@ namespace model {
public:
virtual ~DisplayMetric() { } ///< this is an interface
/** the overall time Duration covered by this timeline canvas */
virtual TimeSpan coveredTime() const =0;
/** extension point for time axis zoom management. */
virtual int translateTimeToPixels (TimeValue) const =0;
virtual int translateTimeToPixels (TimeValue) const =0;
};
@ -101,7 +105,6 @@ namespace model {
*/
template<class WID>
class CanvasHook
: public DisplayMetric
{
public:
virtual ~CanvasHook() { } ///< this is an interface
@ -110,6 +113,9 @@ namespace model {
virtual void move (WID& widget, int xPos, int yPos) =0;
virtual void remove (WID& widget) =0;
/** access the component to handle layout metric */
virtual DisplayMetric& getMetric() const =0;
/** Anchor point to build chains of related View Hooks */
virtual CanvasHook<WID>&
getAnchorHook() noexcept
@ -137,7 +143,7 @@ namespace model {
Pos
hookedAt (Time start, int downshift=0)
{
return hookedAt (translateTimeToPixels (start), downshift);
return hookedAt (getMetric().translateTimeToPixels (start), downshift);
}
};

View file

@ -84,10 +84,6 @@ namespace timeline {
using CairoC = PCairoContext const&;
using StyleC = PStyleContext const&;
namespace { /////////////////////////////////////////////////////TICKET #1213 : use proper zoom handling instead of dummy constants!!
const int TODO_px_per_second = 25;
} /////////////////////////////////////////////////////TICKET #1213 : (END) get rid of these dummy constants!!
namespace { // details of track background painting
const int INITIAL_TIMERULER_HEIGHT_px = 30;
@ -576,10 +572,10 @@ namespace timeline {
getCanvas(yPos).move (widget, xPos, yPos);
}
int
BodyCanvasWidget::translateTimeToPixels (TimeValue startTimePoint) const
model::DisplayMetric&
BodyCanvasWidget::getMetric() const
{
return _raw(startTimePoint) * TODO_px_per_second / Time::SCALE; //////////TICKET #1213 : delegate zoom handling to the display manager (field #layout_) !!
return layout_;
}
/** respond to the DisplayEvaluation pass.

View file

@ -176,8 +176,8 @@ namespace timeline {
void hook (Gtk::Widget&, int xPos=0, int yPos=0) override;
void move (Gtk::Widget&, int xPos, int yPos) override;
void remove (Gtk::Widget&) override;
int translateTimeToPixels (TimeValue) const override;
model::DisplayMetric& getMetric() const override;
protected: /* ==== Interface: LayoutElement ===== */

View file

@ -327,7 +327,7 @@ namespace timeline {
void
establishHorizontalExtension()
{
int hSize = getCanvas().translateTimeToPixels (getLen());
int hSize = getCanvas().getMetric().translateTimeToPixels (getLen());
set_size_request (hSize, -1);
// queue_resize();
}
@ -349,7 +349,7 @@ namespace timeline {
void
get_preferred_width_vfunc(int& minimum_width, int& natural_width) const override
{
minimum_width = natural_width = getCanvas().translateTimeToPixels (getLen());
minimum_width = natural_width = getCanvas().getMetric().translateTimeToPixels (getLen());
}

View file

@ -146,11 +146,11 @@ namespace timeline {
virtual int hookAdjX (int xPos) =0;
virtual int hookAdjY (int yPos) =0;
/** delegating default implementation for timeline zoom */
int
translateTimeToPixels (TimeValue startTimePoint) const override
/** delegating layout metric to the root canvas */
model::DisplayMetric&
getMetric() const override
{
return refHook_.translateTimeToPixels (startTimePoint);
return refHook_.getMetric();
}
public:
@ -215,15 +215,13 @@ namespace timeline {
class DisplayManager
: util::NonCopyable
, public DisplayViewHooks
, public model::DisplayMetric
{
public:
virtual ~DisplayManager(); ///< this is an interface
/** the overall horizontal pixel span to cover by this timeline */
virtual PixSpan getPixSpan() =0;
/** cause a re-allocation of the complete layout */
virtual void triggerDisplayEvaluation() =0;
@ -235,6 +233,16 @@ namespace timeline {
* arrangement of the timeline layout.
*/
SignalStructureChange signalStructureChange_;
/** the overall horizontal pixel span to cover by this timeline */
PixSpan
getPixSpan()
{
return {translateTimeToPixels (coveredTime().start())
,translateTimeToPixels (coveredTime().end())
};
}
private:/* ===== Internals ===== */

View file

@ -40,6 +40,7 @@
#include "common/advice.hpp"
//#include "lib/util.hpp"
#include "lib/time/timevalue.hpp"
//#include <algorithm>
//#include <vector>
@ -53,11 +54,19 @@
//using sigc::ptr_fun;
//using std::cout;
//using std::endl;
using lib::time::Time;
using lib::time::FSecs;
//using lib::time::Duration;
using lib::time::TimeSpan;
namespace stage {
namespace timeline {
namespace { /////////////////////////////////////////////////////TICKET #1213 : use proper zoom handling instead of dummy constants!!
const int TODO_px_per_second = 25;
} /////////////////////////////////////////////////////TICKET #1213 : (END) get rid of these dummy constants!!
@ -108,14 +117,19 @@ namespace timeline {
/* ==== Interface: LayoutManager===== */
/* ==== Interface: DisplayManager===== */
PixSpan
TimelineLayout::getPixSpan()
TimeSpan
TimelineLayout::coveredTime() const
{ /////////////////////////////////////TICKET #1019 : need a "ZoomWindow" here to manage the visible area
/////////////////////////////////////TICKET #1039 : "somehow" wire with the TimelineController to find out the covered span
return TimeSpan {Time::ZERO, FSecs{23}}; ////////////////Lalala Lalü
}
int
TimelineLayout::translateTimeToPixels (TimeValue startTimePoint) const
{
////////////////////////////////////////////////////////TICKET #1019 : need a "ZoomWindow" here to manage the visible area
////////////////////////////////////////////////////////TICKET #1039 : "somehow" wire with the TimelineController to find out the covered span
return PixSpan {0, 248}; ////////////////Lalala Lalü
return _raw(startTimePoint) * TODO_px_per_second / Time::SCALE; //////////TICKET #1213 : delegate zoom handling to the display manager (field #layout_) !!
}

View file

@ -137,9 +137,14 @@ namespace timeline {
protected: /* ==== Interface: LayoutManager===== */
PixSpan getPixSpan() override;
void triggerDisplayEvaluation() override;
/////////////////////////////////////////////////////////////////////////////////////////////TICKET 1218 : better extract into a sub component when providing a non-dummy implementation
virtual lib::time::TimeSpan coveredTime() const override;
virtual int translateTimeToPixels (TimeValue) const override;
/////////////////////////////////////////////////////////////////////////////////////////////TICKET 1218 : better extract into a sub component when providing a non-dummy implementation
protected: /* ==== Interface: DisplayViewHooks===== */
model::ViewHook<TrackHeadWidget>& getHeadHook() override { return *this; };

View file

@ -151,11 +151,10 @@ namespace test {
}
protected:
int
translateTimeToPixels (TimeValue) const override
DisplayMetric&
getMetric() const override
{
NOTREACHED ("Time to pixel translation not covered in this unit test");
return -1;
}
};
}

View file

@ -33099,7 +33099,7 @@
</html></richcontent>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1619697245422" ID="ID_1061197338" MODIFIED="1619697783176" TEXT="Forwarding &#xfc;ber mehrere Schritte">
<node COLOR="#435e98" CREATED="1619697245422" ID="ID_1061197338" MODIFIED="1619804310109" TEXT="Forwarding &#xfc;ber mehrere Schritte">
<richcontent TYPE="NOTE"><html>
<head>
@ -33123,8 +33123,8 @@
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1619697735697" ID="ID_1610716398" MODIFIED="1619697746057" TEXT="effektiv 2-Schritt-Forwarding f&#xfc;r jeden Aufruf"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1619697793583" ID="ID_800939749" MODIFIED="1619697865895" TEXT="kann man (opaque) direkt aufrufen?">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1619697793583" FOLDED="true" ID="ID_800939749" MODIFIED="1619804558065" TEXT="kann man (opaque) direkt aufrufen?">
<icon BUILTIN="button_ok"/>
<node CREATED="1619698100329" ID="ID_1983859376" MODIFIED="1619698109360" TEXT="ja: wenn es ein VTable-Slot ist">
<node CREATED="1619698280744" ID="ID_1197467052" MODIFIED="1619698299342" TEXT="dazu m&#xfc;&#xdf;te das Delegate ein Sub-Interface implementieren"/>
<node CREATED="1619698300242" ID="ID_498514293" MODIFIED="1619698315566" TEXT="und der Wrapper ebenfalls"/>
@ -33164,14 +33164,14 @@
das Platzieren auf den Canvas ist <b>keine</b>&#160;high-Performance-Operation;<br />vielmehr ist es sogar <i>vernachl&#228;ssigbar im Vergleich </i>zum Aufwand der Zeichen-Operationen; und letztere werden eben genau aus Performance-Gr&#252;nden gebatcht und geb&#252;ndelt....
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<linktarget COLOR="#6775b4" DESTINATION="ID_1522870458" ENDARROW="Default" ENDINCLINATION="125;10;" ID="Arrow_ID_565826448" SOURCE="ID_1388699771" STARTARROW="None" STARTINCLINATION="290;14;"/>
<icon BUILTIN="yes"/>
</node>
</node>
</node>
<node CREATED="1619698512378" ID="ID_333159714" MODIFIED="1619698546465" TEXT="Metrik-&#xdc;bersetzung">
<node COLOR="#435e98" CREATED="1619698512378" ID="ID_333159714" MODIFIED="1619804302859" TEXT="Metrik-&#xdc;bersetzung">
<icon BUILTIN="forward"/>
<node CREATED="1619698551205" ID="ID_994295604" MODIFIED="1619698871778" TEXT="sieht nach einem isolierten Belang aus">
<arrowlink COLOR="#fef4ac" DESTINATION="ID_560285819" ENDARROW="Default" ENDINCLINATION="150;-12;" ID="Arrow_ID_514924311" STARTARROW="None" STARTINCLINATION="-370;27;"/>
</node>
@ -33192,14 +33192,13 @@
im Gegensatz zum CanvasHook ist <i>das hier durchaus relevant</i>
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<arrowlink COLOR="#6775b4" DESTINATION="ID_1522870458" ENDARROW="Default" ENDINCLINATION="125;10;" ID="Arrow_ID_565826448" STARTARROW="None" STARTINCLINATION="290;14;"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1619698607118" ID="ID_239118181" MODIFIED="1619698618056" TEXT="Umbau sehr w&#xfc;nschenswert">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1619698607118" ID="ID_239118181" MODIFIED="1619804296540" TEXT="Umbau sehr w&#xfc;nschenswert">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
@ -33214,7 +33213,8 @@
<node CREATED="1619132510942" ID="ID_1513485460" MODIFIED="1619132510942" TEXT="applyScreenDelta(TimeValue, deltaPx)"/>
<node CREATED="1619132513720" ID="ID_718240764" MODIFIED="1619132619351" TEXT="translateScreenDeltaToTime(deltaPx)"/>
</node>
<node CREATED="1619698634099" ID="ID_1185723124" MODIFIED="1619698643209" TEXT="Sub-Interface einf&#xfc;hren">
<node COLOR="#338800" CREATED="1619698634099" ID="ID_1185723124" MODIFIED="1619804547408" TEXT="Sub-Interface einf&#xfc;hren">
<icon BUILTIN="button_ok"/>
<node CREATED="1619698644218" ID="ID_560285819" MODIFIED="1619698871778" TEXT="es ist ein komplett isolierter Belang">
<linktarget COLOR="#fef4ac" DESTINATION="ID_560285819" ENDARROW="Default" ENDINCLINATION="150;-12;" ID="Arrow_ID_514924311" SOURCE="ID_994295604" STARTARROW="None" STARTINCLINATION="-370;27;"/>
<icon BUILTIN="idea"/>
@ -33232,11 +33232,15 @@
</html></richcontent>
<icon BUILTIN="forward"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1619698722008" ID="ID_755674225" MODIFIED="1619698813353" TEXT="wird (parametrisierbare) Komponente im LayoutManager">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1619698722008" FOLDED="true" ID="ID_755674225" MODIFIED="1619804539751" TEXT="wird (parametrisierbare) Komponente im LayoutManager">
<icon BUILTIN="bell"/>
<node CREATED="1619804516182" ID="ID_303795305" MODIFIED="1619804534566" TEXT="vorl&#xe4;ufige Dummy-Implementierung">
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1619698793375" ID="ID_127168366" MODIFIED="1619698814669" TEXT="und Mix-In f&#xfc;r die CanvasHook-Hierarchie">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#435e98" CREATED="1619804525392" ID="ID_1563089049" MODIFIED="1619804538286" TEXT="in timeline-layout.cpp, Zeile 123"/>
</node>
<node COLOR="#338800" CREATED="1619698793375" ID="ID_127168366" MODIFIED="1619804320757" TEXT="und Mix-In f&#xfc;r die CanvasHook-Hierarchie">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>