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 "dock-item.h"
13 #include "desktop.h"
14 #include "inkscape.h"
15 #include "preferences.h"
16 #include "ui/widget/dock.h"
17 #include "widgets/icon.h"
19 #include <gtk/gtk.h>
21 #include <gtkmm/invisible.h>
22 #include <gtkmm/stock.h>
24 namespace Inkscape {
25 namespace UI {
26 namespace Widget {
28 DockItem::DockItem(Dock& dock, const Glib::ustring& name, const Glib::ustring& long_name,
29 const Glib::ustring& icon_name, State state) :
30 _dock(dock),
31 _prev_state(state),
32 _prev_position(0),
33 _window(0),
34 _x(0),
35 _y(0),
36 _grab_focus_on_realize(false),
37 _gdl_dock_item(0),
38 _dock_item_action_area(0)
39 {
40 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
41 GdlDockItemBehavior gdl_dock_behavior =
42 (prefs->getBool("/options/dock/cancenterdock", true) ?
43 GDL_DOCK_ITEM_BEH_NORMAL :
44 GDL_DOCK_ITEM_BEH_CANT_DOCK_CENTER);
46 if (!icon_name.empty()) {
47 Gtk::Widget *icon = sp_icon_get_icon(icon_name, Inkscape::ICON_SIZE_MENU);
48 if (icon) {
49 // check icon type (inkscape, gtk, none)
50 if ( SP_IS_ICON(icon->gobj()) ) {
51 SPIcon* sp_icon = SP_ICON(icon->gobj());
52 sp_icon_fetch_pixbuf(sp_icon);
53 _icon_pixbuf = Glib::wrap(sp_icon->pb, true);
54 } else if ( GTK_IS_IMAGE(icon->gobj()) ) {
55 _icon_pixbuf = Gtk::Invisible().render_icon(Gtk::StockID(icon_name),
56 Gtk::ICON_SIZE_MENU);
57 }
58 delete icon;
60 _gdl_dock_item =
61 gdl_dock_item_new_with_pixbuf_icon(name.c_str(), long_name.c_str(),
62 _icon_pixbuf->gobj(), gdl_dock_behavior);
63 }
64 } else {
65 _gdl_dock_item =
66 gdl_dock_item_new(name.c_str(), long_name.c_str(), gdl_dock_behavior);
67 }
69 _frame.set_shadow_type(Gtk::SHADOW_IN);
70 gtk_container_add (GTK_CONTAINER (_gdl_dock_item), GTK_WIDGET (_frame.gobj()));
71 _frame.add(_dock_item_box);
72 _dock_item_box.set_border_width(3);
74 signal_drag_begin().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDragBegin));
75 signal_drag_end().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDragEnd));
76 signal_hide().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onHide), false);
77 signal_show().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onShow), false);
78 signal_state_changed().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onStateChanged));
79 signal_delete_event().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDeleteEvent));
80 signal_realize().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onRealize));
82 _dock.addItem(*this, (_prev_state == FLOATING_STATE ? FLOATING : TOP));
84 show_all();
85 }
87 DockItem::~DockItem()
88 {
89 g_free(_gdl_dock_item);
90 }
92 Gtk::Widget&
93 DockItem::getWidget()
94 {
95 return *Glib::wrap(GTK_WIDGET(_gdl_dock_item));
96 }
98 GtkWidget *
99 DockItem::gobj()
100 {
101 return _gdl_dock_item;
102 }
104 Gtk::VBox *
105 DockItem::get_vbox()
106 {
107 return &_dock_item_box;
108 }
111 void
112 DockItem::get_position(int& x, int& y)
113 {
114 if (getWindow()) {
115 getWindow()->get_position(x, y);
116 } else {
117 x = _x;
118 y = _y;
119 }
120 }
122 void
123 DockItem::get_size(int& width, int& height)
124 {
125 if (_window) {
126 _window->get_size(width, height);
127 } else {
128 width = get_vbox()->get_width();
129 height = get_vbox()->get_height();
130 }
131 }
134 void
135 DockItem::resize(int width, int height)
136 {
137 if (_window)
138 _window->resize(width, height);
139 }
142 void
143 DockItem::move(int x, int y)
144 {
145 if (_window)
146 _window->move(x, y);
147 }
149 void
150 DockItem::set_position(Gtk::WindowPosition position)
151 {
152 if (_window)
153 _window->set_position(position);
154 }
156 void
157 DockItem::set_size_request(int width, int height)
158 {
159 getWidget().set_size_request(width, height);
160 }
162 void
163 DockItem::size_request(Gtk::Requisition& requisition)
164 {
165 getWidget().size_request(requisition);
166 }
168 void
169 DockItem::set_title(Glib::ustring title)
170 {
171 g_object_set (_gdl_dock_item,
172 "long-name", title.c_str(),
173 NULL);
175 gdl_dock_item_set_tablabel(GDL_DOCK_ITEM(_gdl_dock_item),
176 gtk_label_new (title.c_str()));
177 }
179 bool
180 DockItem::isAttached() const
181 {
182 return GDL_DOCK_OBJECT_ATTACHED (_gdl_dock_item);
183 }
186 bool
187 DockItem::isFloating() const
188 {
189 return (GTK_WIDGET(gdl_dock_object_get_toplevel(GDL_DOCK_OBJECT (_gdl_dock_item))) !=
190 _dock.getGdlWidget());
191 }
193 bool
194 DockItem::isIconified() const
195 {
196 return GDL_DOCK_ITEM_ICONIFIED (_gdl_dock_item);
197 }
199 DockItem::State
200 DockItem::getState() const
201 {
202 return (isAttached() ? (isFloating() ? FLOATING_STATE : DOCKED_STATE) : UNATTACHED);
203 }
205 DockItem::State
206 DockItem::getPrevState() const
207 {
208 return _prev_state;
209 }
211 DockItem::Placement
212 DockItem::getPlacement() const
213 {
214 GdlDockPlacement placement = (GdlDockPlacement)NONE;
215 gdl_dock_object_child_placement(gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT(_gdl_dock_item)),
216 GDL_DOCK_OBJECT(_gdl_dock_item),
217 &placement);
218 return (Placement)placement;
219 }
221 void
222 DockItem::hide()
223 {
224 gdl_dock_item_hide_item (GDL_DOCK_ITEM(_gdl_dock_item));
225 }
227 void
228 DockItem::show()
229 {
230 gdl_dock_item_show_item (GDL_DOCK_ITEM(_gdl_dock_item));
231 }
233 void
234 DockItem::show_all()
235 {
236 gtk_widget_show_all(_gdl_dock_item);
237 }
239 void
240 DockItem::present()
241 {
243 if (isIconified() || !isAttached()) {
244 show();
245 }
247 // tabbed
248 else if (getPlacement() == CENTER) {
249 int i = gtk_notebook_page_num (GTK_NOTEBOOK (_gdl_dock_item->parent),
250 GTK_WIDGET (_gdl_dock_item));
251 if (i >= 0)
252 gtk_notebook_set_current_page (GTK_NOTEBOOK (_gdl_dock_item->parent), i);
253 }
255 // always grab focus, even if we're already present
256 grab_focus();
258 if (!isFloating() && getWidget().is_realized())
259 _dock.scrollToItem(*this);
260 }
263 void
264 DockItem::grab_focus()
265 {
266 if (GTK_WIDGET_REALIZED (_gdl_dock_item)) {
268 // make sure the window we're in is present
269 Gtk::Widget *toplevel = getWidget().get_toplevel();
270 if (Gtk::Window *window = dynamic_cast<Gtk::Window *>(toplevel)) {
271 window->present();
272 }
274 gtk_widget_grab_focus (_gdl_dock_item);
276 } else {
277 _grab_focus_on_realize = true;
278 }
279 }
282 /* Signal wrappers */
284 Glib::SignalProxy0<void>
285 DockItem::signal_show()
286 {
287 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
288 &_signal_show_proxy);
289 }
291 Glib::SignalProxy0<void>
292 DockItem::signal_hide()
293 {
294 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
295 &_signal_hide_proxy);
296 }
298 Glib::SignalProxy1<bool, GdkEventAny *>
299 DockItem::signal_delete_event()
300 {
301 return Glib::SignalProxy1<bool, GdkEventAny *>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
302 &_signal_delete_event_proxy);
303 }
305 Glib::SignalProxy0<void>
306 DockItem::signal_drag_begin()
307 {
308 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
309 &_signal_drag_begin_proxy);
310 }
312 Glib::SignalProxy1<void, bool>
313 DockItem::signal_drag_end()
314 {
315 return Glib::SignalProxy1<void, bool>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
316 &_signal_drag_end_proxy);
317 }
319 Glib::SignalProxy0<void>
320 DockItem::signal_realize()
321 {
322 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
323 &_signal_realize_proxy);
324 }
326 sigc::signal<void, DockItem::State, DockItem::State>
327 DockItem::signal_state_changed()
328 {
329 return _signal_state_changed;
330 }
332 void
333 DockItem::_onHideWindow()
334 {
335 if (_window)
336 _window->get_position(_x, _y);
337 }
339 void
340 DockItem::_onHide()
341 {
342 _signal_state_changed.emit(UNATTACHED, getState());
343 }
345 void
346 DockItem::_onShow()
347 {
348 _signal_state_changed.emit(UNATTACHED, getState());
349 }
351 void
352 DockItem::_onDragBegin()
353 {
354 _prev_state = getState();
355 if (_prev_state == FLOATING_STATE)
356 _dock.toggleDockable(getWidget().get_width(), getWidget().get_height());
357 }
359 void
360 DockItem::_onDragEnd(bool)
361 {
362 State state = getState();
364 if (state != _prev_state)
365 _signal_state_changed.emit(_prev_state, state);
367 if (state == FLOATING_STATE) {
368 if (_prev_state == FLOATING_STATE)
369 _dock.toggleDockable();
370 }
372 _prev_state = state;
373 }
375 void
376 DockItem::_onRealize()
377 {
378 if (_grab_focus_on_realize) {
379 _grab_focus_on_realize = false;
380 grab_focus();
381 }
382 }
384 bool
385 DockItem::_onKeyPress(GdkEventKey *event)
386 {
387 gboolean return_value;
388 g_signal_emit_by_name (_gdl_dock_item, "key_press_event", event, &return_value);
389 return return_value;
390 }
392 void
393 DockItem::_onStateChanged(State /*prev_state*/, State new_state)
394 {
395 _window = getWindow();
397 if (new_state == FLOATING_STATE && _window) {
398 _window->signal_hide().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onHideWindow));
399 _signal_key_press_event_connection =
400 _window->signal_key_press_event().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onKeyPress));
401 }
402 }
405 bool
406 DockItem::_onDeleteEvent(GdkEventAny */*event*/)
407 {
408 hide();
409 return false;
410 }
413 Gtk::Window *
414 DockItem::getWindow()
415 {
416 g_return_val_if_fail(_gdl_dock_item, 0);
417 Gtk::Container *parent = getWidget().get_parent();
418 parent = (parent ? parent->get_parent() : 0);
419 return (parent ? dynamic_cast<Gtk::Window *>(parent) : 0);
420 }
422 const Glib::SignalProxyInfo
423 DockItem::_signal_show_proxy =
424 {
425 "show",
426 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
427 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
428 };
430 const Glib::SignalProxyInfo
431 DockItem::_signal_hide_proxy =
432 {
433 "hide",
434 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
435 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
436 };
439 const Glib::SignalProxyInfo
440 DockItem::_signal_delete_event_proxy =
441 {
442 "delete_event",
443 (GCallback) &_signal_delete_event_callback,
444 (GCallback) &_signal_delete_event_callback
445 };
448 const Glib::SignalProxyInfo
449 DockItem::_signal_drag_begin_proxy =
450 {
451 "dock-drag-begin",
452 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
453 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
454 };
457 const Glib::SignalProxyInfo
458 DockItem::_signal_drag_end_proxy =
459 {
460 "dock_drag_end",
461 (GCallback) &_signal_drag_end_callback,
462 (GCallback) &_signal_drag_end_callback
463 };
466 const Glib::SignalProxyInfo
467 DockItem::_signal_realize_proxy =
468 {
469 "realize",
470 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
471 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
472 };
475 gboolean
476 DockItem::_signal_delete_event_callback(GtkWidget *self, GdkEventAny *event, void *data)
477 {
478 using namespace Gtk;
479 typedef sigc::slot<bool, GdkEventAny *> SlotType;
481 if (Glib::ObjectBase::_get_current_wrapper((GObject *) self)) {
482 try {
483 if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
484 return static_cast<int>( (*static_cast<SlotType*>(slot))(event) );
485 } catch(...) {
486 Glib::exception_handlers_invoke();
487 }
488 }
490 typedef gboolean RType;
491 return RType();
492 }
494 void
495 DockItem::_signal_drag_end_callback(GtkWidget *self, gboolean cancelled, void *data)
496 {
497 using namespace Gtk;
498 typedef sigc::slot<void, bool> SlotType;
500 if (Glib::ObjectBase::_get_current_wrapper((GObject *) self)) {
501 try {
502 if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
503 (*static_cast<SlotType *>(slot))(cancelled);
504 } catch(...) {
505 Glib::exception_handlers_invoke();
506 }
507 }
508 }
511 } // namespace Widget
512 } // namespace UI
513 } // namespace Inkscape
515 /*
516 Local Variables:
517 mode:c++
518 c-file-style:"stroustrup"
519 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
520 indent-tabs-mode:nil
521 fill-column:99
522 End:
523 */
524 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :