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);
|
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()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,8 @@ namespace gui {
|
||||||
namespace widgets {
|
namespace widgets {
|
||||||
namespace timeline {
|
namespace timeline {
|
||||||
|
|
||||||
ClipTrack::ClipTrack()
|
ClipTrack::ClipTrack(TimelineWidget &timeline_widget) :
|
||||||
|
Track(timeline_widget)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ namespace gui {
|
||||||
namespace widgets {
|
namespace widgets {
|
||||||
namespace timeline {
|
namespace timeline {
|
||||||
|
|
||||||
GroupTrack::GroupTrack()
|
GroupTrack::GroupTrack(TimelineWidget &timeline_widget) :
|
||||||
|
Track(timeline_widget)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -150,11 +150,25 @@ bool TimelineHeaderContainer::on_button_press_event (
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3: // Right Click
|
case 3: // Right Click
|
||||||
// Popup the context menu
|
{
|
||||||
contextMenu.popup(event->button, event->time);
|
// Popup the context menu
|
||||||
break;
|
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;
|
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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue