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 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);
265 }
267 void Panel::setLabel(Glib::ustring const &label)
268 {
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);
276 }
278 void Panel::setOrientation(Gtk::AnchorType how)
279 {
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 }
319 }
321 void Panel::present()
322 {
323 _signal_present.emit();
324 }
327 void Panel::restorePanelPrefs()
328 {
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);
342 }
344 sigc::signal<void, int> &
345 Panel::signalResponse()
346 {
347 return _signal_response;
348 }
350 sigc::signal<void> &
351 Panel::signalPresent()
352 {
353 return _signal_present;
354 }
356 void Panel::_bounceCall(int i, int j)
357 {
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 }
446 }
449 void Panel::_wrapToggled(Gtk::CheckMenuItem* toggler)
450 {
451 if (toggler) {
452 _bounceCall(PANEL_SETTING_WRAP, toggler->get_active() ? 1 : 0);
453 }
454 }
456 gchar const *Panel::getPrefsPath() const
457 {
458 return _prefs_path.data();
459 }
461 Glib::ustring const &Panel::getLabel() const
462 {
463 return _label;
464 }
466 int const &Panel::getVerb() const
467 {
468 return _verb_num;
469 }
471 Glib::ustring const &Panel::getApplyLabel() const
472 {
473 return _apply_label;
474 }
476 void Panel::setDesktop(SPDesktop *desktop)
477 {
478 _desktop = desktop;
479 }
481 void Panel::_setTargetFillable(PreviewFillable *target)
482 {
483 _fillable = target;
484 }
486 void Panel::_regItem(Gtk::MenuItem* item, int group, int id)
487 {
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();
491 }
493 void Panel::_handleAction(int /*set_id*/, int /*item_id*/)
494 {
495 // for subclasses to override
496 }
498 void
499 Panel::_apply()
500 {
501 g_warning("Apply button clicked for panel [Panel::_apply()]");
502 }
504 Gtk::Button *
505 Panel::addResponseButton(const Glib::ustring &button_text, int response_id)
506 {
507 Gtk::Button *button = new Gtk::Button(button_text);
508 _addResponseButton(button, response_id);
509 return button;
510 }
512 Gtk::Button *
513 Panel::addResponseButton(const Gtk::StockID &stock_id, int response_id)
514 {
515 Gtk::Button *button = new Gtk::Button(stock_id);
516 _addResponseButton(button, response_id);
517 return button;
518 }
520 void
521 Panel::_addResponseButton(Gtk::Button *button, int response_id)
522 {
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 }
537 }
539 void
540 Panel::setDefaultResponse(int response_id)
541 {
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 }
550 }
552 void
553 Panel::setResponseSensitive(int response_id, bool setting)
554 {
555 if (_response_map[response_id])
556 _response_map[response_id]->set_sensitive(setting);
557 }
559 sigc::signal<void, SPDesktop *, SPDocument *> &
560 Panel::signalDocumentReplaced()
561 {
562 return _signal_document_replaced;
563 }
565 sigc::signal<void, Inkscape::Application *, SPDesktop *> &
566 Panel::signalActivateDesktop()
567 {
568 return _signal_activate_desktop;
569 }
571 sigc::signal<void, Inkscape::Application *, SPDesktop *> &
572 Panel::signalDeactiveDesktop()
573 {
574 return _signal_deactive_desktop;
575 }
577 void
578 Panel::_handleResponse(int response_id)
579 {
580 switch (response_id) {
581 case Gtk::RESPONSE_APPLY: {
582 _apply();
583 break;
584 }
585 }
586 }
588 Inkscape::Selection *Panel::_getSelection()
589 {
590 return sp_desktop_selection(_desktop);
591 }
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 :