From 8cb48a7298015442c02d5e4a9a812fce7414d81d Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 30 Dec 2008 12:35:58 +0000 Subject: [PATCH 01/68] Squished a whole load of warnings --- src/gui/dialogs/render.hpp | 5 +- src/gui/gtk-lumiera.cpp | 19 +++++- src/gui/gtk-lumiera.hpp | 63 ++++++++++--------- src/gui/model/parent-track.hpp | 3 +- src/gui/model/sequence.cpp | 2 +- src/gui/output/xvdisplayer.cpp | 4 +- src/gui/panels/timeline-panel.cpp | 4 +- src/gui/widgets/timeline-widget.cpp | 6 +- src/gui/widgets/timeline/timeline-body.cpp | 22 +++++-- .../widgets/timeline/timeline-group-track.cpp | 3 +- .../timeline/timeline-header-container.cpp | 15 ++--- .../timeline/timeline-header-container.hpp | 2 +- .../widgets/timeline/timeline-ibeam-tool.cpp | 6 +- src/gui/widgets/timeline/timeline-ruler.cpp | 4 +- src/gui/widgets/timeline/timeline-tool.hpp | 4 +- src/gui/widgets/timeline/timeline-track.cpp | 6 +- src/gui/widgets/video-display-widget.cpp | 2 + src/gui/window-manager.cpp | 5 +- src/gui/workspace/actions.cpp | 11 ++-- src/gui/workspace/workspace-window.cpp | 2 +- 20 files changed, 111 insertions(+), 77 deletions(-) diff --git a/src/gui/dialogs/render.hpp b/src/gui/dialogs/render.hpp index 51c088b72..51989a25e 100644 --- a/src/gui/dialogs/render.hpp +++ b/src/gui/dialogs/render.hpp @@ -54,12 +54,11 @@ protected: Gtk::HBox containerFormatHBox; Gtk::Label containerFormatLabel; Gtk::ComboBox containerFormat; + + Gtk::Image renderButtonImage; Gtk::Frame audioFrame; - Gtk::Frame videoFrame; - - Gtk::Image renderButtonImage; }; } // namespace dialogs diff --git a/src/gui/gtk-lumiera.cpp b/src/gui/gtk-lumiera.cpp index 64dd4668c..abdfa7871 100644 --- a/src/gui/gtk-lumiera.cpp +++ b/src/gui/gtk-lumiera.cpp @@ -44,6 +44,7 @@ using namespace gui; using namespace gui::workspace; using namespace gui::model; + GtkLumiera the_application; int @@ -72,7 +73,9 @@ GtkLumiera::main(int argc, char *argv[]) WorkspaceWindow main_window(&project); - kit.run(main_window); + kit.run(main_window); + + return 0; } Glib::ustring @@ -89,6 +92,20 @@ application() return the_application; } +/* ===== Constants ===== */ + +const gchar* GtkLumiera::AppTitle = "Lumiera"; +const gchar* GtkLumiera::AppVersion = _("0.1-dev"); +const gchar* GtkLumiera::AppCopyright = + _("© 2008 The Lumiera Team"); +const gchar* GtkLumiera::AppWebsite = "www.lumiera.org"; +const gchar* GtkLumiera::AppAuthors[] = { + "Joel Holdsworth", + "Christian Thaeter", + "Hermann Vosseler", + ""}; +const int GtkLumiera::AppAuthorCount = 4; + } // namespace gui diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp index 4f3021b76..765a628b7 100644 --- a/src/gui/gtk-lumiera.hpp +++ b/src/gui/gtk-lumiera.hpp @@ -59,37 +59,6 @@ NOBUG_DECLARE_FLAG(gui); */ namespace gui { -/* ===== Global Constants ===== */ - -/** - * The name of the application - */ -static const gchar* AppTitle = "Lumiera"; - -/** - * The version number of the application - */ -static const gchar* AppVersion = N_("0.1-dev"); - -/** - * The copyright of the application - */ -static const gchar* AppCopyright = N_("© 2008 The Lumiera Team"); - -/** - * The website of the application - */ -static const gchar* AppWebsite = "www.lumiera.org"; - -/** - * An alphabetical list of the application's authors - */ -static const gchar* AppAuthors[] = { - "Joel Holdsworth", - "Christian Thaeter", - "Hermann Vosseler", - ""}; - /* ===== The Application Class ===== */ /** @@ -102,6 +71,38 @@ public: static Glib::ustring get_home_data_path(); + +public: + /* ----- Constants ----- */ + /** + * The name of the application + */ + static const gchar* AppTitle; + + /** + * The version number of the application + */ + static const gchar* AppVersion; + + /** + * The copyright of the application + */ + static const gchar* AppCopyright; + + /** + * The website of the application + */ + static const gchar* AppWebsite; + + /** + * An alphabetical list of the application's authors + */ + static const gchar* AppAuthors[]; + + /** + * The number of authors in AppAuthors + **/ + static const int AppAuthorCount; }; /** diff --git a/src/gui/model/parent-track.hpp b/src/gui/model/parent-track.hpp index a040297ca..481f7c352 100644 --- a/src/gui/model/parent-track.hpp +++ b/src/gui/model/parent-track.hpp @@ -40,7 +40,8 @@ protected: ParentTrack(); public: - virtual void add_child_track(Track* child) {}; + virtual void add_child_track(Track* child) + { (void)child; }; std::list< boost::shared_ptr > get_child_tracks() const; diff --git a/src/gui/model/sequence.cpp b/src/gui/model/sequence.cpp index c312108c3..2f89c211b 100644 --- a/src/gui/model/sequence.cpp +++ b/src/gui/model/sequence.cpp @@ -30,7 +30,7 @@ namespace model { Sequence::Sequence() { // TEST CODE - static bool first = true; + //static bool first = true; shared_ptr group_track, group_track2; tracks.push_back(group_track = shared_ptr(new GroupTrack())); diff --git a/src/gui/output/xvdisplayer.cpp b/src/gui/output/xvdisplayer.cpp index 13a692a40..695ffe75f 100644 --- a/src/gui/output/xvdisplayer.cpp +++ b/src/gui/output/xvdisplayer.cpp @@ -32,9 +32,9 @@ namespace gui { namespace output { XvDisplayer::XvDisplayer( Gtk::Widget *drawing_area, int width, int height ) : - xvImage( NULL ), + gotPort( false ), drawingArea( drawing_area ), - gotPort( false ) + xvImage( NULL ) { INFO(gui, "Trying XVideo at %d x %d", width, height); diff --git a/src/gui/panels/timeline-panel.cpp b/src/gui/panels/timeline-panel.cpp index 03cdc8e2f..f1ca132d2 100644 --- a/src/gui/panels/timeline-panel.cpp +++ b/src/gui/panels/timeline-panel.cpp @@ -45,6 +45,7 @@ const int TimelinePanel::ZoomToolSteps = 2; // 2 seems comfortable TimelinePanel::TimelinePanel(model::Project *const owner_project) : Panel(owner_project, "timeline", _("Timeline"), "panel_timeline"), + timeIndicator(), previousButton(Stock::MEDIA_PREVIOUS), rewindButton(Stock::MEDIA_REWIND), playPauseButton(Stock::MEDIA_PLAY), @@ -55,7 +56,6 @@ TimelinePanel::TimelinePanel(model::Project *const owner_project) : iBeamTool(Gtk::StockID("tool_i_beam")), zoomIn(Stock::ZOOM_IN), zoomOut(Stock::ZOOM_OUT), - timeIndicator(), updatingToolbar(false), currentTool(timeline::IBeam) { @@ -191,7 +191,7 @@ TimelinePanel::on_page_switched(GtkNotebookPage*, guint) void TimelinePanel::on_mouse_hover(gavl_time_t time) { - + (void)time; } void diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 7f375fae2..f954d90ee 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -44,14 +44,14 @@ TimelineWidget::TimelineWidget( Table(2, 2), sequence(source_sequence), viewWindow(this, 0, 1), - totalHeight(0), - horizontalAdjustment(0, 0, 0), - verticalAdjustment(0, 0, 0), selectionStart(0), selectionEnd(0), playbackPeriodStart(0), playbackPeriodEnd(0), playbackPoint(GAVL_TIME_UNDEFINED), + totalHeight(0), + horizontalAdjustment(0, 0, 0), + verticalAdjustment(0, 0, 0), horizontalScroll(horizontalAdjustment), verticalScroll(verticalAdjustment) { diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp index 7e8125cac..06a4801c2 100644 --- a/src/gui/widgets/timeline/timeline-body.cpp +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -42,9 +42,9 @@ TimelineBody::TimelineBody(gui::widgets::TimelineWidget *timeline_widget) : Glib::ObjectBase("TimelineBody"), tool(NULL), - dragType(None), mouseDownX(0), mouseDownY(0), + dragType(None), beginShiftTimeOffset(0), selectionAlpha(0.5), timelineWidget(timeline_widget) @@ -98,6 +98,9 @@ TimelineBody::set_tool(timeline::ToolType tool_type) case timeline::IBeam: tool = new IBeamTool(this); break; + + default: + break; } // Apply the cursor if possible @@ -174,7 +177,10 @@ TimelineBody::on_scroll_event (GdkEventScroll* event) case GDK_SCROLL_DOWN: // User scrolled down. Zoom out window.zoom_view(event->x, -1); - break; + break; + + default: + break; } } else @@ -189,9 +195,14 @@ TimelineBody::on_scroll_event (GdkEventScroll* event) case GDK_SCROLL_DOWN: // User scrolled down. Shift 1/16th right window.shift_view(16); - break; + break; + + default: + break; } } + + return true; } bool @@ -250,6 +261,9 @@ TimelineBody::on_motion_notify_event(GdkEventMotion *event) beginShiftVerticalOffset); break; } + + default: + break; } // Forward the event to the tool @@ -383,7 +397,7 @@ TimelineBody::draw_playback_point(Cairo::RefPtr cr) const Allocation allocation = get_allocation(); const gavl_time_t point = timelineWidget->get_playback_point(); - if(point == GAVL_TIME_UNDEFINED) + if(point == (gavl_time_t)GAVL_TIME_UNDEFINED) return; const int x = timelineWidget->get_view_window().time_to_x(point); diff --git a/src/gui/widgets/timeline/timeline-group-track.cpp b/src/gui/widgets/timeline/timeline-group-track.cpp index 4449a3227..f6e7b8382 100644 --- a/src/gui/widgets/timeline/timeline-group-track.cpp +++ b/src/gui/widgets/timeline/timeline-group-track.cpp @@ -38,7 +38,8 @@ void GroupTrack::draw_track(Cairo::RefPtr cairo, TimelineViewWindow* const window) const { - + (void)cairo; + (void)window; } } // namespace timeline diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index d9c15fc90..be1307c1c 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -254,7 +254,7 @@ TimelineHeaderContainer::forall_vfunc(gboolean /* include_internals */, } void -TimelineHeaderContainer::on_remove(Widget* widget) +TimelineHeaderContainer::on_remove(Widget*) { // Do nothing - this is just to keep Gtk::Container happy } @@ -264,9 +264,6 @@ TimelineHeaderContainer::on_expose_event(GdkEventExpose *event) { if(gdkWindow) { - // Start at an offset from the scroll offset - int offset = -timelineWidget->get_y_scroll_offset(); - const Allocation container_allocation = get_allocation(); read_styles(); @@ -299,6 +296,8 @@ void TimelineHeaderContainer::on_hovering_track_changed( boost::shared_ptr hovering_track) { + (void)hovering_track; + // The hovering track has changed, redraw so we can light the header queue_draw(); } @@ -492,9 +491,11 @@ TimelineHeaderContainer::draw_header_decoration( // Recurse through all the children if(timeline_track->get_expanded()) - BOOST_FOREACH( shared_ptr child, - model_track->get_child_tracks() ) - draw_header_decoration(child, clip_rect); + { + BOOST_FOREACH( shared_ptr child, + model_track->get_child_tracks() ) + draw_header_decoration(child, clip_rect); + } } boost::shared_ptr diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index 517ed3bce..86d61182e 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -123,7 +123,7 @@ private: * An event handler that is called when a widget is removed from the * container. **/ - void on_remove(Widget* widget); + void on_remove(Widget*); /* ===== Events ===== */ private: diff --git a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp index e736b6d3a..07942600a 100644 --- a/src/gui/widgets/timeline/timeline-ibeam-tool.cpp +++ b/src/gui/widgets/timeline/timeline-ibeam-tool.cpp @@ -38,10 +38,10 @@ const int IBeamTool::ScrollSlideEventInterval = 40; // ===== Implementation ===== // IBeamTool::IBeamTool(TimelineBody *timeline_body) : + Tool(timeline_body), dragType(None), pinnedDragTime(0), - scrollSlideRate(0), - Tool(timeline_body) + scrollSlideRate(0) { } @@ -70,6 +70,8 @@ IBeamTool::get_cursor() const return Gdk::Cursor(Gdk::LEFT_SIDE); case GrabEnd: return Gdk::Cursor(Gdk::RIGHT_SIDE); + default: + break; } // Are we hovering over the ends of the selection? diff --git a/src/gui/widgets/timeline/timeline-ruler.cpp b/src/gui/widgets/timeline/timeline-ruler.cpp index bbea35c01..e2b826955 100644 --- a/src/gui/widgets/timeline/timeline-ruler.cpp +++ b/src/gui/widgets/timeline/timeline-ruler.cpp @@ -447,7 +447,7 @@ TimelineRuler::draw_playback_point(Cairo::RefPtr cr, REQUIRE(timelineWidget != NULL); const gavl_time_t point = timelineWidget->get_playback_point(); - if(point == GAVL_TIME_UNDEFINED) + if(point == (gavl_time_t)GAVL_TIME_UNDEFINED) return; const int x = timelineWidget->get_view_window().time_to_x(point); @@ -473,7 +473,7 @@ TimelineRuler::draw_playback_point(Cairo::RefPtr cr, gavl_time_t TimelineRuler::calculate_major_spacing() const { - int i; + unsigned int i; REQUIRE(timelineWidget != NULL); diff --git a/src/gui/widgets/timeline/timeline-tool.hpp b/src/gui/widgets/timeline/timeline-tool.hpp index 49c1697ed..e422142aa 100644 --- a/src/gui/widgets/timeline/timeline-tool.hpp +++ b/src/gui/widgets/timeline/timeline-tool.hpp @@ -129,10 +129,10 @@ protected: Gdk::Rectangle get_body_rectangle() const; protected: + TimelineBody *timelineBody; + bool isDragging; Gdk::Point mousePoint; - - TimelineBody *timelineBody; }; } // namespace timeline diff --git a/src/gui/widgets/timeline/timeline-track.cpp b/src/gui/widgets/timeline/timeline-track.cpp index f2787a2a8..ea935d7c0 100644 --- a/src/gui/widgets/timeline/timeline-track.cpp +++ b/src/gui/widgets/timeline/timeline-track.cpp @@ -20,7 +20,7 @@ * *****************************************************/ -#warning This header must soon be removed when we drop Etch compatibility +// !!! This header must soon be removed when we drop Etch compatibility #include #include "timeline-track.hpp" @@ -56,8 +56,8 @@ Track::Track(TimelineWidget &timeline_widget, #if 0 buttonBar.set_icon_size(WindowManager::MenuIconSize); #else -#warning This code soon be removed when we drop Etch compatibility - + TODO("This code soon be removed when we drop Etch compatibility"); + // Temporary bodge for etch compatibility - will be removed soon gtk_toolbar_set_icon_size (buttonBar.gobj(), (GtkIconSize)(int)WindowManager::MenuIconSize); diff --git a/src/gui/widgets/video-display-widget.cpp b/src/gui/widgets/video-display-widget.cpp index 720986156..0c396ed4d 100644 --- a/src/gui/widgets/video-display-widget.cpp +++ b/src/gui/widgets/video-display-widget.cpp @@ -64,6 +64,8 @@ VideoDisplayWidget::on_realize() bool VideoDisplayWidget::on_button_press_event (GdkEventButton* event) { + (void)event; + unsigned char buffer[320 * 240 * 4]; for(int i = 0; i < 320*240*4; i++) diff --git a/src/gui/window-manager.cpp b/src/gui/window-manager.cpp index e9fc1907b..88de4db56 100644 --- a/src/gui/window-manager.cpp +++ b/src/gui/window-manager.cpp @@ -68,10 +68,7 @@ WindowManager::read_style_colour_property( { WARN(gui, "%s style value failed to load", property_name); - GdkColor default_colour; - default_colour.red = red; - default_colour.green = green; - default_colour.blue = blue; + const GdkColor default_colour = {0, red, green, blue}; return default_colour; } } diff --git a/src/gui/workspace/actions.cpp b/src/gui/workspace/actions.cpp index 0ef837707..ed5a43002 100644 --- a/src/gui/workspace/actions.cpp +++ b/src/gui/workspace/actions.cpp @@ -208,13 +208,12 @@ Actions::on_menu_help_about() AboutDialog dialog; //dialog.set_program_name(AppTitle); - dialog.set_version(AppVersion); + dialog.set_version(GtkLumiera::AppVersion); //dialog.set_version(AppState::get("version")); - dialog.set_copyright(AppCopyright); - dialog.set_website(AppWebsite); - dialog.set_authors(StringArrayHandle(AppAuthors, - sizeof(AppAuthors) / sizeof(gchar*), - OWNERSHIP_NONE)); + dialog.set_copyright(GtkLumiera::AppCopyright); + dialog.set_website(GtkLumiera::AppWebsite); + dialog.set_authors(StringArrayHandle(GtkLumiera::AppAuthors, + GtkLumiera::AppAuthorCount, OWNERSHIP_NONE)); dialog.set_transient_for(workspaceWindow); diff --git a/src/gui/workspace/workspace-window.cpp b/src/gui/workspace/workspace-window.cpp index f46c2d9a2..ee315e026 100644 --- a/src/gui/workspace/workspace-window.cpp +++ b/src/gui/workspace/workspace-window.cpp @@ -78,7 +78,7 @@ void WorkspaceWindow::create_ui() { //----- Configure the Window -----// - set_title(AppTitle); + set_title(GtkLumiera::AppTitle); set_default_size(1024, 768); //----- Set up the UI Manager -----// From cdf26d3fe60ddaed487c14b543a582df624b68c5 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 30 Dec 2008 13:06:08 +0000 Subject: [PATCH 02/68] Tidied up the displayer code and added some documentation --- src/gui/output/displayer.hpp | 170 ++++++++--------- src/gui/output/gdkdisplayer.cpp | 72 +++---- src/gui/output/gdkdisplayer.hpp | 49 ++++- src/gui/output/xvdisplayer.cpp | 326 ++++++++++++++++---------------- src/gui/output/xvdisplayer.hpp | 104 +++++++--- 5 files changed, 405 insertions(+), 316 deletions(-) diff --git a/src/gui/output/displayer.hpp b/src/gui/output/displayer.hpp index 235de278f..5dc576565 100644 --- a/src/gui/output/displayer.hpp +++ b/src/gui/output/displayer.hpp @@ -33,99 +33,97 @@ namespace gui { namespace output { -#define MAX_WIDTH 720 -#define MAX_HEIGHT 576 +/** + * Supported Displayer formats + **/ +typedef enum { + DISPLAY_NONE, + DISPLAY_YUV, + DISPLAY_RGB, + DISPLAY_BGR, + DISPLAY_BGR0, + DISPLAY_RGB16 +} +DisplayerInput; - /** Supported Displayer formats +/** + * A Displayer is a class which is responsible for rendering an image + * in some way (ie: Xvideo, GDK, OpenGL etc). + * + * @remarks All Displayer classes must extend the Displayer class and + * minimally rewrite: + * + * + usable() - to indicate if the object can be used, + * + format() - to indicate what type of input the put method expects + * + put( void * ) - deal with an image of the expected type and size + * + * By default, all images will be delivered to the put method in a + * resolution of IMG_WIDTH * IMG_HEIGHT. If another size is required, + * then the rewrite the methods: + * + * + preferredWidth + * + preferredHeight + * + * If the widget being written to doesn't need a fixed size, then + * rewrite the two other put methods as required. + */ +class Displayer +{ +public: + + /** + * Indicates if this object can be used to render images on the + * running system. */ - typedef enum { - DISPLAY_NONE, - DISPLAY_YUV, - DISPLAY_RGB, - DISPLAY_BGR, - DISPLAY_BGR0, - DISPLAY_RGB16 - } - DisplayerInput; + virtual bool usable(); + + /** + * Indicates the format required by the abstract put method. + */ + virtual DisplayerInput format(); + + /** + * Expected width of input to put. + */ + virtual int preferredWidth(); + + /** + * Expected height of input to put. + */ + virtual int preferredHeight(); /** - * A Displayer is a class which is responsible for rendering an image - * in some way (ie: Xvideo, GDK, OpenGL etc). - * - * @remarks All Displayer classes must extend the Displayer class and - * minimally rewrite: - * - * + usable() - to indicate if the object can be used, - * + format() - to indicate what type of input the put method expects - * + put( void * ) - deal with an image of the expected type and size - * - * By default, all images will be delivered to the put method in a - * resolution of IMG_WIDTH * IMG_HEIGHT. If another size is required, - * then the rewrite the methods: - * - * + preferredWidth - * + preferredHeight - * - * If the widget being written to doesn't need a fixed size, then - * rewrite the two other put methods as required. + * Put an image of a given width and height with the expected input + * format (as indicated by the format method). */ - class Displayer - { - public: + virtual void put( const void* ) = 0; - /** - * Indicates if an object can be used to render images on the - * running system. - */ - virtual bool usable(); - - /** - * Indicates the format required by the abstract put method. - */ - virtual DisplayerInput format(); - - /** - * Expected width of input to put. - */ - virtual int preferredWidth(); - - /** - * Expected height of input to put. - */ - virtual int preferredHeight(); - - /** - * Put an image of a given width and height with the expected input - * format (as indicated by the format method). - */ - virtual void put( void * ) = 0; - - protected: - - /** - * Calculates the coordinates for placing a video image inside a - * widget - * - * @param[in] widget_width The width of the display widget. - * @param[in] widget_height The height of the display widget. - * @param[in] image_width The width of the video image. - * @param[in] image_height The height of the video image. - * @param[out] video_x The x-coordinate of the top left - * corner of the scaled video image. - * @param[out] video_y The y-coordinate of the top left - * corner of the scaled video image. - * @param[out] video_width The width of the scale video image. - * @param[out] video_height The height of the scale video image. - */ - static void calculateVideoLayout( - int widget_width, int widget_height, - int image_width, int image_height, - int &video_x, int &video_y, int &video_width, int &video_height ); +protected: - protected: - int imageWidth; - int imageHeight; - }; + /** + * Calculates the coordinates for placing a video image inside a + * widget + * + * @param[in] widget_width The width of the display widget. + * @param[in] widget_height The height of the display widget. + * @param[in] image_width The width of the video image. + * @param[in] image_height The height of the video image. + * @param[out] video_x The x-coordinate of the top left + * corner of the scaled video image. + * @param[out] video_y The y-coordinate of the top left + * corner of the scaled video image. + * @param[out] video_width The width of the scale video image. + * @param[out] video_height The height of the scale video image. + */ + static void calculateVideoLayout( + int widget_width, int widget_height, + int image_width, int image_height, + int &video_x, int &video_y, int &video_width, int &video_height ); + +protected: + int imageWidth; + int imageHeight; +}; } // namespace output } // namespace gui diff --git a/src/gui/output/gdkdisplayer.cpp b/src/gui/output/gdkdisplayer.cpp index 0f83ceac4..523ed2bb5 100644 --- a/src/gui/output/gdkdisplayer.cpp +++ b/src/gui/output/gdkdisplayer.cpp @@ -36,49 +36,49 @@ namespace output { GdkDisplayer::GdkDisplayer( Gtk::Widget *drawing_area, int width, int height ) : drawingArea( drawing_area ) - { - REQUIRE(drawing_area != NULL); - REQUIRE(width > 0); - REQUIRE(height > 0); - - imageWidth = width, imageHeight = height; - } +{ + REQUIRE(drawing_area != NULL); + REQUIRE(width > 0); + REQUIRE(height > 0); + + imageWidth = width, imageHeight = height; +} bool GdkDisplayer::usable() - { - return true; - } +{ + return true; +} void -GdkDisplayer::put( void *image ) - { - int video_x = 0, video_y = 0, video_width = 0, video_height = 0; - calculateVideoLayout( - drawingArea->get_width(), - drawingArea->get_height(), - preferredWidth(), preferredHeight(), - video_x, video_y, video_width, video_height ); +GdkDisplayer::put( const void* image ) +{ + int video_x = 0, video_y = 0, video_width = 0, video_height = 0; + calculateVideoLayout( + drawingArea->get_width(), + drawingArea->get_height(), + preferredWidth(), preferredHeight(), + video_x, video_y, video_width, video_height ); - GdkWindow *window = drawingArea->get_window()->gobj(); - REQUIRE(window != NULL); - - GdkGC *gc = gdk_gc_new( window ); - REQUIRE(gc != NULL); - - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data( (const guchar*)image, GDK_COLORSPACE_RGB, FALSE, 8, - preferredWidth(), preferredHeight(), preferredWidth() * 3, NULL, NULL ); - REQUIRE(pixbuf != NULL); - - GdkPixbuf *scaled_image = gdk_pixbuf_scale_simple( pixbuf, video_width, video_height, GDK_INTERP_NEAREST ); - REQUIRE(scaled_image != NULL); - - gdk_draw_pixbuf( window, gc, scaled_image, 0, 0, video_x, video_y, -1, -1, GDK_RGB_DITHER_NORMAL, 0, 0 ); + GdkWindow *window = drawingArea->get_window()->gobj(); + REQUIRE(window != NULL); - g_object_unref( scaled_image ); - g_object_unref( pixbuf ); - g_object_unref( gc ); - } + GdkGC *gc = gdk_gc_new( window ); + REQUIRE(gc != NULL); + + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data( (const guchar*)image, GDK_COLORSPACE_RGB, FALSE, 8, + preferredWidth(), preferredHeight(), preferredWidth() * 3, NULL, NULL ); + REQUIRE(pixbuf != NULL); + + GdkPixbuf *scaled_image = gdk_pixbuf_scale_simple( pixbuf, video_width, video_height, GDK_INTERP_NEAREST ); + REQUIRE(scaled_image != NULL); + + gdk_draw_pixbuf( window, gc, scaled_image, 0, 0, video_x, video_y, -1, -1, GDK_RGB_DITHER_NORMAL, 0, 0 ); + + g_object_unref( scaled_image ); + g_object_unref( pixbuf ); + g_object_unref( gc ); +} } // namespace output } // namespace gui diff --git a/src/gui/output/gdkdisplayer.hpp b/src/gui/output/gdkdisplayer.hpp index 8e74d4404..76bb66d0f 100644 --- a/src/gui/output/gdkdisplayer.hpp +++ b/src/gui/output/gdkdisplayer.hpp @@ -40,19 +40,48 @@ namespace Gtk { namespace gui { namespace output { +/** + * GdkDisplayer is a class which is responsible for rendering a video + * image via GDK. + **/ class GdkDisplayer : public Displayer - { - public: - GdkDisplayer( Gtk::Widget *drawing_area, int width, int height ); +{ +public: - void put( void *image ); - - protected: - bool usable(); + /** + * Constructor + * @param[in] drawing_area The widget into which the video image will + * be drawn. This value must not be NULL. + * @param[in] width The width of the video image in pixels. This value + * must be greater than zero. + * @param[in] height The height of the video image in pixels. This + * value must be greater than zero. + **/ + GdkDisplayer( Gtk::Widget *drawing_area, int width, int height ); - private: - Gtk::Widget *drawingArea; - }; + /** + * Put an image of a given width and height with the expected input + * format (as indicated by the format method). + * @param[in] image The video image array to draw. + */ + void put( const void* image ); + +protected: + + /** + * Indicates if this object can be used to render images on the + * running system. + */ + bool usable(); + +private: + + /** + * The widget that video will be drawn into. + * @remarks This value must be a valid pointer. + **/ + Gtk::Widget *drawingArea; +}; } // namespace output } // namespace gui diff --git a/src/gui/output/xvdisplayer.cpp b/src/gui/output/xvdisplayer.cpp index 695ffe75f..ade6973e5 100644 --- a/src/gui/output/xvdisplayer.cpp +++ b/src/gui/output/xvdisplayer.cpp @@ -35,190 +35,192 @@ XvDisplayer::XvDisplayer( Gtk::Widget *drawing_area, int width, int height ) : gotPort( false ), drawingArea( drawing_area ), xvImage( NULL ) - { - INFO(gui, "Trying XVideo at %d x %d", width, height); +{ + REQUIRE(drawing_area != NULL); + REQUIRE(width > 0); + REQUIRE(height > 0); + + INFO(gui, "Trying XVideo at %d x %d", width, height); - imageWidth = width, imageHeight = height; + imageWidth = width, imageHeight = height; - shmInfo.shmaddr = NULL; + shmInfo.shmaddr = NULL; - Glib::RefPtr area_window = drawing_area->get_window(); + Glib::RefPtr area_window = drawing_area->get_window(); - window = gdk_x11_drawable_get_xid( area_window->gobj() ); - display = gdk_x11_drawable_get_xdisplay( area_window->gobj() ); + window = gdk_x11_drawable_get_xid( area_window->gobj() ); + display = gdk_x11_drawable_get_xdisplay( area_window->gobj() ); - unsigned int count; - XvAdaptorInfo *adaptorInfo; + unsigned int count; + XvAdaptorInfo *adaptorInfo; - if ( XvQueryAdaptors( display, window, &count, &adaptorInfo ) == Success ) - { + if ( XvQueryAdaptors( display, window, &count, &adaptorInfo ) == Success ) + { - INFO(gui, "XvQueryAdaptors count: %d", count); - for ( unsigned int n = 0; gotPort == false && n < count; ++n ) - { - // Diagnostics - INFO(gui, "%s, %d, %d, %d", adaptorInfo[ n ].name, - adaptorInfo[ n ].base_id, adaptorInfo[ n ].num_ports - 1); + INFO(gui, "XvQueryAdaptors count: %d", count); + for ( unsigned int n = 0; gotPort == false && n < count; ++n ) + { + // Diagnostics + INFO(gui, "%s, %d, %d, %d", adaptorInfo[ n ].name, + adaptorInfo[ n ].base_id, adaptorInfo[ n ].num_ports - 1); - for ( port = adaptorInfo[ n ].base_id; - port < adaptorInfo[ n ].base_id + adaptorInfo[ n ].num_ports; - port ++ ) + for ( unsigned int port = adaptorInfo[ n ].base_id; + port < adaptorInfo[ n ].base_id + adaptorInfo[ n ].num_ports; + port ++ ) + { + if ( XvGrabPort( display, port, CurrentTime ) == Success ) + { + int formats; + XvImageFormatValues *list; + + list = XvListImageFormats( display, port, &formats ); + + INFO(gui, "formats supported: %d", formats); + + for ( int i = 0; i < formats; i ++ ) + { + INFO(gui, "0x%x (%c%c%c%c) %s", + list[ i ].id, + ( list[ i ].id ) & 0xff, + ( list[ i ].id >> 8 ) & 0xff, + ( list[ i ].id >> 16 ) & 0xff, + ( list[ i ].id >> 24 ) & 0xff, + ( list[ i ].format == XvPacked ) ? "packed" : "planar" ); + if ( list[ i ].id == 0x32595559 && !gotPort ) + gotPort = true; + } + + if ( !gotPort ) + { + XvUngrabPort( display, port, CurrentTime ); + } + else + { + grabbedPort = port; + break; + } + } + } + } + + if ( gotPort ) + { + int num; + unsigned int unum; + XvEncodingInfo *enc; + + XvQueryEncodings( display, grabbedPort, &unum, &enc ); + for ( unsigned int index = 0; index < unum; index ++ ) + { + INFO(gui, "%d: %s, %ldx%ld rate = %d/%d", index, enc->name, + enc->width, enc->height, enc->rate.numerator, + enc->rate.denominator ); + } + + XvAttribute *xvattr = XvQueryPortAttributes( display, grabbedPort, &num ); + for ( int k = 0; k < num; k++ ) + { + if ( xvattr[k].flags & XvSettable ) + { + if ( strcmp( xvattr[k].name, "XV_AUTOPAINT_COLORKEY") == 0 ) + { + Atom val_atom = XInternAtom( display, xvattr[k].name, False ); + if ( XvSetPortAttribute( display, grabbedPort, val_atom, 1 ) != Success ) + ERROR(gui, "Couldn't set Xv attribute %s\n", xvattr[k].name); + } + else if ( strcmp( xvattr[k].name, "XV_COLORKEY") == 0 ) + { + Atom val_atom = XInternAtom( display, xvattr[k].name, False ); + if ( XvSetPortAttribute( display, grabbedPort, val_atom, 0x010102 ) != Success ) + ERROR(gui, "Couldn't set Xv attribute %s\n", xvattr[k].name); + } + } + } + } + + if ( gotPort ) + { + XGCValues values; + memset(&values, 0, sizeof(XGCValues)); + gc = XCreateGC( display, window, 0, NULL ); + + xvImage = ( XvImage * ) XvShmCreateImage( display, grabbedPort, 0x32595559, 0, width, height, &shmInfo ); + + shmInfo.shmid = shmget( IPC_PRIVATE, xvImage->data_size, IPC_CREAT | 0777 ); + if (shmInfo.shmid < 0) { + perror("shmget"); + gotPort = false; + } + else + { + shmInfo.shmaddr = ( char * ) shmat( shmInfo.shmid, 0, 0 ); + xvImage->data = shmInfo.shmaddr; + shmInfo.readOnly = 0; + if ( !XShmAttach( gdk_display, &shmInfo ) ) { - if ( XvGrabPort( display, port, CurrentTime ) == Success ) - { - int formats; - XvImageFormatValues *list; - - list = XvListImageFormats( display, port, &formats ); - - INFO(gui, "formats supported: %d", formats); - - for ( int i = 0; i < formats; i ++ ) - { - INFO(gui, "0x%x (%c%c%c%c) %s", - list[ i ].id, - ( list[ i ].id ) & 0xff, - ( list[ i ].id >> 8 ) & 0xff, - ( list[ i ].id >> 16 ) & 0xff, - ( list[ i ].id >> 24 ) & 0xff, - ( list[ i ].format == XvPacked ) ? "packed" : "planar" ); - if ( list[ i ].id == 0x32595559 && !gotPort ) - gotPort = true; - } - - if ( !gotPort ) - { - XvUngrabPort( display, port, CurrentTime ); - } - else - { - grabbedPort = port; - break; - } - } - } - } - - if ( gotPort ) - { - int num; - unsigned int unum; - XvEncodingInfo *enc; - - XvQueryEncodings( display, grabbedPort, &unum, &enc ); - for ( unsigned int index = 0; index < unum; index ++ ) - { - INFO(gui, "%d: %s, %ldx%ld rate = %d/%d", index, enc->name, - enc->width, enc->height, enc->rate.numerator, - enc->rate.denominator ); - } - - XvAttribute *xvattr = XvQueryPortAttributes( display, port, &num ); - for ( int k = 0; k < num; k++ ) - { - if ( xvattr[k].flags & XvSettable ) - { - if ( strcmp( xvattr[k].name, "XV_AUTOPAINT_COLORKEY") == 0 ) - { - Atom val_atom = XInternAtom( display, xvattr[k].name, False ); - if ( XvSetPortAttribute( display, port, val_atom, 1 ) != Success ) - ERROR(gui, "Couldn't set Xv attribute %s\n", xvattr[k].name); - } - else if ( strcmp( xvattr[k].name, "XV_COLORKEY") == 0 ) - { - Atom val_atom = XInternAtom( display, xvattr[k].name, False ); - if ( XvSetPortAttribute( display, port, val_atom, 0x010102 ) != Success ) - ERROR(gui, "Couldn't set Xv attribute %s\n", xvattr[k].name); - } - } - } - } - - if ( gotPort ) - { - gc = XCreateGC( display, window, 0, &values ); - - xvImage = ( XvImage * ) XvShmCreateImage( display, port, 0x32595559, 0, width, height, &shmInfo ); - - shmInfo.shmid = shmget( IPC_PRIVATE, xvImage->data_size, IPC_CREAT | 0777 ); - if (shmInfo.shmid < 0) { - perror("shmget"); gotPort = false; } - else - { - shmInfo.shmaddr = ( char * ) shmat( shmInfo.shmid, 0, 0 ); - xvImage->data = shmInfo.shmaddr; - shmInfo.readOnly = 0; - if ( !XShmAttach( gdk_display, &shmInfo ) ) - { - gotPort = false; - } - XSync( display, false ); - shmctl( shmInfo.shmid, IPC_RMID, 0 ); -#if 0 - xvImage = ( XvImage * ) XvCreateImage( display, port, 0x32595559, pix, width , height ); -#endif - } - } - } - else - { - gotPort = false; - } - } + XSync( display, false ); + shmctl( shmInfo.shmid, IPC_RMID, 0 ); + } + } + } + else + { + gotPort = false; + } +} XvDisplayer::~XvDisplayer() - { - ERROR(gui, "Destroying XV Displayer"); +{ + ERROR(gui, "Destroying XV Displayer"); - if ( gotPort ) - { - XvUngrabPort( display, grabbedPort, CurrentTime ); - } + if ( gotPort ) + { + XvUngrabPort( display, grabbedPort, CurrentTime ); + } - //if ( xvImage != NULL ) - // XvStopVideo( display, port, window ); - - if ( shmInfo.shmaddr != NULL ) - { - XShmDetach( display, &shmInfo ); - shmctl( shmInfo.shmid, IPC_RMID, 0 ); - shmdt( shmInfo.shmaddr ); - } - - if ( xvImage != NULL ) - XFree( xvImage ); - } + if ( shmInfo.shmaddr != NULL ) + { + XShmDetach( display, &shmInfo ); + shmctl( shmInfo.shmid, IPC_RMID, 0 ); + shmdt( shmInfo.shmaddr ); + } + + if ( xvImage != NULL ) + XFree( xvImage ); +} bool XvDisplayer::usable() - { - return gotPort; - } +{ + return gotPort; +} void -XvDisplayer::put( void *image ) - { - REQUIRE(image != NULL); - REQUIRE(drawingArea != NULL); - - if(xvImage != NULL) - { - int video_x = 0, video_y = 0, video_width = 0, video_height = 0; - calculateVideoLayout( - drawingArea->get_width(), - drawingArea->get_height(), - preferredWidth(), preferredHeight(), - video_x, video_y, video_width, video_height ); +XvDisplayer::put( const void* image ) +{ + REQUIRE(image != NULL); + REQUIRE(drawingArea != NULL); + + if(xvImage != NULL) + { + REQUIRE(display != NULL); + + int video_x = 0, video_y = 0, video_width = 0, video_height = 0; + calculateVideoLayout( + drawingArea->get_width(), + drawingArea->get_height(), + preferredWidth(), preferredHeight(), + video_x, video_y, video_width, video_height ); - memcpy( xvImage->data, image, xvImage->data_size ); + memcpy( xvImage->data, image, xvImage->data_size ); - XvShmPutImage( display, port, window, gc, xvImage, - 0, 0, preferredWidth(), preferredHeight(), - video_x, video_y, video_width, video_height, false ); - } - } + XvShmPutImage( display, grabbedPort, window, gc, xvImage, + 0, 0, preferredWidth(), preferredHeight(), + video_x, video_y, video_width, video_height, false ); + } +} } // namespace output } // namespace gui diff --git a/src/gui/output/xvdisplayer.hpp b/src/gui/output/xvdisplayer.hpp index c43db099e..afc25c670 100644 --- a/src/gui/output/xvdisplayer.hpp +++ b/src/gui/output/xvdisplayer.hpp @@ -46,30 +46,90 @@ namespace Gtk { namespace gui { namespace output { - class XvDisplayer : public Displayer - { - public: - XvDisplayer( Gtk::Widget *drawing_area, int width, int height ); - ~XvDisplayer(); - - void put( void *image ); +/** + * XvDisplayer is a class which is responsible for rendering a video + * image via XVideo. + **/ +class XvDisplayer : public Displayer +{ +public: + /** + * Constructor + * @param drawing_area The widget into which the video image will be + * drawn. This value must not be NULL. + * @param width The width of the video image in pixels. This value + * must be greater than zero. + * @param height The height of the video image in pixels. This value + * must be greater than zero. + **/ + XvDisplayer( Gtk::Widget *drawing_area, int width, int height ); - protected: - bool usable(); + /** + * Destructor + **/ + ~XvDisplayer(); - private: - bool gotPort; - int grabbedPort; - Gtk::Widget *drawingArea; - Display *display; - Window window; - GC gc; - XGCValues values; - XvImage *xvImage; - unsigned int port; - XShmSegmentInfo shmInfo; - char pix[ MAX_WIDTH * MAX_HEIGHT * 4 ]; - }; + /** + * Put an image of a given width and height with the expected input + * format (as indicated by the format method). + * @param[in] image The video image array to draw. + */ + void put( const void* image ); + + /** + * Indicates if this object can be used to render images on the + * running system. + */ + bool usable(); + +private: + + /** + * Specifies whether the object is currently attached to an XVideo + * port. + * @remarks This value is false until the constructor has finished + * successfully. + **/ + bool gotPort; + + /** + * The current port being used. + * @remarks This value is meaninless unless gotPort is true. + **/ + unsigned int grabbedPort; + + /** + * The widget that video will be drawn into. + * @remarks This value must be a valid pointer. + **/ + Gtk::Widget *drawingArea; + + /** + * The display that video will be drawn into. + **/ + Display *display; + + /** + * The X11 window that video will be drawn into. + **/ + Window window; + + /** + * The graphics context which will be used when rednering video. + **/ + GC gc; + + /** + * The shared memory image object which video will be written into. + **/ + XvImage *xvImage; + + /** + * Info about the shared memory segment. + * @remarks shmInfo.shmaddr is set to NULL, when the SHM is detached. + **/ + XShmSegmentInfo shmInfo; +}; } // namespace output } // namespace gui From 910bf4b4e4b2ef38866d9c19e12b6ea990e0ec63 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 30 Dec 2008 15:20:19 +0000 Subject: [PATCH 03/68] Added "Remove" to the track dropdown menu --- src/gui/widgets/timeline/timeline-track.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/widgets/timeline/timeline-track.cpp b/src/gui/widgets/timeline/timeline-track.cpp index ea935d7c0..953d66816 100644 --- a/src/gui/widgets/timeline/timeline-track.cpp +++ b/src/gui/widgets/timeline/timeline-track.cpp @@ -70,6 +70,10 @@ Track::Track(TimelineWidget &timeline_widget, Menu::MenuList& title_list = titleMenuButton.get_menu().items(); title_list.push_back( Menu_Helpers::MenuElem(_("_Name..."), mem_fun(this, &Track::on_set_name) ) ); + title_list.push_back( Menu_Helpers::SeparatorElem() ); + title_list.push_back( Menu_Helpers::MenuElem(_("_Remove"), + mem_fun(this, &Track::on_remove_track) ) ); + update_name(); // Setup the context menu From a117fe99e592999568cd02e348ef03123c807f12 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 30 Dec 2008 16:13:09 +0000 Subject: [PATCH 04/68] Removed spurious add_child_track --- src/gui/model/parent-track.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/gui/model/parent-track.hpp b/src/gui/model/parent-track.hpp index 481f7c352..78d27cf85 100644 --- a/src/gui/model/parent-track.hpp +++ b/src/gui/model/parent-track.hpp @@ -39,10 +39,7 @@ class ParentTrack : public Track protected: ParentTrack(); -public: - virtual void add_child_track(Track* child) - { (void)child; }; - +public: std::list< boost::shared_ptr > get_child_tracks() const; From 5e8620135cb95e2b79fcb5a236356160b6342b4f Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 30 Dec 2008 17:16:29 +0000 Subject: [PATCH 05/68] Added stringifying debug methods to track tree classes, and added a big tree to the sequence --- src/gui/model/clip-track.cpp | 10 ++++++++++ src/gui/model/clip-track.hpp | 2 +- src/gui/model/group-track.cpp | 10 ++++++++++ src/gui/model/group-track.hpp | 1 + src/gui/model/sequence.cpp | 34 ++++++++++++++++++++++++++-------- src/gui/model/sequence.hpp | 3 ++- src/gui/model/track.cpp | 30 ++++++++++++++++++++++++++++-- src/gui/model/track.hpp | 15 +++++++++++---- 8 files changed, 89 insertions(+), 16 deletions(-) diff --git a/src/gui/model/clip-track.cpp b/src/gui/model/clip-track.cpp index 5f627eeca..5f8907599 100644 --- a/src/gui/model/clip-track.cpp +++ b/src/gui/model/clip-track.cpp @@ -29,5 +29,15 @@ ClipTrack::ClipTrack() { } +std::string +ClipTrack::print_track() +{ + std::ostringstream os; + + os << "ClipTrack\t\"" << get_name() << "\""; + + return os.str(); +} + } // namespace model } // namespace gui diff --git a/src/gui/model/clip-track.hpp b/src/gui/model/clip-track.hpp index f63ea4e6b..c3c7e0e2f 100644 --- a/src/gui/model/clip-track.hpp +++ b/src/gui/model/clip-track.hpp @@ -40,7 +40,7 @@ class ClipTrack : public Track public: ClipTrack(); - + std::string print_track(); private: diff --git a/src/gui/model/group-track.cpp b/src/gui/model/group-track.cpp index c7572b4d9..73ac08114 100644 --- a/src/gui/model/group-track.cpp +++ b/src/gui/model/group-track.cpp @@ -28,6 +28,16 @@ namespace model { GroupTrack::GroupTrack() { } + +std::string +GroupTrack::print_track() +{ + std::ostringstream os; + + os << "GroupTrack\t\"" << get_name() << "\""; + + return os.str(); +} } // namespace model } // namespace gui diff --git a/src/gui/model/group-track.hpp b/src/gui/model/group-track.hpp index de5ac8f4b..06da74060 100644 --- a/src/gui/model/group-track.hpp +++ b/src/gui/model/group-track.hpp @@ -36,6 +36,7 @@ class GroupTrack : public ParentTrack public: GroupTrack(); + std::string print_track(); }; } // namespace model diff --git a/src/gui/model/sequence.cpp b/src/gui/model/sequence.cpp index 2f89c211b..2503b88cc 100644 --- a/src/gui/model/sequence.cpp +++ b/src/gui/model/sequence.cpp @@ -30,24 +30,42 @@ namespace model { Sequence::Sequence() { // TEST CODE - //static bool first = true; + static bool first = true; shared_ptr group_track, group_track2; + shared_ptr clip_track; tracks.push_back(group_track = shared_ptr(new GroupTrack())); group_track->set_name("Group Track"); - - /*if(first) + + if(first) { - group_track.add_child_track(shared_ptr(new ClipTrack())); - group_track.add_child_track( - group_track2 = shared_ptr(new GroupTrack())); - group_track2.add_child_track(shared_ptr(new ClipTrack())); + group_track->get_child_track_list().push_back( + clip_track = shared_ptr(new ClipTrack())); + group_track->get_child_track_list().push_back( + group_track2 = shared_ptr(new GroupTrack())); + group_track2->set_name("Group Track 2"); + group_track2->get_child_track_list().push_back( + shared_ptr(new ClipTrack())); first = false; - }*/ + } + + tracks.push_back(shared_ptr(new GroupTrack())); tracks.push_back(shared_ptr(new ClipTrack())); // END TEST CODE + + INFO(gui, "\n%s", print_branch().c_str()); +} + +std::string +Sequence::print_track() +{ + std::ostringstream os; + + os << "Sequence\t\"" << get_name() << "\""; + + return os.str(); } } // namespace model diff --git a/src/gui/model/sequence.hpp b/src/gui/model/sequence.hpp index 02a2869c2..277fbf426 100644 --- a/src/gui/model/sequence.hpp +++ b/src/gui/model/sequence.hpp @@ -43,7 +43,8 @@ class Sequence : public ParentTrack public: Sequence(); - + std::string print_track(); + private: }; diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp index 4d49ea2b2..f8390f671 100644 --- a/src/gui/model/track.cpp +++ b/src/gui/model/track.cpp @@ -21,6 +21,7 @@ * *****************************************************/ #include "track.hpp" +#include namespace gui { namespace model { @@ -38,17 +39,42 @@ Track::get_child_tracks() const return Track::NoChildren; } -const Glib::ustring +const std::string Track::get_name() const { return name; } void -Track::set_name(const Glib::ustring &name) +Track::set_name(const std::string &name) { this->name = name; } +std::string +Track::print_branch() +{ + return print_branch_recursive(0); +} + +std::string +Track::print_branch_recursive(const unsigned int indentation) +{ + Glib::ustring str; + + for(unsigned int i = 0; i < indentation; i++) + str += " "; + str += print_track(); + str += "\n"; + + BOOST_FOREACH(boost::shared_ptr track, get_child_tracks()) + { + REQUIRE(track); + str += track->print_branch_recursive(indentation + 1); + } + + return str; +} + } // namespace model } // namespace gui diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp index f57b1d254..f036e3d1d 100644 --- a/src/gui/model/track.hpp +++ b/src/gui/model/track.hpp @@ -41,13 +41,20 @@ public: virtual std::list< boost::shared_ptr > get_child_tracks() const; - const Glib::ustring get_name() const; + const std::string get_name() const; - void set_name(const Glib::ustring &name); - + void set_name(const std::string &name); + + std::string print_branch(); + + virtual std::string print_track() = 0; + +protected: + std::string print_branch_recursive(const unsigned int indentation); + private: //----- Data -----// - Glib::ustring name; + std::string name; protected: static const std::list< boost::shared_ptr > NoChildren; From 4af80c78d8f7d1d66a921ce479bf66ddf5a638dd Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 30 Dec 2008 21:50:18 +0000 Subject: [PATCH 06/68] Reimplemented nested track deleting so it work correctly --- src/gui/model/parent-track.cpp | 23 +++++++++++++++++++ src/gui/model/parent-track.hpp | 2 ++ src/gui/model/track.cpp | 6 +++++ src/gui/model/track.hpp | 4 ++++ src/gui/widgets/timeline-widget.cpp | 5 +++- src/gui/widgets/timeline-widget.hpp | 1 + .../widgets/timeline/timeline-group-track.cpp | 16 ++++++++++++- .../widgets/timeline/timeline-group-track.hpp | 5 +++- src/gui/widgets/timeline/timeline-track.cpp | 2 +- src/gui/widgets/timeline/timeline-track.hpp | 6 ++--- 10 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/gui/model/parent-track.cpp b/src/gui/model/parent-track.cpp index c00048129..612e112d7 100644 --- a/src/gui/model/parent-track.cpp +++ b/src/gui/model/parent-track.cpp @@ -21,6 +21,7 @@ * *****************************************************/ #include "parent-track.hpp" +#include namespace gui { namespace model { @@ -41,5 +42,27 @@ ParentTrack::get_child_track_list() return tracks; } +bool +ParentTrack::remove_child_track(const boost::shared_ptr track) +{ + REQUIRE(track); + + BOOST_FOREACH(const boost::shared_ptr child_track, tracks) + { + REQUIRE(child_track); + + if(track.get() == child_track.get()) + { + tracks.remove(track); + return true; + } + + if(child_track->remove_child_track(track)) + return true; + } + + return false; +} + } // namespace model } // namespace gui diff --git a/src/gui/model/parent-track.hpp b/src/gui/model/parent-track.hpp index 78d27cf85..a895b3427 100644 --- a/src/gui/model/parent-track.hpp +++ b/src/gui/model/parent-track.hpp @@ -45,6 +45,8 @@ public: lumiera::observable_list< boost::shared_ptr >& get_child_track_list(); + + bool remove_child_track(const boost::shared_ptr track); protected: lumiera::observable_list< boost::shared_ptr > tracks; diff --git a/src/gui/model/track.cpp b/src/gui/model/track.cpp index f8390f671..50d50e4b8 100644 --- a/src/gui/model/track.cpp +++ b/src/gui/model/track.cpp @@ -51,6 +51,12 @@ Track::set_name(const std::string &name) this->name = name; } +bool +Track::remove_child_track(const boost::shared_ptr track) +{ + return false; +} + std::string Track::print_branch() { diff --git a/src/gui/model/track.hpp b/src/gui/model/track.hpp index f036e3d1d..42c6e890b 100644 --- a/src/gui/model/track.hpp +++ b/src/gui/model/track.hpp @@ -45,10 +45,14 @@ public: void set_name(const std::string &name); + virtual bool remove_child_track(const boost::shared_ptr track); + std::string print_branch(); virtual std::string print_track() = 0; + + protected: std::string print_branch_recursive(const unsigned int indentation); diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index f954d90ee..4adcfd4d6 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -338,6 +338,9 @@ TimelineWidget::create_timeline_tracks_from_branch( // We will need to create one trackMap[model_track] = create_timeline_track_from_model_track(model_track); + + // Hook up + } // Recurse to child tracks @@ -359,7 +362,7 @@ TimelineWidget::create_timeline_track_from_model_track( *this, model_track)); else if(typeid(*model_track) == typeid(model::GroupTrack)) return shared_ptr(new timeline::GroupTrack( - *this, model_track)); + *this, dynamic_pointer_cast(model_track))); ASSERT(NULL); // Unknown track type; return shared_ptr(); diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index 41ad86b75..3cdca51e7 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -328,6 +328,7 @@ protected: friend class timeline::ArrowTool; friend class timeline::IBeamTool; friend class timeline::Track; + friend class timeline::GroupTrack; }; } // namespace widgets diff --git a/src/gui/widgets/timeline/timeline-group-track.cpp b/src/gui/widgets/timeline/timeline-group-track.cpp index f6e7b8382..56ad56c0a 100644 --- a/src/gui/widgets/timeline/timeline-group-track.cpp +++ b/src/gui/widgets/timeline/timeline-group-track.cpp @@ -21,17 +21,31 @@ * *****************************************************/ #include "timeline-group-track.hpp" +#include "../timeline-widget.hpp" using namespace Gtk; +using namespace boost; +using namespace sigc; namespace gui { namespace widgets { namespace timeline { GroupTrack::GroupTrack(TimelineWidget &timeline_widget, - boost::shared_ptr track) : + shared_ptr track) : Track(timeline_widget, track) +{ + REQUIRE(track); + + // Receive notifications of changes to the tracks + track->get_child_track_list().signal_changed().connect( + sigc::mem_fun( this, &GroupTrack::on_child_list_changed ) ); +} + +void +GroupTrack::on_child_list_changed() { + timelineWidget.on_track_list_changed(); } void diff --git a/src/gui/widgets/timeline/timeline-group-track.hpp b/src/gui/widgets/timeline/timeline-group-track.hpp index 6530503c2..821acf9a8 100644 --- a/src/gui/widgets/timeline/timeline-group-track.hpp +++ b/src/gui/widgets/timeline/timeline-group-track.hpp @@ -37,11 +37,14 @@ class GroupTrack : public timeline::Track { public: GroupTrack(TimelineWidget &timeline_widget, - boost::shared_ptr track); + boost::shared_ptr track); void draw_track(Cairo::RefPtr cairo, TimelineViewWindow* constwindow) const; + +protected: + void on_child_list_changed(); }; } // namespace timeline diff --git a/src/gui/widgets/timeline/timeline-track.cpp b/src/gui/widgets/timeline/timeline-track.cpp index 953d66816..e7d39e22a 100644 --- a/src/gui/widgets/timeline/timeline-track.cpp +++ b/src/gui/widgets/timeline/timeline-track.cpp @@ -146,7 +146,7 @@ Track::on_remove_track() REQUIRE(model_track); REQUIRE(timelineWidget.sequence); - timelineWidget.sequence->get_child_track_list().remove(model_track); + timelineWidget.sequence->remove_child_track(model_track); } } // namespace timeline diff --git a/src/gui/widgets/timeline/timeline-track.hpp b/src/gui/widgets/timeline/timeline-track.hpp index 89215be69..1840b207d 100644 --- a/src/gui/widgets/timeline/timeline-track.hpp +++ b/src/gui/widgets/timeline/timeline-track.hpp @@ -37,7 +37,7 @@ namespace timeline { class TimelineViewWindow; -class Track +class Track : public sigc::trackable { public: Track(TimelineWidget &timeline_widget, @@ -68,12 +68,12 @@ private: void on_remove_track(); - -private: +protected: TimelineWidget &timelineWidget; boost::shared_ptr model_track; +private: bool expanded; //----- Header Widgets ------// From c32ae85a383a7cc174338407d2fc913bc0793e43 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 30 Dec 2008 22:10:24 +0000 Subject: [PATCH 07/68] Small comment correction in timeline-header-container.hpp --- src/gui/widgets/timeline/timeline-header-container.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index 86d61182e..04f332582 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -1,5 +1,5 @@ /* - timeline-header-container.cpp - Declaration of the timeline + timeline-header-container.hpp - Declaration of the timeline header container widget Copyright (C) Lumiera.org From 77c056266f4114cd55bd086f55ab4bbe8c5395f0 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 30 Dec 2008 22:27:09 +0000 Subject: [PATCH 08/68] Added empty timeline layout helper class --- src/gui/Makefile.am | 2 + src/gui/widgets/timeline-widget.hpp | 4 ++ .../timeline/timeline-layout-helper.cpp | 38 ++++++++++++++ .../timeline/timeline-layout-helper.hpp | 50 +++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 src/gui/widgets/timeline/timeline-layout-helper.cpp create mode 100644 src/gui/widgets/timeline/timeline-layout-helper.hpp diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 467521430..70e8264fb 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -144,6 +144,8 @@ libgui_la_SOURCES = \ $(lumigui_srcdir)/widgets/timeline/timeline-group-track.hpp \ $(lumigui_srcdir)/widgets/timeline/timeline-clip.cpp \ $(lumigui_srcdir)/widgets/timeline/timeline-clip.hpp \ + $(lumigui_srcdir)/widgets/timeline/timeline-layout-helper.cpp \ + $(lumigui_srcdir)/widgets/timeline/timeline-layout-helper.hpp \ $(lumigui_srcdir)/model/project.cpp \ $(lumigui_srcdir)/model/project.hpp \ $(lumigui_srcdir)/model/track.cpp \ diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index 3cdca51e7..c169efb21 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -35,6 +35,7 @@ #include "timeline/timeline-ibeam-tool.hpp" #include "timeline/timeline-group-track.hpp" #include "timeline/timeline-clip-track.hpp" +#include "timeline/timeline-layout-helper.hpp" #include "../model/sequence.hpp" @@ -276,6 +277,9 @@ protected: std::map, boost::shared_ptr > trackMap; + + // Helper Classes + timeline::TimelineLayoutHelper layoutHelper; // View State timeline::TimelineViewWindow viewWindow; diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp new file mode 100644 index 000000000..28dfcf25b --- /dev/null +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -0,0 +1,38 @@ +/* + timeline-layout-helper.cpp - Implementation of the timeline + layout helper class + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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. + +* *****************************************************/ + +#include + +#include "timeline-layout-helper.hpp" + +using namespace Gtk; +using namespace std; +using namespace boost; + +namespace gui { +namespace widgets { +namespace timeline { + +} // namespace timeline +} // namespace widgets +} // namespace gui diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp new file mode 100644 index 000000000..3bb48e800 --- /dev/null +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -0,0 +1,50 @@ +/* + timeline-layout-helper.hpp - Declaration of the timeline + layout helper class + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 timeline-layout-helper.cpp + ** This file contains the definition of the layout helpeer class + */ + +#ifndef TIMELINE_LAYOUT_HELPER_HPP +#define TIMELINE_LAYOUT_HELPER_HPP + +#include "../../gtk-lumiera.hpp" + +namespace gui { +namespace widgets { +namespace timeline { + +/** + * A helper class for the TimelineWidget. TimelineLayoutHelper + * is a class which calculates the layout of tracks in the timeline + * track tree. + */ +class TimelineLayoutHelper +{ + +}; + +} // namespace timeline +} // namespace widgets +} // namespace gui + +#endif // TIMELINE_LAYOUT_HELPER_HPP From 2bea14748ce315b7010eeebdf4d6274c45c86507 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 30 Dec 2008 22:58:21 +0000 Subject: [PATCH 09/68] Added Kasper Peeters STL-like templated tree class to lib --- src/lib/Makefile.am | 1 + src/lib/tree.hpp | 2715 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2716 insertions(+) create mode 100644 src/lib/tree.hpp diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 834681720..54c210ce8 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -86,6 +86,7 @@ noinst_HEADERS += \ $(liblumiera_la_srcdir)/observable-list.hpp \ $(liblumiera_la_srcdir)/sync.hpp \ $(liblumiera_la_srcdir)/sync-classlock.hpp \ + $(liblumiera_la_srcdir)/tree.hpp \ $(liblumiera_la_srcdir)/test/mockinjector.hpp \ $(liblumiera_la_srcdir)/test/suite.hpp \ $(liblumiera_la_srcdir)/test/testoption.hpp \ diff --git a/src/lib/tree.hpp b/src/lib/tree.hpp new file mode 100644 index 000000000..6ce5327c3 --- /dev/null +++ b/src/lib/tree.hpp @@ -0,0 +1,2715 @@ +/* + + $Id: tree.hh,v 1.151 2008/05/07 15:46:14 peekas Exp $ + + STL-like templated tree class. + Copyright (C) 2001-2006 Kasper Peeters . + +*/ + +/** \mainpage tree.hh + \author Kasper Peeters + \version 2.62 + \date 28-Aug-2008 + \see http://www.aei.mpg.de/~peekas/tree/ + \see http://www.aei.mpg.de/~peekas/tree/ChangeLog + + The tree.hh library for C++ provides an STL-like container class + for n-ary trees, templated over the data stored at the + nodes. Various types of iterators are provided (post-order, + pre-order, and others). Where possible the access methods are + compatible with the STL or alternative algorithms are + available. +*/ + + +/* + The tree.hh code 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; version 2 or 3. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** \todo + - New-style move members are not completely finished yet. + - It would be good to have an iterator which can iterate over all + nodes below a given node. Something similar to the leaf iterator + we have right now, but not restricted to the leaves. + - If a range uses const iter_base& as end iterator, things will + inevitably go wrong, because upcast from iter_base to a non-sibling_iter + is incorrect. This upcast should be removed (and then all illegal uses + as previously in 'equal' will be flagged by the compiler). This requires + new copy constructors though. + - There's a bug in replace(sibling_iterator, ...) when the ranges + sit next to each other. Turned up in append_child(iter,iter) + but has been avoided now. + - "std::operator<" does not work correctly on our iterators, and for some + reason a globally defined template operator< did not get picked up. + Using a comparison class now, but this should be investigated. +*/ + +#ifndef tree_hh_ +#define tree_hh_ + +#include +#include +#include +#include +#include +#include +#include + +// HP-style construct/destroy have gone from the standard, +// so here is a copy. + +namespace lumiera { + +template +void constructor(T1* p, T2& val) + { + new ((void *) p) T1(val); + } + +template +void constructor(T1* p) + { + new ((void *) p) T1; + } + +template +void destructor(T1* p) + { + p->~T1(); + } + +}; + +/// A node in the tree, combining links to other nodes as well as the actual data. +template +class tree_node_ { // size: 5*4=20 bytes (on 32 bit arch), can be reduced by 8. + public: + tree_node_ *parent; + tree_node_ *first_child, *last_child; + tree_node_ *prev_sibling, *next_sibling; + T data; +}; // __attribute__((packed)); + +template > > +class tree { + protected: + typedef tree_node_ tree_node; + public: + /// Value of the data stored at a node. + typedef T value_type; + + class iterator_base; + class pre_order_iterator; + class post_order_iterator; + class sibling_iterator; + class leaf_iterator; + + tree(); + tree(const T&); + tree(const iterator_base&); + tree(const tree&); + ~tree(); + void operator=(const tree&); + + /// Base class for iterators, only pointers stored, no traversal logic. +#ifdef __SGI_STL_PORT + class iterator_base : public stlport::bidirectional_iterator { +#else + class iterator_base { +#endif + public: + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + iterator_base(); + iterator_base(tree_node *); + + T& operator*() const; + T* operator->() const; + + /// When called, the next increment/decrement skips children of this node. + void skip_children(); + /// Number of children of the node pointed to by the iterator. + unsigned int number_of_children() const; + + sibling_iterator begin() const; + sibling_iterator end() const; + + tree_node *node; + protected: + bool skip_current_children_; + }; + + /// Depth-first iterator, first accessing the node, then its children. + class pre_order_iterator : public iterator_base { + public: + pre_order_iterator(); + pre_order_iterator(tree_node *); + pre_order_iterator(const iterator_base&); + pre_order_iterator(const sibling_iterator&); + + bool operator==(const pre_order_iterator&) const; + bool operator!=(const pre_order_iterator&) const; + pre_order_iterator& operator++(); + pre_order_iterator& operator--(); + pre_order_iterator operator++(int); + pre_order_iterator operator--(int); + pre_order_iterator& operator+=(unsigned int); + pre_order_iterator& operator-=(unsigned int); + }; + + /// Depth-first iterator, first accessing the children, then the node itself. + class post_order_iterator : public iterator_base { + public: + post_order_iterator(); + post_order_iterator(tree_node *); + post_order_iterator(const iterator_base&); + post_order_iterator(const sibling_iterator&); + + bool operator==(const post_order_iterator&) const; + bool operator!=(const post_order_iterator&) const; + post_order_iterator& operator++(); + post_order_iterator& operator--(); + post_order_iterator operator++(int); + post_order_iterator operator--(int); + post_order_iterator& operator+=(unsigned int); + post_order_iterator& operator-=(unsigned int); + + /// Set iterator to the first child as deep as possible down the tree. + void descend_all(); + }; + + /// Breadth-first iterator, using a queue + class breadth_first_queued_iterator : public iterator_base { + public: + breadth_first_queued_iterator(); + breadth_first_queued_iterator(tree_node *); + breadth_first_queued_iterator(const iterator_base&); + + bool operator==(const breadth_first_queued_iterator&) const; + bool operator!=(const breadth_first_queued_iterator&) const; + breadth_first_queued_iterator& operator++(); + breadth_first_queued_iterator operator++(int); + breadth_first_queued_iterator& operator+=(unsigned int); + + private: + std::queue traversal_queue; + }; + + /// The default iterator types throughout the tree class. + typedef pre_order_iterator iterator; + typedef breadth_first_queued_iterator breadth_first_iterator; + + /// Iterator which traverses only the nodes at a given depth from the root. + class fixed_depth_iterator : public iterator_base { + public: + fixed_depth_iterator(); + fixed_depth_iterator(tree_node *); + fixed_depth_iterator(const iterator_base&); + fixed_depth_iterator(const sibling_iterator&); + fixed_depth_iterator(const fixed_depth_iterator&); + + bool operator==(const fixed_depth_iterator&) const; + bool operator!=(const fixed_depth_iterator&) const; + fixed_depth_iterator& operator++(); + fixed_depth_iterator& operator--(); + fixed_depth_iterator operator++(int); + fixed_depth_iterator operator--(int); + fixed_depth_iterator& operator+=(unsigned int); + fixed_depth_iterator& operator-=(unsigned int); + + tree_node *top_node; + }; + + /// Iterator which traverses only the nodes which are siblings of each other. + class sibling_iterator : public iterator_base { + public: + sibling_iterator(); + sibling_iterator(tree_node *); + sibling_iterator(const sibling_iterator&); + sibling_iterator(const iterator_base&); + + bool operator==(const sibling_iterator&) const; + bool operator!=(const sibling_iterator&) const; + sibling_iterator& operator++(); + sibling_iterator& operator--(); + sibling_iterator operator++(int); + sibling_iterator operator--(int); + sibling_iterator& operator+=(unsigned int); + sibling_iterator& operator-=(unsigned int); + + tree_node *range_first() const; + tree_node *range_last() const; + tree_node *parent_; + private: + void set_parent_(); + }; + + /// Iterator which traverses only the leaves. + class leaf_iterator : public iterator_base { + public: + leaf_iterator(); + leaf_iterator(tree_node *, tree_node *top=0); + leaf_iterator(const sibling_iterator&); + leaf_iterator(const iterator_base&); + + bool operator==(const leaf_iterator&) const; + bool operator!=(const leaf_iterator&) const; + leaf_iterator& operator++(); + leaf_iterator& operator--(); + leaf_iterator operator++(int); + leaf_iterator operator--(int); + leaf_iterator& operator+=(unsigned int); + leaf_iterator& operator-=(unsigned int); + private: + tree_node *top_node; + }; + + /// Return iterator to the beginning of the tree. + inline pre_order_iterator begin() const; + /// Return iterator to the end of the tree. + inline pre_order_iterator end() const; + /// Return post-order iterator to the beginning of the tree. + post_order_iterator begin_post() const; + /// Return post-order end iterator of the tree. + post_order_iterator end_post() const; + /// Return fixed-depth iterator to the first node at a given depth from the given iterator. + fixed_depth_iterator begin_fixed(const iterator_base&, unsigned int) const; + /// Return fixed-depth end iterator. + fixed_depth_iterator end_fixed(const iterator_base&, unsigned int) const; + /// Return breadth-first iterator to the first node at a given depth. + breadth_first_queued_iterator begin_breadth_first() const; + /// Return breadth-first end iterator. + breadth_first_queued_iterator end_breadth_first() const; + /// Return sibling iterator to the first child of given node. + sibling_iterator begin(const iterator_base&) const; + /// Return sibling end iterator for children of given node. + sibling_iterator end(const iterator_base&) const; + /// Return leaf iterator to the first leaf of the tree. + leaf_iterator begin_leaf() const; + /// Return leaf end iterator for entire tree. + leaf_iterator end_leaf() const; + /// Return leaf iterator to the first leaf of the subtree at the given node. + leaf_iterator begin_leaf(const iterator_base& top) const; + /// Return leaf end iterator for the subtree at the given node. + leaf_iterator end_leaf(const iterator_base& top) const; + + /// Return iterator to the parent of a node. + template static iter parent(iter); + /// Return iterator to the previous sibling of a node. + template iter previous_sibling(iter) const; + /// Return iterator to the next sibling of a node. + template iter next_sibling(iter) const; + /// Return iterator to the next node at a given depth. + template iter next_at_same_depth(iter) const; + + /// Erase all nodes of the tree. + void clear(); + /// Erase element at position pointed to by iterator, return incremented iterator. + template iter erase(iter); + /// Erase all children of the node pointed to by iterator. + void erase_children(const iterator_base&); + + /// Insert empty node as last/first child of node pointed to by position. + template iter append_child(iter position); + template iter prepend_child(iter position); + /// Insert node as last/first child of node pointed to by position. + template iter append_child(iter position, const T& x); + template iter prepend_child(iter position, const T& x); + /// Append the node (plus its children) at other_position as last/first child of position. + template iter append_child(iter position, iter other_position); + template iter prepend_child(iter position, iter other_position); + /// Append the nodes in the from-to range (plus their children) as last/first children of position. + template iter append_children(iter position, sibling_iterator from, sibling_iterator to); + template iter prepend_children(iter position, sibling_iterator from, sibling_iterator to); + + /// Short-hand to insert topmost node in otherwise empty tree. + pre_order_iterator set_head(const T& x); + /// Insert node as previous sibling of node pointed to by position. + template iter insert(iter position, const T& x); + /// Specialisation of previous member. + sibling_iterator insert(sibling_iterator position, const T& x); + /// Insert node (with children) pointed to by subtree as previous sibling of node pointed to by position. + template iter insert_subtree(iter position, const iterator_base& subtree); + /// Insert node as next sibling of node pointed to by position. + template iter insert_after(iter position, const T& x); + /// Insert node (with children) pointed to by subtree as next sibling of node pointed to by position. + template iter insert_subtree_after(iter position, const iterator_base& subtree); + + /// Replace node at 'position' with other node (keeping same children); 'position' becomes invalid. + template iter replace(iter position, const T& x); + /// Replace node at 'position' with subtree starting at 'from' (do not erase subtree at 'from'); see above. + template iter replace(iter position, const iterator_base& from); + /// Replace string of siblings (plus their children) with copy of a new string (with children); see above + sibling_iterator replace(sibling_iterator orig_begin, sibling_iterator orig_end, + sibling_iterator new_begin, sibling_iterator new_end); + + /// Move all children of node at 'position' to be siblings, returns position. + template iter flatten(iter position); + /// Move nodes in range to be children of 'position'. + template iter reparent(iter position, sibling_iterator begin, sibling_iterator end); + /// Move all child nodes of 'from' to be children of 'position'. + template iter reparent(iter position, iter from); + + /// Replace node with a new node, making the old node a child of the new node. + template iter wrap(iter position, const T& x); + + /// Move 'source' node (plus its children) to become the next sibling of 'target'. + template iter move_after(iter target, iter source); + /// Move 'source' node (plus its children) to become the previous sibling of 'target'. + template iter move_before(iter target, iter source); + sibling_iterator move_before(sibling_iterator target, sibling_iterator source); + /// Move 'source' node (plus its children) to become the node at 'target' (erasing the node at 'target'). + template iter move_ontop(iter target, iter source); + + /// Merge with other tree, creating new branches and leaves only if they are not already present. + void merge(sibling_iterator, sibling_iterator, sibling_iterator, sibling_iterator, + bool duplicate_leaves=false); + /// Sort (std::sort only moves values of nodes, this one moves children as well). + void sort(sibling_iterator from, sibling_iterator to, bool deep=false); + template + void sort(sibling_iterator from, sibling_iterator to, StrictWeakOrdering comp, bool deep=false); + /// Compare two ranges of nodes (compares nodes as well as tree structure). + template + bool equal(const iter& one, const iter& two, const iter& three) const; + template + bool equal(const iter& one, const iter& two, const iter& three, BinaryPredicate) const; + template + bool equal_subtree(const iter& one, const iter& two) const; + template + bool equal_subtree(const iter& one, const iter& two, BinaryPredicate) const; + /// Extract a new tree formed by the range of siblings plus all their children. + tree subtree(sibling_iterator from, sibling_iterator to) const; + void subtree(tree&, sibling_iterator from, sibling_iterator to) const; + /// Exchange the node (plus subtree) with its sibling node (do nothing if no sibling present). + void swap(sibling_iterator it); + /// Exchange two nodes (plus subtrees) + void swap(iterator, iterator); + + /// Count the total number of nodes. + size_t size() const; + /// Count the total number of nodes below the indicated node (plus one). + size_t size(const iterator_base&) const; + /// Check if tree is empty. + bool empty() const; + /// Compute the depth to the root or to a fixed other iterator. + static int depth(const iterator_base&); + static int depth(const iterator_base&, const iterator_base&); + /// Determine the maximal depth of the tree. An empty tree has max_depth=-1. + int max_depth() const; + /// Determine the maximal depth of the tree with top node at the given position. + int max_depth(const iterator_base&) const; + /// Count the number of children of node at position. + static unsigned int number_of_children(const iterator_base&); + /// Count the number of siblings (left and right) of node at iterator. Total nodes at this level is +1. + unsigned int number_of_siblings(const iterator_base&) const; + /// Determine whether node at position is in the subtrees with root in the range. + bool is_in_subtree(const iterator_base& position, const iterator_base& begin, + const iterator_base& end) const; + /// Determine whether the iterator is an 'end' iterator and thus not actually pointing to a node. + bool is_valid(const iterator_base&) const; + + /// Determine the index of a node in the range of siblings to which it belongs. + unsigned int index(sibling_iterator it) const; + /// Inverse of 'index': return the n-th child of the node at position. + static sibling_iterator child(const iterator_base& position, unsigned int); + + /// Comparator class for iterators (compares pointer values; why doesn't this work automatically?) + class iterator_base_less { + public: + bool operator()(const typename tree::iterator_base& one, + const typename tree::iterator_base& two) const + { + return one.node < two.node; + } + }; + tree_node *head, *feet; // head/feet are always dummy; if an iterator points to them it is invalid + private: + tree_node_allocator alloc_; + void head_initialise_(); + void copy_(const tree& other); + + /// Comparator class for two nodes of a tree (used for sorting and searching). + template + class compare_nodes { + public: + compare_nodes(StrictWeakOrdering comp) : comp_(comp) {}; + + bool operator()(const tree_node *a, const tree_node *b) + { + static StrictWeakOrdering comp; + return comp(a->data, b->data); + } + private: + StrictWeakOrdering comp_; + }; +}; + +//template +//class iterator_base_less { +// public: +// bool operator()(const typename tree::iterator_base& one, +// const typename tree::iterator_base& two) const +// { +// txtout << "operatorclass<" << one.node < two.node << std::endl; +// return one.node < two.node; +// } +//}; + +// template +// bool operator<(const typename tree::iterator& one, +// const typename tree::iterator& two) +// { +// txtout << "operator< " << one.node < two.node << std::endl; +// if(one.node < two.node) return true; +// return false; +// } +// +// template +// bool operator==(const typename tree::iterator& one, +// const typename tree::iterator& two) +// { +// txtout << "operator== " << one.node == two.node << std::endl; +// if(one.node == two.node) return true; +// return false; +// } +// +// template +// bool operator>(const typename tree::iterator_base& one, +// const typename tree::iterator_base& two) +// { +// txtout << "operator> " << one.node < two.node << std::endl; +// if(one.node > two.node) return true; +// return false; +// } + + + +// Tree + +template +tree::tree() + { + head_initialise_(); + } + +template +tree::tree(const T& x) + { + head_initialise_(); + set_head(x); + } + +template +tree::tree(const iterator_base& other) + { + head_initialise_(); + set_head((*other)); + replace(begin(), other); + } + +template +tree::~tree() + { + clear(); + alloc_.deallocate(head,1); + alloc_.deallocate(feet,1); + } + +template +void tree::head_initialise_() + { + head = alloc_.allocate(1,0); // MSVC does not have default second argument + feet = alloc_.allocate(1,0); + + head->parent=0; + head->first_child=0; + head->last_child=0; + head->prev_sibling=0; //head; + head->next_sibling=feet; //head; + + feet->parent=0; + feet->first_child=0; + feet->last_child=0; + feet->prev_sibling=head; + feet->next_sibling=0; + } + +template +void tree::operator=(const tree& other) + { + copy_(other); + } + +template +tree::tree(const tree& other) + { + head_initialise_(); + copy_(other); + } + +template +void tree::copy_(const tree& other) + { + clear(); + pre_order_iterator it=other.begin(), to=begin(); + while(it!=other.end()) { + to=insert(to, (*it)); + it.skip_children(); + ++it; + } + to=begin(); + it=other.begin(); + while(it!=other.end()) { + to=replace(to, it); + to.skip_children(); + it.skip_children(); + ++to; + ++it; + } + } + +template +void tree::clear() + { + if(head) + while(head->next_sibling!=feet) + erase(pre_order_iterator(head->next_sibling)); + } + +template +void tree::erase_children(const iterator_base& it) + { +// std::cout << "erase_children " << it.node << std::endl; + if(it.node==0) return; + + tree_node *cur=it.node->first_child; + tree_node *prev=0; + + while(cur!=0) { + prev=cur; + cur=cur->next_sibling; + erase_children(pre_order_iterator(prev)); + kp::destructor(&prev->data); + alloc_.deallocate(prev,1); + } + it.node->first_child=0; + it.node->last_child=0; +// std::cout << "exit" << std::endl; + } + +template +template +iter tree::erase(iter it) + { + tree_node *cur=it.node; + assert(cur!=head); + iter ret=it; + ret.skip_children(); + ++ret; + erase_children(it); + if(cur->prev_sibling==0) { + cur->parent->first_child=cur->next_sibling; + } + else { + cur->prev_sibling->next_sibling=cur->next_sibling; + } + if(cur->next_sibling==0) { + cur->parent->last_child=cur->prev_sibling; + } + else { + cur->next_sibling->prev_sibling=cur->prev_sibling; + } + + kp::destructor(&cur->data); + alloc_.deallocate(cur,1); + return ret; + } + +template +typename tree::pre_order_iterator tree::begin() const + { + return pre_order_iterator(head->next_sibling); + } + +template +typename tree::pre_order_iterator tree::end() const + { + return pre_order_iterator(feet); + } + +template +typename tree::breadth_first_queued_iterator tree::begin_breadth_first() const + { + return breadth_first_queued_iterator(head->next_sibling); + } + +template +typename tree::breadth_first_queued_iterator tree::end_breadth_first() const + { + return breadth_first_queued_iterator(); + } + +template +typename tree::post_order_iterator tree::begin_post() const + { + tree_node *tmp=head->next_sibling; + if(tmp!=feet) { + while(tmp->first_child) + tmp=tmp->first_child; + } + return post_order_iterator(tmp); + } + +template +typename tree::post_order_iterator tree::end_post() const + { + return post_order_iterator(feet); + } + +template +typename tree::fixed_depth_iterator tree::begin_fixed(const iterator_base& pos, unsigned int dp) const + { + typename tree::fixed_depth_iterator ret; + ret.top_node=pos.node; + + tree_node *tmp=pos.node; + unsigned int curdepth=0; + while(curdepthfirst_child==0) { + if(tmp->next_sibling==0) { + // try to walk up and then right again + do { + if(tmp==ret.top_node) + throw std::range_error("tree: begin_fixed out of range"); + tmp=tmp->parent; + if(tmp==0) + throw std::range_error("tree: begin_fixed out of range"); + --curdepth; + } while(tmp->next_sibling==0); + } + tmp=tmp->next_sibling; + } + tmp=tmp->first_child; + ++curdepth; + } + + ret.node=tmp; + return ret; + } + +template +typename tree::fixed_depth_iterator tree::end_fixed(const iterator_base& pos, unsigned int dp) const + { + assert(1==0); // FIXME: not correct yet: use is_valid() as a temporary workaround + tree_node *tmp=pos.node; + unsigned int curdepth=1; + while(curdepthfirst_child==0) { + tmp=tmp->next_sibling; + if(tmp==0) + throw std::range_error("tree: end_fixed out of range"); + } + tmp=tmp->first_child; + ++curdepth; + } + return tmp; + } + +template +typename tree::sibling_iterator tree::begin(const iterator_base& pos) const + { + assert(pos.node!=0); + if(pos.node->first_child==0) { + return end(pos); + } + return pos.node->first_child; + } + +template +typename tree::sibling_iterator tree::end(const iterator_base& pos) const + { + sibling_iterator ret(0); + ret.parent_=pos.node; + return ret; + } + +template +typename tree::leaf_iterator tree::begin_leaf() const + { + tree_node *tmp=head->next_sibling; + if(tmp!=feet) { + while(tmp->first_child) + tmp=tmp->first_child; + } + return leaf_iterator(tmp); + } + +template +typename tree::leaf_iterator tree::end_leaf() const + { + return leaf_iterator(feet); + } + +template +typename tree::leaf_iterator tree::begin_leaf(const iterator_base& top) const + { + tree_node *tmp=top.node; + while(tmp->first_child) + tmp=tmp->first_child; + return leaf_iterator(tmp, top.node); + } + +template +typename tree::leaf_iterator tree::end_leaf(const iterator_base& top) const + { + return leaf_iterator(top.node, top.node); + } + +template +template +iter tree::parent(iter position) + { + assert(position.node!=0); + return iter(position.node->parent); + } + +template +template +iter tree::previous_sibling(iter position) const + { + assert(position.node!=0); + iter ret(position); + ret.node=position.node->prev_sibling; + return ret; + } + +template +template +iter tree::next_sibling(iter position) const + { + assert(position.node!=0); + iter ret(position); + ret.node=position.node->next_sibling; + return ret; + } + +template +template +iter tree::next_at_same_depth(iter position) const + { + // We make use of a temporary fixed_depth iterator to implement this. + + typename tree::fixed_depth_iterator tmp(position.node); + + ++tmp; + return iter(tmp); + +// assert(position.node!=0); +// iter ret(position); +// +// if(position.node->next_sibling) { +// ret.node=position.node->next_sibling; +// } +// else { +// int relative_depth=0; +// upper: +// do { +// ret.node=ret.node->parent; +// if(ret.node==0) return ret; +// --relative_depth; +// } while(ret.node->next_sibling==0); +// lower: +// ret.node=ret.node->next_sibling; +// while(ret.node->first_child==0) { +// if(ret.node->next_sibling==0) +// goto upper; +// ret.node=ret.node->next_sibling; +// if(ret.node==0) return ret; +// } +// while(relative_depth<0 && ret.node->first_child!=0) { +// ret.node=ret.node->first_child; +// ++relative_depth; +// } +// if(relative_depth<0) { +// if(ret.node->next_sibling==0) goto upper; +// else goto lower; +// } +// } +// return ret; + } + +template +template +iter tree::append_child(iter position) + { + assert(position.node!=head); + assert(position.node); + + tree_node *tmp=alloc_.allocate(1,0); + kp::constructor(&tmp->data); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->last_child!=0) { + position.node->last_child->next_sibling=tmp; + } + else { + position.node->first_child=tmp; + } + tmp->prev_sibling=position.node->last_child; + position.node->last_child=tmp; + tmp->next_sibling=0; + return tmp; + } + +template +template +iter tree::prepend_child(iter position) + { + assert(position.node!=head); + assert(position.node); + + tree_node *tmp=alloc_.allocate(1,0); + kp::constructor(&tmp->data); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->first_child!=0) { + position.node->first_child->prev_sibling=tmp; + } + else { + position.node->last_child=tmp; + } + tmp->next_sibling=position.node->first_child; + position.node->prev_child=tmp; + tmp->prev_sibling=0; + return tmp; + } + +template +template +iter tree::append_child(iter position, const T& x) + { + // If your program fails here you probably used 'append_child' to add the top + // node to an empty tree. From version 1.45 the top element should be added + // using 'insert'. See the documentation for further information, and sorry about + // the API change. + assert(position.node!=head); + assert(position.node); + + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->last_child!=0) { + position.node->last_child->next_sibling=tmp; + } + else { + position.node->first_child=tmp; + } + tmp->prev_sibling=position.node->last_child; + position.node->last_child=tmp; + tmp->next_sibling=0; + return tmp; + } + +template +template +iter tree::prepend_child(iter position, const T& x) + { + assert(position.node!=head); + assert(position.node); + + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->first_child!=0) { + position.node->first_child->prev_sibling=tmp; + } + else { + position.node->last_child=tmp; + } + tmp->next_sibling=position.node->first_child; + position.node->first_child=tmp; + tmp->prev_sibling=0; + return tmp; + } + +template +template +iter tree::append_child(iter position, iter other) + { + assert(position.node!=head); + assert(position.node); + + sibling_iterator aargh=append_child(position, value_type()); + return replace(aargh, other); + } + +template +template +iter tree::prepend_child(iter position, iter other) + { + assert(position.node!=head); + assert(position.node); + + sibling_iterator aargh=prepend_child(position, value_type()); + return replace(aargh, other); + } + +template +template +iter tree::append_children(iter position, sibling_iterator from, sibling_iterator to) + { + assert(position.node!=head); + assert(position.node); + + iter ret=from; + + while(from!=to) { + insert_subtree(position.end(), from); + ++from; + } + return ret; + } + +template +template +iter tree::prepend_children(iter position, sibling_iterator from, sibling_iterator to) + { + assert(position.node!=head); + assert(position.node); + + iter ret=from; + + while(from!=to) { + insert_subtree(position.begin(), from); + ++from; + } + return ret; + } + +template +typename tree::pre_order_iterator tree::set_head(const T& x) + { + assert(head->next_sibling==feet); + return insert(iterator(feet), x); + } + +template +template +iter tree::insert(iter position, const T& x) + { + if(position.node==0) { + position.node=feet; // Backward compatibility: when calling insert on a null node, + // insert before the feet. + } + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node->parent; + tmp->next_sibling=position.node; + tmp->prev_sibling=position.node->prev_sibling; + position.node->prev_sibling=tmp; + + if(tmp->prev_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->first_child=tmp; + } + else + tmp->prev_sibling->next_sibling=tmp; + return tmp; + } + +template +typename tree::sibling_iterator tree::insert(sibling_iterator position, const T& x) + { + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->next_sibling=position.node; + if(position.node==0) { // iterator points to end of a subtree + tmp->parent=position.parent_; + tmp->prev_sibling=position.range_last(); + tmp->parent->last_child=tmp; + } + else { + tmp->parent=position.node->parent; + tmp->prev_sibling=position.node->prev_sibling; + position.node->prev_sibling=tmp; + } + + if(tmp->prev_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->first_child=tmp; + } + else + tmp->prev_sibling->next_sibling=tmp; + return tmp; + } + +template +template +iter tree::insert_after(iter position, const T& x) + { + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node->parent; + tmp->prev_sibling=position.node; + tmp->next_sibling=position.node->next_sibling; + position.node->next_sibling=tmp; + + if(tmp->next_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->last_child=tmp; + } + else { + tmp->next_sibling->prev_sibling=tmp; + } + return tmp; + } + +template +template +iter tree::insert_subtree(iter position, const iterator_base& subtree) + { + // insert dummy + iter it=insert(position, value_type()); + // replace dummy with subtree + return replace(it, subtree); + } + +template +template +iter tree::insert_subtree_after(iter position, const iterator_base& subtree) + { + // insert dummy + iter it=insert_after(position, value_type()); + // replace dummy with subtree + return replace(it, subtree); + } + +// template +// template +// iter tree::insert_subtree(sibling_iterator position, iter subtree) +// { +// // insert dummy +// iter it(insert(position, value_type())); +// // replace dummy with subtree +// return replace(it, subtree); +// } + +template +template +iter tree::replace(iter position, const T& x) + { + kp::destructor(&position.node->data); + kp::constructor(&position.node->data, x); + return position; + } + +template +template +iter tree::replace(iter position, const iterator_base& from) + { + assert(position.node!=head); + tree_node *current_from=from.node; + tree_node *start_from=from.node; + tree_node *current_to =position.node; + + // replace the node at position with head of the replacement tree at from +// std::cout << "warning!" << position.node << std::endl; + erase_children(position); +// std::cout << "no warning!" << std::endl; + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, (*from)); + tmp->first_child=0; + tmp->last_child=0; + if(current_to->prev_sibling==0) { + if(current_to->parent!=0) + current_to->parent->first_child=tmp; + } + else { + current_to->prev_sibling->next_sibling=tmp; + } + tmp->prev_sibling=current_to->prev_sibling; + if(current_to->next_sibling==0) { + if(current_to->parent!=0) + current_to->parent->last_child=tmp; + } + else { + current_to->next_sibling->prev_sibling=tmp; + } + tmp->next_sibling=current_to->next_sibling; + tmp->parent=current_to->parent; + kp::destructor(¤t_to->data); + alloc_.deallocate(current_to,1); + current_to=tmp; + + // only at this stage can we fix 'last' + tree_node *last=from.node->next_sibling; + + pre_order_iterator toit=tmp; + // copy all children + do { + assert(current_from!=0); + if(current_from->first_child != 0) { + current_from=current_from->first_child; + toit=append_child(toit, current_from->data); + } + else { + while(current_from->next_sibling==0 && current_from!=start_from) { + current_from=current_from->parent; + toit=parent(toit); + assert(current_from!=0); + } + current_from=current_from->next_sibling; + if(current_from!=last) { + toit=append_child(parent(toit), current_from->data); + } + } + } while(current_from!=last); + + return current_to; + } + +template +typename tree::sibling_iterator tree::replace( + sibling_iterator orig_begin, + sibling_iterator orig_end, + sibling_iterator new_begin, + sibling_iterator new_end) + { + tree_node *orig_first=orig_begin.node; + tree_node *new_first=new_begin.node; + tree_node *orig_last=orig_first; + while((++orig_begin)!=orig_end) + orig_last=orig_last->next_sibling; + tree_node *new_last=new_first; + while((++new_begin)!=new_end) + new_last=new_last->next_sibling; + + // insert all siblings in new_first..new_last before orig_first + bool first=true; + pre_order_iterator ret; + while(1==1) { + pre_order_iterator tt=insert_subtree(pre_order_iterator(orig_first), pre_order_iterator(new_first)); + if(first) { + ret=tt; + first=false; + } + if(new_first==new_last) + break; + new_first=new_first->next_sibling; + } + + // erase old range of siblings + bool last=false; + tree_node *next=orig_first; + while(1==1) { + if(next==orig_last) + last=true; + next=next->next_sibling; + erase((pre_order_iterator)orig_first); + if(last) + break; + orig_first=next; + } + return ret; + } + +template +template +iter tree::flatten(iter position) + { + if(position.node->first_child==0) + return position; + + tree_node *tmp=position.node->first_child; + while(tmp) { + tmp->parent=position.node->parent; + tmp=tmp->next_sibling; + } + if(position.node->next_sibling) { + position.node->last_child->next_sibling=position.node->next_sibling; + position.node->next_sibling->prev_sibling=position.node->last_child; + } + else { + position.node->parent->last_child=position.node->last_child; + } + position.node->next_sibling=position.node->first_child; + position.node->next_sibling->prev_sibling=position.node; + position.node->first_child=0; + position.node->last_child=0; + + return position; + } + + +template +template +iter tree::reparent(iter position, sibling_iterator begin, sibling_iterator end) + { + tree_node *first=begin.node; + tree_node *last=first; + + assert(first!=position.node); + + if(begin==end) return begin; + // determine last node + while((++begin)!=end) { + last=last->next_sibling; + } + // move subtree + if(first->prev_sibling==0) { + first->parent->first_child=last->next_sibling; + } + else { + first->prev_sibling->next_sibling=last->next_sibling; + } + if(last->next_sibling==0) { + last->parent->last_child=first->prev_sibling; + } + else { + last->next_sibling->prev_sibling=first->prev_sibling; + } + if(position.node->first_child==0) { + position.node->first_child=first; + position.node->last_child=last; + first->prev_sibling=0; + } + else { + position.node->last_child->next_sibling=first; + first->prev_sibling=position.node->last_child; + position.node->last_child=last; + } + last->next_sibling=0; + + tree_node *pos=first; + while(1==1) { + pos->parent=position.node; + if(pos==last) break; + pos=pos->next_sibling; + } + + return first; + } + +template +template iter tree::reparent(iter position, iter from) + { + if(from.node->first_child==0) return position; + return reparent(position, from.node->first_child, end(from)); + } + +template +template iter tree::wrap(iter position, const T& x) + { + assert(position.node!=0); + sibling_iterator fr=position, to=position; + ++to; + iter ret = insert(position, x); + reparent(ret, fr, to); + return ret; + } + +template +template iter tree::move_after(iter target, iter source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return source; + if(dst->next_sibling) + if(dst->next_sibling==src) // already in the right spot + return source; + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst->next_sibling!=0) dst->next_sibling->prev_sibling=src; + else dst->parent->last_child=src; + src->next_sibling=dst->next_sibling; + dst->next_sibling=src; + src->prev_sibling=dst; + src->parent=dst->parent; + return src; + } + +template +template iter tree::move_before(iter target, iter source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return source; + if(dst->prev_sibling) + if(dst->prev_sibling==src) // already in the right spot + return source; + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst->prev_sibling!=0) dst->prev_sibling->next_sibling=src; + else dst->parent->first_child=src; + src->prev_sibling=dst->prev_sibling; + dst->prev_sibling=src; + src->next_sibling=dst; + src->parent=dst->parent; + return src; + } + +// specialisation for sibling_iterators +template +typename tree::sibling_iterator tree::move_before(sibling_iterator target, + sibling_iterator source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + tree_node *dst_prev_sibling; + if(dst==0) { // must then be an end iterator + dst_prev_sibling=target.parent_->last_child; + assert(dst_prev_sibling); + } + else dst_prev_sibling=dst->prev_sibling; + assert(src); + + if(dst==src) return source; + if(dst_prev_sibling) + if(dst_prev_sibling==src) // already in the right spot + return source; + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst_prev_sibling!=0) dst_prev_sibling->next_sibling=src; + else target.parent_->first_child=src; + src->prev_sibling=dst_prev_sibling; + if(dst) { + dst->prev_sibling=src; + src->parent=dst->parent; + } + src->next_sibling=dst; + return src; + } + +template +template iter tree::move_ontop(iter target, iter source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return source; + + // remember connection points + tree_node *b_prev_sibling=dst->prev_sibling; + tree_node *b_next_sibling=dst->next_sibling; + tree_node *b_parent=dst->parent; + + // remove target + erase(target); + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(b_prev_sibling!=0) b_prev_sibling->next_sibling=src; + else b_parent->first_child=src; + if(b_next_sibling!=0) b_next_sibling->prev_sibling=src; + else b_parent->last_child=src; + src->prev_sibling=b_prev_sibling; + src->next_sibling=b_next_sibling; + src->parent=b_parent; + return src; + } + +template +void tree::merge(sibling_iterator to1, sibling_iterator to2, + sibling_iterator from1, sibling_iterator from2, + bool duplicate_leaves) + { + sibling_iterator fnd; + while(from1!=from2) { + if((fnd=std::find(to1, to2, (*from1))) != to2) { // element found + if(from1.begin()==from1.end()) { // full depth reached + if(duplicate_leaves) + append_child(parent(to1), (*from1)); + } + else { // descend further + merge(fnd.begin(), fnd.end(), from1.begin(), from1.end(), duplicate_leaves); + } + } + else { // element missing + insert_subtree(to2, from1); + } + ++from1; + } + } + + +template +void tree::sort(sibling_iterator from, sibling_iterator to, bool deep) + { + std::less comp; + sort(from, to, comp, deep); + } + +template +template +void tree::sort(sibling_iterator from, sibling_iterator to, + StrictWeakOrdering comp, bool deep) + { + if(from==to) return; + // make list of sorted nodes + // CHECK: if multiset stores equivalent nodes in the order in which they + // are inserted, then this routine should be called 'stable_sort'. + std::multiset > nodes(comp); + sibling_iterator it=from, it2=to; + while(it != to) { + nodes.insert(it.node); + ++it; + } + // reassemble + --it2; + + // prev and next are the nodes before and after the sorted range + tree_node *prev=from.node->prev_sibling; + tree_node *next=it2.node->next_sibling; + typename std::multiset >::iterator nit=nodes.begin(), eit=nodes.end(); + if(prev==0) { + if((*nit)->parent!=0) // to catch "sorting the head" situations, when there is no parent + (*nit)->parent->first_child=(*nit); + } + else prev->next_sibling=(*nit); + + --eit; + while(nit!=eit) { + (*nit)->prev_sibling=prev; + if(prev) + prev->next_sibling=(*nit); + prev=(*nit); + ++nit; + } + // prev now points to the last-but-one node in the sorted range + if(prev) + prev->next_sibling=(*eit); + + // eit points to the last node in the sorted range. + (*eit)->next_sibling=next; + (*eit)->prev_sibling=prev; // missed in the loop above + if(next==0) { + if((*eit)->parent!=0) // to catch "sorting the head" situations, when there is no parent + (*eit)->parent->last_child=(*eit); + } + else next->prev_sibling=(*eit); + + if(deep) { // sort the children of each node too + sibling_iterator bcs(*nodes.begin()); + sibling_iterator ecs(*eit); + ++ecs; + while(bcs!=ecs) { + sort(begin(bcs), end(bcs), comp, deep); + ++bcs; + } + } + } + +template +template +bool tree::equal(const iter& one_, const iter& two, const iter& three_) const + { + std::equal_to comp; + return equal(one_, two, three_, comp); + } + +template +template +bool tree::equal_subtree(const iter& one_, const iter& two_) const + { + std::equal_to comp; + return equal_subtree(one_, two_, comp); + } + +template +template +bool tree::equal(const iter& one_, const iter& two, const iter& three_, BinaryPredicate fun) const + { + pre_order_iterator one(one_), three(three_); + +// if(one==two && is_valid(three) && three.number_of_children()!=0) +// return false; + while(one!=two && is_valid(three)) { + if(!fun(*one,*three)) + return false; + if(one.number_of_children()!=three.number_of_children()) + return false; + ++one; + ++three; + } + return true; + } + +template +template +bool tree::equal_subtree(const iter& one_, const iter& two_, BinaryPredicate fun) const + { + pre_order_iterator one(one_), two(two_); + + if(!fun(*one,*two)) return false; + if(number_of_children(one)!=number_of_children(two)) return false; + return equal(begin(one),end(one),begin(two),fun); + } + +template +tree tree::subtree(sibling_iterator from, sibling_iterator to) const + { + tree tmp; + tmp.set_head(value_type()); + tmp.replace(tmp.begin(), tmp.end(), from, to); + return tmp; + } + +template +void tree::subtree(tree& tmp, sibling_iterator from, sibling_iterator to) const + { + tmp.set_head(value_type()); + tmp.replace(tmp.begin(), tmp.end(), from, to); + } + +template +size_t tree::size() const + { + size_t i=0; + pre_order_iterator it=begin(), eit=end(); + while(it!=eit) { + ++i; + ++it; + } + return i; + } + +template +size_t tree::size(const iterator_base& top) const + { + size_t i=0; + pre_order_iterator it=top, eit=top; + eit.skip_children(); + ++eit; + while(it!=eit) { + ++i; + ++it; + } + return i; + } + +template +bool tree::empty() const + { + pre_order_iterator it=begin(), eit=end(); + return (it==eit); + } + +template +int tree::depth(const iterator_base& it) + { + tree_node* pos=it.node; + assert(pos!=0); + int ret=0; + while(pos->parent!=0) { + pos=pos->parent; + ++ret; + } + return ret; + } + +template +int tree::depth(const iterator_base& it, const iterator_base& root) + { + tree_node* pos=it.node; + assert(pos!=0); + int ret=0; + while(pos->parent!=0 && pos!=root.node) { + pos=pos->parent; + ++ret; + } + return ret; + } + +template +int tree::max_depth() const + { + int maxd=-1; + for(tree_node *it = head->next_sibling; it!=feet; it=it->next_sibling) + maxd=std::max(maxd, max_depth(it)); + + return maxd; + } + + +template +int tree::max_depth(const iterator_base& pos) const + { + tree_node *tmp=pos.node; + + if(tmp==0 || tmp==head || tmp==feet) return -1; + + int curdepth=0, maxdepth=0; + while(true) { // try to walk the bottom of the tree + while(tmp->first_child==0) { + if(tmp==pos.node) return maxdepth; + if(tmp->next_sibling==0) { + // try to walk up and then right again + do { + tmp=tmp->parent; + if(tmp==0) return maxdepth; + --curdepth; + } while(tmp->next_sibling==0); + } + if(tmp==pos.node) return maxdepth; + tmp=tmp->next_sibling; + } + tmp=tmp->first_child; + ++curdepth; + maxdepth=std::max(curdepth, maxdepth); + } + } + +template +unsigned int tree::number_of_children(const iterator_base& it) + { + tree_node *pos=it.node->first_child; + if(pos==0) return 0; + + unsigned int ret=1; +// while(pos!=it.node->last_child) { +// ++ret; +// pos=pos->next_sibling; +// } + while((pos=pos->next_sibling)) + ++ret; + return ret; + } + +template +unsigned int tree::number_of_siblings(const iterator_base& it) const + { + tree_node *pos=it.node; + unsigned int ret=0; + // count forward + while(pos->next_sibling && + pos->next_sibling!=head && + pos->next_sibling!=feet) { + ++ret; + pos=pos->next_sibling; + } + // count backward + pos=it.node; + while(pos->prev_sibling && + pos->prev_sibling!=head && + pos->prev_sibling!=feet) { + ++ret; + pos=pos->prev_sibling; + } + + return ret; + } + +template +void tree::swap(sibling_iterator it) + { + tree_node *nxt=it.node->next_sibling; + if(nxt) { + if(it.node->prev_sibling) + it.node->prev_sibling->next_sibling=nxt; + else + it.node->parent->first_child=nxt; + nxt->prev_sibling=it.node->prev_sibling; + tree_node *nxtnxt=nxt->next_sibling; + if(nxtnxt) + nxtnxt->prev_sibling=it.node; + else + it.node->parent->last_child=it.node; + nxt->next_sibling=it.node; + it.node->prev_sibling=nxt; + it.node->next_sibling=nxtnxt; + } + } + +template +void tree::swap(iterator one, iterator two) + { + // if one and two are adjacent siblings, use the sibling swap + if(one.node->next_sibling==two.node) swap(one); + else if(two.node->next_sibling==one.node) swap(two); + else { + tree_node *nxt1=one.node->next_sibling; + tree_node *nxt2=two.node->next_sibling; + tree_node *pre1=one.node->prev_sibling; + tree_node *pre2=two.node->prev_sibling; + tree_node *par1=one.node->parent; + tree_node *par2=two.node->parent; + + // reconnect + one.node->parent=par2; + one.node->next_sibling=nxt2; + if(nxt2) nxt2->prev_sibling=one.node; + else par2->last_child=one.node; + one.node->prev_sibling=pre2; + if(pre2) pre2->next_sibling=one.node; + else par2->first_child=one.node; + + two.node->parent=par1; + two.node->next_sibling=nxt1; + if(nxt1) nxt1->prev_sibling=two.node; + else par1->last_child=two.node; + two.node->prev_sibling=pre1; + if(pre1) pre1->next_sibling=two.node; + else par1->first_child=two.node; + } + } + +// template +// tree::iterator tree::find_subtree( +// sibling_iterator subfrom, sibling_iterator subto, iterator from, iterator to, +// BinaryPredicate fun) const +// { +// assert(1==0); // this routine is not finished yet. +// while(from!=to) { +// if(fun(*subfrom, *from)) { +// +// } +// } +// return to; +// } + +template +bool tree::is_in_subtree(const iterator_base& it, const iterator_base& begin, + const iterator_base& end) const + { + // FIXME: this should be optimised. + pre_order_iterator tmp=begin; + while(tmp!=end) { + if(tmp==it) return true; + ++tmp; + } + return false; + } + +template +bool tree::is_valid(const iterator_base& it) const + { + if(it.node==0 || it.node==feet || it.node==head) return false; + else return true; + } + +template +unsigned int tree::index(sibling_iterator it) const + { + unsigned int ind=0; + if(it.node->parent==0) { + while(it.node->prev_sibling!=head) { + it.node=it.node->prev_sibling; + ++ind; + } + } + else { + while(it.node->prev_sibling!=0) { + it.node=it.node->prev_sibling; + ++ind; + } + } + return ind; + } + + +template +typename tree::sibling_iterator tree::child(const iterator_base& it, unsigned int num) + { + tree_node *tmp=it.node->first_child; + while(num--) { + assert(tmp!=0); + tmp=tmp->next_sibling; + } + return tmp; + } + + + + +// Iterator base + +template +tree::iterator_base::iterator_base() + : node(0), skip_current_children_(false) + { + } + +template +tree::iterator_base::iterator_base(tree_node *tn) + : node(tn), skip_current_children_(false) + { + } + +template +T& tree::iterator_base::operator*() const + { + return node->data; + } + +template +T* tree::iterator_base::operator->() const + { + return &(node->data); + } + +template +bool tree::post_order_iterator::operator!=(const post_order_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::post_order_iterator::operator==(const post_order_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +bool tree::pre_order_iterator::operator!=(const pre_order_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::pre_order_iterator::operator==(const pre_order_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +bool tree::sibling_iterator::operator!=(const sibling_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::sibling_iterator::operator==(const sibling_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +bool tree::leaf_iterator::operator!=(const leaf_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::leaf_iterator::operator==(const leaf_iterator& other) const + { + if(other.node==this->node && other.top_node==this->top_node) return true; + else return false; + } + +template +typename tree::sibling_iterator tree::iterator_base::begin() const + { + if(node->first_child==0) + return end(); + + sibling_iterator ret(node->first_child); + ret.parent_=this->node; + return ret; + } + +template +typename tree::sibling_iterator tree::iterator_base::end() const + { + sibling_iterator ret(0); + ret.parent_=node; + return ret; + } + +template +void tree::iterator_base::skip_children() + { + skip_current_children_=true; + } + +template +unsigned int tree::iterator_base::number_of_children() const + { + tree_node *pos=node->first_child; + if(pos==0) return 0; + + unsigned int ret=1; + while(pos!=node->last_child) { + ++ret; + pos=pos->next_sibling; + } + return ret; + } + + + +// Pre-order iterator + +template +tree::pre_order_iterator::pre_order_iterator() + : iterator_base(0) + { + } + +template +tree::pre_order_iterator::pre_order_iterator(tree_node *tn) + : iterator_base(tn) + { + } + +template +tree::pre_order_iterator::pre_order_iterator(const iterator_base &other) + : iterator_base(other.node) + { + } + +template +tree::pre_order_iterator::pre_order_iterator(const sibling_iterator& other) + : iterator_base(other.node) + { + if(this->node==0) { + if(other.range_last()!=0) + this->node=other.range_last(); + else + this->node=other.parent_; + this->skip_children(); + ++(*this); + } + } + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator++() + { + assert(this->node!=0); + if(!this->skip_current_children_ && this->node->first_child != 0) { + this->node=this->node->first_child; + } + else { + this->skip_current_children_=false; + while(this->node->next_sibling==0) { + this->node=this->node->parent; + if(this->node==0) + return *this; + } + this->node=this->node->next_sibling; + } + return *this; + } + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator--() + { + assert(this->node!=0); + if(this->node->prev_sibling) { + this->node=this->node->prev_sibling; + while(this->node->last_child) + this->node=this->node->last_child; + } + else { + this->node=this->node->parent; + if(this->node==0) + return *this; + } + return *this; +} + +template +typename tree::pre_order_iterator tree::pre_order_iterator::operator++(int n) + { + pre_order_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::pre_order_iterator tree::pre_order_iterator::operator--(int n) +{ + pre_order_iterator copy = *this; + --(*this); + return copy; +} + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + + + +// Post-order iterator + +template +tree::post_order_iterator::post_order_iterator() + : iterator_base(0) + { + } + +template +tree::post_order_iterator::post_order_iterator(tree_node *tn) + : iterator_base(tn) + { + } + +template +tree::post_order_iterator::post_order_iterator(const iterator_base &other) + : iterator_base(other.node) + { + } + +template +tree::post_order_iterator::post_order_iterator(const sibling_iterator& other) + : iterator_base(other.node) + { + if(this->node==0) { + if(other.range_last()!=0) + this->node=other.range_last(); + else + this->node=other.parent_; + this->skip_children(); + ++(*this); + } + } + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator++() + { + assert(this->node!=0); + if(this->node->next_sibling==0) { + this->node=this->node->parent; + this->skip_current_children_=false; + } + else { + this->node=this->node->next_sibling; + if(this->skip_current_children_) { + this->skip_current_children_=false; + } + else { + while(this->node->first_child) + this->node=this->node->first_child; + } + } + return *this; + } + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator--() + { + assert(this->node!=0); + if(this->skip_current_children_ || this->node->last_child==0) { + this->skip_current_children_=false; + while(this->node->prev_sibling==0) + this->node=this->node->parent; + this->node=this->node->prev_sibling; + } + else { + this->node=this->node->last_child; + } + return *this; + } + +template +typename tree::post_order_iterator tree::post_order_iterator::operator++(int) + { + post_order_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::post_order_iterator tree::post_order_iterator::operator--(int) + { + post_order_iterator copy = *this; + --(*this); + return copy; + } + + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + +template +void tree::post_order_iterator::descend_all() + { + assert(this->node!=0); + while(this->node->first_child) + this->node=this->node->first_child; + } + + +// Breadth-first iterator + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator() + : iterator_base() + { + } + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator(tree_node *tn) + : iterator_base(tn) + { + traversal_queue.push(tn); + } + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator(const iterator_base& other) + : iterator_base(other.node) + { + traversal_queue.push(other.node); + } + +template +bool tree::breadth_first_queued_iterator::operator!=(const breadth_first_queued_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::breadth_first_queued_iterator::operator==(const breadth_first_queued_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +typename tree::breadth_first_queued_iterator& tree::breadth_first_queued_iterator::operator++() + { + assert(this->node!=0); + + // Add child nodes and pop current node + sibling_iterator sib=this->begin(); + while(sib!=this->end()) { + traversal_queue.push(sib.node); + ++sib; + } + traversal_queue.pop(); + if(traversal_queue.size()>0) + this->node=traversal_queue.front(); + else + this->node=0; + return (*this); + } + +template +typename tree::breadth_first_queued_iterator tree::breadth_first_queued_iterator::operator++(int n) + { + breadth_first_queued_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::breadth_first_queued_iterator& tree::breadth_first_queued_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + + + +// Fixed depth iterator + +template +tree::fixed_depth_iterator::fixed_depth_iterator() + : iterator_base() + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(tree_node *tn) + : iterator_base(tn), top_node(0) + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(const iterator_base& other) + : iterator_base(other.node), top_node(0) + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(const sibling_iterator& other) + : iterator_base(other.node), top_node(0) + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(const fixed_depth_iterator& other) + : iterator_base(other.node), top_node(other.top_node) + { + } + +template +bool tree::fixed_depth_iterator::operator==(const fixed_depth_iterator& other) const + { + if(other.node==this->node && other.top_node==top_node) return true; + else return false; + } + +template +bool tree::fixed_depth_iterator::operator!=(const fixed_depth_iterator& other) const + { + if(other.node!=this->node || other.top_node!=top_node) return true; + else return false; + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator++() + { + assert(this->node!=0); + + if(this->node->next_sibling) { + this->node=this->node->next_sibling; + } + else { + int relative_depth=0; + upper: + do { + if(this->node==this->top_node) { + this->node=0; // FIXME: return a proper fixed_depth end iterator once implemented + return *this; + } + this->node=this->node->parent; + if(this->node==0) return *this; + --relative_depth; + } while(this->node->next_sibling==0); + lower: + this->node=this->node->next_sibling; + while(this->node->first_child==0) { + if(this->node->next_sibling==0) + goto upper; + this->node=this->node->next_sibling; + if(this->node==0) return *this; + } + while(relative_depth<0 && this->node->first_child!=0) { + this->node=this->node->first_child; + ++relative_depth; + } + if(relative_depth<0) { + if(this->node->next_sibling==0) goto upper; + else goto lower; + } + } + return *this; + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator--() + { + assert(this->node!=0); + + if(this->node->prev_sibling) { + this->node=this->node->prev_sibling; + } + else { + int relative_depth=0; + upper: + do { + if(this->node==this->top_node) { + this->node=0; + return *this; + } + this->node=this->node->parent; + if(this->node==0) return *this; + --relative_depth; + } while(this->node->prev_sibling==0); + lower: + this->node=this->node->prev_sibling; + while(this->node->last_child==0) { + if(this->node->prev_sibling==0) + goto upper; + this->node=this->node->prev_sibling; + if(this->node==0) return *this; + } + while(relative_depth<0 && this->node->last_child!=0) { + this->node=this->node->last_child; + ++relative_depth; + } + if(relative_depth<0) { + if(this->node->prev_sibling==0) goto upper; + else goto lower; + } + } + return *this; + +// +// +// assert(this->node!=0); +// if(this->node->prev_sibling!=0) { +// this->node=this->node->prev_sibling; +// assert(this->node!=0); +// if(this->node->parent==0 && this->node->prev_sibling==0) // head element +// this->node=0; +// } +// else { +// tree_node *par=this->node->parent; +// do { +// par=par->prev_sibling; +// if(par==0) { // FIXME: need to keep track of this! +// this->node=0; +// return *this; +// } +// } while(par->last_child==0); +// this->node=par->last_child; +// } +// return *this; + } + +template +typename tree::fixed_depth_iterator tree::fixed_depth_iterator::operator++(int) + { + fixed_depth_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::fixed_depth_iterator tree::fixed_depth_iterator::operator--(int) + { + fixed_depth_iterator copy = *this; + --(*this); + return copy; + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --(num); + } + return (*this); + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --(num); + } + return *this; + } + + +// Sibling iterator + +template +tree::sibling_iterator::sibling_iterator() + : iterator_base() + { + set_parent_(); + } + +template +tree::sibling_iterator::sibling_iterator(tree_node *tn) + : iterator_base(tn) + { + set_parent_(); + } + +template +tree::sibling_iterator::sibling_iterator(const iterator_base& other) + : iterator_base(other.node) + { + set_parent_(); + } + +template +tree::sibling_iterator::sibling_iterator(const sibling_iterator& other) + : iterator_base(other), parent_(other.parent_) + { + } + +template +void tree::sibling_iterator::set_parent_() + { + parent_=0; + if(this->node==0) return; + if(this->node->parent!=0) + parent_=this->node->parent; + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator++() + { + if(this->node) + this->node=this->node->next_sibling; + return *this; + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator--() + { + if(this->node) this->node=this->node->prev_sibling; + else { + assert(parent_); + this->node=parent_->last_child; + } + return *this; +} + +template +typename tree::sibling_iterator tree::sibling_iterator::operator++(int) + { + sibling_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::sibling_iterator tree::sibling_iterator::operator--(int) + { + sibling_iterator copy = *this; + --(*this); + return copy; + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + +template +typename tree::tree_node *tree::sibling_iterator::range_first() const + { + tree_node *tmp=parent_->first_child; + return tmp; + } + +template +typename tree::tree_node *tree::sibling_iterator::range_last() const + { + return parent_->last_child; + } + +// Leaf iterator + +template +tree::leaf_iterator::leaf_iterator() + : iterator_base(0), top_node(0) + { + } + +template +tree::leaf_iterator::leaf_iterator(tree_node *tn, tree_node *top) + : iterator_base(tn), top_node(top) + { + } + +template +tree::leaf_iterator::leaf_iterator(const iterator_base &other) + : iterator_base(other.node), top_node(0) + { + } + +template +tree::leaf_iterator::leaf_iterator(const sibling_iterator& other) + : iterator_base(other.node), top_node(0) + { + if(this->node==0) { + if(other.range_last()!=0) + this->node=other.range_last(); + else + this->node=other.parent_; + ++(*this); + } + } + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator++() + { + assert(this->node!=0); + if(this->node->first_child!=0) { // current node is no longer leaf (children got added) + while(this->node->first_child) + this->node=this->node->first_child; + } + else { + while(this->node->next_sibling==0) { + if (this->node->parent==0) return *this; + this->node=this->node->parent; + if (top_node != 0 && this->node==top_node) return *this; + } + this->node=this->node->next_sibling; + while(this->node->first_child) + this->node=this->node->first_child; + } + return *this; + } + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator--() + { + assert(this->node!=0); + while (this->node->prev_sibling==0) { + if (this->node->parent==0) return *this; + this->node=this->node->parent; + if (top_node !=0 && this->node==top_node) return *this; + } + this->node=this->node->prev_sibling; + while(this->node->last_child) + this->node=this->node->last_child; + return *this; + } + +template +typename tree::leaf_iterator tree::leaf_iterator::operator++(int) + { + leaf_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::leaf_iterator tree::leaf_iterator::operator--(int) + { + leaf_iterator copy = *this; + --(*this); + return copy; + } + + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + +#endif + +// Local variables: +// default-tab-width: 3 +// End: From 54ddf81afac80866fcf27acf651cd0c4df2cb75a Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 30 Dec 2008 23:06:22 +0000 Subject: [PATCH 10/68] Moved tree into the lumiera namespace --- src/lib/tree.hpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/lib/tree.hpp b/src/lib/tree.hpp index 6ce5327c3..8d0a85496 100644 --- a/src/lib/tree.hpp +++ b/src/lib/tree.hpp @@ -606,7 +606,7 @@ void tree::erase_children(const iterator_base& it) prev=cur; cur=cur->next_sibling; erase_children(pre_order_iterator(prev)); - kp::destructor(&prev->data); + lumiera::destructor(&prev->data); alloc_.deallocate(prev,1); } it.node->first_child=0; @@ -637,7 +637,7 @@ iter tree::erase(iter it) cur->next_sibling->prev_sibling=cur->prev_sibling; } - kp::destructor(&cur->data); + lumiera::destructor(&cur->data); alloc_.deallocate(cur,1); return ret; } @@ -863,7 +863,7 @@ iter tree::append_child(iter position) assert(position.node); tree_node *tmp=alloc_.allocate(1,0); - kp::constructor(&tmp->data); + lumiera::constructor(&tmp->data); tmp->first_child=0; tmp->last_child=0; @@ -888,7 +888,7 @@ iter tree::prepend_child(iter position) assert(position.node); tree_node *tmp=alloc_.allocate(1,0); - kp::constructor(&tmp->data); + lumiera::constructor(&tmp->data); tmp->first_child=0; tmp->last_child=0; @@ -917,7 +917,7 @@ iter tree::append_child(iter position, const T& x) assert(position.node); tree_node* tmp = alloc_.allocate(1,0); - kp::constructor(&tmp->data, x); + lumiera::constructor(&tmp->data, x); tmp->first_child=0; tmp->last_child=0; @@ -942,7 +942,7 @@ iter tree::prepend_child(iter position, const T& x) assert(position.node); tree_node* tmp = alloc_.allocate(1,0); - kp::constructor(&tmp->data, x); + lumiera::constructor(&tmp->data, x); tmp->first_child=0; tmp->last_child=0; @@ -1029,7 +1029,7 @@ iter tree::insert(iter position, const T& x) // insert before the feet. } tree_node* tmp = alloc_.allocate(1,0); - kp::constructor(&tmp->data, x); + lumiera::constructor(&tmp->data, x); tmp->first_child=0; tmp->last_child=0; @@ -1051,7 +1051,7 @@ template typename tree::sibling_iterator tree::insert(sibling_iterator position, const T& x) { tree_node* tmp = alloc_.allocate(1,0); - kp::constructor(&tmp->data, x); + lumiera::constructor(&tmp->data, x); tmp->first_child=0; tmp->last_child=0; @@ -1081,7 +1081,7 @@ template iter tree::insert_after(iter position, const T& x) { tree_node* tmp = alloc_.allocate(1,0); - kp::constructor(&tmp->data, x); + lumiera::constructor(&tmp->data, x); tmp->first_child=0; tmp->last_child=0; @@ -1134,8 +1134,8 @@ template template iter tree::replace(iter position, const T& x) { - kp::destructor(&position.node->data); - kp::constructor(&position.node->data, x); + lumiera::destructor(&position.node->data); + lumiera::constructor(&position.node->data, x); return position; } @@ -1153,7 +1153,7 @@ iter tree::replace(iter position, const iterator_base& f erase_children(position); // std::cout << "no warning!" << std::endl; tree_node* tmp = alloc_.allocate(1,0); - kp::constructor(&tmp->data, (*from)); + lumiera::constructor(&tmp->data, (*from)); tmp->first_child=0; tmp->last_child=0; if(current_to->prev_sibling==0) { @@ -1173,7 +1173,7 @@ iter tree::replace(iter position, const iterator_base& f } tmp->next_sibling=current_to->next_sibling; tmp->parent=current_to->parent; - kp::destructor(¤t_to->data); + lumiera::destructor(¤t_to->data); alloc_.deallocate(current_to,1); current_to=tmp; From e670f42a391c33250f9623c70b702673017fdaac Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 30 Dec 2008 23:07:16 +0000 Subject: [PATCH 11/68] Opps - tree.hpp committed now --- src/lib/tree.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/tree.hpp b/src/lib/tree.hpp index 8d0a85496..aad422a14 100644 --- a/src/lib/tree.hpp +++ b/src/lib/tree.hpp @@ -90,8 +90,6 @@ void destructor(T1* p) p->~T1(); } -}; - /// A node in the tree, combining links to other nodes as well as the actual data. template class tree_node_ { // size: 5*4=20 bytes (on 32 bit arch), can be reduced by 8. @@ -2707,6 +2705,8 @@ typename tree::leaf_iterator& tree Date: Tue, 30 Dec 2008 23:07:59 +0000 Subject: [PATCH 12/68] Added a track tree object to the layout helper --- src/gui/widgets/timeline/timeline-layout-helper.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 3bb48e800..d4d0e3f88 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -28,10 +28,13 @@ #define TIMELINE_LAYOUT_HELPER_HPP #include "../../gtk-lumiera.hpp" +#include "../../../lib/tree.hpp" namespace gui { namespace widgets { namespace timeline { + +class Track; /** * A helper class for the TimelineWidget. TimelineLayoutHelper @@ -40,7 +43,9 @@ namespace timeline { */ class TimelineLayoutHelper { - +protected: + + lumiera::tree currentTrackTree; }; } // namespace timeline From 8d092d3b853d4ff536a8128b38717c04c43ec605 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Wed, 31 Dec 2008 17:05:32 +0000 Subject: [PATCH 13/68] Added TimelineLayoutHelper::clone_tree_from_sequence --- src/gui/widgets/timeline-widget.cpp | 1 + src/gui/widgets/timeline-widget.hpp | 1 + .../timeline/timeline-layout-helper.cpp | 37 +++++++++++++++++++ .../timeline/timeline-layout-helper.hpp | 24 +++++++++++- 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 4adcfd4d6..155b021df 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -43,6 +43,7 @@ TimelineWidget::TimelineWidget( shared_ptr source_sequence) : Table(2, 2), sequence(source_sequence), + layoutHelper(*this), viewWindow(this, 0, 1), selectionStart(0), selectionEnd(0), diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index c169efb21..9f368e147 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -327,6 +327,7 @@ protected: friend class timeline::TimelineViewWindow; friend class timeline::TimelineBody; friend class timeline::TimelineHeaderContainer; + friend class timeline::TimelineLayoutHelper; friend class timeline::TimelineRuler; friend class timeline::Tool; friend class timeline::ArrowTool; diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 28dfcf25b..41c9fc12e 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -24,14 +24,51 @@ #include #include "timeline-layout-helper.hpp" +#include "../timeline-widget.hpp" +#include "../../model/sequence.hpp" using namespace Gtk; using namespace std; using namespace boost; +using namespace lumiera; namespace gui { namespace widgets { namespace timeline { + +TimelineLayoutHelper::TimelineLayoutHelper(TimelineWidget &owner) + : timelineWidget(owner) +{ +} + +void +TimelineLayoutHelper::clone_tree_from_sequence() +{ + const shared_ptr &sequence = timelineWidget.sequence; + REQUIRE(sequence); + + layoutTree.clear(); + tree< shared_ptr >::iterator_base iterator = + layoutTree.set_head(sequence); + + add_branch(iterator, sequence); +} + +void +TimelineLayoutHelper::add_branch( + lumiera::tree< shared_ptr >::iterator_base + parent_iterator, + shared_ptr parent) +{ + BOOST_FOREACH(shared_ptr child, + parent->get_child_tracks()) + { + lumiera::tree< shared_ptr >::iterator_base + child_iterator = + layoutTree.append_child(parent_iterator, child); + add_branch(child_iterator, child); + } +} } // namespace timeline } // namespace widgets diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index d4d0e3f88..b5c077ce3 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -31,7 +31,15 @@ #include "../../../lib/tree.hpp" namespace gui { + +namespace model { +class Track; +} + namespace widgets { + +class TimelineWidget; + namespace timeline { class Track; @@ -41,11 +49,23 @@ class Track; * is a class which calculates the layout of tracks in the timeline * track tree. */ -class TimelineLayoutHelper +class TimelineLayoutHelper : public boost::noncopyable { +public: + TimelineLayoutHelper(TimelineWidget &owner); protected: - lumiera::tree currentTrackTree; + void clone_tree_from_sequence(); + + void add_branch( + lumiera::tree< boost::shared_ptr >::iterator_base + parent_iterator, + boost::shared_ptr parent); + +protected: + TimelineWidget &timelineWidget; + + lumiera::tree< boost::shared_ptr > layoutTree; }; } // namespace timeline From 8d44b90a8b8281a8175f3d11b21c3d8eefbfc27f Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Wed, 31 Dec 2008 17:29:57 +0000 Subject: [PATCH 14/68] Removed a spurious lumiera:: --- src/gui/widgets/timeline/timeline-layout-helper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 41c9fc12e..148132c16 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -63,7 +63,7 @@ TimelineLayoutHelper::add_branch( BOOST_FOREACH(shared_ptr child, parent->get_child_tracks()) { - lumiera::tree< shared_ptr >::iterator_base + tree< shared_ptr >::iterator_base child_iterator = layoutTree.append_child(parent_iterator, child); add_branch(child_iterator, child); From 0f3b290b6ddf271f46799ccb291869624f3b69c3 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Thu, 1 Jan 2009 12:34:39 +0000 Subject: [PATCH 15/68] Tweaked tree.hpp to improve documentation to work better in lumiera doxygen --- src/lib/tree.hpp | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/lib/tree.hpp b/src/lib/tree.hpp index aad422a14..02e823f72 100644 --- a/src/lib/tree.hpp +++ b/src/lib/tree.hpp @@ -1,30 +1,15 @@ /* - $Id: tree.hh,v 1.151 2008/05/07 15:46:14 peekas Exp $ + $Id: tree.hpp,v 1.151 2008/05/07 15:46:14 peekas Exp $ STL-like templated tree class. Copyright (C) 2001-2006 Kasper Peeters . + Copyright (C) 2009 Joel Holdsworth . */ -/** \mainpage tree.hh - \author Kasper Peeters - \version 2.62 - \date 28-Aug-2008 - \see http://www.aei.mpg.de/~peekas/tree/ - \see http://www.aei.mpg.de/~peekas/tree/ChangeLog - - The tree.hh library for C++ provides an STL-like container class - for n-ary trees, templated over the data stored at the - nodes. Various types of iterators are provided (post-order, - pre-order, and others). Where possible the access methods are - compatible with the STL or alternative algorithms are - available. -*/ - - /* - The tree.hh code is free software; you can redistribute it and/or modify + The tree.hpp code 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; version 2 or 3. @@ -100,6 +85,15 @@ class tree_node_ { // size: 5*4=20 bytes (on 32 bit arch), can be reduced by 8. T data; }; // __attribute__((packed)); +/** + * A STL-like tree implementation class + * @remarks The tree class provides an STL-like container + * class for n-ary trees, templated over the data stored at the + * nodes. Various types of iterators are provided (post-order, + * pre-order, and others). Where possible the access methods are + * compatible with the STL or alternative algorithms are + * available. + **/ template > > class tree { protected: From ac28251915c7aa01cead836caf0ad824cee09a76 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Thu, 1 Jan 2009 13:31:34 +0000 Subject: [PATCH 16/68] Added layout code from TimelineHeaderContainer --- .../timeline/timeline-layout-helper.cpp | 81 +++++++++++++++++-- .../timeline/timeline-layout-helper.hpp | 55 ++++++++++++- 2 files changed, 127 insertions(+), 9 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 148132c16..11d97d7ce 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -48,7 +48,7 @@ TimelineLayoutHelper::clone_tree_from_sequence() REQUIRE(sequence); layoutTree.clear(); - tree< shared_ptr >::iterator_base iterator = + TrackTree::iterator_base iterator = layoutTree.set_head(sequence); add_branch(iterator, sequence); @@ -56,20 +56,91 @@ TimelineLayoutHelper::clone_tree_from_sequence() void TimelineLayoutHelper::add_branch( - lumiera::tree< shared_ptr >::iterator_base - parent_iterator, + TrackTree::iterator_base parent_iterator, shared_ptr parent) { BOOST_FOREACH(shared_ptr child, parent->get_child_tracks()) { - tree< shared_ptr >::iterator_base - child_iterator = + TrackTree::iterator_base child_iterator = layoutTree.append_child(parent_iterator, child); add_branch(child_iterator, child); } } +void +TimelineLayoutHelper::update_layout() +{ + // Make sure the style are loaded + //read_styles(); + + // Clear previously cached layout + headerBoxes.clear(); + + // Start at minus-the-scroll offset + int offset = 0;//-timelineWidget->get_y_scroll_offset(); + + //const Allocation container_allocation = get_allocation(); + const int header_width = 100;//container_allocation.get_width(); + const int indent_width = 10; + + layout_headers_recursive(layoutTree.begin(), + offset, header_width, indent_width, 0, true); +} + +void +TimelineLayoutHelper::layout_headers_recursive( + TrackTree::iterator_base parent_iterator, + int &offset, const int header_width, const int indent_width, + const int depth, bool parent_expanded) +{ + REQUIRE(depth >= 0); + + TrackTree::sibling_iterator iterator; + for(iterator = layoutTree.begin(parent_iterator); + iterator != layoutTree.end(parent_iterator); + iterator++) + { + const shared_ptr &model_track = *iterator; + REQUIRE(model_track); + + shared_ptr timeline_track = + lookup_timeline_track(model_track); + + if(parent_expanded) + { + // Calculate and store the box of the header + const int track_height = timeline_track->get_height(); + const int indent = depth * indent_width; + + headerBoxes[timeline_track] = Gdk::Rectangle( + indent, // x + offset, // y + max( header_width - indent, 0 ), // width + track_height); // height + + // Offset for the next header + offset += track_height + TimelineWidget::TrackPadding; + } + + layout_headers_recursive(iterator, offset, header_width, + indent_width, depth + 1, + timeline_track->get_expanded() && parent_expanded); + } +} + +shared_ptr +TimelineLayoutHelper::lookup_timeline_track( + shared_ptr model_track) +{ + REQUIRE(model_track != NULL); + shared_ptr timeline_track = + timelineWidget.lookup_timeline_track(model_track); + ENSURE(timeline_track); + + return timeline_track; +} + } // namespace timeline } // namespace widgets } // namespace gui diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index b5c077ce3..d9446d707 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -51,21 +51,68 @@ class Track; */ class TimelineLayoutHelper : public boost::noncopyable { +public: + typedef lumiera::tree< boost::shared_ptr > TrackTree; + public: TimelineLayoutHelper(TimelineWidget &owner); protected: void clone_tree_from_sequence(); - void add_branch( - lumiera::tree< boost::shared_ptr >::iterator_base - parent_iterator, + void add_branch(TrackTree::iterator_base parent_iterator, boost::shared_ptr parent); + /** + * Recaculates the track layout from layoutTree. + **/ + void update_layout(); + + /** + * Recursively lays out all the controls in the header widget. + + * /!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * + * + * * @param track The parent track object which will be recursed into. + * @param offset A shared value used to accumulate the y-offset of + * header widgets. + * @param header_width The width of this widget in pixels. + * !!!!!!!!!!! indent_width + * @param depth The depth within the tree of track. + **/ + void layout_headers_recursive( + TrackTree::iterator_base parent_iterator, + int &offset, const int header_width, const int indent_width, + const int depth, bool parent_expanded); + + /** + * A helper function which calls lookup_timeline_track within the + * parent timeline widget, but also applies lots of data consistency + * checks in the process. + * @param model_track The model track to look up in the parent widget. + * @return Returns the track found, or returns NULL if no matching + * track was found. + * @remarks If the return value is going to be NULL, an ENSURE will + * fail. + **/ + boost::shared_ptr lookup_timeline_track( + boost::shared_ptr model_track); + protected: + TimelineWidget &timelineWidget; - lumiera::tree< boost::shared_ptr > layoutTree; + TrackTree layoutTree; + + /** + * A map of tracks to the rectangles of their headers. + * @remarks This map is used as a cache, so that the rectangles don't + * need to be perpetually recalculated. This cache is regenerated by + * the layout_headers method. + **/ + std::map, Gdk::Rectangle> + headerBoxes; }; } // namespace timeline From afb5b7298faae74ba157b2bdc706e7b998bc00b0 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Thu, 1 Jan 2009 18:43:46 +0000 Subject: [PATCH 17/68] WIP: Applying new layout system --- src/gui/gtk-lumiera.hpp | 1 + src/gui/widgets/timeline-widget.cpp | 76 ++----- src/gui/widgets/timeline-widget.hpp | 16 -- .../timeline/timeline-header-container.cpp | 205 ++++++++---------- .../timeline/timeline-header-container.hpp | 30 +-- .../timeline/timeline-layout-helper.cpp | 61 +++++- .../timeline/timeline-layout-helper.hpp | 27 ++- src/gui/widgets/timeline/timeline-track.cpp | 6 + src/gui/widgets/timeline/timeline-track.hpp | 2 + 9 files changed, 190 insertions(+), 234 deletions(-) diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp index 765a628b7..e0bb55310 100644 --- a/src/gui/gtk-lumiera.hpp +++ b/src/gui/gtk-lumiera.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include "lib/util.hpp" diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 155b021df..64421bf16 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -50,12 +50,12 @@ TimelineWidget::TimelineWidget( playbackPeriodStart(0), playbackPeriodEnd(0), playbackPoint(GAVL_TIME_UNDEFINED), - totalHeight(0), horizontalAdjustment(0, 0, 0), verticalAdjustment(0, 0, 0), horizontalScroll(horizontalAdjustment), verticalScroll(verticalAdjustment) { + g_message("TimelineWidget::TimelineWidget"); REQUIRE(sequence); body = new TimelineBody(this); @@ -64,6 +64,8 @@ TimelineWidget::TimelineWidget( ENSURE(headerContainer != NULL); ruler = new TimelineRuler(this); ENSURE(ruler != NULL); + + g_message("Widgets Constructed"); horizontalAdjustment.signal_value_changed().connect( sigc::mem_fun( this, &TimelineWidget::on_scroll) ); @@ -77,6 +79,7 @@ TimelineWidget::TimelineWidget( viewWindow.set_time_scale(GAVL_TIME_SCALE / 200); set_selection(2000000, 4000000); + g_message("update_tracks"); update_tracks(); attach(*body, 1, 2, 1, 2, FILL|EXPAND, FILL|EXPAND); @@ -90,6 +93,7 @@ TimelineWidget::TimelineWidget( // Receive notifications of changes to the tracks sequence->get_child_track_list().signal_changed().connect( sigc::mem_fun( this, &TimelineWidget::on_track_list_changed ) ); + g_message("Constructor }"); } TimelineWidget::~TimelineWidget() @@ -296,6 +300,10 @@ TimelineWidget::update_tracks() // Create timeline tracks from all the model tracks create_timeline_tracks(); + // Update the layout helper + layoutHelper.clone_tree_from_sequence(); + layoutHelper.update_layout(); + // Update the header container REQUIRE(headerContainer != NULL); headerContainer->show_all_children(); @@ -303,15 +311,6 @@ TimelineWidget::update_tracks() // Update the body body->queue_draw(); - - // Recalculate the total height of the timeline scrolled area - totalHeight = 0; - BOOST_FOREACH(shared_ptr track, - sequence->get_child_tracks()) - { - REQUIRE(track); - totalHeight += measure_branch_height(track); - } } void @@ -339,9 +338,6 @@ TimelineWidget::create_timeline_tracks_from_branch( // We will need to create one trackMap[model_track] = create_timeline_track_from_model_track(model_track); - - // Hook up - } // Recurse to child tracks @@ -419,6 +415,9 @@ TimelineWidget::lookup_timeline_track( shared_ptr model_track) const { REQUIRE(sequence); + REQUIRE(model_track); + REQUIRE(model_track != sequence); // The sequence isn't really a track + std::map, shared_ptr >:: const_iterator iterator = trackMap.find(model_track); if(iterator == trackMap.end()) @@ -434,31 +433,6 @@ TimelineWidget::lookup_timeline_track( return iterator->second; } -boost::shared_ptr -TimelineWidget::lookup_model_track( - const timeline::Track *timeline_track) const -{ - REQUIRE(sequence); - - std::pair, shared_ptr > - 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(); -} - void TimelineWidget::update_scroll() { @@ -479,7 +453,8 @@ TimelineWidget::update_scroll() // Calculate the vertical length that can be scrolled: // the total height of all the tracks minus one screenful - int y_scroll_length = totalHeight - body_allocation.get_height(); + int y_scroll_length = layoutHelper.get_total_height() - + body_allocation.get_height(); if(y_scroll_length < 0) y_scroll_length = 0; // If by resizing we're now over-scrolled, scroll back to @@ -501,29 +476,6 @@ TimelineWidget::update_scroll() } -int -TimelineWidget::measure_branch_height( - shared_ptr model_track) -{ - REQUIRE(model_track); - - const shared_ptr timeline_track = - lookup_timeline_track(model_track); - ENSURE(timeline_track); - - int height = timeline_track->get_height() + TrackPadding; - - // Recurse through all the children - BOOST_FOREACH( shared_ptr child, - model_track->get_child_tracks() ) - { - REQUIRE(child); - height += measure_branch_height(child); - } - - return height; -} - int TimelineWidget::get_y_scroll_offset() const { diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index 9f368e147..b6ea075a4 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -217,25 +217,11 @@ private: **/ boost::shared_ptr lookup_timeline_track( boost::shared_ptr 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 lookup_model_track( - const timeline::Track *timeline_track) const; // ----- Layout Functions ----- // void update_scroll(); - int measure_branch_height( - boost::shared_ptr model_track); - int get_y_scroll_offset() const; // ----- Event Handlers -----// @@ -293,8 +279,6 @@ protected: boost::shared_ptr hoveringTrack; - int totalHeight; - // Child Widgets timeline::TimelineHeaderContainer *headerContainer; timeline::TimelineBody *body; diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index be1307c1c..a1bd1b075 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -135,6 +135,7 @@ TimelineHeaderContainer::on_unrealize() bool TimelineHeaderContainer::on_button_press_event ( GdkEventButton* event) { + REQUIRE(timelineWidget != NULL); REQUIRE(event != NULL); switch(event->button) @@ -152,8 +153,9 @@ bool TimelineHeaderContainer::on_button_press_event ( case 3: // Right Click { // Popup the context menu - shared_ptr header = header_from_point( - Gdk::Point(event->x, event->y)); + shared_ptr header( + timelineWidget->layoutHelper.header_from_point( + Gdk::Point(event->x, event->y))); // Are we hovering on a header? if(header) @@ -183,6 +185,8 @@ bool TimelineHeaderContainer::on_button_release_event ( // Yes? The toggle the expanding clickedExpander->set_expanded(!clickedExpander->get_expanded()); clickedExpander.reset(); + + timelineWidget->layoutHelper.update_layout(); layout_headers(); } @@ -304,88 +308,58 @@ TimelineHeaderContainer::on_hovering_track_changed( void TimelineHeaderContainer::layout_headers() -{ +{ + REQUIRE(timelineWidget != NULL); + // We can't layout before the widget has been set up if(!gdkWindow) return; - - // Make sure the style are loaded - read_styles(); - - // Clear previously cached layout - headerBoxes.clear(); - - // Start at minus-the-scroll offset - int offset = -timelineWidget->get_y_scroll_offset(); - - const Allocation container_allocation = get_allocation(); - const int header_width = container_allocation.get_width(); - BOOST_FOREACH( shared_ptr model_track, get_tracks() ) - layout_headers_recursive( - model_track, offset, header_width, 0, true); + TimelineLayoutHelper &layoutHelper = + timelineWidget->layoutHelper; + const TimelineLayoutHelper::TrackTree &layoutTree = + layoutHelper.get_layout_tree(); + + TimelineLayoutHelper::TrackTree::pre_order_iterator iterator; + for(iterator = ++layoutTree.begin(); // ++ so that we skip the sequence root + iterator != layoutTree.end(); + iterator++) + { + const shared_ptr timeline_track = + lookup_timeline_track(*iterator); + + Widget &widget = timeline_track->get_header_widget(); + + optional header_rect = + layoutHelper.get_track_header_rect(timeline_track); + + if(header_rect) + { + REQUIRE(header_rect->get_width() >= 0); + REQUIRE(header_rect->get_height() >= 0); + + // Calculate the allocation of the header widget + Allocation header_allocation( + header_rect->get_x() + margin + expand_button_size, // x + header_rect->get_y() + margin, // y + max( header_rect->get_width() - expand_button_size - + margin * 2, 0 ), // width + header_rect->get_height() - margin * 2); // height + + // Apply the allocation to the header + widget.size_allocate (header_allocation); + if(!widget.is_visible()) + widget.show(); + } + else // No header rect, so the track must be hidden + if(widget.is_visible()) + widget.hide(); + } // Repaint the background of our parenting queue_draw (); } -void -TimelineHeaderContainer::layout_headers_recursive( - shared_ptr model_track, int &offset, - const int header_width, const int depth, bool parent_expanded) -{ - REQUIRE(depth >= 0); - REQUIRE(model_track != NULL); - - shared_ptr timeline_track = - lookup_timeline_track(model_track); - - const int indent = depth * 10; - Widget &widget = timeline_track->get_header_widget(); - - if(parent_expanded) - { - const int track_height = timeline_track->get_height(); - - // Calculate the box of the header - Gdk::Rectangle header_box( - indent, // x - offset, // y - max( header_width - indent, 0 ), // width - track_height); // height - REQUIRE(header_box.get_height() >= 0); - - // Cache the bounding box - headerBoxes[timeline_track] = header_box; - - // Calculate the allocation of the header widget - Allocation header_allocation( - header_box.get_x() + margin + expand_button_size, // x - header_box.get_y() + margin, // y - max( header_box.get_width() - expand_button_size - - margin * 2, 0 ), // width - header_box.get_height() - margin * 2); // height - - // Apply the allocation to the header - widget.size_allocate (header_allocation); - if(!widget.is_visible()) - widget.show(); - - // Offset for the next header - offset += track_height + TimelineWidget::TrackPadding; - } - else - if(widget.is_visible()) - widget.hide(); - - // Recurse through all the children - BOOST_FOREACH( boost::shared_ptr child, - model_track->get_child_tracks() ) - layout_headers_recursive( - child, offset, header_width, depth + 1, - timeline_track->get_expanded() && parent_expanded); -} - void TimelineHeaderContainer::set_parent_recursive( boost::shared_ptr model_track) @@ -442,6 +416,7 @@ TimelineHeaderContainer::draw_header_decoration( shared_ptr model_track, const Gdk::Rectangle &clip_rect) { + REQUIRE(timelineWidget != NULL); REQUIRE(model_track != NULL); REQUIRE(clip_rect.get_width() > 0); REQUIRE(clip_rect.get_height() > 0); @@ -452,10 +427,11 @@ TimelineHeaderContainer::draw_header_decoration( shared_ptr timeline_track = lookup_timeline_track(model_track); - // Get the cached header box - weak_ptr ptr(timeline_track); - REQUIRE(contains(headerBoxes, ptr)); - const Gdk::Rectangle &box = headerBoxes[timeline_track]; + // Get the header box + const optional &optional_box = + timelineWidget->layoutHelper.get_track_header_rect(timeline_track); + REQUIRE(optional_box); + const Gdk::Rectangle box = *optional_box; // Paint the box, if it will be visible if(box.get_x() < clip_rect.get_width() && @@ -498,58 +474,55 @@ TimelineHeaderContainer::draw_header_decoration( } } -boost::shared_ptr -TimelineHeaderContainer::header_from_point(const Gdk::Point &point) -{ - std::pair, 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(); -} - shared_ptr TimelineHeaderContainer::expander_button_from_point( const Gdk::Point &point) -{ - std::pair, Gdk::Rectangle> pair; - BOOST_FOREACH( pair, headerBoxes ) +{ + const TimelineLayoutHelper::TrackTree &layoutTree = + timelineWidget->layoutHelper.get_layout_tree(); + + TimelineLayoutHelper::TrackTree::pre_order_iterator iterator; + for(iterator = ++layoutTree.begin(); // ++ so we skip the sequence root + iterator != layoutTree.end(); + iterator++) { - // Hit test the rectangle - const Gdk::Rectangle rect = - get_expander_button_rectangle(pair.first); + const shared_ptr timeline_track = + lookup_timeline_track(*iterator); - 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; + // Hit test the rectangle + const optional rect = + get_expander_button_rectangle(timeline_track); + + if(rect) + { + 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 timeline_track; + } } return shared_ptr(); } -const Gdk::Rectangle +const optional TimelineHeaderContainer::get_expander_button_rectangle( shared_ptr track) { + REQUIRE(timelineWidget != NULL); REQUIRE(track != NULL); - weak_ptr ptr(track); - REQUIRE(contains(headerBoxes, ptr)); - const Gdk::Rectangle &box = headerBoxes[track]; - return Gdk::Rectangle( - margin + box.get_x(), margin + box.get_y(), - expand_button_size, box.get_height() - margin * 2); + optional box = + timelineWidget->layoutHelper.get_track_header_rect(track); + if(box) + { + return optional(Gdk::Rectangle( + margin + box->get_x(), margin + box->get_y(), + expand_button_size, box->get_height() - margin * 2)); + } + + return optional(); } shared_ptr diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index 86d61182e..d8e29d2a2 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -149,19 +149,7 @@ private: * stacking etc. */ void layout_headers(); - - /** - * Recursively lays out all the controls in the header widget. - * @param track The parent track object which will be recursed into. - * @param offset A shared value used to accumulate the y-offset of - * header widgets. - * @param header_width The width of this widget in pixels. - * @param depth The depth within the tree of track. - **/ - void layout_headers_recursive(boost::shared_ptr track, - int &offset, const int header_width, const int depth, - bool parent_expanded); - + /** * Recursively sets all the track header widgets to be child widgets * of this widget. @@ -199,9 +187,6 @@ private: void draw_header_decoration( boost::shared_ptr model_track, const Gdk::Rectangle &clip_rect); - - boost::shared_ptr header_from_point( - const Gdk::Point &point); /** * Given a point, expander_button_from_point finds the track of the @@ -219,7 +204,7 @@ private: * @param track The track to get the expander button rectangle of. * @return Returns the rectangle of the expander button of track. **/ - const Gdk::Rectangle get_expander_button_rectangle( + const boost::optional get_expander_button_rectangle( boost::shared_ptr track); /** @@ -278,16 +263,7 @@ private: * click is not processed by track headers. **/ Gtk::Menu contextMenu; - - /** - * A map of tracks to the rectangles of their headers. - * @remarks This map is used as a cache, so that the rectangles don't - * need to be perpetually recalculated. This cache is regenerated by - * the layout_headers method. - **/ - std::map, Gdk::Rectangle> - headerBoxes; - + //----- User Interaction State -----// boost::shared_ptr hoveringExpander; diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 11d97d7ce..f7c46dafd 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -31,13 +31,15 @@ using namespace Gtk; using namespace std; using namespace boost; using namespace lumiera; +using namespace util; namespace gui { namespace widgets { namespace timeline { -TimelineLayoutHelper::TimelineLayoutHelper(TimelineWidget &owner) - : timelineWidget(owner) +TimelineLayoutHelper::TimelineLayoutHelper(TimelineWidget &owner) : + timelineWidget(owner), + totalHeight(0) { } @@ -48,12 +50,16 @@ TimelineLayoutHelper::clone_tree_from_sequence() REQUIRE(sequence); layoutTree.clear(); - TrackTree::iterator_base iterator = - layoutTree.set_head(sequence); - + TrackTree::iterator_base iterator = layoutTree.set_head(sequence); add_branch(iterator, sequence); } +TimelineLayoutHelper::TrackTree& +TimelineLayoutHelper::get_layout_tree() +{ + return layoutTree; +} + void TimelineLayoutHelper::add_branch( TrackTree::iterator_base parent_iterator, @@ -68,6 +74,45 @@ TimelineLayoutHelper::add_branch( } } +optional +TimelineLayoutHelper::get_track_header_rect( + boost::weak_ptr track) +{ + if(contains(headerBoxes, track)) + { + Gdk::Rectangle rect(headerBoxes[track]); + rect.set_y(rect.get_y() - timelineWidget.get_y_scroll_offset()); + return optional(rect); + } + return optional(); +} + +weak_ptr +TimelineLayoutHelper::header_from_point(const Gdk::Point &point) +{ + std::pair, 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(); +} + +int +TimelineLayoutHelper::get_total_height() const +{ + ENSURE(totalHeight >= 0); + return totalHeight; +} + void TimelineLayoutHelper::update_layout() { @@ -81,11 +126,13 @@ TimelineLayoutHelper::update_layout() int offset = 0;//-timelineWidget->get_y_scroll_offset(); //const Allocation container_allocation = get_allocation(); - const int header_width = 100;//container_allocation.get_width(); + const int header_width = 150;//container_allocation.get_width(); const int indent_width = 10; - + layout_headers_recursive(layoutTree.begin(), offset, header_width, indent_width, 0, true); + + totalHeight = offset; } void diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index d9446d707..61ce80e52 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -56,17 +56,30 @@ public: public: TimelineLayoutHelper(TimelineWidget &owner); -protected: - + void clone_tree_from_sequence(); + TrackTree& get_layout_tree(); + + /** + * Recalculates the track layout from layoutTree. + **/ + void update_layout(); + + boost::optional get_track_header_rect( + boost::weak_ptr track); + + boost::weak_ptr header_from_point( + const Gdk::Point &point); + + int get_total_height() const; + +protected: + void add_branch(TrackTree::iterator_base parent_iterator, boost::shared_ptr parent); - /** - * Recaculates the track layout from layoutTree. - **/ - void update_layout(); + /** * Recursively lays out all the controls in the header widget. @@ -113,6 +126,8 @@ protected: **/ std::map, Gdk::Rectangle> headerBoxes; + + int totalHeight; }; } // namespace timeline diff --git a/src/gui/widgets/timeline/timeline-track.cpp b/src/gui/widgets/timeline/timeline-track.cpp index e7d39e22a..d6605941c 100644 --- a/src/gui/widgets/timeline/timeline-track.cpp +++ b/src/gui/widgets/timeline/timeline-track.cpp @@ -90,6 +90,12 @@ Track::get_header_widget() return headerWidget; } +shared_ptr +Track::get_model_track() const +{ + return model_track; +} + int Track::get_height() const { diff --git a/src/gui/widgets/timeline/timeline-track.hpp b/src/gui/widgets/timeline/timeline-track.hpp index 1840b207d..652543afc 100644 --- a/src/gui/widgets/timeline/timeline-track.hpp +++ b/src/gui/widgets/timeline/timeline-track.hpp @@ -45,6 +45,8 @@ public: Gtk::Widget& get_header_widget(); + boost::shared_ptr get_model_track() const; + int get_height() const; bool get_expanded() const; From 85d6a19dd484ee6b6044e0ca2d6ca6f90788a236 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 00:33:40 +0000 Subject: [PATCH 18/68] Fixed a bug caused by TimelineHeaderContainer::read_styles being called at the wrong time --- src/gui/widgets/timeline/timeline-header-container.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index a1bd1b075..e2445c67e 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -87,6 +87,9 @@ TimelineHeaderContainer::on_realize() // Call base class: Gtk::Container::on_realize(); + // Load the styles up + read_styles(); + // Create the GdkWindow: GdkWindowAttr attributes; memset(&attributes, 0, sizeof(attributes)); @@ -269,8 +272,6 @@ TimelineHeaderContainer::on_expose_event(GdkEventExpose *event) if(gdkWindow) { const Allocation container_allocation = get_allocation(); - - read_styles(); // Paint a border underneath all the root headers BOOST_FOREACH( shared_ptr model_track, @@ -314,7 +315,7 @@ TimelineHeaderContainer::layout_headers() // We can't layout before the widget has been set up if(!gdkWindow) return; - + TimelineLayoutHelper &layoutHelper = timelineWidget->layoutHelper; const TimelineLayoutHelper::TrackTree &layoutTree = @@ -568,6 +569,9 @@ TimelineHeaderContainer::read_styles() { if(margin <= 0) get_style_property("heading_margin", margin); + else + WARN(gui, "TimelineHeaderContainer::read_styles()" + " should only be called once"); } } // namespace timeline From 8285daec39a4ff211f319a2480547166884fb2f1 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 00:44:10 +0000 Subject: [PATCH 19/68] Added more strictness to the use of read_styles --- src/gui/widgets/timeline/timeline-header-container.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index e2445c67e..4ac26b9e5 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -311,6 +311,7 @@ void TimelineHeaderContainer::layout_headers() { REQUIRE(timelineWidget != NULL); + REQUIRE(margin >= 0); // read_styles must have been called before now // We can't layout before the widget has been set up if(!gdkWindow) @@ -568,7 +569,10 @@ void TimelineHeaderContainer::read_styles() { if(margin <= 0) - get_style_property("heading_margin", margin); + { + get_style_property("heading_margin", margin); + margin = max(margin, 0); + } else WARN(gui, "TimelineHeaderContainer::read_styles()" " should only be called once"); From e3a7b896d0d5c36d799a5ec61276275291777a34 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 00:45:20 +0000 Subject: [PATCH 20/68] Removed debug g_message calls --- src/gui/widgets/timeline-widget.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 64421bf16..eab079fce 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -55,7 +55,6 @@ TimelineWidget::TimelineWidget( horizontalScroll(horizontalAdjustment), verticalScroll(verticalAdjustment) { - g_message("TimelineWidget::TimelineWidget"); REQUIRE(sequence); body = new TimelineBody(this); @@ -64,8 +63,6 @@ TimelineWidget::TimelineWidget( ENSURE(headerContainer != NULL); ruler = new TimelineRuler(this); ENSURE(ruler != NULL); - - g_message("Widgets Constructed"); horizontalAdjustment.signal_value_changed().connect( sigc::mem_fun( this, &TimelineWidget::on_scroll) ); @@ -79,7 +76,6 @@ TimelineWidget::TimelineWidget( viewWindow.set_time_scale(GAVL_TIME_SCALE / 200); set_selection(2000000, 4000000); - g_message("update_tracks"); update_tracks(); attach(*body, 1, 2, 1, 2, FILL|EXPAND, FILL|EXPAND); @@ -93,7 +89,6 @@ TimelineWidget::TimelineWidget( // Receive notifications of changes to the tracks sequence->get_child_track_list().signal_changed().connect( sigc::mem_fun( this, &TimelineWidget::on_track_list_changed ) ); - g_message("Constructor }"); } TimelineWidget::~TimelineWidget() From 325a2101e718d780977b50527f6e7abf91f8fd29 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 00:47:09 +0000 Subject: [PATCH 21/68] Moved read_styles to occur earlier in the creation of TimelineHeaderContainer --- src/gui/widgets/timeline/timeline-header-container.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index 4ac26b9e5..c8f3bc1de 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -69,6 +69,9 @@ TimelineHeaderContainer::TimelineHeaderContainer( // Install style properties register_styles(); + + // Load the styles up + read_styles(); } void @@ -87,9 +90,6 @@ TimelineHeaderContainer::on_realize() // Call base class: Gtk::Container::on_realize(); - // Load the styles up - read_styles(); - // Create the GdkWindow: GdkWindowAttr attributes; memset(&attributes, 0, sizeof(attributes)); From bb8f825afe17ff2033fb82e3c4f43f346564123a Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 2 Jan 2009 01:51:22 +0100 Subject: [PATCH 22/68] add AC_CONFIG_MACRO_DIR and fixed some m4 quoting --- configure.ac | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index eb78e6d9a..abd465973 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,7 @@ AC_INIT(lumiera, 0.1pre) -AC_CONFIG_SRCDIR(src/lib/luid.c) -AC_CONFIG_AUX_DIR(scripts) +AC_CONFIG_SRCDIR([src/lib/luid.c]) +AC_CONFIG_AUX_DIR([scripts]) +AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE AC_PREREQ(2.59) From c05f0fbbfba70481622487986dcedc50f2f89384 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 11:39:45 +0000 Subject: [PATCH 23/68] Added a comment --- src/gui/widgets/timeline/timeline-layout-helper.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index f7c46dafd..0274c2d12 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -102,7 +102,8 @@ TimelineLayoutHelper::header_from_point(const Gdk::Point &point) point.get_y() < rect.get_y() + rect.get_height()) return pair.first; } - + + // No track was found - return an empty pointer return shared_ptr(); } From 9fac0b8b46667c89862960243518b93395b59c3c Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 11:53:32 +0000 Subject: [PATCH 24/68] Renamed some local variables for greater consistency --- .../timeline/timeline-header-container.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index c8f3bc1de..eb99979f3 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -317,14 +317,14 @@ TimelineHeaderContainer::layout_headers() if(!gdkWindow) return; - TimelineLayoutHelper &layoutHelper = + TimelineLayoutHelper &layout_helper = timelineWidget->layoutHelper; - const TimelineLayoutHelper::TrackTree &layoutTree = - layoutHelper.get_layout_tree(); + const TimelineLayoutHelper::TrackTree &layout_tree = + layout_helper.get_layout_tree(); TimelineLayoutHelper::TrackTree::pre_order_iterator iterator; - for(iterator = ++layoutTree.begin(); // ++ so that we skip the sequence root - iterator != layoutTree.end(); + for(iterator = ++layout_tree.begin(); // ++ so that we skip the sequence root + iterator != layout_tree.end(); iterator++) { const shared_ptr timeline_track = @@ -333,7 +333,7 @@ TimelineHeaderContainer::layout_headers() Widget &widget = timeline_track->get_header_widget(); optional header_rect = - layoutHelper.get_track_header_rect(timeline_track); + layout_helper.get_track_header_rect(timeline_track); if(header_rect) { @@ -480,12 +480,12 @@ shared_ptr TimelineHeaderContainer::expander_button_from_point( const Gdk::Point &point) { - const TimelineLayoutHelper::TrackTree &layoutTree = + const TimelineLayoutHelper::TrackTree &layout_tree = timelineWidget->layoutHelper.get_layout_tree(); TimelineLayoutHelper::TrackTree::pre_order_iterator iterator; - for(iterator = ++layoutTree.begin(); // ++ so we skip the sequence root - iterator != layoutTree.end(); + for(iterator = ++layout_tree.begin(); // ++ so we skip the sequence root + iterator != layout_tree.end(); iterator++) { const shared_ptr timeline_track = From bcd5dababea8702bb846037f52124264cf9e6db5 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 12:17:19 +0000 Subject: [PATCH 25/68] Transitioned TimelineBody drawing code to use the TimelineLayoutHelper --- src/gui/widgets/timeline/timeline-body.cpp | 44 ++++++++++++------- src/gui/widgets/timeline/timeline-body.hpp | 2 +- .../timeline/timeline-layout-helper.cpp | 16 +++++++ .../timeline/timeline-layout-helper.hpp | 2 + 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp index 06a4801c2..d6ee18eba 100644 --- a/src/gui/widgets/timeline/timeline-body.cpp +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -287,26 +287,46 @@ TimelineBody::draw_tracks(Cairo::RefPtr cr) REQUIRE(timelineWidget->sequence); // Prepare + TimelineLayoutHelper &layout_helper = timelineWidget->layoutHelper; + const TimelineLayoutHelper::TrackTree &layout_tree = + layout_helper.get_layout_tree(); const Allocation allocation = get_allocation(); // Save the view matrix Cairo::Matrix view_matrix; cr->get_matrix(view_matrix); - // Translate the view by the scroll distance - cr->translate(0, -get_vertical_offset()); - - // Interate drawing each track - BOOST_FOREACH( shared_ptr model_track, - timelineWidget->sequence->get_child_tracks() ) - draw_track_recursive(cr, model_track, allocation.get_width()); + // Iterate drawing each track + TimelineLayoutHelper::TrackTree::pre_order_iterator iterator; + for(iterator = ++layout_tree.begin(); // ++ so we skip the sequence root + iterator != layout_tree.end(); + iterator++) + { + const shared_ptr model_track(*iterator); + const shared_ptr timeline_track = + timelineWidget->lookup_timeline_track(*iterator); + + optional rect = + layout_helper.get_track_header_rect(timeline_track); + + // Is this track visible? + if(rect) + { + // Translate to the top of the track + cr->set_matrix(view_matrix); + cr->translate(0, rect->get_y()); + + // Draw the track + draw_track(cr, model_track, allocation.get_width()); + } + } // Restore the view matrix cr->set_matrix(view_matrix); } void -TimelineBody::draw_track_recursive(Cairo::RefPtr cr, +TimelineBody::draw_track(Cairo::RefPtr cr, shared_ptr model_track, const int view_width) const { REQUIRE(cr); @@ -329,14 +349,6 @@ TimelineBody::draw_track_recursive(Cairo::RefPtr cr, cr->save(); timeline_track->draw_track(cr, &timelineWidget->get_view_window()); cr->restore(); - - // Shift for the next track - cr->translate(0, height + TimelineWidget::TrackPadding); - - // Recurse drawing into children - BOOST_FOREACH( shared_ptr child, - model_track->get_child_tracks() ) - draw_track_recursive(cr, child, view_width); } void diff --git a/src/gui/widgets/timeline/timeline-body.hpp b/src/gui/widgets/timeline/timeline-body.hpp index 2489ee7de..12ec6c5a9 100644 --- a/src/gui/widgets/timeline/timeline-body.hpp +++ b/src/gui/widgets/timeline/timeline-body.hpp @@ -118,7 +118,7 @@ private: */ void draw_tracks(Cairo::RefPtr cr); - void draw_track_recursive(Cairo::RefPtr cr, + void draw_track(Cairo::RefPtr cr, boost::shared_ptr track, const int view_width) const; /** diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 0274c2d12..011869d70 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -107,6 +107,22 @@ TimelineLayoutHelper::header_from_point(const Gdk::Point &point) return shared_ptr(); } +boost::weak_ptr +TimelineLayoutHelper::track_from_y(const int y) +{ + std::pair, Gdk::Rectangle> pair; + BOOST_FOREACH( pair, headerBoxes ) + { + // Hit test the rectangle + const Gdk::Rectangle &rect = pair.second; + if(y >= rect.get_y() && y < rect.get_y() + rect.get_height()) + return pair.first; + } + + // No track was found - return an empty pointer + return shared_ptr(); +} + int TimelineLayoutHelper::get_total_height() const { diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 61ce80e52..566ad1f02 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -72,6 +72,8 @@ public: boost::weak_ptr header_from_point( const Gdk::Point &point); + boost::weak_ptr track_from_y(const int y); + int get_total_height() const; protected: From 86947936a5c7c355e505bd4627c3e3d2f6a4628f Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 12:20:43 +0000 Subject: [PATCH 26/68] Tidied TimelineBody::draw_track somewhat --- src/gui/widgets/timeline/timeline-body.cpp | 12 +++++------- src/gui/widgets/timeline/timeline-body.hpp | 3 ++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp index d6ee18eba..3d47f9500 100644 --- a/src/gui/widgets/timeline/timeline-body.cpp +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -317,7 +317,7 @@ TimelineBody::draw_tracks(Cairo::RefPtr cr) cr->translate(0, rect->get_y()); // Draw the track - draw_track(cr, model_track, allocation.get_width()); + draw_track(cr, timeline_track, allocation.get_width()); } } @@ -327,15 +327,13 @@ TimelineBody::draw_tracks(Cairo::RefPtr cr) void TimelineBody::draw_track(Cairo::RefPtr cr, - shared_ptr model_track, const int view_width) const + shared_ptr timeline_track, + const int view_width) const { REQUIRE(cr); - REQUIRE(model_track != NULL); + REQUIRE(timeline_track != NULL); REQUIRE(timelineWidget != NULL); - - shared_ptr timeline_track = timelineWidget-> - lookup_timeline_track(model_track); - + const int height = timeline_track->get_height(); REQUIRE(height >= 0); diff --git a/src/gui/widgets/timeline/timeline-body.hpp b/src/gui/widgets/timeline/timeline-body.hpp index 12ec6c5a9..fe4ecd2ef 100644 --- a/src/gui/widgets/timeline/timeline-body.hpp +++ b/src/gui/widgets/timeline/timeline-body.hpp @@ -119,7 +119,8 @@ private: void draw_tracks(Cairo::RefPtr cr); void draw_track(Cairo::RefPtr cr, - boost::shared_ptr track, const int view_width) const; + boost::shared_ptr timeline_track, + const int view_width) const; /** * Draws the selected timeline period. From e135cb18cbc90a3979e3013f16ee4d85078e26a9 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 12:41:30 +0000 Subject: [PATCH 27/68] Removed TimelineBody::track_from_point --- src/gui/widgets/timeline/timeline-body.cpp | 59 +------------------ src/gui/widgets/timeline/timeline-body.hpp | 9 +-- .../timeline/timeline-layout-helper.cpp | 4 +- .../timeline/timeline-layout-helper.hpp | 2 +- 4 files changed, 7 insertions(+), 67 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp index 3d47f9500..67cd257ea 100644 --- a/src/gui/widgets/timeline/timeline-body.cpp +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -244,6 +244,7 @@ bool TimelineBody::on_motion_notify_event(GdkEventMotion *event) { REQUIRE(event != NULL); + REQUIRE(timelineWidget != NULL); // Handle a middle-mouse drag if one is occuring switch(dragType) @@ -270,8 +271,8 @@ TimelineBody::on_motion_notify_event(GdkEventMotion *event) tool->on_motion_notify_event(event); // See if the track that we're hovering over has changed - shared_ptr new_hovering_track = - track_from_point(event->y); + shared_ptr new_hovering_track( + timelineWidget->layoutHelper.track_from_y(event->y)); if(timelineWidget->get_hovering_track() != new_hovering_track) timelineWidget->set_hovering_track(new_hovering_track); @@ -446,60 +447,6 @@ TimelineBody::set_vertical_offset(int offset) timelineWidget->verticalAdjustment.set_value(offset); } -shared_ptr -TimelineBody::track_from_point(const int y) const -{ - REQUIRE(timelineWidget != NULL); - REQUIRE(timelineWidget->sequence); - - int offset = -get_vertical_offset(); - - BOOST_FOREACH( shared_ptr model_track, - timelineWidget->sequence->get_child_tracks() ) - { - shared_ptr result = track_from_branch( - model_track, y, offset); - if(result) - return result; - } - - // No track has been found with this point in it - return boost::shared_ptr(); -} - -shared_ptr TimelineBody::track_from_branch( - shared_ptr model_track, - const int y, int &offset) const -{ - REQUIRE(timelineWidget != NULL); - - shared_ptr timeline_track = timelineWidget-> - lookup_timeline_track(model_track); - - const int height = timeline_track->get_height(); - REQUIRE(height >= 0); - - // Does the point fall in this track? - if(offset <= y && y < offset + height) - return timeline_track; - - // Add the height of this track to the accumulation - offset += height; - - // Recurse drawing into children - BOOST_FOREACH( shared_ptr child, - model_track->get_child_tracks() ) - { - shared_ptr result = - track_from_branch(child, y, offset); - if(result != NULL) - return result; - } - - // No track has been found in this branch - return shared_ptr(); -} - void TimelineBody::register_styles() const { diff --git a/src/gui/widgets/timeline/timeline-body.hpp b/src/gui/widgets/timeline/timeline-body.hpp index fe4ecd2ef..1200f56e8 100644 --- a/src/gui/widgets/timeline/timeline-body.hpp +++ b/src/gui/widgets/timeline/timeline-body.hpp @@ -139,14 +139,7 @@ private: int get_vertical_offset() const; void set_vertical_offset(int offset); - - boost::shared_ptr track_from_point(const int y) - const; - - boost::shared_ptr track_from_branch( - boost::shared_ptr model_track, - const int y, int &offset) const; - + /** * Registers all the styles that this class will respond to. */ diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 011869d70..299be4c4a 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -107,7 +107,7 @@ TimelineLayoutHelper::header_from_point(const Gdk::Point &point) return shared_ptr(); } -boost::weak_ptr +boost::shared_ptr TimelineLayoutHelper::track_from_y(const int y) { std::pair, Gdk::Rectangle> pair; @@ -116,7 +116,7 @@ TimelineLayoutHelper::track_from_y(const int y) // Hit test the rectangle const Gdk::Rectangle &rect = pair.second; if(y >= rect.get_y() && y < rect.get_y() + rect.get_height()) - return pair.first; + return shared_ptr(pair.first); } // No track was found - return an empty pointer diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 566ad1f02..3e9d77145 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -72,7 +72,7 @@ public: boost::weak_ptr header_from_point( const Gdk::Point &point); - boost::weak_ptr track_from_y(const int y); + boost::shared_ptr track_from_y(const int y); int get_total_height() const; From a501616a87ff0931453a9e2ce41585b7cbc9df63 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 12:43:21 +0000 Subject: [PATCH 28/68] Transitioned TimelineLayoutHelper::get_track_header_rect to return weak_ptr --- src/gui/widgets/timeline/timeline-layout-helper.cpp | 4 ++-- src/gui/widgets/timeline/timeline-layout-helper.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 299be4c4a..8ab9b8978 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -87,7 +87,7 @@ TimelineLayoutHelper::get_track_header_rect( return optional(); } -weak_ptr +shared_ptr TimelineLayoutHelper::header_from_point(const Gdk::Point &point) { std::pair, Gdk::Rectangle> pair; @@ -100,7 +100,7 @@ TimelineLayoutHelper::header_from_point(const Gdk::Point &point) 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(pair.first); } // No track was found - return an empty pointer diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 3e9d77145..6ca659365 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -69,7 +69,7 @@ public: boost::optional get_track_header_rect( boost::weak_ptr track); - boost::weak_ptr header_from_point( + boost::shared_ptr header_from_point( const Gdk::Point &point); boost::shared_ptr track_from_y(const int y); From 1c685a2d61601fff10308f8e9244ed3e85caf882 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 13:03:00 +0000 Subject: [PATCH 29/68] Added a new layout update infrastructure --- src/gui/widgets/timeline-widget.cpp | 19 +++++++++++++------ src/gui/widgets/timeline-widget.hpp | 2 ++ .../timeline/timeline-header-container.cpp | 1 - .../timeline/timeline-header-container.hpp | 1 + .../timeline/timeline-layout-helper.cpp | 2 ++ 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index eab079fce..6a4c0add2 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -295,17 +295,14 @@ TimelineWidget::update_tracks() // Create timeline tracks from all the model tracks create_timeline_tracks(); - // Update the layout helper - layoutHelper.clone_tree_from_sequence(); - layoutHelper.update_layout(); - // Update the header container REQUIRE(headerContainer != NULL); headerContainer->show_all_children(); headerContainer->update_headers(); - // Update the body - body->queue_draw(); + // Update the layout helper + layoutHelper.clone_tree_from_sequence(); + layoutHelper.update_layout(); } void @@ -428,6 +425,16 @@ TimelineWidget::lookup_timeline_track( return iterator->second; } +void +TimelineWidget::on_layout_changed() +{ + REQUIRE(headerContainer != NULL); + REQUIRE(body != NULL); + + headerContainer->layout_headers(); + body->queue_draw(); +} + void TimelineWidget::update_scroll() { diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index b6ea075a4..cbd21925e 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -220,6 +220,8 @@ private: // ----- Layout Functions ----- // + void on_layout_changed(); + void update_scroll(); int get_y_scroll_offset() const; diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index eb99979f3..41f9bed0e 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -190,7 +190,6 @@ bool TimelineHeaderContainer::on_button_release_event ( clickedExpander.reset(); timelineWidget->layoutHelper.update_layout(); - layout_headers(); } return Container::on_button_release_event(event); diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index d8e29d2a2..e81db9149 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -283,6 +283,7 @@ private: **/ int expand_button_size; + friend class gui::widgets::TimelineWidget; friend class timeline::Track; }; diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 8ab9b8978..4feedd5cc 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -150,6 +150,8 @@ TimelineLayoutHelper::update_layout() offset, header_width, indent_width, 0, true); totalHeight = offset; + + timelineWidget.on_layout_changed(); } void From 8debd21363094cf6a0e8855d58caf9a630c7b7cd Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 13:10:56 +0000 Subject: [PATCH 30/68] Squished some warnings in lib/tree.hpp --- src/lib/tree.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/tree.hpp b/src/lib/tree.hpp index 02e823f72..a3cef9f57 100644 --- a/src/lib/tree.hpp +++ b/src/lib/tree.hpp @@ -2074,7 +2074,7 @@ typename tree::pre_order_iterator& tree -typename tree::pre_order_iterator tree::pre_order_iterator::operator++(int n) +typename tree::pre_order_iterator tree::pre_order_iterator::operator++(int) { pre_order_iterator copy = *this; ++(*this); @@ -2082,7 +2082,7 @@ typename tree::pre_order_iterator tree -typename tree::pre_order_iterator tree::pre_order_iterator::operator--(int n) +typename tree::pre_order_iterator tree::pre_order_iterator::operator--(int) { pre_order_iterator copy = *this; --(*this); @@ -2284,7 +2284,7 @@ typename tree::breadth_first_queued_iterator& tree -typename tree::breadth_first_queued_iterator tree::breadth_first_queued_iterator::operator++(int n) +typename tree::breadth_first_queued_iterator tree::breadth_first_queued_iterator::operator++(int) { breadth_first_queued_iterator copy = *this; ++(*this); From 2a9f1764c865d0b006d9c3b5c7851244b9d96847 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 13:18:09 +0000 Subject: [PATCH 31/68] Tidied TimelineLayoutHelper --- src/gui/widgets/timeline-widget.hpp | 1 + .../widgets/timeline/timeline-layout-helper.cpp | 14 +++++--------- .../widgets/timeline/timeline-layout-helper.hpp | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index cbd21925e..f362faaff 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -308,6 +308,7 @@ public: protected: static const int TrackPadding; static const int HeaderWidth; + static const int HeaderIndentWidth; static const double ZoomIncrement; friend class timeline::TimelineViewWindow; diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 4feedd5cc..85864b4ea 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -133,24 +133,20 @@ TimelineLayoutHelper::get_total_height() const void TimelineLayoutHelper::update_layout() { - // Make sure the style are loaded - //read_styles(); + int offset = 0; // Clear previously cached layout headerBoxes.clear(); - - // Start at minus-the-scroll offset - int offset = 0;//-timelineWidget->get_y_scroll_offset(); - - //const Allocation container_allocation = get_allocation(); - const int header_width = 150;//container_allocation.get_width(); - const int indent_width = 10; + // Do the layout + const int header_width = TimelineWidget::HeaderWidth; + const int indent_width = TimelineWidget::HeaderIndentWidth; layout_headers_recursive(layoutTree.begin(), offset, header_width, indent_width, 0, true); totalHeight = offset; + // Signal that the layout has changed timelineWidget.on_layout_changed(); } diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 6ca659365..39c01ea4b 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -86,7 +86,7 @@ protected: /** * Recursively lays out all the controls in the header widget. - * /!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * /!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! [in,out] * * * * @param track The parent track object which will be recursed into. From 8ad308e6797e68e8020136dca977fb3b4fefbf10 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 15:25:45 +0000 Subject: [PATCH 32/68] Fixed the find functions so they're offset by the scroll position, not absolute --- src/gui/widgets/timeline/timeline-layout-helper.cpp | 12 ++++++++++-- src/gui/widgets/timeline/timeline-layout-helper.hpp | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 85864b4ea..2116641fc 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -88,8 +88,12 @@ TimelineLayoutHelper::get_track_header_rect( } shared_ptr -TimelineLayoutHelper::header_from_point(const Gdk::Point &point) +TimelineLayoutHelper::header_from_point(Gdk::Point point) { + // Apply the scroll offset + point.set_y(point.get_y() + timelineWidget.get_y_scroll_offset()); + + // Search the headers std::pair, Gdk::Rectangle> pair; BOOST_FOREACH( pair, headerBoxes ) { @@ -108,8 +112,12 @@ TimelineLayoutHelper::header_from_point(const Gdk::Point &point) } boost::shared_ptr -TimelineLayoutHelper::track_from_y(const int y) +TimelineLayoutHelper::track_from_y(int y) { + // Apply the scroll offset + y += timelineWidget.get_y_scroll_offset(); + + // Search the tracks std::pair, Gdk::Rectangle> pair; BOOST_FOREACH( pair, headerBoxes ) { diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 39c01ea4b..0960afd10 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -70,9 +70,9 @@ public: boost::weak_ptr track); boost::shared_ptr header_from_point( - const Gdk::Point &point); + Gdk::Point point); - boost::shared_ptr track_from_y(const int y); + boost::shared_ptr track_from_y(int y); int get_total_height() const; From 643e1c9be1c56eb831f6f3efe159fd978074be07 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 15:26:12 +0000 Subject: [PATCH 33/68] Fixed an undefined constant --- src/gui/widgets/timeline-widget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 6a4c0add2..91cf58b01 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -36,6 +36,7 @@ namespace widgets { 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; From a28a901539be7de13a6888b249fd35439c51ccd4 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 15:47:56 +0000 Subject: [PATCH 34/68] Added an extra const of consistency --- src/gui/widgets/timeline/timeline-layout-helper.cpp | 2 +- src/gui/widgets/timeline/timeline-layout-helper.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 2116641fc..d57baddc5 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -162,7 +162,7 @@ void TimelineLayoutHelper::layout_headers_recursive( TrackTree::iterator_base parent_iterator, int &offset, const int header_width, const int indent_width, - const int depth, bool parent_expanded) + const int depth, const bool parent_expanded) { REQUIRE(depth >= 0); diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 0960afd10..08e3588be 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -99,7 +99,7 @@ protected: void layout_headers_recursive( TrackTree::iterator_base parent_iterator, int &offset, const int header_width, const int indent_width, - const int depth, bool parent_expanded); + const int depth, const bool parent_expanded); /** * A helper function which calls lookup_timeline_track within the From dfbe3764cd88f376596e036b64538356fda63205 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 15:54:32 +0000 Subject: [PATCH 35/68] Added documentation to timeline-layout-helper.hpp --- .../timeline/timeline-layout-helper.hpp | 121 +++++++++++++++--- 1 file changed, 102 insertions(+), 19 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.hpp b/src/gui/widgets/timeline/timeline-layout-helper.hpp index 08e3588be..f6fade115 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.hpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.hpp @@ -48,53 +48,124 @@ class Track; * A helper class for the TimelineWidget. TimelineLayoutHelper * is a class which calculates the layout of tracks in the timeline * track tree. + * @see gui::widgets::TimelineWidget */ class TimelineLayoutHelper : public boost::noncopyable { public: + /** + * Definition of the layout track tree type. + **/ typedef lumiera::tree< boost::shared_ptr > TrackTree; public: + /** + * Constructor. + * @param owner The timeline widget which is the owner of this helper + * class. + **/ TimelineLayoutHelper(TimelineWidget &owner); - + + /** + * Clones the timelineWidget sequence's track tree to create a layout + * tree which will be identitcal to it. + * @remarks The current layout tree will be deleted and replaced with + * the clone. + * @see add_branch + **/ void clone_tree_from_sequence(); + /** + * Gets a reference to the helper's layout tree. + * @return Returns a reference to the helper's layout tree. + **/ TrackTree& get_layout_tree(); /** * Recalculates the track layout from layoutTree. + * @see layout_headers_recursive **/ void update_layout(); + /** + * Get's the header rectangle of a given timeline track. + * @param[in] track The track which will be looked up. + * @return Returns the rectangle of the header offset by the y-scroll + * offset, or if the track is hidden, or not present in the layout + * tree, an empty optional will be returned. + * @remarks This function is only usable after update_layout() has + * been called on a valid tree of tracks. + * @see update_layout() + **/ boost::optional get_track_header_rect( boost::weak_ptr track); - + + /** + * Searches for a header which has the specified point inside of it. + * @param[in] point The point to search with. + * @return Returns the header which has been found, or if no header is + * found, an empty shared pointer is returned. + * @remarks The point specified is relative to the scroll offset, so + * y = 0 is the top edge of the scroll view. This function is only + * usable after update_layout() has been called on a valid tree of + * tracks. + * @see update_layout() + **/ boost::shared_ptr header_from_point( Gdk::Point point); - + + /** + * Searches for a tack which has the specified y-offset inside of it. + * @param[in] y The y-coordinate to search with. + * @return Returns the track which has been found, or if no track is + * found, an empty shared pointer is returned. + * @remarks The point specified is relative to the scroll offset, so + * y = 0 is the top edge of the scroll view. This function is only + * usable after update_layout() has been called on a valid tree of + * tracks. + * @see update_layout() + **/ boost::shared_ptr track_from_y(int y); - + + /** + * Returns the total height in pixels of the layout tree. + * @remarks This function is only on returns a valid value fter + * update_layout() has been called on a valid tree of tracks. + * @see update_layout() + **/ int get_total_height() const; protected: + /** + * A helper function for clone_tree_from_sequence(). This function + * clones a branch within the model tree into the specified point in + * that layout tree. + * @param[in] parent_iterator The iterator of the node in the tree + * which will become the parent of any tracks added. + * @param[in] parent A pointer to the model track whose children + * will be added to the layout tree branch. + * @see clone_tree_from_sequence() + **/ void add_branch(TrackTree::iterator_base parent_iterator, boost::shared_ptr parent); - - /** - * Recursively lays out all the controls in the header widget. - - * /!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! [in,out] - * - * - * * @param track The parent track object which will be recursed into. - * @param offset A shared value used to accumulate the y-offset of - * header widgets. - * @param header_width The width of this widget in pixels. - * !!!!!!!!!!! indent_width - * @param depth The depth within the tree of track. + * Recursively calculates the boxes for a given branch in the timeline + * tree. + * @param[in] parent_iterator The iterator of the parent of the branch + * whose boxes will be laid out. + * @param[in,out] offset The accumulating y-offset value in pixels. + * This value should be set to 0 on the first call, and will + * susequently accumulate the offset of each box. + * @param[in] header_width The width of the header container widget in + * pixels + * @param[in] depth The depth within the tree of tracks. depth = 0 for + * root tracks. + * @param[in] parent_expanded This value is set to true if all of the + * ancestors of this track, up to the root are expanded and visible, + * false if any of them are collapsed. + * @see update_layout() **/ void layout_headers_recursive( TrackTree::iterator_base parent_iterator, @@ -116,19 +187,31 @@ protected: protected: + /** + * The owner timeline widget as provided to the constructor. + **/ TimelineWidget &timelineWidget; + /** + * The layout tree. + **/ TrackTree layoutTree; /** * A map of tracks to the rectangles of their headers. * @remarks This map is used as a cache, so that the rectangles don't * need to be perpetually recalculated. This cache is regenerated by - * the layout_headers method. + * the update_layout method. + * @see update_layout() **/ std::map, Gdk::Rectangle> headerBoxes; - + + /** + * The total height of the track tree layout in pixels. This value + * is only valid after layout_headers has been called. + * @see update_layout() + **/ int totalHeight; }; From bf0cfc295ea521118922970abc266872cade5984 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 16:15:42 +0000 Subject: [PATCH 36/68] Transitioned TimelineHeaderContainer to having a reference to TimelineWidget, not a pointer --- src/gui/widgets/timeline-widget.cpp | 2 +- .../timeline/timeline-header-container.cpp | 32 +++++++------------ .../timeline/timeline-header-container.hpp | 4 +-- 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 91cf58b01..4f1fac3eb 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -60,7 +60,7 @@ TimelineWidget::TimelineWidget( body = new TimelineBody(this); ENSURE(body != NULL); - headerContainer = new TimelineHeaderContainer(this); + headerContainer = new TimelineHeaderContainer(*this); ENSURE(headerContainer != NULL); ruler = new TimelineRuler(this); ENSURE(ruler != NULL); diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index 41f9bed0e..7aca6e240 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -37,14 +37,12 @@ namespace widgets { namespace timeline { TimelineHeaderContainer::TimelineHeaderContainer( - gui::widgets::TimelineWidget *timeline_widget) : + gui::widgets::TimelineWidget &timeline_widget) : Glib::ObjectBase("TimelineHeaderContainer"), timelineWidget(timeline_widget), margin(-1), expand_button_size(12) { - REQUIRE(timeline_widget != NULL); - // This widget will not have a window at first set_flags(Gtk::NO_WINDOW); @@ -52,12 +50,12 @@ TimelineHeaderContainer::TimelineHeaderContainer( // Connect to the timeline widget's vertical scroll event, // so that we get notified when the view shifts - timelineWidget->verticalAdjustment.signal_value_changed().connect( + timelineWidget.verticalAdjustment.signal_value_changed().connect( sigc::mem_fun(this, &TimelineHeaderContainer::on_scroll) ); // Connect to the timeline widget's hover event, // so that we get notified when tracks are hovered on - timelineWidget->hovering_track_changed_signal().connect( + timelineWidget.hovering_track_changed_signal().connect( sigc::mem_fun(this, &TimelineHeaderContainer::on_hovering_track_changed) ); @@ -138,7 +136,6 @@ TimelineHeaderContainer::on_unrealize() bool TimelineHeaderContainer::on_button_press_event ( GdkEventButton* event) { - REQUIRE(timelineWidget != NULL); REQUIRE(event != NULL); switch(event->button) @@ -157,7 +154,7 @@ bool TimelineHeaderContainer::on_button_press_event ( { // Popup the context menu shared_ptr header( - timelineWidget->layoutHelper.header_from_point( + timelineWidget.layoutHelper.header_from_point( Gdk::Point(event->x, event->y))); // Are we hovering on a header? @@ -189,7 +186,7 @@ bool TimelineHeaderContainer::on_button_release_event ( clickedExpander->set_expanded(!clickedExpander->get_expanded()); clickedExpander.reset(); - timelineWidget->layoutHelper.update_layout(); + timelineWidget.layoutHelper.update_layout(); } return Container::on_button_release_event(event); @@ -309,7 +306,6 @@ TimelineHeaderContainer::on_hovering_track_changed( void TimelineHeaderContainer::layout_headers() { - REQUIRE(timelineWidget != NULL); REQUIRE(margin >= 0); // read_styles must have been called before now // We can't layout before the widget has been set up @@ -317,7 +313,7 @@ TimelineHeaderContainer::layout_headers() return; TimelineLayoutHelper &layout_helper = - timelineWidget->layoutHelper; + timelineWidget.layoutHelper; const TimelineLayoutHelper::TrackTree &layout_tree = layout_helper.get_layout_tree(); @@ -417,7 +413,6 @@ TimelineHeaderContainer::draw_header_decoration( shared_ptr model_track, const Gdk::Rectangle &clip_rect) { - REQUIRE(timelineWidget != NULL); REQUIRE(model_track != NULL); REQUIRE(clip_rect.get_width() > 0); REQUIRE(clip_rect.get_height() > 0); @@ -430,7 +425,7 @@ TimelineHeaderContainer::draw_header_decoration( // Get the header box const optional &optional_box = - timelineWidget->layoutHelper.get_track_header_rect(timeline_track); + timelineWidget.layoutHelper.get_track_header_rect(timeline_track); REQUIRE(optional_box); const Gdk::Rectangle box = *optional_box; @@ -480,7 +475,7 @@ TimelineHeaderContainer::expander_button_from_point( const Gdk::Point &point) { const TimelineLayoutHelper::TrackTree &layout_tree = - timelineWidget->layoutHelper.get_layout_tree(); + timelineWidget.layoutHelper.get_layout_tree(); TimelineLayoutHelper::TrackTree::pre_order_iterator iterator; for(iterator = ++layout_tree.begin(); // ++ so we skip the sequence root @@ -511,11 +506,10 @@ const optional TimelineHeaderContainer::get_expander_button_rectangle( shared_ptr track) { - REQUIRE(timelineWidget != NULL); REQUIRE(track != NULL); optional box = - timelineWidget->layoutHelper.get_track_header_rect(track); + timelineWidget.layoutHelper.get_track_header_rect(track); if(box) { return optional(Gdk::Rectangle( @@ -531,10 +525,9 @@ TimelineHeaderContainer::lookup_timeline_track( shared_ptr model_track) { REQUIRE(model_track != NULL); - REQUIRE(timelineWidget != NULL); shared_ptr timeline_track = - timelineWidget->lookup_timeline_track(model_track); + timelineWidget.lookup_timeline_track(model_track); ENSURE(timeline_track); return timeline_track; @@ -543,9 +536,8 @@ TimelineHeaderContainer::lookup_timeline_track( const std::list< boost::shared_ptr > TimelineHeaderContainer::get_tracks() const { - REQUIRE(timelineWidget != NULL); - REQUIRE(timelineWidget->sequence); - return timelineWidget->sequence->get_child_tracks(); + [.sequence); + return timelineWidget.sequence->get_child_tracks(); } void diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index 195fe7840..cdf472b06 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -57,7 +57,7 @@ public: * * @param[in] timeline_widget A pointer to the owner timeline widget */ - TimelineHeaderContainer(gui::widgets::TimelineWidget* timeline_widget); + TimelineHeaderContainer(gui::widgets::TimelineWidget &timeline_widget); /** * Attaches the header all the header widgets of root @@ -246,7 +246,7 @@ private: /** * The owner TimelineWidget of which this class is a helper */ - gui::widgets::TimelineWidget* const timelineWidget; + gui::widgets::TimelineWidget &timelineWidget; /** * The widget's window object. From fa60ea76dd5e9a08c1f704f60ab8d6377972c8e1 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 16:17:10 +0000 Subject: [PATCH 37/68] Small correction to timeline-header-container.hpp --- src/gui/widgets/timeline/timeline-header-container.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index cdf472b06..f6b448958 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -55,9 +55,10 @@ public: /** * Constructor * - * @param[in] timeline_widget A pointer to the owner timeline widget + * @param[in] timeline_widget A reference to the owner timeline widget */ - TimelineHeaderContainer(gui::widgets::TimelineWidget &timeline_widget); + TimelineHeaderContainer( + gui::widgets::TimelineWidget &timeline_widget); /** * Attaches the header all the header widgets of root From 9581fc6779350de1955e47cc7f94482f2b2e2733 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 16:18:29 +0000 Subject: [PATCH 38/68] Corrected a small mistake in timeline-header-container.cpp --- src/gui/widgets/timeline/timeline-header-container.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index 7aca6e240..61669394b 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -536,7 +536,7 @@ TimelineHeaderContainer::lookup_timeline_track( const std::list< boost::shared_ptr > TimelineHeaderContainer::get_tracks() const { - [.sequence); + REQUIRE(timelineWidget.sequence); return timelineWidget.sequence->get_child_tracks(); } From 6bfef606a0ec2281583bfe72d57e8e0d867ced3a Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 16:21:52 +0000 Subject: [PATCH 39/68] Transition TimelineRuler to have a reference to TimelineWidget not a pointer --- src/gui/widgets/timeline-widget.cpp | 2 +- src/gui/widgets/timeline/timeline-ruler.cpp | 47 ++++++++------------- src/gui/widgets/timeline/timeline-ruler.hpp | 7 +-- 3 files changed, 23 insertions(+), 33 deletions(-) diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 4f1fac3eb..a71e94b7a 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -62,7 +62,7 @@ TimelineWidget::TimelineWidget( ENSURE(body != NULL); headerContainer = new TimelineHeaderContainer(*this); ENSURE(headerContainer != NULL); - ruler = new TimelineRuler(this); + ruler = new TimelineRuler(*this); ENSURE(ruler != NULL); horizontalAdjustment.signal_value_changed().connect( sigc::mem_fun( diff --git a/src/gui/widgets/timeline/timeline-ruler.cpp b/src/gui/widgets/timeline/timeline-ruler.cpp index e2b826955..47b47ecef 100644 --- a/src/gui/widgets/timeline/timeline-ruler.cpp +++ b/src/gui/widgets/timeline/timeline-ruler.cpp @@ -42,7 +42,7 @@ namespace widgets { namespace timeline { TimelineRuler::TimelineRuler( - gui::widgets::TimelineWidget *timeline_widget) : + gui::widgets::TimelineWidget &timeline_widget) : Glib::ObjectBase("TimelineRuler"), isDragging(false), pinnedDragTime(0), @@ -61,11 +61,9 @@ TimelineRuler::TimelineRuler( playbackPeriodArrowSize(10), playbackPeriodArrowStemSize(3), timelineWidget(timeline_widget) -{ - REQUIRE(timelineWidget != NULL); - +{ // Connect event handlers - timelineWidget->get_view_window().changed_signal().connect( + timelineWidget.get_view_window().changed_signal().connect( sigc::mem_fun(this, &TimelineRuler::on_update_view) ); // Install style properties @@ -157,7 +155,7 @@ TimelineRuler::on_button_press_event(GdkEventButton* event) if(event->button == 1) { pinnedDragTime = - timelineWidget->get_view_window().x_to_time(event->x); + timelineWidget.get_view_window().x_to_time(event->x); isDragging = true; } @@ -168,12 +166,11 @@ bool TimelineRuler::on_button_release_event(GdkEventButton* event) { REQUIRE(event != NULL); - REQUIRE(timelineWidget != NULL); if(event->button == 1) { isDragging = false; - timelineWidget->on_playback_period_drag_released(); + timelineWidget.on_playback_period_drag_released(); } return true; @@ -214,14 +211,12 @@ TimelineRuler::on_size_allocate(Gtk::Allocation& allocation) void TimelineRuler::set_leading_x(const int x) { - REQUIRE(timelineWidget != NULL); - const gavl_time_t time = - timelineWidget->get_view_window().x_to_time(x); + timelineWidget.get_view_window().x_to_time(x); if(time > pinnedDragTime) - timelineWidget->set_playback_period(pinnedDragTime, time); + timelineWidget.set_playback_period(pinnedDragTime, time); else - timelineWidget->set_playback_period(time, pinnedDragTime); + timelineWidget.set_playback_period(time, pinnedDragTime); } void @@ -231,9 +226,8 @@ TimelineRuler::draw_ruler(Cairo::RefPtr cr, REQUIRE(cr); REQUIRE(ruler_rect.get_width() > 0); REQUIRE(ruler_rect.get_height() > 0); - REQUIRE(timelineWidget != NULL); - const TimelineViewWindow &window = timelineWidget->get_view_window(); + const TimelineViewWindow &window = timelineWidget.get_view_window(); const gavl_time_t left_offset = window.get_time_offset(); const int64_t time_scale = window.get_time_scale(); @@ -334,15 +328,14 @@ TimelineRuler::draw_selection(Cairo::RefPtr cr, REQUIRE(cr); REQUIRE(ruler_rect.get_width() > 0); REQUIRE(ruler_rect.get_height() > 0); - REQUIRE(timelineWidget != NULL); - const TimelineViewWindow &window = timelineWidget->get_view_window(); + const TimelineViewWindow &window = timelineWidget.get_view_window(); Glib::RefPtr