libcrn  3.9.5
A document image processing library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GtkCRNDrawingPanel.cpp
Go to the documentation of this file.
1 /* Copyright 2010-2016 CoReNum, INSA-Lyon, ENS-Lyon
2  *
3  * This file is part of libgtkcrnmm.
4  *
5  * libgtkcrnmm is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * libgtkcrnmm is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with libgtkcrnmm. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * file: GtkCRNDrawingPanel.cpp
19  * \author Yann LEYDIER
20  */
21 
22 #include <GtkCRNDrawingPanel.h>
23 
24 #ifndef CRN_USING_GTKMM3
25 
26 #include <CRNIO/CRNIO.h>
27 #include <GdkCRNPixbuf.h>
28 #include <CRNi18n.h>
29 
30 using namespace GtkCRN;
31 
34  thickness(2.0),
35  zoom(1.0),
36  actions(Gtk::ActionGroup::create("drawing panel"))
37 {
38 #ifndef CRN_USING_GTKMM3
39  bg_act = GtkCRN::ColorAction::create("drawing-panel-background", Gtk::Stock::SELECT_COLOR, _("_Background Color…"), _("Background Color"));
40  actions->add(bg_act);
41  actions->get_action("drawing-panel-background")->set_short_label(_("Background"));
42  actions->get_action("drawing-panel-background")->set_is_important();
43  bg_act->set_color(Gdk::Color("white"));
44  bg_act->signal_changed().connect(sigc::mem_fun(this, &Gtk::Widget::queue_draw));
45 
46  fg_act = GtkCRN::ColorAction::create("drawing-panel-foreground", Gtk::Stock::SELECT_COLOR, _("_Foreground Color…"), _("Foreground Color"));
47  actions->add(fg_act);
48  actions->get_action("drawing-panel-foreground")->set_short_label(_("Foreground"));
49  actions->get_action("drawing-panel-foreground")->set_is_important();
50  fg_act->set_color(Gdk::Color("black"));
51  fg_act->signal_changed().connect(sigc::mem_fun(this, &Gtk::Widget::queue_draw));
52 
53  //actions->add(Gtk::Action::create("drawing-panel-clear", Gtk::Stock::CLEAR, _("_Clear"), _("Clear")), sigc::mem_fun(this, &DrawingPanel::clear));
54  /*
55  actions->add(Gtk::Action::create("drawing-panel-thickness-plus", Gtk::StockID("gtk-crn-size-plus"), _("_Increase Thickness"), _("Increase Thickness")), sigc::bind(sigc::mem_fun(this, &DrawingPanel::modify_thickness), 0.1));
56  actions->add(Gtk::Action::create("drawing-panel-thickness-minus", Gtk::StockID("gtk-crn-size-minus"), _("_Decrease Thickness"), _("Decrease Thickness")), sigc::bind(sigc::mem_fun(this, &DrawingPanel::modify_thickness), -0.1));
57  */
58  thick_act = GtkCRN::ScaleAction::create("drawing-panel-thickness-set", _("Set _Thickness"), _("Set Thickness"));
59 
60  actions->add(thick_act);
61  thick_act->get_adjustment().configure(thickness, 0.2, 20, 0.1, 1, 1);
62  thick_act->signal_changed().connect(sigc::mem_fun(this, &DrawingPanel::on_thickness_set));
63 
64  std::vector<Glib::ustring> icons;
65  icons.push_back("line05");
66  icons.push_back("line3");
67  icons.push_back("line1");
68  icons.push_back("line2");
69  icons.push_back("line3");
70  thick_act->set_icons(icons);
71 #endif
72 
73  add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON_MOTION_MASK);
74  signal_button_press_event().connect(sigc::mem_fun(this, &DrawingPanel::on_button_press));
75  signal_motion_notify_event().connect(sigc::mem_fun(this, &DrawingPanel::on_motion));
76 #ifdef CRN_USING_GTKMM3
77  signal_draw().connect(sigc::mem_fun(this, &DrawingPanel::on_expose));
78 #else /* CRN_USING_GTKMM3 */
79  signal_expose_event().connect(sigc::mem_fun(this, &DrawingPanel::on_expose));
80 #endif /* CRN_USING_GTKMM3 */
81 }
82 
90 void DrawingPanel::set_zoom(double z)
91 {
92  if (z <= 0)
93  {
94  throw Glib::OptionError(Glib::OptionError::BAD_VALUE, Glib::ustring("void DrawingPanel::set_zoom(double z): ") + _("null or negative zoom value."));
95  }
96  zoom = z;
97  queue_draw();
98 }
99 
102 {
103  stroke_list.clear();
104  queue_draw();
105 }
106 
110 #ifdef CRN_USING_GTKMM3
111 Gdk::RGBA DrawingPanel::get_background() const
112 {
113  return Gdk::RGBA{}; // TODO
114 }
115 #else /* CRN_USING_GTKMM3 */
117 {
118  return bg_act->get_color();
119 }
120 #endif /* CRN_USING_GTKMM3 */
121 
125 #ifdef CRN_USING_GTKMM3
126 void DrawingPanel::set_background(const Gdk::RGBA& col)
127 {
128 }
129 #else /* CRN_USING_GTKMM3 */
130 void DrawingPanel::set_background(const Gdk::Color& col)
131 {
132  bg_act->set_color(col);
133 }
134 #endif /* CRN_USING_GTKMM3 */
135 
139 #ifdef CRN_USING_GTKMM3
140 Gdk::RGBA DrawingPanel::get_foreground() const
141 {
142  return Gdk::RGBA{}; // TODO
143 }
144 #else /* CRN_USING_GTKMM3 */
146 {
147  return fg_act->get_color();
148 }
149 #endif /* CRN_USING_GTKMM3 */
150 
154 #ifdef CRN_USING_GTKMM3
155 void DrawingPanel::set_foreground(const Gdk::RGBA& col)
156 {
157 }
158 #else /* CRN_USING_GTKMM3 */
159 void DrawingPanel::set_foreground(const Gdk::Color& col)
160 {
161  fg_act->set_color(col);
162 }
163 #endif /* CRN_USING_GTKMM3 */
164 
168 Glib::RefPtr<Gdk::Pixbuf> DrawingPanel::create_image()
169 {
170  int l = std::numeric_limits<int>::max(), t = std::numeric_limits<int>::max(), r = 0, b = 0;
171  for (const std::vector<crn::Point2DDouble> &stroke : stroke_list)
172  {
173  for (const crn::Point2DDouble &pnt : stroke)
174  {
175  int pl = int(floor(pnt.X));
176  int pt = int(floor(pnt.Y));
177  int pr = int(ceil(pnt.X));
178  int pb = int(ceil(pnt.Y));
179  if (pl < l) l = pl;
180  if (pt < t) t = pt;
181  if (pr > r) r = pr;
182  if (pb > b) b = pb;
183  }
184  }
185  if ((r == 0) || (b == 0))
186  {
187  return Glib::RefPtr<Gdk::Pixbuf>(nullptr);
188  }
189  int border = int(ceil(thickness));
190  r += border;
191  b += border;
192  l -= border; if (l < 0) l = 0;
193  t -= border; if (t < 0) t = 0;
194  Cairo::RefPtr<Cairo::ImageSurface> surf(Cairo::ImageSurface::create(Cairo::FORMAT_RGB24, r, b));
195  Cairo::RefPtr<Cairo::Context> cr(Cairo::Context::create(surf));
196 #ifdef CRN_USING_GTKMM3
197  //Gdk::Cairo::set_source_rgba(cr, bg_act->get_color());
198 #else /* CRN_USING_GTKMM3 */
199  cr->set_source_rgb(bg_act->get_color().get_red_p(), bg_act->get_color().get_green_p(), bg_act->get_color().get_blue_p());
200 #endif /* CRN_USING_GTKMM3 */
201  cr->move_to(0, 0);
202  cr->paint();
203 #ifdef CRN_USING_GTKMM3
204  //Gdk::Cairo::set_source_rgba(cr, fg_act->get_color());
205 #else /* CRN_USING_GTKMM3 */
206  cr->set_source_rgb(fg_act->get_color().get_red_p(), fg_act->get_color().get_green_p(), fg_act->get_color().get_blue_p());
207 #endif /* CRN_USING_GTKMM3 */
208  cr->set_line_join(Cairo::LINE_JOIN_ROUND);
209  cr->set_line_cap(Cairo::LINE_CAP_ROUND);
210  cr->set_line_width(thickness);
211  for (const std::vector<crn::Point2DDouble> &stroke : stroke_list)
212  {
213  if (stroke.size())
214  {
215  cr->move_to(stroke.front().X, stroke.front().Y);
216  for (size_t i = 1; i < stroke.size(); ++i)
217  {
218  cr->line_to(stroke[i].X, stroke[i].Y);
219  }
220  cr->stroke();
221  }
222  }
223  crn::Path tmpname(tmpnam(nullptr));
224  surf->write_to_png(tmpname.CStr());
225  Glib::RefPtr<Gdk::Pixbuf> pb = GdkCRN::PixbufFromFile(tmpname);
226  try
227  {
228  crn::IO::Rm(tmpname);
229  } catch (...) { }
230  Glib::RefPtr<Gdk::Pixbuf> fpb(Gdk::Pixbuf::create_subpixbuf(pb, l, t, r - l, b - t));
231  return fpb;
232 }
233 
237 bool DrawingPanel::draw()
238 {
239  Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();
240 #ifdef CRN_USING_GTKMM3
241  //Gdk::Cairo::set_source_rgba(cr, bg_act->get_color());
242 #else /* CRN_USING_GTKMM3 */
243  cr->set_source_rgb(bg_act->get_color().get_red_p(), bg_act->get_color().get_green_p(), bg_act->get_color().get_blue_p());
244 #endif /* CRN_USING_GTKMM3 */
245  cr->move_to(0, 0);
246  cr->paint();
247 #ifdef CRN_USING_GTKMM3
248  //Gdk::Cairo::set_source_rgba(cr, fg_act->get_color());
249 #else /* CRN_USING_GTKMM3 */
250  cr->set_source_rgb(fg_act->get_color().get_red_p(), fg_act->get_color().get_green_p(), fg_act->get_color().get_blue_p());
251 #endif /* CRN_USING_GTKMM3 */
252  cr->set_line_join(Cairo::LINE_JOIN_ROUND);
253  cr->set_line_cap(Cairo::LINE_CAP_ROUND);
254  cr->set_line_width(thickness * zoom);
255  for (const std::vector<crn::Point2DDouble> &stroke : stroke_list)
256  {
257  if (stroke.size())
258  {
259  cr->move_to(stroke.front().X * zoom, stroke.front().Y * zoom);
260  for (size_t i = 1; i < stroke.size(); ++i)
261  {
262  cr->line_to(stroke[i].X * zoom, stroke[i].Y * zoom);
263  }
264  cr->stroke();
265  }
266  }
267  return true;
268 }
269 
274 bool DrawingPanel::on_button_press(GdkEventButton *ev)
275 {
276  stroke_list.push_back(std::vector<crn::Point2DDouble>());
277  stroke_list.back().push_back(crn::Point2DDouble(ev->x / zoom, ev->y / zoom));
278  return true;
279 }
280 
285 bool DrawingPanel::on_motion(GdkEventMotion *ev)
286 {
287  stroke_list.back().push_back(crn::Point2DDouble(ev->x / zoom, ev->y / zoom));
288  queue_draw();
289  return true;
290 }
291 
296 #ifdef CRN_USING_GTKMM3
297 bool DrawingPanel::on_expose(const Cairo::RefPtr<Cairo::Context> &)
298 #else /* CRN_USING_GTKMM3 */
299 bool DrawingPanel::on_expose(GdkEventExpose *ev)
300 #endif /* CRN_USING_GTKMM3 */
301 {
302  draw();
303  return true;
304 }
305 
309 void DrawingPanel::modify_thickness(double val)
310 {
311  thickness += val;
312  if (thickness <= 0)
313  thickness = 0.2;
314 #ifdef CRN_USING_GTKMM3
315  //thick_act->get_adjustment()->set_value(thickness);
316 #else /* CRN_USING_GTKMM3 */
317  thick_act->get_adjustment().set_value(thickness);
318 #endif /* CRN_USING_GTKMM3 */
319  queue_draw();
320 }
321 
323 void DrawingPanel::on_thickness_set()
324 {
325 #ifdef CRN_USING_GTKMM3
326  //thickness = thick_act->get_adjustment()->get_value();
327 #else /* CRN_USING_GTKMM3 */
328  thickness = thick_act->get_adjustment().get_value();
329 #endif /* CRN_USING_GTKMM3 */
330  queue_draw();
331 }
332 
333 #endif
A 2D point class.
Glib::RefPtr< Gdk::Pixbuf > create_image()
Renders the panel to a Pixbuf.
Glib::RefPtr< Gdk::Pixbuf > PixbufFromFile(const crn::Path &p)
Creates a Gdk::Pixbuf from a file.
static Glib::RefPtr< ScaleAction > create()
Creates a blank ScaleAction.
#define _(String)
Definition: CRNi18n.h:51
Gdk::Color get_background() const
Gets the background color.
void set_zoom(double z)
Sets the zoom level.
void set_background(const Gdk::Color &col)
Sets the background color.
const char * CStr() const noexcept
Conversion to UTF8 cstring.
void clear()
Clears the panel.
A convenience class for file paths.
Definition: CRNPath.h:39
static Glib::RefPtr< ColorAction > create()
Creates a blank ColorAction.
static void Rm(const Path &name)
Removes a file.
Definition: CRNIO.cpp:175
void set_foreground(const Gdk::Color &col)
Sets the foreground color.
Gdk::Color get_foreground() const
Gets the foreground color.