Added remove track feature
This commit is contained in:
parent
bc2fdc40e9
commit
992cd4d77b
10 changed files with 204 additions and 17 deletions
|
|
@ -289,13 +289,20 @@ TimelineWidget::update_tracks()
|
|||
{
|
||||
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();
|
||||
|
||||
// Update the header container
|
||||
ASSERT(headerContainer != NULL);
|
||||
headerContainer->show_all_children();
|
||||
headerContainer->update_headers();
|
||||
|
||||
// Update the body
|
||||
body->queue_draw();
|
||||
|
||||
// Recalculate the total height of the timeline scrolled area
|
||||
totalHeight = 0;
|
||||
BOOST_FOREACH(shared_ptr<model::Track> track,
|
||||
|
|
@ -316,9 +323,6 @@ TimelineWidget::create_timeline_tracks()
|
|||
BOOST_FOREACH(shared_ptr<model::Track> child,
|
||||
sequence->get_child_tracks())
|
||||
create_timeline_tracks_from_branch(child);
|
||||
|
||||
headerContainer->show_all_children();
|
||||
body->queue_draw();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -351,14 +355,59 @@ TimelineWidget::create_timeline_track_from_model_track(
|
|||
// Choose a corresponding timeline track class from the model track's
|
||||
// class
|
||||
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))
|
||||
return shared_ptr<timeline::Track>(new timeline::GroupTrack());
|
||||
return shared_ptr<timeline::Track>(new timeline::GroupTrack(*this));
|
||||
|
||||
ASSERT(NULL); // Unknown track type;
|
||||
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>
|
||||
TimelineWidget::lookup_timeline_track(
|
||||
shared_ptr<model::Track> model_track) const
|
||||
|
|
@ -378,7 +427,32 @@ TimelineWidget::lookup_timeline_track(
|
|||
ENSURE(iterator->second != NULL);
|
||||
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
|
||||
TimelineWidget::update_scroll()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -191,10 +191,21 @@ private:
|
|||
* @return The timeline track created, or an empty shared_ptr if
|
||||
* 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(
|
||||
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
|
||||
* given model_track.
|
||||
|
|
@ -205,6 +216,17 @@ private:
|
|||
**/
|
||||
boost::shared_ptr<timeline::Track> lookup_timeline_track(
|
||||
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 ----- //
|
||||
|
||||
|
|
@ -305,6 +327,7 @@ protected:
|
|||
friend class timeline::Tool;
|
||||
friend class timeline::ArrowTool;
|
||||
friend class timeline::IBeamTool;
|
||||
friend class timeline::Track;
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ namespace gui {
|
|||
namespace widgets {
|
||||
namespace timeline {
|
||||
|
||||
ClipTrack::ClipTrack()
|
||||
ClipTrack::ClipTrack(TimelineWidget &timeline_widget) :
|
||||
Track(timeline_widget)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class TimelineViewWindow;
|
|||
class ClipTrack : public timeline::Track
|
||||
{
|
||||
public:
|
||||
ClipTrack();
|
||||
ClipTrack(TimelineWidget &timeline_widget);
|
||||
|
||||
void draw_track(Cairo::RefPtr<Cairo::Context> cairo,
|
||||
TimelineViewWindow* const window) const;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ namespace gui {
|
|||
namespace widgets {
|
||||
namespace timeline {
|
||||
|
||||
GroupTrack::GroupTrack()
|
||||
GroupTrack::GroupTrack(TimelineWidget &timeline_widget) :
|
||||
Track(timeline_widget)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ namespace timeline {
|
|||
class GroupTrack : public timeline::Track
|
||||
{
|
||||
public:
|
||||
GroupTrack();
|
||||
GroupTrack(TimelineWidget &timeline_widget);
|
||||
|
||||
void draw_track(Cairo::RefPtr<Cairo::Context> cairo,
|
||||
TimelineViewWindow* constwindow)
|
||||
|
|
|
|||
|
|
@ -150,11 +150,25 @@ bool TimelineHeaderContainer::on_button_press_event (
|
|||
break;
|
||||
|
||||
case 3: // Right Click
|
||||
// Popup the context menu
|
||||
contextMenu.popup(event->button, event->time);
|
||||
break;
|
||||
|
||||
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
TimelineHeaderContainer::on_expose_event(GdkEventExpose *event)
|
||||
{
|
||||
|
|
@ -477,6 +497,25 @@ TimelineHeaderContainer::draw_header_decoration(
|
|||
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>
|
||||
TimelineHeaderContainer::expander_button_from_point(
|
||||
const Gdk::Point &point)
|
||||
|
|
|
|||
|
|
@ -118,6 +118,12 @@ private:
|
|||
**/
|
||||
void forall_vfunc(gboolean include_internals, GtkCallback callback,
|
||||
gpointer callback_data);
|
||||
|
||||
/**
|
||||
* An event handler that is called when a widget is removed from the
|
||||
* container.
|
||||
**/
|
||||
void on_remove(Widget* widget);
|
||||
|
||||
/* ===== Events ===== */
|
||||
private:
|
||||
|
|
@ -193,6 +199,9 @@ private:
|
|||
void draw_header_decoration(
|
||||
boost::shared_ptr<model::Track> model_track,
|
||||
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
|
||||
|
|
@ -297,6 +306,8 @@ private:
|
|||
* in pixels.
|
||||
**/
|
||||
int expand_button_size;
|
||||
|
||||
friend class timeline::Track;
|
||||
};
|
||||
|
||||
} // namespace timeline
|
||||
|
|
|
|||
|
|
@ -24,15 +24,18 @@
|
|||
#include <gtk/gtktoolbar.h>
|
||||
|
||||
#include "timeline-track.hpp"
|
||||
#include "../timeline-widget.hpp"
|
||||
#include "../../window-manager.hpp"
|
||||
|
||||
using namespace boost;
|
||||
using namespace Gtk;
|
||||
|
||||
namespace gui {
|
||||
namespace widgets {
|
||||
namespace timeline {
|
||||
|
||||
Track::Track() :
|
||||
Track::Track(TimelineWidget &timeline_widget) :
|
||||
timelineWidget(timeline_widget),
|
||||
expanded(true),
|
||||
enableButton(Gtk::StockID("track_enabled")),
|
||||
lockButton(Gtk::StockID("track_unlocked"))
|
||||
|
|
@ -54,6 +57,14 @@ Track::Track() :
|
|||
|
||||
headerWidget.pack_start(titleBox, 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&
|
||||
|
|
@ -80,6 +91,23 @@ Track::set_expanded(bool 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 widgets
|
||||
} // namespace gui
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "../../gtk-lumiera.hpp"
|
||||
#include "../../model/track.hpp"
|
||||
#include "timeline-header-container.hpp"
|
||||
|
||||
#ifndef TIMELINE_TRACK_HPP
|
||||
#define TIMELINE_TRACK_HPP
|
||||
|
|
@ -38,7 +39,7 @@ class TimelineViewWindow;
|
|||
class Track
|
||||
{
|
||||
public:
|
||||
Track();
|
||||
Track(TimelineWidget &timeline_widget);
|
||||
|
||||
Gtk::Widget& get_header_widget();
|
||||
|
||||
|
|
@ -47,12 +48,19 @@ public:
|
|||
bool get_expanded() const;
|
||||
|
||||
void set_expanded(bool expanded);
|
||||
|
||||
void show_header_context_menu(guint button, guint32 time);
|
||||
|
||||
virtual void draw_track(Cairo::RefPtr<Cairo::Context> cairo,
|
||||
TimelineViewWindow* const window)
|
||||
const = 0;
|
||||
|
||||
private:
|
||||
void on_remove_track();
|
||||
|
||||
private:
|
||||
|
||||
TimelineWidget &timelineWidget;
|
||||
|
||||
bool expanded;
|
||||
|
||||
|
|
@ -65,6 +73,8 @@ private:
|
|||
|
||||
Gtk::Entry titleBox;
|
||||
Gtk::Toolbar buttonBar;
|
||||
|
||||
Gtk::Menu contextMenu;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue