From a1709c74c6ea1b6effe4edfebab145a495195b38 Mon Sep 17 00:00:00 2001 From: Valeriy Kamyshniy Date: Mon, 14 Apr 2014 12:37:20 -0500 Subject: [PATCH] Adding XML scripting to ArdourCanvas [git-p4: depot-paths = "//Abdaw/dev_main/tracks/": change = 452743] --- gtk2_ardour/waves_dialog.cc | 4 +- gtk2_ardour/waves_dialog.h | 3 + gtk2_ardour/waves_ui.cc | 118 ++++------------ gtk2_ardour/waves_ui.h | 21 ++- libs/canvas/canvas.cc | 32 ++++- libs/canvas/canvas/canvas.h | 6 +- libs/canvas/canvas/fill.h | 2 + libs/canvas/canvas/group.h | 4 + libs/canvas/canvas/item.h | 5 +- libs/canvas/canvas/outline.h | 1 + libs/canvas/canvas/pixbuf.h | 3 + libs/canvas/canvas/rectangle.h | 1 + libs/canvas/canvas/text.h | 4 +- libs/canvas/canvas/types.h | 7 + libs/canvas/canvas/xml_ui.h | 64 +++++++++ libs/canvas/fill.cc | 9 ++ libs/canvas/group.cc | 10 ++ libs/canvas/item.cc | 28 +++- libs/canvas/outline.cc | 10 ++ libs/canvas/pixbuf.cc | 53 +++++++- libs/canvas/rectangle.cc | 12 ++ libs/canvas/text.cc | 14 ++ libs/canvas/wscript | 3 +- libs/canvas/xml_ui.cc | 242 +++++++++++++++++++++++++++++++++ 24 files changed, 534 insertions(+), 122 deletions(-) create mode 100644 libs/canvas/canvas/xml_ui.h create mode 100644 libs/canvas/xml_ui.cc diff --git a/gtk2_ardour/waves_dialog.cc b/gtk2_ardour/waves_dialog.cc index 3562f3f6ff..b60aac25e5 100644 --- a/gtk2_ardour/waves_dialog.cc +++ b/gtk2_ardour/waves_dialog.cc @@ -173,9 +173,9 @@ WavesDialog::read_layout (std::string file_name) return false; } - std::string title = WavesUI::xml_property (*root, "title", WavesUI::XMLNodeMap(), ""); + std::string title = xml_property (*root, "title", ""); set_title(title); - bool resizeable = WavesUI::xml_property (*root, "resizeable", WavesUI::XMLNodeMap(), false); + bool resizeable = xml_property (*root, "resizeable", false); property_allow_grow().set_value(resizeable); set_border_width(0); diff --git a/gtk2_ardour/waves_dialog.h b/gtk2_ardour/waves_dialog.h index 814a5773da..eea021d8dd 100644 --- a/gtk2_ardour/waves_dialog.h +++ b/gtk2_ardour/waves_dialog.h @@ -23,6 +23,9 @@ #include #include "ardour/session_handle.h" +#include "canvas/xml_ui.h" + +using namespace ArdourCanvas::XMLUI; namespace WM { class ProxyTemporary; diff --git a/gtk2_ardour/waves_ui.cc b/gtk2_ardour/waves_ui.cc index 13368e7d06..8896dd7c53 100644 --- a/gtk2_ardour/waves_ui.cc +++ b/gtk2_ardour/waves_ui.cc @@ -17,159 +17,87 @@ */ #include "waves_ui.h" +#include "canvas/canvas.h" +#include "waves_button.h" //std::ofstream dbg_out("/users/WavesUILog.txt"); -void -WavesUI::get_styles(const XMLTree& layout, WavesUI::XMLNodeMap &styles) -{ - XMLNode* root = layout.root(); - if (root != NULL) { - - for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i) { - if ( !strcasecmp((*i)->name().c_str(), "style")) { - std::string style_name = ((*i)->property("name") ? (*i)->property("name")->value() : std::string("")); - if (!style_name.empty()) { - styles[style_name] = *i; - } - } - } - } -} - -double -WavesUI::xml_property (const XMLNode &node, const char *prop_name, const XMLNodeMap& styles, double default_value) -{ - std::string property = xml_property(node, prop_name, styles, ""); - if (property.empty()) { - return default_value; - } - return atof(property.c_str()); -} - -int -WavesUI::xml_property (const XMLNode &node, const char *prop_name, const XMLNodeMap& styles, int default_value) -{ - std::string property = xml_property(node, prop_name, styles, ""); - if (property.empty()) { - return default_value; - } - - return atoi(property.c_str()); -} - -bool -WavesUI::xml_property (const XMLNode &node, const char *prop_name, const XMLNodeMap& styles, bool default_value) -{ - std::string property = xml_property(node, prop_name, styles, ""); - if (property.empty()) { - return default_value; - } - std::transform(property.begin(), property.end(), property.begin(), ::toupper); - return property == "TRUE"; -} - -std::string -WavesUI::xml_property (const XMLNode &node, const char *prop_name, const XMLNodeMap& styles, const std::string default_value) -{ - std::string property = node.property (prop_name) ? node.property(prop_name)->value() : ""; - if (property.empty()) { - std::string style_name = node.property ("style") ? node.property("style")->value() : ""; - if (!style_name.empty()) { - XMLNodeMap::const_iterator style = styles.find(style_name); - if (style != styles.end()) { - return WavesUI::xml_property (*style->second, prop_name, styles, default_value); - } - } - } - - - if (property.empty()) { - return default_value; - } - return property; -} - -std::string -WavesUI::xml_property (const XMLNode& node, const char* prop_name, const XMLNodeMap& styles, const char* default_value) -{ - return xml_property (node, prop_name, styles, std::string(default_value)); -} - Gtk::Widget* WavesUI::create_widget (const XMLNode& definition, const XMLNodeMap& styles, std::map &named_widgets) { Gtk::Widget* child = NULL; std::string widget_type = definition.name(); - std::string widget_id = WavesUI::xml_property (definition, "id", styles, ""); + std::string widget_id = xml_property (definition, "id", styles, ""); - std::string text = WavesUI::xml_property (definition, "text", styles, ""); + std::string text = xml_property (definition, "text", styles, ""); boost::replace_all(text, "\\n", "\n"); - int height = WavesUI::xml_property (definition, "height", styles, -1); - int width = WavesUI::xml_property (definition, "width", styles, -1); - std::transform(widget_type.begin(), widget_type.end(), widget_type.begin(), ::toupper); if (widget_type == "BUTTON") { child = manage (new WavesButton(text)); - ((WavesButton*)child)->set_border_width (WavesUI::xml_property (definition, "borderwidth", styles, "0").c_str()); - ((WavesButton*)child)->set_border_color (WavesUI::xml_property (definition, "bordercolor", styles, "#000000").c_str()); + ((WavesButton*)child)->set_border_width (xml_property (definition, "borderwidth", styles, "0").c_str()); + ((WavesButton*)child)->set_border_color (xml_property (definition, "bordercolor", styles, "#000000").c_str()); } else if (widget_type == "COMBOBOXTEXT") { child = manage (new Gtk::ComboBoxText); } else if (widget_type == "LABEL") { child = manage (new Gtk::Label(text)); } else if (widget_type == "LAYOUT") { child = manage (new Gtk::Layout); + } else if (widget_type == "CANVAS") { + std::map named_items; + child = new ArdourCanvas::GtkCanvas(definition, styles, named_items); } if (child != NULL) { + int height = xml_property (definition, "height", styles, -1); + int width = xml_property (definition, "width", styles, -1); child->set_size_request (width, height); if (!widget_id.empty()) { named_widgets[widget_id] = child; } - std::string property = WavesUI::xml_property (definition, "bgnormal", styles, ""); + std::string property = xml_property (definition, "bgnormal", styles, ""); if (!property.empty()) { child->modify_bg(Gtk::STATE_NORMAL, Gdk::Color(property)); } - property = WavesUI::xml_property (definition, "bgdisabled", styles, property); + property = xml_property (definition, "bgdisabled", styles, property); if (!property.empty()) { child->modify_bg(Gtk::STATE_INSENSITIVE, Gdk::Color(property)); } - property = WavesUI::xml_property (definition, "bgactive", styles, ""); + property = xml_property (definition, "bgactive", styles, ""); if (!property.empty()) { child->modify_bg(Gtk::STATE_ACTIVE, Gdk::Color(property)); } - property = WavesUI::xml_property (definition, "bghover", styles, ""); + property = xml_property (definition, "bghover", styles, ""); if (!property.empty()) { child->modify_bg(Gtk::STATE_PRELIGHT, Gdk::Color(property)); } - property = WavesUI::xml_property (definition, "fgnormal", styles, ""); + property = xml_property (definition, "fgnormal", styles, ""); if (!property.empty()) { child->modify_fg(Gtk::STATE_NORMAL, Gdk::Color(property)); } - property = WavesUI::xml_property (definition, "fgdisabled", styles, property); + property = xml_property (definition, "fgdisabled", styles, property); if (!property.empty()) { child->modify_fg(Gtk::STATE_INSENSITIVE, Gdk::Color(property)); } - property = WavesUI::xml_property (definition, "fgactive", styles, ""); + property = xml_property (definition, "fgactive", styles, ""); if (!property.empty()) { child->modify_fg(Gtk::STATE_ACTIVE, Gdk::Color(property)); } - property = WavesUI::xml_property (definition, "fghover", styles, ""); + property = xml_property (definition, "fghover", styles, ""); if (!property.empty()) { child->modify_fg(Gtk::STATE_PRELIGHT, Gdk::Color(property)); } - property = WavesUI::xml_property (definition, "font", styles, ""); + property = xml_property (definition, "font", styles, ""); if (!property.empty()) { child->modify_font(Pango::FontDescription(property)); } @@ -199,8 +127,8 @@ WavesUI::add_widget (Gtk::Layout& parent, const XMLNode& definition, const XMLNo if (child != NULL) { parent.put (*child, - WavesUI::xml_property (definition, "x", styles, 0), - WavesUI::xml_property (definition, "y", styles, 0)); + xml_property (definition, "x", styles, 0), + xml_property (definition, "y", styles, 0)); } return child; } @@ -235,7 +163,7 @@ void WavesUI::create_ui (const XMLTree& layout, Gtk::Widget& root, std::map &named_widgets) { XMLNodeMap styles; - WavesUI::get_styles(layout, styles); + get_styles(layout, styles); const XMLNodeList& definition = layout.root()->children(); WavesUI::create_ui (definition, styles, root, named_widgets); } \ No newline at end of file diff --git a/gtk2_ardour/waves_ui.h b/gtk2_ardour/waves_ui.h index 8c42356b04..e691eec7cf 100644 --- a/gtk2_ardour/waves_ui.h +++ b/gtk2_ardour/waves_ui.h @@ -17,27 +17,20 @@ */ +#ifndef __WAVES_UI_H__ +#define __WAVES_UI_H__ + #include #include #include #include "gtkmm/box.h" #include "gtkmm/layout.h" #include "gtkmm/label.h" -#include "pbd/xml++.h" -#include "waves_button.h" +#include "canvas/xml_ui.h" +using namespace ArdourCanvas::XMLUI; namespace WavesUI { - typedef std::map XMLNodeMap; - - void get_styles(const XMLTree& layout, WavesUI::XMLNodeMap &styles); - - double xml_property (const XMLNode& node, const char* prop_name, const XMLNodeMap& styles, double default_value); - int xml_property (const XMLNode& node, const char* prop_name, const XMLNodeMap& styles, int default_value); - bool xml_property (const XMLNode& node, const char* prop_name, const XMLNodeMap& styles, bool default_value); - std::string xml_property (const XMLNode& node, const char* prop_name, const XMLNodeMap& styles, const std::string default_value); - std::string xml_property (const XMLNode& node, const char* prop_name, const XMLNodeMap& styles, const char* default_value); - void create_ui (const XMLTree& layout, Gtk::Widget& root, std::map &named_widgets); void create_ui (const XMLNodeList& definition, const XMLNodeMap& styles, Gtk::Widget& root, std::map &named_widgets); Gtk::Widget* create_widget (const XMLNode& definition, const XMLNodeMap& styles, std::map &named_widgets); @@ -45,4 +38,6 @@ namespace WavesUI { Gtk::Widget* add_widget (Gtk::Layout& parent, const XMLNode &definition, const XMLNodeMap& styles, std::map &named_widgets); Gtk::Widget* add_widget (Gtk::Widget& parent, const XMLNode &definition, const XMLNodeMap& styles, std::map &named_widgets); -} \ No newline at end of file +} + +#endif //__WAVES_UI_H__ \ No newline at end of file diff --git a/libs/canvas/canvas.cc b/libs/canvas/canvas.cc index d5d8562361..93068789b2 100644 --- a/libs/canvas/canvas.cc +++ b/libs/canvas/canvas.cc @@ -46,6 +46,18 @@ Canvas::Canvas () set_epoch (); } +Canvas::Canvas (const XMLNode& definition, const XMLNodeMap& styles, std::map& named_items) + : _root (this) + , _scroll_offset_x (0) + , _scroll_offset_y (0) +{ + set_epoch (); + const XMLNodeList& children = definition.children(); + for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) { + XMLUI::create_item (root(), **i, styles, named_items); + } +} + void Canvas::scroll_to (Coord x, Coord y) { @@ -278,6 +290,19 @@ GtkCanvas::GtkCanvas () Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); } +GtkCanvas::GtkCanvas (const XMLNode& definition, const XMLNodeMap& styles, std::map& named_items) + : Canvas(definition, styles, named_items) + , _current_item (0) + , _new_current_item (0) + , _grabbed_item (0) + , _focused_item (0) +{ + /* these are the events we want to know about */ + add_events (Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK | + Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); +} + + void GtkCanvas::pick_current_item (int state) { @@ -752,8 +777,11 @@ GtkCanvas::request_size (Duple size) if (req.y > INT_MAX) { req.y = INT_MAX; } - - set_size_request (req.x, req.y); + int applied_width; + int applied_height; + get_size_request(applied_width, applied_height); + set_size_request (applied_width == -1 ? req.x : applied_width, + applied_height == -1 ? req.y : applied_height ); } /** `Grab' an item, so that all events are sent to that item until it is `ungrabbed'. diff --git a/libs/canvas/canvas/canvas.h b/libs/canvas/canvas/canvas.h index 616336409d..9cfb5b3246 100644 --- a/libs/canvas/canvas/canvas.h +++ b/libs/canvas/canvas/canvas.h @@ -38,9 +38,11 @@ #include "canvas/root_group.h" +#include "canvas/xml_ui.h" + namespace ArdourCanvas { - +using namespace XMLUI; class Rect; class Group; @@ -58,6 +60,7 @@ class LIBCANVAS_API Canvas { public: Canvas (); + Canvas (const XMLNode&, const XMLNodeMap&, std::map&); virtual ~Canvas () {} /** called to request a redraw of an area of the canvas */ @@ -134,6 +137,7 @@ class LIBCANVAS_API GtkCanvas : public Canvas, public Gtk::EventBox { public: GtkCanvas (); + GtkCanvas (const XMLNode&, const XMLNodeMap&, std::map&); void request_redraw (Rect const &); void request_size (Duple); diff --git a/libs/canvas/canvas/fill.h b/libs/canvas/canvas/fill.h index 56044de4bd..3e083ed366 100644 --- a/libs/canvas/canvas/fill.h +++ b/libs/canvas/canvas/fill.h @@ -27,11 +27,13 @@ #include "canvas/item.h" namespace ArdourCanvas { +using namespace XMLUI; class LIBCANVAS_API Fill : virtual public Item { public: Fill (Group *); + Fill (Group *, const XMLNode&, const XMLNodeMap&, std::map&); virtual void set_fill_color (Color); virtual void set_fill (bool); diff --git a/libs/canvas/canvas/group.h b/libs/canvas/canvas/group.h index 94aabfded6..11873edc46 100644 --- a/libs/canvas/canvas/group.h +++ b/libs/canvas/canvas/group.h @@ -28,13 +28,17 @@ #include "canvas/types.h" #include "canvas/lookup_table.h" +#include "canvas/xml_ui.h" + namespace ArdourCanvas { +using namespace XMLUI; class LIBCANVAS_API Group : public Item { public: explicit Group (Group *); explicit Group (Group *, Duple); + explicit Group (Group *, const XMLNode&, const XMLNodeMap&, std::map&); ~Group (); void render (Rect const &, Cairo::RefPtr) const; diff --git a/libs/canvas/canvas/item.h b/libs/canvas/canvas/item.h index da061f5bfc..e8f3c23ebd 100644 --- a/libs/canvas/canvas/item.h +++ b/libs/canvas/canvas/item.h @@ -30,9 +30,11 @@ #include "canvas/visibility.h" #include "canvas/types.h" +#include "canvas/xml_ui.h" namespace ArdourCanvas { +using namespace XMLUI; class Canvas; class Group; @@ -48,12 +50,13 @@ class Rect; * 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 *, const XMLNode&, const XMLNodeMap&, std::map&); Item (Group *, Duple); virtual ~Item (); diff --git a/libs/canvas/canvas/outline.h b/libs/canvas/canvas/outline.h index 972c07b11c..c75d635141 100644 --- a/libs/canvas/canvas/outline.h +++ b/libs/canvas/canvas/outline.h @@ -32,6 +32,7 @@ class LIBCANVAS_API Outline : virtual public Item { public: Outline (Group *); + Outline (Group *, const XMLNode&, const XMLNodeMap&, std::map&); virtual ~Outline () {} Color outline_color () const { diff --git a/libs/canvas/canvas/pixbuf.h b/libs/canvas/canvas/pixbuf.h index 3974b560a9..43c3ad790c 100644 --- a/libs/canvas/canvas/pixbuf.h +++ b/libs/canvas/canvas/pixbuf.h @@ -24,17 +24,20 @@ #include "canvas/visibility.h" #include "canvas/item.h" +#include "canvas/xml_ui.h" namespace Gdk { class Pixbuf; } namespace ArdourCanvas { +using namespace XMLUI; class LIBCANVAS_API Pixbuf : public Item { public: Pixbuf (Group *); + Pixbuf (Group *, const XMLNode&, const XMLNodeMap&, std::map&); void render (Rect const &, Cairo::RefPtr) const; void compute_bounding_box () const; diff --git a/libs/canvas/canvas/rectangle.h b/libs/canvas/canvas/rectangle.h index 91f23f9336..2ab703a36f 100644 --- a/libs/canvas/canvas/rectangle.h +++ b/libs/canvas/canvas/rectangle.h @@ -33,6 +33,7 @@ class LIBCANVAS_API Rectangle : virtual public Item, public Outline, public Fill { public: Rectangle (Group *); + Rectangle (Group *, const XMLNode&, const XMLNodeMap&, std::map&); Rectangle (Group *, Rect const &); void render (Rect const &, Cairo::RefPtr) const; diff --git a/libs/canvas/canvas/text.h b/libs/canvas/canvas/text.h index 59d2007ceb..7543477e97 100644 --- a/libs/canvas/canvas/text.h +++ b/libs/canvas/canvas/text.h @@ -27,12 +27,14 @@ #include "canvas/item.h" namespace ArdourCanvas { +using namespace XMLUI; class LIBCANVAS_API Text : public Item { public: Text (Group *); - ~Text(); + Text (Group *, const XMLNode&, const XMLNodeMap&, std::map&); + ~Text(); void render (Rect const &, Cairo::RefPtr) const; void compute_bounding_box () const; diff --git a/libs/canvas/canvas/types.h b/libs/canvas/canvas/types.h index 2800ccc91b..f176a4f6d5 100644 --- a/libs/canvas/canvas/types.h +++ b/libs/canvas/canvas/types.h @@ -85,6 +85,13 @@ struct LIBCANVAS_API Rect , y1 (y1_) {} + Rect (const Duple& p0, const Duple &p1) + : x0 (p0.x) + , y0 (p0.y) + , x1 (p1.x) + , y1 (p1.y) + {} + Coord x0; Coord y0; Coord x1; diff --git a/libs/canvas/canvas/xml_ui.h b/libs/canvas/canvas/xml_ui.h new file mode 100644 index 0000000000..54281b03eb --- /dev/null +++ b/libs/canvas/canvas/xml_ui.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2014 Valeriy Kamyshniy + + 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_XML_UI_H__ +#define __CANVAS_XML_UI_H__ + +#include "canvas/visibility.h" +#include +#include +#include +#include +#include "pbd/xml++.h" + +namespace ArdourCanvas { + +class Item; +class Canvas; +class Group; + +namespace XMLUI { + + typedef std::map XMLNodeMap; + + extern LIBCANVAS_API void get_styles(const XMLTree& layout, XMLNodeMap &styles); + + extern LIBCANVAS_API double xml_property (const XMLNode& node, const char* prop_name, const XMLNodeMap& styles, double default_value); + extern LIBCANVAS_API double xml_property (const XMLNode& node, const char* prop_name, double default_value); + extern LIBCANVAS_API int32_t xml_property (const XMLNode& node, const char* prop_name, const XMLNodeMap& styles, int32_t default_value); + extern LIBCANVAS_API uint32_t xml_property (const XMLNode& node, const char* prop_name, const XMLNodeMap& styles, uint32_t default_value); + + extern LIBCANVAS_API bool xml_property (const XMLNode& node, const char* prop_name, const XMLNodeMap& styles, bool default_value); + extern LIBCANVAS_API bool xml_property (const XMLNode& node, const char* prop_name, bool default_value); + + extern LIBCANVAS_API std::string xml_property (const XMLNode& node, const char* prop_name, const XMLNodeMap& styles, const std::string& default_value); + extern LIBCANVAS_API std::string xml_property (const XMLNode& node, const char* prop_name, const std::string& default_value); + extern LIBCANVAS_API std::string xml_property (const XMLNode& node, const char* prop_name, const XMLNodeMap& styles, const char* default_value); + extern LIBCANVAS_API std::string xml_property (const XMLNode& node, const char* prop_name, const char* default_value); + + extern LIBCANVAS_API std::string xml_nodetype(const XMLNode& node); + extern LIBCANVAS_API std::string xml_id(const XMLNode& node); + extern LIBCANVAS_API double xml_x (const XMLNode& node, const XMLNodeMap& styles, double default_value = 0); + extern LIBCANVAS_API double xml_y (const XMLNode& node, const XMLNodeMap& styles, double default_value = 0); + extern LIBCANVAS_API Pango::Alignment xml_text_alignment (const XMLNode& node, const XMLNodeMap& styles, Pango::Alignment default_value = Pango::ALIGN_LEFT); + + extern LIBCANVAS_API ArdourCanvas::Item* create_item (Group* parent, const XMLNode& definition, const XMLNodeMap& styles, std::map &named_items); +} +} + +#endif //__CANVAS_XML_UI_H__ \ No newline at end of file diff --git a/libs/canvas/fill.cc b/libs/canvas/fill.cc index 41c616a0f9..e803d68d4c 100644 --- a/libs/canvas/fill.cc +++ b/libs/canvas/fill.cc @@ -37,6 +37,15 @@ Fill::Fill (Group* parent) } +Fill::Fill (Group* parent, const XMLNode& definition, const XMLNodeMap& styles, std::map& named_items) + : Item (parent, definition, styles, named_items) + , _fill_color (xml_property(definition, "fillcolor", styles, 0x000000ff)) + , _fill (xml_property(definition, "fill", styles, true)) + , _transparent (xml_property(definition, "transparent", styles, false)) +{ + +} + void Fill::set_fill_color (Color color) { diff --git a/libs/canvas/group.cc b/libs/canvas/group.cc index fbe252a17c..8f29aea633 100644 --- a/libs/canvas/group.cc +++ b/libs/canvas/group.cc @@ -56,6 +56,16 @@ Group::Group (Group* parent, Duple position) } +Group::Group (Group* parent, const XMLNode& definition, const XMLNodeMap& styles, std::map& named_items) + : Item (parent, definition, styles, named_items) + , _lut (0) +{ + const XMLNodeList& children = definition.children(); + for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) { + XMLUI::create_item (this, **i, styles, named_items); + } +} + Group::~Group () { clear_items (true); diff --git a/libs/canvas/item.cc b/libs/canvas/item.cc index e4e3c30546..4ecd3d01c4 100644 --- a/libs/canvas/item.cc +++ b/libs/canvas/item.cc @@ -42,14 +42,39 @@ Item::Item (Canvas* canvas) Item::Item (Group* parent) : _canvas (parent->canvas ()) , _parent (parent) + , _visible (true) + , _bounding_box_dirty (true) + , _ignore_events (false) { init (); } +Item::Item (Group* parent, const XMLNode& definition, const XMLNodeMap& styles, std::map& named_items) + : _canvas (parent->canvas ()) + , _parent (parent) + , _position(xml_x (definition, styles), + xml_y (definition, styles)) + , _visible (xml_property(definition, "visible", styles, true)) + , _bounding_box_dirty (true) + , _ignore_events (false) +{ + std::string item_id = xml_id (definition); + if (!item_id.empty()) { + named_items[item_id] = this; + } + + _position = Duple (xml_x (definition, styles), + xml_y (definition, styles)); + init (); +} + Item::Item (Group* parent, Duple position) : _canvas (parent->canvas()) , _parent (parent) , _position (position) + , _visible (true) + , _bounding_box_dirty (true) + , _ignore_events (false) { init (); } @@ -57,9 +82,6 @@ Item::Item (Group* parent, Duple position) void Item::init () { - _visible = true; - _bounding_box_dirty = true; - _ignore_events = false; if (_parent) { _parent->add (this); diff --git a/libs/canvas/outline.cc b/libs/canvas/outline.cc index be8b924df2..6b24601107 100644 --- a/libs/canvas/outline.cc +++ b/libs/canvas/outline.cc @@ -38,6 +38,16 @@ Outline::Outline (Group* parent) } +Outline::Outline (Group* parent, const XMLNode& definition, const XMLNodeMap& styles, std::map& named_items) + : Item (parent, definition, styles, named_items) + , _outline_color (xml_property(definition, "linecolor", styles, 0x000000ff)) + , _outline_width (xml_property(definition, "linewidth", styles, 1.0)) + , _outline (xml_property(definition, "contour", styles, true)) +{ + +} + + void Outline::set_outline_color (Color color) { diff --git a/libs/canvas/pixbuf.cc b/libs/canvas/pixbuf.cc index 62d9357c61..cc92994739 100644 --- a/libs/canvas/pixbuf.cc +++ b/libs/canvas/pixbuf.cc @@ -16,14 +16,23 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +//#include "gtkmm/messagedialog.h" #include #include #include "canvas/pixbuf.h" +#include "pbd/error.h" +#include "pbd/compose.h" +#include "pbd/search_path.h" +#include "pbd/file_utils.h" +#include "ardour/filesystem_paths.h" using namespace std; using namespace ArdourCanvas; +using namespace PBD; + +//#define dbg_msg(a) Gtk::MessageDialog (a, "ArdourCanvas::Pixbuf").run(); Pixbuf::Pixbuf (Group* g) : Item (g) @@ -31,10 +40,48 @@ Pixbuf::Pixbuf (Group* g) } -void -Pixbuf::render (Rect const & /*area*/, Cairo::RefPtr context) const +Pixbuf::Pixbuf (Group* g, const XMLNode& definition, const XMLNodeMap& styles, std::map& named_items) + : Item (g, definition, styles, named_items) { - Gdk::Cairo::set_source_pixbuf (context, _pixbuf, 0, 0); + std::string imagename = xml_property(definition, "file", styles, ""); + if (!imagename.empty()) + { + Searchpath spath(ARDOUR::ardour_data_search_path()); + + std::string dirname = Glib::path_get_dirname (imagename); + std::string filename = Glib::path_get_basename (imagename); + if (!dirname.empty()) { + spath.add_subdirectory_to_paths(dirname); + } + + std::string data_file_path; + + if (find_file_in_search_path (spath, filename, data_file_path)) { + try { + _pixbuf = Gdk::Pixbuf::create_from_file (data_file_path); + } catch (const Gdk::PixbufError &e) { + cerr << "Caught PixbufError: " << e.what() << endl; + } catch (...) { + cerr << string_compose ("Caught exception while loading icon named %1", imagename) << endmsg; + } + } + } +} + +void +Pixbuf::render (Rect const & area, Cairo::RefPtr context) const +{ + Rect self = item_to_window (Rect (position(), position().translate (Duple (_pixbuf->get_width(), _pixbuf->get_height())))); + boost::optional r = self.intersection (area); + + if (!r) { + return; + } + + Rect draw = r.get (); + + context->rectangle (draw.x0, draw.y0, draw.width(), draw.height()); + Gdk::Cairo::set_source_pixbuf (context, _pixbuf, draw.x0, draw.y0); context->paint (); } diff --git a/libs/canvas/rectangle.cc b/libs/canvas/rectangle.cc index 57c26874c4..aaa442f083 100644 --- a/libs/canvas/rectangle.cc +++ b/libs/canvas/rectangle.cc @@ -38,6 +38,18 @@ Rectangle::Rectangle (Group* parent) { } +Rectangle::Rectangle (Group* parent, const XMLNode& definition, const XMLNodeMap& styles, std::map& named_items) + : Item (parent, definition, styles, named_items) + , Outline (parent, definition, styles, named_items) + , Fill (parent, definition, styles, named_items) + , _outline_what ((What) (LEFT | RIGHT | TOP | BOTTOM)) +{ + //_rect.x0 = xml_property(definition, "x", styles, 0.0); + //_rect.y0 = xml_property(definition, "y", styles, 0.0); + _rect.x1 = _rect.x0 + xml_property(definition, "width", styles, 0.0); + _rect.y1 = _rect.y0 + xml_property(definition, "height", styles, 0.0); +} + Rectangle::Rectangle (Group* parent, Rect const & rect) : Item (parent) , Outline (parent) diff --git a/libs/canvas/text.cc b/libs/canvas/text.cc index 438413080a..0dd5c9ad96 100644 --- a/libs/canvas/text.cc +++ b/libs/canvas/text.cc @@ -44,6 +44,20 @@ Text::Text (Group* parent) } +Text::Text (Group* parent, const XMLNode& definition, const XMLNodeMap& styles, std::map& named_items) + : Item (parent, definition, styles, named_items) + , _color (xml_property(definition, "color", styles, 0x000000ff)) + , _font_description ((xml_property(definition, "font", styles, "") == "") ? 0 : + new Pango::FontDescription (xml_property(definition, "font", styles, ""))) + , _alignment (xml_text_alignment(definition, styles, Pango::ALIGN_LEFT)) + , _width (xml_property(definition, "width", styles, 0.0)) + , _height (xml_property(definition, "heigt", styles, 0.0)) + , _text (xml_property(definition, "text", styles, "")) + , _need_redraw (false) + , _clamped_width (COORD_MAX) +{ +} + Text::~Text () { delete _font_description; diff --git a/libs/canvas/wscript b/libs/canvas/wscript index 05add846c3..6d3fccd23b 100644 --- a/libs/canvas/wscript +++ b/libs/canvas/wscript @@ -54,7 +54,8 @@ canvas_sources = [ 'text.cc', 'types.cc', 'utils.cc', - 'wave_view.cc' + 'wave_view.cc', + 'xml_ui.cc' ] def options(opt): diff --git a/libs/canvas/xml_ui.cc b/libs/canvas/xml_ui.cc new file mode 100644 index 0000000000..a156f3cf49 --- /dev/null +++ b/libs/canvas/xml_ui.cc @@ -0,0 +1,242 @@ +/* +Copyright (C) 2014 Valeriy Kamyshniy + +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 "canvas/xml_ui.h" +#include "canvas/group.h" +#include "canvas/rectangle.h" +#include "canvas/pixbuf.h" +#include "canvas/text.h" + +//std::ofstream dbg_out("/users/WavesUILog.txt"); +namespace ArdourCanvas { +namespace XMLUI { + +void +get_styles(const XMLTree& layout, XMLNodeMap &styles) +{ + XMLNode* root = layout.root(); + if (root != NULL) { + + for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i) { + if ( !strcasecmp((*i)->name().c_str(), "style")) { + std::string style_name = ((*i)->property("name") ? (*i)->property("name")->value() : std::string("")); + if (!style_name.empty()) { + styles[style_name] = *i; + } + } + } + } +} + +double +xml_property (const XMLNode &node, const char *prop_name, const XMLNodeMap& styles, double default_value) +{ + std::string property = xml_property(node, prop_name, styles, ""); + if (property.empty()) { + return default_value; + } + return atof(property.c_str()); +} + +int32_t +xml_property (const XMLNode &node, const char *prop_name, const XMLNodeMap& styles, int32_t default_value) +{ + std::string property = xml_property(node, prop_name, styles, ""); + if (property.empty()) { + return default_value; + } + + int32_t value; + int num_of_read_values; + + const char* source = property.c_str(); + if (source[0] == '#') { + num_of_read_values = sscanf(property.c_str()+1, "%x", &value); + } else { + num_of_read_values = sscanf(property.c_str(), "%d", &value); + } + + if(num_of_read_values != 1) { + return default_value; + } + + return value; +} + +uint32_t +xml_property (const XMLNode &node, const char *prop_name, const XMLNodeMap& styles, uint32_t default_value) +{ + std::string property = xml_property(node, prop_name, styles, ""); + if (property.empty()) { + return default_value; + } + + uint32_t value; + int num_of_read_values; + + const char* source = property.c_str(); + if (source[0] == '#') { + num_of_read_values = sscanf(property.c_str()+1, "%x", &value); + } else { + num_of_read_values = sscanf(property.c_str(), "%u", &value); + } + + if(num_of_read_values != 1) { + return default_value; + } + + return value; +} + +bool +xml_property (const XMLNode &node, const char *prop_name, const XMLNodeMap& styles, bool default_value) +{ + std::string property = xml_property(node, prop_name, styles, ""); + + if (property.empty()) { + return default_value; + } + + std::transform(property.begin(), property.end(), property.begin(), ::toupper); + return property == "TRUE"; +} + +bool +xml_property (const XMLNode &node, const char *prop_name, bool default_value) +{ + std::string property = xml_property(node, prop_name, ""); + + if (property.empty()) { + return default_value; + } + + std::transform(property.begin(), property.end(), property.begin(), ::toupper); + return property == "TRUE"; +} + +std::string +xml_property (const XMLNode &node, const char *prop_name, const XMLNodeMap& styles, const std::string& default_value) +{ + if (!node.property (prop_name)) { + std::string style_name = node.property ("style") ? node.property("style")->value() : ""; + if (!style_name.empty()) { + XMLNodeMap::const_iterator style = styles.find(style_name); + if (style != styles.end()) { + return xml_property (*style->second, prop_name, styles, std::string(default_value)); + } + } + } + else + { + return node.property(prop_name)->value(); + } + return default_value; +} + +std::string +xml_property (const XMLNode &node, const char *prop_name, const std::string& default_value) +{ + return node.property (prop_name) ? node.property(prop_name)->value() : ""; +} + +std::string +xml_property (const XMLNode& node, const char* prop_name, const XMLNodeMap& styles, const char* default_value) +{ + return xml_property (node, prop_name, styles, std::string(default_value)); +} + +std::string +xml_property (const XMLNode& node, const char* prop_name, const char* default_value) +{ + return xml_property (node, prop_name, std::string(default_value)); +} + +std::string +xml_nodetype(const XMLNode& node) +{ + std::string item_type = node.name(); + std::transform(item_type.begin(), item_type.end(), item_type.begin(), ::toupper); + return item_type; +} + +std::string +xml_id(const XMLNode& node) +{ + return xml_property (node, "id", std::string("")); +} + +double xml_x (const XMLNode& node, const XMLNodeMap& styles, double default_value) +{ + return xml_property (node, "x", styles, default_value); +} + +double xml_y (const XMLNode& node, const XMLNodeMap& styles, double default_value) +{ + return xml_property (node, "y", styles, default_value); +} + +Pango::Alignment xml_text_alignment (const XMLNode& node, const XMLNodeMap& styles, Pango::Alignment default_value) +{ + std::string property = xml_property(node, "alignment", styles, ""); + + std::transform(property.begin(), property.end(), property.begin(), ::toupper); + if (property == "LEFT") { + return Pango::ALIGN_LEFT; + } else if (property == "RIGHT") { + return Pango::ALIGN_RIGHT; + } else if (property == "CENTER") { + return Pango::ALIGN_CENTER; + } + + return default_value; +} + +ArdourCanvas::Item* +create_item (Group* parent, const XMLNode& definition, const XMLNodeMap& styles, std::map& named_items) +{ + ArdourCanvas::Item* child = NULL; + std::string item_type = definition.name(); + std::transform(item_type.begin(), item_type.end(), item_type.begin(), ::toupper); + + if (item_type == "GROUP") { + child = new Group (parent, definition, styles, named_items); + } else if (item_type == "RECTANGLE") { + child = new Rectangle (parent, definition, styles, named_items); + } else if (item_type == "ICON") { + child = new Pixbuf (parent, definition, styles, named_items); + } else if (item_type == "TEXT") { + child = new Text (parent, definition, styles, named_items); + } else if (item_type == "FROMSTYLE") { + std::string style_name = xml_property (definition, "style", ""); + if (!style_name.empty()) { + XMLNodeMap::const_iterator style = styles.find(style_name); + if (style != styles.end()) { + const XMLNodeList& children = (*style->second).children(); + for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) { + create_item(parent, **i, styles, named_items); + } + } + } + } + + return child; +} + +} +} +