1 /* Copyright (C) 2008 The goocanvasmm Development Team
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free
15 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 */
17
18 #include "examplewindow.h"
19 #include <iostream>
20
21 const int DRAG_DATA_FORMAT = 8; // 8 bits format
22
ExampleWindow()23 ExampleWindow::ExampleWindow()
24 : m_vbox(false, 6),
25 m_hbox(false, 6),
26 m_button_rect("Rectangle"),
27 m_button_ellipse("Ellipse"),
28 m_drag_preview_requested(false)
29 {
30 set_title("goocanvasmm - Simple Example");
31
32 m_drag_targets.push_back( Gtk::TargetEntry("goocanvasmm_example_drag_item", Gtk::TARGET_SAME_APP) );
33
34 add(m_vbox);
35 m_vbox.pack_start(m_hbox, Gtk::PACK_SHRINK);
36
37 m_hbox.pack_start(m_button_rect, Gtk::PACK_SHRINK);
38 make_widget_draggable(m_button_rect, DRAG_ITEM_RECTANGLE);
39 m_hbox.pack_start(m_button_ellipse, Gtk::PACK_SHRINK);
40 make_widget_draggable(m_button_ellipse, DRAG_ITEM_ELLIPSE);
41
42 m_canvas.set_size_request(640, 480);
43 m_canvas.set_bounds(0, 0, 1000, 1000);
44
45
46 Gtk::ScrolledWindow* sw = Gtk::manage(new Gtk::ScrolledWindow());
47 sw->add(m_canvas);
48 m_vbox.pack_start(*sw);
49
50 // Make the canvas a drag-and-drop destination. As we are implementing
51 // custom handlers for all (motion, highlight, drop), we set the second
52 // argument of drag_dest_set to 0. See the documentation of
53 // drag_dest_set for details. It would be nice if Gtk::DestDefaults did
54 // contain a GTK_DEST_DEFAULT_NONE, but short of that we can still brute
55 // force it to 0.
56 m_canvas.drag_dest_set(m_drag_targets, (Gtk::DestDefaults)0, Gdk::ACTION_COPY);
57 m_canvas.signal_drag_motion().connect(
58 sigc::mem_fun(*this, &ExampleWindow::on_canvas_drag_motion) );
59 m_canvas.signal_drag_drop().connect(
60 sigc::mem_fun(*this, &ExampleWindow::on_canvas_drag_drop) );
61
62 m_canvas.signal_drag_data_received().connect(
63 sigc::mem_fun(*this, &ExampleWindow::on_canvas_drag_data_received) );
64
65 show_all_children();
66 }
67
make_widget_draggable(Gtk::Widget & widget,DragItem drag_item)68 void ExampleWindow::make_widget_draggable(Gtk::Widget& widget, DragItem drag_item)
69 {
70 widget.drag_source_set(m_drag_targets, Gdk::BUTTON1_MASK, Gdk::ACTION_COPY);
71
72 //Set the icon to be shown when dragging:
73 //Glib::RefPtr<Gdk::Pixbuf> pixbuf = get_icon_for_toolbar_item(*item);
74 //if(pixbuf)
75 // widget.drag_source_set_icon(pixbuf);
76
77 //widget.signal_drag_begin().connect(
78 // sigc::mem_fun(*this, &ExampleWindow::on_toolbar_item_drag_begin) );
79
80 //widget.signal_drag_end().connect(
81 // sigc::mem_fun(*this, &ExampleWindow::on_toolbar_item_drag_end) );
82
83 //Let the item supply some data when the destination asks for it:
84 widget.signal_drag_data_get().connect(
85 sigc::bind( sigc::mem_fun(*this, &ExampleWindow::on_button_drag_data_get), drag_item) );
86 }
87
on_canvas_drag_drop(const Glib::RefPtr<Gdk::DragContext> & drag_context,int,int,guint timestamp)88 bool ExampleWindow::on_canvas_drag_drop(const Glib::RefPtr<Gdk::DragContext>& drag_context, int /* x */, int /* y */, guint timestamp)
89 {
90 std::cout << "ExampleWindow::on_canvas_drag_drop" << std::endl;
91 Glib::ustring target = m_canvas.drag_dest_find_target(drag_context);
92 if(target.empty())
93 return false;
94
95 //Get the details, to create the appropriate canvas item:
96 //This will cause our drag_data_received callback to be called, with that information:
97 m_drag_preview_requested = false;
98 m_canvas.drag_get_data(drag_context, target, timestamp);
99 return true; //Allow the drop.
100 }
101
102
on_canvas_drag_motion(const Glib::RefPtr<Gdk::DragContext> & drag_context,int x,int y,guint timestamp)103 bool ExampleWindow::on_canvas_drag_motion(const Glib::RefPtr<Gdk::DragContext>& drag_context, int x, int y, guint timestamp)
104 {
105 std::cout << "ExampleWindow::on_canvas_drag_motion" << std::endl;
106 Glib::ustring target = m_canvas.drag_dest_find_target(drag_context);
107 if(target.empty())
108 return false;
109
110 m_canvas.drag_highlight();
111
112 //Create the temporary canvas item if necesary:
113 if(!m_layout_item_dropping)
114 {
115 std::cout << " ExampleWindow::on_canvas_drag_motion(): Calling drag_get_data()" << std::endl;
116
117 //TODO: This stops the drop (or any further motion events) from happening:
118
119 //We need to examine the SelectionData:
120 //This will cause our drag_data_received callback to be called, with that information:
121 m_drag_preview_requested = true;
122 m_canvas.drag_get_data(drag_context, target, timestamp);
123 return true;
124 }
125
126 std::cout << " ExampleWindow::on_canvas_drag_motion(): item already created." << std::endl;
127
128 drag_context->drag_status(Gdk::ACTION_COPY, timestamp);
129
130 //Move the temporary canvas item to the new position:
131 double item_x = x;
132 double item_y = y;
133 m_canvas.convert_from_pixels(item_x, item_y);
134
135 gdouble t_x, t_y, t_scale, t_rotation;
136 m_layout_item_dropping->get_simple_transform(t_x, t_y, t_scale, t_rotation);
137 m_layout_item_dropping->set_simple_transform(item_x, item_y, t_scale, t_rotation);
138
139 return true; //Allow the drop.
140 }
141
get_drag_item_from_selection_data(const Gtk::SelectionData & selection_data)142 ExampleWindow::DragItem ExampleWindow::get_drag_item_from_selection_data(const Gtk::SelectionData& selection_data)
143 {
144 DragItem item_type = DRAG_ITEM_NONE;
145 if((selection_data.get_length() >= 0) && (selection_data.get_format() == DRAG_DATA_FORMAT))
146 {
147 const guint8* data = selection_data.get_data();
148 if(data)
149 item_type = (DragItem)(data[0]);
150 }
151
152 return item_type;
153 }
154
on_canvas_drag_data_received(const Glib::RefPtr<Gdk::DragContext> & drag_context,int x,int y,const Gtk::SelectionData & selection_data,guint,guint timestamp)155 void ExampleWindow::on_canvas_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& drag_context, int x, int y, const Gtk::SelectionData& selection_data, guint /* info */, guint timestamp)
156 {
157 std::cout << "ExampleWindow::on_canvas_drag_data_received" << std::endl;
158
159 //This is called when an item is dropped on the canvas,
160 //or after our drag_motion handler has called drag_get_data()):
161
162 //Discover what toolbar item was dragged:
163 const DragItem drag_item = get_drag_item_from_selection_data(selection_data);
164
165
166 //Create the temporary drag item if necessary:
167 if(m_drag_preview_requested && !m_layout_item_dropping)
168 {
169 m_layout_item_dropping = create_canvas_item(drag_item, x, y);
170 }
171 else
172 {
173 if(m_layout_item_dropping)
174 m_layout_item_dropping->remove();
175
176 m_layout_item_dropping.reset();
177 create_canvas_item(drag_item, x, y);
178 }
179
180 if(m_drag_preview_requested)
181 {
182 std::cout << "ExampleWindow::on_canvas_drag_data_received: m_drag_preview_requested" << std::endl;
183
184 drag_context->drag_status(Gdk::ACTION_COPY, timestamp);
185 m_drag_preview_requested = false;
186 }
187 else
188 {
189 drag_context->drag_finish(false, false, timestamp);
190 m_canvas.drag_unhighlight();
191 }
192 }
193
on_button_drag_data_get(const Glib::RefPtr<Gdk::DragContext> &,Gtk::SelectionData & selection_data,guint,guint,DragItem drag_item)194 void ExampleWindow::on_button_drag_data_get(const Glib::RefPtr<Gdk::DragContext>& /* drag_context */, Gtk::SelectionData& selection_data, guint /* info */, guint /* time */, DragItem drag_item)
195 {
196 std::cout << "ExampleWindow::on_button_drag_data_get" << std::endl;
197
198 selection_data.set(selection_data.get_target(), DRAG_DATA_FORMAT,
199 (const guchar*)&drag_item,
200 1 /* 1 byte */);
201 }
202
create_canvas_item(DragItem drag_item,int x,int y)203 Glib::RefPtr<Goocanvas::Item> ExampleWindow::create_canvas_item(DragItem drag_item, int x, int y)
204 {
205 Glib::RefPtr<Goocanvas::Item> result;
206
207 if(drag_item == DRAG_ITEM_RECTANGLE)
208 {
209 Glib::RefPtr<Goocanvas::Rect> rect = Goocanvas::Rect::create(0, 0, 20, 20);
210 #ifdef GLIBMM_PROPERTIES_ENABLED
211 rect->property_line_width() = 10.0;
212 rect->property_stroke_color() = "yellow";
213 rect->property_fill_color() = "red";
214 #else
215 rect->set_property("line_width", 10.0);
216 rect->set_property("stroke_color", Glib::ustring("yellow"));
217 rect->set_property("fill_color", Glib::ustring("red"));
218 #endif //GLIBMM_PROPERTIES_ENABLED
219 result = rect;
220 }
221 else if(drag_item == DRAG_ITEM_ELLIPSE)
222 {
223 Glib::RefPtr<Goocanvas::Ellipse> ellipse = Goocanvas::Ellipse::create();
224 #ifdef GLIBMM_PROPERTIES_ENABLED
225 ellipse->property_line_width() = 10.0;
226 ellipse->property_radius_x() = 20.0;
227 ellipse->property_radius_y() = 20.0;
228 ellipse->property_stroke_color() = "yellow";
229 ellipse->property_fill_color() = "red";
230 #else
231 ellipse->set_property("line_width", 10.0);
232 ellipse->set_property("radius_x", 20.0);
233 ellipse->set_property("radius_y", 20.0);
234 ellipse->set_property("stroke_color", Glib::ustring("yellow"));
235 ellipse->set_property("fill_color", Glib::ustring("red"));
236 #endif //GLIBMM_PROPERTIES_ENABLED
237 result = ellipse;
238 }
239
240 if(result)
241 {
242 Glib::RefPtr<Goocanvas::Item> root = m_canvas.get_root_item();
243 root->add_child(result);
244
245 //Show it on the canvas, at the position:
246 double item_x = x;
247 double item_y = y;
248 m_canvas.convert_from_pixels(item_x, item_y);
249 result->translate(item_x, item_y);
250 }
251
252 return result;
253 }
254
255