Tscope5
mouse.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // __ ______
4 // / /_______________ ____ ___ / ____/
5 // / __/ ___/ ___/ __ \/ __ \/ _ \ /___ )
6 // / /_(__ ) /__/ /_/ / /_/ / __/ ____/ /
7 // \__/____/\___/\____/ .___/\___/ /_____/
8 // /_/
9 //
10 /// \file mouse.c
11 /// Definitions of mouse functions.
12 /// \example mouse01.c
13 /// \example mouse02.c
14 ////////////////////////////////////////////////////////////////////////////////
15 
16 
17 #include "../include/tscope5/mouse.h"
18 #include "../include/tscope5/timer.h"
19 #include "../include/tscope5/graphics.h"
20 #include "../include/tscope5/bitmaps.h"
21 #include "../include/tscope5/display.h"
22 #include "../include/tscope5/primitives.h"
23 #include "../include/tscope5/mouse_internal.h"
24 #include "../include/tscope5/system_internal.h"
25 #include "../include/tscope5/graphics_internal.h"
26 
27 
28 ////////////////////////////////////////////////////////////////////////////////
29 /// @name Response registration
30 /// The mouse can be used as a response device.
31 /// See timer.c for more information about response registration.
32 //@{
33 ////////////////////////////////////////////////////////////////////////////////
34 
35 
36 ////////////////////////////////////////////////////////////////////////////////
37 /// Define a mouse button as a response button.
38 ///
39 /// \param button Number of the button (buttons are counted from 1).
40 ///
41 /// \return The reponse number associated with the button.
42 ///
43 /// Give a positive number if you want to monitor button press events,
44 /// a negative number if you want to monitor button release events.
45 ////////////////////////////////////////////////////////////////////////////////
46 int ts5_define_mouse_button(int button)
47 {
48  ts5_check_mouse("ts5_define_mouse_button");
49  ts5_log(TS5_LOGLEVEL_3, "ts5_define_mouse_button(%d)\n", button);
50 
51  if (button==0) {
52  ts5_fatal("%s: %s\n", "ts5_define_mouse_button",
53  "button argument is 0, response buttons are numbered from 1");
54  }
55 
56  if (abs(button)>_ts5_status.timer.mouse.num_buttons) {
57  ts5_fatal("%s: %s %d, %s is %d\n", "ts5_define_mouse_button",
58  "button argument is", button,
59  "number of mouse buttons",
60  _ts5_status.timer.mouse.num_buttons);
61  }
62 
63  if (button>0 && _ts5_status.timer.mouse
64  .button_press_defined[button-1]!=0) {
65  ts5_fatal("%s: %s %d %s\n", "ts5_define_mouse_button",
66  "button press", button, "is already defined");
67  }
68 
69  if (button<0 && _ts5_status.timer.mouse
70  .button_release_defined[-button-1]!=0) {
71  ts5_fatal("%s: %s %d %s\n", "ts5_define_mouse_button",
72  "button release", button, "is already defined");
73  }
74 
75  _ts5_status.timer.mouse_is_response_device = 1;
76  _ts5_status.timer.num_defined_buttons++;
77  _ts5_status.timer.num_active_buttons++;
78  _ts5_status.timer.mouse.num_defined_buttons++;
79  _ts5_status.timer.mouse.num_active_buttons++;
80 
81  if (button>0) {
82  _ts5_status.timer.mouse.button_press_defined[button-1] =
83  _ts5_status.timer.num_defined_buttons;
84 
85  _ts5_status.timer.mouse.button_press_active[button-1] =
86  _ts5_status.timer.num_defined_buttons;
87  }
88  else {
89  _ts5_status.timer.mouse.button_release_defined[-button-1] =
90  _ts5_status.timer.num_defined_buttons;
91 
92  _ts5_status.timer.mouse.button_release_active[-button-1] =
93  _ts5_status.timer.num_defined_buttons;
94  }
95 
96  return _ts5_status.timer.num_defined_buttons;
97 }
98 
99 
100 ////////////////////////////////////////////////////////////////////////////////
101 /// Get the number of buttons available on the mouse.
102 ///
103 /// \return The number of buttons on the mouse.
104 ////////////////////////////////////////////////////////////////////////////////
106 {
107  ts5_check_mouse("ts5_get_num_mouse_buttons");
108  ts5_log(TS5_LOGLEVEL_4, "ts5_get_num_mouse_buttons()\n");
109 
110  return _ts5_status.timer.mouse.num_buttons;
111 }
112 
113 
114 ////////////////////////////////////////////////////////////////////////////////
115 //@}
116 ////////////////////////////////////////////////////////////////////////////////
117 
118 
119 ////////////////////////////////////////////////////////////////////////////////
120 /// @name Mouse GUI functions
121 //@{
122 ////////////////////////////////////////////////////////////////////////////////
123 
124 
125 ////////////////////////////////////////////////////////////////////////////////
126 /// Make the mouse cursor visible on the active display.
127 ////////////////////////////////////////////////////////////////////////////////
129 {
130  ts5_check_mouse("ts5_show_mouse");
131  ts5_log(TS5_LOGLEVEL_5, "ts5_show_mouse()\n");
132 
133  #ifndef TS5_RASPBERRYPI
134  al_show_mouse_cursor(_ts5_data.display[_ts5_status.active_display]);
135 
136  #endif
137 }
138 
139 
140 ////////////////////////////////////////////////////////////////////////////////
141 /// Make the mouse cursor invisible on the active display.
142 ////////////////////////////////////////////////////////////////////////////////
144 {
145  ts5_check_mouse("ts5_hide_mouse");
146  ts5_log(TS5_LOGLEVEL_5, "ts5_hide_mouse()\n");
147 
148  #ifndef TS5_RASPBERRYPI
149  al_hide_mouse_cursor(_ts5_data.display[_ts5_status.active_display]);
150 
151  #endif
152 }
153 
154 
155 ////////////////////////////////////////////////////////////////////////////////
156 /// Move the mouse pointer to position (x,y).
157 ///
158 /// \param x Horizontal position of the mouse on the active display.
159 /// \param y Vertical position of the mouse on the active display.
160 ////////////////////////////////////////////////////////////////////////////////
161 void ts5_set_mouse_position(double x, double y)
162 {
163  ts5_check_mouse("ts5_set_mouse_position");
164  ts5_log(TS5_LOGLEVEL_5, "ts5_set_mouse_position(%f,%f)\n", x, y);
165 
166  if (_ts5_status.graphics.coordinate_scale
167  == TS5_RELATIVE_COORDINATES) {
170  }
171 
172  if (_ts5_status.graphics.coordinate_system
173  == TS5_CARTESIAN_COORDINATES) {
176  }
177 
178  al_set_mouse_xy(_ts5_data.display[_ts5_status.active_display],
179  (int)x, (int)y);
180 }
181 
182 ////////////////////////////////////////////////////////////////////////////////
183 /// Get the horizontal and vertical position of the mouse pointer
184 ///
185 /// \param x Variable that will store the horizontal position.
186 /// \param y Variable that will store the vertical position.
187 ///
188 /// You can pass NULL for values you are not interested in.
189 ////////////////////////////////////////////////////////////////////////////////
190 void ts5_get_mouse_position(double *x, double *y)
191 {
192  ts5_check_mouse("ts5_get_mouse_position");
193  ts5_log(TS5_LOGLEVEL_6, "ts5_get_mouse_position(%p,%p)\n", x, y);
194 
195  ALLEGRO_MOUSE_STATE status;
196  al_get_mouse_state(&status);
197 
198  double xx, yy;
199 
200  xx = al_get_mouse_state_axis(&status, 0);
201  yy = al_get_mouse_state_axis(&status, 1);
202 
203  #ifdef TS5_RASPBERRYPI
204  #include <allegro5/allegro_primitives.h>
205 
206  // draw mouse
207  al_set_target_backbuffer(_ts5_data.display[_ts5_status.active_display]);
208  al_draw_bitmap(_ts5_data.display_buffer[_ts5_status.active_display], 0.0, 0.0, 0);
209 
210  TS5_COLOR gulf_blue = ts5_make_rgb_color(0x85/255.0, 0xB2/255.0, 0xD3/255.0,1.0);
211 
212  TS5_COLOR oldcolor = ts5_set_foreground_color(gulf_blue);
213 
214  al_draw_line(xx-8.0, yy-8.0, xx+8.0, yy+8.0, _ts5_status.graphics.background_color, 9.0);
215  al_draw_line(xx-8.0, yy+8.0, xx+8.0, yy-8.0, _ts5_status.graphics.background_color, 9.0);
216  al_draw_line(xx-6.0, yy-6.0, xx+6.0, yy+6.0, _ts5_status.graphics.foreground_color, 3.0);
217  al_draw_line(xx-6.0, yy+6.0, xx+6.0, yy-6.0, _ts5_status.graphics.foreground_color, 3.0);
218 
219  ts5_set_foreground_color(oldcolor);
220  al_flip_display();
221 
222  #endif
223 
224  if (_ts5_status.graphics.coordinate_system
225  == TS5_CARTESIAN_COORDINATES) {
228  }
229 
230  if (_ts5_status.graphics.coordinate_scale
231  == TS5_RELATIVE_COORDINATES) {
234  }
235 
236  if (x) {
237  *x = xx;
238  }
239 
240  if (y) {
241  *y = yy;
242  }
243 }
244 
245 
246 ////////////////////////////////////////////////////////////////////////////////
247 /// Get the horizontal position of the mouse pointer
248 ///
249 /// \return The horizontal position of the mouse pointer.
250 ////////////////////////////////////////////////////////////////////////////////
252 {
253  ts5_check_mouse("ts5_get_mouse_x");
254  ts5_log(TS5_LOGLEVEL_6, "ts5_get_mouse_x()\n");
255 
256  double x;
257  ts5_get_mouse_position(&x, NULL);
258 
259  return x;
260 }
261 
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 /// Get the vertical position of the mouse pointer
265 ///
266 /// \return The vertical position of the mouse pointer.
267 ////////////////////////////////////////////////////////////////////////////////
269 {
270  ts5_check_mouse("ts5_get_mouse_y");
271  ts5_log(TS5_LOGLEVEL_6, "ts5_get_mouse_y()\n");
272 
273  double y;
274  ts5_get_mouse_position(NULL, &y);
275 
276  return y;
277 }
278 
279 
280 ////////////////////////////////////////////////////////////////////////////////
281 /// Draw a mouse button and wait for a click.
282 ///
283 /// \param x Horizontal position of the button on the active display.
284 /// \param y Vertical position of the button on the active display.
285 ///
286 /// The button color cannot be changed by the user.
287 /// From version 0.6 onwards it changes with every new release of Tscope5.
288 /// This way (almost) every Tscope5 program will have a built-in visual check
289 /// of the up-to-dateness of your experiment computer.
290 ///
291 /// Here is the list of version/color combinations:
292 /// - Tscope5 0.6: Gulf Orange
293 /// - Tscope5 <= 0.5: Chartreuse
294 ////////////////////////////////////////////////////////////////////////////////
295 void ts5_draw_mouse_button(double x, double y)
296 {
297  ts5_check_mouse("ts5_draw_mouse_button");
298  ts5_log(TS5_LOGLEVEL_5, "ts5_draw_mouse_button(%f,%f)\n", x, y);
299 
300  // always write to the display
301  ts5_set_active_display(_ts5_status.active_display+1);
302 
303  TS5_BITMAP *oldmap = ts5_set_drawing_target(
304  _ts5_data.display_buffer
305  [_ts5_status.active_display]);
306 
307  TS5_COLOR gulf_orange = ts5_make_rgb_color(0xF2/255.0, 0x5C/255.0, 0.0, 1.0);
308  TS5_COLOR gulf_blue = ts5_make_rgb_color(0x85/255.0, 0xB2/255.0, 0xD3/255.0,1.0);
309 
310  TS5_COLOR oldcolor = ts5_set_foreground_color(gulf_blue);
311 
312  double oldthick = ts5_set_drawing_thickness(4.0);
313  int oldfill = ts5_set_fill_mode(TS5_FILL_OFF);
314 
315  double w_abs_disp = 40, h_abs_disp = 40;
316  double x1_abs_disp, x2_abs_disp, y1_abs_disp, y2_abs_disp;
317 
318  // covert to absolute scale
319  if (_ts5_status.graphics.coordinate_scale
320  == TS5_RELATIVE_COORDINATES) {
321  x1_abs_disp = ts5_relative_to_absolute_coordinate_x(x);
322  y1_abs_disp = ts5_relative_to_absolute_coordinate_y(y);
323  }
324  else {
325  x1_abs_disp = x;
326  y1_abs_disp = y;
327  }
328 
329  // convert to display coordinates.
330  if (_ts5_status.graphics.coordinate_system
331  == TS5_CARTESIAN_COORDINATES) {
332  x1_abs_disp = ts5_cartesian_to_display_coordinate_x(x1_abs_disp);
333  y1_abs_disp = ts5_cartesian_to_display_coordinate_y(y1_abs_disp);
334 
335  x1_abs_disp -= w_abs_disp/2;
336  y1_abs_disp -= h_abs_disp/2;
337  }
338 
339  x2_abs_disp = x1_abs_disp + w_abs_disp;
340  y2_abs_disp = y1_abs_disp + h_abs_disp;
341 
342  int oldsystem = ts5_set_coordinate_system(TS5_DISPLAY_COORDINATES);
343  int oldscale = ts5_set_coordinate_scale(TS5_ABSOLUTE_COORDINATES);
344 
345  // check if the button will be on the screen
346  double dispw = _ts5_status.display[_ts5_status.active_display].w;
347  double disph = _ts5_status.display[_ts5_status.active_display].h;
348 
349  if (x1_abs_disp < 0.0 || x2_abs_disp > dispw
350  || y1_abs_disp < 0.0 || y2_abs_disp > disph) {
351  ts5_fatal("%s: %s (%f,%f)\n", "ts5_draw_mouse_button",
352  "button will be off screen", x1_abs_disp, y1_abs_disp);
353  }
354 
355  ts5_draw_rounded_rectangle(x1_abs_disp, y1_abs_disp,
356  x2_abs_disp, y2_abs_disp, 3.0, 3.0);
357 
358  ts5_set_fill_mode(TS5_FILL_ON);
359  ts5_set_foreground_color(gulf_orange);
360  ts5_draw_triangle(x2_abs_disp - 5.0, (y1_abs_disp+y2_abs_disp)/2.0,
361  x1_abs_disp+5.0, y1_abs_disp+5.0, x1_abs_disp+5.0, y2_abs_disp-5.0);
363 
364  // FIXME: this needs to be fixed
365  #ifndef ALLEGRO_RASPBERRYPI
366  ts5_show_mouse();
367 
368  #endif
369  ts5_show_mouse();
370 
371  ALLEGRO_MOUSE_STATE status;
372  int down;
373  int ok = 0;
374  do {
375  double xp, yp;
376  ts5_get_mouse_position(&xp, &yp);
377  al_get_mouse_state(&status);
378  down = al_mouse_button_down(&status, 1);
379  if (down && xp > x1_abs_disp && xp < x2_abs_disp
380  && yp > y1_abs_disp && yp < y2_abs_disp) {
381  ok = 1;
382  }
383  } while (!ok);
384 
386  ts5_draw_triangle(x2_abs_disp - 5, (y1_abs_disp+y2_abs_disp)/2,
387  x1_abs_disp+5, y1_abs_disp+5, x1_abs_disp+5, y2_abs_disp-5);
389 
390  ok = 0;
391  do {
392  al_get_mouse_state(&status);
393  down = al_mouse_button_down(&status, 1);
394  if (!down) {
395  ok = 1;
396  }
397  } while (!ok);
398 
399  ts5_set_foreground_color(gulf_orange);
400  ts5_draw_triangle(x2_abs_disp - 5, (y1_abs_disp+y2_abs_disp)/2,
401  x1_abs_disp+5, y1_abs_disp+5, x1_abs_disp+5, y2_abs_disp-5);
403 
404  ts5_set_drawing_target(oldmap);
405  ts5_set_foreground_color(oldcolor);
406  ts5_set_drawing_thickness(oldthick);
407  ts5_set_fill_mode(oldfill);
408  ts5_set_coordinate_system(oldsystem);
409  ts5_set_coordinate_scale(oldscale);
410 }
411 
412 
413 ////////////////////////////////////////////////////////////////////////////////
414 //@}
415 ////////////////////////////////////////////////////////////////////////////////
416 
double ts5_display_to_cartesian_coordinate_y(const double y)
Convert a vertical display coordinate into a vertical Cartisian coordinate.
Definition: graphics.c:396
void ts5_hide_mouse()
Make the mouse cursor invisible on the active display.
Definition: mouse.c:143
TS5_COLOR ts5_make_named_color(const char *name, const double a)
Return a color that corresponds to name.
Definition: graphics.c:549
double ts5_display_to_cartesian_coordinate_x(const double x)
Convert a horizontal display coordinate into a horizontal Cartisian coordinate.
Definition: graphics.c:375
double ts5_flip_display()
Make what has been drawn visible on the screen.
Definition: display.c:539
int ts5_set_active_display(const int display)
Set the active display.
Definition: display.c:637
int ts5_set_fill_mode(const int fill_mode)
Set the fill mode.
Definition: graphics.c:746
void ts5_show_mouse()
Make the mouse cursor visible on the active display.
Definition: mouse.c:128
TS5_COLOR ts5_set_foreground_color(const TS5_COLOR foreground_color)
Set the foreground color.
Definition: graphics.c:607
void ts5_get_mouse_position(double *x, double *y)
Get the horizontal and vertical position of the mouse pointer.
Definition: mouse.c:190
int ts5_set_coordinate_scale(const int coordinate_scale)
Set the coordinate scale.
Definition: graphics.c:147
void ts5_set_mouse_position(double x, double y)
Move the mouse pointer to position (x,y).
Definition: mouse.c:161
TS5_BITMAP * ts5_set_drawing_target(TS5_BITMAP *target)
Set the active drawing target.
Definition: bitmaps.c:285
void ts5_draw_rounded_rectangle(double x1, double y1, double x2, double y2, double rx, double ry)
Draw a rounded rectangle.
Definition: primitives.c:206
int ts5_get_num_mouse_buttons()
Get the number of buttons available on the mouse.
Definition: mouse.c:105
void ts5_draw_mouse_button(double x, double y)
Draw a mouse button and wait for a click.
Definition: mouse.c:295
double ts5_relative_to_absolute_coordinate_x(const double x)
Convert a relative horizontal coordinate into an absolute horizontal coordinate.
Definition: graphics.c:208
double ts5_set_drawing_thickness(double drawing_thickness)
Set the drawing thickness.
Definition: graphics.c:698
int ts5_define_mouse_button(int button)
Define a mouse button as a response button.
Definition: mouse.c:46
void ts5_log(const unsigned int level, const char *format,...)
Send info to a logging window.
Definition: system.c:45
double ts5_cartesian_to_display_coordinate_x(const double x)
Convert a horizontal Cartesian coordinate into a horizontal display coordinate.
Definition: graphics.c:333
double ts5_cartesian_to_display_coordinate_y(const double y)
Convert a vertical Cartesian coordinate into a vertical display coordinate.
Definition: graphics.c:354
void ts5_check_mouse(char *calling_function)
Do some checks at the start of each mouse function.
void ts5_draw_triangle(double x1, double y1, double x2, double y2, double x3, double y3)
Draw a triangle.
Definition: primitives.c:285
double ts5_absolute_to_relative_coordinate_y(const double y)
Convert an absolute vertical coordinate into a relative vertical coordinate.
Definition: graphics.c:302
TS5_COLOR ts5_make_rgb_color(const double r, const double g, const double b, const double a)
Generate a color specification based on an RGB triplet plus an alpha channel.
Definition: graphics.c:436
double ts5_absolute_to_relative_coordinate_x(const double x)
Convert an absolute horizontal coordinate into a relative horizontal coordinate.
Definition: graphics.c:271
void ts5_fatal(const char *format,...)
Exit safely with an error message.
Definition: system.c:533
double ts5_relative_to_absolute_coordinate_y(const double y)
Convert a relative vertical coordinate into an absolute vertical coordinate.
Definition: graphics.c:240
double ts5_get_mouse_x()
Get the horizontal position of the mouse pointer.
Definition: mouse.c:251
int ts5_set_coordinate_system(const int coordinate_system)
Set the coordinate system.
Definition: graphics.c:81
double ts5_get_mouse_y()
Get the vertical position of the mouse pointer.
Definition: mouse.c:268