diff --git a/SConstruct b/SConstruct index 250936bc7..318f3f53c 100644 --- a/SConstruct +++ b/SConstruct @@ -254,8 +254,10 @@ def configurePlatform(env): problems.append('We need boost::format (header).') if not conf.CheckLibWithHeader('boost_program_options-mt','boost/program_options.hpp','C++'): problems.append('We need boost::program_options (including binary lib for linking).') + if not conf.CheckLibWithHeader('boost_system-mt','boost/system/error_code.hpp','C++'): + problems.append('We need the boost::system support library (including binary lib).') if not conf.CheckLibWithHeader('boost_filesystem-mt','boost/filesystem.hpp','C++'): - problems.append('We need the boost::filesystem (including binary lib for linking).') + problems.append('We need the boost::filesystem lib (including binary lib for linking).') if not conf.CheckLibWithHeader('boost_regex-mt','boost/regex.hpp','C++'): problems.append('We need the boost regular expression lib (incl. binary lib for linking).') diff --git a/doc/devel/uml/fig130309.png b/doc/devel/uml/fig130309.png index d63c8432b..6afb6d279 100644 Binary files a/doc/devel/uml/fig130309.png and b/doc/devel/uml/fig130309.png differ diff --git a/doc/devel/uml/fig130437.png b/doc/devel/uml/fig130437.png index e12e4b48b..925723480 100644 Binary files a/doc/devel/uml/fig130437.png and b/doc/devel/uml/fig130437.png differ diff --git a/doc/devel/uml/fig131205.png b/doc/devel/uml/fig131205.png index 17826d19b..5d46c3249 100644 Binary files a/doc/devel/uml/fig131205.png and b/doc/devel/uml/fig131205.png differ diff --git a/doc/devel/uml/fig142725.png b/doc/devel/uml/fig142725.png index 6e8c570d8..91c795876 100644 Binary files a/doc/devel/uml/fig142725.png and b/doc/devel/uml/fig142725.png differ diff --git a/doc/devel/uml/fig143877.png b/doc/devel/uml/fig143877.png new file mode 100644 index 000000000..1e628bc41 Binary files /dev/null and b/doc/devel/uml/fig143877.png differ diff --git a/doc/devel/uml/fig144005.png b/doc/devel/uml/fig144005.png new file mode 100644 index 000000000..6ca73fc49 Binary files /dev/null and b/doc/devel/uml/fig144005.png differ diff --git a/doc/devel/uml/fig145157.png b/doc/devel/uml/fig145157.png new file mode 100644 index 000000000..dac8e23cb Binary files /dev/null and b/doc/devel/uml/fig145157.png differ diff --git a/src/proc/engine/trafo.cpp b/src/backend/engine/scheduler-frontend.cpp similarity index 74% rename from src/proc/engine/trafo.cpp rename to src/backend/engine/scheduler-frontend.cpp index 636e59e4e..3cf1698ab 100644 --- a/src/proc/engine/trafo.cpp +++ b/src/backend/engine/scheduler-frontend.cpp @@ -1,8 +1,8 @@ /* - Trafo - transforming processing Node + SchedulerFrontend - access point to the scheduler within the renderengine Copyright (C) Lumiera.org - 2008, Hermann Vosseler + 2011, 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 @@ -21,13 +21,14 @@ * *****************************************************/ -#include "proc/engine/trafo.hpp" - -namespace engine - { +#include "backend/engine/scheduler-frontend.hpp" +namespace backend{ +namespace engine { + + /** */ - - - -} // namespace engine + + + +}} // namespace backend::engine diff --git a/src/backend/engine/scheduler-frontend.hpp b/src/backend/engine/scheduler-frontend.hpp new file mode 100644 index 000000000..887435191 --- /dev/null +++ b/src/backend/engine/scheduler-frontend.hpp @@ -0,0 +1,55 @@ +/* + SCHEDULER-FRONTEND.hpp - access point to the scheduler within the renderengine + + Copyright (C) Lumiera.org + 2011, 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. + +*/ + + +#ifndef BACKEND_ENGINE_SCHEDULER_FRONTEND_H +#define BACKEND_ENGINE_SCHEDULER_FRONTEND_H + + + +//using std::list; + + +namespace backend{ +namespace engine { + + + /** + * @todo this is planned to become the frontend + * to the render node network, which can be considered + * at the lower end of the middle layer; the actual + * render operations are mostly implemented by the backend + * ////////TODO WIP as of 12/2010 + */ + class SchedulerFrontend + { + public: + ///// TODO: find out about the public operations + // note: the play controller lives in the proc-layer, + // but is a subsystem separate of the sesison. + + private: + + }; + +}} // namespace backend::engine +#endif diff --git a/src/backend/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp index 60413b037..699bfd11d 100644 --- a/src/backend/thread-wrapper.hpp +++ b/src/backend/thread-wrapper.hpp @@ -200,7 +200,7 @@ namespace backend { /** Synchronisation barrier. In the function executing in this thread - * needs to be a corresponding Thread::sync() call. Blocking until + * needs to be a corresponding Thread::syncPoint() call. Blocking until * both the caller and the thread have reached the barrier. */ void diff --git a/src/common/guifacade.cpp b/src/common/guifacade.cpp index aff7febb8..5e1c4599d 100644 --- a/src/common/guifacade.cpp +++ b/src/common/guifacade.cpp @@ -156,7 +156,7 @@ namespace gui { if (facade) { WARN (guifacade, "GUI subsystem terminates, but GuiFacade isn't properly closed. " - "Closing it forcedly; this indicates broken startup logic and should be fixed."); + "Closing it forcedly; this indicates broken startup logic and should be fixed."); try { facade.reset (0); } catch(...) { WARN_IF (lumiera_error_peek(), guifacade, "Ignoring error: %s", lumiera_error()); } lumiera_error(); // clear any remaining error state... diff --git a/src/common/instancehandle.hpp b/src/common/instancehandle.hpp index d6c98e546..9f8004c65 100644 --- a/src/common/instancehandle.hpp +++ b/src/common/instancehandle.hpp @@ -184,7 +184,7 @@ namespace lumiera { public: /** Set up an InstanceHandle representing a plugin. - * Should be placed at the client side. + * Should be placed at the client side. * @param iName unmangled name of the interface * @param version major version * @param minminor minimum acceptable minor version number @@ -203,7 +203,7 @@ namespace lumiera { * registration and deregistration of interface(s). * Should be placed at the service providing side. * @param a (single) interface descriptor, which can be created with - * LUMIERA_INTERFACE_INSTANCE and referred to by LUMIERA_INTERFACE_REF + * LUMIERA_INTERFACE_INSTANCE and referred to by LUMIERA_INTERFACE_REF */ InstanceHandle (LumieraInterface descriptor) : desc_(descriptor) @@ -222,9 +222,9 @@ namespace lumiera { - /** act as smart pointer providing access through the facade. + /** act as smart pointer providing access through the facade. * @note we don't provide operator* */ - FA * operator-> () const { return &(facadeLink_(*this)); } + FA * operator-> () const { return &(facadeLink_(*this)); } /** directly access the instance via the CL interface */ I& get () const { ENSURE(instance_); return *instance_; } diff --git a/src/common/interface-facade-link.hpp b/src/common/interface-facade-link.hpp new file mode 100644 index 000000000..27c0826c9 --- /dev/null +++ b/src/common/interface-facade-link.hpp @@ -0,0 +1,123 @@ +/* + INTERFACE-FACADE-LINK - a switchable link from interface to service implementation + + Copyright (C) Lumiera.org + 2011, 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 interface-facade-link.hpp + ** Opening, accessing and closing the service access through a facade interface. + ** Client code is assumed to access an application level service through an facade + ** interface, while the actual implementation object remains an opaque internal detail. + ** Moreover, services may come up and shut down, so the implementation might change + ** during the Lifecycle. The facility defined here in this header provides a basic + ** implementation for this access mechanism, but without any adaptation, binding + ** or plugin access layer. It works only under the assumption that both the + ** interface and the actual service implementation coexist in the same + ** executable and are written in C++, so any invocation of an + ** interface method boils down to a language-level call. + ** + ** Usually, client code doesn't need to include this header. Clients are assumed + ** to use the facade interface of the service in question. This facade interface + ** contains a static member of type \c lumiera::facade::Accessor (where I is + ** the type of the facade interface). The Accessor baseclass is defined in + ** interfaceproxy.hpp and typically included through the facade header. + ** + ** @note there is a way more elaborate implementation of the same mechanism + ** for use with the Lumiera Interface/Plugin system. + ** + ** @see interfaceproxy.hpp description of the more general use case + ** @see PlayService example for the simple use case + */ + + +#ifndef LUMIERA_FACADE_INTERFACE_FACADE_LINK_H +#define LUMIERA_FACADE_INTERFACE_FACADE_LINK_H + + +#include "lib/error.hpp" +#include "lib/test/test-helper.hpp" +#include "include/interfaceproxy.hpp" +#include "lib/symbol.hpp" + +#include + + + +namespace lumiera { +namespace facade { + + using lib::Literal; + + + /************************************************************************ + * simple access-frontend to the implementation of a service (C++ only). + * Usually, an instance of Accessor is placed as static member right into + * the facade interface used to access the service. This implementation + * of the access mechanism handles the simple case that both the facade + * and the service implementation are written in C++ and calls happen + * within the main executable as direct language calls, without an + * binding layer and without involving the Interface/Plugin system. + * + * Typically, the InterfaceFacadeLink becomes a member of the service + * implementation class and is directly tied into the constructor of + * the latter. Being a subclass of lumiera::facade::Accessor, it is + * allowed to "open" the facade access just by setting the static + * protected pointer Accessor::implProxy_ + */ + template + class InterfaceFacadeLink + : protected Accessor + , boost::noncopyable + { + Literal displayName_; + + void + __checkLifecycle () + { + if (Accessor::implProxy_) + throw error::State("Attempt to open an already opened Facade interface." + , error::LUMIERA_ERROR_LIFECYCLE); + } + + public: + InterfaceFacadeLink(FA& serviceImpl, Literal interfaceName_for_Log=0) + : displayName_(lib::test::showType(interfaceName_for_Log)) + { + __checkLifecycle(); + Accessor::implProxy_ = &serviceImpl; + INFO (interface, "interface %s opened", displayName_.c()); + } + + ~InterfaceFacadeLink() + { + INFO (interface, "closing interface %s...", displayName_.c()); + Accessor::implProxy_ = 0; + } + }; + + + + /** storage for the static access pointer */ + template + FA* Accessor::implProxy_; + + +}} // namespace lumiera::facade + +#endif diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index e403e40a5..814f991b4 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -28,73 +28,87 @@ using util::cStr; -namespace lumiera { - namespace facade { - - - LUMIERA_ERROR_DEFINE (FACADE_LIFECYCLE, "facade interface currently not accessible"); - - - template - class Holder; - - template - class Holder > - : Accessor, - protected FA - { - protected: - typedef InstanceHandle IHandle; - typedef Holder THolder; - typedef Proxy TProxy; - typedef Accessor Access; - - I& _i_; - - Holder (IHandle const& iha) - : _i_(iha.get()) - { } - - public: - static TProxy& open(IHandle const& iha) - { - static char buff[sizeof(TProxy)]; - TProxy* p = new(buff) TProxy(iha); - Access::implProxy_ = p; - return *p; - } - - static void close() - { - if (!Access::implProxy_) return; - TProxy* p = static_cast (Access::implProxy_); - Access::implProxy_ = 0; - p->~TProxy(); - } - }; - - - template - FA* Accessor::implProxy_; - - - template - void - openProxy (IHA const& iha) - { - Proxy::open(iha); - } - - template - void - closeProxy () - { - Proxy::close(); - } - - } // namespace facade +namespace lumiera{ +namespace facade { -} // namespace lumiera + + LUMIERA_ERROR_DEFINE (FACADE_LIFECYCLE, "facade is closed; service currently not accessible"); + + + /** + * Implementation Base + * for building Facade Proxy implementations. + * Typically the purpose of such a proxy is to route + * any calls through the C-Bindings of the Lumiera Interface system. + * The actual storage for the concrete proxy object is embedded, + * inline within the #open() function. For access by the clients, + * a frontend-object of type \c Accessor may be placed into + * the facade interface; this accessor-frontend is basically + * a concealed static pointer to the proxy, and will be set, + * when the interface is opened. This opening and closing + * of the interface itself is controlled by the + * InstanceHandle, which in turn is typically + * created and managed within the context + * of the service implementation. + */ + template + class Holder; + + template + class Holder > + : Accessor + , protected FA + { + protected: + typedef InstanceHandle IHandle; + typedef Holder THolder; + typedef Proxy TProxy; + typedef Accessor Access; + + I& _i_; + + Holder (IHandle const& iha) + : _i_(iha.get()) + { } + + public: + static TProxy& open(IHandle const& iha) + { + static char buff[sizeof(TProxy)]; + TProxy* p = new(buff) TProxy(iha); + Access::implProxy_ = p; + return *p; + } + + static void close() + { + if (!Access::implProxy_) return; + TProxy* p = static_cast (Access::implProxy_); + Access::implProxy_ = 0; + p->~TProxy(); + } + }; + + + template + FA* Accessor::implProxy_; + + + template + void + openProxy (IHA const& iha) + { + Proxy::open(iha); + } + + template + void + closeProxy () + { + Proxy::close(); + } + +}} // namespace lumiera::facade diff --git a/src/common/subsys.hpp b/src/common/subsys.hpp index 363b17e51..26b080861 100644 --- a/src/common/subsys.hpp +++ b/src/common/subsys.hpp @@ -104,9 +104,12 @@ namespace lumiera { /** initiate termination of this subsystem. - * may be called repeatedly any time... - * @warning must not block nor throw. */ - virtual void triggerShutdown () throw() =0; + * This trigger may be called repeatedly any time... + * When the subsystem actually has terminated, + * the SigTerm passed to #start must be invoked. + * @note called within a locked context (barrier) + * @warning must not block nor throw. */ + virtual void triggerShutdown () throw() =0; const std::vector @@ -114,7 +117,7 @@ namespace lumiera { private: - /** weather this subsystem is actually operational. + /** whether this subsystem is actually operational. * When returning \c false here, the application may * terminate at any point without further notice * Note further, that a subsystem must not be in diff --git a/src/common/subsystem-runner.hpp b/src/common/subsystem-runner.hpp index 89a90245d..6cbd3495a 100644 --- a/src/common/subsystem-runner.hpp +++ b/src/common/subsystem-runner.hpp @@ -173,7 +173,7 @@ namespace lumiera { if (!and_all (susy->getPrerequisites(), isRunning() )) { susy->triggerShutdown(); - throw error::Logic("Unable to start all prerequisites of Subsystem "+string(*susy)); + throw error::State("Unable to start all prerequisites of Subsystem "+string(*susy)); } } void diff --git a/src/gui/display-service.hpp b/src/gui/display-service.hpp index 1dec2c192..1c5cda79f 100644 --- a/src/gui/display-service.hpp +++ b/src/gui/display-service.hpp @@ -50,6 +50,7 @@ #include "common/instancehandle.hpp" #include "lib/singleton-ref.hpp" #include "lib/scoped-ptrvect.hpp" +#include "include/logging.h" #include #include diff --git a/src/gui/panels/timeline-panel.cpp b/src/gui/panels/timeline-panel.cpp index 07dce7b1d..6f755f25c 100644 --- a/src/gui/panels/timeline-panel.cpp +++ b/src/gui/panels/timeline-panel.cpp @@ -23,10 +23,12 @@ #include "gui/gtk-lumiera.hpp" #include "gui/panels/timeline-panel.hpp" +#include "gui/widgets/timeline/timeline-zoom-scale.hpp" #include "gui/workspace/workspace-window.hpp" #include "gui/model/project.hpp" #include "gui/controller/controller.hpp" + #include "lib/util.hpp" #include @@ -34,6 +36,7 @@ using namespace Gtk; using namespace sigc; using namespace gui::widgets; +using namespace gui::widgets::timeline; using namespace gui::model; using boost::shared_ptr; ///////////////////////////////TICKET #796 @@ -60,6 +63,7 @@ TimelinePanel::TimelinePanel (workspace::PanelManager &panel_manager, , iBeamTool(Gtk::StockID("tool_i_beam")) , zoomIn(Stock::ZOOM_IN) , zoomOut(Stock::ZOOM_OUT) + , zoomScale() , updatingToolbar(false) , currentTool(timeline::Arrow) { @@ -101,14 +105,15 @@ TimelinePanel::TimelinePanel (workspace::PanelManager &panel_manager, toolbar.append(separator2); - toolbar.append(zoomIn, mem_fun(this, &TimelinePanel::on_zoom_in)); - toolbar.append(zoomOut, mem_fun(this, &TimelinePanel::on_zoom_out)); - + toolbar.append(zoomScale); + zoomScale.signal_zoom(). + connect(mem_fun(this,&TimelinePanel::on_zoom)); + toolbar.show_all(); panelBar.pack_start(toolbar, PACK_SHRINK); // Setup tooltips - sequenceChooser .set_tooltip_text(_("Change sequence")); + sequenceChooser .set_tooltip_text(_("Change sequence")); previousButton .set_tooltip_text(_("To beginning")); rewindButton .set_tooltip_text(_("Rewind")); @@ -122,12 +127,18 @@ TimelinePanel::TimelinePanel (workspace::PanelManager &panel_manager, zoomIn .set_tooltip_text(_("Zoom in")); zoomOut .set_tooltip_text(_("Zoom out")); + zoomScale .set_tooltip_text(_("Adjust timeline zoom scale")); // Setup the timeline widget - shared_ptr sequence ///////////////////////////////TICKET #796 + shared_ptr sequence ///////////////////////////////TICKET #796 : should use std::tr1::shared_ptr instead of boost = *get_project().get_sequences().begin(); timelineWidget.reset(new TimelineWidget(load_state(sequence))); pack_start(*timelineWidget, PACK_EXPAND_WIDGET); + + // since TimelineWidget is now initialised, + // wire the zoom slider to react on timeline state changes + zoomScale.wireTimelineState (timelineWidget->get_state(), + timelineWidget->state_changed_signal()); // Set the initial UI state update_sequence_chooser(); @@ -136,7 +147,6 @@ TimelinePanel::TimelinePanel (workspace::PanelManager &panel_manager, show_time (Time::ZERO); } - const char* TimelinePanel::get_title() { @@ -183,6 +193,13 @@ TimelinePanel::on_ibeam_tool() set_tool(timeline::IBeam); } +void +TimelinePanel::on_zoom(double time_scale_ratio) +{ + REQUIRE(timelineWidget); + timelineWidget->zoom_view(time_scale_ratio); +} + void TimelinePanel::on_zoom_in() { @@ -236,18 +253,19 @@ TimelinePanel::on_sequence_chosen() { weak_ptr sequence_ptr = (*iter)[sequenceChooserColumns.sequenceColumn]; + shared_ptr sequence(sequence_ptr.lock()); + if(sequence) { shared_ptr old_state( timelineWidget->get_state()); REQUIRE(old_state); - if(sequence != old_state->get_sequence()) timelineWidget->set_state(load_state(sequence)); } } - + update_zoom_buttons(); } @@ -379,9 +397,10 @@ TimelinePanel::on_frame() shared_ptr TimelinePanel::load_state(weak_ptr sequence) { + /* state exists */ if(contains(timelineStates, sequence)) - return timelineStates[sequence]; - + return timelineStates[sequence]; + shared_ptr shared_sequence = sequence.lock(); if(shared_sequence) { diff --git a/src/gui/panels/timeline-panel.hpp b/src/gui/panels/timeline-panel.hpp index b65469bc9..2215c8657 100644 --- a/src/gui/panels/timeline-panel.hpp +++ b/src/gui/panels/timeline-panel.hpp @@ -32,6 +32,8 @@ #include "gui/panels/panel.hpp" #include "gui/widgets/timecode-widget.hpp" #include "gui/widgets/timeline-widget.hpp" +#include "gui/widgets/timeline/timeline-zoom-scale.hpp" + #include "lib/time/timevalue.hpp" #include @@ -87,6 +89,7 @@ private: void on_arrow_tool(); void on_ibeam_tool(); + void on_zoom(double time_scale_ratio); void on_zoom_in(); void on_zoom_out(); @@ -171,7 +174,7 @@ private: boost::scoped_ptr timelineWidget; std::map< boost::weak_ptr, - boost::shared_ptr > ///////////////////////////////TICKET #796 + boost::shared_ptr > ///////////////////////////////TICKET #796 : should use std::tr1::shared_ptr timelineStates; // Toolbar Widgets @@ -191,6 +194,7 @@ private: MiniButton zoomIn; MiniButton zoomOut; + gui::widgets::timeline::TimelineZoomScale zoomScale; Gtk::SeparatorToolItem separator2; diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index a00882b7e..eb4decffa 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -41,7 +41,7 @@ const int TimelineWidget::TrackPadding = 1; const int TimelineWidget::HeaderWidth = 150; const int TimelineWidget::HeaderIndentWidth = 10; const double TimelineWidget::ZoomIncrement = 1.25; -const int64_t TimelineWidget::MaxScale = 30000000; +const int64_t TimelineWidget::MaxScale = 30000000; // 30 Million TimelineWidget::TimelineWidget( boost::shared_ptr source_state) : @@ -102,6 +102,7 @@ TimelineWidget::get_state() void TimelineWidget::set_state(shared_ptr new_state) { + state = new_state; // Clear the track tree @@ -125,17 +126,17 @@ TimelineWidget::set_state(shared_ptr new_state) update_tracks(); // Send the state changed signal - stateChangedSignal.emit(); + stateChangedSignal.emit (state); } void -TimelineWidget::zoom_view(int zoom_size) +TimelineWidget::zoom_view(double timescale_ratio) { if(state) - { - const int view_width = body->get_allocation().get_width(); - state->get_view_window().zoom_view(view_width / 2, zoom_size); - } + { + const int view_width = body->get_allocation().get_width(); + state->get_view_window().zoom_view(view_width / 2, timescale_ratio); + } } ToolType @@ -178,7 +179,7 @@ TimelineWidget::hovering_track_changed_signal() const return hoveringTrackChangedSignal; } -sigc::signal +TimelineWidget::TimelineStateChangeSignal TimelineWidget::state_changed_signal() const { return stateChangedSignal; @@ -212,10 +213,12 @@ TimelineWidget::on_view_window_changed() if(state) { timeline::TimelineViewWindow &window = state->get_view_window(); + const int view_width = body->get_allocation().get_width(); - + horizontalAdjustment.set_page_size( window.get_time_scale() * view_width); + horizontalAdjustment.set_value(_raw(window.get_time_offset())); } } diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index ca213c15b..884598067 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -98,7 +98,7 @@ public: * @param zoom_size The number of steps to zoom by. The scale factor * is 1.25^(-zoom_size). */ - void zoom_view(int zoom_size); + void zoom_view(double timescale_ratio); /** * Gets the type of the tool currently active. @@ -115,14 +115,16 @@ public: public: /* ===== Signals ===== */ + typedef sigc::signal > TimelineStateChangeSignal; + typedef sigc::signal > HoveringTrackChangedSignal; + sigc::signal mouse_hover_signal() const; sigc::signal playback_period_drag_released_signal() const; - sigc::signal > - hovering_track_changed_signal() const; + HoveringTrackChangedSignal hovering_track_changed_signal() const; - sigc::signal state_changed_signal() const; + TimelineStateChangeSignal state_changed_signal() const; /* ===== Events ===== */ protected: @@ -275,9 +277,8 @@ protected: // Signals sigc::signal mouseHoverSignal; sigc::signal playbackPeriodDragReleasedSignal; - sigc::signal > - hoveringTrackChangedSignal; - sigc::signal stateChangedSignal; + HoveringTrackChangedSignal hoveringTrackChangedSignal; + TimelineStateChangeSignal stateChangedSignal; bool update_tracks_frozen; diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp index 7f78d0929..b64757477 100644 --- a/src/gui/widgets/timeline/timeline-body.cpp +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -39,6 +39,8 @@ using namespace lumiera; using gui::util::CairoUtil; +using boost::shared_ptr; ////////////////////TICKET #796 + namespace gui { namespace widgets { namespace timeline { @@ -61,7 +63,7 @@ TimelineBody::TimelineBody (TimelineWidget &timelineWidget) register_styles(); // Reset the state - on_state_changed(); + propagateStateChange(); } TimelineBody::~TimelineBody() @@ -69,6 +71,13 @@ TimelineBody::~TimelineBody() WARN_IF(!tool, gui, "An invalid tool pointer is unexpected here"); } +TimelineViewWindow& +TimelineBody::viewWindow() const +{ + REQUIRE(timelineState); + return timelineState->get_view_window(); +} + TimelineWidget& TimelineBody::getTimelineWidget () const { @@ -147,7 +156,7 @@ TimelineBody::on_expose_event(GdkEventExpose* event) // Makes sure the widget styles have been loaded read_styles(); - if(timelineWidget.get_state()) + if (timelineState) { // Prepare to render via cairo const Allocation allocation = get_allocation(); @@ -169,9 +178,9 @@ TimelineBody::on_scroll_event (GdkEventScroll* event) { REQUIRE(event != NULL); - if(timelineWidget.get_state()) + if (timelineState) { - TimelineViewWindow &window = view_window(); + TimelineViewWindow &window = viewWindow(); const Allocation allocation = get_allocation(); if(event->state & GDK_CONTROL_MASK) @@ -255,17 +264,16 @@ TimelineBody::on_motion_notify_event(GdkEventMotion *event) { REQUIRE(event != NULL); - if(timelineWidget.get_state()) + if (timelineState) { // Handle a middle-mouse drag if one is occuring switch(dragType) { case Shift: { - TimelineViewWindow &window = view_window(); - - /////////////////////////////TICKET# 795 : don't reach in from outside and manipulate internals of the timeline view! + /////////////////////////////TICKET #795 : don't reach in from outside and manipulate internals of the timeline view! ///////////////////////////// : either encapsulate this entirely here, or leave it to the timeline view! + TimelineViewWindow &window = viewWindow(); const int64_t scale = window.get_time_scale(); window.set_time_offset(beginShiftTimeOffset + TimeValue(scale * (mouseDownX - event->x))); @@ -294,12 +302,20 @@ TimelineBody::on_motion_notify_event(GdkEventMotion *event) } void -TimelineBody::on_state_changed() +TimelineBody::on_state_changed (shared_ptr newState) { - if(timelineWidget.get_state()) + REQUIRE (newState); + timelineState = newState; + propagateStateChange(); +} + +void +TimelineBody::propagateStateChange() +{ + if (timelineState) { // Connect up some events - view_window().changed_signal().connect( + viewWindow().changed_signal().connect( sigc::mem_fun(this, &TimelineBody::on_update_view) ); } @@ -373,7 +389,7 @@ TimelineBody::draw_track(Cairo::RefPtr cr, // Render the track cr->save(); - TimelineViewWindow &window = view_window(); + TimelineViewWindow &window = viewWindow(); timeline_track->draw_track(cr, &window); cr->restore(); } @@ -386,12 +402,11 @@ TimelineBody::draw_selection(Cairo::RefPtr cr) // Prepare const Allocation allocation = get_allocation(); - shared_ptr state = timelineWidget.get_state(); - REQUIRE(state); + REQUIRE(timelineState); - TimelineViewWindow const& window = state->get_view_window(); - const int start_x = window.time_to_x(state->getSelectionStart()); - const int end_x = window.time_to_x(state->getSelectionEnd()); + TimelineViewWindow const& window = timelineState->get_view_window(); + const int start_x = window.time_to_x(timelineState->getSelectionStart()); + const int end_x = window.time_to_x(timelineState->getSelectionEnd()); // Draw the cover if(end_x > 0 && start_x < allocation.get_width()) @@ -427,16 +442,13 @@ TimelineBody::draw_playback_point(Cairo::RefPtr cr) { REQUIRE(cr); - // Prepare - - shared_ptr state = timelineWidget.get_state(); - if(state) + if (timelineState) { - if (!state->isPlaying()) return; + if (!timelineState->isPlaying()) return; const Allocation allocation = get_allocation(); - Time point = state->getPlaybackPoint(); - const int x = view_window().time_to_x(point); + Time point = timelineState->getPlaybackPoint(); + const int x = viewWindow().time_to_x(point); // Set source cr->set_source(playbackPointColour); @@ -455,10 +467,10 @@ TimelineBody::draw_playback_point(Cairo::RefPtr cr) void TimelineBody::begin_shift_drag() { - if(timelineWidget.get_state()) + if (timelineState) { dragType = Shift; - beginShiftTimeOffset = view_window().get_time_offset(); + beginShiftTimeOffset = viewWindow().get_time_offset(); beginShiftVerticalOffset = get_vertical_offset(); } } @@ -475,14 +487,6 @@ TimelineBody::set_vertical_offset(int offset) timelineWidget.verticalAdjustment.set_value(offset); } -TimelineViewWindow& -TimelineBody::view_window() const -{ - shared_ptr state = timelineWidget.get_state(); - REQUIRE(state); - return state->get_view_window(); -} - void TimelineBody::register_styles() const { diff --git a/src/gui/widgets/timeline/timeline-body.hpp b/src/gui/widgets/timeline/timeline-body.hpp index 74b057738..aaf90cb2e 100644 --- a/src/gui/widgets/timeline/timeline-body.hpp +++ b/src/gui/widgets/timeline/timeline-body.hpp @@ -68,10 +68,7 @@ public: */ TimelineBody(gui::widgets::TimelineWidget &timeline_widget); - /** - * Destructor - */ - ~TimelineBody(); + virtual ~TimelineBody(); TimelineWidget& getTimelineWidget () const; @@ -125,13 +122,18 @@ protected: bool on_motion_notify_event(GdkEventMotion *event); /** - * The event handler for when the TimelineWidget's state object is - * replaced. + * The event handler for when the TimelineWidget's state is switched. */ - void on_state_changed(); + void on_state_changed (boost::shared_ptr newState); /* ===== Internals ===== */ private: + /** + * Access the current timeline view window + * @warning must not be called unless the TimlineWidget + * has a valid state. + */ + TimelineViewWindow& viewWindow() const; /** * Draws the timeline tracks. @@ -161,13 +163,9 @@ private: void set_vertical_offset(int offset); - /** - * A helper function to get the view window - * @remarks This function must not be called unless the TimlineWidget - * has a valid state. - */ - TimelineViewWindow& view_window() const; - + /** adjust to the new timeline state */ + void propagateStateChange(); + /** * Registers all the styles that this class will respond to. */ @@ -202,6 +200,8 @@ private: Cairo::RefPtr playbackPointColour; gui::widgets::TimelineWidget &timelineWidget; + boost::shared_ptr timelineState; ////////////////////TICKET #796 : should use std::tr1::shared_ptr + friend class Tool; friend class ArrowTool; diff --git a/src/gui/widgets/timeline/timeline-ruler.cpp b/src/gui/widgets/timeline/timeline-ruler.cpp index afc395710..03a866482 100644 --- a/src/gui/widgets/timeline/timeline-ruler.cpp +++ b/src/gui/widgets/timeline/timeline-ruler.cpp @@ -75,6 +75,14 @@ TimelineRuler::TimelineRuler (TimelineWidget &timeline_widget) register_styles(); } +TimelineViewWindow& +TimelineRuler::viewWindow() const +{ + REQUIRE(timelineState); + return timelineState->get_view_window(); +} + + void TimelineRuler::set_mouse_chevron_offset(int offset) { @@ -114,7 +122,7 @@ TimelineRuler::on_expose_event(GdkEventExpose* event) if(!window) return false; - if(timelineWidget.get_state()) + if (timelineState) { // Prepare to render via cairo const Allocation allocation = get_allocation(); @@ -160,11 +168,11 @@ TimelineRuler::on_button_press_event(GdkEventButton* event) { REQUIRE(event != NULL); - if(timelineWidget.get_state()) + if (timelineState) { if(event->button == 1) { - pinnedDragTime = view_window().x_to_time(event->x); + pinnedDragTime = viewWindow().x_to_time(event->x); isDragging = true; } } @@ -219,34 +227,40 @@ TimelineRuler::on_size_allocate(Gtk::Allocation& allocation) } void -TimelineRuler::on_state_changed() +TimelineRuler::on_state_changed (shared_ptr newState) { - if(timelineWidget.get_state()) - { - // Connect up some events - view_window().changed_signal().connect( - sigc::mem_fun(this, &TimelineRuler::on_update_view) ); - } - + REQUIRE (newState); + timelineState = newState; + + propagateStateChange(); +} + +void +TimelineRuler::propagateStateChange() +{ + // Connect up some events + viewWindow().changed_signal().connect( + sigc::mem_fun(this, &TimelineRuler::on_update_view) ); + // Redraw on_update_view(); } + + void TimelineRuler::set_leading_x(const int x) { - shared_ptr state = timelineWidget.get_state(); - - if(state) + if (timelineState) { - TimeVar newStartPoint (view_window().x_to_time(x)); + TimeVar newStartPoint (viewWindow().x_to_time(x)); Offset selectionLength (pinnedDragTime, newStartPoint); if (newStartPoint > pinnedDragTime) newStartPoint=pinnedDragTime; // use the smaller one as selection start - state->setPlaybackPeriod (Mutation::changeTime(newStartPoint) ); - state->setPlaybackPeriod (Mutation::changeDuration(selectionLength)); + timelineState->setPlaybackPeriod (Mutation::changeTime(newStartPoint) ); + timelineState->setPlaybackPeriod (Mutation::changeDuration(selectionLength)); //////////////////////////////////////////////////////TICKET #797 : this is cheesy. Should provide a single Mutation to change all at once ////////////////////TODO : code duplication with timeline-ibeam-tool 205 } @@ -260,7 +274,7 @@ TimelineRuler::draw_ruler(Cairo::RefPtr cr, REQUIRE(ruler_rect.get_width() > 0); REQUIRE(ruler_rect.get_height() > 0); - const TimelineViewWindow &window = view_window(); + const TimelineViewWindow &window = viewWindow(); const gavl_time_t left_offset = _raw(window.get_time_offset()); const int64_t time_scale = window.get_time_scale(); @@ -361,16 +375,15 @@ TimelineRuler::draw_selection(Cairo::RefPtr cr, REQUIRE(cr); REQUIRE(ruler_rect.get_width() > 0); REQUIRE(ruler_rect.get_height() > 0); + REQUIRE(timelineState); - shared_ptr state = timelineWidget.get_state(); - REQUIRE(state); - const TimelineViewWindow &window = state->get_view_window(); + const TimelineViewWindow &window = timelineState->get_view_window(); Glib::RefPtr