From 77c056266f4114cd55bd086f55ab4bbe8c5395f0 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 30 Dec 2008 22:27:09 +0000 Subject: [PATCH 01/27] 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 02/27] 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 03/27] 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 04/27] 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 05/27] 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 06/27] 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 07/27] 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 08/27] 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 09/27] 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 10/27] 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 11/27] 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 12/27] 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 13/27] 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 14/27] 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 c05f0fbbfba70481622487986dcedc50f2f89384 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 2 Jan 2009 11:39:45 +0000 Subject: [PATCH 15/27] 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 16/27] 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 17/27] 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 18/27] 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 19/27] 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 20/27] 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 21/27] 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 22/27] 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 23/27] 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 24/27] 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 25/27] 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 26/27] 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 27/27] 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; };