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
This commit is contained in:
parent
98a675e54c
commit
d4b1735013
4 changed files with 123 additions and 209 deletions
|
|
@ -1,181 +0,0 @@
|
|||
/*
|
||||
ClipPresenter - presentation control element for a clip within the timeline
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2016, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
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 <algorithm>
|
||||
//#include <vector>
|
||||
|
||||
|
||||
|
||||
//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<TimeSpan> 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<ClipPresenter>;
|
||||
using PEffect = unique_ptr<ClipPresenter>;
|
||||
using PMarker = unique_ptr<MarkerWidget>;
|
||||
|
||||
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<MarkerWidget> (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<TimeSpan> timing = spec.retrieveAttribute<TimeSpan> (string{ATTR_timing});
|
||||
return make_unique<ClipPresenter> (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<ClipPresenter> (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<TimeSpan> 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
|
||||
|
|
@ -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<TimeSpan> 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<TimeSpan> 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<ClipPresenter>;
|
||||
using PEffect = unique_ptr<ClipPresenter>;
|
||||
using PMarker = unique_ptr<MarkerWidget>;
|
||||
|
||||
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<MarkerWidget> (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<TimeSpan> timing = spec.retrieveAttribute<TimeSpan> (string{ATTR_timing});
|
||||
return make_unique<ClipPresenter> (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<ClipPresenter> (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<TimeSpan> const& timing =nullopt);
|
||||
void
|
||||
establishAppearance(WidgetHook* newView =nullptr,
|
||||
optional<TimeSpan> 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");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in a new issue