Code

4b806afb53981ba3ec3093c8cb830f26381bc7f4
[inkscape.git] / src / ui / widget / panel.cpp
1 /**
2  * \brief Panel widget
3  *
4  * Authors:
5  *   Bryce Harrington <bryce@bryceharrington.org>
6  *   Jon A. Cruz <jon@joncruz.org>
7  *   Gustav Broberg <broberg@kth.se>
8  *
9  * Copyright (C) 2004 Bryce Harrington
10  * Copyright (C) 2005 Jon A. Cruz
11  * Copyright (C) 2007 Gustav Broberg
12  *
13  * Released under GNU GPL.  Read the file 'COPYING' for more information
14  */
16 #ifdef HAVE_CONFIG_H
17 # include <config.h>
18 #endif
20 #include <glibmm/i18n.h>
22 #include <gtkmm/dialog.h> // for Gtk::RESPONSE_*
23 #include <gtkmm/stock.h>
25 #include <gtk/gtkiconfactory.h>
27 #include "panel.h"
28 #include "icon-size.h"
29 #include "preferences.h"
30 #include "desktop-handles.h"
31 #include "inkscape.h"
32 #include "widgets/eek-preview.h"
34 namespace Inkscape {
35 namespace UI {
36 namespace Widget {
38 static const int PANEL_SETTING_SIZE = 0;
39 static const int PANEL_SETTING_MODE = 1;
40 static const int PANEL_SETTING_SHAPE = 2;
41 static const int PANEL_SETTING_WRAP = 3;
42 static const int PANEL_SETTING_NEXTFREE = 4;
45 void Panel::prep() {
46     GtkIconSize sizes[] = {
47         Inkscape::getRegisteredIconSize(Inkscape::ICON_SIZE_DECORATION),
48         GTK_ICON_SIZE_MENU,
49         GTK_ICON_SIZE_SMALL_TOOLBAR,
50         GTK_ICON_SIZE_BUTTON,
51         GTK_ICON_SIZE_DND, // Not used by options, but included to make the last size larger
52         GTK_ICON_SIZE_DIALOG
53     };
54     eek_preview_set_size_mappings( G_N_ELEMENTS(sizes), sizes );
55 }
57 /**
58  *    Construct a Panel
59  */
61 Panel::Panel(Glib::ustring const &label, gchar const *prefs_path,
62              int verb_num, Glib::ustring const &apply_label,
63              bool menu_desired) :
64     _prefs_path(prefs_path),
65     _menu_desired(menu_desired),
66     _desktop(SP_ACTIVE_DESKTOP),
67     _label(label),
68     _apply_label(apply_label),
69     _verb_num(verb_num),
70     _temp_arrow(Gtk::ARROW_LEFT, Gtk::SHADOW_ETCHED_OUT),
71     _menu(0),
72     _action_area(0),
73     _fillable(0)
74 {
75     _init();
76 }
78 Panel::~Panel()
79 {
80     delete _menu;
81 }
83 void Panel::_popper(GdkEventButton* event)
84 {
85     if ( (event->type == GDK_BUTTON_PRESS) && (event->button == 3 || event->button == 1) ) {
86         if (_menu) {
87             _menu->popup(event->button, event->time);
88         }
89     }
90 }
92 void Panel::_init()
93 {
94     Glib::ustring tmp("<");
95     _anchor = Gtk::ANCHOR_CENTER;
97     guint panel_size = 0, panel_mode = 0, panel_ratio = 100;
98     bool panel_wrap = 0;
99     if (!_prefs_path.empty()) {
100         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
101         panel_wrap = prefs->getBool(_prefs_path + "/panel_wrap");
102         panel_size = prefs->getIntLimited(_prefs_path + "/panel_size", 1, 0, PREVIEW_SIZE_HUGE);
103         panel_mode = prefs->getIntLimited(_prefs_path + "/panel_mode", 1, 0, 10);
104         panel_ratio = prefs->getIntLimited(_prefs_path + "/panel_ratio", 100, 0, 500 );
105     }
107     _menu = new Gtk::Menu();
109     {
110         Gtk::RadioMenuItem::Group group;
111         Glib::ustring one_label(_("List"));
112         Glib::ustring two_label(_("Grid"));
113         Gtk::RadioMenuItem *one = manage(new Gtk::RadioMenuItem(group, one_label));
114         Gtk::RadioMenuItem *two = manage(new Gtk::RadioMenuItem(group, two_label));
116         if (panel_mode == 0) {
117             one->set_active(true);
118         } else if (panel_mode == 1) {
119             two->set_active(true);
120         }
122         _menu->append(*one);
123         _non_horizontal.push_back(one);
124         _menu->append(*two);
125         _non_horizontal.push_back(two);
126         Gtk::MenuItem* sep = manage(new Gtk::SeparatorMenuItem());
127         _menu->append(*sep);
128         _non_horizontal.push_back(sep);
129         one->signal_activate().connect(sigc::bind<int, int>(sigc::mem_fun(*this, &Panel::_bounceCall), PANEL_SETTING_MODE, 0));
130         two->signal_activate().connect(sigc::bind<int, int>(sigc::mem_fun(*this, &Panel::_bounceCall), PANEL_SETTING_MODE, 1));
131     }
133     {
134         //TRANSLATORS: only translate "string" in "context|string".
135         // For more details, see http://developer.gnome.org/doc/API/2.0/glib/glib-I18N.html#Q-:CAPS
136         Glib::ustring heightItemLabel(Q_("swatches|Size"));
138         //TRANSLATORS: Indicates size of colour swatches
139         const gchar *heightLabels[] = {
140             N_("tiny"),
141             N_("small"),
142             //TRANSLATORS: only translate "string" in "context|string".
143             // For more details, see http://developer.gnome.org/doc/API/2.0/glib/glib-I18N.html#Q-:CAPS
144             // "medium" indicates size of colour swatches
145             N_("swatchesHeight|medium"),
146             N_("large"),
147             N_("huge")
148         };
150         Gtk::MenuItem *sizeItem = manage(new Gtk::MenuItem(heightItemLabel));
151         Gtk::Menu *sizeMenu = manage(new Gtk::Menu());
152         sizeItem->set_submenu(*sizeMenu);
154         Gtk::RadioMenuItem::Group heightGroup;
155         for (unsigned int i = 0; i < G_N_ELEMENTS(heightLabels); i++) {
156             Glib::ustring _label(Q_(heightLabels[i]));
157             Gtk::RadioMenuItem* _item = manage(new Gtk::RadioMenuItem(heightGroup, _label));
158             sizeMenu->append(*_item);
159             if (i == panel_size) {
160                 _item->set_active(true);
161             }
162             _item->signal_activate().connect(sigc::bind<int, int>(sigc::mem_fun(*this, &Panel::_bounceCall), PANEL_SETTING_SIZE, i));
163        }
165        _menu->append(*sizeItem);
166     }
168     {
169         //TRANSLATORS: only translate "string" in "context|string".
170         // For more details, see http://developer.gnome.org/doc/API/2.0/glib/glib-I18N.html#Q-:CAPS
171         Glib::ustring widthItemLabel(Q_("swatches|Width"));
173         //TRANSLATORS: Indicates width of colour swatches
174         const gchar *widthLabels[] = {
175             N_("narrower"),
176             N_("narrow"),
177             //TRANSLATORS: only translate "string" in "context|string".
178             // For more details, see http://developer.gnome.org/doc/API/2.0/glib/glib-I18N.html#Q-:CAPS
179             // "medium" indicates width of colour swatches
180             N_("swatchesWidth|medium"),
181             N_("wide"),
182             N_("wider")
183         };
185         Gtk::MenuItem *item = manage( new Gtk::MenuItem(widthItemLabel));
186         Gtk::Menu *type_menu = manage(new Gtk::Menu());
187         item->set_submenu(*type_menu);
188         _menu->append(*item);
190         Gtk::RadioMenuItem::Group widthGroup;
192         guint values[] = {0, 25, 50, 100, 200, 400};
193         guint hot_index = 3;
194         for ( guint i = 0; i < G_N_ELEMENTS(widthLabels); ++i ) {
195             // Assume all values are in increasing order
196             if ( values[i] <= panel_ratio ) {
197                 hot_index = i;
198             }
199         }
200         for ( guint i = 0; i < G_N_ELEMENTS(widthLabels); ++i ) {
201             Glib::ustring _label(Q_(widthLabels[i]));
202             Gtk::RadioMenuItem *_item = manage(new Gtk::RadioMenuItem(widthGroup, _label));
203             type_menu->append(*_item);
204             if ( i <= hot_index ) {
205                 _item->set_active(true);
206             }
207             _item->signal_activate().connect(sigc::bind<int, int>(sigc::mem_fun(*this, &Panel::_bounceCall), PANEL_SETTING_SHAPE, values[i]));
208         }
209     }
211     {
212         //TRANSLATORS: only translate "string" in "context|string".
213         // For more details, see http://developer.gnome.org/doc/API/2.0/glib/glib-I18N.html#Q-:CAPS
214         // "Wrap" indicates how colour swatches are displayed
215         Glib::ustring wrap_label(Q_("swatches|Wrap"));
216         Gtk::CheckMenuItem *check = manage(new Gtk::CheckMenuItem(wrap_label));
217         check->set_active(panel_wrap);
218         _menu->append(*check);
219         _non_vertical.push_back(check);
221         check->signal_toggled().connect(sigc::bind<Gtk::CheckMenuItem*>(sigc::mem_fun(*this, &Panel::_wrapToggled), check));
222     }
224     Gtk::SeparatorMenuItem *sep;
225     sep = manage(new Gtk::SeparatorMenuItem());
226     _menu->append(*sep);
228     _menu->show_all_children();
229     for ( std::vector<Gtk::Widget*>::iterator iter = _non_vertical.begin(); iter != _non_vertical.end(); ++iter ) {
230         (*iter)->hide();
231     }
233     // _close_button.set_label("X");
235     if (!_label.empty()) {
236         _tab_title.set_label(_label);
237         _top_bar.pack_start(_tab_title);
238     }
240     // _top_bar.pack_end(_close_button, false, false);
243     if ( _menu_desired ) {
244         _top_bar.pack_end(_menu_popper, false, false);
245         gint width = 0;
246         gint height = 0;
248         if ( gtk_icon_size_lookup( Inkscape::getRegisteredIconSize(Inkscape::ICON_SIZE_DECORATION), &width, &height ) ) {
249             _temp_arrow.set_size_request(width, height);
250         }
252         _menu_popper.add(_temp_arrow);
253         _menu_popper.signal_button_press_event().connect_notify(sigc::mem_fun(*this, &Panel::_popper));
254     }
256     pack_start(_top_bar, false, false);
258     Gtk::HBox* boxy = manage(new Gtk::HBox());
260     boxy->pack_start(_contents, true, true);
261     boxy->pack_start(_right_bar, false, true);
263     pack_start(*boxy, true, true);
265     signalResponse().connect(sigc::mem_fun(*this, &Panel::_handleResponse));
267     signalActivateDesktop().connect(sigc::hide<0>(sigc::mem_fun(*this, &Panel::setDesktop)));
269     show_all_children();
271     _bounceCall(PANEL_SETTING_SIZE, panel_size);
272     _bounceCall(PANEL_SETTING_MODE, panel_mode);
273     _bounceCall(PANEL_SETTING_SHAPE, panel_ratio);
274     _bounceCall(PANEL_SETTING_WRAP, panel_wrap);
277 void Panel::setLabel(Glib::ustring const &label)
279     if (_label.empty() && !label.empty())
280         _top_bar.pack_start(_tab_title);
281     else if (!_label.empty() && label.empty())
282         _top_bar.remove(_tab_title);
284     _label = label;
285     _tab_title.set_label(_label);
288 void Panel::setOrientation(Gtk::AnchorType how)
290     if (_anchor != how) {
291         _anchor = how;
292         switch (_anchor) {
293             case Gtk::ANCHOR_NORTH:
294             case Gtk::ANCHOR_SOUTH:
295             {
296                 if (_menu_desired) {
297                     _menu_popper.reference();
298                     _top_bar.remove(_menu_popper);
299                     _right_bar.pack_start(_menu_popper, false, false);
300                     _menu_popper.unreference();
302                     for (std::vector<Gtk::Widget*>::iterator iter = _non_horizontal.begin(); iter != _non_horizontal.end(); ++iter) {
303                         (*iter)->hide();
304                     }
305                     for (std::vector<Gtk::Widget*>::iterator iter = _non_vertical.begin(); iter != _non_vertical.end(); ++iter) {
306                         (*iter)->show();
307                     }
308                 }
309                 // Ensure we are not in "list" mode
310                 _bounceCall(PANEL_SETTING_MODE, 1);
311                 if (!_label.empty())
312                     _top_bar.remove(_tab_title);
313             }
314             break;
316             default:
317             {
318                 if ( _menu_desired ) {
319                     for (std::vector<Gtk::Widget*>::iterator iter = _non_horizontal.begin(); iter != _non_horizontal.end(); ++iter) {
320                         (*iter)->show();
321                     }
322                     for (std::vector<Gtk::Widget*>::iterator iter = _non_vertical.begin(); iter != _non_vertical.end(); ++iter) {
323                         (*iter)->hide();
324                     }
325                 }
326             }
327         }
328     }
331 void Panel::present()
333     _signal_present.emit();
337 void Panel::restorePanelPrefs()
339     guint panel_size = 0, panel_mode = 0, panel_ratio = 100;
340     bool panel_wrap = 0;
341     if (!_prefs_path.empty()) {
342         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
343         panel_wrap = prefs->getBool(_prefs_path + "/panel_wrap");
344         panel_size = prefs->getIntLimited(_prefs_path + "/panel_size", 1, 0, PREVIEW_SIZE_HUGE);
345         panel_mode = prefs->getIntLimited(_prefs_path + "/panel_mode", 1, 0, 10);
346         panel_ratio = prefs->getIntLimited(_prefs_path + "/panel_ratio", 000, 0, 500 );
347     }
348     _bounceCall(PANEL_SETTING_SIZE, panel_size);
349     _bounceCall(PANEL_SETTING_MODE, panel_mode);
350     _bounceCall(PANEL_SETTING_SHAPE, panel_ratio);
351     _bounceCall(PANEL_SETTING_WRAP, panel_wrap);
354 sigc::signal<void, int> &
355 Panel::signalResponse()
357     return _signal_response;
360 sigc::signal<void> &
361 Panel::signalPresent()
363     return _signal_present;
366 void Panel::_bounceCall(int i, int j)
368     _menu->set_active(0);
369     switch (i) {
370     case PANEL_SETTING_SIZE:
371         if (!_prefs_path.empty()) {
372             Inkscape::Preferences *prefs = Inkscape::Preferences::get();
373             prefs->setInt(_prefs_path + "/panel_size", j);
374         }
375         if (_fillable) {
376             ViewType curr_type = _fillable->getPreviewType();
377             guint curr_ratio = _fillable->getPreviewRatio();
378             switch (j) {
379             case 0:
380             {
381                 _fillable->setStyle(::PREVIEW_SIZE_TINY, curr_type, curr_ratio);
382             }
383             break;
384             case 1:
385             {
386                 _fillable->setStyle(::PREVIEW_SIZE_SMALL, curr_type, curr_ratio);
387             }
388             break;
389             case 2:
390             {
391                 _fillable->setStyle(::PREVIEW_SIZE_MEDIUM, curr_type, curr_ratio);
392             }
393             break;
394             case 3:
395             {
396                 _fillable->setStyle(::PREVIEW_SIZE_BIG, curr_type, curr_ratio);
397             }
398             break;
399             case 4:
400             {
401                 _fillable->setStyle(::PREVIEW_SIZE_HUGE, curr_type, curr_ratio);
402             }
403             break;
404             default:
405                 ;
406             }
407         }
408         break;
409     case PANEL_SETTING_MODE:
410         if (!_prefs_path.empty()) {
411             Inkscape::Preferences *prefs = Inkscape::Preferences::get();
412             prefs->setInt(_prefs_path + "/panel_mode", j);
413         }
414         if (_fillable) {
415             ::PreviewSize curr_size = _fillable->getPreviewSize();
416             guint curr_ratio = _fillable->getPreviewRatio();
417             switch (j) {
418             case 0:
419             {
420                 _fillable->setStyle(curr_size, VIEW_TYPE_LIST, curr_ratio);
421             }
422             break;
423             case 1:
424             {
425                 _fillable->setStyle(curr_size, VIEW_TYPE_GRID, curr_ratio);
426             }
427             break;
428             default:
429                 break;
430             }
431         }
432         break;
433     case PANEL_SETTING_SHAPE:
434         if (!_prefs_path.empty()) {
435             Inkscape::Preferences *prefs = Inkscape::Preferences::get();
436             prefs->setInt(_prefs_path + "/panel_ratio", j);
437         }
438         if ( _fillable ) {
439             ViewType curr_type = _fillable->getPreviewType();
440             ::PreviewSize curr_size = _fillable->getPreviewSize();
441             _fillable->setStyle(curr_size, curr_type, j);
442         }
443         break;
444     case PANEL_SETTING_WRAP:
445         if (!_prefs_path.empty()) {
446             Inkscape::Preferences *prefs = Inkscape::Preferences::get();
447             prefs->setBool(_prefs_path + "/panel_wrap", j);
448         }
449         if ( _fillable ) {
450             _fillable->setWrap(j);
451         }
452         break;
453     default:
454         _handleAction(i - PANEL_SETTING_NEXTFREE, j);
455     }
459 void Panel::_wrapToggled(Gtk::CheckMenuItem* toggler)
461     if (toggler) {
462         _bounceCall(PANEL_SETTING_WRAP, toggler->get_active() ? 1 : 0);
463     }
466 gchar const *Panel::getPrefsPath() const
468     return _prefs_path.data();
471 Glib::ustring const &Panel::getLabel() const
473     return _label;
476 int const &Panel::getVerb() const
478     return _verb_num;
481 Glib::ustring const &Panel::getApplyLabel() const
483     return _apply_label;
486 void Panel::setDesktop(SPDesktop *desktop)
488     _desktop = desktop;
491 void Panel::_setTargetFillable(PreviewFillable *target)
493     _fillable = target;
496 void Panel::_regItem(Gtk::MenuItem* item, int group, int id)
498     _menu->append(*item);
499     item->signal_activate().connect(sigc::bind<int, int>(sigc::mem_fun(*this, &Panel::_bounceCall), group + PANEL_SETTING_NEXTFREE, id));
500     item->show();
503 void Panel::_handleAction(int /*set_id*/, int /*item_id*/)
505 // for subclasses to override
508 void
509 Panel::_apply()
511     g_warning("Apply button clicked for panel [Panel::_apply()]");
514 Gtk::Button *
515 Panel::addResponseButton(const Glib::ustring &button_text, int response_id)
517     Gtk::Button *button = new Gtk::Button(button_text);
518     _addResponseButton(button, response_id);
519     return button;
522 Gtk::Button *
523 Panel::addResponseButton(const Gtk::StockID &stock_id, int response_id)
525     Gtk::Button *button = new Gtk::Button(stock_id);
526     _addResponseButton(button, response_id);
527     return button;
530 void
531 Panel::_addResponseButton(Gtk::Button *button, int response_id)
533     // Create a button box for the response buttons if it's the first button to be added
534     if (!_action_area) {
535         _action_area = new Gtk::HButtonBox(Gtk::BUTTONBOX_END, 6);
536         _action_area->set_border_width(4);
537         pack_end(*_action_area, Gtk::PACK_SHRINK, 0);
538     }
540     _action_area->pack_end(*button);
542     if (response_id != 0) {
543         // Re-emit clicked signals as response signals
544         button->signal_clicked().connect(sigc::bind(_signal_response.make_slot(), response_id));
545         _response_map[response_id] = button;
546     }
549 void
550 Panel::setDefaultResponse(int response_id)
552     ResponseMap::iterator widget_found;
553     widget_found = _response_map.find(response_id);
555     if (widget_found != _response_map.end()) {
556         widget_found->second->activate();
557         widget_found->second->property_can_default() = true;
558         widget_found->second->grab_default();
559     }
562 void
563 Panel::setResponseSensitive(int response_id, bool setting)
565     if (_response_map[response_id])
566         _response_map[response_id]->set_sensitive(setting);
569 sigc::signal<void, SPDesktop *, SPDocument *> &
570 Panel::signalDocumentReplaced()
572     return _signal_document_replaced;
575 sigc::signal<void, Inkscape::Application *, SPDesktop *> &
576 Panel::signalActivateDesktop()
578     return _signal_activate_desktop;
581 sigc::signal<void, Inkscape::Application *, SPDesktop *> &
582 Panel::signalDeactiveDesktop()
584     return _signal_deactive_desktop;
587 void
588 Panel::_handleResponse(int response_id)
590     switch (response_id) {
591         case Gtk::RESPONSE_APPLY: {
592             _apply();
593             break;
594         }
595     }
598 Inkscape::Selection *Panel::_getSelection()
600     return sp_desktop_selection(_desktop);
603 } // namespace Widget
604 } // namespace UI
605 } // namespace Inkscape
607 /*
608   Local Variables:
609   mode:c++
610   c-file-style:"stroustrup"
611   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
612   indent-tabs-mode:nil
613   fill-column:99
614   End:
615 */
616 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :