diff options
Diffstat (limited to 'libs/canvas/canvas/item.h')
-rw-r--r-- | libs/canvas/canvas/item.h | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/libs/canvas/canvas/item.h b/libs/canvas/canvas/item.h new file mode 100644 index 0000000000..da061f5bfc --- /dev/null +++ b/libs/canvas/canvas/item.h @@ -0,0 +1,250 @@ +/* + Copyright (C) 2011-2013 Paul Davis + Original Author: Carl Hetherington <cth@carlh.net> + + 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. +*/ + +#ifndef __CANVAS_ITEM_H__ +#define __CANVAS_ITEM_H__ + +#include <stdint.h> + +#include <gdk/gdk.h> + +#include <cairomm/context.h> + +#include "pbd/signals.h" + +#include "canvas/visibility.h" +#include "canvas/types.h" + +namespace ArdourCanvas +{ + +class Canvas; +class Group; +class Rect; + +/** The parent class for anything that goes on the canvas. + * + * Items have a position, which is expressed in the coordinates of the parent. + * They also have a bounding box, which describes the area in which they have + * drawable content, which is expressed in their own coordinates (whose origin + * is at the item position). + * + * Any item that is being displayed on a canvas has a pointer to that canvas, + * and all except the `root group' have a pointer to their parent group. + */ + +class LIBCANVAS_API Item +{ +public: + Item (Canvas *); + Item (Group *); + Item (Group *, Duple); + virtual ~Item (); + + void redraw () const; + + /** Render this item to a Cairo context. + * @param area Area to draw, in **window** coordinates + * + * Items must convert their own coordinates into window coordinates + * because Cairo is limited to a fixed point coordinate space that + * does not extend as far as the Ardour timeline. All rendering must + * be done using coordinates that do not exceed the (rough) limits + * of the canvas' window, to avoid odd errors within Cairo as it + * converts doubles into its fixed point format and then tesselates + * the results. + */ + virtual void render (Rect const & area, Cairo::RefPtr<Cairo::Context>) const = 0; + + virtual void add_items_at_point (Duple, std::vector<Item const *>& items) const { + items.push_back (this); + } + + virtual bool covers (Duple const &) const; + + /** Update _bounding_box and _bounding_box_dirty */ + virtual void compute_bounding_box () const = 0; + + void grab (); + void ungrab (); + + void unparent (); + void reparent (Group *); + + /** @return Parent group, or 0 if this is the root group */ + Group* parent () const { + return _parent; + } + + uint32_t depth() const; + const Item* closest_ancestor_with (const Item& other) const; + bool common_ancestor_within (uint32_t, const Item& other) const; + + /** returns true if this item is an ancestor of @param candidate, + * and false otherwise. + */ + bool is_ancestor_of (const Item& candidate) const { + return candidate.is_descendant_of (*this); + } + /** returns true if this Item is a descendant of @param candidate, + * and false otherwise. + */ + bool is_descendant_of (const Item& candidate) const; + + void set_position (Duple); + void set_x_position (Coord); + void set_y_position (Coord); + void move (Duple); + + /** @return Position of this item in the parent's coordinates */ + Duple position () const { + return _position; + } + + boost::optional<Rect> bounding_box () const; + Coord height() const; + Coord width() const; + + Duple item_to_parent (Duple const &) const; + Rect item_to_parent (Rect const &) const; + Duple parent_to_item (Duple const &) const; + Rect parent_to_item (Rect const &) const; + /* XXX: it's a pity these aren't the same form as item_to_parent etc., + but it makes a bit of a mess in the rest of the code if they are not. + */ + + void canvas_to_item (Coord &, Coord &) const; + Duple canvas_to_item (Duple const &) const; + void item_to_canvas (Coord &, Coord &) const; + Rect item_to_canvas (Rect const &) const; + Rect canvas_to_item (Rect const &) const; + Duple item_to_canvas (Duple const &) const; + + Duple item_to_window (Duple const&) const; + Duple window_to_item (Duple const&) const; + Rect item_to_window (Rect const&) const; + + void raise_to_top (); + void raise (int); + void lower_to_bottom (); + + void hide (); + void show (); + + /** @return true if this item is visible (ie it will be rendered), + * otherwise false + */ + bool visible () const { + return _visible; + } + + /** @return Our canvas, or 0 if we are not attached to one */ + Canvas* canvas () const { + return _canvas; + } + + void set_ignore_events (bool); + bool ignore_events () const { + return _ignore_events; + } + + void set_data (std::string const &, void *); + void* get_data (std::string const &) const; + + /* This is a sigc++ signal because it is solely + concerned with GUI stuff and is thus single-threaded + */ + + template <class T> + struct EventAccumulator { + typedef T result_type; + template <class U> + result_type operator () (U first, U last) { + while (first != last) { + if (*first) { + return true; + } + ++first; + } + return false; + } + }; + + sigc::signal1<bool, GdkEvent*, EventAccumulator<bool> > Event; + +#ifdef CANVAS_DEBUG + std::string name; +#endif + +#ifdef CANVAS_COMPATIBILITY + void grab_focus (); +#endif + + virtual void dump (std::ostream&) const; + std::string whatami() const; + +protected: + + /** To be called at the beginning of any property change that + * may alter the bounding box of this item + */ + void begin_change (); + /** To be called at the endof any property change that + * may alter the bounding box of this item + */ + void end_change (); + /** To be called at the beginning of any property change that + * does NOT alter the bounding box of this item + */ + void begin_visual_change (); + /** To be called at the endof any property change that + * does NOT alter the bounding box of this item + */ + void end_visual_change (); + + Canvas* _canvas; + /** parent group; may be 0 if we are the root group or if we have been unparent()ed */ + Group* _parent; + /** position of this item in parent coordinates */ + Duple _position; + /** true if this item is visible (ie to be drawn), otherwise false */ + bool _visible; + /** our bounding box before any change that is currently in progress */ + boost::optional<Rect> _pre_change_bounding_box; + + /** our bounding box; may be out of date if _bounding_box_dirty is true */ + mutable boost::optional<Rect> _bounding_box; + /** true if _bounding_box might be out of date, false if its definitely not */ + mutable bool _bounding_box_dirty; + + /* XXX: this is a bit grubby */ + std::map<std::string, void *> _data; + +private: + void init (); + + bool _ignore_events; +}; + +extern LIBCANVAS_API std::ostream& operator<< (std::ostream&, const ArdourCanvas::Item&); + +} + + +#endif |