Visual Servoing Platform  version 3.5.0 under development (2022-02-15)
vpDisplayGTK.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Image display.
33  *
34  * Authors:
35  * Christophe Collewet
36  * Eric Marchand
37  * Fabien Spindler
38  *
39  *****************************************************************************/
40 
46 #include <visp3/core/vpConfig.h>
47 
48 #if (defined(VISP_HAVE_GTK))
49 
50 #include <cmath> // std::fabs
51 #include <iostream>
52 #include <limits> // numeric_limits
53 #include <stdio.h>
54 #include <stdlib.h>
55 
56 // Display stuff
57 #include <visp3/core/vpDisplay.h>
58 #include <visp3/gui/vpDisplayGTK.h>
59 
60 // debug / exception
61 #include <visp3/core/vpDebug.h>
62 #include <visp3/core/vpDisplayException.h>
63 #include <visp3/core/vpImageConvert.h>
64 #include <visp3/core/vpImageTools.h>
65 #include <visp3/core/vpMath.h>
66 
67 #ifndef DOXYGEN_SHOULD_SKIP_THIS
68 
69 #include <gtk/gtk.h>
70 #include <gdk/gdk.h>
71 #include <gdk/gdkrgb.h>
72 
73 class vpDisplayGTK::Impl
74 {
75 public:
76  Impl()
77  : m_widget(NULL), m_background(NULL), m_gc(NULL), m_blue(), m_red(), m_yellow(), m_green(), m_cyan(), m_orange(),
78  m_white(), m_black(), m_gdkcolor(), m_lightBlue(), m_darkBlue(), m_lightRed(), m_darkRed(), m_lightGreen(), m_darkGreen(),
79  m_purple(), m_lightGray(), m_gray(), m_darkGray(), m_colormap(NULL), m_font(NULL), m_vectgtk(NULL), m_col(NULL)
80  {
81 
82  }
83 
84  ~Impl() {}
85 
86  void init(unsigned int win_width, unsigned int win_height, int win_x, int win_y, const std::string &title)
87  {
88  gint width = static_cast<gint>(win_width);
89  gint height = static_cast<gint>(win_height);
90 
91  /* Initialisation of the gdk et gdk_rgb library */
92  int *argc = NULL;
93  char **argv;
94 
95  gtk_init(argc, &argv);
96 
97  /* Create the window*/
98  m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
99 
100  gtk_widget_add_events(m_widget, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
101 
102  gtk_window_set_default_size(GTK_WINDOW(m_widget), width, height);
103 
104  gtk_window_move(GTK_WINDOW(m_widget), win_x, win_y);
105 
106  gtk_widget_show(m_widget);
107 
108  gdk_rgb_init();
109 
110  /* Create background pixmap */
111  m_background = gdk_pixmap_new(m_widget->window, width, height, -1);
112 
113  /* Create graphic context */
114  m_gc = gdk_gc_new(m_widget->window);
115 
116  /* get the colormap */
117  m_colormap = gdk_window_get_colormap(m_widget->window);
118 
119  m_col = new GdkColor *[vpColor::id_unknown]; // id_unknown = number of predefined colors
120 
121  /* Create color */
122  gdk_color_parse("light blue", &m_lightBlue);
123  gdk_colormap_alloc_color(m_colormap, &m_lightBlue, FALSE, TRUE);
124  m_col[vpColor::id_lightBlue] = &m_lightBlue;
125 
126  gdk_color_parse("blue", &m_blue);
127  gdk_colormap_alloc_color(m_colormap, &m_blue, FALSE, TRUE);
128  m_col[vpColor::id_blue] = &m_blue;
129 
130  gdk_color_parse("dark blue", &m_darkBlue);
131  gdk_colormap_alloc_color(m_colormap, &m_darkBlue, FALSE, TRUE);
132  m_col[vpColor::id_darkBlue] = &m_darkBlue;
133 
134  gdk_color_parse("#FF8C8C", &m_lightRed);
135  gdk_colormap_alloc_color(m_colormap, &m_lightRed, FALSE, TRUE);
136  m_col[vpColor::id_lightRed] = &m_lightRed;
137 
138  gdk_color_parse("red", &m_red);
139  gdk_colormap_alloc_color(m_colormap, &m_red, FALSE, TRUE);
140  m_col[vpColor::id_red] = &m_red;
141 
142  gdk_color_parse("dark red", &m_darkRed);
143  gdk_colormap_alloc_color(m_colormap, &m_darkRed, FALSE, TRUE);
144  m_col[vpColor::id_darkRed] = &m_darkRed;
145 
146  gdk_color_parse("light green", &m_lightGreen);
147  gdk_colormap_alloc_color(m_colormap, &m_lightGreen, FALSE, TRUE);
148  m_col[vpColor::id_lightGreen] = &m_lightGreen;
149 
150  gdk_color_parse("green", &m_green);
151  gdk_colormap_alloc_color(m_colormap, &m_green, FALSE, TRUE);
152  m_col[vpColor::id_green] = &m_green;
153 
154  gdk_color_parse("dark green", &m_darkGreen);
155  gdk_colormap_alloc_color(m_colormap, &m_darkGreen, FALSE, TRUE);
156  m_col[vpColor::id_darkGreen] = &m_darkGreen;
157 
158  gdk_color_parse("yellow", &m_yellow);
159  gdk_colormap_alloc_color(m_colormap, &m_yellow, FALSE, TRUE);
160  m_col[vpColor::id_yellow] = &m_yellow;
161 
162  gdk_color_parse("cyan", &m_cyan);
163  gdk_colormap_alloc_color(m_colormap, &m_cyan, FALSE, TRUE);
164  m_col[vpColor::id_cyan] = &m_cyan;
165 
166  gdk_color_parse("orange", &m_orange);
167  gdk_colormap_alloc_color(m_colormap, &m_orange, FALSE, TRUE);
168  m_col[vpColor::id_orange] = &m_orange;
169 
170  gdk_color_parse("purple", &m_purple);
171  gdk_colormap_alloc_color(m_colormap, &m_purple, FALSE, TRUE);
172  m_col[vpColor::id_purple] = &m_purple;
173 
174  gdk_color_parse("white", &m_white);
175  gdk_colormap_alloc_color(m_colormap, &m_white, FALSE, TRUE);
176  m_col[vpColor::id_white] = &m_white;
177 
178  gdk_color_parse("black", &m_black);
179  gdk_colormap_alloc_color(m_colormap, &m_black, FALSE, TRUE);
180  m_col[vpColor::id_black] = &m_black;
181 
182  gdk_color_parse("#C0C0C0", &m_lightGray);
183  gdk_colormap_alloc_color(m_colormap, &m_lightGray, FALSE, TRUE);
184  m_col[vpColor::id_lightGray] = &m_lightGray;
185 
186  gdk_color_parse("#808080", &m_gray);
187  gdk_colormap_alloc_color(m_colormap, &m_gray, FALSE, TRUE);
188  m_col[vpColor::id_gray] = &m_gray;
189 
190  gdk_color_parse("#404040", &m_darkGray);
191  gdk_colormap_alloc_color(m_colormap, &m_darkGray, FALSE, TRUE);
192  m_col[vpColor::id_darkGray] = &m_darkGray;
193 
194  // Try to load a default font
195  m_font = gdk_font_load("-*-times-medium-r-normal-*-16-*-*-*-*-*-*-*");
196  if (m_font == NULL)
197  m_font = gdk_font_load("-*-courier-bold-r-normal-*-*-140-*-*-*-*-*-*");
198  if (m_font == NULL)
199  m_font = gdk_font_load("-*-courier 10 pitch-medium-r-normal-*-16-*-*-*-*-*-*-*");
200 
201  if (!title.empty())
202  gdk_window_set_title(m_widget->window, title.c_str());
203  }
204 
205  void setFont(const std::string &fontname)
206  {
207  m_font = gdk_font_load((const gchar *)fontname.c_str());
208  }
209 
210  void setTitle(const std::string &title)
211  {
212  gdk_window_set_title(m_widget->window, title.c_str());
213  }
214 
215  void setWindowPosition(int win_x, int win_y)
216  {
217  gtk_window_move(GTK_WINDOW(m_widget), win_x, win_y);
218  }
219 
220  void displayImage(const vpImage<unsigned char> &I, unsigned int scale, gint width, gint height)
221  {
222  if (scale == 1) {
223  /* Copie de l'image dans le pixmap fond */
224  gdk_draw_gray_image(m_background, m_gc, 0, 0, width, height, GDK_RGB_DITHER_NONE, I.bitmap, width);
225  } else {
226  vpImage<unsigned char> sampled;
227  I.subsample(scale, scale, sampled);
228  gdk_draw_gray_image(m_background, m_gc, 0, 0, width, height, GDK_RGB_DITHER_NONE, sampled.bitmap, width);
229  }
230 
231  /* Le pixmap background devient le fond de la zone de dessin */
232  gdk_window_set_back_pixmap(m_widget->window, m_background, FALSE);
233  }
234 
235  void displayImage(const vpImage<vpRGBa> &I, unsigned int scale, gint width, gint height)
236  {
237  if (scale == 1) {
238  /* Copie de l'image dans le pixmap fond */
239  gdk_draw_rgb_32_image(m_background, m_gc, 0, 0, width, height, GDK_RGB_DITHER_NONE, (unsigned char *)I.bitmap, 4 * width);
240  } else {
241  vpImage<vpRGBa> sampled;
242  I.subsample(scale, scale, sampled);
243  gdk_draw_rgb_32_image(m_background, m_gc, 0, 0, width, height, GDK_RGB_DITHER_NONE, (unsigned char *)sampled.bitmap, 4 * width);
244  }
245 
246  /* Le pixmap background devient le fond de la zone de dessin */
247  gdk_window_set_back_pixmap(m_widget->window, m_background, FALSE);
248  }
249 
250  void displayImageROI(const vpImage<unsigned char> &I, gint j_min, gint i_min, gint width, gint height)
251  {
252  gdk_draw_gray_image(m_background, m_gc, j_min, i_min,
253  width, height, GDK_RGB_DITHER_NONE, I.bitmap, width);
254  /* Le pixmap background devient le fond de la zone de dessin */
255  gdk_window_set_back_pixmap(m_widget->window, m_background, FALSE);
256  }
257 
258  void displayImageROI(const vpImage<vpRGBa> &I, gint j_min, gint i_min, gint width, gint height)
259  {
260  gdk_draw_rgb_32_image(m_background, m_gc, j_min, i_min, width, height, GDK_RGB_DITHER_NONE,
261  (unsigned char *)I.bitmap, width * 4);
262 
263  /* Le pixmap background devient le fond de la zone de dessin */
264  gdk_window_set_back_pixmap(m_widget->window, m_background, FALSE);
265  }
266 
267  void closeDisplay()
268  {
269  if (m_col != NULL) {
270  delete[] m_col;
271  m_col = NULL;
272  }
273 
274  if (m_widget != NULL) {
275  gdk_window_hide(m_widget->window);
276  gdk_window_destroy(m_widget->window);
277  gtk_widget_destroy(m_widget);
278  m_widget = NULL;
279  }
280  }
281 
282  void flushDisplay()
283  {
284  gdk_window_clear(m_widget->window);
285  gdk_flush();
286  }
287 
288  void displayCharString(const vpImagePoint &ip, const char *text, const vpColor &color, unsigned int scale)
289  {
290  if (color.id < vpColor::id_unknown)
291  gdk_gc_set_foreground(m_gc, m_col[color.id]);
292  else {
293  m_gdkcolor.red = 256 * color.R;
294  m_gdkcolor.green = 256 * color.G;
295  m_gdkcolor.blue = 256 * color.B;
296  gdk_colormap_alloc_color(m_colormap, &m_gdkcolor, FALSE, TRUE);
297  gdk_gc_set_foreground(m_gc, &m_gdkcolor);
298  }
299  if (m_font != NULL)
300  gdk_draw_string(m_background, m_font, m_gc, vpMath::round(ip.get_u() / scale),
301  vpMath::round(ip.get_v() / scale), (const gchar *)text);
302  else
303  std::cout << "Cannot draw string: no font is selected" << std::endl;
304  }
305 
306  void displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill,
307  unsigned int thickness, unsigned int scale)
308  {
309  if (color.id < vpColor::id_unknown)
310  gdk_gc_set_foreground(m_gc, m_col[color.id]);
311  else {
312  m_gdkcolor.red = 256 * color.R;
313  m_gdkcolor.green = 256 * color.G;
314  m_gdkcolor.blue = 256 * color.B;
315  gdk_colormap_alloc_color(m_colormap, &m_gdkcolor, FALSE, TRUE);
316  gdk_gc_set_foreground(m_gc, &m_gdkcolor);
317  }
318 
319  gdk_gc_set_line_attributes(m_gc, static_cast<gint>(thickness), GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
320 
321  if (fill == false)
322  gdk_draw_arc(m_background, m_gc, FALSE, vpMath::round((center.get_u() - radius) / scale),
323  vpMath::round((center.get_v() - radius) / scale), static_cast<gint>(2. * radius / scale),
324  static_cast<gint>(2. * radius / scale), 23040, 23040); /* 23040 = 360*64 */
325  else
326  gdk_draw_arc(m_background, m_gc, TRUE, vpMath::round((center.get_u() - radius) / scale),
327  vpMath::round((center.get_v() - radius) / scale), static_cast<gint>(2. * radius / scale),
328  static_cast<gint>(2. * radius / scale), 23040, 23040); /* 23040 = 360*64 */
329  }
330 
331  void displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness, unsigned int scale)
332  {
333  if (color.id < vpColor::id_unknown)
334  gdk_gc_set_foreground(m_gc, m_col[color.id]);
335  else {
336  m_gdkcolor.red = 256 * color.R;
337  m_gdkcolor.green = 256 * color.G;
338  m_gdkcolor.blue = 256 * color.B;
339  gdk_colormap_alloc_color(m_colormap, &m_gdkcolor, FALSE, TRUE);
340  gdk_gc_set_foreground(m_gc, &m_gdkcolor);
341  }
342 
343  gdk_gc_set_line_attributes(m_gc, static_cast<gint>(thickness), GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
344  gdk_draw_line(m_background, m_gc, vpMath::round(ip1.get_u() / scale), vpMath::round(ip1.get_v() / scale),
345  vpMath::round(ip2.get_u() / scale), vpMath::round(ip2.get_v() / scale));
346  gdk_gc_set_line_attributes(m_gc, 0, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
347  }
348 
349  void displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness, unsigned int scale)
350  {
351  if (color.id < vpColor::id_unknown)
352  gdk_gc_set_foreground(m_gc, m_col[color.id]);
353  else {
354  m_gdkcolor.red = 256 * color.R;
355  m_gdkcolor.green = 256 * color.G;
356  m_gdkcolor.blue = 256 * color.B;
357  gdk_colormap_alloc_color(m_colormap, &m_gdkcolor, FALSE, TRUE);
358  gdk_gc_set_foreground(m_gc, &m_gdkcolor);
359  }
360 
361  gdk_gc_set_line_attributes(m_gc, static_cast<gint>(thickness), GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
362  gdk_draw_line(m_background, m_gc, vpMath::round(ip1.get_u() / scale), vpMath::round(ip1.get_v() / scale),
363  vpMath::round(ip2.get_u() / scale), vpMath::round(ip2.get_v() / scale));
364  }
365 
366  void displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness, unsigned int scale)
367  {
368  if (color.id < vpColor::id_unknown)
369  gdk_gc_set_foreground(m_gc, m_col[color.id]);
370  else {
371  m_gdkcolor.red = 256 * color.R;
372  m_gdkcolor.green = 256 * color.G;
373  m_gdkcolor.blue = 256 * color.B;
374  gdk_colormap_alloc_color(m_colormap, &m_gdkcolor, FALSE, TRUE);
375  gdk_gc_set_foreground(m_gc, &m_gdkcolor);
376  }
377 
378  if (thickness == 1) {
379  gdk_draw_point(m_background, m_gc, vpMath::round(ip.get_u() / scale), vpMath::round(ip.get_v() / scale));
380  } else {
381  gdk_draw_rectangle(m_background, m_gc, TRUE, vpMath::round(ip.get_u() / scale),
382  vpMath::round(ip.get_v() / scale), static_cast<gint>(thickness), static_cast<gint>(thickness));
383  }
384  }
385 
386  void displayRectangle(const vpImagePoint &topLeft, unsigned int w, unsigned int h, const vpColor &color,
387  bool fill, unsigned int thickness, unsigned int scale)
388  {
389  if (color.id < vpColor::id_unknown)
390  gdk_gc_set_foreground(m_gc, m_col[color.id]);
391  else {
392  m_gdkcolor.red = 256 * color.R;
393  m_gdkcolor.green = 256 * color.G;
394  m_gdkcolor.blue = 256 * color.B;
395  gdk_colormap_alloc_color(m_colormap, &m_gdkcolor, FALSE, TRUE);
396  gdk_gc_set_foreground(m_gc, &m_gdkcolor);
397  }
398  gdk_gc_set_line_attributes(m_gc, static_cast<gint>(thickness), GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
399 
400  if (fill == false)
401  gdk_draw_rectangle(m_background, m_gc, FALSE, vpMath::round(topLeft.get_u() / scale),
402  vpMath::round(topLeft.get_v() / scale), static_cast<gint>(w / scale), static_cast<gint>(h / scale));
403  else
404  gdk_draw_rectangle(m_background, m_gc, TRUE, vpMath::round(topLeft.get_u() / scale),
405  vpMath::round(topLeft.get_v() / scale), static_cast<gint>(w / scale), static_cast<gint>(h / scale));
406 
407  if (thickness > 1)
408  gdk_gc_set_line_attributes(m_gc, 0, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL);
409  }
410 
411  bool getClick(vpImagePoint &ip, vpMouseButton::vpMouseButtonType &button, bool blocking, unsigned int scale, const GdkEventType &event_type)
412  {
413  bool ret = false;
414  do {
415  GdkEvent *ev = NULL;
416  while ((ev = gdk_event_get())) {
417  if (ev->any.window == m_widget->window && ev->type == event_type) {
418  double u = ((GdkEventButton *)ev)->x;
419  double v = ((GdkEventButton *)ev)->y;
420  ip.set_u(u * scale);
421  ip.set_v(v * scale);
422 
423  switch (static_cast<int>(((GdkEventButton *)ev)->button)) {
424  case 1:
425  button = vpMouseButton::button1;
426  break;
427  case 2:
428  button = vpMouseButton::button2;
429  break;
430  case 3:
431  button = vpMouseButton::button3;
432  break;
433  }
434  ret = true;
435  }
436  gdk_event_free(ev);
437  }
438  if (blocking) {
439  flushDisplay();
440  vpTime::wait(100);
441  }
442 
443  } while (ret == false && blocking == true);
444  return ret;
445  }
446 
447  void getImage(vpImage<vpRGBa> &I, gint width, gint height)
448  {
449  GdkImage *ImageGtk;
450  ImageGtk = gdk_image_get(m_background, 0, 0, width, height);
451 
452  I.resize(height, width);
453  guint32 pixel;
454 
455  guchar OctetRouge, OctetVert, OctetBleu, mask;
456  mask = 0x000000FF;
457 
458  for (gint y = 0; y < height; y++) {
459  for (gint x = 0; x < width; x++) {
460  pixel = gdk_image_get_pixel(ImageGtk, x, y);
461  OctetBleu = static_cast<guchar>(pixel) & mask;
462  OctetVert = static_cast<guchar>(pixel >> 8) & mask;
463  OctetRouge = static_cast<guchar>(pixel >> 16) & mask;
464  I[y][x].R = OctetRouge;
465  I[y][x].G = OctetVert;
466  I[y][x].B = OctetBleu;
467  I[y][x].A = vpRGBa::alpha_default; // default opacity
468  }
469  }
470  }
471 
472  unsigned int getScreenDepth()
473  {
474  return static_cast<unsigned int>(gdk_window_get_visual(m_widget->window)->depth);
475  }
476 
477  bool getKeyboardEvent(std::string &key, bool blocking)
478  {
479  bool ret = false;
480  int cpt = 0;
481  do {
482  GdkEvent *ev = NULL;
483  while ((ev = gdk_event_get()) != NULL) {
484  cpt++;
485  // printf("event %d type %d on window %p My window %p\n",
486  // cpt, ev->type, ev->any.window, widget->window);
487 
488  if (ev->any.window == m_widget->window && ev->type == GDK_KEY_PRESS) {
489  // std::cout << "Key val: \"" << gdk_keyval_name (ev->key.keyval)
490  // /*ev->key.string*/ << "\"" << std::endl;
491  key = gdk_keyval_name(ev->key.keyval);
492  ret = true;
493  // printf("Key press detection\n");
494  }
495  gdk_event_free(ev);
496  }
497  if (blocking) {
498  flushDisplay();
499  vpTime::wait(100);
500  }
501  } while (ret == false && blocking == true);
502  return ret;
503  }
504 
505  bool getPointerMotionEvent(vpImagePoint &ip, unsigned int scale)
506  {
507  bool ret = false;
508  GdkEvent *ev = NULL;
509  if ((ev = gdk_event_get())) {
510  if (ev->any.window == m_widget->window && ev->type == GDK_MOTION_NOTIFY) {
511  double u = ((GdkEventMotion *)ev)->x;
512  double v = ((GdkEventMotion *)ev)->y;
513  ip.set_u(u * scale);
514  ip.set_v(v * scale);
515 
516  ret = true;
517  }
518  gdk_event_free(ev);
519  }
520  return ret;
521  }
522 
523  void getPointerPosition(vpImagePoint &ip, unsigned int scale)
524  {
525  gint u, v;
526  gdk_window_get_pointer(m_widget->window, &u, &v, NULL);
527  ip.set_u(static_cast<double>(u) * scale);
528  ip.set_v(static_cast<double>(v) * scale);
529  }
530 
531  void getScreenSize(bool is_init, unsigned int &w, unsigned int &h)
532  {
533  if (!is_init) {
534  int *argc = NULL;
535  char **argv;
536 
537  gtk_init(argc, &argv);
538 
539  GtkWidget *widget_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
540  gtk_window_set_default_size(GTK_WINDOW(widget_), 100, 100);
541  gtk_widget_show(widget_);
542 
543  GdkScreen *screen_ = gdk_window_get_screen(widget_->window);
544  w = static_cast<unsigned int>(gdk_screen_get_width(screen_));
545  h = static_cast<unsigned int>(gdk_screen_get_height(screen_));
546  gtk_widget_destroy(widget_);
547  } else {
548  GdkScreen *screen_ = gdk_window_get_screen(m_widget->window);
549  w = static_cast<unsigned int>(gdk_screen_get_width(screen_));
550  h = static_cast<unsigned int>(gdk_screen_get_height(screen_));
551  }
552  }
553 
554 private:
555  GtkWidget *m_widget;
556  GdkPixmap *m_background;
557  GdkGC *m_gc;
558  GdkColor m_blue, m_red, m_yellow, m_green, m_cyan, m_orange, m_white, m_black, m_gdkcolor;
559  GdkColor m_lightBlue, m_darkBlue, m_lightRed, m_darkRed, m_lightGreen, m_darkGreen, m_purple;
560  GdkColor m_lightGray, m_gray, m_darkGray;
561  GdkColormap *m_colormap;
562 
563  GdkFont *m_font;
564  guchar *m_vectgtk;
565  GdkColor **m_col;
566 };
567 
568 #endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
569 
592  : vpDisplay(), m_impl(new Impl())
593 {
594  setScale(scaleType, I.getWidth(), I.getHeight());
595  init(I);
596 }
597 
621 vpDisplayGTK::vpDisplayGTK(vpImage<unsigned char> &I, int win_x, int win_y, const std::string &win_title, vpScaleType scaleType)
622  : vpDisplay(), m_impl(new Impl())
623 {
624  setScale(scaleType, I.getWidth(), I.getHeight());
625  init(I, win_x, win_y, win_title);
626 }
627 
648  : vpDisplay(), m_impl(new Impl())
649 {
650  setScale(scaleType, I.getWidth(), I.getHeight());
651  init(I);
652 }
653 
675 vpDisplayGTK::vpDisplayGTK(vpImage<vpRGBa> &I, int win_x, int win_y, const std::string &win_title, vpScaleType scaleType)
676  : vpDisplay(), m_impl(new Impl())
677 {
678  setScale(scaleType, I.getWidth(), I.getHeight());
679  init(I, win_x, win_y, win_title);
680 }
681 
704 vpDisplayGTK::vpDisplayGTK(int win_x, int win_y, const std::string &win_title)
705  : vpDisplay(), m_impl(new Impl())
706 {
707  m_windowXPosition = win_x;
708  m_windowYPosition = win_y;
709  m_title = win_title;
710 }
711 
732  : vpDisplay(), m_impl(new Impl())
733 {
734 }
735 
740 {
741  closeDisplay();
742  delete m_impl;
743 }
744 
753 void vpDisplayGTK::init(vpImage<unsigned char> &I, int win_x, int win_y, const std::string &win_title)
754 {
755  if ((I.getHeight() == 0) || (I.getWidth() == 0)) {
756  throw(vpDisplayException(vpDisplayException::notInitializedError, "Image not initialized"));
757  }
758 
759  if (win_x != -1)
760  m_windowXPosition = win_x;
761  if (win_y != -1)
762  m_windowYPosition = win_y;
763 
764  if (!win_title.empty())
765  m_title = win_title;
766 
769 
770  I.display = this;
772 }
773 
783 void vpDisplayGTK::init(vpImage<vpRGBa> &I, int win_x, int win_y, const std::string &win_title)
784 {
785  if ((I.getHeight() == 0) || (I.getWidth() == 0)) {
786  throw(vpDisplayException(vpDisplayException::notInitializedError, "Image not initialized"));
787  }
788 
789  if (win_x != -1)
790  m_windowXPosition = win_x;
791  if (win_y != -1)
792  m_windowYPosition = win_y;
793 
794  if (!win_title.empty())
795  m_title = win_title;
796 
799 
800  I.display = this;
802 }
803 
812 void vpDisplayGTK::init(unsigned int win_width, unsigned int win_height, int win_x, int win_y, const std::string &win_title)
813 {
814  setScale(m_scaleType, win_width, win_height);
815 
816  m_width = win_width / m_scale;
817  m_height = win_height / m_scale;
818 
819  if (win_x != -1)
820  m_windowXPosition = win_x;
821  if (win_y != -1)
822  m_windowYPosition = win_y;
823 
824  m_title = win_title;
825 
827 
829 }
830 
843 void vpDisplayGTK::setFont(const std::string &fontname)
844 {
845  m_impl->setFont(fontname);
846 }
847 
852 void vpDisplayGTK::setTitle(const std::string &title)
853 {
855  m_title = title;
856  if (!title.empty()) {
857  m_impl->setTitle(title);
858  }
859  } else {
860  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
861  }
862 }
863 
873 void vpDisplayGTK::setWindowPosition(int win_x, int win_y)
874 {
876  m_impl->setWindowPosition(win_x, win_y);
877  } else {
878  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
879  }
880 }
881 
894 {
896  m_impl->displayImage(I, m_scale, static_cast<gint>(m_width), static_cast<gint>(m_height));
897  } else {
898  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
899  }
900 }
901 
919 void vpDisplayGTK::displayImageROI(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int w,
920  unsigned int h)
921 {
924  vpImageTools::crop(I, iP.get_i(), iP.get_j(), h, w, Itemp, m_scale, m_scale);
925 
926  /* Copie de l'image dans le pixmap fond */
927  int i_min = (std::max)(static_cast<int>(ceil(iP.get_i() / m_scale)), 0);
928  int j_min = (std::max)(static_cast<int>(ceil(iP.get_j() / m_scale)), 0);
929 
930  m_impl->displayImageROI(Itemp, static_cast<gint>(j_min), static_cast<gint>(i_min),
931  static_cast<gint>(Itemp.getWidth()), static_cast<gint>(Itemp.getHeight()));
932  } else {
933  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
934  }
935 }
936 
949 {
951  m_impl->displayImage(I, m_scale, static_cast<gint>(m_width), static_cast<gint>(m_height));
952  } else {
953  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
954  }
955 }
956 
974 void vpDisplayGTK::displayImageROI(const vpImage<vpRGBa> &I, const vpImagePoint &iP, unsigned int w,
975  unsigned int h)
976 {
978  vpImage<vpRGBa> Itemp;
979  vpImageTools::crop(I, iP.get_i(), iP.get_j(), h, w, Itemp, m_scale, m_scale);
980 
981  /* Copie de l'image dans le pixmap fond */
982  int i_min = (std::max)(static_cast<int>(ceil(iP.get_i() / m_scale)), 0);
983  int j_min = (std::max)(static_cast<int>(ceil(iP.get_j() / m_scale)), 0);
984 
985  m_impl->displayImageROI(Itemp, static_cast<gint>(j_min), static_cast<gint>(i_min),
986  static_cast<gint>(Itemp.getWidth()), static_cast<gint>(Itemp.getHeight()));
987  } else {
988  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
989  }
990 }
991 
997 void vpDisplayGTK::displayImage(const unsigned char * /* I */) { vpTRACE(" not implemented "); }
998 
1005 {
1007  m_impl->closeDisplay();
1008 
1010  }
1011 }
1012 
1018 {
1020  m_impl->flushDisplay();
1021  } else {
1022  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1023  }
1024 }
1025 
1030 void vpDisplayGTK::flushDisplayROI(const vpImagePoint & /*iP*/, const unsigned int /*width*/,
1031  const unsigned int /*height*/)
1032 {
1034  m_impl->flushDisplay();
1035  } else {
1036  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1037  }
1038 }
1039 
1043 void vpDisplayGTK::clearDisplay(const vpColor & /* color */) { vpTRACE("Not implemented"); }
1044 
1052 void vpDisplayGTK::displayArrow(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int w,
1053  unsigned int h, unsigned int thickness)
1054 {
1056  double a = ip2.get_i() - ip1.get_i();
1057  double b = ip2.get_j() - ip1.get_j();
1058  double lg = sqrt(vpMath::sqr(a) + vpMath::sqr(b));
1059 
1060  if ((std::fabs(a) > std::numeric_limits<double>::epsilon()) &&
1061  (std::fabs(b) > std::numeric_limits<double>::epsilon())) {
1062  a /= lg;
1063  b /= lg;
1064 
1065  vpImagePoint ip3;
1066  ip3.set_i(ip2.get_i() - w * a);
1067  ip3.set_j(ip2.get_j() - w * b);
1068 
1069  vpImagePoint ip4;
1070  ip4.set_i(ip3.get_i() - b * h);
1071  ip4.set_j(ip3.get_j() + a * h);
1072 
1073  if (lg > 2 * vpImagePoint::distance(ip2, ip4))
1074  displayLine(ip2, ip4, color, thickness);
1075 
1076  ip4.set_i(ip3.get_i() + b * h);
1077  ip4.set_j(ip3.get_j() - a * h);
1078 
1079  if (lg > 2 * vpImagePoint::distance(ip2, ip4))
1080  displayLine(ip2, ip4, color, thickness);
1081 
1082  displayLine(ip1, ip2, color, thickness);
1083  }
1084  } else {
1085  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1086  }
1087 }
1088 
1100 void vpDisplayGTK::displayCharString(const vpImagePoint &ip, const char *text, const vpColor &color)
1101 {
1103  m_impl->displayCharString(ip, text, color, m_scale);
1104  } else {
1105  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1106  }
1107 }
1117 void vpDisplayGTK::displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill,
1118  unsigned int thickness)
1119 {
1121  if (thickness == 1)
1122  thickness = 0;
1123 
1124  m_impl->displayCircle(center, radius, color, fill, thickness, m_scale);
1125  } else {
1126  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1127  }
1128 }
1136 void vpDisplayGTK::displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness)
1137 {
1139  double i = ip.get_i();
1140  double j = ip.get_j();
1141  vpImagePoint ip1, ip2;
1142 
1143  ip1.set_i(i - size / 2);
1144  ip1.set_j(j);
1145  ip2.set_i(i + size / 2);
1146  ip2.set_j(j);
1147  displayLine(ip1, ip2, color, thickness);
1148 
1149  ip1.set_i(i);
1150  ip1.set_j(j - size / 2);
1151  ip2.set_i(i);
1152  ip2.set_j(j + size / 2);
1153 
1154  displayLine(ip1, ip2, color, thickness);
1155  }
1156 
1157  else {
1158  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1159  }
1160 }
1167 void vpDisplayGTK::displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
1168  unsigned int thickness)
1169 {
1170 
1172  if (thickness == 1)
1173  thickness = 0;
1174 
1175  m_impl->displayDotLine(ip1, ip2, color, thickness, m_scale);
1176  } else {
1177  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1178  }
1179 }
1180 
1187 void vpDisplayGTK::displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
1188  unsigned int thickness)
1189 {
1191  if (thickness == 1)
1192  thickness = 0;
1193 
1194  m_impl->displayLine(ip1, ip2, color, thickness, m_scale);
1195  } else {
1196  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1197  }
1198 }
1199 
1206 void vpDisplayGTK::displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness)
1207 {
1209  m_impl->displayPoint(ip, color, thickness, m_scale);
1210  } else {
1211  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1212  }
1213 }
1214 
1228 void vpDisplayGTK::displayRectangle(const vpImagePoint &topLeft, unsigned int w, unsigned int h, const vpColor &color,
1229  bool fill, unsigned int thickness)
1230 {
1232  if (thickness == 1)
1233  thickness = 0;
1234 
1235  m_impl->displayRectangle(topLeft, w, h, color, fill, thickness, m_scale);
1236  } else {
1237  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1238  }
1239 }
1240 
1253 void vpDisplayGTK::displayRectangle(const vpImagePoint &topLeft, const vpImagePoint &bottomRight, const vpColor &color,
1254  bool fill, unsigned int thickness)
1255 {
1257  if (thickness == 1)
1258  thickness = 0;
1259 
1260  unsigned int w = static_cast<unsigned int>(vpMath::round(bottomRight.get_u() - topLeft.get_u()));
1261  unsigned int h = static_cast<unsigned int>(vpMath::round(bottomRight.get_v() - topLeft.get_v()));
1262 
1263  m_impl->displayRectangle(topLeft, w, h, color, fill, thickness, m_scale);
1264  } else {
1265  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1266  }
1267 }
1268 
1281 void vpDisplayGTK::displayRectangle(const vpRect &rectangle, const vpColor &color, bool fill, unsigned int thickness)
1282 {
1284  if (thickness == 1)
1285  thickness = 0;
1286 
1287  vpImagePoint topLeft = rectangle.getTopLeft();
1288  unsigned int w = static_cast<unsigned int>(vpMath::round(rectangle.getWidth()));
1289  unsigned int h = static_cast<unsigned int>(vpMath::round(rectangle.getRight()));
1290  m_impl->displayRectangle(topLeft, w, h, color, fill, thickness, m_scale);
1291  } else {
1292  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1293  }
1294 }
1295 
1311 bool vpDisplayGTK::getClick(bool blocking)
1312 {
1313  bool ret = false;
1314 
1316  vpImagePoint ip;
1318  ret = m_impl->getClick(ip, button, blocking, m_scale, GDK_BUTTON_PRESS);
1319  } else {
1320  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1321  }
1322  return ret;
1323 }
1324 
1341 bool vpDisplayGTK::getClick(vpImagePoint &ip, bool blocking)
1342 {
1343  bool ret = false;
1344 
1347  ret = m_impl->getClick(ip, button, blocking, m_scale, GDK_BUTTON_PRESS);
1348  } else {
1349  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1350  }
1351  return ret;
1352 }
1353 
1374 {
1375  bool ret = false;
1376 
1378  ret = m_impl->getClick(ip, button, blocking, m_scale, GDK_BUTTON_PRESS);
1379  } else {
1380  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1381  }
1382  return ret;
1383 }
1384 
1409 {
1410  bool ret = false;
1411 
1413  ret = m_impl->getClick(ip, button, blocking, m_scale, GDK_BUTTON_RELEASE);
1414  } else {
1415  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1416  }
1417  return ret;
1418 }
1419 
1420 /*
1421  \brief gets the displayed image (including the overlay plane)
1422  and returns an RGBa image
1423 */
1425 {
1426  // should certainly be optimized.
1428  m_impl->getImage(I, static_cast<gint>(m_width), static_cast<gint>(m_height));
1429  } else {
1430  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1431  }
1432 }
1433 
1440 {
1441  unsigned int depth = m_impl->getScreenDepth();
1442 
1443  return (depth);
1444 }
1445 
1462 {
1463  bool ret = false;
1464 
1466  std::string key;
1467  ret = m_impl->getKeyboardEvent(key, blocking);
1468  } else {
1469  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1470  }
1471  return ret;
1472 }
1473 
1493 bool vpDisplayGTK::getKeyboardEvent(std::string &key, bool blocking)
1494 {
1495  bool ret = false;
1496 
1498  ret = m_impl->getKeyboardEvent(key, blocking);
1499  } else {
1500  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1501  }
1502  return ret;
1503 }
1504 
1518 {
1519  bool ret = false;
1520 
1522  ret = m_impl->getPointerMotionEvent(ip, m_scale);
1523  } else {
1524  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1525  }
1526  return ret;
1527 }
1528 
1540 {
1542  m_impl->getPointerPosition(ip, m_scale);
1543  } else {
1544  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1545  }
1546 
1547  return true;
1548 }
1549 
1554 void vpDisplayGTK::getScreenSize(unsigned int &w, unsigned int &h)
1555 {
1556  w = h = 0;
1557 
1558  m_impl->getScreenSize(m_displayHasBeenInitialized, w, h);
1559 }
1560 
1565 {
1566  unsigned int width, height;
1567  getScreenSize(width, height);
1568  return width;
1569 }
1570 
1575 {
1576  unsigned int width, height;
1577  getScreenSize(width, height);
1578  return height;
1579 }
1580 
1581 #elif !defined(VISP_BUILD_SHARED_LIBS)
1582 // Work arround to avoid warning: libvisp_core.a(vpDisplayGTK.cpp.o) has no
1583 // symbols
1584 void dummy_vpDisplayGTK(){};
1585 #endif
unsigned int m_height
Definition: vpDisplay.h:216
vpDisplay * display
Definition: vpImage.h:144
void displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)
double get_i() const
Definition: vpImagePoint.h:203
VISP_EXPORT int wait(double t0, double t)
Definition: vpTime.cpp:173
void setWindowPosition(int win_x, int win_y)
int m_windowYPosition
display position
Definition: vpDisplay.h:214
void displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill=false, unsigned int thickness=1)
Class that defines generic functionnalities for display.
Definition: vpDisplay.h:177
bool getClick(bool blocking=true)
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:800
unsigned char B
Blue component.
Definition: vpRGBa.h:150
Type * bitmap
points toward the bitmap
Definition: vpImage.h:143
void set_u(double u)
Definition: vpImagePoint.h:225
void subsample(unsigned int v_scale, unsigned int h_scale, vpImage< Type > &sampled) const
Definition: vpImage.h:1220
Class to define RGB colors available for display functionnalities.
Definition: vpColor.h:157
void flushDisplayROI(const vpImagePoint &iP, unsigned int width, unsigned int height)
bool getClickUp(vpImagePoint &ip, vpMouseButton::vpMouseButtonType &button, bool blocking=true)
void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
unsigned char G
Green component.
Definition: vpRGBa.h:149
bool m_displayHasBeenInitialized
display has been initialized
Definition: vpDisplay.h:210
vpImagePoint getTopLeft() const
Definition: vpRect.h:200
double getRight() const
Definition: vpRect.h:180
void getScreenSize(unsigned int &screen_width, unsigned int &screen_height)
void displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1)
vpColorIdentifier id
Definition: vpColor.h:206
double get_u() const
Definition: vpImagePoint.h:262
int m_windowXPosition
display position
Definition: vpDisplay.h:212
double getWidth() const
Definition: vpRect.h:228
void set_i(double ii)
Definition: vpImagePoint.h:166
unsigned int m_scale
Definition: vpDisplay.h:218
void setScale(vpScaleType scaleType, unsigned int width, unsigned int height)
Definition: vpDisplay.cpp:259
#define vpTRACE
Definition: vpDebug.h:416
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
static double sqr(double x)
Definition: vpMath.h:116
virtual ~vpDisplayGTK()
double get_j() const
Definition: vpImagePoint.h:214
void init(vpImage< unsigned char > &I, int win_x=-1, int win_y=-1, const std::string &win_title="")
bool getPointerPosition(vpImagePoint &ip)
vpScaleType m_scaleType
Definition: vpDisplay.h:219
void displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)
std::string m_title
Definition: vpDisplay.h:217
void displayImage(const vpImage< vpRGBa > &I)
unsigned int getScreenWidth()
bool getPointerMotionEvent(vpImagePoint &ip)
void getImage(vpImage< vpRGBa > &I)
get the window pixmap and put it in vpRGBa image
void displayArrow(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color=vpColor::white, unsigned int w=4, unsigned int h=2, unsigned int thickness=1)
static int round(double x)
Definition: vpMath.h:247
void set_j(double jj)
Definition: vpImagePoint.h:177
void displayCharString(const vpImagePoint &ip, const char *text, const vpColor &color=vpColor::green)
Error that can be emited by the vpDisplay class and its derivates.
void set_v(double v)
Definition: vpImagePoint.h:236
void displayRectangle(const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1)
unsigned int getHeight() const
Definition: vpImage.h:188
void setFont(const std::string &fontname)
unsigned int m_width
Definition: vpDisplay.h:215
static void crop(const vpImage< Type > &I, double roi_top, double roi_left, unsigned int roi_height, unsigned int roi_width, vpImage< Type > &crop, unsigned int v_scale=1, unsigned int h_scale=1)
Definition: vpImageTools.h:305
void setTitle(const std::string &win_title)
unsigned char R
Red component.
Definition: vpRGBa.h:148
unsigned int getScreenDepth()
get the window depth (8,16,24,32)
Defines a rectangle in the plane.
Definition: vpRect.h:79
unsigned int getScreenHeight()
void clearDisplay(const vpColor &color=vpColor::white)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:87
bool getKeyboardEvent(bool blocking=true)
unsigned int getWidth() const
Definition: vpImage.h:246
void displayImageROI(const vpImage< unsigned char > &I, const vpImagePoint &iP, unsigned int width, unsigned int height)
double get_v() const
Definition: vpImagePoint.h:273