Visual Servoing Platform  version 3.4.1 under development (2021-09-19)
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 
749 void vpDisplayGTK::init(vpImage<unsigned char> &I, int win_x, int win_y, const std::string &win_title)
750 {
751  if ((I.getHeight() == 0) || (I.getWidth() == 0)) {
752  throw(vpDisplayException(vpDisplayException::notInitializedError, "Image not initialized"));
753  }
754 
755  if (win_x != -1)
756  m_windowXPosition = win_x;
757  if (win_y != -1)
758  m_windowYPosition = win_y;
759 
760  if (!win_title.empty())
761  m_title = win_title;
762 
765 
766  I.display = this;
768 }
769 
779 void vpDisplayGTK::init(vpImage<vpRGBa> &I, int win_x, int win_y, const std::string &win_title)
780 {
781  if ((I.getHeight() == 0) || (I.getWidth() == 0)) {
782  throw(vpDisplayException(vpDisplayException::notInitializedError, "Image not initialized"));
783  }
784 
785  if (win_x != -1)
786  m_windowXPosition = win_x;
787  if (win_y != -1)
788  m_windowYPosition = win_y;
789 
790  if (!win_title.empty())
791  m_title = win_title;
792 
795 
796  I.display = this;
798 }
799 
808 void vpDisplayGTK::init(unsigned int win_width, unsigned int win_height, int win_x, int win_y, const std::string &win_title)
809 {
810  setScale(m_scaleType, win_width, win_height);
811 
812  m_width = win_width / m_scale;
813  m_height = win_height / m_scale;
814 
815  if (win_x != -1)
816  m_windowXPosition = win_x;
817  if (win_y != -1)
818  m_windowYPosition = win_y;
819 
820  m_title = win_title;
821 
823 
825 }
826 
839 void vpDisplayGTK::setFont(const std::string &fontname)
840 {
841  m_impl->setFont(fontname);
842 }
843 
848 void vpDisplayGTK::setTitle(const std::string &title)
849 {
851  m_title = title;
852  if (!title.empty()) {
853  m_impl->setTitle(title);
854  }
855  } else {
856  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
857  }
858 }
859 
869 void vpDisplayGTK::setWindowPosition(int win_x, int win_y)
870 {
872  m_impl->setWindowPosition(win_x, win_y);
873  } else {
874  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
875  }
876 }
877 
890 {
892  m_impl->displayImage(I, m_scale, static_cast<gint>(m_width), static_cast<gint>(m_height));
893  } else {
894  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
895  }
896 }
897 
915 void vpDisplayGTK::displayImageROI(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int w,
916  unsigned int h)
917 {
920  vpImageTools::crop(I, iP.get_i(), iP.get_j(), h, w, Itemp, m_scale, m_scale);
921 
922  /* Copie de l'image dans le pixmap fond */
923  int i_min = (std::max)(static_cast<int>(ceil(iP.get_i() / m_scale)), 0);
924  int j_min = (std::max)(static_cast<int>(ceil(iP.get_j() / m_scale)), 0);
925 
926  m_impl->displayImageROI(Itemp, static_cast<gint>(j_min), static_cast<gint>(i_min),
927  static_cast<gint>(Itemp.getWidth()), static_cast<gint>(Itemp.getHeight()));
928  } else {
929  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
930  }
931 }
932 
945 {
947  m_impl->displayImage(I, m_scale, static_cast<gint>(m_width), static_cast<gint>(m_height));
948  } else {
949  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
950  }
951 }
952 
970 void vpDisplayGTK::displayImageROI(const vpImage<vpRGBa> &I, const vpImagePoint &iP, unsigned int w,
971  unsigned int h)
972 {
974  vpImage<vpRGBa> Itemp;
975  vpImageTools::crop(I, iP.get_i(), iP.get_j(), h, w, Itemp, m_scale, m_scale);
976 
977  /* Copie de l'image dans le pixmap fond */
978  int i_min = (std::max)(static_cast<int>(ceil(iP.get_i() / m_scale)), 0);
979  int j_min = (std::max)(static_cast<int>(ceil(iP.get_j() / m_scale)), 0);
980 
981  m_impl->displayImageROI(Itemp, static_cast<gint>(j_min), static_cast<gint>(i_min),
982  static_cast<gint>(Itemp.getWidth()), static_cast<gint>(Itemp.getHeight()));
983  } else {
984  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
985  }
986 }
987 
993 void vpDisplayGTK::displayImage(const unsigned char * /* I */) { vpTRACE(" not implemented "); }
994 
1001 {
1002  m_impl->closeDisplay();
1003 
1005 }
1006 
1012 {
1014  m_impl->flushDisplay();
1015  } else {
1016  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1017  }
1018 }
1019 
1024 void vpDisplayGTK::flushDisplayROI(const vpImagePoint & /*iP*/, const unsigned int /*width*/,
1025  const unsigned int /*height*/)
1026 {
1028  m_impl->flushDisplay();
1029  } else {
1030  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1031  }
1032 }
1033 
1037 void vpDisplayGTK::clearDisplay(const vpColor & /* color */) { vpTRACE("Not implemented"); }
1038 
1046 void vpDisplayGTK::displayArrow(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int w,
1047  unsigned int h, unsigned int thickness)
1048 {
1050  double a = ip2.get_i() - ip1.get_i();
1051  double b = ip2.get_j() - ip1.get_j();
1052  double lg = sqrt(vpMath::sqr(a) + vpMath::sqr(b));
1053 
1054  if ((std::fabs(a) > std::numeric_limits<double>::epsilon()) &&
1055  (std::fabs(b) > std::numeric_limits<double>::epsilon())) {
1056  a /= lg;
1057  b /= lg;
1058 
1059  vpImagePoint ip3;
1060  ip3.set_i(ip2.get_i() - w * a);
1061  ip3.set_j(ip2.get_j() - w * b);
1062 
1063  vpImagePoint ip4;
1064  ip4.set_i(ip3.get_i() - b * h);
1065  ip4.set_j(ip3.get_j() + a * h);
1066 
1067  if (lg > 2 * vpImagePoint::distance(ip2, ip4))
1068  displayLine(ip2, ip4, color, thickness);
1069 
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  displayLine(ip1, ip2, color, thickness);
1077  }
1078  } else {
1079  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1080  }
1081 }
1082 
1094 void vpDisplayGTK::displayCharString(const vpImagePoint &ip, const char *text, const vpColor &color)
1095 {
1097  m_impl->displayCharString(ip, text, color, m_scale);
1098  } else {
1099  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1100  }
1101 }
1111 void vpDisplayGTK::displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill,
1112  unsigned int thickness)
1113 {
1115  if (thickness == 1)
1116  thickness = 0;
1117 
1118  m_impl->displayCircle(center, radius, color, fill, thickness, m_scale);
1119  } else {
1120  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1121  }
1122 }
1130 void vpDisplayGTK::displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness)
1131 {
1133  double i = ip.get_i();
1134  double j = ip.get_j();
1135  vpImagePoint ip1, ip2;
1136 
1137  ip1.set_i(i - size / 2);
1138  ip1.set_j(j);
1139  ip2.set_i(i + size / 2);
1140  ip2.set_j(j);
1141  displayLine(ip1, ip2, color, thickness);
1142 
1143  ip1.set_i(i);
1144  ip1.set_j(j - size / 2);
1145  ip2.set_i(i);
1146  ip2.set_j(j + size / 2);
1147 
1148  displayLine(ip1, ip2, color, thickness);
1149  }
1150 
1151  else {
1152  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1153  }
1154 }
1161 void vpDisplayGTK::displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
1162  unsigned int thickness)
1163 {
1164 
1166  if (thickness == 1)
1167  thickness = 0;
1168 
1169  m_impl->displayDotLine(ip1, ip2, color, thickness, m_scale);
1170  } else {
1171  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1172  }
1173 }
1174 
1181 void vpDisplayGTK::displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
1182  unsigned int thickness)
1183 {
1185  if (thickness == 1)
1186  thickness = 0;
1187 
1188  m_impl->displayLine(ip1, ip2, color, thickness, m_scale);
1189  } else {
1190  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1191  }
1192 }
1193 
1200 void vpDisplayGTK::displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness)
1201 {
1203  m_impl->displayPoint(ip, color, thickness, m_scale);
1204  } else {
1205  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1206  }
1207 }
1208 
1222 void vpDisplayGTK::displayRectangle(const vpImagePoint &topLeft, unsigned int w, unsigned int h, const vpColor &color,
1223  bool fill, unsigned int thickness)
1224 {
1226  if (thickness == 1)
1227  thickness = 0;
1228 
1229  m_impl->displayRectangle(topLeft, w, h, color, fill, thickness, m_scale);
1230  } else {
1231  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1232  }
1233 }
1234 
1247 void vpDisplayGTK::displayRectangle(const vpImagePoint &topLeft, const vpImagePoint &bottomRight, const vpColor &color,
1248  bool fill, unsigned int thickness)
1249 {
1251  if (thickness == 1)
1252  thickness = 0;
1253 
1254  unsigned int w = static_cast<unsigned int>(vpMath::round(bottomRight.get_u() - topLeft.get_u()));
1255  unsigned int h = static_cast<unsigned int>(vpMath::round(bottomRight.get_v() - topLeft.get_v()));
1256 
1257  m_impl->displayRectangle(topLeft, w, h, color, fill, thickness, m_scale);
1258  } else {
1259  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1260  }
1261 }
1262 
1275 void vpDisplayGTK::displayRectangle(const vpRect &rectangle, const vpColor &color, bool fill, unsigned int thickness)
1276 {
1278  if (thickness == 1)
1279  thickness = 0;
1280 
1281  vpImagePoint topLeft = rectangle.getTopLeft();
1282  unsigned int w = static_cast<unsigned int>(vpMath::round(rectangle.getWidth()));
1283  unsigned int h = static_cast<unsigned int>(vpMath::round(rectangle.getRight()));
1284  m_impl->displayRectangle(topLeft, w, h, color, fill, thickness, m_scale);
1285  } else {
1286  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1287  }
1288 }
1289 
1305 bool vpDisplayGTK::getClick(bool blocking)
1306 {
1307  bool ret = false;
1308 
1310  vpImagePoint ip;
1312  ret = m_impl->getClick(ip, button, blocking, m_scale, GDK_BUTTON_PRESS);
1313  } else {
1314  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1315  }
1316  return ret;
1317 }
1318 
1335 bool vpDisplayGTK::getClick(vpImagePoint &ip, bool blocking)
1336 {
1337  bool ret = false;
1338 
1341  ret = m_impl->getClick(ip, button, blocking, m_scale, GDK_BUTTON_PRESS);
1342  } else {
1343  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1344  }
1345  return ret;
1346 }
1347 
1368 {
1369  bool ret = false;
1370 
1372  ret = m_impl->getClick(ip, button, blocking, m_scale, GDK_BUTTON_PRESS);
1373  } else {
1374  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1375  }
1376  return ret;
1377 }
1378 
1403 {
1404  bool ret = false;
1405 
1407  ret = m_impl->getClick(ip, button, blocking, m_scale, GDK_BUTTON_RELEASE);
1408  } else {
1409  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1410  }
1411  return ret;
1412 }
1413 
1414 /*
1415  \brief gets the displayed image (including the overlay plane)
1416  and returns an RGBa image
1417 */
1419 {
1420  // should certainly be optimized.
1422  m_impl->getImage(I, static_cast<gint>(m_width), static_cast<gint>(m_height));
1423  } else {
1424  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1425  }
1426 }
1427 
1434 {
1435  unsigned int depth = m_impl->getScreenDepth();
1436 
1437  return (depth);
1438 }
1439 
1456 {
1457  bool ret = false;
1458 
1460  std::string key;
1461  ret = m_impl->getKeyboardEvent(key, blocking);
1462  } else {
1463  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1464  }
1465  return ret;
1466 }
1467 
1487 bool vpDisplayGTK::getKeyboardEvent(std::string &key, bool blocking)
1488 {
1489  bool ret = false;
1490 
1492  ret = m_impl->getKeyboardEvent(key, blocking);
1493  } else {
1494  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1495  }
1496  return ret;
1497 }
1498 
1512 {
1513  bool ret = false;
1514 
1516  ret = m_impl->getPointerMotionEvent(ip, m_scale);
1517  } else {
1518  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1519  }
1520  return ret;
1521 }
1522 
1534 {
1536  m_impl->getPointerPosition(ip, m_scale);
1537  } else {
1538  throw(vpDisplayException(vpDisplayException::notInitializedError, "GTK not initialized"));
1539  }
1540 
1541  return true;
1542 }
1543 
1548 void vpDisplayGTK::getScreenSize(unsigned int &w, unsigned int &h)
1549 {
1550  w = h = 0;
1551 
1552  m_impl->getScreenSize(m_displayHasBeenInitialized, w, h);
1553 }
1554 
1559 {
1560  unsigned int width, height;
1561  getScreenSize(width, height);
1562  return width;
1563 }
1564 
1569 {
1570  unsigned int width, height;
1571  getScreenSize(width, height);
1572  return height;
1573 }
1574 
1575 #elif !defined(VISP_BUILD_SHARED_LIBS)
1576 // Work arround to avoid warning: libvisp_core.a(vpDisplayGTK.cpp.o) has no
1577 // symbols
1578 void dummy_vpDisplayGTK(){};
1579 #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:245
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