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 _icon_pixbuf = Gtk::IconTheme::get_default()->load_icon(icon_name, width, (Gtk::IconLookupFlags) 0);
48 _gdl_dock_item =
49 gdl_dock_item_new_with_pixbuf_icon(name.c_str(), long_name.c_str(),
50 _icon_pixbuf->gobj(), gdl_dock_behavior);
51 } else {
52 _gdl_dock_item =
53 gdl_dock_item_new(name.c_str(), long_name.c_str(), gdl_dock_behavior);
54 }
56 _frame.set_shadow_type(Gtk::SHADOW_IN);
57 gtk_container_add (GTK_CONTAINER (_gdl_dock_item), GTK_WIDGET (_frame.gobj()));
58 _frame.add(_dock_item_box);
59 _dock_item_box.set_border_width(3);
61 signal_drag_begin().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDragBegin));
62 signal_drag_end().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDragEnd));
63 signal_hide().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onHide), false);
64 signal_show().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onShow), false);
65 signal_state_changed().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onStateChanged));
66 signal_delete_event().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDeleteEvent));
67 signal_realize().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onRealize));
69 _dock.addItem(*this, (_prev_state == FLOATING_STATE ? FLOATING : TOP));
71 show_all();
72 }
74 DockItem::~DockItem()
75 {
76 g_free(_gdl_dock_item);
77 }
79 Gtk::Widget&
80 DockItem::getWidget()
81 {
82 return *Glib::wrap(GTK_WIDGET(_gdl_dock_item));
83 }
85 GtkWidget *
86 DockItem::gobj()
87 {
88 return _gdl_dock_item;
89 }
91 Gtk::VBox *
92 DockItem::get_vbox()
93 {
94 return &_dock_item_box;
95 }
98 void
99 DockItem::get_position(int& x, int& y)
100 {
101 if (getWindow()) {
102 getWindow()->get_position(x, y);
103 } else {
104 x = _x;
105 y = _y;
106 }
107 }
109 void
110 DockItem::get_size(int& width, int& height)
111 {
112 if (_window) {
113 _window->get_size(width, height);
114 } else {
115 width = get_vbox()->get_width();
116 height = get_vbox()->get_height();
117 }
118 }
121 void
122 DockItem::resize(int width, int height)
123 {
124 if (_window)
125 _window->resize(width, height);
126 }
129 void
130 DockItem::move(int x, int y)
131 {
132 if (_window)
133 _window->move(x, y);
134 }
136 void
137 DockItem::set_position(Gtk::WindowPosition position)
138 {
139 if (_window)
140 _window->set_position(position);
141 }
143 void
144 DockItem::set_size_request(int width, int height)
145 {
146 getWidget().set_size_request(width, height);
147 }
149 void
150 DockItem::size_request(Gtk::Requisition& requisition)
151 {
152 getWidget().size_request(requisition);
153 }
155 void
156 DockItem::set_title(Glib::ustring title)
157 {
158 g_object_set (_gdl_dock_item,
159 "long-name", title.c_str(),
160 NULL);
162 gdl_dock_item_set_tablabel(GDL_DOCK_ITEM(_gdl_dock_item),
163 gtk_label_new (title.c_str()));
164 }
166 bool
167 DockItem::isAttached() const
168 {
169 return GDL_DOCK_OBJECT_ATTACHED (_gdl_dock_item);
170 }
173 bool
174 DockItem::isFloating() const
175 {
176 return (GTK_WIDGET(gdl_dock_object_get_toplevel(GDL_DOCK_OBJECT (_gdl_dock_item))) !=
177 _dock.getGdlWidget());
178 }
180 bool
181 DockItem::isIconified() const
182 {
183 return GDL_DOCK_ITEM_ICONIFIED (_gdl_dock_item);
184 }
186 DockItem::State
187 DockItem::getState() const
188 {
189 return (isAttached() ? (isFloating() ? FLOATING_STATE : DOCKED_STATE) : UNATTACHED);
190 }
192 DockItem::State
193 DockItem::getPrevState() const
194 {
195 return _prev_state;
196 }
198 DockItem::Placement
199 DockItem::getPlacement() const
200 {
201 GdlDockPlacement placement = (GdlDockPlacement)NONE;
202 gdl_dock_object_child_placement(gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT(_gdl_dock_item)),
203 GDL_DOCK_OBJECT(_gdl_dock_item),
204 &placement);
205 return (Placement)placement;
206 }
208 void
209 DockItem::hide()
210 {
211 gdl_dock_item_hide_item (GDL_DOCK_ITEM(_gdl_dock_item));
212 }
214 void
215 DockItem::show()
216 {
217 gdl_dock_item_show_item (GDL_DOCK_ITEM(_gdl_dock_item));
218 }
220 void
221 DockItem::show_all()
222 {
223 gtk_widget_show_all(_gdl_dock_item);
224 }
226 void
227 DockItem::present()
228 {
230 if (isIconified() || !isAttached()) {
231 show();
232 }
234 // tabbed
235 else if (getPlacement() == CENTER) {
236 int i = gtk_notebook_page_num (GTK_NOTEBOOK (_gdl_dock_item->parent),
237 GTK_WIDGET (_gdl_dock_item));
238 if (i >= 0)
239 gtk_notebook_set_current_page (GTK_NOTEBOOK (_gdl_dock_item->parent), i);
240 }
242 // always grab focus, even if we're already present
243 grab_focus();
245 if (!isFloating() && getWidget().is_realized())
246 _dock.scrollToItem(*this);
247 }
250 void
251 DockItem::grab_focus()
252 {
253 if (GTK_WIDGET_REALIZED (_gdl_dock_item)) {
255 // make sure the window we're in is present
256 Gtk::Widget *toplevel = getWidget().get_toplevel();
257 if (Gtk::Window *window = dynamic_cast<Gtk::Window *>(toplevel)) {
258 window->present();
259 }
261 gtk_widget_grab_focus (_gdl_dock_item);
263 } else {
264 _grab_focus_on_realize = true;
265 }
266 }
269 /* Signal wrappers */
271 Glib::SignalProxy0<void>
272 DockItem::signal_show()
273 {
274 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
275 &_signal_show_proxy);
276 }
278 Glib::SignalProxy0<void>
279 DockItem::signal_hide()
280 {
281 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
282 &_signal_hide_proxy);
283 }
285 Glib::SignalProxy1<bool, GdkEventAny *>
286 DockItem::signal_delete_event()
287 {
288 return Glib::SignalProxy1<bool, GdkEventAny *>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
289 &_signal_delete_event_proxy);
290 }
292 Glib::SignalProxy0<void>
293 DockItem::signal_drag_begin()
294 {
295 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
296 &_signal_drag_begin_proxy);
297 }
299 Glib::SignalProxy1<void, bool>
300 DockItem::signal_drag_end()
301 {
302 return Glib::SignalProxy1<void, bool>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
303 &_signal_drag_end_proxy);
304 }
306 Glib::SignalProxy0<void>
307 DockItem::signal_realize()
308 {
309 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
310 &_signal_realize_proxy);
311 }
313 sigc::signal<void, DockItem::State, DockItem::State>
314 DockItem::signal_state_changed()
315 {
316 return _signal_state_changed;
317 }
319 void
320 DockItem::_onHideWindow()
321 {
322 if (_window)
323 _window->get_position(_x, _y);
324 }
326 void
327 DockItem::_onHide()
328 {
329 _signal_state_changed.emit(UNATTACHED, getState());
330 }
332 void
333 DockItem::_onShow()
334 {
335 _signal_state_changed.emit(UNATTACHED, getState());
336 }
338 void
339 DockItem::_onDragBegin()
340 {
341 _prev_state = getState();
342 if (_prev_state == FLOATING_STATE)
343 _dock.toggleDockable(getWidget().get_width(), getWidget().get_height());
344 }
346 void
347 DockItem::_onDragEnd(bool)
348 {
349 State state = getState();
351 if (state != _prev_state)
352 _signal_state_changed.emit(_prev_state, state);
354 if (state == FLOATING_STATE) {
355 if (_prev_state == FLOATING_STATE)
356 _dock.toggleDockable();
357 }
359 _prev_state = state;
360 }
362 void
363 DockItem::_onRealize()
364 {
365 if (_grab_focus_on_realize) {
366 _grab_focus_on_realize = false;
367 grab_focus();
368 }
369 }
371 bool
372 DockItem::_onKeyPress(GdkEventKey *event)
373 {
374 gboolean return_value;
375 g_signal_emit_by_name (_gdl_dock_item, "key_press_event", event, &return_value);
376 return return_value;
377 }
379 void
380 DockItem::_onStateChanged(State /*prev_state*/, State new_state)
381 {
382 _window = getWindow();
384 if (new_state == FLOATING_STATE && _window) {
385 _window->signal_hide().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onHideWindow));
386 _signal_key_press_event_connection =
387 _window->signal_key_press_event().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onKeyPress));
388 }
389 }
392 bool
393 DockItem::_onDeleteEvent(GdkEventAny */*event*/)
394 {
395 hide();
396 return false;
397 }
400 Gtk::Window *
401 DockItem::getWindow()
402 {
403 g_return_val_if_fail(_gdl_dock_item, 0);
404 Gtk::Container *parent = getWidget().get_parent();
405 parent = (parent ? parent->get_parent() : 0);
406 return (parent ? dynamic_cast<Gtk::Window *>(parent) : 0);
407 }
409 const Glib::SignalProxyInfo
410 DockItem::_signal_show_proxy =
411 {
412 "show",
413 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
414 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
415 };
417 const Glib::SignalProxyInfo
418 DockItem::_signal_hide_proxy =
419 {
420 "hide",
421 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
422 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
423 };
426 const Glib::SignalProxyInfo
427 DockItem::_signal_delete_event_proxy =
428 {
429 "delete_event",
430 (GCallback) &_signal_delete_event_callback,
431 (GCallback) &_signal_delete_event_callback
432 };
435 const Glib::SignalProxyInfo
436 DockItem::_signal_drag_begin_proxy =
437 {
438 "dock-drag-begin",
439 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
440 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
441 };
444 const Glib::SignalProxyInfo
445 DockItem::_signal_drag_end_proxy =
446 {
447 "dock_drag_end",
448 (GCallback) &_signal_drag_end_callback,
449 (GCallback) &_signal_drag_end_callback
450 };
453 const Glib::SignalProxyInfo
454 DockItem::_signal_realize_proxy =
455 {
456 "realize",
457 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
458 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
459 };
462 gboolean
463 DockItem::_signal_delete_event_callback(GtkWidget *self, GdkEventAny *event, void *data)
464 {
465 using namespace Gtk;
466 typedef sigc::slot<bool, GdkEventAny *> SlotType;
468 if (Glib::ObjectBase::_get_current_wrapper((GObject *) self)) {
469 try {
470 if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
471 return static_cast<int>( (*static_cast<SlotType*>(slot))(event) );
472 } catch(...) {
473 Glib::exception_handlers_invoke();
474 }
475 }
477 typedef gboolean RType;
478 return RType();
479 }
481 void
482 DockItem::_signal_drag_end_callback(GtkWidget *self, gboolean cancelled, void *data)
483 {
484 using namespace Gtk;
485 typedef sigc::slot<void, bool> SlotType;
487 if (Glib::ObjectBase::_get_current_wrapper((GObject *) self)) {
488 try {
489 if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
490 (*static_cast<SlotType *>(slot))(cancelled);
491 } catch(...) {
492 Glib::exception_handlers_invoke();
493 }
494 }
495 }
498 } // namespace Widget
499 } // namespace UI
500 } // namespace Inkscape
502 /*
503 Local Variables:
504 mode:c++
505 c-file-style:"stroustrup"
506 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
507 indent-tabs-mode:nil
508 fill-column:99
509 End:
510 */
511 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :