7b24c00cd61a73b6dac40a9d3f0ae713606d8879
1 /**
2 * \brief A custom Inkscape wrapper around gdl_dock_item
3 *
4 * Author:
5 * Gustav Broberg <broberg@kth.se>
6 *
7 * Copyright (C) 2007 Authors
8 *
9 * Released under GNU GPL. Read the file 'COPYING' for more information.
10 */
12 #include <gtk/gtk.h>
13 #include <gtkmm.h>
15 #include "dock-item.h"
16 #include "desktop.h"
17 #include "inkscape.h"
18 #include "preferences.h"
19 #include "ui/widget/dock.h"
20 #include "widgets/icon.h"
22 namespace Inkscape {
23 namespace UI {
24 namespace Widget {
26 DockItem::DockItem(Dock& dock, const Glib::ustring& name, const Glib::ustring& long_name,
27 const Glib::ustring& icon_name, State state) :
28 _dock(dock),
29 _prev_state(state),
30 _prev_position(0),
31 _window(0),
32 _x(0),
33 _y(0),
34 _grab_focus_on_realize(false),
35 _gdl_dock_item(0),
36 _dock_item_action_area(0)
37 {
38 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
39 GdlDockItemBehavior gdl_dock_behavior =
40 (prefs->getBool("/options/dock/cancenterdock", true) ?
41 GDL_DOCK_ITEM_BEH_NORMAL :
42 GDL_DOCK_ITEM_BEH_CANT_DOCK_CENTER);
44 if (!icon_name.empty()) {
45 int width = 0, height = 0;
46 Gtk::IconSize::lookup(Gtk::ICON_SIZE_MENU, width, height);
47 try {
48 _icon_pixbuf = Gtk::IconTheme::get_default()->load_icon(icon_name, width, (Gtk::IconLookupFlags) 0);
49 _gdl_dock_item =
50 gdl_dock_item_new_with_pixbuf_icon(name.c_str(), long_name.c_str(),
51 _icon_pixbuf->gobj(), gdl_dock_behavior);
52 } catch (Gtk::IconThemeError) {
53 // ignore - create the dock item without an icon below
54 }
55 }
57 if (!_gdl_dock_item) {
58 _gdl_dock_item =
59 gdl_dock_item_new(name.c_str(), long_name.c_str(), gdl_dock_behavior);
60 }
62 _frame.set_shadow_type(Gtk::SHADOW_IN);
63 gtk_container_add (GTK_CONTAINER (_gdl_dock_item), GTK_WIDGET (_frame.gobj()));
64 _frame.add(_dock_item_box);
65 _dock_item_box.set_border_width(3);
67 signal_drag_begin().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDragBegin));
68 signal_drag_end().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDragEnd));
69 signal_hide().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onHide), false);
70 signal_show().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onShow), false);
71 signal_state_changed().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onStateChanged));
72 signal_delete_event().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDeleteEvent));
73 signal_realize().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onRealize));
75 _dock.addItem(*this, (_prev_state == FLOATING_STATE ? FLOATING : TOP));
77 show_all();
78 }
80 DockItem::~DockItem()
81 {
82 g_free(_gdl_dock_item);
83 }
85 Gtk::Widget&
86 DockItem::getWidget()
87 {
88 return *Glib::wrap(GTK_WIDGET(_gdl_dock_item));
89 }
91 GtkWidget *
92 DockItem::gobj()
93 {
94 return _gdl_dock_item;
95 }
97 Gtk::VBox *
98 DockItem::get_vbox()
99 {
100 return &_dock_item_box;
101 }
104 void
105 DockItem::get_position(int& x, int& y)
106 {
107 if (getWindow()) {
108 getWindow()->get_position(x, y);
109 } else {
110 x = _x;
111 y = _y;
112 }
113 }
115 void
116 DockItem::get_size(int& width, int& height)
117 {
118 if (_window) {
119 _window->get_size(width, height);
120 } else {
121 width = get_vbox()->get_width();
122 height = get_vbox()->get_height();
123 }
124 }
127 void
128 DockItem::resize(int width, int height)
129 {
130 if (_window)
131 _window->resize(width, height);
132 }
135 void
136 DockItem::move(int x, int y)
137 {
138 if (_window)
139 _window->move(x, y);
140 }
142 void
143 DockItem::set_position(Gtk::WindowPosition position)
144 {
145 if (_window)
146 _window->set_position(position);
147 }
149 void
150 DockItem::set_size_request(int width, int height)
151 {
152 getWidget().set_size_request(width, height);
153 }
155 void
156 DockItem::size_request(Gtk::Requisition& requisition)
157 {
158 getWidget().size_request(requisition);
159 }
161 void
162 DockItem::set_title(Glib::ustring title)
163 {
164 g_object_set (_gdl_dock_item,
165 "long-name", title.c_str(),
166 NULL);
168 gdl_dock_item_set_tablabel(GDL_DOCK_ITEM(_gdl_dock_item),
169 gtk_label_new (title.c_str()));
170 }
172 bool
173 DockItem::isAttached() const
174 {
175 return GDL_DOCK_OBJECT_ATTACHED (_gdl_dock_item);
176 }
179 bool
180 DockItem::isFloating() const
181 {
182 return (GTK_WIDGET(gdl_dock_object_get_toplevel(GDL_DOCK_OBJECT (_gdl_dock_item))) !=
183 _dock.getGdlWidget());
184 }
186 bool
187 DockItem::isIconified() const
188 {
189 return GDL_DOCK_ITEM_ICONIFIED (_gdl_dock_item);
190 }
192 DockItem::State
193 DockItem::getState() const
194 {
195 return (isAttached() ? (isFloating() ? FLOATING_STATE : DOCKED_STATE) : UNATTACHED);
196 }
198 DockItem::State
199 DockItem::getPrevState() const
200 {
201 return _prev_state;
202 }
204 DockItem::Placement
205 DockItem::getPlacement() const
206 {
207 GdlDockPlacement placement = (GdlDockPlacement)NONE;
208 gdl_dock_object_child_placement(gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT(_gdl_dock_item)),
209 GDL_DOCK_OBJECT(_gdl_dock_item),
210 &placement);
211 return (Placement)placement;
212 }
214 void
215 DockItem::hide()
216 {
217 gdl_dock_item_hide_item (GDL_DOCK_ITEM(_gdl_dock_item));
218 }
220 void
221 DockItem::show()
222 {
223 gdl_dock_item_show_item (GDL_DOCK_ITEM(_gdl_dock_item));
224 }
226 void
227 DockItem::show_all()
228 {
229 gtk_widget_show_all(_gdl_dock_item);
230 }
232 void
233 DockItem::present()
234 {
236 if (isIconified() || !isAttached()) {
237 show();
238 }
240 // tabbed
241 else if (getPlacement() == CENTER) {
242 int i = gtk_notebook_page_num (GTK_NOTEBOOK (_gdl_dock_item->parent),
243 GTK_WIDGET (_gdl_dock_item));
244 if (i >= 0)
245 gtk_notebook_set_current_page (GTK_NOTEBOOK (_gdl_dock_item->parent), i);
246 }
248 // always grab focus, even if we're already present
249 grab_focus();
251 if (!isFloating() && getWidget().is_realized())
252 _dock.scrollToItem(*this);
253 }
256 void
257 DockItem::grab_focus()
258 {
259 if (GTK_WIDGET_REALIZED (_gdl_dock_item)) {
261 // make sure the window we're in is present
262 Gtk::Widget *toplevel = getWidget().get_toplevel();
263 if (Gtk::Window *window = dynamic_cast<Gtk::Window *>(toplevel)) {
264 window->present();
265 }
267 gtk_widget_grab_focus (_gdl_dock_item);
269 } else {
270 _grab_focus_on_realize = true;
271 }
272 }
275 /* Signal wrappers */
277 Glib::SignalProxy0<void>
278 DockItem::signal_show()
279 {
280 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
281 &_signal_show_proxy);
282 }
284 Glib::SignalProxy0<void>
285 DockItem::signal_hide()
286 {
287 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
288 &_signal_hide_proxy);
289 }
291 Glib::SignalProxy1<bool, GdkEventAny *>
292 DockItem::signal_delete_event()
293 {
294 return Glib::SignalProxy1<bool, GdkEventAny *>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
295 &_signal_delete_event_proxy);
296 }
298 Glib::SignalProxy0<void>
299 DockItem::signal_drag_begin()
300 {
301 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
302 &_signal_drag_begin_proxy);
303 }
305 Glib::SignalProxy1<void, bool>
306 DockItem::signal_drag_end()
307 {
308 return Glib::SignalProxy1<void, bool>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
309 &_signal_drag_end_proxy);
310 }
312 Glib::SignalProxy0<void>
313 DockItem::signal_realize()
314 {
315 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
316 &_signal_realize_proxy);
317 }
319 sigc::signal<void, DockItem::State, DockItem::State>
320 DockItem::signal_state_changed()
321 {
322 return _signal_state_changed;
323 }
325 void
326 DockItem::_onHideWindow()
327 {
328 if (_window)
329 _window->get_position(_x, _y);
330 }
332 void
333 DockItem::_onHide()
334 {
335 _signal_state_changed.emit(UNATTACHED, getState());
336 }
338 void
339 DockItem::_onShow()
340 {
341 _signal_state_changed.emit(UNATTACHED, getState());
342 }
344 void
345 DockItem::_onDragBegin()
346 {
347 _prev_state = getState();
348 if (_prev_state == FLOATING_STATE)
349 _dock.toggleDockable(getWidget().get_width(), getWidget().get_height());
350 }
352 void
353 DockItem::_onDragEnd(bool)
354 {
355 State state = getState();
357 if (state != _prev_state)
358 _signal_state_changed.emit(_prev_state, state);
360 if (state == FLOATING_STATE) {
361 if (_prev_state == FLOATING_STATE)
362 _dock.toggleDockable();
363 }
365 _prev_state = state;
366 }
368 void
369 DockItem::_onRealize()
370 {
371 if (_grab_focus_on_realize) {
372 _grab_focus_on_realize = false;
373 grab_focus();
374 }
375 }
377 bool
378 DockItem::_onKeyPress(GdkEventKey *event)
379 {
380 gboolean return_value;
381 g_signal_emit_by_name (_gdl_dock_item, "key_press_event", event, &return_value);
382 return return_value;
383 }
385 void
386 DockItem::_onStateChanged(State /*prev_state*/, State new_state)
387 {
388 _window = getWindow();
390 if (new_state == FLOATING_STATE && _window) {
391 _window->signal_hide().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onHideWindow));
392 _signal_key_press_event_connection =
393 _window->signal_key_press_event().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onKeyPress));
394 }
395 }
398 bool
399 DockItem::_onDeleteEvent(GdkEventAny */*event*/)
400 {
401 hide();
402 return false;
403 }
406 Gtk::Window *
407 DockItem::getWindow()
408 {
409 g_return_val_if_fail(_gdl_dock_item, 0);
410 Gtk::Container *parent = getWidget().get_parent();
411 parent = (parent ? parent->get_parent() : 0);
412 return (parent ? dynamic_cast<Gtk::Window *>(parent) : 0);
413 }
415 const Glib::SignalProxyInfo
416 DockItem::_signal_show_proxy =
417 {
418 "show",
419 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
420 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
421 };
423 const Glib::SignalProxyInfo
424 DockItem::_signal_hide_proxy =
425 {
426 "hide",
427 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
428 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
429 };
432 const Glib::SignalProxyInfo
433 DockItem::_signal_delete_event_proxy =
434 {
435 "delete_event",
436 (GCallback) &_signal_delete_event_callback,
437 (GCallback) &_signal_delete_event_callback
438 };
441 const Glib::SignalProxyInfo
442 DockItem::_signal_drag_begin_proxy =
443 {
444 "dock-drag-begin",
445 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
446 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
447 };
450 const Glib::SignalProxyInfo
451 DockItem::_signal_drag_end_proxy =
452 {
453 "dock_drag_end",
454 (GCallback) &_signal_drag_end_callback,
455 (GCallback) &_signal_drag_end_callback
456 };
459 const Glib::SignalProxyInfo
460 DockItem::_signal_realize_proxy =
461 {
462 "realize",
463 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
464 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
465 };
468 gboolean
469 DockItem::_signal_delete_event_callback(GtkWidget *self, GdkEventAny *event, void *data)
470 {
471 using namespace Gtk;
472 typedef sigc::slot<bool, GdkEventAny *> SlotType;
474 if (Glib::ObjectBase::_get_current_wrapper((GObject *) self)) {
475 try {
476 if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
477 return static_cast<int>( (*static_cast<SlotType*>(slot))(event) );
478 } catch(...) {
479 Glib::exception_handlers_invoke();
480 }
481 }
483 typedef gboolean RType;
484 return RType();
485 }
487 void
488 DockItem::_signal_drag_end_callback(GtkWidget *self, gboolean cancelled, void *data)
489 {
490 using namespace Gtk;
491 typedef sigc::slot<void, bool> SlotType;
493 if (Glib::ObjectBase::_get_current_wrapper((GObject *) self)) {
494 try {
495 if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
496 (*static_cast<SlotType *>(slot))(cancelled);
497 } catch(...) {
498 Glib::exception_handlers_invoke();
499 }
500 }
501 }
504 } // namespace Widget
505 } // namespace UI
506 } // namespace Inkscape
508 /*
509 Local Variables:
510 mode:c++
511 c-file-style:"stroustrup"
512 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
513 indent-tabs-mode:nil
514 fill-column:99
515 End:
516 */
517 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :