From d4b1735013c329e2264e7749b35bab460044eb53 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 27 Mar 2021 13:47:43 +0100 Subject: [PATCH] define the ClipPresenter header-only (no change) A separate translation unit turns out to be unnecessary here, since this is implementation level code included into one single other translation unit (timeline-controller.cpp). In such a situation, having the whole class definition at one code location improves readability. Moreover, there clearly is now another abstraction barrier, insofar all of the clip widget's implementation technicalities are buried within clip-widget.cpp --- src/stage/timeline/clip-presenter.cpp | 181 -------------------------- src/stage/timeline/clip-presenter.hpp | 146 +++++++++++++++++---- src/stage/timeline/clip-widget.cpp | 4 +- src/stage/timeline/ruler-track.cpp | 1 - 4 files changed, 123 insertions(+), 209 deletions(-) delete mode 100644 src/stage/timeline/clip-presenter.cpp diff --git a/src/stage/timeline/clip-presenter.cpp b/src/stage/timeline/clip-presenter.cpp deleted file mode 100644 index a5aace080..000000000 --- a/src/stage/timeline/clip-presenter.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - ClipPresenter - presentation control element for a clip within the timeline - - Copyright (C) Lumiera.org - 2016, Hermann Vosseler - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -* *****************************************************/ - - -/** @file clip-presenter.cpp - ** Implementation details of clip presentation management. - ** - ** @todo WIP-WIP-WIP as of 12/2016 - ** @todo as of 10/2018 timeline display in the UI is rebuilt to match the architecture - ** - */ - - -#include "stage/gtk-base.hpp" -#include "include/ui-protocol.hpp" -#include "stage/timeline/clip-presenter.hpp" -#include "stage/timeline/marker-widget.hpp" - -//#include "stage/ui-bus.hpp" -//#include "lib/format-string.hpp" -//#include "lib/format-cout.hpp" - -//#include "lib/util.hpp" - -//#include -//#include - - - -//using util::_Fmt; -using lib::diff::TreeMutator; -using lib::diff::collection; -using std::make_unique; -//using util::contains; -//using Gtk::Widget; -//using sigc::mem_fun; -//using sigc::ptr_fun; -//using std::cout; -//using std::endl; - - -namespace stage { -namespace timeline { - - - - - /** - * @param identity referring to the corresponding session::Clip in Steam-Layer. - * @param nexus a way to connect this Controller to the UI-Bus. - * @param view (abstracted) canvas or display framework to attach this clip to - * @param timing (optional) start time point and duration of the clip. - * @note Clip can not be displayed unless #timing is given - */ - ClipPresenter::ClipPresenter (ID identity, ctrl::BusTerm& nexus, WidgetHook& view, optional const& timing) - : Controller{identity, nexus} - , channels_{} - , effects_{} - , markers_{} - , widget_{} - { - establishAppearance (&view, timing); - ENSURE (widget_); - } - - - ClipPresenter::~ClipPresenter() - { - } - - - - - void - ClipPresenter::buildMutator (TreeMutator::Handle buffer) - { - using PChannel = unique_ptr; - using PEffect = unique_ptr; - using PMarker = unique_ptr; - - buffer.create ( - TreeMutator::build() - .attach (collection(markers_) - .isApplicableIf ([&](GenNode const& spec) -> bool - { // »Selector« : require object-like sub scope with type-field "Marker" - return TYPE_Marker == spec.data.recordType(); - }) - .constructFrom ([&](GenNode const& spec) -> PMarker - { - return make_unique (spec.idi, this->uiBus_); - })) - .attach (collection(effects_) - .isApplicableIf ([&](GenNode const& spec) -> bool - { // »Selector« : require object-like sub scope with type-field "Effect" - return TYPE_Effect == spec.data.recordType(); - }) - .constructFrom ([&](GenNode const& spec) -> PEffect - { - std::optional timing = spec.retrieveAttribute (string{ATTR_timing}); - return make_unique (spec.idi, this->uiBus_ - ,getClipContentCanvas() - ,timing); - })) - .attach (collection(channels_) - .isApplicableIf ([&](GenNode const& spec) -> bool - { // »Selector« : require object-like sub scope with type-field "Channel" - return TYPE_Channel == spec.data.recordType(); - }) - .constructFrom ([&](GenNode const& spec) -> PChannel - { - return make_unique (spec.idi, this->uiBus_ - ,getClipContentCanvas() - ,std::nullopt); /////////////////////////TICKET #1213 : time → horizontal extension : how to represent "always" / "the whole track"?? - })) - .change(ATTR_name, [&](string val) - { // »Attribute Setter« : receive a new value for the clip name field - REQUIRE (widget_); - widget_->setClipName (val); - }) - .change(ATTR_timing, [&](TimeSpan val) - { - REQUIRE (widget_); - widget_->changeTiming (val); - }) - //-Diff-Change-Listener---------------- - .onLocalChange ([this]() - { - this->establishAppearance(); - })); - } - - - - void - ClipPresenter::establishAppearance (WidgetHook* newView, optional const& timing) - { - ClipDelegate::selectAppearance (this->widget_, defaultAppearance, newView, timing); - } - - WidgetHook& - ClipPresenter::getClipContentCanvas() - { - UNIMPLEMENTED ("how to create and wire an embedded canvas for the clip contents/effects"); - } - - uint - ClipPresenter::determineRequiredVerticalExtension() const - { - REQUIRE (widget_); - return widget_->calcRequiredHeight() - + widget_->getVerticalOffset(); - } - - void - ClipPresenter::relink() - { - REQUIRE (widget_); - widget_->updatePosition(); - } - - -}}// namespace stage::timeline diff --git a/src/stage/timeline/clip-presenter.hpp b/src/stage/timeline/clip-presenter.hpp index a1c52b535..bb2740d82 100644 --- a/src/stage/timeline/clip-presenter.hpp +++ b/src/stage/timeline/clip-presenter.hpp @@ -53,8 +53,10 @@ #define STAGE_TIMELINE_CLIP_PRESENTER_H #include "stage/gtk-base.hpp" +#include "include/ui-protocol.hpp" #include "stage/model/controller.hpp" #include "stage/timeline/clip-widget.hpp" +#include "stage/timeline/marker-widget.hpp" #include "stage/interact/cmd-context.hpp" #include "lib/time/timevalue.hpp" @@ -73,8 +75,9 @@ namespace timeline { using std::optional; using std::unique_ptr; using lib::time::TimeSpan; - - class MarkerWidget; + using lib::diff::TreeMutator; + using lib::diff::collection; + using std::make_unique; /** @@ -100,43 +103,136 @@ namespace timeline { public: - ClipPresenter (ID, ctrl::BusTerm&, WidgetHook&, optional const&); + /** + * @param identity referring to the corresponding session::Clip in Steam-Layer. + * @param nexus a way to connect this Controller to the UI-Bus. + * @param view (abstracted) canvas or display framework to attach this clip to + * @param timing (optional) start time point and duration of the clip. + * @note Clip can not be displayed unless #timing is given + */ + ClipPresenter (ID identity, ctrl::BusTerm& nexus, WidgetHook& view, optional const& timing) + : Controller{identity, nexus} + , channels_{} + , effects_{} + , markers_{} + , widget_{} + { + establishAppearance (&view, timing); + ENSURE (widget_); + } - ~ClipPresenter(); + ~ClipPresenter() { }; /** set up a binding to respond to mutation messages via UiBus */ - virtual void buildMutator (lib::diff::TreeMutator::Handle) override; + virtual void + buildMutator (TreeMutator::Handle buffer) override + { + using PChannel = unique_ptr; + using PEffect = unique_ptr; + using PMarker = unique_ptr; + + buffer.create ( + TreeMutator::build() + .attach (collection(markers_) + .isApplicableIf ([&](GenNode const& spec) -> bool + { // »Selector« : require object-like sub scope with type-field "Marker" + return TYPE_Marker == spec.data.recordType(); + }) + .constructFrom ([&](GenNode const& spec) -> PMarker + { + return make_unique (spec.idi, this->uiBus_); + })) + .attach (collection(effects_) + .isApplicableIf ([&](GenNode const& spec) -> bool + { // »Selector« : require object-like sub scope with type-field "Effect" + return TYPE_Effect == spec.data.recordType(); + }) + .constructFrom ([&](GenNode const& spec) -> PEffect + { + std::optional timing = spec.retrieveAttribute (string{ATTR_timing}); + return make_unique (spec.idi, this->uiBus_ + ,getClipContentCanvas() + ,timing); + })) + .attach (collection(channels_) + .isApplicableIf ([&](GenNode const& spec) -> bool + { // »Selector« : require object-like sub scope with type-field "Channel" + return TYPE_Channel == spec.data.recordType(); + }) + .constructFrom ([&](GenNode const& spec) -> PChannel + { + return make_unique (spec.idi, this->uiBus_ + ,getClipContentCanvas() + ,std::nullopt); /////////////////////////TICKET #1213 : time → horizontal extension : how to represent "always" / "the whole track"?? + })) + .change(ATTR_name, [&](string val) + { // »Attribute Setter« : receive a new value for the clip name field + REQUIRE (widget_); + widget_->setClipName (val); + }) + .change(ATTR_timing, [&](TimeSpan val) + { + REQUIRE (widget_); + widget_->changeTiming (val); + }) + //-Diff-Change-Listener---------------- + .onLocalChange ([this]() + { + this->establishAppearance(); + })); + } - /** find out the number of pixels necessary to render this clip properly, - * assuming its current presentation mode (abbreviated, full, expanded). + /** + * find out the number of pixels necessary to render this clip properly, + * assuming its current presentation mode (abbreviated, full, expanded). */ - uint determineRequiredVerticalExtension() const; + uint + determineRequiredVerticalExtension() const + { + REQUIRE (widget_); + return widget_->calcRequiredHeight() + + widget_->getVerticalOffset(); + } - /** update and re-attach the presentation widget into its presentation context. - * Will be called during the "re-link phase" of DisplayEvaluation, after the - * timeline layout has been (re)established globally. Often, this incurs - * attaching the presentation widget (ClipDelegate) at a different actual - * position onto the drawing canvas, be it due to a zoom change, or - * as result of layout re-flow. + /** + * update and re-attach the presentation widget into its presentation context. + * Will be called during the "re-link phase" of DisplayEvaluation, after the timeline layout + * has been (re)established globally. Often, this incurs attaching the presentation widget + * (ClipDelegate) at a different actual position onto the drawing canvas, be it due to a + * zoom change, or as result of layout re-flow. */ - void relink(); + void + relink() + { + REQUIRE (widget_); + widget_->updatePosition(); + } + private:/* ===== Internals ===== */ - - /** reevaluate desired presentation mode and available data, + /** + * reevaluate desired presentation mode and available data, * possibly leading to a changed appearance style of the clip. - * @remark a typical example would be, when a clip's temporal position, - * previously unspecified, now becomes defined through a diff message. - * With this data, it becomes feasible _actually to show the clip_ in - * the timeline. Thus the [Appearance style](\ref ClipDelegate::Appearance) - * of the presentation widget (delegate) can be switched up from `PENDING` - * to `ABRIDGED`. + * @remark a typical example would be, when a clip's temporal position, previously unspecified, + * now becomes defined through a diff message. With this data, it becomes feasible + * _actually to show the clip_ in the timeline. Thus the [Appearance style](\ref ClipDelegate::Appearance) + * of the presentation widget (delegate) can be switched up from `PENDING` to `ABRIDGED`. */ - void establishAppearance(WidgetHook* newView =nullptr, optional const& timing =nullopt); + void + establishAppearance(WidgetHook* newView =nullptr, + optional const& timing =nullopt) + { + ClipDelegate::selectAppearance (this->widget_, defaultAppearance, newView, timing); + } - WidgetHook& getClipContentCanvas(); + + WidgetHook& + getClipContentCanvas() + { + UNIMPLEMENTED ("how to create and wire an embedded canvas for the clip contents/effects"); + } }; diff --git a/src/stage/timeline/clip-widget.cpp b/src/stage/timeline/clip-widget.cpp index d6deb06ed..ebd909644 100644 --- a/src/stage/timeline/clip-widget.cpp +++ b/src/stage/timeline/clip-widget.cpp @@ -73,8 +73,8 @@ ** ** When especially the optional argument `timing` is provided by the _population diff_ ** creating the clip, then we can use the given lib::time::TimeSpan data for actually - ** allocating a screen rectangle, and thus only in this case, a ClipWidget is constructed - ** and mapped into presentation. + ** allocating a screen rectangle, and thus only when this condition is met (which should + ** be the default), a ClipWidget is constructed and mapped into presentation. ** ** Later the appearance style can be switched, which might incur the necessity also to ** exchange the actual implementation of the clip delegate. The latter is the case whenever diff --git a/src/stage/timeline/ruler-track.cpp b/src/stage/timeline/ruler-track.cpp index 676072401..285a91965 100644 --- a/src/stage/timeline/ruler-track.cpp +++ b/src/stage/timeline/ruler-track.cpp @@ -34,7 +34,6 @@ #include "stage/gtk-base.hpp" #include "stage/style-scheme.hpp" /////////////////////TODO needed? #include "stage/timeline/ruler-track.hpp" -#include "stage/timeline/track-presenter.hpp" //#include "stage/ui-bus.hpp" //#include "lib/format-string.hpp"