diff options
Diffstat (limited to 'src/ui')
31 files changed, 4594 insertions, 41 deletions
diff --git a/src/ui/Makefile_insert b/src/ui/Makefile_insert index e91c22025..3eb6c6b13 100644 --- a/src/ui/Makefile_insert +++ b/src/ui/Makefile_insert @@ -1,9 +1,11 @@ ## Makefile.am fragment sourced by src/Makefile.am. ink_common_sources += \ - ui/clipboard.cpp \ - ui/clipboard.h \ - ui/icon-names.h \ + ui/context-menu.cpp \ + ui/context-menu.h \ + ui/clipboard.cpp \ + ui/clipboard.h \ + ui/icon-names.h \ ui/previewable.h \ ui/previewfillable.h \ ui/previewholder.cpp \ diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert index bf3b6baeb..6a9ebf61f 100644 --- a/src/ui/dialog/Makefile_insert +++ b/src/ui/dialog/Makefile_insert @@ -1,11 +1,23 @@ ## Makefile.am fragment sourced by src/Makefile.am. +if WITH_INKBOARD +inkboard_dialogs = \ + whiteboard-connect.cpp \ + whiteboard-connect.h \ + whiteboard-sharewithchat.cpp \ + whiteboard-sharewithchat.h \ + whiteboard-sharewithuser.cpp \ + whiteboard-sharewithuser.h +endif + ink_common_sources += \ ui/dialog/aboutbox.cpp \ ui/dialog/aboutbox.h \ ui/dialog/align-and-distribute.cpp \ ui/dialog/align-and-distribute.h \ ui/dialog/behavior.h \ + ui/dialog/calligraphic-profile-rename.h \ + ui/dialog/calligraphic-profile-rename.cpp \ ui/dialog/debug.cpp \ ui/dialog/debug.h \ ui/dialog/dialog.cpp \ @@ -20,6 +32,8 @@ ink_common_sources += \ ui/dialog/document-properties.h \ ui/dialog/extension-editor.cpp \ ui/dialog/extension-editor.h \ + ui/dialog/extensions.cpp \ + ui/dialog/extensions.h \ ui/dialog/filedialog.cpp \ ui/dialog/filedialog.h \ ui/dialog/filedialogimpl-gtkmm.cpp \ @@ -34,10 +48,18 @@ ink_common_sources += \ ui/dialog/find.h \ ui/dialog/floating-behavior.cpp \ ui/dialog/floating-behavior.h \ + ui/dialog/guides.cpp \ + ui/dialog/guides.h \ + ui/dialog/icon-preview.cpp \ + ui/dialog/icon-preview.h \ ui/dialog/inkscape-preferences.cpp \ ui/dialog/inkscape-preferences.h \ ui/dialog/input.cpp \ ui/dialog/input.h \ + ui/dialog/layer-properties.cpp \ + ui/dialog/layer-properties.h \ + ui/dialog/layers.cpp \ + ui/dialog/layers.h \ ui/dialog/livepatheffect-editor.cpp \ ui/dialog/livepatheffect-editor.h \ ui/dialog/memory.cpp \ @@ -53,6 +75,8 @@ ink_common_sources += \ ui/dialog/scriptdialog.h \ ui/dialog/svg-fonts-dialog.cpp \ ui/dialog/svg-fonts-dialog.h \ + ui/dialog/swatches.cpp \ + ui/dialog/swatches.h \ ui/dialog/tile.cpp \ ui/dialog/tile.h \ ui/dialog/tracedialog.cpp \ diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp index 0a59c004f..d8c4bc005 100644 --- a/src/ui/dialog/align-and-distribute.cpp +++ b/src/ui/dialog/align-and-distribute.cpp @@ -21,7 +21,7 @@ #include <gtkmm/spinbutton.h> #include "desktop-handles.h" -#include "dialogs/unclump.h" +#include "unclump.h" #include "document.h" #include "enums.h" #include "graphlayout/graphlayout.h" diff --git a/src/ui/dialog/calligraphic-profile-rename.cpp b/src/ui/dialog/calligraphic-profile-rename.cpp new file mode 100644 index 000000000..888b327f4 --- /dev/null +++ b/src/ui/dialog/calligraphic-profile-rename.cpp @@ -0,0 +1,108 @@ +/** @file + * @brief Dialog for naming calligraphic profiles + * + * @note This file is in the wrong directory because of link order issues - + * it is required by widgets/toolbox.cpp, and libspwidgets.a comes after + * libinkdialogs.a in the current link order. + */ +/* Author: + * Aubanel MONNIER + * + * Copyright (C) 2007 Authors + * Released under GNU GPL. Read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <glibmm/i18n.h> +#include <gtkmm/stock.h> + +#include "desktop.h" +#include "calligraphic-profile-rename.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + +CalligraphicProfileRename::CalligraphicProfileRename() : + _applied(false) +{ + Gtk::VBox *mainVBox = get_vbox(); + _layout_table.set_spacings(4); + _layout_table.resize (1, 2); + + _profile_name_entry.set_activates_default(true); + + _profile_name_label.set_label(_("Profile name:")); + _profile_name_label.set_alignment(1.0, 0.5); + + _layout_table.attach(_profile_name_label, + 0, 1, 0, 1, Gtk::FILL, Gtk::FILL); + _layout_table.attach(_profile_name_entry, + 1, 2, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::FILL); + mainVBox->pack_start(_layout_table, false, false, 4); + // Buttons + _close_button.set_use_stock(true); + _close_button.set_label(Gtk::Stock::CANCEL.id); + _close_button.set_flags(Gtk::CAN_DEFAULT); + + _apply_button.set_use_underline(true); + _apply_button.set_label(_("Save")); + _apply_button.set_flags(Gtk::CAN_DEFAULT); + + _close_button.signal_clicked() + .connect(sigc::mem_fun(*this, &CalligraphicProfileRename::_close)); + _apply_button.signal_clicked() + .connect(sigc::mem_fun(*this, &CalligraphicProfileRename::_apply)); + + signal_delete_event().connect( sigc::bind_return( + sigc::hide(sigc::mem_fun(*this, &CalligraphicProfileRename::_close)), true ) ); + + add_action_widget(_close_button, Gtk::RESPONSE_CLOSE); + add_action_widget(_apply_button, Gtk::RESPONSE_APPLY); + + _apply_button.grab_default(); + + show_all_children(); +} + +void CalligraphicProfileRename::_apply() +{ + _profile_name = _profile_name_entry.get_text(); + _applied = true; + _close(); +} + +void CalligraphicProfileRename::_close() +{ + this->Gtk::Dialog::hide(); +} + +void CalligraphicProfileRename::show(SPDesktop *desktop) +{ + CalligraphicProfileRename &dial = instance(); + dial._applied=false; + dial.set_modal(true); + desktop->setWindowTransient (dial.gobj()); + dial.property_destroy_with_parent() = true; + // dial.Gtk::Dialog::show(); + //dial.present(); + dial.run(); +} + +} // namespace Dialog +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/calligraphic-profile-rename.h b/src/ui/dialog/calligraphic-profile-rename.h new file mode 100644 index 000000000..53ce907ed --- /dev/null +++ b/src/ui/dialog/calligraphic-profile-rename.h @@ -0,0 +1,75 @@ +/** @file + * @brief Dialog for naming calligraphic profiles + */ +/* Author: + * Aubanel MONNIER + * + * Copyright (C) 2007 Authors + * Released under GNU GPL. Read the file 'COPYING' for more information + */ + +#ifndef INKSCAPE_DIALOG_CALLIGRAPHIC_PROFILE_H +#define INKSCAPE_DIALOG_CALLIGRAPHIC_PROFILE_H + +#include <gtkmm/dialog.h> +#include <gtkmm/entry.h> +#include <gtkmm/label.h> +#include <gtkmm/table.h> +struct SPDesktop; + +namespace Inkscape { +namespace UI { +namespace Dialog { + +class CalligraphicProfileRename : public Gtk::Dialog { +public: + CalligraphicProfileRename(); + virtual ~CalligraphicProfileRename() {} + Glib::ustring getName() const { + return "CalligraphicProfileRename"; + } + + static void show(SPDesktop *desktop); + static bool applied() { + return instance()._applied; + } + static Glib::ustring getProfileName() { + return instance()._profile_name; + } + +protected: + void _close(); + void _apply(); + + Gtk::Label _profile_name_label; + Gtk::Entry _profile_name_entry; + Gtk::Table _layout_table; + Gtk::Button _close_button; + Gtk::Button _apply_button; + Glib::ustring _profile_name; + bool _applied; +private: + static CalligraphicProfileRename &instance() { + static CalligraphicProfileRename instance_; + return instance_; + } + CalligraphicProfileRename(CalligraphicProfileRename const &); // no copy + CalligraphicProfileRename &operator=(CalligraphicProfileRename const &); // no assign +}; + +} // namespace Dialog +} // namespace UI +} // namespace Inkscape + +#endif // INKSCAPE_DIALOG_CALLIGRAPHIC_PROFILE_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp index 7a8947adf..d1b818d23 100644 --- a/src/ui/dialog/dialog-manager.cpp +++ b/src/ui/dialog/dialog-manager.cpp @@ -31,22 +31,21 @@ #include "ui/dialog/memory.h" #include "ui/dialog/messages.h" #include "ui/dialog/scriptdialog.h" -#ifdef ENABLE_SVG_FONTS -#include "ui/dialog/svg-fonts-dialog.h" -#endif // ENABLE_SVG_FONTS #include "ui/dialog/tile.h" #include "ui/dialog/tracedialog.h" #include "ui/dialog/transformation.h" #include "ui/dialog/undo-history.h" #include "ui/dialog/panel-dialog.h" - -#include "dialogs/layers-panel.h" -#include "dialogs/iconpreview.h" - +#include "ui/dialog/layers.h" +#include "ui/dialog/icon-preview.h" #include "ui/dialog/floating-behavior.h" #include "ui/dialog/dock-behavior.h" #include "preferences.h" +#ifdef ENABLE_SVG_FONTS +#include "ui/dialog/svg-fonts-dialog.h" +#endif // ENABLE_SVG_FONTS + namespace Inkscape { namespace UI { namespace Dialog { diff --git a/src/ui/dialog/document-metadata.cpp b/src/ui/dialog/document-metadata.cpp index 32838309a..96cad1fbe 100644 --- a/src/ui/dialog/document-metadata.cpp +++ b/src/ui/dialog/document-metadata.cpp @@ -17,18 +17,14 @@ # include <config.h> #endif - - -#include "ui/widget/entity-entry.h" - -#include "xml/node-event-vector.h" -#include "dialogs/rdf.h" - -#include "inkscape.h" -#include "verbs.h" -#include "desktop-handles.h" #include "desktop.h" +#include "desktop-handles.h" +#include "inkscape.h" +#include "rdf.h" #include "sp-namedview.h" +#include "ui/widget/entity-entry.h" +#include "verbs.h" +#include "xml/node-event-vector.h" #include "document-metadata.h" diff --git a/src/ui/dialog/extensions.cpp b/src/ui/dialog/extensions.cpp new file mode 100644 index 000000000..f168da33a --- /dev/null +++ b/src/ui/dialog/extensions.cpp @@ -0,0 +1,129 @@ +/** @file + * @brief A simple dialog with information about extensions + */ +/* Authors: + * Jon A. Cruz + * + * Copyright (C) 2005 Jon A. Cruz + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <gtk/gtkdialog.h> //for GTK_RESPONSE* types +#include <gtkmm/scrolledwindow.h> + +#include "extension/db.h" +#include "extensions.h" + + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +using Inkscape::Extension::Extension; + +ExtensionsPanel &ExtensionsPanel::getInstance() +{ + ExtensionsPanel &instance = *new ExtensionsPanel(); + + instance.rescan(); + + return instance; +} + + + +/** + * Constructor + */ +ExtensionsPanel::ExtensionsPanel() : + _showAll(false) +{ + Gtk::ScrolledWindow* scroller = new Gtk::ScrolledWindow(); + + _view.set_editable(false); + + scroller->add(_view); + add(*scroller); + + rescan(); + + show_all_children(); +} + +void ExtensionsPanel::set_full(bool full) +{ + if ( full != _showAll ) { + _showAll = full; + rescan(); + } +} + +void ExtensionsPanel::listCB( Inkscape::Extension::Extension * in_plug, gpointer in_data ) +{ + ExtensionsPanel * self = (ExtensionsPanel*)in_data; + + const char* stateStr; + Extension::state_t state = in_plug->get_state(); + switch ( state ) { + case Extension::STATE_LOADED: + { + stateStr = "loaded"; + } + break; + case Extension::STATE_UNLOADED: + { + stateStr = "unloaded"; + } + break; + case Extension::STATE_DEACTIVATED: + { + stateStr = "deactivated"; + } + break; + default: + stateStr = "unknown"; + } + + if ( self->_showAll || in_plug->deactivated() ) { +// gchar* line = g_strdup_printf( " extension %c %c %s |%s|%s|", +// (in_plug->loaded() ? 'X' : '-'), +// (in_plug->deactivated() ? 'X' : '-'), +// stateStr, in_plug->get_id(), +// in_plug->get_name() ); + gchar* line = g_strdup_printf( "%s %s\n \"%s\"", stateStr, in_plug->get_name(), in_plug->get_id() ); + + self->_view.get_buffer()->insert( self->_view.get_buffer()->end(), line ); + self->_view.get_buffer()->insert( self->_view.get_buffer()->end(), "\n" ); + //g_message( "%s", line ); + } + + + + return; +} + +void ExtensionsPanel::rescan() +{ + _view.get_buffer()->set_text("Extensions:\n"); +// g_message("/------------------"); + + Inkscape::Extension::db.foreach(listCB, (gpointer)this); + +// g_message("\\------------------"); +} + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/extensions.h b/src/ui/dialog/extensions.h new file mode 100644 index 000000000..8b0fc2780 --- /dev/null +++ b/src/ui/dialog/extensions.h @@ -0,0 +1,56 @@ +/** @file + * A simple dialog with information about extensions + */ +/* Authors: + * Jon A. Cruz + * + * Copyright (C) 2005 The Inkscape Organization + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_EXTENSIONS_H +#define SEEN_EXTENSIONS_H + +#include <gtkmm/textview.h> +#include "ui/widget/panel.h" + +namespace Inkscape { +namespace Extension { +class Extension; +} +} + +namespace Inkscape { +namespace UI { +namespace Dialogs { + + +/** + * A panel that displays information about extensions. + */ +class ExtensionsPanel : public Inkscape::UI::Widget::Panel +{ +public: + ExtensionsPanel(); + + static ExtensionsPanel &getInstance(); + + void set_full(bool full); + +private: + ExtensionsPanel(ExtensionsPanel const &); // no copy + ExtensionsPanel &operator=(ExtensionsPanel const &); // no assign + + static void listCB(Inkscape::Extension::Extension *in_plug, gpointer in_data); + + void rescan(); + + bool _showAll; + Gtk::TextView _view; +}; + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + +#endif // SEEN_EXTENSIONS_H diff --git a/src/ui/dialog/fill-and-stroke.cpp b/src/ui/dialog/fill-and-stroke.cpp index d28dc7955..fe63c6e24 100644 --- a/src/ui/dialog/fill-and-stroke.cpp +++ b/src/ui/dialog/fill-and-stroke.cpp @@ -21,15 +21,13 @@ #include "selection.h" #include "style.h" #include "svg/css-ostringstream.h" +#include "ui/icon-names.h" #include "verbs.h" -#include "xml/repr.h" +#include "widgets/fill-style.h" #include "widgets/icon.h" -#include "ui/icon-names.h" - -#include "dialogs/fill-style.h" -#include "dialogs/stroke-style.h" - -#include <widgets/paint-selector.h> +#include "widgets/paint-selector.h" +#include "widgets/stroke-style.h" +#include "xml/repr.h" namespace Inkscape { namespace UI { diff --git a/src/ui/dialog/guides.cpp b/src/ui/dialog/guides.cpp new file mode 100644 index 000000000..c5d2ae488 --- /dev/null +++ b/src/ui/dialog/guides.cpp @@ -0,0 +1,285 @@ +/** @file + * @brief Simple guideline dialog + */ +/* Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * Andrius R. <knutux@gmail.com> + * Johan Engelen + * + * Copyright (C) 1999-2007 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include "display/guideline.h" +#include "helper/unit-menu.h" +#include "helper/units.h" +#include "desktop.h" +#include "document.h" +#include "sp-guide.h" +#include "sp-namedview.h" +#include "desktop-handles.h" +#include "event-context.h" +#include "widgets/desktop-widget.h" +#include "sp-metrics.h" +#include <glibmm/i18n.h> +#include "dialogs/dialog-events.h" +#include "message-context.h" +#include "xml/repr.h" +#include <2geom/point.h> +#include <2geom/angle.h> +#include "guides.h" + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +GuidelinePropertiesDialog::GuidelinePropertiesDialog(SPGuide *guide, SPDesktop *desktop) +: _desktop(desktop), _guide(guide), + _label_units(_("Unit:")), + _label_X(_("X:")), + _label_Y(_("Y:")), + _label_degrees(_("Angle (degrees):")), + _relative_toggle(_("Rela_tive change"), _("Move and/or rotate the guide relative to current settings")), + _adjustment_x(0.0, -1e6, 1e6, 1.0, 10.0, 10.0), + _adjustment_y(0.0, -1e6, 1e6, 1.0, 10.0, 10.0), + _adj_angle(0.0, -360, 360, 1.0, 10.0, 10.0), + _unit_selector(NULL), _mode(true), _oldpos(0.,0.), _oldangle(0.0) +{ +} + +GuidelinePropertiesDialog::~GuidelinePropertiesDialog() { +} + +void GuidelinePropertiesDialog::showDialog(SPGuide *guide, SPDesktop *desktop) { + GuidelinePropertiesDialog dialog(guide, desktop); + dialog._setup(); + dialog.run(); +} + +void GuidelinePropertiesDialog::_modeChanged() +{ + _mode = !_relative_toggle.get_active(); + if (!_mode) { + // relative + _spin_angle.set_value(0); + + _spin_button_y.set_value(0); + _spin_button_x.set_value(0); + } else { + // absolute + _spin_angle.set_value(_oldangle); + + SPUnit const &unit = *sp_unit_selector_get_unit(SP_UNIT_SELECTOR(_unit_selector->gobj())); + gdouble const val_y = sp_pixels_get_units(_oldpos[Geom::Y], unit); + _spin_button_y.set_value(val_y); + gdouble const val_x = sp_pixels_get_units(_oldpos[Geom::X], unit); + _spin_button_x.set_value(val_x); + } +} + +void GuidelinePropertiesDialog::_onApply() +{ + double deg_angle = _spin_angle.get_value(); + if (!_mode) + deg_angle += _oldangle; + Geom::Point normal; + if ( deg_angle == 90. || deg_angle == 270. || deg_angle == -90. || deg_angle == -270.) { + normal = Geom::Point(1.,0.); + } else if ( deg_angle == 0. || deg_angle == 180. || deg_angle == -180.) { + normal = Geom::Point(0.,1.); + } else { + double rad_angle = Geom::deg_to_rad( deg_angle ); + normal = Geom::rot90(Geom::Point::polar(rad_angle, 1.0)); + } + sp_guide_set_normal(*_guide, normal, true); + + SPUnit const &unit = *sp_unit_selector_get_unit(SP_UNIT_SELECTOR(_unit_selector->gobj())); + gdouble const raw_dist_x = _spin_button_x.get_value(); + gdouble const points_x = sp_units_get_pixels(raw_dist_x, unit); + gdouble const raw_dist_y = _spin_button_y.get_value(); + gdouble const points_y = sp_units_get_pixels(raw_dist_y, unit); + Geom::Point newpos(points_x, points_y); + if (!_mode) + newpos += _oldpos; + + sp_guide_moveto(*_guide, newpos, true); + + sp_document_done(SP_OBJECT_DOCUMENT(_guide), SP_VERB_NONE, + _("Set guide properties")); +} + +void GuidelinePropertiesDialog::_onOK() +{ + _onApply(); +} + +void GuidelinePropertiesDialog::_onDelete() +{ + SPDocument *doc = SP_OBJECT_DOCUMENT(_guide); + sp_guide_remove(_guide); + sp_document_done(doc, SP_VERB_NONE, + _("Delete guide")); +} + +void GuidelinePropertiesDialog::_response(gint response) +{ + switch (response) { + case Gtk::RESPONSE_OK: + _onOK(); + break; + case -12: + _onDelete(); + break; + case Gtk::RESPONSE_CANCEL: + break; + case Gtk::RESPONSE_DELETE_EVENT: + break; +/* case GTK_RESPONSE_APPLY: + _onApply(); + break; +*/ + default: + g_assert_not_reached(); + } +} + +void GuidelinePropertiesDialog::_setup() { + set_title(_("Guideline")); + add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK); + add_button(Gtk::Stock::DELETE, -12); + add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + + Gtk::VBox *mainVBox = get_vbox(); + + _layout_table.set_spacings(4); + _layout_table.resize (3, 4); + + mainVBox->pack_start(_layout_table, false, false, 0); + + _label_name.set_label("foo0"); + _layout_table.attach(_label_name, + 0, 3, 0, 1, Gtk::FILL, Gtk::FILL); + _label_name.set_alignment(0, 0.5); + + _label_descr.set_label("foo1"); + _layout_table.attach(_label_descr, + 0, 3, 1, 2, Gtk::FILL, Gtk::FILL); + _label_descr.set_alignment(0, 0.5); + + // indent + _layout_table.attach(*manage(new Gtk::Label(" ")), + 0, 1, 2, 3, Gtk::FILL, Gtk::FILL, 10); + + // mode radio button + _layout_table.attach(_relative_toggle, + 1, 3, 9, 10, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + _relative_toggle.signal_toggled().connect(sigc::mem_fun(*this, &GuidelinePropertiesDialog::_modeChanged)); + + // unitmenu + /* fixme: We should allow percents here too, as percents of the canvas size */ + GtkWidget *unit_selector = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE); + sp_unit_selector_set_unit(SP_UNIT_SELECTOR(unit_selector), _desktop->namedview->doc_units); + _unit_selector = Gtk::manage(Glib::wrap(unit_selector)); + + // position spinbuttons + sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(unit_selector), GTK_ADJUSTMENT(_adjustment_x.gobj())); + sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(unit_selector), GTK_ADJUSTMENT(_adjustment_y.gobj())); + _spin_button_x.configure(_adjustment_x, 1.0 , 3); + _spin_button_x.set_numeric(); + _spin_button_y.configure(_adjustment_y, 1.0 , 3); + _spin_button_y.set_numeric(); + _layout_table.attach(_label_X, + 1, 2, 4, 5, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + _layout_table.attach(_spin_button_x, + 2, 3, 4, 5, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + _layout_table.attach(_label_Y, + 1, 2, 5, 6, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + _layout_table.attach(_spin_button_y, + 2, 3, 5, 6, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + gtk_signal_connect_object(GTK_OBJECT(_spin_button_x.gobj()), "activate", + GTK_SIGNAL_FUNC(gtk_window_activate_default), + gobj()); + + _layout_table.attach(_label_units, + 1, 2, 6, 7, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + _layout_table.attach(*_unit_selector, + 2, 3, 6, 7, Gtk::FILL, Gtk::FILL); + + // angle spinbutton + _spin_angle.configure(_adj_angle, 5.0 , 3); + _spin_angle.set_numeric(); + _spin_angle.show(); + _layout_table.attach(_label_degrees, + 1, 2, 8, 9, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + _layout_table.attach(_spin_angle, + 2, 3, 8, 9, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + + + // dialog + set_default_response(Gtk::RESPONSE_OK); + signal_response().connect(sigc::mem_fun(*this, &GuidelinePropertiesDialog::_response)); + + // initialize dialog + _oldpos = _guide->point_on_line; + if (_guide->is_vertical()) { + _oldangle = 90; + } else if (_guide->is_horizontal()) { + _oldangle = 0; + } else { + _oldangle = Geom::rad_to_deg( std::atan2( - _guide->normal_to_line[Geom::X], _guide->normal_to_line[Geom::Y] ) ); + } + + { + Inkscape::XML::Node *repr = SP_OBJECT_REPR (_guide); + const gchar *guide_id = repr->attribute("id"); + gchar *label = g_strdup_printf(_("Guideline ID: %s"), guide_id); + _label_name.set_label(label); + g_free(label); + } + { + gchar *guide_description = sp_guide_description(_guide); + gchar *label = g_strdup_printf(_("Current: %s"), guide_description); + g_free(guide_description); + _label_descr.set_markup(label); + g_free(label); + } + + _modeChanged(); // sets values of spinboxes. + + if ( _oldangle == 90. || _oldangle == 270. || _oldangle == -90. || _oldangle == -270.) { + _spin_button_x.grab_focus(); + _spin_button_x.select_region(0, 20); + } else if ( _oldangle == 0. || _oldangle == 180. || _oldangle == -180.) { + _spin_button_y.grab_focus(); + _spin_button_y.select_region(0, 20); + } else { + _spin_angle.grab_focus(); + _spin_angle.select_region(0, 20); + } + + set_position(Gtk::WIN_POS_MOUSE); + + show_all_children(); + set_modal(true); + _desktop->setWindowTransient (gobj()); + property_destroy_with_parent() = true; +} + +} +} +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/guides.h b/src/ui/dialog/guides.h new file mode 100644 index 000000000..49f94deea --- /dev/null +++ b/src/ui/dialog/guides.h @@ -0,0 +1,93 @@ +/** + * + * \brief Dialog for modifying guidelines + * + * Author: + * Andrius R. <knutux@gmail.com> + * Johan Engelen + * + * Copyright (C) 2006-2007 Authors + * + * Released under GNU GPL. Read the file 'COPYING' for more information + */ + +#ifndef INKSCAPE_DIALOG_GUIDELINE_H +#define INKSCAPE_DIALOG_GUIDELINE_H + +#include <gtkmm/dialog.h> +#include <gtkmm/table.h> +#include <gtkmm/spinbutton.h> +#include <gtkmm/label.h> +#include <gtkmm/stock.h> +#include <gtkmm/adjustment.h> +#include "ui/widget/button.h" +#include <2geom/point.h> + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +class GuidelinePropertiesDialog : public Gtk::Dialog { +public: + GuidelinePropertiesDialog(SPGuide *guide, SPDesktop *desktop); + virtual ~GuidelinePropertiesDialog(); + + Glib::ustring getName() const { return "GuidelinePropertiesDialog"; } + + static void showDialog(SPGuide *guide, SPDesktop *desktop); + +protected: + void _setup(); + + void _onApply(); + void _onOK(); + void _onDelete(); + + void _response(gint response); + void _modeChanged(); + +private: + GuidelinePropertiesDialog(GuidelinePropertiesDialog const &); // no copy + GuidelinePropertiesDialog &operator=(GuidelinePropertiesDialog const &); // no assign + + SPDesktop *_desktop; + SPGuide *_guide; + Gtk::Table _layout_table; + Gtk::Label _label_name; + Gtk::Label _label_descr; + Gtk::Label _label_units; + Gtk::Label _label_X; + Gtk::Label _label_Y; + Gtk::Label _label_degrees; + Inkscape::UI::Widget::CheckButton _relative_toggle; + Gtk::Adjustment _adjustment_x; + Gtk::SpinButton _spin_button_x; + Gtk::Adjustment _adjustment_y; + Gtk::SpinButton _spin_button_y; + + Gtk::Adjustment _adj_angle; + Gtk::SpinButton _spin_angle; + + Gtk::Widget *_unit_selector; + bool _mode; + Geom::Point _oldpos; + gdouble _oldangle; +}; + +} // namespace +} // namespace +} // namespace + + +#endif // INKSCAPE_DIALOG_GUIDELINE_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/icon-preview.cpp b/src/ui/dialog/icon-preview.cpp new file mode 100644 index 000000000..336afc3c5 --- /dev/null +++ b/src/ui/dialog/icon-preview.cpp @@ -0,0 +1,307 @@ +/** @file + * @brief A simple dialog for previewing icon representation. + */ +/* Authors: + * Jon A. Cruz + * Bob Jamison + * Other dudes from The Inkscape Organization + * + * Copyright (C) 2004 Bob Jamison + * Copyright (C) 2005 Jon A. Cruz + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gtk/gtk.h> +#include <glib/gmem.h> +#include <glibmm/i18n.h> +#include <gtkmm/buttonbox.h> +#include <gtkmm/stock.h> + +#include "desktop.h" +#include "desktop-handles.h" +#include "display/nr-arena.h" +#include "document.h" +#include "inkscape.h" +#include "preferences.h" +#include "selection.h" +#include "sp-root.h" +#include "xml/repr.h" + +#include "icon-preview.h" + +extern "C" { +// takes doc, root, icon, and icon name to produce pixels +guchar * +sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, + const gchar *name, unsigned int psize ); +} + +namespace Inkscape { +namespace UI { +namespace Dialogs { + + +IconPreviewPanel& +IconPreviewPanel::getInstance() +{ + static IconPreviewPanel &instance = *new IconPreviewPanel(); + + instance.refreshPreview(); + + return instance; +} + +//######################################################################### +//## E V E N T S +//######################################################################### + +void IconPreviewPanel::on_button_clicked(int which) +{ + if ( hot != which ) { + buttons[hot]->set_active( false ); + + hot = which; + updateMagnify(); + _getContents()->queue_draw(); + } +} + + + + +//######################################################################### +//## C O N S T R U C T O R / D E S T R U C T O R +//######################################################################### +/** + * Constructor + */ +IconPreviewPanel::IconPreviewPanel() : + UI::Widget::Panel("", "/dialogs/iconpreview", SP_VERB_VIEW_ICON_PREVIEW), + hot(1), + refreshButton(0), + selectionButton(0) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + numEntries = 0; + + std::vector<Glib::ustring> pref_sizes = prefs->getAllDirs("/iconpreview/sizes/default"); + std::vector<int> rawSizes; + + for (std::vector<Glib::ustring>::iterator i = pref_sizes.begin(); i != pref_sizes.end(); ++i) { + if (prefs->getBool(*i + "/show", true)) { + int sizeVal = prefs->getInt(*i + "/value", -1); + if (sizeVal > 0) { + rawSizes.push_back(sizeVal); + } + } + } + + if ( !rawSizes.empty() ) { + numEntries = rawSizes.size(); + sizes = new int[numEntries]; + int i = 0; + for ( std::vector<int>::iterator it = rawSizes.begin(); it != rawSizes.end(); ++it, ++i ) { + sizes[i] = *it; + } + } + + if ( numEntries < 1 ) + { + numEntries = 5; + sizes = new int[numEntries]; + sizes[0] = 16; + sizes[1] = 24; + sizes[2] = 32; + sizes[3] = 48; + sizes[4] = 128; + } + + pixMem = new guchar*[numEntries]; + images = new Gtk::Image*[numEntries]; + labels = new Glib::ustring*[numEntries]; + buttons = new Gtk::ToggleToolButton*[numEntries]; + + + for ( int i = 0; i < numEntries; i++ ) { + char *label = g_strdup_printf(_("%d x %d"), sizes[i], sizes[i]); + labels[i] = new Glib::ustring(label); + g_free(label); + pixMem[i] = 0; + images[i] = 0; + } + + + magLabel.set_label( *labels[hot] ); + + Gtk::VBox* magBox = new Gtk::VBox(); + + magBox->pack_start( magnified ); + magBox->pack_start( magLabel, Gtk::PACK_SHRINK ); + + + Gtk::VBox * verts = new Gtk::VBox(); + for ( int i = 0; i < numEntries; i++ ) { + pixMem[i] = new guchar[4 * sizes[i] * sizes[i]]; + memset( pixMem[i], 0x00, 4 * sizes[i] * sizes[i] ); + + GdkPixbuf *pb = gdk_pixbuf_new_from_data( pixMem[i], GDK_COLORSPACE_RGB, TRUE, 8, sizes[i], sizes[i], sizes[i] * 4, /*(GdkPixbufDestroyNotify)g_free*/NULL, NULL ); + GtkImage* img = GTK_IMAGE( gtk_image_new_from_pixbuf( pb ) ); + images[i] = Glib::wrap(img); + Glib::ustring label(*labels[i]); + buttons[i] = new Gtk::ToggleToolButton(label); + buttons[i]->set_active( i == hot ); + buttons[i]->set_icon_widget(*images[i]); + + tips.set_tip((*buttons[i]), label); + + buttons[i]->signal_clicked().connect( sigc::bind<int>( sigc::mem_fun(*this, &IconPreviewPanel::on_button_clicked), i) ); + + + verts->add(*buttons[i]); + } + + iconBox.pack_start(splitter); + splitter.pack1( *magBox, true, true ); + splitter.pack2( *verts, false, false ); + + + //## The Refresh button + + + Gtk::HButtonBox* holder = new Gtk::HButtonBox( Gtk::BUTTONBOX_END ); + _getContents()->pack_end(*holder, false, false); + + selectionButton = new Gtk::ToggleButton(_("Selection")); // , GTK_RESPONSE_APPLY + holder->pack_start( *selectionButton, false, false ); + tips.set_tip((*selectionButton), _("Selection only or whole document")); + selectionButton->signal_clicked().connect( sigc::mem_fun(*this, &IconPreviewPanel::modeToggled) ); + + gint val = prefs->getBool("/iconpreview/selectionOnly"); + selectionButton->set_active( val != 0 ); + + refreshButton = new Gtk::Button(Gtk::Stock::REFRESH); // , GTK_RESPONSE_APPLY + holder->pack_end( *refreshButton, false, false ); + tips.set_tip((*refreshButton), _("Refresh the icons")); + refreshButton->signal_clicked().connect( sigc::mem_fun(*this, &IconPreviewPanel::refreshPreview) ); + + + _getContents()->pack_start(iconBox, Gtk::PACK_EXPAND_WIDGET); + + show_all_children(); +} + +//######################################################################### +//## M E T H O D S +//######################################################################### + + +void IconPreviewPanel::refreshPreview() +{ + SPDesktop *desktop = getDesktop(); + if ( desktop ) { + + if ( selectionButton && selectionButton->get_active() ) + { + Inkscape::Selection * sel = sp_desktop_selection(desktop); + if ( sel ) { + //g_message("found a selection to play with"); + + GSList const *items = sel->itemList(); + SPObject *target = 0; + while ( items && !target ) { + SPItem* item = SP_ITEM( items->data ); + SPObject * obj = SP_OBJECT(item); + gchar const *id = SP_OBJECT_ID( obj ); + if ( id ) { + target = obj; + } + + items = g_slist_next(items); + } + if ( target ) { + renderPreview(target); + } + } + } + else + { + SPObject *target = desktop->currentRoot(); + if ( target ) { + renderPreview(target); + } + } + } +} + +void IconPreviewPanel::modeToggled() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/iconpreview/selectionOnly", (selectionButton && selectionButton->get_active())); + + refreshPreview(); +} + +void IconPreviewPanel::renderPreview( SPObject* obj ) +{ + SPDocument * doc = SP_OBJECT_DOCUMENT(obj); + gchar * id = SP_OBJECT_ID(obj); + +// g_message(" setting up to render '%s' as the icon", id ); + + NRArenaItem *root = NULL; + + /* Create new arena */ + NRArena *arena = NRArena::create(); + + /* Create ArenaItem and set transform */ + unsigned int visionkey = sp_item_display_key_new(1); + + root = sp_item_invoke_show ( SP_ITEM( SP_DOCUMENT_ROOT(doc) ), + arena, visionkey, SP_ITEM_SHOW_DISPLAY ); + + for ( int i = 0; i < numEntries; i++ ) { + guchar * px = sp_icon_doc_icon( doc, root, id, sizes[i] ); +// g_message( " size %d %s", sizes[i], (px ? "worked" : "failed") ); + if ( px ) { + memcpy( pixMem[i], px, sizes[i] * sizes[i] * 4 ); + g_free( px ); + px = 0; + } else { + memset( pixMem[i], 0, sizes[i] * sizes[i] * 4 ); + } + images[i]->queue_draw(); + } + updateMagnify(); + + sp_item_invoke_hide(SP_ITEM(sp_document_root(doc)), visionkey); + nr_object_unref((NRObject *) arena); +} + +void IconPreviewPanel::updateMagnify() +{ + Glib::RefPtr<Gdk::Pixbuf> buf = images[hot]->get_pixbuf()->scale_simple( 128, 128, Gdk::INTERP_NEAREST ); + magLabel.set_label( *labels[hot] ); + magnified.set( buf ); + magnified.queue_draw(); + magnified.get_parent()->queue_draw(); +} + + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/icon-preview.h b/src/ui/dialog/icon-preview.h new file mode 100644 index 000000000..8f143725d --- /dev/null +++ b/src/ui/dialog/icon-preview.h @@ -0,0 +1,84 @@ +/** @file + * @brief A simple dialog for previewing icon representation. + */ +/* Authors: + * Jon A. Cruz + * Bob Jamison + * Other dudes from The Inkscape Organization + * + * Copyright (C) 2004,2005 The Inkscape Organization + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_ICON_PREVIEW_H +#define SEEN_ICON_PREVIEW_H + +#include <gtkmm/box.h> +#include <gtkmm/button.h> +#include <gtkmm/label.h> +#include <gtkmm/paned.h> +#include <gtkmm/image.h> +#include <gtkmm/togglebutton.h> +#include <gtkmm/toggletoolbutton.h> + +#include "ui/widget/panel.h" + +struct SPObject; + +namespace Inkscape { +namespace UI { +namespace Dialogs { + + +/** + * A panel that displays an icon preview + */ +class IconPreviewPanel : public UI::Widget::Panel +{ +public: + IconPreviewPanel(); + //IconPreviewPanel(Glib::ustring const &label); + + static IconPreviewPanel& getInstance(); + + void refreshPreview(); + void modeToggled(); + +private: + IconPreviewPanel(IconPreviewPanel const &); // no copy + IconPreviewPanel &operator=(IconPreviewPanel const &); // no assign + + + void on_button_clicked(int which); + void renderPreview( SPObject* obj ); + void updateMagnify(); + + Gtk::Tooltips tips; + + Gtk::VBox iconBox; + Gtk::HPaned splitter; + + int hot; + int numEntries; + int* sizes; + + Gtk::Image magnified; + Gtk::Label magLabel; + + Gtk::Button *refreshButton; + Gtk::ToggleButton *selectionButton; + + guchar** pixMem; + Gtk::Image** images; + Glib::ustring** labels; + Gtk::ToggleToolButton** buttons; +}; + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + + + +#endif // SEEN_ICON_PREVIEW_H diff --git a/src/ui/dialog/layer-properties.cpp b/src/ui/dialog/layer-properties.cpp new file mode 100644 index 000000000..ccd91fa2e --- /dev/null +++ b/src/ui/dialog/layer-properties.cpp @@ -0,0 +1,256 @@ +/** @file + * @brief Dialog for renaming layers + */ +/* Author: + * Bryce W. Harrington <bryce@bryceharrington.com> + * Andrius R. <knutux@gmail.com> + * + * Copyright (C) 2004 Bryce Harrington + * Copyright (C) 2006 Andrius R. + * + * Released under GNU GPL. Read the file 'COPYING' for more information + */ + +#include <gtkmm/stock.h> +#include <glibmm/i18n.h> +#include "inkscape.h" +#include "desktop.h" +#include "document.h" +#include "layer-manager.h" +#include "message-stack.h" +#include "desktop-handles.h" +#include "sp-object.h" +#include "sp-item.h" + +#include "layer-properties.h" + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +LayerPropertiesDialog::LayerPropertiesDialog() +: _strategy(NULL), _desktop(NULL), _layer(NULL), _position_visible(false) +{ + Gtk::VBox *mainVBox = get_vbox(); + + _layout_table.set_spacings(4); + _layout_table.resize (1, 2); + + // Layer name widgets + _layer_name_entry.set_activates_default(true); + _layer_name_label.set_label(_("Layer name:")); + _layer_name_label.set_alignment(1.0, 0.5); + + _layout_table.attach(_layer_name_label, + 0, 1, 0, 1, Gtk::FILL, Gtk::FILL); + _layout_table.attach(_layer_name_entry, + 1, 2, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::FILL); + mainVBox->pack_start(_layout_table, false, false, 4); + + // Buttons + _close_button.set_use_stock(true); + _close_button.set_label(Gtk::Stock::CANCEL.id); + _close_button.set_flags(Gtk::CAN_DEFAULT); + + _apply_button.set_use_underline(true); + _apply_button.set_flags(Gtk::CAN_DEFAULT); + + _close_button.signal_clicked() + .connect(sigc::mem_fun(*this, &LayerPropertiesDialog::_close)); + _apply_button.signal_clicked() + .connect(sigc::mem_fun(*this, &LayerPropertiesDialog::_apply)); + + signal_delete_event().connect( + sigc::bind_return( + sigc::hide(sigc::mem_fun(*this, &LayerPropertiesDialog::_close)), + true + ) + ); + + add_action_widget(_close_button, Gtk::RESPONSE_CLOSE); + add_action_widget(_apply_button, Gtk::RESPONSE_APPLY); + + _apply_button.grab_default(); + + show_all_children(); +} + +LayerPropertiesDialog::~LayerPropertiesDialog() { + _setDesktop(NULL); + _setLayer(NULL); +} + +void LayerPropertiesDialog::_showDialog(LayerPropertiesDialog::Strategy &strategy, + SPDesktop *desktop, SPObject *layer) +{ + LayerPropertiesDialog *dialog = new LayerPropertiesDialog(); + + dialog->_strategy = &strategy; + dialog->_setDesktop(desktop); + dialog->_setLayer(layer); + + dialog->_strategy->setup(*dialog); + + dialog->set_modal(true); + desktop->setWindowTransient (dialog->gobj()); + dialog->property_destroy_with_parent() = true; + + dialog->show(); + dialog->present(); +} + +void +LayerPropertiesDialog::_apply() +{ + g_assert(_strategy != NULL); + + _strategy->perform(*this); + sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_NONE, + _("Add layer")); + + _close(); +} + +void +LayerPropertiesDialog::_close() +{ + _setLayer(NULL); + _setDesktop(NULL); + destroy_(); + Glib::signal_idle().connect( + sigc::bind_return( + sigc::bind(sigc::ptr_fun(&::operator delete), this), + false + ) + ); +} + +void +LayerPropertiesDialog::_setup_position_controls() { + if ( NULL == _layer || _desktop->currentRoot() == _layer ) { + // no layers yet, so option above/below/sublayer is useless + return; + } + + _position_visible = true; + _dropdown_list = Gtk::ListStore::create(_dropdown_columns); + _layer_position_combo.set_model(_dropdown_list); + _layer_position_combo.pack_start(_label_renderer); + _layer_position_combo.set_cell_data_func(_label_renderer, + sigc::mem_fun(*this, &LayerPropertiesDialog::_prepareLabelRenderer)); + + _layout_table.resize (2, 2); + + Gtk::ListStore::iterator row; + row = _dropdown_list->append(); + row->set_value(_dropdown_columns.position, LPOS_ABOVE); + row->set_value(_dropdown_columns.name, Glib::ustring(_("Above current"))); + _layer_position_combo.set_active(row); + row = _dropdown_list->append(); + row->set_value(_dropdown_columns.position, LPOS_BELOW); + row->set_value(_dropdown_columns.name, Glib::ustring(_("Below current"))); + row = _dropdown_list->append(); + row->set_value(_dropdown_columns.position, LPOS_CHILD); + row->set_value(_dropdown_columns.name, Glib::ustring(_("As sublayer of current"))); + + _layout_table.attach(_layer_position_combo, + 1, 2, 1, 2, Gtk::FILL | Gtk::EXPAND, Gtk::FILL); + _layer_position_label.set_label(_("Position:")); + _layer_position_label.set_alignment(1.0, 0.5); + _layout_table.attach(_layer_position_label, + 0, 1, 1, 2, Gtk::FILL, Gtk::FILL); + show_all_children(); +} + +/** Formats the label for a given layer row + */ +void LayerPropertiesDialog::_prepareLabelRenderer( + Gtk::TreeModel::const_iterator const &row +) { + Glib::ustring name=(*row)[_dropdown_columns.name]; + _label_renderer.property_markup() = name.c_str(); +} + +void LayerPropertiesDialog::Rename::setup(LayerPropertiesDialog &dialog) { + SPDesktop *desktop=dialog._desktop; + dialog.set_title(_("Rename Layer")); + gchar const *name = desktop->currentLayer()->label(); + dialog._layer_name_entry.set_text(( name ? name : "" )); + dialog._apply_button.set_label(_("_Rename")); +} + +void LayerPropertiesDialog::Rename::perform(LayerPropertiesDialog &dialog) { + SPDesktop *desktop=dialog._desktop; + Glib::ustring name(dialog._layer_name_entry.get_text()); + desktop->layer_manager->renameLayer( desktop->currentLayer(), + ( name.empty() ? NULL : (gchar *)name.c_str() ) + ); + sp_document_done(sp_desktop_document(desktop), SP_VERB_NONE, + _("Rename layer")); + // TRANSLATORS: This means "The layer has been renamed" + desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Renamed layer")); +} + +void LayerPropertiesDialog::Create::setup(LayerPropertiesDialog &dialog) { + dialog.set_title(_("Add Layer")); + dialog._layer_name_entry.set_text(""); + dialog._apply_button.set_label(_("_Add")); + dialog._setup_position_controls(); +} + +void LayerPropertiesDialog::Create::perform(LayerPropertiesDialog &dialog) { + SPDesktop *desktop=dialog._desktop; + + LayerRelativePosition position = LPOS_ABOVE; + + if (dialog._position_visible) { + Gtk::ListStore::iterator activeRow(dialog._layer_position_combo.get_active()); + position = activeRow->get_value(dialog._dropdown_columns.position); + } + + SPObject *new_layer=Inkscape::create_layer(desktop->currentRoot(), dialog._layer, position); + + Glib::ustring name(dialog._layer_name_entry.get_text()); + if (!name.empty()) { + desktop->layer_manager->renameLayer( new_layer, (gchar *)name.c_str() ); + } + sp_desktop_selection(desktop)->clear(); + desktop->setCurrentLayer(new_layer); + desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("New layer created.")); +} + +void LayerPropertiesDialog::_setDesktop(SPDesktop *desktop) { + if (desktop) { + Inkscape::GC::anchor (desktop); + } + if (_desktop) { + Inkscape::GC::release (_desktop); + } + _desktop = desktop; +} + +void LayerPropertiesDialog::_setLayer(SPObject *layer) { + if (layer) { + sp_object_ref(layer, NULL); + } + if (_layer) { + sp_object_unref(_layer, NULL); + } + _layer = layer; +} + +} // namespace +} // namespace +} // namespace + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/layer-properties.h b/src/ui/dialog/layer-properties.h new file mode 100644 index 000000000..807967e8d --- /dev/null +++ b/src/ui/dialog/layer-properties.h @@ -0,0 +1,132 @@ +/** @file + * @brief Dialog for renaming layers + */ +/* Author: + * Bryce W. Harrington <bryce@bryceharrington.com> + * + * Copyright (C) 2004 Bryce Harrington + * + * Released under GNU GPL. Read the file 'COPYING' for more information + */ + +#ifndef INKSCAPE_DIALOG_LAYER_PROPERTIES_H +#define INKSCAPE_DIALOG_LAYER_PROPERTIES_H + +#include <gtkmm/dialog.h> +#include <gtkmm/notebook.h> +#include <gtkmm/separator.h> +#include <gtkmm/frame.h> +#include <gtkmm/entry.h> +#include <gtkmm/label.h> +#include <gtkmm/table.h> +#include <gtkmm/combobox.h> +#include <gtkmm/liststore.h> + +#include "selection.h" +#include "layer-fns.h" + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +class LayerPropertiesDialog : public Gtk::Dialog { + public: + LayerPropertiesDialog(); + virtual ~LayerPropertiesDialog(); + + Glib::ustring getName() const { return "LayerPropertiesDialog"; } + + static void showRename(SPDesktop *desktop, SPObject *layer) { + _showDialog(Rename::instance(), desktop, layer); + } + static void showCreate(SPDesktop *desktop, SPObject *layer) { + _showDialog(Create::instance(), desktop, layer); + } + +protected: + struct Strategy { + virtual ~Strategy() {} + virtual void setup(LayerPropertiesDialog &)=0; + virtual void perform(LayerPropertiesDialog &)=0; + }; + struct Rename : public Strategy { + static Rename &instance() { static Rename instance; return instance; } + void setup(LayerPropertiesDialog &dialog); + void perform(LayerPropertiesDialog &dialog); + }; + struct Create : public Strategy { + static Create &instance() { static Create instance; return instance; } + void setup(LayerPropertiesDialog &dialog); + void perform(LayerPropertiesDialog &dialog); + }; + + friend class Rename; + friend class Create; + + Strategy *_strategy; + SPDesktop *_desktop; + SPObject *_layer; + + class PositionDropdownColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn<LayerRelativePosition> position; + Gtk::TreeModelColumn<Glib::ustring> name; + + PositionDropdownColumns() { + add(position); add(name); + } + }; + + Gtk::Label _layer_name_label; + Gtk::Entry _layer_name_entry; + Gtk::Label _layer_position_label; + Gtk::ComboBox _layer_position_combo; + Gtk::Table _layout_table; + bool _position_visible; + + PositionDropdownColumns _dropdown_columns; + Gtk::CellRendererText _label_renderer; + Glib::RefPtr<Gtk::ListStore> _dropdown_list; + + Gtk::Button _close_button; + Gtk::Button _apply_button; + + sigc::connection _destroy_connection; + + static LayerPropertiesDialog &_instance() { + static LayerPropertiesDialog instance; + return instance; + } + + void _setDesktop(SPDesktop *desktop); + void _setLayer(SPObject *layer); + + static void _showDialog(Strategy &strategy, SPDesktop *desktop, SPObject *layer); + void _apply(); + void _close(); + + void _setup_position_controls(); + void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row); + +private: + LayerPropertiesDialog(LayerPropertiesDialog const &); // no copy + LayerPropertiesDialog &operator=(LayerPropertiesDialog const &); // no assign +}; + +} // namespace +} // namespace +} // namespace + + +#endif //INKSCAPE_DIALOG_LAYER_PROPERTIES_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/layers.cpp b/src/ui/dialog/layers.cpp new file mode 100644 index 000000000..0e75401ab --- /dev/null +++ b/src/ui/dialog/layers.cpp @@ -0,0 +1,805 @@ +/* + * A simple panel for layers + * + * Authors: + * Jon A. Cruz + * + * Copyright (C) 2006 Jon A. Cruz + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gtk/gtkstock.h> +#include <gtk/gtkmain.h> +#include <gtkmm/widget.h> +#include <gtkmm/icontheme.h> +#include <glibmm/i18n.h> + +#include "desktop.h" +#include "desktop-style.h" +#include "document.h" +#include "helper/action.h" +#include "inkscape.h" +#include "layer-fns.h" +#include "layer-manager.h" +#include "preferences.h" +#include "sp-item.h" +#include "sp-object.h" +#include "svg/css-ostringstream.h" +#include "ui/icon-names.h" +#include "ui/widget/imagetoggler.h" +#include "verbs.h" +#include "widgets/icon.h" +#include "xml/repr.h" + +#include "layers.h" + +//#define DUMP_LAYERS 1 + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +LayersPanel& +LayersPanel::getInstance() +{ + return *new LayersPanel(); +} + +enum { + COL_VISIBLE = 1, + COL_LOCKED +}; + +enum { + BUTTON_NEW = 0, + BUTTON_RENAME, + BUTTON_TOP, + BUTTON_BOTTOM, + BUTTON_UP, + BUTTON_DOWN, + BUTTON_DUPLICATE, + BUTTON_DELETE, + BUTTON_SOLO +}; + +class LayersPanel::InternalUIBounce +{ +public: + int _actionCode; + SPObject* _target; +}; + +static gboolean layers_panel_activated( GtkObject */*object*/, GdkEvent * /*event*/, gpointer data ) +{ + if ( data ) + { + LayersPanel* panel = reinterpret_cast<LayersPanel*>(data); + panel->setDesktop(panel->getDesktop()); + } + + return FALSE; +} + +static gboolean layers_panel_deactivated( GtkObject */*object*/, GdkEvent * /*event*/, gpointer data ) +{ + if ( data ) + { + LayersPanel* panel = reinterpret_cast<LayersPanel*>(data); + panel->setDesktop(NULL); + } + + return FALSE; +} + + +void LayersPanel::_styleButton( Gtk::Button& btn, SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback ) +{ + bool set = false; + + if ( iconName ) { + GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, iconName ); + gtk_widget_show( child ); + btn.add( *manage(Glib::wrap(child)) ); + set = true; + } + + if ( desktop ) { + Verb *verb = Verb::get( code ); + if ( verb ) { + SPAction *action = verb->get_action(desktop); + if ( !set && action && action->image ) { + GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, action->image ); + gtk_widget_show( child ); + btn.add( *manage(Glib::wrap(child)) ); + set = true; + } + + if ( action && action->tip ) { + _tips.set_tip( btn, action->tip ); + } + } + } + + if ( !set && fallback ) { + btn.set_label( fallback ); + } +} + + +Gtk::MenuItem& LayersPanel::_addPopupItem( SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback, int id ) +{ + GtkWidget* iconWidget = 0; + const char* label = 0; + + if ( iconName ) { + iconWidget = sp_icon_new( Inkscape::ICON_SIZE_MENU, iconName ); + } + + if ( desktop ) { + Verb *verb = Verb::get( code ); + if ( verb ) { + SPAction *action = verb->get_action(desktop); + if ( !iconWidget && action && action->image ) { + iconWidget = sp_icon_new( Inkscape::ICON_SIZE_MENU, action->image ); + } + + if ( action ) { + label = action->name; + } + } + } + + if ( !label && fallback ) { + label = fallback; + } + + Gtk::Widget* wrapped = 0; + if ( iconWidget ) { + wrapped = manage(Glib::wrap(iconWidget)); + wrapped->show(); + } + + + + Gtk::Menu::MenuList& menulist = _popupMenu.items(); + + if ( wrapped ) { + menulist.push_back( Gtk::Menu_Helpers::ImageMenuElem( label, *wrapped, sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), id)) ); + } else { + menulist.push_back( Gtk::Menu_Helpers::MenuElem( label, sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), id)) ); + } + return menulist.back(); +} + +void LayersPanel::_fireAction( unsigned int code ) +{ + if ( _desktop ) { + Verb *verb = Verb::get( code ); + if ( verb ) { + SPAction *action = verb->get_action(_desktop); + if ( action ) { + sp_action_perform( action, NULL ); +// } else { +// g_message("no action"); + } +// } else { +// g_message("no verb for %u", code); + } +// } else { +// g_message("no active desktop"); + } +} + +// SP_VERB_LAYER_NEXT, +// SP_VERB_LAYER_PREV, +void LayersPanel::_takeAction( int val ) +{ + if ( !_pending ) { + _pending = new InternalUIBounce(); + _pending->_actionCode = val; + _pending->_target = _selectedLayer(); + Glib::signal_timeout().connect( sigc::mem_fun(*this, &LayersPanel::_executeAction), 0 ); + } +} + +bool LayersPanel::_executeAction() +{ + // Make sure selected layer hasn't changed since the action was triggered + if ( _pending + && ( + (_pending->_actionCode == BUTTON_NEW) + || !( (_desktop && _desktop->currentLayer()) + && (_desktop->currentLayer() != _pending->_target) + ) + ) + ) { + int val = _pending->_actionCode; +// SPObject* target = _pending->_target; + + switch ( val ) { + case BUTTON_NEW: + { + _fireAction( SP_VERB_LAYER_NEW ); + } + break; + case BUTTON_RENAME: + { + _fireAction( SP_VERB_LAYER_RENAME ); + } + break; + case BUTTON_TOP: + { + _fireAction( SP_VERB_LAYER_TO_TOP ); + } + break; + case BUTTON_BOTTOM: + { + _fireAction( SP_VERB_LAYER_TO_BOTTOM ); + } + break; + case BUTTON_UP: + { + _fireAction( SP_VERB_LAYER_RAISE ); + } + break; + case BUTTON_DOWN: + { + _fireAction( SP_VERB_LAYER_LOWER ); + } + break; + case BUTTON_DUPLICATE: + { + _fireAction( SP_VERB_LAYER_DUPLICATE ); + } + break; + case BUTTON_DELETE: + { + _fireAction( SP_VERB_LAYER_DELETE ); + } + case BUTTON_SOLO: + { + _fireAction( SP_VERB_LAYER_SOLO ); + } + break; + } + + delete _pending; + _pending = 0; + } + + return false; +} + +class LayersPanel::ModelColumns : public Gtk::TreeModel::ColumnRecord +{ +public: + + ModelColumns() + { + add(_colObject); + add(_colVisible); + add(_colLocked); + add(_colLabel); + } + virtual ~ModelColumns() {} + + Gtk::TreeModelColumn<SPObject*> _colObject; + Gtk::TreeModelColumn<Glib::ustring> _colLabel; + Gtk::TreeModelColumn<bool> _colVisible; + Gtk::TreeModelColumn<bool> _colLocked; +}; + +void LayersPanel::_updateLayer( SPObject *layer ) { + _store->foreach( sigc::bind<SPObject*>(sigc::mem_fun(*this, &LayersPanel::_checkForUpdated), layer) ); +} + +bool LayersPanel::_checkForUpdated(const Gtk::TreePath &/*path*/, const Gtk::TreeIter& iter, SPObject* layer) +{ + bool stopGoing = false; + Gtk::TreeModel::Row row = *iter; + Glib::ustring tmp = row[_model->_colLabel]; + if ( layer == row[_model->_colObject] ) + { + row[_model->_colLabel] = layer->label() ? layer->label() : SP_OBJECT_ID(layer); + row[_model->_colVisible] = SP_IS_ITEM(layer) ? !SP_ITEM(layer)->isHidden() : false; + row[_model->_colLocked] = SP_IS_ITEM(layer) ? SP_ITEM(layer)->isLocked() : false; + + stopGoing = true; + } + + return stopGoing; +} + +void LayersPanel::_selectLayer( SPObject *layer ) { + if ( !layer || (_desktop && _desktop->doc() && (layer == _desktop->doc()->root)) ) { + if ( _tree.get_selection()->count_selected_rows() != 0 ) { + _tree.get_selection()->unselect_all(); + } + } else { + _store->foreach( sigc::bind<SPObject*>(sigc::mem_fun(*this, &LayersPanel::_checkForSelected), layer) ); + } + + _checkTreeSelection(); +} + +bool LayersPanel::_checkForSelected(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPObject* layer) +{ + bool stopGoing = false; + + Gtk::TreeModel::Row row = *iter; + if ( layer == row[_model->_colObject] ) + { + _tree.expand_to_path( path ); + + Glib::RefPtr<Gtk::TreeSelection> select = _tree.get_selection(); + + select->select(iter); + + stopGoing = true; + } + + return stopGoing; +} + +void LayersPanel::_layersChanged() +{ +// g_message("_layersChanged()"); + SPDocument* document = _desktop->doc(); + SPObject* root = document->root; + if ( root ) { + _selectedConnection.block(); + if ( _mgr && _mgr->includes( root ) ) { + SPObject* target = _desktop->currentLayer(); + _store->clear(); + +#if DUMP_LAYERS + g_message("root:%p {%s} [%s]", root, root->id, root->label() ); +#endif // DUMP_LAYERS + _addLayer( document, root, 0, target, 0 ); + } + _selectedConnection.unblock(); + } +} + +void LayersPanel::_addLayer( SPDocument* doc, SPObject* layer, Gtk::TreeModel::Row* parentRow, SPObject* target, int level ) +{ + if ( layer && (level < _maxNestDepth) ) { + unsigned int counter = _mgr->childCount(layer); + for ( unsigned int i = 0; i < counter; i++ ) { + SPObject *child = _mgr->nthChildOf(layer, i); + if ( child ) { +#if DUMP_LAYERS + g_message(" %3d layer:%p {%s} [%s]", level, child, child->id, child->label() ); +#endif // DUMP_LAYERS + + Gtk::TreeModel::iterator iter = parentRow ? _store->prepend(parentRow->children()) : _store->prepend(); + Gtk::TreeModel::Row row = *iter; + row[_model->_colObject] = child; + row[_model->_colLabel] = child->label() ? child->label() : SP_OBJECT_ID(child); + row[_model->_colVisible] = SP_IS_ITEM(child) ? !SP_ITEM(child)->isHidden() : false; + row[_model->_colLocked] = SP_IS_ITEM(child) ? SP_ITEM(child)->isLocked() : false; + + if ( target && child == target ) { + _tree.expand_to_path( _store->get_path(iter) ); + + Glib::RefPtr<Gtk::TreeSelection> select = _tree.get_selection(); + select->select(iter); + + _checkTreeSelection(); + } + + _addLayer( doc, child, &row, target, level + 1 ); + } + } + } +} + +SPObject* LayersPanel::_selectedLayer() +{ + SPObject* obj = 0; + + Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected(); + if ( iter ) { + Gtk::TreeModel::Row row = *iter; + obj = row[_model->_colObject]; + } + + return obj; +} + +void LayersPanel::_pushTreeSelectionToCurrent() +{ + SPObject* inTree = _selectedLayer(); + // TODO hunt down the possible API abuse in getting NULL + if ( _desktop->currentRoot() ) { + if ( inTree ) { + SPObject* curr = _desktop->currentLayer(); + if ( curr != inTree ) { + _mgr->setCurrentLayer( inTree ); + } + } else { + _mgr->setCurrentLayer( _desktop->doc()->root ); + } + } +} + +void LayersPanel::_checkTreeSelection() +{ + bool sensitive = false; + bool sensitiveNonTop = false; + bool sensitiveNonBottom = false; + if ( _tree.get_selection()->count_selected_rows() > 0 ) { + sensitive = true; + + SPObject* inTree = _selectedLayer(); + if ( inTree ) { + + sensitiveNonTop = (Inkscape::next_layer(inTree->parent, inTree) != 0); + sensitiveNonBottom = (Inkscape::previous_layer(inTree->parent, inTree) != 0); + + } + } + + + for ( std::vector<Gtk::Widget*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) { + (*it)->set_sensitive( sensitive ); + } + for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) { + (*it)->set_sensitive( sensitiveNonTop ); + } + for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) { + (*it)->set_sensitive( sensitiveNonBottom ); + } +} + +void LayersPanel::_preToggle( GdkEvent const *event ) +{ + if ( _toggleEvent ) { + gdk_event_free(_toggleEvent); + _toggleEvent = 0; + } + + if ( event && (event->type == GDK_BUTTON_PRESS) ) { + // Make a copy so we can keep it around. + _toggleEvent = gdk_event_copy(const_cast<GdkEvent*>(event)); + } +} + +void LayersPanel::_toggled( Glib::ustring const& str, int targetCol ) +{ + Gtk::TreeModel::Children::iterator iter = _tree.get_model()->get_iter(str); + Gtk::TreeModel::Row row = *iter; + + Glib::ustring tmp = row[_model->_colLabel]; + + SPObject* obj = row[_model->_colObject]; + SPItem* item = ( obj && SP_IS_ITEM(obj) ) ? SP_ITEM(obj) : 0; + if ( item ) { + switch ( targetCol ) { + case COL_VISIBLE: + { + bool newValue = !row[_model->_colVisible]; + row[_model->_colVisible] = newValue; + item->setHidden( !newValue ); + item->updateRepr(); + sp_document_done( _desktop->doc() , SP_VERB_DIALOG_LAYERS, + newValue? _("Unhide layer") : _("Hide layer")); + } + break; + + case COL_LOCKED: + { + bool newValue = !row[_model->_colLocked]; + row[_model->_colLocked] = newValue; + item->setLocked( newValue ); + item->updateRepr(); + sp_document_done( _desktop->doc() , SP_VERB_DIALOG_LAYERS, + newValue? _("Lock layer") : _("Unlock layer")); + } + break; + } + } +} + +void LayersPanel::_handleButtonEvent(GdkEventButton* evt) +{ + // TODO - fix to a better is-popup function + if ( (evt->type == GDK_BUTTON_PRESS) && (evt->button == 3) ) { + + + { + Gtk::TreeModel::Path path; + Gtk::TreeViewColumn* col = 0; + int x = static_cast<int>(evt->x); + int y = static_cast<int>(evt->y); + int x2 = 0; + int y2 = 0; + if ( _tree.get_path_at_pos( x, y, + path, col, + x2, y2 ) ) { + _checkTreeSelection(); + _popupMenu.popup(evt->button, evt->time); + } + } + + } +} + +void LayersPanel::_handleRowChange( Gtk::TreeModel::Path const& /*path*/, Gtk::TreeModel::iterator const& iter ) +{ + Gtk::TreeModel::Row row = *iter; + if ( row ) { + SPObject* obj = row[_model->_colObject]; + if ( obj ) { + gchar const* oldLabel = obj->label(); + Glib::ustring tmp = row[_model->_colLabel]; + if ( oldLabel && oldLabel[0] && !tmp.empty() && (tmp != oldLabel) ) { + _mgr->renameLayer( obj, tmp.c_str() ); + row[_model->_colLabel] = obj->label(); + } + } + } +} + +bool LayersPanel::_rowSelectFunction( Glib::RefPtr<Gtk::TreeModel> const & /*model*/, Gtk::TreeModel::Path const & /*path*/, bool currentlySelected ) +{ + bool val = true; + if ( !currentlySelected && _toggleEvent ) + { + GdkEvent* event = gtk_get_current_event(); + if ( event ) { + // (keep these checks separate, so we know when to call gdk_event_free() + if ( event->type == GDK_BUTTON_PRESS ) { + GdkEventButton const* target = reinterpret_cast<GdkEventButton const*>(_toggleEvent); + GdkEventButton const* evtb = reinterpret_cast<GdkEventButton const*>(event); + + if ( (evtb->window == target->window) + && (evtb->send_event == target->send_event) + && (evtb->time == target->time) + && (evtb->state == target->state) + ) + { + // Ooooh! It's a magic one + val = false; + } + } + gdk_event_free(event); + } + } + return val; +} + +/** + * Constructor + */ +LayersPanel::LayersPanel() : + UI::Widget::Panel("", "/dialogs/layers", SP_VERB_DIALOG_LAYERS), + _maxNestDepth(20), + _mgr(0), + _desktop(0), + _model(0), + _pending(0), + _toggleEvent(0), + _compositeSettings(SP_VERB_DIALOG_LAYERS, "layers", UI::Widget::SimpleFilterModifier::BLEND) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + _maxNestDepth = prefs->getIntLimited("/dialogs/layers/maxDepth", 20, 1, 1000); + + ModelColumns *zoop = new ModelColumns(); + _model = zoop; + + _store = Gtk::TreeStore::create( *zoop ); + + _tree.set_model( _store ); + _tree.set_headers_visible(false); + + Inkscape::UI::Widget::ImageToggler *eyeRenderer = manage( new Inkscape::UI::Widget::ImageToggler( + INKSCAPE_ICON_OBJECT_VISIBLE, INKSCAPE_ICON_OBJECT_HIDDEN) ); + int visibleColNum = _tree.append_column("vis", *eyeRenderer) - 1; + eyeRenderer->signal_pre_toggle().connect( sigc::mem_fun(*this, &LayersPanel::_preToggle) ); + eyeRenderer->signal_toggled().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_toggled), (int)COL_VISIBLE) ); + eyeRenderer->property_activatable() = true; + Gtk::TreeViewColumn* col = _tree.get_column(visibleColNum); + if ( col ) { + col->add_attribute( eyeRenderer->property_active(), _model->_colVisible ); + } + + Inkscape::UI::Widget::ImageToggler * renderer = manage( new Inkscape::UI::Widget::ImageToggler( + INKSCAPE_ICON_OBJECT_LOCKED, INKSCAPE_ICON_OBJECT_UNLOCKED) ); + int lockedColNum = _tree.append_column("lock", *renderer) - 1; + renderer->signal_pre_toggle().connect( sigc::mem_fun(*this, &LayersPanel::_preToggle) ); + renderer->signal_toggled().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_toggled), (int)COL_LOCKED) ); + renderer->property_activatable() = true; + col = _tree.get_column(lockedColNum); + if ( col ) { + col->add_attribute( renderer->property_active(), _model->_colLocked ); + } + + int nameColNum = _tree.append_column_editable("Name", _model->_colLabel) - 1; + + _tree.set_expander_column( *_tree.get_column(nameColNum) ); + + _compositeSettings.setSubject(&_subject); + + _selectedConnection = _tree.get_selection()->signal_changed().connect( sigc::mem_fun(*this, &LayersPanel::_pushTreeSelectionToCurrent) ); + _tree.get_selection()->set_select_function( sigc::mem_fun(*this, &LayersPanel::_rowSelectFunction) ); + + _tree.get_model()->signal_row_changed().connect( sigc::mem_fun(*this, &LayersPanel::_handleRowChange) ); + _tree.signal_button_press_event().connect_notify( sigc::mem_fun(*this, &LayersPanel::_handleButtonEvent) ); + + _scroller.add( _tree ); + _scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); + _scroller.set_shadow_type(Gtk::SHADOW_IN); + + _watching.push_back( &_compositeSettings ); + + _layersPage.pack_start( _scroller, Gtk::PACK_EXPAND_WIDGET ); + _layersPage.pack_end(_compositeSettings, Gtk::PACK_SHRINK); + _layersPage.pack_end(_buttonsRow, Gtk::PACK_SHRINK); + + _notebook.append_page(_layersPage, _("Layers")); + + _getContents()->pack_start(_notebook, Gtk::PACK_EXPAND_WIDGET); + + SPDesktop* targetDesktop = getDesktop(); + + _buttonsRow.set_child_min_width( 16 ); + + Gtk::Button* btn = manage( new Gtk::Button() ); + _styleButton( *btn, targetDesktop, SP_VERB_LAYER_NEW, GTK_STOCK_ADD, _("New") ); + btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_NEW) ); + _buttonsRow.add( *btn ); + + btn = manage( new Gtk::Button() ); + _styleButton( *btn, targetDesktop, SP_VERB_LAYER_TO_TOP, GTK_STOCK_GOTO_TOP, _("Top") ); + btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_TOP) ); + _watchingNonTop.push_back( btn ); + _buttonsRow.add( *btn ); + + btn = manage( new Gtk::Button() ); + _styleButton( *btn, targetDesktop, SP_VERB_LAYER_RAISE, GTK_STOCK_GO_UP, _("Up") ); + btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_UP) ); + _watchingNonTop.push_back( btn ); + _buttonsRow.add( *btn ); + + btn = manage( new Gtk::Button() ); + _styleButton( *btn, targetDesktop, SP_VERB_LAYER_LOWER, GTK_STOCK_GO_DOWN, _("Dn") ); + btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DOWN) ); + _watchingNonBottom.push_back( btn ); + _buttonsRow.add( *btn ); + + btn = manage( new Gtk::Button() ); + _styleButton( *btn, targetDesktop, SP_VERB_LAYER_TO_BOTTOM, GTK_STOCK_GOTO_BOTTOM, _("Bot") ); + btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_BOTTOM) ); + _watchingNonBottom.push_back( btn ); + _buttonsRow.add( *btn ); + +// btn = manage( new Gtk::Button("Dup") ); +// btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DUPLICATE) ); +// _buttonsRow.add( *btn ); + + btn = manage( new Gtk::Button() ); + _styleButton( *btn, targetDesktop, SP_VERB_LAYER_DELETE, GTK_STOCK_REMOVE, _("X") ); + btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DELETE) ); + _watching.push_back( btn ); + _buttonsRow.add( *btn ); + + + + + // ------------------------------------------------------- + { + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RENAME, 0, "Rename", (int)BUTTON_RENAME ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_DUPLICATE, 0, "Duplicate", (int)BUTTON_DUPLICATE ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_NEW, 0, "New", (int)BUTTON_NEW ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_SOLO, 0, "Solo", (int)BUTTON_SOLO ) ); + + _popupMenu.items().push_back( Gtk::Menu_Helpers::SeparatorElem() ); + + _watchingNonTop.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RAISE, GTK_STOCK_GO_UP, "Up", (int)BUTTON_UP ) ); + _watchingNonBottom.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOWER, GTK_STOCK_GO_DOWN, "Down", (int)BUTTON_DOWN ) ); + + _popupMenu.show_all_children(); + } + // ------------------------------------------------------- + + + + for ( std::vector<Gtk::Widget*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) { + (*it)->set_sensitive( false ); + } + for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) { + (*it)->set_sensitive( false ); + } + for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) { + (*it)->set_sensitive( false ); + } + + g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK( layers_panel_activated ), this ); + g_signal_connect( G_OBJECT(INKSCAPE), "deactivate_desktop", G_CALLBACK( layers_panel_deactivated ), this ); + setDesktop( targetDesktop ); + + show_all_children(); + + // restorePanelPrefs(); +} + +LayersPanel::~LayersPanel() +{ + setDesktop(NULL); + + _compositeSettings.setSubject(NULL); + + if ( _model ) + { + delete _model; + } + + if ( _toggleEvent ) + { + gdk_event_free( _toggleEvent ); + _toggleEvent = 0; + } +} + + +void LayersPanel::setDesktop( SPDesktop* desktop ) +{ + Panel::setDesktop(desktop); + + if ( desktop != _desktop ) { + _layerChangedConnection.disconnect(); + _layerUpdatedConnection.disconnect(); + _changedConnection.disconnect(); + if ( _mgr ) { + _mgr = 0; + } + if ( _desktop ) { + _desktop = 0; + } + + _desktop = getDesktop(); + if ( _desktop ) { + //setLabel( _desktop->doc()->name ); + + _mgr = _desktop->layer_manager; + if ( _mgr ) { + _layerChangedConnection = _mgr->connectCurrentLayerChanged( sigc::mem_fun(*this, &LayersPanel::_selectLayer) ); + _layerUpdatedConnection = _mgr->connectLayerDetailsChanged( sigc::mem_fun(*this, &LayersPanel::_updateLayer) ); + _changedConnection = _mgr->connectChanged( sigc::mem_fun(*this, &LayersPanel::_layersChanged) ); + } + + _layersChanged(); + } + } +/* + GSList const *layers=sp_document_get_resource_list( _desktop->doc(), "layer" ); + g_message( "layers list starts at %p", layers ); + for ( GSList const *iter=layers ; iter ; iter = iter->next ) { + SPObject *layer=static_cast<SPObject *>(iter->data); + g_message(" {%s} [%s]", layer->id, layer->label() ); + } +*/ +} + + + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/layers.h b/src/ui/dialog/layers.h new file mode 100644 index 000000000..1f593b9c6 --- /dev/null +++ b/src/ui/dialog/layers.h @@ -0,0 +1,146 @@ +/* + * A simple dialog for layer UI. + * + * Authors: + * Jon A. Cruz + * + * Copyright (C) 2006 Jon A. Cruz + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_LAYERS_PANEL_H +#define SEEN_LAYERS_PANEL_H + +#include <gtkmm/treeview.h> +#include <gtkmm/treestore.h> +#include <gtkmm/tooltips.h> +#include <gtkmm/scale.h> +#include <gtkmm/scrolledwindow.h> +#include <gtkmm/box.h> +#include <gtkmm/buttonbox.h> +#include <gtkmm/spinbutton.h> +#include <gtkmm/notebook.h> + +//#include "ui/previewholder.h" +#include "ui/widget/panel.h" +#include "ui/widget/object-composite-settings.h" + +class SPObject; + +namespace Inkscape { + +class LayerManager; + +namespace UI { +namespace Dialogs { + + +/** + * A panel that displays layers. + */ +class LayersPanel : public UI::Widget::Panel +{ +public: + LayersPanel(); + virtual ~LayersPanel(); + + //virtual void setOrientation( Gtk::AnchorType how ); + + static LayersPanel& getInstance(); + + void setDesktop( SPDesktop* desktop ); + +protected: + //virtual void _handleAction( int setId, int itemId ); + +private: + class ModelColumns; + class InternalUIBounce; + + LayersPanel(LayersPanel const &); // no copy + LayersPanel &operator=(LayersPanel const &); // no assign + + void _styleButton( Gtk::Button& btn, SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback ); + void _fireAction( unsigned int code ); + Gtk::MenuItem& _addPopupItem( SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback, int id ); + + void _preToggle( GdkEvent const *event ); + void _toggled( Glib::ustring const& str, int targetCol ); + + void _handleButtonEvent(GdkEventButton* evt); + void _handleRowChange( Gtk::TreeModel::Path const& path, Gtk::TreeModel::iterator const& iter ); + + void _pushTreeSelectionToCurrent(); + void _checkTreeSelection(); + + void _takeAction( int val ); + bool _executeAction(); + + bool _rowSelectFunction( Glib::RefPtr<Gtk::TreeModel> const & model, Gtk::TreeModel::Path const & path, bool b ); + + void _updateLayer(SPObject *layer); + bool _checkForUpdated(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPObject* layer); + + void _selectLayer(SPObject *layer); + bool _checkForSelected(const Gtk::TreePath& path, const Gtk::TreeIter& iter, SPObject* layer); + + void _layersChanged(); + void _addLayer( SPDocument* doc, SPObject* layer, Gtk::TreeModel::Row* parentRow, SPObject* target, int level ); + + SPObject* _selectedLayer(); + + // Hooked to the layer manager: + sigc::connection _layerChangedConnection; + sigc::connection _layerUpdatedConnection; + sigc::connection _changedConnection; + sigc::connection _addedConnection; + sigc::connection _removedConnection; + + // Internal + sigc::connection _selectedConnection; + + int _maxNestDepth; + Inkscape::LayerManager* _mgr; + SPDesktop* _desktop; + ModelColumns* _model; + InternalUIBounce* _pending; + GdkEvent* _toggleEvent; + Glib::RefPtr<Gtk::TreeStore> _store; + std::vector<Gtk::Widget*> _watching; + std::vector<Gtk::Widget*> _watchingNonTop; + std::vector<Gtk::Widget*> _watchingNonBottom; + + Gtk::Tooltips _tips; + Gtk::TreeView _tree; + Gtk::HButtonBox _buttonsRow; + Gtk::ScrolledWindow _scroller; + Gtk::Menu _popupMenu; + Gtk::SpinButton _spinBtn; + Gtk::Notebook _notebook; + Gtk::VBox _layersPage; + + UI::Widget::StyleSubject::CurrentLayer _subject; + UI::Widget::ObjectCompositeSettings _compositeSettings; +}; + + + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + + + +#endif // SEEN_LAYERS_PANEL_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/panel-dialog.h b/src/ui/dialog/panel-dialog.h index f087f40e4..7dbb6dd4a 100644 --- a/src/ui/dialog/panel-dialog.h +++ b/src/ui/dialog/panel-dialog.h @@ -19,7 +19,7 @@ #include "verbs.h" #include "dialog.h" -#include "dialogs/swatches.h" +#include "ui/dialog/swatches.h" #include "ui/dialog/floating-behavior.h" #include "ui/dialog/dock-behavior.h" #include "preferences.h" diff --git a/src/ui/dialog/swatches.cpp b/src/ui/dialog/swatches.cpp new file mode 100644 index 000000000..dfb60c04e --- /dev/null +++ b/src/ui/dialog/swatches.cpp @@ -0,0 +1,1212 @@ +/** @file + * @brief Color swatches dialog + */ +/* Authors: + * Jon A. Cruz + * John Bintz + * + * Copyright (C) 2005 Jon A. Cruz + * Copyright (C) 2008 John Bintz + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <errno.h> + +#include <gtk/gtkdialog.h> //for GTK_RESPONSE* types +#include <gtk/gtkdnd.h> +#include <gtk/gtkmenu.h> +#include <gtk/gtkmenuitem.h> +#include <gtk/gtkseparatormenuitem.h> +#include <glibmm/i18n.h> +#include <gdkmm/pixbuf.h> + +#include "desktop.h" +#include "desktop-handles.h" +#include "desktop-style.h" +#include "document.h" +#include "extension/db.h" +#include "inkscape.h" +#include "inkscape.h" +#include "io/sys.h" +#include "message-context.h" +#include "path-prefix.h" +#include "preferences.h" +#include "sp-item.h" +#include "svg/svg-color.h" +#include "swatches.h" +#include "widgets/eek-preview.h" + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +ColorItem::ColorItem() : _isRemove(true){}; +ColorItem::ColorItem( unsigned int r, unsigned int g, unsigned int b, Glib::ustring& name ) : + def( r, g, b, name ), + _isRemove(false), + _isLive(false), + _linkIsTone(false), + _linkPercent(0), + _linkGray(0), + _linkSrc(0) +{ +} + +ColorItem::~ColorItem() +{ +} + +ColorItem::ColorItem(ColorItem const &other) : + Inkscape::UI::Previewable() +{ + if ( this != &other ) { + *this = other; + } +} + +ColorItem &ColorItem::operator=(ColorItem const &other) +{ + if ( this != &other ) { + def = other.def; + + // TODO - correct linkage + _linkSrc = other._linkSrc; + g_message("Erk!"); + } + return *this; +} + + +class JustForNow +{ +public: + JustForNow() : _prefWidth(0) {} + + Glib::ustring _name; + int _prefWidth; + std::vector<ColorItem*> _colors; +}; + +static std::vector<JustForNow*> possible; + + + +typedef enum { + APP_X_INKY_COLOR_ID = 0, + APP_X_INKY_COLOR = 0, + APP_X_COLOR, + TEXT_DATA +} colorFlavorType; + +//TODO: warning: deprecated conversion from string constant to ‘gchar*’ +// +//Turn out to be warnings that we should probably leave in place. The +// pointers/types used need to be read-only. So until we correct the using +// code, those warnings are actually desired. They say "Hey! Fix this". We +// definitely don't want to hide/ignore them. --JonCruz +static const GtkTargetEntry sourceColorEntries[] = { +#if ENABLE_MAGIC_COLORS +// {"application/x-inkscape-color-id", GTK_TARGET_SAME_APP, APP_X_INKY_COLOR_ID}, + {"application/x-inkscape-color", 0, APP_X_INKY_COLOR}, +#endif // ENABLE_MAGIC_COLORS + {"application/x-color", 0, APP_X_COLOR}, + {"text/plain", 0, TEXT_DATA}, +}; + +void ColorItem::_dragGetColorData( GtkWidget *widget, + GdkDragContext *drag_context, + GtkSelectionData *data, + guint info, + guint time, + gpointer user_data) +{ + (void)widget; + (void)drag_context; + (void)time; + static GdkAtom typeXColor = gdk_atom_intern("application/x-color", FALSE); + static GdkAtom typeText = gdk_atom_intern("text/plain", FALSE); + + ColorItem* item = reinterpret_cast<ColorItem*>(user_data); + if ( info == TEXT_DATA ) { + gchar* tmp = g_strdup_printf("#%02x%02x%02x", item->def.getR(), item->def.getG(), item->def.getB() ); + + gtk_selection_data_set( data, + typeText, + 8, // format + (guchar*)tmp, + strlen((const char*)tmp) + 1); + g_free(tmp); + tmp = 0; + } else if ( info == APP_X_INKY_COLOR ) { + Glib::ustring paletteName; + + // Find where this thing came from + bool found = false; + int index = 0; + for ( std::vector<JustForNow*>::iterator it = possible.begin(); it != possible.end() && !found; ++it ) { + JustForNow* curr = *it; + index = 0; + for ( std::vector<ColorItem*>::iterator zz = curr->_colors.begin(); zz != curr->_colors.end(); ++zz ) { + if ( item == *zz ) { + found = true; + paletteName = curr->_name; + break; + } else { + index++; + } + } + } + +// if ( found ) { +// g_message("Found the color at entry %d in palette '%s'", index, paletteName.c_str() ); +// } else { +// g_message("Unable to find the color"); +// } + int itemCount = 4 + 2 + 1 + paletteName.length(); + + guint16* tmp = new guint16[itemCount]; + tmp[0] = (item->def.getR() << 8) | item->def.getR(); + tmp[1] = (item->def.getG() << 8) | item->def.getG(); + tmp[2] = (item->def.getB() << 8) | item->def.getB(); + tmp[3] = 0xffff; + tmp[4] = (item->_isLive || !item->_listeners.empty() || (item->_linkSrc != 0) ) ? 1 : 0; + + tmp[5] = index; + tmp[6] = paletteName.length(); + for ( unsigned int i = 0; i < paletteName.length(); i++ ) { + tmp[7 + i] = paletteName[i]; + } + gtk_selection_data_set( data, + typeXColor, + 16, // format + reinterpret_cast<const guchar*>(tmp), + itemCount * 2); + delete[] tmp; + } else { + guint16 tmp[4]; + tmp[0] = (item->def.getR() << 8) | item->def.getR(); + tmp[1] = (item->def.getG() << 8) | item->def.getG(); + tmp[2] = (item->def.getB() << 8) | item->def.getB(); + tmp[3] = 0xffff; + gtk_selection_data_set( data, + typeXColor, + 16, // format + reinterpret_cast<const guchar*>(tmp), + (3+1) * 2); + } +} + +static void dragBegin( GtkWidget *widget, GdkDragContext* dc, gpointer data ) +{ + (void)widget; + ColorItem* item = reinterpret_cast<ColorItem*>(data); + if ( item ) + { + if (item->isRemove()){ + GError *error = NULL; + gchar *filepath = (gchar *) g_strdup_printf("%s/remove-color.png", INKSCAPE_PIXMAPDIR); + gsize bytesRead = 0; + gsize bytesWritten = 0; + gchar *localFilename = g_filename_from_utf8( filepath, + -1, + &bytesRead, + &bytesWritten, + &error); + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_scale(localFilename, 32, 24, FALSE, &error); + g_free(localFilename); + g_free(filepath); + gtk_drag_set_icon_pixbuf( dc, pixbuf, 0, 0 ); + return; + } + + Glib::RefPtr<Gdk::Pixbuf> thumb = Gdk::Pixbuf::create( Gdk::COLORSPACE_RGB, false, 8, 32, 24 ); + guint32 fillWith = (0xff000000 & (item->def.getR() << 24)) + | (0x00ff0000 & (item->def.getG() << 16)) + | (0x0000ff00 & (item->def.getB() << 8)); + thumb->fill( fillWith ); + gtk_drag_set_icon_pixbuf( dc, thumb->gobj(), 0, 0 ); + } + +} + +//"drag-drop" +// gboolean dragDropColorData( GtkWidget *widget, +// GdkDragContext *drag_context, +// gint x, +// gint y, +// guint time, +// gpointer user_data) +// { +// // TODO finish + +// return TRUE; +// } + +static void handleClick( GtkWidget* widget, gpointer callback_data ) { + (void)widget; + ColorItem* item = reinterpret_cast<ColorItem*>(callback_data); + if ( item ) { + item->buttonClicked(false); + } +} + +static void handleSecondaryClick( GtkWidget* widget, gint arg1, gpointer callback_data ) { + (void)widget; + (void)arg1; + ColorItem* item = reinterpret_cast<ColorItem*>(callback_data); + if ( item ) { + item->buttonClicked(true); + } +} + +static gboolean handleEnterNotify( GtkWidget* /*widget*/, GdkEventCrossing* /*event*/, gpointer callback_data ) { + ColorItem* item = reinterpret_cast<ColorItem*>(callback_data); + if ( item ) { + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if ( desktop ) { + gchar* msg = g_strdup_printf(_("Color: <b>%s</b>; <b>Click</b> to set fill, <b>Shift+click</b> to set stroke"), + item->def.descr.c_str()); + desktop->tipsMessageContext()->set(Inkscape::INFORMATION_MESSAGE, msg); + g_free(msg); + } + } + return FALSE; +} + +static gboolean handleLeaveNotify( GtkWidget* /*widget*/, GdkEventCrossing* /*event*/, gpointer callback_data ) { + ColorItem* item = reinterpret_cast<ColorItem*>(callback_data); + if ( item ) { + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if ( desktop ) { + desktop->tipsMessageContext()->clear(); + } + } + return FALSE; +} + +static GtkWidget* popupMenu = 0; +static ColorItem* bounceTarget = 0; + +static void redirClick( GtkMenuItem *menuitem, gpointer user_data ) +{ + (void)user_data; + if ( bounceTarget ) { + handleClick( GTK_WIDGET(menuitem), bounceTarget ); + } +} + +static void redirSecondaryClick( GtkMenuItem *menuitem, gpointer user_data ) +{ + (void)user_data; + if ( bounceTarget ) { + handleSecondaryClick( GTK_WIDGET(menuitem), 0, bounceTarget ); + } +} + +static gboolean handleButtonPress( GtkWidget* widget, GdkEventButton* event, gpointer user_data) +{ + (void)widget; + gboolean handled = FALSE; + + if ( (event->button == 3) && (event->type == GDK_BUTTON_PRESS) ) { + if ( !popupMenu ) { + popupMenu = gtk_menu_new(); + GtkWidget* child = 0; + + //TRANSLATORS: An item in context menu on a colour in the swatches + child = gtk_menu_item_new_with_label(_("Set fill")); + g_signal_connect( G_OBJECT(child), + "activate", + G_CALLBACK(redirClick), + user_data); + gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child); + + //TRANSLATORS: An item in context menu on a colour in the swatches + child = gtk_menu_item_new_with_label(_("Set stroke")); + + g_signal_connect( G_OBJECT(child), + "activate", + G_CALLBACK(redirSecondaryClick), + user_data); + gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child); + + gtk_widget_show_all(popupMenu); + } + + ColorItem* item = reinterpret_cast<ColorItem*>(user_data); + if ( item ) { + bounceTarget = item; + if ( popupMenu ) { + gtk_menu_popup(GTK_MENU(popupMenu), NULL, NULL, NULL, NULL, event->button, event->time); + handled = TRUE; + } + } + } + + return handled; +} + +static void dieDieDie( GtkObject *obj, gpointer user_data ) +{ + g_message("die die die %p %p", obj, user_data ); +} + +//TODO: warning: deprecated conversion from string constant to ‘gchar*’ +// +//Turn out to be warnings that we should probably leave in place. The +// pointers/types used need to be read-only. So until we correct the using +// code, those warnings are actually desired. They say "Hey! Fix this". We +// definitely don't want to hide/ignore them. --JonCruz +static const GtkTargetEntry destColorTargets[] = { +#if ENABLE_MAGIC_COLORS +// {"application/x-inkscape-color-id", GTK_TARGET_SAME_APP, APP_X_INKY_COLOR_ID}, + {"application/x-inkscape-color", 0, APP_X_INKY_COLOR}, +#endif // ENABLE_MAGIC_COLORS + {"application/x-color", 0, APP_X_COLOR}, +}; + +#include "color.h" // for SP_RGBA32_U_COMPOSE + +void ColorItem::_dropDataIn( GtkWidget *widget, + GdkDragContext *drag_context, + gint x, gint y, + GtkSelectionData *data, + guint info, + guint event_time, + gpointer user_data) +{ + (void)widget; + (void)drag_context; + (void)x; + (void)y; + (void)event_time; +// g_message(" droppy droppy %d", info); + switch (info) { + case APP_X_INKY_COLOR: + { + if ( data->length >= 8 ) { + // Careful about endian issues. + guint16* dataVals = (guint16*)data->data; + if ( user_data ) { + ColorItem* item = reinterpret_cast<ColorItem*>(user_data); + if ( item->def.isEditable() ) { + // Shove on in the new value + item->def.setRGB( 0x0ff & (dataVals[0] >> 8), 0x0ff & (dataVals[1] >> 8), 0x0ff & (dataVals[2] >> 8) ); + } + } + } + break; + } + case APP_X_COLOR: + { + if ( data->length == 8 ) { + // Careful about endian issues. + guint16* dataVals = (guint16*)data->data; +// { +// gchar c[64] = {0}; +// sp_svg_write_color( c, 64, +// SP_RGBA32_U_COMPOSE( +// 0x0ff & (dataVals[0] >> 8), +// 0x0ff & (dataVals[1] >> 8), +// 0x0ff & (dataVals[2] >> 8), +// 0xff // can't have transparency in the color itself +// //0x0ff & (data->data[3] >> 8), +// )); +// } + if ( user_data ) { + ColorItem* item = reinterpret_cast<ColorItem*>(user_data); + if ( item->def.isEditable() ) { + // Shove on in the new value + item->def.setRGB( 0x0ff & (dataVals[0] >> 8), 0x0ff & (dataVals[1] >> 8), 0x0ff & (dataVals[2] >> 8) ); + } + } + } + break; + } + default: + g_message("unknown drop type"); + } + +} + +static bool bruteForce( SPDocument* document, Inkscape::XML::Node* node, Glib::ustring const& match, int r, int g, int b ) +{ + bool changed = false; + + if ( node ) { + gchar const * val = node->attribute("inkscape:x-fill-tag"); + if ( val && (match == val) ) { + SPObject *obj = document->getObjectByRepr( node ); + + gchar c[64] = {0}; + sp_svg_write_color( c, sizeof(c), SP_RGBA32_U_COMPOSE( r, g, b, 0xff ) ); + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property( css, "fill", c ); + + sp_desktop_apply_css_recursive( (SPItem*)obj, css, true ); + ((SPItem*)obj)->updateRepr(); + + changed = true; + } + + val = node->attribute("inkscape:x-stroke-tag"); + if ( val && (match == val) ) { + SPObject *obj = document->getObjectByRepr( node ); + + gchar c[64] = {0}; + sp_svg_write_color( c, sizeof(c), SP_RGBA32_U_COMPOSE( r, g, b, 0xff ) ); + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property( css, "stroke", c ); + + sp_desktop_apply_css_recursive( (SPItem*)obj, css, true ); + ((SPItem*)obj)->updateRepr(); + + changed = true; + } + + Inkscape::XML::Node* first = node->firstChild(); + changed |= bruteForce( document, first, match, r, g, b ); + + changed |= bruteForce( document, node->next(), match, r, g, b ); + } + + return changed; +} + +void ColorItem::_colorDefChanged(void* data) +{ + ColorItem* item = reinterpret_cast<ColorItem*>(data); + if ( item ) { + for ( std::vector<Gtk::Widget*>::iterator it = item->_previews.begin(); it != item->_previews.end(); ++it ) { + Gtk::Widget* widget = *it; + if ( IS_EEK_PREVIEW(widget->gobj()) ) { + EekPreview * preview = EEK_PREVIEW(widget->gobj()); + eek_preview_set_color( preview, + (item->def.getR() << 8) | item->def.getR(), + (item->def.getG() << 8) | item->def.getG(), + (item->def.getB() << 8) | item->def.getB() ); + + eek_preview_set_linked( preview, (LinkType)((item->_linkSrc ? PREVIEW_LINK_IN:0) + | (item->_listeners.empty() ? 0:PREVIEW_LINK_OUT) + | (item->_isLive ? PREVIEW_LINK_OTHER:0)) ); + + widget->queue_draw(); + } + } + + for ( std::vector<ColorItem*>::iterator it = item->_listeners.begin(); it != item->_listeners.end(); ++it ) { + guint r = item->def.getR(); + guint g = item->def.getG(); + guint b = item->def.getB(); + + if ( (*it)->_linkIsTone ) { + r = ( ((*it)->_linkPercent * (*it)->_linkGray) + ((100 - (*it)->_linkPercent) * r) ) / 100; + g = ( ((*it)->_linkPercent * (*it)->_linkGray) + ((100 - (*it)->_linkPercent) * g) ) / 100; + b = ( ((*it)->_linkPercent * (*it)->_linkGray) + ((100 - (*it)->_linkPercent) * b) ) / 100; + } else { + r = ( ((*it)->_linkPercent * 255) + ((100 - (*it)->_linkPercent) * r) ) / 100; + g = ( ((*it)->_linkPercent * 255) + ((100 - (*it)->_linkPercent) * g) ) / 100; + b = ( ((*it)->_linkPercent * 255) + ((100 - (*it)->_linkPercent) * b) ) / 100; + } + + (*it)->def.setRGB( r, g, b ); + } + + + // Look for objects using this color + { + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if ( desktop ) { + SPDocument* document = sp_desktop_document( desktop ); + Inkscape::XML::Node *rroot = sp_document_repr_root( document ); + if ( rroot ) { + + // Find where this thing came from + Glib::ustring paletteName; + bool found = false; + int index = 0; + for ( std::vector<JustForNow*>::iterator it2 = possible.begin(); it2 != possible.end() && !found; ++it2 ) { + JustForNow* curr = *it2; + index = 0; + for ( std::vector<ColorItem*>::iterator zz = curr->_colors.begin(); zz != curr->_colors.end(); ++zz ) { + if ( item == *zz ) { + found = true; + paletteName = curr->_name; + break; + } else { + index++; + } + } + } + + if ( !paletteName.empty() ) { + gchar* str = g_strdup_printf("%d|", index); + paletteName.insert( 0, str ); + g_free(str); + str = 0; + + if ( bruteForce( document, rroot, paletteName, item->def.getR(), item->def.getG(), item->def.getB() ) ) { + sp_document_done( document , SP_VERB_DIALOG_SWATCHES, + _("Change color definition")); + } + } + } + } + } + } +} + + +Gtk::Widget* ColorItem::getPreview(PreviewStyle style, ViewType view, ::PreviewSize size, guint ratio) +{ + Gtk::Widget* widget = 0; + if ( style == PREVIEW_STYLE_BLURB) { + Gtk::Label *lbl = new Gtk::Label(def.descr); + lbl->set_alignment(Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER); + widget = lbl; + } else { +// Glib::ustring blank(" "); +// if ( size == Inkscape::ICON_SIZE_MENU || size == Inkscape::ICON_SIZE_DECORATION ) { +// blank = " "; +// } + + GtkWidget* eekWidget = eek_preview_new(); + EekPreview * preview = EEK_PREVIEW(eekWidget); + Gtk::Widget* newBlot = Glib::wrap(eekWidget); + + eek_preview_set_color( preview, (def.getR() << 8) | def.getR(), (def.getG() << 8) | def.getG(), (def.getB() << 8) | def.getB()); + if ( _isRemove ) { + GError *error = NULL; + gchar *filepath = (gchar *) g_strdup_printf("%s/remove-color.png", INKSCAPE_PIXMAPDIR); + gsize bytesRead = 0; + gsize bytesWritten = 0; + gchar *localFilename = g_filename_from_utf8( filepath, + -1, + &bytesRead, + &bytesWritten, + &error); + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file(localFilename, &error); + if (!pixbuf) { + g_warning("Null pixbuf for %p [%s]", localFilename, localFilename ); + } + g_free(localFilename); + g_free(filepath); + + eek_preview_set_pixbuf( preview, pixbuf ); + } + + eek_preview_set_details( preview, (::PreviewStyle)style, (::ViewType)view, (::PreviewSize)size, ratio ); + eek_preview_set_linked( preview, (LinkType)((_linkSrc ? PREVIEW_LINK_IN:0) + | (_listeners.empty() ? 0:PREVIEW_LINK_OUT) + | (_isLive ? PREVIEW_LINK_OTHER:0)) ); + + def.addCallback( _colorDefChanged, this ); + + GValue val = {0, {{0}, {0}}}; + g_value_init( &val, G_TYPE_BOOLEAN ); + g_value_set_boolean( &val, FALSE ); + g_object_set_property( G_OBJECT(preview), "focus-on-click", &val ); + +/* + Gtk::Button *btn = new Gtk::Button(blank); + Gdk::Color color; + color.set_rgb((_r << 8)|_r, (_g << 8)|_g, (_b << 8)|_b); + btn->modify_bg(Gtk::STATE_NORMAL, color); + btn->modify_bg(Gtk::STATE_ACTIVE, color); + btn->modify_bg(Gtk::STATE_PRELIGHT, color); + btn->modify_bg(Gtk::STATE_SELECTED, color); + + Gtk::Widget* newBlot = btn; +*/ + + tips.set_tip((*newBlot), def.descr); + +/* + newBlot->signal_clicked().connect( sigc::mem_fun(*this, &ColorItem::buttonClicked) ); + + sigc::signal<void> type_signal_something; +*/ + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "clicked", + G_CALLBACK(handleClick), + this); + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "alt-clicked", + G_CALLBACK(handleSecondaryClick), + this); + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "button-press-event", + G_CALLBACK(handleButtonPress), + this); + + gtk_drag_source_set( GTK_WIDGET(newBlot->gobj()), + GDK_BUTTON1_MASK, + sourceColorEntries, + G_N_ELEMENTS(sourceColorEntries), + GdkDragAction(GDK_ACTION_MOVE | GDK_ACTION_COPY) ); + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "drag-data-get", + G_CALLBACK(ColorItem::_dragGetColorData), + this); + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "drag-begin", + G_CALLBACK(dragBegin), + this ); + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "enter-notify-event", + G_CALLBACK(handleEnterNotify), + this); + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "leave-notify-event", + G_CALLBACK(handleLeaveNotify), + this); + +// g_signal_connect( G_OBJECT(newBlot->gobj()), +// "drag-drop", +// G_CALLBACK(dragDropColorData), +// this); + + if ( def.isEditable() ) + { + gtk_drag_dest_set( GTK_WIDGET(newBlot->gobj()), + GTK_DEST_DEFAULT_ALL, + destColorTargets, + G_N_ELEMENTS(destColorTargets), + GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE) ); + + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "drag-data-received", + G_CALLBACK(_dropDataIn), + this ); + } + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "destroy", + G_CALLBACK(dieDieDie), + this); + + + widget = newBlot; + } + + _previews.push_back( widget ); + + return widget; +} + +void ColorItem::buttonClicked(bool secondary) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (!desktop) return; + char const * attrName = secondary ? "stroke" : "fill"; + + gchar c[64]; + if (!_isRemove){ + guint32 rgba = (def.getR() << 24) | (def.getG() << 16) | (def.getB() << 8) | 0xff; + sp_svg_write_color(c, sizeof(c), rgba); + } + + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property( css, attrName, _isRemove ? "none" : c ); + sp_desktop_set_style(desktop, css); + sp_repr_css_attr_unref(css); + + if (_isRemove){ + sp_document_done (sp_desktop_document (desktop), SP_VERB_DIALOG_SWATCHES, + secondary? _("Remove stroke color") : _("Remove fill color")); + } else { + sp_document_done (sp_desktop_document (desktop), SP_VERB_DIALOG_SWATCHES, + secondary? _("Set stroke color from swatch") : _("Set fill color from swatch")); + } +} + +static char* trim( char* str ) { + char* ret = str; + while ( *str && (*str == ' ' || *str == '\t') ) { + str++; + } + ret = str; + while ( *str ) { + str++; + } + str--; + while ( str > ret && (( *str == ' ' || *str == '\t' ) || *str == '\r' || *str == '\n') ) { + *str-- = 0; + } + return ret; +} + +void skipWhitespace( char*& str ) { + while ( *str == ' ' || *str == '\t' ) { + str++; + } +} + +bool parseNum( char*& str, int& val ) { + val = 0; + while ( '0' <= *str && *str <= '9' ) { + val = val * 10 + (*str - '0'); + str++; + } + bool retval = !(*str == 0 || *str == ' ' || *str == '\t' || *str == '\r' || *str == '\n'); + return retval; +} + + +static bool getBlock( std::string& dst, guchar ch, std::string const str ) +{ + bool good = false; + std::string::size_type pos = str.find(ch); + if ( pos != std::string::npos ) + { + std::string::size_type pos2 = str.find( '(', pos ); + if ( pos2 != std::string::npos ) { + std::string::size_type endPos = str.find( ')', pos2 ); + if ( endPos != std::string::npos ) { + dst = str.substr( pos2 + 1, (endPos - pos2 - 1) ); + good = true; + } + } + } + return good; +} + +static bool popVal( guint64& numVal, std::string& str ) +{ + bool good = false; + std::string::size_type endPos = str.find(','); + if ( endPos == std::string::npos ) { + endPos = str.length(); + } + + if ( endPos != std::string::npos && endPos > 0 ) { + std::string xxx = str.substr( 0, endPos ); + const gchar* ptr = xxx.c_str(); + gchar* endPtr = 0; + numVal = g_ascii_strtoull( ptr, &endPtr, 10 ); + if ( (numVal == G_MAXUINT64) && (ERANGE == errno) ) { + // overflow + } else if ( (numVal == 0) && (endPtr == ptr) ) { + // failed conversion + } else { + good = true; + str.erase( 0, endPos + 1 ); + } + } + + return good; +} + +void ColorItem::_wireMagicColors( void* p ) +{ + JustForNow* onceMore = reinterpret_cast<JustForNow*>(p); + if ( onceMore ) + { + for ( std::vector<ColorItem*>::iterator it = onceMore->_colors.begin(); it != onceMore->_colors.end(); ++it ) + { + std::string::size_type pos = (*it)->def.descr.find("*{"); + if ( pos != std::string::npos ) + { + std::string subby = (*it)->def.descr.substr( pos + 2 ); + std::string::size_type endPos = subby.find("}*"); + if ( endPos != std::string::npos ) + { + subby.erase( endPos ); + //g_message("FOUND MAGIC at '%s'", (*it)->def.descr.c_str()); + //g_message(" '%s'", subby.c_str()); + + if ( subby.find('E') != std::string::npos ) + { + (*it)->def.setEditable( true ); + } + + if ( subby.find('L') != std::string::npos ) + { + (*it)->_isLive = true; + } + + std::string part; + // Tint. index + 1 more val. + if ( getBlock( part, 'T', subby ) ) { + guint64 colorIndex = 0; + if ( popVal( colorIndex, part ) ) { + guint64 percent = 0; + if ( popVal( percent, part ) ) { + (*it)->_linkTint( *(onceMore->_colors[colorIndex]), percent ); + } + } + } + + // Shade/tone. index + 1 or 2 more val. + if ( getBlock( part, 'S', subby ) ) { + guint64 colorIndex = 0; + if ( popVal( colorIndex, part ) ) { + guint64 percent = 0; + if ( popVal( percent, part ) ) { + guint64 grayLevel = 0; + if ( !popVal( grayLevel, part ) ) { + grayLevel = 0; + } + (*it)->_linkTone( *(onceMore->_colors[colorIndex]), percent, grayLevel ); + } + } + } + + } + } + } + } +} + + +void ColorItem::_linkTint( ColorItem& other, int percent ) +{ + if ( !_linkSrc ) + { + other._listeners.push_back(this); + _linkIsTone = false; + _linkPercent = percent; + if ( _linkPercent > 100 ) + _linkPercent = 100; + if ( _linkPercent < 0 ) + _linkPercent = 0; + _linkGray = 0; + _linkSrc = &other; + + ColorItem::_colorDefChanged(&other); + } +} + +void ColorItem::_linkTone( ColorItem& other, int percent, int grayLevel ) +{ + if ( !_linkSrc ) + { + other._listeners.push_back(this); + _linkIsTone = true; + _linkPercent = percent; + if ( _linkPercent > 100 ) + _linkPercent = 100; + if ( _linkPercent < 0 ) + _linkPercent = 0; + _linkGray = grayLevel; + _linkSrc = &other; + + ColorItem::_colorDefChanged(&other); + } +} + + +void _loadPaletteFile( gchar const *filename ) +{ + char block[1024]; + FILE *f = Inkscape::IO::fopen_utf8name( filename, "r" ); + if ( f ) { + char* result = fgets( block, sizeof(block), f ); + if ( result ) { + if ( strncmp( "GIMP Palette", block, 12 ) == 0 ) { + bool inHeader = true; + bool hasErr = false; + + JustForNow *onceMore = new JustForNow(); + + do { + result = fgets( block, sizeof(block), f ); + block[sizeof(block) - 1] = 0; + if ( result ) { + if ( block[0] == '#' ) { + // ignore comment + } else { + char *ptr = block; + // very simple check for header versus entry + while ( *ptr == ' ' || *ptr == '\t' ) { + ptr++; + } + if ( (*ptr == 0) || (*ptr == '\r') || (*ptr == '\n') ) { + // blank line. skip it. + } else if ( '0' <= *ptr && *ptr <= '9' ) { + // should be an entry link + inHeader = false; + ptr = block; + Glib::ustring name(""); + int r = 0; + int g = 0; + int b = 0; + skipWhitespace(ptr); + if ( *ptr ) { + hasErr = parseNum(ptr, r); + if ( !hasErr ) { + skipWhitespace(ptr); + hasErr = parseNum(ptr, g); + } + if ( !hasErr ) { + skipWhitespace(ptr); + hasErr = parseNum(ptr, b); + } + if ( !hasErr && *ptr ) { + char* n = trim(ptr); + if (n != NULL) { + name = n; + } + } + if ( !hasErr ) { + // Add the entry now + Glib::ustring nameStr(name); + ColorItem* item = new ColorItem( r, g, b, nameStr ); + onceMore->_colors.push_back(item); + } + } else { + hasErr = true; + } + } else { + if ( !inHeader ) { + // Hmmm... probably bad. Not quite the format we want? + hasErr = true; + } else { + char* sep = strchr(result, ':'); + if ( sep ) { + *sep = 0; + char* val = trim(sep + 1); + char* name = trim(result); + if ( *name ) { + if ( strcmp( "Name", name ) == 0 ) + { + onceMore->_name = val; + } + else if ( strcmp( "Columns", name ) == 0 ) + { + gchar* endPtr = 0; + guint64 numVal = g_ascii_strtoull( val, &endPtr, 10 ); + if ( (numVal == G_MAXUINT64) && (ERANGE == errno) ) { + // overflow + } else if ( (numVal == 0) && (endPtr == val) ) { + // failed conversion + } else { + onceMore->_prefWidth = numVal; + } + } + } else { + // error + hasErr = true; + } + } else { + // error + hasErr = true; + } + } + } + } + } + } while ( result && !hasErr ); + if ( !hasErr ) { + possible.push_back(onceMore); +#if ENABLE_MAGIC_COLORS + ColorItem::_wireMagicColors( onceMore ); +#endif // ENABLE_MAGIC_COLORS + } else { + delete onceMore; + } + } + } + + fclose(f); + } +} + +static void loadEmUp() +{ + static bool beenHere = false; + if ( !beenHere ) { + beenHere = true; + + std::list<gchar *> sources; + sources.push_back( profile_path("palettes") ); + sources.push_back( g_strdup(INKSCAPE_PALETTESDIR) ); + sources.push_back( g_strdup(CREATE_PALETTESDIR) ); + + // Use this loop to iterate through a list of possible document locations. + while (!sources.empty()) { + gchar *dirname = sources.front(); + + if ( Inkscape::IO::file_test( dirname, G_FILE_TEST_EXISTS ) + && Inkscape::IO::file_test( dirname, G_FILE_TEST_IS_DIR )) { + GError *err = 0; + GDir *directory = g_dir_open(dirname, 0, &err); + if (!directory) { + gchar *safeDir = Inkscape::IO::sanitizeString(dirname); + g_warning(_("Palettes directory (%s) is unavailable."), safeDir); + g_free(safeDir); + } else { + gchar *filename = 0; + while ((filename = (gchar *)g_dir_read_name(directory)) != NULL) { + gchar* lower = g_ascii_strdown( filename, -1 ); +// if ( g_str_has_suffix(lower, ".gpl") ) { + gchar* full = g_build_filename(dirname, filename, NULL); + if ( !Inkscape::IO::file_test( full, G_FILE_TEST_IS_DIR ) ) { + _loadPaletteFile(full); + } + g_free(full); +// } + g_free(lower); + } + g_dir_close(directory); + } + } + + // toss the dirname + g_free(dirname); + sources.pop_front(); + } + } +} + + + + + + + + + +SwatchesPanel& SwatchesPanel::getInstance() +{ + return *new SwatchesPanel(); +} + + +/** + * Constructor + */ +SwatchesPanel::SwatchesPanel(gchar const* prefsPath) : + Inkscape::UI::Widget::Panel("", prefsPath, SP_VERB_DIALOG_SWATCHES, "", true), + _holder(0) +{ + Gtk::RadioMenuItem* hotItem = 0; + _holder = new PreviewHolder(); + _remove = new ColorItem(); + loadEmUp(); + if ( !possible.empty() ) { + JustForNow* first = 0; + Glib::ustring targetName; + if ( !_prefs_path.empty() ) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + targetName = prefs->getString(_prefs_path + "/palette"); + if (!targetName.empty()) { + for ( std::vector<JustForNow*>::iterator iter = possible.begin(); iter != possible.end(); ++iter ) { + if ( (*iter)->_name == targetName ) { + first = *iter; + break; + } + } + } + } + + if ( !first ) { + first = possible.front(); + } + + if ( first->_prefWidth > 0 ) { + _holder->setColumnPref( first->_prefWidth ); + } + _holder->freezeUpdates(); + _holder->addPreview(_remove); + for ( std::vector<ColorItem*>::iterator it = first->_colors.begin(); it != first->_colors.end(); it++ ) { + _holder->addPreview(*it); + } + _holder->thawUpdates(); + + Gtk::RadioMenuItem::Group groupOne; + + int i = 0; + for ( std::vector<JustForNow*>::iterator it = possible.begin(); it != possible.end(); it++ ) { + JustForNow* curr = *it; + Gtk::RadioMenuItem* single = manage(new Gtk::RadioMenuItem(groupOne, curr->_name)); + if ( curr == first ) { + hotItem = single; + } + _regItem( single, 3, i ); + i++; + } + } + + + _getContents()->pack_start(*_holder, Gtk::PACK_EXPAND_WIDGET); + _setTargetFillable(_holder); + + show_all_children(); + + restorePanelPrefs(); + if ( hotItem ) { + hotItem->set_active(); + } +} + +SwatchesPanel::~SwatchesPanel() +{ + if (_remove) delete _remove; + if (_holder) delete _holder; +} + +void SwatchesPanel::setOrientation( Gtk::AnchorType how ) +{ + // Must call the parent class or bad things might happen + Inkscape::UI::Widget::Panel::setOrientation( how ); + + if ( _holder ) + { + _holder->setOrientation( Gtk::ANCHOR_SOUTH ); + } +} + +void SwatchesPanel::_handleAction( int setId, int itemId ) +{ + switch( setId ) { + case 3: + { + if ( itemId >= 0 && itemId < static_cast<int>(possible.size()) ) { + _holder->clear(); + JustForNow* curr = possible[itemId]; + + if ( !_prefs_path.empty() ) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString(_prefs_path + "/palette", curr->_name); + } + + if ( curr->_prefWidth > 0 ) { + _holder->setColumnPref( curr->_prefWidth ); + } + _holder->freezeUpdates(); + _holder->addPreview(_remove); + for ( std::vector<ColorItem*>::iterator it = curr->_colors.begin(); it != curr->_colors.end(); it++ ) { + _holder->addPreview(*it); + } + _holder->thawUpdates(); + } + } + break; + } +} + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/swatches.h b/src/ui/dialog/swatches.h new file mode 100644 index 000000000..08fc9f79b --- /dev/null +++ b/src/ui/dialog/swatches.h @@ -0,0 +1,128 @@ +/** @file + * @brief Color swatches dialog + */ +/* Authors: + * Jon A. Cruz + * + * Copyright (C) 2005 Jon A. Cruz + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifndef SEEN_DIALOGS_SWATCHES_H +#define SEEN_DIALOGS_SWATCHES_H + +#include <gtkmm/textview.h> +#include <gtkmm/tooltips.h> + +#include "ui/widget/panel.h" +#include "ui/previewholder.h" +#include "widgets/eek-color-def.h" + +using eek::ColorDef; + +namespace Inkscape { +namespace UI { +namespace Dialogs { + + +void _loadPaletteFile( gchar const *filename ); + +/** + * The color swatch you see on screen as a clickable box. + */ +class ColorItem : public Inkscape::UI::Previewable +{ + friend void _loadPaletteFile( gchar const *filename ); +public: + ColorItem(); + ColorItem( unsigned int r, unsigned int g, unsigned int b, + Glib::ustring& name ); + virtual ~ColorItem(); + ColorItem(ColorItem const &other); + virtual ColorItem &operator=(ColorItem const &other); + virtual Gtk::Widget* getPreview(PreviewStyle style, + ViewType view, + ::PreviewSize size, + guint ratio); + void buttonClicked(bool secondary = false); + bool isRemove(){ return _isRemove; } + ColorDef def; + +private: + static void _dropDataIn( GtkWidget *widget, + GdkDragContext *drag_context, + gint x, gint y, + GtkSelectionData *data, + guint info, + guint event_time, + gpointer user_data); + + static void _dragGetColorData( GtkWidget *widget, + GdkDragContext *drag_context, + GtkSelectionData *data, + guint info, + guint time, + gpointer user_data); + + static void _wireMagicColors( void* p ); + static void _colorDefChanged(void* data); + + void _linkTint( ColorItem& other, int percent ); + void _linkTone( ColorItem& other, int percent, int grayLevel ); + + Gtk::Tooltips tips; + std::vector<Gtk::Widget*> _previews; + + bool _isRemove; + bool _isLive; + bool _linkIsTone; + int _linkPercent; + int _linkGray; + ColorItem* _linkSrc; + std::vector<ColorItem*> _listeners; +}; + +class RemoveColorItem; + +/** + * A panel that displays color swatches. + */ +class SwatchesPanel : public Inkscape::UI::Widget::Panel +{ +public: + SwatchesPanel(gchar const* prefsPath = "/dialogs/swatches"); + virtual ~SwatchesPanel(); + + static SwatchesPanel& getInstance(); + virtual void setOrientation( Gtk::AnchorType how ); + +protected: + virtual void _handleAction( int setId, int itemId ); + +private: + SwatchesPanel(SwatchesPanel const &); // no copy + SwatchesPanel &operator=(SwatchesPanel const &); // no assign + + static SwatchesPanel* instance; + + PreviewHolder* _holder; + ColorItem* _remove; +}; + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + + + +#endif // SEEN_SWATCHES_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/previewable.h b/src/ui/previewable.h index c517e4f28..ef1ca3ce2 100644 --- a/src/ui/previewable.h +++ b/src/ui/previewable.h @@ -14,7 +14,7 @@ #include <gtkmm/widget.h> -#include "../dialogs/eek-preview.h" +#include "../widgets/eek-preview.h" namespace Inkscape { namespace UI { diff --git a/src/ui/previewfillable.h b/src/ui/previewfillable.h index 6f02b60a8..f863af121 100644 --- a/src/ui/previewfillable.h +++ b/src/ui/previewfillable.h @@ -14,7 +14,7 @@ #include "previewable.h" -#include "../dialogs/eek-preview.h" +#include "../widgets/eek-preview.h" namespace Inkscape { namespace UI { diff --git a/src/ui/previewholder.h b/src/ui/previewholder.h index 812d4b27d..3c1a16195 100644 --- a/src/ui/previewholder.h +++ b/src/ui/previewholder.h @@ -17,7 +17,7 @@ #include <gtkmm/bin.h> #include <gtkmm/table.h> #include "previewfillable.h" -#include "../dialogs/eek-preview.h" +#include "../widgets/eek-preview.h" namespace Inkscape { namespace UI { diff --git a/src/ui/view/edit-widget.h b/src/ui/view/edit-widget.h index ea3205696..2bb708305 100644 --- a/src/ui/view/edit-widget.h +++ b/src/ui/view/edit-widget.h @@ -28,12 +28,12 @@ #include "ui/dialog/dialog-manager.h" #include "ui/view/edit-widget-interface.h" #include "ui/widget/dock.h" -#include "ui/widget/selected-style.h" +#include "ui/widget/layer-selector.h" #include "ui/widget/ruler.h" -#include "ui/widget/toolbox.h" +#include "ui/widget/selected-style.h" #include "ui/widget/svg-canvas.h" +#include "ui/widget/toolbox.h" #include "ui/widget/zoom-status.h" -#include "widgets/layer-selector.h" struct SPDesktop; struct SPDocument; diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert index 9b4048ea9..b6069631b 100644 --- a/src/ui/widget/Makefile_insert +++ b/src/ui/widget/Makefile_insert @@ -31,6 +31,8 @@ ink_common_sources += \ ui/widget/imagetoggler.h \ ui/widget/labelled.cpp \ ui/widget/labelled.h \ + ui/widget/layer-selector.cpp \ + ui/widget/layer-selector.h \ ui/widget/licensor.cpp \ ui/widget/licensor.h \ ui/widget/notebook-page.cpp \ diff --git a/src/ui/widget/entity-entry.cpp b/src/ui/widget/entity-entry.cpp index 980d225b2..e9f09f574 100644 --- a/src/ui/widget/entity-entry.cpp +++ b/src/ui/widget/entity-entry.cpp @@ -19,11 +19,9 @@ #include <gtkmm/scrolledwindow.h> #include <gtkmm/entry.h> -#include "ui/widget/registry.h" - -#include "dialogs/rdf.h" - #include "inkscape.h" +#include "rdf.h" +#include "ui/widget/registry.h" #include "entity-entry.h" diff --git a/src/ui/widget/layer-selector.cpp b/src/ui/widget/layer-selector.cpp new file mode 100644 index 000000000..51084b127 --- /dev/null +++ b/src/ui/widget/layer-selector.cpp @@ -0,0 +1,608 @@ +/* + * Inkscape::Widgets::LayerSelector - layer selector widget + * + * Authors: + * MenTaLguY <mental@rydia.net> + * + * Copyright (C) 2004 MenTaLguY + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <cstring> +#include <string> +#include <glibmm/i18n.h> + +#include "desktop.h" +#include "desktop-handles.h" +#include "document.h" +#include "layer-manager.h" +#include "sp-item.h" +#include "ui/dialog/layer-properties.h" +#include "ui/widget/layer-selector.h" +#include "util/filter-list.h" +#include "util/reverse-list.h" +#include "verbs.h" +#include "widgets/icon.h" +#include "widgets/shrink-wrap-button.h" +#include "xml/node-event-vector.h" + +namespace Inkscape { +namespace Widgets { + +namespace { + +class AlternateIcons : public Gtk::HBox { +public: + AlternateIcons(Inkscape::IconSize size, gchar const *a, gchar const *b) + : _a(NULL), _b(NULL) + { + if (a) { + _a = Gtk::manage(sp_icon_get_icon(a, size)); + _a->set_no_show_all(true); + add(*_a); + } + if (b) { + _b = Gtk::manage(sp_icon_get_icon(b, size)); + _b->set_no_show_all(true); + add(*_b); + } + setState(false); + } + + bool state() const { return _state; } + void setState(bool state) { + _state = state; + if (_state) { + if (_a) { + _a->hide(); + } + if (_b) { + _b->show(); + } + } else { + if (_a) { + _a->show(); + } + if (_b) { + _b->hide(); + } + } + } + +private: + Gtk::Widget *_a; + Gtk::Widget *_b; + bool _state; +}; + +} + +/** LayerSelector constructor. Creates lock and hide buttons, + * initalizes the layer dropdown selector with a label renderer, + * and hooks up signal for setting the desktop layer when the + * selector is changed. + */ +LayerSelector::LayerSelector(SPDesktop *desktop) +: _desktop(NULL), _layer(NULL) +{ + AlternateIcons *label; + + label = Gtk::manage(new AlternateIcons(Inkscape::ICON_SIZE_DECORATION, "visible", "hidden")); + _visibility_toggle.add(*label); + _visibility_toggle.signal_toggled().connect( + sigc::compose( + sigc::mem_fun(*label, &AlternateIcons::setState), + sigc::mem_fun(_visibility_toggle, &Gtk::ToggleButton::get_active) + ) + ); + _visibility_toggled_connection = _visibility_toggle.signal_toggled().connect( + sigc::compose( + sigc::mem_fun(*this, &LayerSelector::_hideLayer), + sigc::mem_fun(_visibility_toggle, &Gtk::ToggleButton::get_active) + ) + ); + + _visibility_toggle.set_relief(Gtk::RELIEF_NONE); + shrink_wrap_button(_visibility_toggle); + _tooltips.set_tip(_visibility_toggle, _("Toggle current layer visibility")); + pack_start(_visibility_toggle, Gtk::PACK_EXPAND_PADDING); + + label = Gtk::manage(new AlternateIcons(Inkscape::ICON_SIZE_DECORATION, "lock_unlocked", "width_height_lock")); + _lock_toggle.add(*label); + _lock_toggle.signal_toggled().connect( + sigc::compose( + sigc::mem_fun(*label, &AlternateIcons::setState), + sigc::mem_fun(_lock_toggle, &Gtk::ToggleButton::get_active) + ) + ); + _lock_toggled_connection = _lock_toggle.signal_toggled().connect( + sigc::compose( + sigc::mem_fun(*this, &LayerSelector::_lockLayer), + sigc::mem_fun(_lock_toggle, &Gtk::ToggleButton::get_active) + ) + ); + + _lock_toggle.set_relief(Gtk::RELIEF_NONE); + shrink_wrap_button(_lock_toggle); + _tooltips.set_tip(_lock_toggle, _("Lock or unlock current layer")); + pack_start(_lock_toggle, Gtk::PACK_EXPAND_PADDING); + + _tooltips.set_tip(_selector, _("Current layer")); + pack_start(_selector, Gtk::PACK_EXPAND_WIDGET); + + _layer_model = Gtk::ListStore::create(_model_columns); + _selector.set_model(_layer_model); + _selector.pack_start(_label_renderer); + _selector.set_cell_data_func( + _label_renderer, + sigc::mem_fun(*this, &LayerSelector::_prepareLabelRenderer) + ); + + _selection_changed_connection = _selector.signal_changed().connect( + sigc::mem_fun(*this, &LayerSelector::_setDesktopLayer) + ); + setDesktop(desktop); +} + +/** Destructor - disconnects signal handler + */ +LayerSelector::~LayerSelector() { + setDesktop(NULL); + _selection_changed_connection.disconnect(); +} + +namespace { + +/** Helper function - detaches desktop from selector + */ +bool detach(LayerSelector *selector) { + selector->setDesktop(NULL); + return FALSE; +} + +} + +/** Sets the desktop for the widget. First disconnects signals + * for the current desktop, then stores the pointer to the + * given \a desktop, and attaches its signals to this one. + * Then it selects the current layer for the desktop. + */ +void LayerSelector::setDesktop(SPDesktop *desktop) { + if ( desktop == _desktop ) { + return; + } + + if (_desktop) { +// _desktop_shutdown_connection.disconnect(); + _layer_changed_connection.disconnect(); +// g_signal_handlers_disconnect_by_func(_desktop, (gpointer)&detach, this); + } + _desktop = desktop; + if (_desktop) { + // TODO we need a different signal for this, really..s +// _desktop_shutdown_connection = _desktop->connectShutdown( +// sigc::bind (sigc::ptr_fun (detach), this)); +// g_signal_connect_after(_desktop, "shutdown", GCallback(detach), this); + + _layer_changed_connection = _desktop->connectCurrentLayerChanged( + sigc::mem_fun(*this, &LayerSelector::_selectLayer) + ); + _selectLayer(_desktop->currentLayer()); + } +} + +namespace { + +class is_layer { +public: + is_layer(SPDesktop *desktop) : _desktop(desktop) {} + bool operator()(SPObject &object) const { + return _desktop->isLayer(&object); + } +private: + SPDesktop *_desktop; +}; + +class column_matches_object { +public: + column_matches_object(Gtk::TreeModelColumn<SPObject *> const &column, + SPObject &object) + : _column(column), _object(object) {} + bool operator()(Gtk::TreeModel::const_iterator const &iter) const { + SPObject *current=(*iter)[_column]; + return current == &_object; + } +private: + Gtk::TreeModelColumn<SPObject *> const &_column; + SPObject &_object; +}; + +} + +/** Selects the given layer in the dropdown selector. + */ +void LayerSelector::_selectLayer(SPObject *layer) { + using Inkscape::Util::List; + using Inkscape::Util::cons; + using Inkscape::Util::reverse_list; + + _selection_changed_connection.block(); + + while (!_layer_model->children().empty()) { + Gtk::ListStore::iterator first_row(_layer_model->children().begin()); + _destroyEntry(first_row); + _layer_model->erase(first_row); + } + + SPObject *root=_desktop->currentRoot(); + + if (_layer) { + sp_object_unref(_layer, NULL); + _layer = NULL; + } + + if (layer) { + List<SPObject &> hierarchy=reverse_list<SPObject::ParentIterator>(layer, root); + if ( layer == root ) { + _buildEntries(0, cons(*root, hierarchy)); + } else if (hierarchy) { + _buildSiblingEntries(0, *root, hierarchy); + } + + Gtk::TreeIter row( + std::find_if( + _layer_model->children().begin(), + _layer_model->children().end(), + column_matches_object(_model_columns.object, *layer) + ) + ); + if ( row != _layer_model->children().end() ) { + _selector.set_active(row); + } + + _layer = layer; + sp_object_ref(_layer, NULL); + } + + if ( !layer || layer == root ) { + _visibility_toggle.set_sensitive(false); + _visibility_toggle.set_active(false); + _lock_toggle.set_sensitive(false); + _lock_toggle.set_active(false); + } else { + _visibility_toggle.set_sensitive(true); + _visibility_toggle.set_active(( SP_IS_ITEM(layer) ? SP_ITEM(layer)->isHidden() : false )); + _lock_toggle.set_sensitive(true); + _lock_toggle.set_active(( SP_IS_ITEM(layer) ? SP_ITEM(layer)->isLocked() : false )); + } + + _selection_changed_connection.unblock(); +} + +/** Sets the current desktop layer to the actively selected layer. + */ +void LayerSelector::_setDesktopLayer() { + Gtk::ListStore::iterator selected(_selector.get_active()); + SPObject *layer=_selector.get_active()->get_value(_model_columns.object); + if ( _desktop && layer ) { + _layer_changed_connection.block(); + + _desktop->layer_manager->setCurrentLayer(layer); + + _layer_changed_connection.unblock(); + + _selectLayer(_desktop->currentLayer()); + } + if (_desktop && _desktop->canvas) { + gtk_widget_grab_focus (GTK_WIDGET(_desktop->canvas)); + } +} + +/** Creates rows in the _layer_model data structure for each item + * in \a hierarchy, to a given \a depth. + */ +void LayerSelector::_buildEntries(unsigned depth, + Inkscape::Util::List<SPObject &> hierarchy) +{ + using Inkscape::Util::List; + using Inkscape::Util::rest; + + _buildEntry(depth, *hierarchy); + + List<SPObject &> remainder=rest(hierarchy); + if (remainder) { + _buildEntries(depth+1, remainder); + } else { + _buildSiblingEntries(depth+1, *hierarchy, remainder); + } +} + +/** Creates entries in the _layer_model data structure for + * all siblings of the first child in \a parent. + */ +void LayerSelector::_buildSiblingEntries( + unsigned depth, SPObject &parent, + Inkscape::Util::List<SPObject &> hierarchy +) { + using Inkscape::Util::List; + using Inkscape::Util::rest; + using Inkscape::Util::reverse_list_in_place; + using Inkscape::Util::filter_list; + + Inkscape::Util::List<SPObject &> siblings( + reverse_list_in_place( + filter_list<SPObject::SiblingIterator>( + is_layer(_desktop), parent.firstChild(), NULL + ) + ) + ); + + SPObject *layer( hierarchy ? &*hierarchy : NULL ); + + while (siblings) { + _buildEntry(depth, *siblings); + if ( &*siblings == layer ) { + _buildSiblingEntries(depth+1, *layer, rest(hierarchy)); + } + ++siblings; + } +} + +namespace { + +struct Callbacks { + sigc::slot<void> update_row; + sigc::slot<void> update_list; +}; + +void attribute_changed(Inkscape::XML::Node */*repr*/, gchar const *name, + gchar const */*old_value*/, gchar const */*new_value*/, + bool /*is_interactive*/, void *data) +{ + if ( !std::strcmp(name, "inkscape:groupmode") ) { + reinterpret_cast<Callbacks *>(data)->update_list(); + } else { + reinterpret_cast<Callbacks *>(data)->update_row(); + } +} + +void node_added(Inkscape::XML::Node */*parent*/, Inkscape::XML::Node *child, Inkscape::XML::Node */*ref*/, void *data) { + gchar const *mode=child->attribute("inkscape:groupmode"); + if ( mode && !std::strcmp(mode, "layer") ) { + reinterpret_cast<Callbacks *>(data)->update_list(); + } +} + +void node_removed(Inkscape::XML::Node */*parent*/, Inkscape::XML::Node *child, Inkscape::XML::Node */*ref*/, void *data) { + gchar const *mode=child->attribute("inkscape:groupmode"); + if ( mode && !std::strcmp(mode, "layer") ) { + reinterpret_cast<Callbacks *>(data)->update_list(); + } +} + +void node_reordered(Inkscape::XML::Node */*parent*/, Inkscape::XML::Node *child, + Inkscape::XML::Node */*old_ref*/, Inkscape::XML::Node */*new_ref*/, + void *data) +{ + gchar const *mode=child->attribute("inkscape:groupmode"); + if ( mode && !std::strcmp(mode, "layer") ) { + reinterpret_cast<Callbacks *>(data)->update_list(); + } +} + +void update_row_for_object(SPObject *object, + Gtk::TreeModelColumn<SPObject *> const &column, + Glib::RefPtr<Gtk::ListStore> const &model) +{ + Gtk::TreeIter row( + std::find_if( + model->children().begin(), + model->children().end(), + column_matches_object(column, *object) + ) + ); + if ( row != model->children().end() ) { + model->row_changed(model->get_path(row), row); + } +} + +void rebuild_all_rows(sigc::slot<void, SPObject *> rebuild, SPDesktop *desktop) +{ + rebuild(desktop->currentLayer()); +} + +} + +void LayerSelector::_protectUpdate(sigc::slot<void> slot) { + bool visibility_blocked=_visibility_toggled_connection.blocked(); + bool lock_blocked=_lock_toggled_connection.blocked(); + _visibility_toggled_connection.block(true); + _lock_toggled_connection.block(true); + slot(); + + SPObject *layer = _desktop ? _desktop->currentLayer() : 0; + if ( layer ) { + bool wantedValue = ( SP_IS_ITEM(layer) ? SP_ITEM(layer)->isLocked() : false ); + if ( _lock_toggle.get_active() != wantedValue ) { + _lock_toggle.set_active( wantedValue ); + } + wantedValue = ( SP_IS_ITEM(layer) ? SP_ITEM(layer)->isHidden() : false ); + if ( _visibility_toggle.get_active() != wantedValue ) { + _visibility_toggle.set_active( wantedValue ); + } + } + _visibility_toggled_connection.block(visibility_blocked); + _lock_toggled_connection.block(lock_blocked); +} + +/** Builds and appends a row in the layer model object. + */ +void LayerSelector::_buildEntry(unsigned depth, SPObject &object) { + Inkscape::XML::NodeEventVector *vector; + + Callbacks *callbacks=new Callbacks(); + + callbacks->update_row = sigc::bind( + sigc::mem_fun(*this, &LayerSelector::_protectUpdate), + sigc::bind( + sigc::ptr_fun(&update_row_for_object), + &object, _model_columns.object, _layer_model + ) + ); + + SPObject *layer=_desktop->currentLayer(); + if ( &object == layer || &object == SP_OBJECT_PARENT(layer) ) { + callbacks->update_list = sigc::bind( + sigc::mem_fun(*this, &LayerSelector::_protectUpdate), + sigc::bind( + sigc::ptr_fun(&rebuild_all_rows), + sigc::mem_fun(*this, &LayerSelector::_selectLayer), + _desktop + ) + ); + + Inkscape::XML::NodeEventVector events = { + &node_added, + &node_removed, + &attribute_changed, + NULL, + &node_reordered + }; + + vector = new Inkscape::XML::NodeEventVector(events); + } else { + Inkscape::XML::NodeEventVector events = { + NULL, + NULL, + &attribute_changed, + NULL, + NULL + }; + + vector = new Inkscape::XML::NodeEventVector(events); + } + + Gtk::ListStore::iterator row(_layer_model->append()); + + row->set_value(_model_columns.depth, depth); + + sp_object_ref(&object, NULL); + row->set_value(_model_columns.object, &object); + + Inkscape::GC::anchor(SP_OBJECT_REPR(&object)); + row->set_value(_model_columns.repr, SP_OBJECT_REPR(&object)); + + row->set_value(_model_columns.callbacks, reinterpret_cast<void *>(callbacks)); + + sp_repr_add_listener(SP_OBJECT_REPR(&object), vector, callbacks); +} + +/** Removes a row from the _model_columns object, disconnecting listeners + * on the slot. + */ +void LayerSelector::_destroyEntry(Gtk::ListStore::iterator const &row) { + Callbacks *callbacks=reinterpret_cast<Callbacks *>(row->get_value(_model_columns.callbacks)); + SPObject *object=row->get_value(_model_columns.object); + if (object) { + sp_object_unref(object, NULL); + } + Inkscape::XML::Node *repr=row->get_value(_model_columns.repr); + if (repr) { + sp_repr_remove_listener_by_data(repr, callbacks); + Inkscape::GC::release(repr); + } + delete callbacks; +} + +/** Formats the label for a given layer row + */ +void LayerSelector::_prepareLabelRenderer( + Gtk::TreeModel::const_iterator const &row +) { + unsigned depth=(*row)[_model_columns.depth]; + SPObject *object=(*row)[_model_columns.object]; + bool label_defaulted(false); + + // TODO: when the currently selected row is removed, + // (or before one has been selected) something appears to + // "invent" an iterator with null data and try to render it; + // where does it come from, and how can we avoid it? + if ( object && SP_OBJECT_REPR(object) ) { + SPObject *layer=( _desktop ? _desktop->currentLayer() : NULL ); + SPObject *root=( _desktop ? _desktop->currentRoot() : NULL ); + + bool isancestor = !( (layer && (SP_OBJECT_PARENT(object) == SP_OBJECT_PARENT(layer))) || ((layer == root) && (SP_OBJECT_PARENT(object) == root))); + + bool iscurrent = ( object == layer && object != root ); + + gchar *format = g_strdup_printf ( + "<span size=\"smaller\" %s><tt>%*s%s</tt>%s%s%s%%s%s%s%s</span>", + ( _desktop && _desktop->itemIsHidden (SP_ITEM(object)) ? "foreground=\"gray50\"" : "" ), + depth, "", ( iscurrent ? "•" : " " ), + ( iscurrent ? "<b>" : "" ), + ( SP_ITEM(object)->isLocked() ? "[" : "" ), + ( isancestor ? "<small>" : "" ), + ( isancestor ? "</small>" : "" ), + ( SP_ITEM(object)->isLocked() ? "]" : "" ), + ( iscurrent ? "</b>" : "" ) + ); + + gchar const *label; + if ( object != root ) { + label = object->label(); + if (!label) { + label = object->defaultLabel(); + label_defaulted = true; + } + } else { + label = _("(root)"); + } + + gchar *text = g_markup_printf_escaped(format, label); + _label_renderer.property_markup() = text; + g_free(text); + g_free(format); + } else { + _label_renderer.property_markup() = "<small> </small>"; + } + + _label_renderer.property_ypad() = 1; + _label_renderer.property_style() = ( label_defaulted ? + Pango::STYLE_ITALIC : + Pango::STYLE_NORMAL ); +} + +void LayerSelector::_lockLayer(bool lock) { + if ( _layer && SP_IS_ITEM(_layer) ) { + SP_ITEM(_layer)->setLocked(lock); + sp_document_done(sp_desktop_document(_desktop), SP_VERB_NONE, + lock? _("Lock layer") : _("Unlock layer")); + } +} + +void LayerSelector::_hideLayer(bool hide) { + if ( _layer && SP_IS_ITEM(_layer) ) { + SP_ITEM(_layer)->setHidden(hide); + sp_document_done(sp_desktop_document(_desktop), SP_VERB_NONE, + hide? _("Hide layer") : _("Unhide layer")); + } +} + +} +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/widget/layer-selector.h b/src/ui/widget/layer-selector.h new file mode 100644 index 000000000..0b5300272 --- /dev/null +++ b/src/ui/widget/layer-selector.h @@ -0,0 +1,110 @@ +/* + * Inkscape::Widgets::LayerSelector - layer selector widget + * + * Authors: + * MenTaLguY <mental@rydia.net> + * + * Copyright (C) 2004 MenTaLguY + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_WIDGETS_LAYER_SELECTOR +#define SEEN_INKSCAPE_WIDGETS_LAYER_SELECTOR + +#include <gtkmm/box.h> +#include <gtkmm/combobox.h> +#include <gtkmm/togglebutton.h> +#include <gtkmm/tooltips.h> +#include <gtkmm/cellrenderertext.h> +#include <gtkmm/treemodel.h> +#include <gtkmm/liststore.h> +#include <sigc++/slot.h> +#include "util/list.h" + +class SPDesktop; +class SPDocument; +class SPObject; +namespace Inkscape { +namespace XML { +class Node; +} +} + + +namespace Inkscape { +namespace Widgets { + +class DocumentTreeModel; + +class LayerSelector : public Gtk::HBox { +public: + LayerSelector(SPDesktop *desktop = NULL); + ~LayerSelector(); + + SPDesktop *desktop() { return _desktop; } + void setDesktop(SPDesktop *desktop); + +private: + class LayerModelColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn<unsigned> depth; + Gtk::TreeModelColumn<SPObject *> object; + Gtk::TreeModelColumn<Inkscape::XML::Node *> repr; + Gtk::TreeModelColumn<void *> callbacks; + + LayerModelColumns() { + add(depth); add(object); add(repr); add(callbacks); + } + }; + + SPDesktop *_desktop; + + Gtk::Tooltips _tooltips; + Gtk::ComboBox _selector; + Gtk::ToggleButton _visibility_toggle; + Gtk::ToggleButton _lock_toggle; + + LayerModelColumns _model_columns; + Gtk::CellRendererText _label_renderer; + Glib::RefPtr<Gtk::ListStore> _layer_model; + +// sigc::connection _desktop_shutdown_connection; + sigc::connection _layer_changed_connection; + sigc::connection _selection_changed_connection; + sigc::connection _visibility_toggled_connection; + sigc::connection _lock_toggled_connection; + + SPObject *_layer; + + void _selectLayer(SPObject *layer); + void _setDesktopLayer(); + + void _buildEntry(unsigned depth, SPObject &object); + void _buildEntries(unsigned depth, + Inkscape::Util::List<SPObject &> hierarchy); + void _buildSiblingEntries(unsigned depth, + SPObject &parent, + Inkscape::Util::List<SPObject &> hierarchy); + void _protectUpdate(sigc::slot<void> slot); + void _destroyEntry(Gtk::ListStore::iterator const &row); + void _hideLayer(bool hide); + void _lockLayer(bool lock); + + void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row); +}; + +} +} + +#endif +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/widget/licensor.cpp b/src/ui/widget/licensor.cpp index 24bd5595f..05f00edfc 100644 --- a/src/ui/widget/licensor.cpp +++ b/src/ui/widget/licensor.cpp @@ -20,7 +20,7 @@ #include "ui/widget/entity-entry.h" #include "ui/widget/registry.h" -#include "dialogs/rdf.h" +#include "rdf.h" #include "inkscape.h" #include "licensor.h" diff --git a/src/ui/widget/panel.cpp b/src/ui/widget/panel.cpp index 9811cc89c..82f75c3ff 100644 --- a/src/ui/widget/panel.cpp +++ b/src/ui/widget/panel.cpp @@ -29,7 +29,7 @@ #include "preferences.h" #include "desktop-handles.h" #include "inkscape.h" -#include "dialogs/eek-preview.h" +#include "widgets/eek-preview.h" namespace Inkscape { namespace UI { |
