Code

From trunk
[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 "dialogs/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         Glib::ustring heightItemLabel(Q_("swatches|Size"));
136         //TRANSLATORS: Indicates size of colour swatches
137         const gchar *heightLabels[] = {
138             N_("tiny"),
139             N_("small"),
140             //TRANSLATORS: Translate only the word "medium". Indicates size of colour swatches
141             N_("swatchesHeight|medium"),
142             N_("large"),
143             N_("huge")
144         };
146         Gtk::MenuItem *sizeItem = manage(new Gtk::MenuItem(heightItemLabel));
147         Gtk::Menu *sizeMenu = manage(new Gtk::Menu());
148         sizeItem->set_submenu(*sizeMenu);
150         Gtk::RadioMenuItem::Group heightGroup;
151         for (unsigned int i = 0; i < G_N_ELEMENTS(heightLabels); i++) {
152             Glib::ustring _label(Q_(heightLabels[i]));
153             Gtk::RadioMenuItem* _item = manage(new Gtk::RadioMenuItem(heightGroup, _label));
154             sizeMenu->append(*_item);
155             if (i == panel_size) {
156                 _item->set_active(true);
157             }
158             _item->signal_activate().connect(sigc::bind<int, int>(sigc::mem_fun(*this, &Panel::_bounceCall), PANEL_SETTING_SIZE, i));
159        }
161        _menu->append(*sizeItem);
162     }
164     {
165         Glib::ustring widthItemLabel(Q_("swatches|Width"));
167         //TRANSLATORS: Indicates width of colour swatches
168         const gchar *widthLabels[] = {
169             N_("narrower"),
170             N_("narrow"),
171             //TRANSLATORS: Translate only the word "medium". Indicates width of colour swatches
172             N_("swatchesWidth|medium"),
173             N_("wide"),
174             N_("wider")
175         };
177         Gtk::MenuItem *item = manage( new Gtk::MenuItem(widthItemLabel));
178         Gtk::Menu *type_menu = manage(new Gtk::Menu());
179         item->set_submenu(*type_menu);
180         _menu->append(*item);
182         Gtk::RadioMenuItem::Group widthGroup;
184         guint values[] = {0, 25, 50, 100, 200, 400};
185         guint hot_index = 3;
186         for ( guint i = 0; i < G_N_ELEMENTS(widthLabels); ++i ) {
187             // Assume all values are in increasing order
188             if ( values[i] <= panel_ratio ) {
189                 hot_index = i;
190             }
191         }
192         for ( guint i = 0; i < G_N_ELEMENTS(widthLabels); ++i ) {
193                 Glib::ustring _label(Q_(widthLabels[i]));
194             Gtk::RadioMenuItem *_item = manage(new Gtk::RadioMenuItem(widthGroup, _label));
195             type_menu->append(*_item);
196             if ( i <= hot_index ) {
197                 _item->set_active(true);
198             }
199             _item->signal_activate().connect(sigc::bind<int, int>(sigc::mem_fun(*this, &Panel::_bounceCall), PANEL_SETTING_SHAPE, values[i]));
200         }
201     }
203     {
204         //TRANSLATORS: Translate only the word "Wrap". Indicates how colour swatches are displayed
205         Glib::ustring wrap_label(Q_("swatches|Wrap"));
206         Gtk::CheckMenuItem *check = manage(new Gtk::CheckMenuItem(wrap_label));
207         check->set_active(panel_wrap);
208         _menu->append(*check);
209         _non_vertical.push_back(check);
211         check->signal_toggled().connect(sigc::bind<Gtk::CheckMenuItem*>(sigc::mem_fun(*this, &Panel::_wrapToggled), check));
212     }
214     Gtk::SeparatorMenuItem *sep;
215     sep = manage(new Gtk::SeparatorMenuItem());
216     _menu->append(*sep);
218     _menu->show_all_children();
219     for ( std::vector<Gtk::Widget*>::iterator iter = _non_vertical.begin(); iter != _non_vertical.end(); ++iter ) {
220         (*iter)->hide();
221     }
223     // _close_button.set_label("X");
225     if (!_label.empty()) {
226         _tab_title.set_label(_label);
227         _top_bar.pack_start(_tab_title);
228     }
230     // _top_bar.pack_end(_close_button, false, false);
233     if ( _menu_desired ) {
234         _top_bar.pack_end(_menu_popper, false, false);
235         gint width = 0;
236         gint height = 0;
238         if ( gtk_icon_size_lookup( Inkscape::getRegisteredIconSize(Inkscape::ICON_SIZE_DECORATION), &width, &height ) ) {
239             _temp_arrow.set_size_request(width, height);
240         }
242         _menu_popper.add(_temp_arrow);
243         _menu_popper.signal_button_press_event().connect_notify(sigc::mem_fun(*this, &Panel::_popper));
244     }
246     pack_start(_top_bar, false, false);
248     Gtk::HBox* boxy = manage(new Gtk::HBox());
250     boxy->pack_start(_contents, true, true);
251     boxy->pack_start(_right_bar, false, true);
253     pack_start(*boxy, true, true);
255     signalResponse().connect(sigc::mem_fun(*this, &Panel::_handleResponse));
257     signalActivateDesktop().connect(sigc::hide<0>(sigc::mem_fun(*this, &Panel::setDesktop)));
259     show_all_children();
261     _bounceCall(PANEL_SETTING_SIZE, panel_size);
262     _bounceCall(PANEL_SETTING_MODE, panel_mode);
263     _bounceCall(PANEL_SETTING_SHAPE, panel_ratio);
264     _bounceCall(PANEL_SETTING_WRAP, panel_wrap);
267 void Panel::setLabel(Glib::ustring const &label)
269     if (_label.empty() && !label.empty())
270         _top_bar.pack_start(_tab_title);
271     else if (!_label.empty() && label.empty())
272         _top_bar.remove(_tab_title);
274     _label = label;
275     _tab_title.set_label(_label);
278 void Panel::setOrientation(Gtk::AnchorType how)
280     if (_anchor != how) {
281         _anchor = how;
282         switch (_anchor) {
283             case Gtk::ANCHOR_NORTH:
284             case Gtk::ANCHOR_SOUTH:
285             {
286                 if (_menu_desired) {
287                     _menu_popper.reference();
288                     _top_bar.remove(_menu_popper);
289                     _right_bar.pack_start(_menu_popper, false, false);
290                     _menu_popper.unreference();
292                     for (std::vector<Gtk::Widget*>::iterator iter = _non_horizontal.begin(); iter != _non_horizontal.end(); ++iter) {
293                         (*iter)->hide();
294                     }
295                     for (std::vector<Gtk::Widget*>::iterator iter = _non_vertical.begin(); iter != _non_vertical.end(); ++iter) {
296                         (*iter)->show();
297                     }
298                 }
299                 // Ensure we are not in "list" mode
300                 _bounceCall(PANEL_SETTING_MODE, 1);
301                 if (!_label.empty())
302                     _top_bar.remove(_tab_title);
303             }
304             break;
306             default:
307             {
308                 if ( _menu_desired ) {
309                     for (std::vector<Gtk::Widget*>::iterator iter = _non_horizontal.begin(); iter != _non_horizontal.end(); ++iter) {
310                         (*iter)->show();
311                     }
312                     for (std::vector<Gtk::Widget*>::iterator iter = _non_vertical.begin(); iter != _non_vertical.end(); ++iter) {
313                         (*iter)->hide();
314                     }
315                 }
316             }
317         }
318     }
321 void Panel::present()
323     _signal_present.emit();
327 void Panel::restorePanelPrefs()
329     guint panel_size = 0, panel_mode = 0, panel_ratio = 100;
330     bool panel_wrap = 0;
331     if (!_prefs_path.empty()) {
332         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
333         panel_wrap = prefs->getBool(_prefs_path + "/panel_wrap");
334         panel_size = prefs->getIntLimited(_prefs_path + "/panel_size", 1, 0, PREVIEW_SIZE_HUGE);
335         panel_mode = prefs->getIntLimited(_prefs_path + "/panel_mode", 1, 0, 10);
336         panel_ratio = prefs->getIntLimited(_prefs_path + "/panel_ratio", 000, 0, 500 );
337     }
338     _bounceCall(PANEL_SETTING_SIZE, panel_size);
339     _bounceCall(PANEL_SETTING_MODE, panel_mode);
340     _bounceCall(PANEL_SETTING_SHAPE, panel_ratio);
341     _bounceCall(PANEL_SETTING_WRAP, panel_wrap);
344 sigc::signal<void, int> &
345 Panel::signalResponse()
347     return _signal_response;
350 sigc::signal<void> &
351 Panel::signalPresent()
353     return _signal_present;
356 void Panel::_bounceCall(int i, int j)
358     _menu->set_active(0);
359     switch (i) {
360     case PANEL_SETTING_SIZE:
361         if (!_prefs_path.empty()) {
362             Inkscape::Preferences *prefs = Inkscape::Preferences::get();
363             prefs->setInt(_prefs_path + "/panel_size", j);
364         }
365         if (_fillable) {
366             ViewType curr_type = _fillable->getPreviewType();
367             guint curr_ratio = _fillable->getPreviewRatio();
368             switch (j) {
369             case 0:
370             {
371                 _fillable->setStyle(::PREVIEW_SIZE_TINY, curr_type, curr_ratio);
372             }
373             break;
374             case 1:
375             {
376                 _fillable->setStyle(::PREVIEW_SIZE_SMALL, curr_type, curr_ratio);
377             }
378             break;
379             case 2:
380             {
381                 _fillable->setStyle(::PREVIEW_SIZE_MEDIUM, curr_type, curr_ratio);
382             }
383             break;
384             case 3:
385             {
386                 _fillable->setStyle(::PREVIEW_SIZE_BIG, curr_type, curr_ratio);
387             }
388             break;
389             case 4:
390             {
391                 _fillable->setStyle(::PREVIEW_SIZE_HUGE, curr_type, curr_ratio);
392             }
393             break;
394             default:
395                 ;
396             }
397         }
398         break;
399     case PANEL_SETTING_MODE:
400         if (!_prefs_path.empty()) {
401             Inkscape::Preferences *prefs = Inkscape::Preferences::get();
402             prefs->setInt(_prefs_path + "/panel_mode", j);
403         }
404         if (_fillable) {
405             ::PreviewSize curr_size = _fillable->getPreviewSize();
406             guint curr_ratio = _fillable->getPreviewRatio();
407             switch (j) {
408             case 0:
409             {
410                 _fillable->setStyle(curr_size, VIEW_TYPE_LIST, curr_ratio);
411             }
412             break;
413             case 1:
414             {
415                 _fillable->setStyle(curr_size, VIEW_TYPE_GRID, curr_ratio);
416             }
417             break;
418             default:
419                 break;
420             }
421         }
422         break;
423     case PANEL_SETTING_SHAPE:
424         if (!_prefs_path.empty()) {
425             Inkscape::Preferences *prefs = Inkscape::Preferences::get();
426             prefs->setInt(_prefs_path + "/panel_ratio", j);
427         }
428         if ( _fillable ) {
429             ViewType curr_type = _fillable->getPreviewType();
430             ::PreviewSize curr_size = _fillable->getPreviewSize();
431             _fillable->setStyle(curr_size, curr_type, j);
432         }
433         break;
434     case PANEL_SETTING_WRAP:
435         if (!_prefs_path.empty()) {
436             Inkscape::Preferences *prefs = Inkscape::Preferences::get();
437             prefs->setBool(_prefs_path + "/panel_wrap", j);
438         }
439         if ( _fillable ) {
440             _fillable->setWrap(j);
441         }
442         break;
443     default:
444         _handleAction(i - PANEL_SETTING_NEXTFREE, j);
445     }
449 void Panel::_wrapToggled(Gtk::CheckMenuItem* toggler)
451     if (toggler) {
452         _bounceCall(PANEL_SETTING_WRAP, toggler->get_active() ? 1 : 0);
453     }
456 gchar const *Panel::getPrefsPath() const
458     return _prefs_path.data();
461 Glib::ustring const &Panel::getLabel() const
463     return _label;
466 int const &Panel::getVerb() const
468     return _verb_num;
471 Glib::ustring const &Panel::getApplyLabel() const
473     return _apply_label;
476 void Panel::setDesktop(SPDesktop *desktop)
478     _desktop = desktop;
481 void Panel::_setTargetFillable(PreviewFillable *target)
483     _fillable = target;
486 void Panel::_regItem(Gtk::MenuItem* item, int group, int id)
488     _menu->append(*item);
489     item->signal_activate().connect(sigc::bind<int, int>(sigc::mem_fun(*this, &Panel::_bounceCall), group + PANEL_SETTING_NEXTFREE, id));
490     item->show();
493 void Panel::_handleAction(int /*set_id*/, int /*item_id*/)
495 // for subclasses to override
498 void
499 Panel::_apply()
501     g_warning("Apply button clicked for panel [Panel::_apply()]");
504 Gtk::Button *
505 Panel::addResponseButton(const Glib::ustring &button_text, int response_id)
507     Gtk::Button *button = new Gtk::Button(button_text);
508     _addResponseButton(button, response_id);
509     return button;
512 Gtk::Button *
513 Panel::addResponseButton(const Gtk::StockID &stock_id, int response_id)
515     Gtk::Button *button = new Gtk::Button(stock_id);
516     _addResponseButton(button, response_id);
517     return button;
520 void
521 Panel::_addResponseButton(Gtk::Button *button, int response_id)
523     // Create a button box for the response buttons if it's the first button to be added
524     if (!_action_area) {
525         _action_area = new Gtk::HButtonBox(Gtk::BUTTONBOX_END, 6);
526         _action_area->set_border_width(4);
527         pack_end(*_action_area, Gtk::PACK_SHRINK, 0);
528     }
530     _action_area->pack_end(*button);
532     if (response_id != 0) {
533         // Re-emit clicked signals as response signals
534         button->signal_clicked().connect(sigc::bind(_signal_response.make_slot(), response_id));
535         _response_map[response_id] = button;
536     }
539 void
540 Panel::setDefaultResponse(int response_id)
542     ResponseMap::iterator widget_found;
543     widget_found = _response_map.find(response_id);
545     if (widget_found != _response_map.end()) {
546         widget_found->second->activate();
547         widget_found->second->property_can_default() = true;
548         widget_found->second->grab_default();
549     }
552 void
553 Panel::setResponseSensitive(int response_id, bool setting)
555     if (_response_map[response_id])
556         _response_map[response_id]->set_sensitive(setting);
559 sigc::signal<void, SPDesktop *, SPDocument *> &
560 Panel::signalDocumentReplaced()
562     return _signal_document_replaced;
565 sigc::signal<void, Inkscape::Application *, SPDesktop *> &
566 Panel::signalActivateDesktop()
568     return _signal_activate_desktop;
571 sigc::signal<void, Inkscape::Application *, SPDesktop *> &
572 Panel::signalDeactiveDesktop()
574     return _signal_deactive_desktop;
577 void
578 Panel::_handleResponse(int response_id)
580     switch (response_id) {
581         case Gtk::RESPONSE_APPLY: {
582             _apply();
583             break;
584         }
585     }
588 Inkscape::Selection *Panel::_getSelection()
590     return sp_desktop_selection(_desktop);
593 } // namespace Widget
594 } // namespace UI
595 } // namespace Inkscape
597 /*
598   Local Variables:
599   mode:c++
600   c-file-style:"stroustrup"
601   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
602   indent-tabs-mode:nil
603   fill-column:99
604   End:
605 */
606 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :