Added remove track feature

This commit is contained in:
Joel Holdsworth 2008-12-20 14:31:11 +00:00
parent bc2fdc40e9
commit 992cd4d77b
10 changed files with 204 additions and 17 deletions

View file

@ -289,13 +289,20 @@ TimelineWidget::update_tracks()
{ {
REQUIRE(sequence); REQUIRE(sequence);
// Remove any tracks which are no longer present in the model
remove_orphaned_tracks();
// Create timeline tracks from all the model tracks // Create timeline tracks from all the model tracks
create_timeline_tracks(); create_timeline_tracks();
// Update the header container // Update the header container
ASSERT(headerContainer != NULL); ASSERT(headerContainer != NULL);
headerContainer->show_all_children();
headerContainer->update_headers(); headerContainer->update_headers();
// Update the body
body->queue_draw();
// Recalculate the total height of the timeline scrolled area // Recalculate the total height of the timeline scrolled area
totalHeight = 0; totalHeight = 0;
BOOST_FOREACH(shared_ptr<model::Track> track, BOOST_FOREACH(shared_ptr<model::Track> track,
@ -316,9 +323,6 @@ TimelineWidget::create_timeline_tracks()
BOOST_FOREACH(shared_ptr<model::Track> child, BOOST_FOREACH(shared_ptr<model::Track> child,
sequence->get_child_tracks()) sequence->get_child_tracks())
create_timeline_tracks_from_branch(child); create_timeline_tracks_from_branch(child);
headerContainer->show_all_children();
body->queue_draw();
} }
void void
@ -351,14 +355,59 @@ TimelineWidget::create_timeline_track_from_model_track(
// Choose a corresponding timeline track class from the model track's // Choose a corresponding timeline track class from the model track's
// class // class
if(typeid(*model_track) == typeid(model::ClipTrack)) if(typeid(*model_track) == typeid(model::ClipTrack))
return shared_ptr<timeline::Track>(new timeline::ClipTrack()); return shared_ptr<timeline::Track>(new timeline::ClipTrack(*this));
else if(typeid(*model_track) == typeid(model::GroupTrack)) else if(typeid(*model_track) == typeid(model::GroupTrack))
return shared_ptr<timeline::Track>(new timeline::GroupTrack()); return shared_ptr<timeline::Track>(new timeline::GroupTrack(*this));
ASSERT(NULL); // Unknown track type; ASSERT(NULL); // Unknown track type;
return shared_ptr<timeline::Track>(); return shared_ptr<timeline::Track>();
} }
void
TimelineWidget::remove_orphaned_tracks()
{
REQUIRE(sequence);
REQUIRE(headerContainer != NULL);
REQUIRE(body != NULL);
std::map<boost::shared_ptr<model::Track>,
boost::shared_ptr<timeline::Track> >
orphan_track_map(trackMap);
// Remove all tracks which are still present in the sequence
BOOST_FOREACH(shared_ptr<model::Track> child,
sequence->get_child_tracks())
search_orphaned_tracks_in_branch(child, orphan_track_map);
// orphan_track_map now contains all the orphaned tracks
// Remove them
std::pair<shared_ptr<model::Track>, shared_ptr<timeline::Track> >
pair;
BOOST_FOREACH( pair, orphan_track_map )
{
ENSURE(pair.first)
trackMap.erase(pair.first);
}
}
void
TimelineWidget::search_orphaned_tracks_in_branch(
boost::shared_ptr<model::Track> model_track,
std::map<boost::shared_ptr<model::Track>,
boost::shared_ptr<timeline::Track> > &orphan_track_map)
{
REQUIRE(model_track);
// Is the timeline UI still present?
if(contains(orphan_track_map, model_track))
orphan_track_map.erase(model_track);
// Recurse to child tracks
BOOST_FOREACH(shared_ptr<model::Track> child,
model_track->get_child_tracks())
search_orphaned_tracks_in_branch(child, orphan_track_map);
}
shared_ptr<timeline::Track> shared_ptr<timeline::Track>
TimelineWidget::lookup_timeline_track( TimelineWidget::lookup_timeline_track(
shared_ptr<model::Track> model_track) const shared_ptr<model::Track> model_track) const
@ -379,6 +428,31 @@ TimelineWidget::lookup_timeline_track(
return iterator->second; return iterator->second;
} }
boost::shared_ptr<model::Track>
TimelineWidget::lookup_model_track(
const timeline::Track *timeline_track) const
{
REQUIRE(sequence);
std::pair<shared_ptr<model::Track>, shared_ptr<timeline::Track> >
pair;
BOOST_FOREACH( pair, trackMap )
{
if(pair.second.get() == timeline_track)
{
ENSURE(pair.first);
return pair.first;
}
}
// The track is not present in the map
// We are in an error condition if the timeline track is not found
// - the timeline tracks must always be synchronous with the model
// tracks.
ENSURE(0);
return shared_ptr<model::Track>();
}
void void
TimelineWidget::update_scroll() TimelineWidget::update_scroll()
{ {

View file

@ -191,10 +191,21 @@ private:
* @return The timeline track created, or an empty shared_ptr if * @return The timeline track created, or an empty shared_ptr if
* model_track has an unreckognised type (this is an error condition). * model_track has an unreckognised type (this is an error condition).
**/ **/
static boost::shared_ptr<timeline::Track> boost::shared_ptr<timeline::Track>
create_timeline_track_from_model_track( create_timeline_track_from_model_track(
boost::shared_ptr<model::Track> model_track); boost::shared_ptr<model::Track> model_track);
/**
* Removes any UI tracks which no longer have corresponding model
* tracks present in the sequence.
**/
void remove_orphaned_tracks();
void search_orphaned_tracks_in_branch(
boost::shared_ptr<model::Track> model_track,
std::map<boost::shared_ptr<model::Track>,
boost::shared_ptr<timeline::Track> > &orphan_track_map);
/** /**
* Looks up a timeline UI track in trackMap that corresponds to a * Looks up a timeline UI track in trackMap that corresponds to a
* given model_track. * given model_track.
@ -206,6 +217,17 @@ private:
boost::shared_ptr<timeline::Track> lookup_timeline_track( boost::shared_ptr<timeline::Track> lookup_timeline_track(
boost::shared_ptr<model::Track> model_track) const; boost::shared_ptr<model::Track> model_track) const;
/**
* Looks up a model track in trackMap that corresponds to a
* given timeline track.
* @param timeline_track The timeline UI track to look up.
* @returns The model track found, or an empty shared_ptr if
* timeline_track has no corresponding timeline UI track (this is an
* error condition).
**/
boost::shared_ptr<model::Track> lookup_model_track(
const timeline::Track *timeline_track) const;
// ----- Layout Functions ----- // // ----- Layout Functions ----- //
void update_scroll(); void update_scroll();
@ -305,6 +327,7 @@ protected:
friend class timeline::Tool; friend class timeline::Tool;
friend class timeline::ArrowTool; friend class timeline::ArrowTool;
friend class timeline::IBeamTool; friend class timeline::IBeamTool;
friend class timeline::Track;
}; };
} // namespace widgets } // namespace widgets

View file

@ -29,7 +29,8 @@ namespace gui {
namespace widgets { namespace widgets {
namespace timeline { namespace timeline {
ClipTrack::ClipTrack() ClipTrack::ClipTrack(TimelineWidget &timeline_widget) :
Track(timeline_widget)
{ {
} }

View file

@ -41,7 +41,7 @@ class TimelineViewWindow;
class ClipTrack : public timeline::Track class ClipTrack : public timeline::Track
{ {
public: public:
ClipTrack(); ClipTrack(TimelineWidget &timeline_widget);
void draw_track(Cairo::RefPtr<Cairo::Context> cairo, void draw_track(Cairo::RefPtr<Cairo::Context> cairo,
TimelineViewWindow* const window) const; TimelineViewWindow* const window) const;

View file

@ -28,7 +28,8 @@ namespace gui {
namespace widgets { namespace widgets {
namespace timeline { namespace timeline {
GroupTrack::GroupTrack() GroupTrack::GroupTrack(TimelineWidget &timeline_widget) :
Track(timeline_widget)
{ {
} }

View file

@ -36,7 +36,7 @@ namespace timeline {
class GroupTrack : public timeline::Track class GroupTrack : public timeline::Track
{ {
public: public:
GroupTrack(); GroupTrack(TimelineWidget &timeline_widget);
void draw_track(Cairo::RefPtr<Cairo::Context> cairo, void draw_track(Cairo::RefPtr<Cairo::Context> cairo,
TimelineViewWindow* constwindow) TimelineViewWindow* constwindow)

View file

@ -150,11 +150,25 @@ bool TimelineHeaderContainer::on_button_press_event (
break; break;
case 3: // Right Click case 3: // Right Click
{
// Popup the context menu // Popup the context menu
shared_ptr<Track> header = header_from_point(
Gdk::Point(event->x, event->y));
// Are we hovering on a header?
if(header)
{
// Yes - show the header's context menu
header->show_header_context_menu(
event->button, event->time);
}
else
{
// No - show the default context menu
contextMenu.popup(event->button, event->time); contextMenu.popup(event->button, event->time);
}
break; break;
}
} }
return true; return true;
@ -239,6 +253,12 @@ TimelineHeaderContainer::forall_vfunc(gboolean /* include_internals */,
} }
} }
void
TimelineHeaderContainer::on_remove(Widget* widget)
{
// Do nothing - this is just to keep Gtk::Container happy
}
bool bool
TimelineHeaderContainer::on_expose_event(GdkEventExpose *event) TimelineHeaderContainer::on_expose_event(GdkEventExpose *event)
{ {
@ -477,6 +497,25 @@ TimelineHeaderContainer::draw_header_decoration(
draw_header_decoration(child, clip_rect); draw_header_decoration(child, clip_rect);
} }
boost::shared_ptr<timeline::Track>
TimelineHeaderContainer::header_from_point(const Gdk::Point &point)
{
std::pair<shared_ptr<timeline::Track>, Gdk::Rectangle> pair;
BOOST_FOREACH( pair, headerBoxes )
{
// Hit test the rectangle
const Gdk::Rectangle &rect = pair.second;
if(point.get_x() >= rect.get_x() &&
point.get_x() < rect.get_x() + rect.get_width() &&
point.get_y() >= rect.get_y() &&
point.get_y() < rect.get_y() + rect.get_height())
return pair.first;
}
return shared_ptr<timeline::Track>();
}
shared_ptr<timeline::Track> shared_ptr<timeline::Track>
TimelineHeaderContainer::expander_button_from_point( TimelineHeaderContainer::expander_button_from_point(
const Gdk::Point &point) const Gdk::Point &point)

View file

@ -119,6 +119,12 @@ private:
void forall_vfunc(gboolean include_internals, GtkCallback callback, void forall_vfunc(gboolean include_internals, GtkCallback callback,
gpointer callback_data); gpointer callback_data);
/**
* An event handler that is called when a widget is removed from the
* container.
**/
void on_remove(Widget* widget);
/* ===== Events ===== */ /* ===== Events ===== */
private: private:
@ -194,6 +200,9 @@ private:
boost::shared_ptr<model::Track> model_track, boost::shared_ptr<model::Track> model_track,
const Gdk::Rectangle &clip_rect); const Gdk::Rectangle &clip_rect);
boost::shared_ptr<timeline::Track> header_from_point(
const Gdk::Point &point);
/** /**
* Given a point, expander_button_from_point finds the track of the * Given a point, expander_button_from_point finds the track of the
* expand button that this point is hovering over, if there is one. * expand button that this point is hovering over, if there is one.
@ -297,6 +306,8 @@ private:
* in pixels. * in pixels.
**/ **/
int expand_button_size; int expand_button_size;
friend class timeline::Track;
}; };
} // namespace timeline } // namespace timeline

View file

@ -24,15 +24,18 @@
#include <gtk/gtktoolbar.h> #include <gtk/gtktoolbar.h>
#include "timeline-track.hpp" #include "timeline-track.hpp"
#include "../timeline-widget.hpp"
#include "../../window-manager.hpp" #include "../../window-manager.hpp"
using namespace boost;
using namespace Gtk; using namespace Gtk;
namespace gui { namespace gui {
namespace widgets { namespace widgets {
namespace timeline { namespace timeline {
Track::Track() : Track::Track(TimelineWidget &timeline_widget) :
timelineWidget(timeline_widget),
expanded(true), expanded(true),
enableButton(Gtk::StockID("track_enabled")), enableButton(Gtk::StockID("track_enabled")),
lockButton(Gtk::StockID("track_unlocked")) lockButton(Gtk::StockID("track_unlocked"))
@ -54,6 +57,14 @@ Track::Track() :
headerWidget.pack_start(titleBox, PACK_SHRINK); headerWidget.pack_start(titleBox, PACK_SHRINK);
headerWidget.pack_start(buttonBar, PACK_SHRINK); headerWidget.pack_start(buttonBar, PACK_SHRINK);
// Setup the context menu
Menu::MenuList& menu_list = contextMenu.items();
menu_list.push_back( Menu_Helpers::MenuElem(_("_Add Track"),
sigc::mem_fun(timelineWidget,
&TimelineWidget::on_add_track_command) ) );
menu_list.push_back( Menu_Helpers::MenuElem(_("_Remove Track"),
sigc::mem_fun(this, &Track::on_remove_track) ) );
} }
Gtk::Widget& Gtk::Widget&
@ -80,6 +91,23 @@ Track::set_expanded(bool expanded)
this->expanded = expanded; this->expanded = expanded;
} }
void
Track::show_header_context_menu(guint button, guint32 time)
{
contextMenu.popup(button, time);
}
void
Track::on_remove_track()
{
shared_ptr<model::Track> model_track =
timelineWidget.lookup_model_track(this);
ASSERT(model_track);
ASSERT(timelineWidget.sequence);
timelineWidget.sequence->get_child_track_list().remove(model_track);
}
} // namespace timeline } // namespace timeline
} // namespace widgets } // namespace widgets
} // namespace gui } // namespace gui

View file

@ -25,6 +25,7 @@
#include "../../gtk-lumiera.hpp" #include "../../gtk-lumiera.hpp"
#include "../../model/track.hpp" #include "../../model/track.hpp"
#include "timeline-header-container.hpp"
#ifndef TIMELINE_TRACK_HPP #ifndef TIMELINE_TRACK_HPP
#define TIMELINE_TRACK_HPP #define TIMELINE_TRACK_HPP
@ -38,7 +39,7 @@ class TimelineViewWindow;
class Track class Track
{ {
public: public:
Track(); Track(TimelineWidget &timeline_widget);
Gtk::Widget& get_header_widget(); Gtk::Widget& get_header_widget();
@ -48,11 +49,18 @@ public:
void set_expanded(bool expanded); void set_expanded(bool expanded);
void show_header_context_menu(guint button, guint32 time);
virtual void draw_track(Cairo::RefPtr<Cairo::Context> cairo, virtual void draw_track(Cairo::RefPtr<Cairo::Context> cairo,
TimelineViewWindow* const window) TimelineViewWindow* const window)
const = 0; const = 0;
private: private:
void on_remove_track();
private:
TimelineWidget &timelineWidget;
bool expanded; bool expanded;
@ -65,6 +73,8 @@ private:
Gtk::Entry titleBox; Gtk::Entry titleBox;
Gtk::Toolbar buttonBar; Gtk::Toolbar buttonBar;
Gtk::Menu contextMenu;
}; };