97f11f56eadd30af91f26f3bfe686075db45a580
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 "ui/widget/dock.h"
16 #include "widgets/icon.h"
18 #include <gtk/gtk.h>
20 #include <gtkmm/invisible.h>
21 #include <gtkmm/stock.h>
23 namespace Inkscape {
24 namespace UI {
25 namespace Widget {
27 DockItem::DockItem(Dock& dock, const Glib::ustring& name, const Glib::ustring& long_name,
28 const Glib::ustring& icon_name, State state) :
29 _dock (dock),
30 _prev_state (state),
31 _window (NULL),
32 _dock_item_action_area (NULL)
33 {
34 /* Add a "signal_response" signal to the GdlDockItem, make sure it is
35 * only done once for the class.
36 */
37 static guint response_signal = 0;
39 if (response_signal == 0) {
40 response_signal = g_signal_new ("signal_response",
41 GDL_TYPE_DOCK_ITEM,
42 G_SIGNAL_RUN_FIRST,
43 0,
44 NULL, NULL,
45 g_cclosure_marshal_VOID__INT,
46 G_TYPE_NONE, 1, G_TYPE_INT);
47 }
50 if (!icon_name.empty()) {
51 Gtk::Widget *icon = sp_icon_get_icon(icon_name, Inkscape::ICON_SIZE_MENU);
52 if (icon) {
53 // check icon type (inkscape, gtk, none)
54 if ( SP_IS_ICON(icon->gobj()) ) {
55 SPIcon* sp_icon = SP_ICON(icon->gobj());
56 sp_icon_fetch_pixbuf(sp_icon);
57 _icon_pixbuf = Glib::wrap(sp_icon->pb, true);
58 } else if ( GTK_IS_IMAGE(icon->gobj()) ) {
59 _icon_pixbuf = Gtk::Invisible().render_icon(Gtk::StockID(icon_name),
60 Gtk::ICON_SIZE_MENU);
61 }
62 delete icon;
64 _gdl_dock_item =
65 gdl_dock_item_new_with_pixbuf_icon(name.c_str(), long_name.c_str(), _icon_pixbuf->gobj(),
66 GDL_DOCK_ITEM_BEH_NORMAL);
67 }
68 } else {
69 _gdl_dock_item =
70 gdl_dock_item_new(name.c_str(), long_name.c_str(), GDL_DOCK_ITEM_BEH_NORMAL);
71 }
73 _frame.set_shadow_type(Gtk::SHADOW_IN);
74 gtk_container_add (GTK_CONTAINER (_gdl_dock_item), GTK_WIDGET (_frame.gobj()));
75 _frame.add(_dock_item_box);
76 _dock_item_box.set_border_width(3);
78 signal_drag_begin().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDragBegin));
79 signal_drag_end().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDragEnd));
80 signal_hide().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onHide), false);
81 signal_show().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onShow), false);
82 signal_state_changed().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onStateChanged));
83 signal_delete_event().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDeleteEvent));
85 _dock.addItem(*this, (_prev_state == FLOATING_STATE ? FLOATING : TOP));
87 show_all();
88 }
90 DockItem::~DockItem()
91 {
92 g_free(_gdl_dock_item);
93 }
95 Gtk::Widget&
96 DockItem::getWidget()
97 {
98 return *Glib::wrap(GTK_WIDGET(_gdl_dock_item));
99 }
101 GtkWidget *
102 DockItem::gobj()
103 {
104 return _gdl_dock_item;
105 }
107 Gtk::VBox *
108 DockItem::get_vbox()
109 {
110 return &_dock_item_box;
111 }
114 bool
115 DockItem::isAttached() const
116 {
117 return GDL_DOCK_OBJECT_ATTACHED (_gdl_dock_item);
118 }
121 bool
122 DockItem::isFloating() const
123 {
124 gboolean floating = FALSE;
125 if (GDL_IS_DOCK (gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT (_gdl_dock_item)))) {
126 GdlDock* dock = GDL_DOCK (gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT (_gdl_dock_item)));
127 g_object_get (dock,
128 "floating", &floating,
129 NULL);
130 }
131 return floating;
132 }
134 bool
135 DockItem::isIconified() const
136 {
137 return GDL_DOCK_ITEM_ICONIFIED (_gdl_dock_item);
138 }
140 DockItem::State
141 DockItem::getState() const
142 {
143 return (isAttached() ? (isFloating() ? FLOATING_STATE : DOCKED_STATE) : UNATTACHED);
144 }
146 DockItem::State
147 DockItem::getPrevState() const
148 {
149 return _prev_state;
150 }
152 DockItem::Placement
153 DockItem::getPlacement() const
154 {
155 GdlDockPlacement placement = (GdlDockPlacement)NONE;
156 gdl_dock_object_child_placement(gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT(_gdl_dock_item)),
157 GDL_DOCK_OBJECT(_gdl_dock_item),
158 &placement);
159 return (Placement)placement;
160 }
163 void
164 DockItem::addButton(Gtk::Button* button, int response_id)
165 {
166 // Create a button box for the response buttons if it's the first button to be added
167 if (!_dock_item_action_area) {
168 _dock_item_action_area = new Gtk::HButtonBox(Gtk::BUTTONBOX_END, 6);
169 _dock_item_box.pack_end(*_dock_item_action_area, Gtk::PACK_SHRINK, 0);
170 _dock_item_action_area->set_border_width(6);
171 }
173 _dock_item_action_area->pack_start(*button);
174 }
176 void
177 DockItem::hide()
178 {
179 gdl_dock_item_hide_item (GDL_DOCK_ITEM(_gdl_dock_item));
180 }
182 void
183 DockItem::show()
184 {
185 gdl_dock_item_show_item (GDL_DOCK_ITEM(_gdl_dock_item));
186 }
188 void
189 DockItem::show_all()
190 {
191 gtk_widget_show_all(_gdl_dock_item);
192 }
194 void
195 DockItem::present()
196 {
197 // iconified
198 if (isIconified()) {
199 show();
200 return;
201 }
203 // unattached
204 if (!isAttached()) {
205 gdl_dock_item_show_item (GDL_DOCK_ITEM(_gdl_dock_item));
206 return;
207 }
209 // tabbed
210 if (getPlacement() == CENTER) {
211 int i = gtk_notebook_page_num (GTK_NOTEBOOK (_gdl_dock_item->parent),
212 GTK_WIDGET (_gdl_dock_item));
213 if (i >= 0)
214 gtk_notebook_set_current_page (GTK_NOTEBOOK (_gdl_dock_item->parent), i);
215 return;
216 }
218 // we're already present, do nothing
219 }
222 void
223 DockItem::get_position(int& x, int& y)
224 {
225 if (getWindow()) {
226 getWindow()->get_position(x, y);
227 } else {
228 x = _x;
229 y = _y;
230 }
231 }
233 void
234 DockItem::get_size(int& width, int& height)
235 {
236 if (_window) {
237 _window->get_size(width, height);
238 } else {
239 width = get_vbox()->get_width();
240 height = get_vbox()->get_height();
241 }
242 }
245 void
246 DockItem::resize(int width, int height)
247 {
248 if (_window)
249 _window->resize(width, height);
250 }
253 void
254 DockItem::move(int x, int y)
255 {
256 if (_window)
257 _window->move(x, y);
258 }
260 void
261 DockItem::set_position(Gtk::WindowPosition position)
262 {
263 if (_window)
264 _window->set_position(position);
265 }
267 void
268 DockItem::set_size_request(int width, int height)
269 {
270 getWidget().set_size_request(width, height);
271 }
273 void
274 DockItem::size_request(Gtk::Requisition& requisition)
275 {
276 getWidget().size_request(requisition);
277 }
280 void
281 DockItem::set_title(Glib::ustring title)
282 {
283 g_object_set (_gdl_dock_item,
284 "long-name", title.c_str(),
285 NULL);
287 gdl_dock_item_set_tablabel(GDL_DOCK_ITEM(_gdl_dock_item),
288 gtk_label_new (title.c_str()));
289 }
291 /* Signal wrappers */
293 Glib::SignalProxy0<void>
294 DockItem::signal_show()
295 {
296 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
297 &_signal_show_proxy);
298 }
300 Glib::SignalProxy0<void>
301 DockItem::signal_hide()
302 {
303 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
304 &_signal_hide_proxy);
305 }
307 Glib::SignalProxy1<bool, GdkEventAny *>
308 DockItem::signal_delete_event()
309 {
310 return Glib::SignalProxy1<bool, GdkEventAny *>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
311 &_signal_delete_event_proxy);
312 }
314 Glib::SignalProxy1<void, int>
315 DockItem::signal_response()
316 {
317 return Glib::SignalProxy1<void, int>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
318 &_signal_response_proxy);
319 }
321 Glib::SignalProxy0<void>
322 DockItem::signal_drag_begin()
323 {
324 return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
325 &_signal_drag_begin_proxy);
326 }
328 Glib::SignalProxy1<void, bool>
329 DockItem::signal_drag_end()
330 {
331 return Glib::SignalProxy1<void, bool>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
332 &_signal_drag_end_proxy);
333 }
335 sigc::signal<void, DockItem::State, DockItem::State>
336 DockItem::signal_state_changed()
337 {
338 return _signal_state_changed;
339 }
341 void
342 DockItem::_onHideWindow()
343 {
344 if (_window)
345 _window->get_position(_x, _y);
346 }
348 void
349 DockItem::_onHide()
350 {
351 _signal_state_changed.emit(UNATTACHED, getState());
352 }
354 void
355 DockItem::_onShow()
356 {
357 _signal_state_changed.emit(UNATTACHED, getState());
358 }
360 void
361 DockItem::_onDragBegin()
362 {
363 _prev_state = getState();
364 if (_prev_state == FLOATING_STATE)
365 _dock.toggleDockable(getWidget().get_width(), getWidget().get_height());
366 }
368 void
369 DockItem::_onDragEnd(bool)
370 {
371 State state = getState();
373 if (state != _prev_state)
374 _signal_state_changed.emit(_prev_state, state);
376 if (state == FLOATING_STATE) {
377 if (_prev_state == FLOATING_STATE)
378 _dock.toggleDockable();
379 }
381 _prev_state = state;
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) {
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_response_proxy =
450 {
451 "signal_response",
452 (GCallback) &_signal_response_callback,
453 (GCallback) &_signal_response_callback
454 };
456 const Glib::SignalProxyInfo
457 DockItem::_signal_drag_begin_proxy =
458 {
459 "dock-drag-begin",
460 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
461 (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
462 };
465 const Glib::SignalProxyInfo
466 DockItem::_signal_drag_end_proxy =
467 {
468 "dock_drag_end",
469 (GCallback) &_signal_drag_end_callback,
470 (GCallback) &_signal_drag_end_callback
471 };
474 gboolean
475 DockItem::_signal_delete_event_callback(GtkWidget *self, GdkEventAny *event, void *data)
476 {
477 using namespace Gtk;
478 typedef sigc::slot<bool, GdkEventAny *> SlotType;
480 if (Glib::ObjectBase::_get_current_wrapper((GObject *) self)) {
481 try {
482 if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
483 return static_cast<int>( (*static_cast<SlotType*>(slot))(event) );
484 } catch(...) {
485 Glib::exception_handlers_invoke();
486 }
487 }
489 typedef gboolean RType;
490 return RType();
491 }
493 void
494 DockItem::_signal_response_callback(GtkWidget *self, gint response_id, void *data)
495 {
496 using namespace Gtk;
497 typedef sigc::slot<void, int> SlotType;
499 if (Glib::ObjectBase::_get_current_wrapper((GObject *) self)) {
500 try {
501 if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
502 (*static_cast<SlotType *>(slot))(response_id);
503 } catch(...) {
504 Glib::exception_handlers_invoke();
505 }
506 }
507 }
509 void
510 DockItem::_signal_drag_end_callback(GtkWidget *self, gboolean cancelled, void *data)
511 {
512 using namespace Gtk;
513 typedef sigc::slot<void, bool> SlotType;
515 if (Glib::ObjectBase::_get_current_wrapper((GObject *) self)) {
516 try {
517 if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
518 (*static_cast<SlotType *>(slot))(cancelled);
519 } catch(...) {
520 Glib::exception_handlers_invoke();
521 }
522 }
523 }
526 } // namespace Widget
527 } // namespace UI
528 } // namespace Inkscape
530 /*
531 Local Variables:
532 mode:c++
533 c-file-style:"stroustrup"
534 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
535 indent-tabs-mode:nil
536 fill-column:99
537 End:
538 */
539 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :