ARB
AWT_canvas.cxx
Go to the documentation of this file.
1 // ================================================================ //
2 // //
3 // File : AWT_canvas.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // ================================================================ //
10 
11 #include "awt_canvas.hxx"
12 #include "awt.hxx"
13 
14 #include <aw_root.hxx>
15 #include <aw_msg.hxx>
16 #include <aw_preset.hxx>
17 
18 #include <arbdbt.h>
19 
20 #include <algorithm>
21 
22 #if defined(DEVEL_RALF)
23 // # define TRACE_MODEL_VIEW_UPDATES
24 #endif
25 
26 #if defined(TRACE_MODEL_VIEW_UPDATES)
27 inline void TRACE_UPDATE(const char *action) {
28  char atime[256];
29  time_t t = time(0);
30  tm *tms = localtime(&t);
31 
32  strftime(atime, 255, "%k:%M:%S", tms);
33  fprintf(stderr, "[MVU] %s: %s\n", atime, action);
34 }
35 #else // !TRACE_MODEL_VIEW_UPDATES
36 inline void TRACE_UPDATE(const char *) {}
37 #endif
38 
39 using namespace std;
40 using namespace AW;
41 
43  modifying = 0;
44 
45  refresh = 0;
46  resize = 0;
47  zoom_reset = 0;
48  supdate = 0;
49  save = 0;
50 
51  padding.clear();
52 
53  zoom_mode = AWT_ZOOM_BOTH;
54  fit_mode = AWT_FIT_LARGER;
55 
56  dont_scroll = 0;
57 }
58 
61 
63  int maxpos = int(worldsize.r-rect.r)-1;
64  if (pos>maxpos) pos = maxpos;
65  if (pos<0) pos = 0;
66  aww->set_horizontal_scrollbar_position(pos);
67 }
68 
70  int maxpos = int(worldsize.b-rect.b)-1;
71  if (pos>maxpos) pos = maxpos;
72  if (pos<0) pos = 0;
73  aww->set_vertical_scrollbar_position(pos);
74 }
75 
77  AW_pos width = this->worldinfo.r - this->worldinfo.l;
78  AW_pos height = this->worldinfo.b - this->worldinfo.t;
79 
80  worldsize.l = 0;
81  worldsize.t = 0;
82 
83  AW::Vector zv = gfx->exports.zoomVector(trans_to_fit);
84 
85  worldsize.r = width *zv.x() + gfx->exports.get_x_padding();
86  worldsize.b = height*zv.y() + gfx->exports.get_y_padding();
87 
88  aww->tell_scrolled_picture_size(worldsize);
89 
90  aww->calculate_scrollbars();
91 
92  this->old_hor_scroll_pos = (int)((-this->worldinfo.l -
93  this->shift_x_to_fit)*
94  this->trans_to_fit +
95  gfx->exports.get_left_padding());
96  this->set_horizontal_scrollbar_position(this->aww, old_hor_scroll_pos);
97 
98  this->old_vert_scroll_pos = (int)((-this->worldinfo.t -
99  this->shift_y_to_fit)*
100  this->trans_to_fit+
101  gfx->exports.get_top_padding());
102 
103  this->set_vertical_scrollbar_position(this->aww, old_vert_scroll_pos);
104 }
105 
107  device->reset();
108  device->shift(AW::Vector(shift_x_to_fit, shift_y_to_fit));
109  device->zoom(this->trans_to_fit);
110 }
111 
112 void AWT_canvas::instant_resize(bool adjust_scrollbars) {
113  TRACE_UPDATE("resize");
114 
116 
117  AW_pos old_width = worldinfo.r - worldinfo.l;
118  AW_pos old_height = worldinfo.b - worldinfo.t;
119 
120  GB_transaction ta(this->gb_main);
121  AW_device_size *size_device = aww->get_size_device(AW_MIDDLE_AREA);
122 
123  size_device->set_filter(AW_SIZE|(consider_text_for_size ? AW_SIZE_UNSCALED : 0));
124  size_device->reset();
125 
126  gfx->show(size_device);
127 
128  if (consider_text_for_size) {
129  gfx->exports.set_extra_text_padding(size_device->get_unscaleable_overlap());
130  }
131 
132  size_device->get_size_information(&(this->worldinfo));
133  rect = size_device->get_area_size(); // real world size (no offset)
134 
135  if (adjust_scrollbars) {
136  if (old_width>0) {
137  if (shift_x_to_fit<0) {
138  AW_pos new_width = worldinfo.r - worldinfo.l;
139  shift_x_to_fit *= new_width/old_width;
140  }
141  }
142  if (old_height>0) {
143  if (shift_y_to_fit<0) {
144  AW_pos new_height = worldinfo.b - worldinfo.t;
145  shift_y_to_fit *= new_height/old_height;
146  }
147  }
148 
149  set_scrollbars();
150  }
151 
152  gfx->exports.clear_resize_request();
153  gfx->exports.request_refresh();
154 }
155 
157  instant_resize(false);
158 
159  TRACE_UPDATE("zoom_reset");
160  AW_pos width = this->worldinfo.r - this->worldinfo.l;
161  AW_pos height = this->worldinfo.b - this->worldinfo.t;
162 
163  AW_pos net_window_width = rect.r - rect.l - gfx->exports.get_x_padding();
164  AW_pos net_window_height = rect.b - rect.t - gfx->exports.get_y_padding();
165 
166  if (net_window_width<AWT_MIN_WIDTH) net_window_width = AWT_MIN_WIDTH;
167  if (net_window_height<AWT_MIN_WIDTH) net_window_height = AWT_MIN_WIDTH;
168 
169  if (width <EPS) width = EPS;
170  if (height <EPS) height = EPS;
171 
172  AW_pos x_scale = net_window_width/width;
173  AW_pos y_scale = net_window_height/height;
174 
175  trans_to_fit = -1;
176  switch (gfx->exports.fit_mode) {
177  case AWT_FIT_NEVER: trans_to_fit = 1.0; break;
178  case AWT_FIT_X: trans_to_fit = x_scale; break;
179  case AWT_FIT_Y: trans_to_fit = y_scale; break;
180  case AWT_FIT_LARGER: trans_to_fit = std::min(x_scale, y_scale); break;
181  case AWT_FIT_SMALLER: trans_to_fit = std::max(x_scale, y_scale); break;
182  }
183  aw_assert(trans_to_fit > 0);
184 
185  AW_pos center_shift_x = 0;
186  AW_pos center_shift_y = 0;
187 
188  if (gfx->exports.zoom_mode&AWT_ZOOM_X) center_shift_x = (net_window_width /trans_to_fit - width)/2;
189  if (gfx->exports.zoom_mode&AWT_ZOOM_Y) center_shift_y = (net_window_height/trans_to_fit - height)/2;
190 
191  // complete, upper left corner
192  this->shift_x_to_fit = - this->worldinfo.l + gfx->exports.get_left_padding()/trans_to_fit + center_shift_x;
193  this->shift_y_to_fit = - this->worldinfo.t + gfx->exports.get_top_padding()/trans_to_fit + center_shift_y;
194 
195  this->old_hor_scroll_pos = 0;
196  this->old_vert_scroll_pos = 0;
197 
198  // scale
199 
200  this->set_scrollbars();
201 
202  gfx->exports.clear_zoom_reset_request();
203 }
204 
205 void AWT_canvas::zoom(AW_device *device, bool zoomIn, const Rectangle& wanted_part, const Rectangle& current_part, int percent) {
206  // zooms the device.
207  //
208  // zoomIn == true -> wanted_part is zoomed to current_part
209  // zoomIn == false -> current_part is zoomed to wanted_part
210  //
211  // If wanted_part is very small -> assume mistake (act like single click)
212  // Single click zooms by 'percent' % centering on click position
213 
214  init_device(device);
215 
216  if (!gfx) {
217  awt_assert(0); // we have no display - does this occur?
218  // if yes, pls inform devel@arb-home.de about circumstances
219  return;
220  }
221 
222  AW_pos width = worldinfo.r-worldinfo.l;
223  AW_pos height = worldinfo.b-worldinfo.t;
224 
225  if (width<EPS) width = EPS;
226  if (height<EPS) height = EPS;
227 
228  AWT_zoom_mode zoom_mode = gfx->exports.zoom_mode;
229  if (zoom_mode == AWT_ZOOM_NEVER) {
230  aw_message("Zoom does not work in this mode");
231  return;
232  }
233 
234  Rectangle current(device->rtransform(current_part));
235  Rectangle wanted;
236 
237  bool isClick = false;
238  switch (zoom_mode) {
239  case AWT_ZOOM_BOTH: isClick = wanted_part.line_vector().length()<40.0; break;
240  case AWT_ZOOM_X: isClick = wanted_part.width()<30.0; break;
241  case AWT_ZOOM_Y: isClick = wanted_part.height()<30.0; break;
242 
243  case AWT_ZOOM_NEVER: awt_assert(0); break;
244  }
245 
246  if (isClick) { // very small part or single click
247  // -> zoom by 'percent' % on click position
248  Position clickPos = device->rtransform(wanted_part.centroid());
249 
250  Vector click2UpperLeft = current.upper_left_corner()-clickPos;
251  Vector click2LowerRight = current.lower_right_corner()-clickPos;
252 
253  double scale = (100-percent)/100.0;
254 
255  wanted = Rectangle(clickPos+scale*click2UpperLeft, clickPos+scale*click2LowerRight);
256  }
257  else {
258  wanted = Rectangle(device->rtransform(wanted_part));
259  }
260 
261  if (!zoomIn) {
262  // calculate big rectangle (outside of viewport), which is zoomed into viewport
263 
264  if (zoom_mode == AWT_ZOOM_BOTH) {
265  double factor = current.diagonal().length()/wanted.diagonal().length();
266  Vector curr2wanted(current.upper_left_corner(), wanted.upper_left_corner());
267  Rectangle big(current.upper_left_corner()+(curr2wanted*-factor), current.diagonal()*factor);
268 
269  wanted = big;
270  }
271  else {
272  double factor;
273  if (zoom_mode == AWT_ZOOM_X) {
274  factor = current.width()/wanted.width();
275  }
276  else {
277  awt_assert(zoom_mode == AWT_ZOOM_Y);
278  factor = current.height()/wanted.height();
279  }
280  Vector curr2wanted_start(current.upper_left_corner(), wanted.upper_left_corner());
281  Vector curr2wanted_end(current.lower_right_corner(), wanted.lower_right_corner());
282  Rectangle big(current.upper_left_corner()+(curr2wanted_start*-factor),
283  current.lower_right_corner()+(curr2wanted_end*-factor));
284 
285  wanted = big;
286  }
287  }
288 
289  // scroll
290  shift_x_to_fit = (zoom_mode&AWT_ZOOM_X) ? -wanted.start().xpos() : (shift_x_to_fit+worldinfo.l)*trans_to_fit;
291  shift_y_to_fit = (zoom_mode&AWT_ZOOM_Y) ? -wanted.start().ypos() : (shift_y_to_fit+worldinfo.t)*trans_to_fit;
292 
293  // scale
294  if ((rect.r-rect.l)<EPS) rect.r = rect.l+1;
295  if ((rect.b-rect.t)<EPS) rect.b = rect.t+1;
296 
297  AW_pos max_trans_to_fit = 0;
298 
299  switch (zoom_mode) {
300  case AWT_ZOOM_BOTH:
301  trans_to_fit = max((rect.r-rect.l)/wanted.width(), (rect.b-rect.t)/wanted.height());
302  max_trans_to_fit = 32000.0/max(width, height);
303  break;
304 
305  case AWT_ZOOM_X:
306  trans_to_fit = (rect.r-rect.l)/wanted.width();
307  max_trans_to_fit = 32000.0/width;
308  break;
309 
310  case AWT_ZOOM_Y:
311  trans_to_fit = (rect.b-rect.t)/wanted.height();
312  max_trans_to_fit = 32000.0/height;
313  break;
314 
315  case AWT_ZOOM_NEVER: awt_assert(0); break;
316  }
317  trans_to_fit = std::min(trans_to_fit, max_trans_to_fit);
318 
319  // correct scrolling for "dont_fit"-direction
320  if (zoom_mode == AWT_ZOOM_Y) shift_x_to_fit = (shift_x_to_fit/trans_to_fit)-worldinfo.l;
321  if (zoom_mode == AWT_ZOOM_X) shift_y_to_fit = (shift_y_to_fit/trans_to_fit)-worldinfo.t;
322 
323  set_scrollbars();
324 }
325 
326 inline void nt_draw_zoom_box(AW_device *device, int gc, AW_pos x1, AW_pos y1, AW_pos x2, AW_pos y2) {
327  device->box(gc, AW::FillStyle::EMPTY, x1, y1, x2-x1, y2-y1);
328 }
329 inline void nt_draw_zoom_box(AW_device *device, AWT_canvas *scr) {
330  nt_draw_zoom_box(device,
331  scr->gfx->get_drag_gc(),
332  scr->zoom_drag_sx, scr->zoom_drag_sy,
333  scr->zoom_drag_ex, scr->zoom_drag_ey);
334 }
335 
336 static void clip_expose(AW_window *aww, AWT_canvas *scr,
337  int left_border, int right_border,
338  int top_border, int bottom_border,
339  int hor_overlap, int ver_overlap)
340 {
341  AW_device *device = aww->get_device(AW_MIDDLE_AREA);
342  device->set_filter(AW_SCREEN);
343  device->reset();
344 
345  device->set_top_clip_border(top_border);
346  device->set_bottom_clip_border(bottom_border);
347  device->set_left_clip_border(left_border);
348  device->set_right_clip_border(right_border);
349 
350  device->clear_part(left_border, top_border, right_border-left_border,
351  bottom_border-top_border, -1);
352 
353  GB_transaction ta(scr->gb_main);
354 
355  scr->init_device(device);
356 
357  if (hor_overlap> 0.0) {
358  device->set_right_clip_border(right_border + hor_overlap);
359  }
360  if (hor_overlap< 0.0) {
361  device->set_left_clip_border(left_border + hor_overlap);
362  }
363  if (ver_overlap> 0.0) {
364  device->set_bottom_clip_border(bottom_border + ver_overlap);
365  }
366  if (ver_overlap< 0.0) {
367  device->set_top_clip_border(top_border + ver_overlap);
368  }
369  scr->gfx->show(device);
370  scr->announce_screen_update();
371 }
372 
374  TRACE_UPDATE("refresh");
376 
377  AW_device *device = this->aww->get_device (AW_MIDDLE_AREA);
378  device->clear(-1);
379  clip_expose(this->aww, this, this->rect.l, this->rect.r,
380  this->rect.t, this->rect.b, 0, 0);
381 
382  gfx->exports.clear_refresh_request();
383 }
384 
386  AWT_auto_refresh allowed_on(scr);
387  scr->request_refresh();
388 }
389 static void canvas_resize_cb(UNFIXED, AWT_canvas *scr) {
390  AWT_auto_refresh allowed_on(scr);
391  scr->request_zoom_reset();
392 }
393 
394 void AWT_GC_changed_cb(GcChange whatChanged, AWT_canvas *scr) {
395  // standard callback which may be passed to AW_manage_GC
396  AWT_auto_refresh allowed_on(scr);
397 
398  switch (whatChanged) {
399  case GC_COLOR_CHANGED:
401  scr->request_refresh();
402  break;
403  case GC_FONT_CHANGED:
404  scr->request_resize();
405  break;
406  }
407 }
408 
409 static void canvas_focus_cb(AW_window *, AWT_canvas *scr) {
410  if (scr->gb_main) {
411  scr->push_transaction();
412 
413  { AWT_auto_refresh check_db_update(scr); }
414 
415  scr->pop_transaction();
416  }
417 }
418 
419 const int ZOOM_SPEED_CLICK = 10;
420 const int ZOOM_SPEED_WHEEL = 4;
421 
422 static bool handleZoomEvent(AWT_canvas *scr, AW_device *device, const AW_event& event, int percent) {
423  bool handled = false;
424  bool zoomIn = true;
425 
426  if (event.button == AW_BUTTON_LEFT) { handled = true; }
427  else if (event.button == AW_BUTTON_RIGHT) { handled = true; zoomIn = false; }
428 
429  if (handled) {
430  if (event.type == AW_Mouse_Press) {
431  scr->drag = 1;
432  scr->zoom_drag_sx = scr->zoom_drag_ex = event.x;
433  scr->zoom_drag_sy = scr->zoom_drag_ey = event.y;
434  }
435  else {
436  // delete last box
437  nt_draw_zoom_box(device, scr);
438  scr->drag = 0;
439 
440  Rectangle screen(scr->rect, INCLUSIVE_OUTLINE);
441  Rectangle drag(scr->zoom_drag_sx, scr->zoom_drag_sy, scr->zoom_drag_ex, scr->zoom_drag_ey);
442 
443  scr->zoom(device, zoomIn, drag, screen, percent);
444  scr->request_refresh();
445  }
446  }
447  else if (event.keycode == AW_KEY_ASCII && event.character == '0') { // reset zoom (as promised by MODE_TEXT_STANDARD_ZOOMMODE)
448  scr->request_zoom_reset();
449  handled = true;
450  }
451  return handled;
452 }
453 
454 bool AWT_canvas::handleWheelEvent(AW_device *device, const AW_event& event) {
455  if (event.button != AW_WHEEL_UP && event.button != AW_WHEEL_DOWN) {
456  return false; // not handled
457  }
458  if (event.type == AW_Mouse_Press) {
459  AWT_auto_refresh allowed_on(this);
460 
461  if (event.keymodifier & AW_KEYMODE_CONTROL) {
462  AW_event faked = event;
463 
464  faked.button = (event.button == AW_WHEEL_UP) ? AW_BUTTON_LEFT : AW_BUTTON_RIGHT;
465  handleZoomEvent(this, device, faked, ZOOM_SPEED_WHEEL);
466  faked.type = AW_Mouse_Release;
467  handleZoomEvent(this, device, faked, ZOOM_SPEED_WHEEL);
468  }
469  else {
470  bool horizontal = event.keymodifier & AW_KEYMODE_ALT;
471 
472  int viewport_size = horizontal ? (rect.r-rect.l+1) : (rect.b-rect.t+1);
473  int gfx_size = horizontal ? (worldsize.r-worldsize.l) : (worldsize.b-worldsize.t);
474 
475  // scroll 10% of screen or 10% of graphic size (whichever is smaller):
476  int dist = std::min(viewport_size / 20, gfx_size / 30);
477  int direction = event.button == AW_WHEEL_UP ? -dist : dist;
478 
479  int dx = horizontal ? direction : 0;
480  int dy = horizontal ? 0 : direction;
481 
482  scroll(dx, dy);
483  }
484  }
485  return true;
486 }
487 
488 void AWT_graphic::update_DB_and_model_as_requested(GBDATA *gb_main) {
489  // updates DB from model and recalculates structure
490  // (does only what is requested via exports-flags)
491 
492  if (exports.needs_save()) {
493  TRACE_UPDATE("save_to_DB");
494  GB_ERROR error = save_to_DB(gb_main, NULp);
495  if (error) {
496  aw_message(error);
497  load_from_DB(gb_main, NULp);
498  }
499  exports.clear_save_request(); // move into save and load?
500 
501  exports.request_structure_update(); // @@@ shall be done by load/save
502  awt_assert(!exports.needs_save());
503  }
504  if (exports.needs_structure_update()) {
505  TRACE_UPDATE("update_structure");
506  update_structure();
507  exports.clear_structure_update_request(); // @@@ move into update_structure?
508 
509  exports.request_resize(); // @@@ shall be done by update_structure itself!
510  awt_assert(!exports.needs_structure_update());
511  }
512  if (gb_main) notify_synchronized(gb_main);
513 }
514 
515 void AWT_canvas::sync_DB_model_and_view(bool perform_refresh) {
516  // synchronizes DB from model, updates the model and the view
517  // (does only what is requested via exports-flags)
518  //
519  // if 'perform_refresh' is true -> updates display
520  // otherwise refresh is skipped
521 
522  push_transaction(); // w/o sync may perform an invalid recursion (e.g. if AWAR_TREE_REFRESH gets triggered by save)
523  {
524  LocallyModify<int> allow_flag_modify(gfx->exports.get_modifying_flag_ref(), -1); // allow flag updates
525 
526  gfx->update_DB_and_model_as_requested(gb_main);
527 
528  // @@@ display shall not be updated unconditionally, as done atm
529  // (instead force after some commands, delay until idle callback for other commands)
530  gfx->exports.update_display_as_requested(this, perform_refresh);
531  }
532  pop_transaction();
533 }
534 
535 static void input_event(AW_window *aww, AWT_canvas *scr) {
536  awt_assert(aww = scr->aww);
537 
538  AW_event event;
539  aww->get_event(&event);
540 
541  AW_device *device = aww->get_device(AW_MIDDLE_AREA);
542  device->set_filter(AW_SCREEN);
543  device->reset();
544 
545  scr->push_transaction();
546  {
547  AWT_auto_refresh allowed_on(scr);
548 
549  bool event_handled = false;
550 
551  if (event.button == AW_BUTTON_MIDDLE) {
552  event_handled = true; // only set zoom_drag_e.. below
553  }
554  else if (scr->mode == AWT_MODE_ZOOM) { // zoom mode is identical for all applications, so handle it here
555  event_handled = handleZoomEvent(scr, device, event, ZOOM_SPEED_CLICK);
556  }
557 
558  if (!event_handled) {
559  event_handled = scr->handleWheelEvent(device, event);
560  }
561 
562  if (!event_handled) {
563  AW_device_click *click_device = aww->get_click_device(AW_MIDDLE_AREA, event.x, event.y, AWT_CATCH);
564  click_device->set_filter(AW_CLICK);
565  device->set_filter(AW_SCREEN);
566 
567  scr->init_device(click_device);
568  scr->init_device(device);
569 
570  scr->gfx->show(click_device);
571  if (event.type == AW_Mouse_Press) {
572  scr->gfx->drag_target_detection(false);
573  // drag_target_detection is off by default.
574  // it should be activated in handle_command (by all modes that need it)
575  }
576 
577  AWT_graphic_event gevent(scr->mode, event, false, click_device);
578  scr->gfx->handle_command(device, gevent);
579  }
580  }
581 
582  scr->zoom_drag_ex = event.x;
583  scr->zoom_drag_ey = event.y;
584 
585  scr->pop_transaction();
586 }
587 
588 
589 void AWT_canvas::set_dragEndpoint(int dragx, int dragy) {
590  switch (gfx->exports.zoom_mode) {
591  case AWT_ZOOM_NEVER: {
592  awt_assert(0);
593  break;
594  }
595  case AWT_ZOOM_X: {
596  zoom_drag_sy = rect.t;
597  zoom_drag_ey = rect.b-1;
598  zoom_drag_ex = dragx;
599  break;
600  }
601  case AWT_ZOOM_Y: {
602  zoom_drag_sx = rect.l;
603  zoom_drag_ex = rect.r-1;
604  zoom_drag_ey = dragy;
605  break;
606  }
607  case AWT_ZOOM_BOTH: {
608  zoom_drag_ex = dragx;
609  zoom_drag_ey = dragy;
610 
611  int drag_sx = zoom_drag_ex-zoom_drag_sx;
612  int drag_sy = zoom_drag_ey-zoom_drag_sy;
613 
614  bool correct_x = false;
615  bool correct_y = false;
616  double factor;
617 
618  int scr_sx = rect.r-rect.l;
619  int scr_sy = rect.b-rect.t;
620 
621  if (drag_sx == 0) {
622  if (drag_sy != 0) { factor = double(drag_sy)/scr_sy; correct_x = true; }
623  }
624  else {
625  if (drag_sy == 0) { factor = double(drag_sx)/scr_sx; correct_y = true; }
626  else {
627  double facx = double(drag_sx)/scr_sx;
628  double facy = double(drag_sy)/scr_sy;
629 
630  if (fabs(facx)>fabs(facy)) { factor = facx; correct_y = true; }
631  else { factor = facy; correct_x = true; }
632  }
633  }
634 
635  if (correct_x) {
636  int width = int(scr_sx*factor) * ((drag_sx*drag_sy) < 0 ? -1 : 1);
637  zoom_drag_ex = zoom_drag_sx+width;
638  }
639  else if (correct_y) {
640  int height = int(scr_sy*factor) * ((drag_sx*drag_sy) < 0 ? -1 : 1);
641  zoom_drag_ey = zoom_drag_sy+height;
642  }
643  break;
644  }
645  }
646 }
647 
648 static void motion_event(AW_window *aww, AWT_canvas *scr) {
649  AW_device *device = aww->get_device(AW_MIDDLE_AREA);
650  device->reset();
651  device->set_filter(AW_SCREEN);
652 
653  scr->push_transaction();
654 
655  AW_event event;
656  aww->get_event(&event);
657 
658  {
659  AWT_auto_refresh allowed_on(scr);
660 
661  if (event.button == AW_BUTTON_MIDDLE) {
662  // shift display in ALL modes
663  int dx = event.x - scr->zoom_drag_ex;
664  int dy = event.y - scr->zoom_drag_ey;
665 
666  scr->zoom_drag_ex = event.x;
667  scr->zoom_drag_ey = event.y;
668 
669  // display
670  scr->scroll(-dx*3, -dy*3);
671  }
672  else {
673  if (event.button == AW_BUTTON_LEFT || event.button == AW_BUTTON_RIGHT) {
674  if (scr->mode == AWT_MODE_ZOOM) {
675  if (scr->gfx->exports.zoom_mode != AWT_ZOOM_NEVER) {
676  nt_draw_zoom_box(device, scr);
677  scr->set_dragEndpoint(event.x, event.y);
678  nt_draw_zoom_box(device, scr);
679  }
680  }
681  else {
682  AW_device_click *click_device = NULp;
683 
684  if (scr->gfx->wants_drag_target()) {
685  // drag/drop-target is only updated if requested via AWT_graphic::drag_target_detection
686  click_device = aww->get_click_device(AW_MIDDLE_AREA, event.x, event.y, AWT_CATCH);
687  click_device->set_filter(AW_CLICK_DROP);
688 
689  scr->init_device(click_device);
690  scr->gfx->show(click_device);
691  }
692 
693  scr->init_device(device);
694  AWT_graphic_event gevent(scr->mode, event, true, click_device);
695  scr->gfx->handle_command(device, gevent);
696  }
697  }
698  }
699  }
700  scr->pop_transaction();
701 }
702 
703 void AWT_canvas::scroll(int dx, int dy, bool dont_update_scrollbars) {
704  int csx, cdx, cwidth, csy, cdy, cheight;
705  AW_device *device;
706  if (!dont_update_scrollbars) {
707  this->old_hor_scroll_pos += dx;
708  this->set_horizontal_scrollbar_position(aww, this->old_hor_scroll_pos);
709  this->old_vert_scroll_pos += dy;
710  this->set_vertical_scrollbar_position(aww, this->old_vert_scroll_pos);
711  }
712  device = aww->get_device (AW_MIDDLE_AREA);
713  device->set_filter(AW_SCREEN);
714  device->reset();
715  int screenwidth = this->rect.r-this->rect.l;
716  int screenheight = this->rect.b-this->rect.t;
717 
718  // compute move area params
719 
720  if (dx>0) {
721  csx = dx;
722  cdx = 0;
723  cwidth = screenwidth-dx;
724  }
725  else {
726  csx = 0;
727  cdx = -dx;
728  cwidth = screenwidth+dx;
729  }
730  if (dy>0) {
731  csy = dy;
732  cdy = 0;
733  cheight = screenheight-dy;
734  }
735  else {
736  csy = 0;
737  cdy = -dy;
738  cheight = screenheight+dy;
739  }
740 
741  // move area
742  if (!gfx->exports.dont_scroll) {
743  device->move_region(csx, csy, cwidth, cheight, cdx, cdy);
744  // redraw stripes
745  this->shift_x_to_fit -= dx/this->trans_to_fit;
746  this->shift_y_to_fit -= dy/this->trans_to_fit;
747 
748  // x-stripe
749  if ((int)dx>0) {
750  clip_expose(aww, this,
751  screenwidth-dx, screenwidth, 0, screenheight,
752  -CLIP_OVERLAP, 0);
753  }
754  if ((int)dx<0) {
755  clip_expose(aww, this,
756  0, -dx, 0, screenheight,
757  CLIP_OVERLAP, 0);
758  }
759 
760  // y-stripe
761  if ((int)dy>0) {
762  clip_expose(aww, this,
763  0, screenwidth, screenheight-dy, screenheight,
764  0, -CLIP_OVERLAP);
765  }
766  if ((int)dy<0) {
767  clip_expose(aww, this,
768  0, screenwidth, 0, -dy,
769  0, CLIP_OVERLAP);
770  }
771  }
772  else { // redraw everything
773  // redraw stripes
774  this->shift_x_to_fit -= dx/this->trans_to_fit;
775  this->shift_y_to_fit -= dy/this->trans_to_fit;
776  }
777  AWT_auto_refresh allowed_on(this);
778  this->request_refresh();
779 }
780 
781 static void scroll_vert_cb(AW_window *aww, AWT_canvas* scr) {
782  int new_vert = aww->slider_pos_vertical;
783  int delta_screen_y = (new_vert - scr->old_vert_scroll_pos);
784 
785  scr->scroll(0, delta_screen_y, true);
786  scr->old_vert_scroll_pos = new_vert;
787 }
788 
789 static void scroll_hor_cb(AW_window *aww, AWT_canvas* scr) {
790  int new_hor = aww->slider_pos_horizontal;
791  int delta_screen_x = (new_hor - scr->old_hor_scroll_pos);
792 
793  scr->scroll(delta_screen_x, 0, true);
794  scr->old_hor_scroll_pos = new_hor;
795 }
796 
797 
798 AWT_canvas::AWT_canvas(GBDATA *gb_main_, AW_window *aww_, const char *gc_base_name_, AWT_graphic *gfx_) :
799  consider_text_for_size(true),
800  gc_base_name(ARB_strdup(gc_base_name_)),
801  announce_update_cb(NULp),
802  user_data(0),
803  shift_x_to_fit(0),
804  shift_y_to_fit(0),
805  gb_main(gb_main_),
806  aww(aww_),
807  awr(aww->get_root()),
808  gfx(gfx_),
809  gc_manager(gfx->init_devices(aww, aww->get_device(AW_MIDDLE_AREA), this)),
810  mode(AWT_MODE_NONE)
811 {
813 
814  canvas_resize_cb(NULp, this);
815 
816  aww->set_expose_callback(AW_MIDDLE_AREA, makeWindowCallback(AWT_expose_cb, this));
817  aww->set_resize_callback(AW_MIDDLE_AREA, makeWindowCallback(canvas_resize_cb, this));
818  aww->set_input_callback(AW_MIDDLE_AREA, makeWindowCallback(input_event, this));
819  aww->set_focus_callback(makeWindowCallback(canvas_focus_cb, this));
820 
821  aww->set_motion_callback(AW_MIDDLE_AREA, makeWindowCallback(motion_event, this));
822  aww->set_horizontal_change_callback(makeWindowCallback(scroll_hor_cb, this));
823  aww->set_vertical_change_callback(makeWindowCallback(scroll_vert_cb, this));
824 }
825 
826 // --------------------------
827 // AWT_nonDB_graphic
828 
830  return "AWT_nonDB_graphic cannot be loaded";
831 }
832 
834  return "AWT_nonDB_graphic cannot be saved";
835 }
836 
837 void AWT_nonDB_graphic::check_for_DB_update(GBDATA *) { // @@@ should not be called!
838 #if defined(DEBUG)
839  printf("AWT_nonDB_graphic can't check_for_DB_update\n");
840 #endif // DEBUG
841 }
843 #if defined(DEBUG)
844  printf("AWT_nonDB_graphic can't notify_synchronized\n");
845 #endif // DEBUG
846 }
847 
848 
849 
void zoom(AW_device *device, bool zoomIn, const AW::Rectangle &wanted_part, const AW::Rectangle &current_part, int percent)
Definition: AWT_canvas.cxx:205
virtual void clear(AW_bitset filteri)
Definition: AW_device.cxx:313
const char * GB_ERROR
Definition: arb_core.h:25
void push_transaction() const
Definition: AWT_canvas.cxx:59
int zoom_drag_ey
Definition: awt_canvas.hxx:322
#define AWT_MIN_WIDTH
Definition: awt_canvas.hxx:294
void set_resize_callback(AW_area area, const WindowCallback &wcb)
Definition: AW_window.cxx:816
const AW_bitset AW_SIZE
Definition: aw_device.hxx:37
const AW_bitset AW_SCREEN
Definition: aw_device.hxx:34
void request_zoom_reset()
Definition: awt_canvas.hxx:364
void set_horizontal_scrollbar_position(AW_window *aww, int pos)
Definition: AWT_canvas.cxx:62
AW_device * get_device(AW_area area)
Definition: AW_window.cxx:537
const AW_screen_area & get_area_size() const
Definition: AW_device.cxx:57
Position centroid() const
void set_left_clip_border(int left, bool allow_oversize=false)
#define CLIP_OVERLAP
Definition: awt_canvas.hxx:292
double width() const
void shift(const AW::Vector &doff)
Definition: aw_device.hxx:131
void request_refresh()
Definition: awt_canvas.hxx:362
virtual void clear_part(const AW::Rectangle &rect, AW_bitset filteri)
Definition: AW_device.cxx:317
#define awt_assert(cond)
Definition: awt.hxx:28
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
void set_top_clip_border(int top, bool allow_oversize=false)
const int ZOOM_SPEED_WHEEL
Definition: AWT_canvas.cxx:420
void sync_DB_model_and_view(bool perform_refresh)
Definition: AWT_canvas.cxx:515
STL namespace.
void announce_screen_update()
Definition: awt_canvas.hxx:395
int get_drag_gc() const
Definition: awt_canvas.hxx:273
static void input_event(AW_window *aww, AWT_canvas *scr)
Definition: AWT_canvas.cxx:535
void instant_zoom_reset()
Definition: AWT_canvas.cxx:156
int slider_pos_horizontal
current position of the vertical slider
Definition: aw_window.hxx:350
AWT_canvas(GBDATA *gb_main_, AW_window *aww_, const char *gc_base_name_, AWT_graphic *gfx_)
Definition: AWT_canvas.cxx:798
void zoom(AW_pos scale)
Definition: AW_device.cxx:336
AW_screen_area rect
Definition: awt_canvas.hxx:316
int old_vert_scroll_pos
Definition: awt_canvas.hxx:315
GB_ERROR GB_push_transaction(GBDATA *gbd)
Definition: arbdb.cxx:2494
char character
Definition: aw_window.hxx:91
void set_motion_callback(AW_area area, const WindowCallback &wcb)
Definition: AW_window.cxx:811
void nt_draw_zoom_box(AW_device *device, int gc, AW_pos x1, AW_pos y1, AW_pos x2, AW_pos y2)
Definition: AWT_canvas.cxx:326
struct Unfixed_cb_parameter * UNFIXED
Definition: cb_base.h:15
GcChange
Definition: aw_base.hxx:94
double AW_pos
Definition: aw_base.hxx:29
int AW_get_drag_gc(AW_gc_manager *gcman)
Definition: AW_preset.cxx:1377
void drag_target_detection(bool detect)
Definition: awt_canvas.hxx:271
#define AWT_CATCH
void get_event(AW_event *eventi) const
Definition: AW_window.cxx:543
GB_ERROR save_to_DB(GBDATA *gb_main, const char *name) OVERRIDE __ATTR__USERESULT
Definition: AWT_canvas.cxx:833
static bool handleZoomEvent(AWT_canvas *scr, AW_device *device, const AW_event &event, int percent)
Definition: AWT_canvas.cxx:422
void set_bottom_clip_border(int bottom, bool allow_oversize=false)
#define true
Definition: ureadseq.h:14
#define aw_assert(bed)
Definition: aw_position.hxx:29
AW_device_click * get_click_device(AW_area area, int mousex, int mousey, int max_distance)
Definition: AW_window.cxx:526
double height() const
void set_dragEndpoint(int x, int y)
Definition: AWT_canvas.cxx:589
void set_expose_callback(AW_area area, const WindowCallback &wcb)
Definition: AW_window.cxx:765
AW::Vector rtransform(const AW::Vector &vec) const
Definition: aw_device.hxx:145
static void error(const char *msg)
Definition: mkptypes.cxx:96
const AW_bitset AW_CLICK_DROP
Definition: aw_device.hxx:36
void set_vertical_scrollbar_position(AW_window *aww, int pos)
Definition: AWT_canvas.cxx:69
static void clip_expose(AW_window *aww, AWT_canvas *scr, int left_border, int right_border, int top_border, int bottom_border, int hor_overlap, int ver_overlap)
Definition: AWT_canvas.cxx:336
GB_write_int const char GB_write_autoconv_string WRITE_SKELETON(write_pointer, GBDATA *,"%p", GB_write_pointer) char *AW_awa if)(!gb_var) return strdup("")
Definition: AW_awar.cxx:163
void set_scrollbars()
Definition: AWT_canvas.cxx:76
const double & y() const
void check_for_DB_update(GBDATA *gb_main) OVERRIDE
Definition: AWT_canvas.cxx:837
const AW_bitset AW_CLICK
Definition: aw_device.hxx:35
GB_ERROR GB_pop_transaction(GBDATA *gbd)
Definition: arbdb.cxx:2524
GB_ERROR load_from_DB(GBDATA *gb_main, const char *name) OVERRIDE __ATTR__USERESULT
Definition: AWT_canvas.cxx:829
AW_borders get_unscaleable_overlap() const
AW_key_code keycode
Definition: aw_window.hxx:90
AW_key_mod keymodifier
Definition: aw_window.hxx:83
int zoom_drag_sy
Definition: awt_canvas.hxx:320
const Vector & diagonal() const
int old_hor_scroll_pos
Definition: awt_canvas.hxx:314
static void motion_event(AW_window *aww, AWT_canvas *scr)
Definition: AWT_canvas.cxx:648
const Vector & line_vector() const
#define EPS
Definition: awt_canvas.hxx:291
virtual void handle_command(AW_device *device, AWT_graphic_event &event)=0
void set_right_clip_border(int right, bool allow_oversize=false)
void instant_refresh()
Definition: AWT_canvas.cxx:373
AWT_graphic * gfx
Definition: awt_canvas.hxx:339
static void scroll_vert_cb(AW_window *aww, AWT_canvas *scr)
Definition: AWT_canvas.cxx:781
int zoom_drag_sx
Definition: awt_canvas.hxx:319
const int ZOOM_SPEED_CLICK
Definition: AWT_canvas.cxx:419
AW_event_type type
Definition: aw_window.hxx:81
bool wants_drag_target() const
Definition: awt_canvas.hxx:270
const double & length() const
void scroll(int delta_x, int delta_y, bool dont_update_scrollbars=false)
Definition: AWT_canvas.cxx:703
void AWT_expose_cb(UNFIXED, AWT_canvas *scr)
Definition: AWT_canvas.cxx:385
void set_focus_callback(const WindowCallback &wcb)
Definition: AW_window.cxx:778
void get_size_information(AW_world *ptr) const __ATTR__DEPRECATED_TODO("whole AW_world is deprecated")
Definition: aw_device.hxx:657
AW_gc_manager * gc_manager
Definition: awt_canvas.hxx:341
AW_MouseButton button
Definition: aw_window.hxx:86
bool handleWheelEvent(AW_device *device, const AW_event &event)
Definition: AWT_canvas.cxx:454
AWT_graphic_exports exports
Definition: awt_canvas.hxx:249
void init_device(AW_device *device)
Definition: AWT_canvas.cxx:106
void reset()
Definition: AW_device.cxx:280
#define assert_no_auto_refresh_for(CANVAS)
Definition: awt_canvas.hxx:359
const AW_bitset AW_SIZE_UNSCALED
Definition: aw_device.hxx:38
void aw_message(const char *msg)
Definition: AW_status.cxx:1142
int zoom_drag_ex
Definition: awt_canvas.hxx:321
static void canvas_resize_cb(UNFIXED, AWT_canvas *scr)
Definition: AWT_canvas.cxx:389
#define NULp
Definition: cxxforward.h:116
void set_filter(AW_bitset filteri)
Definition: AW_device.cxx:321
static void scroll_hor_cb(AW_window *aww, AWT_canvas *scr)
Definition: AWT_canvas.cxx:789
virtual void move_region(AW_pos src_x, AW_pos src_y, AW_pos width, AW_pos height, AW_pos dest_x, AW_pos dest_y)
Definition: AW_device.cxx:263
void pop_transaction() const
Definition: AWT_canvas.cxx:60
void instant_resize(bool adjust_scrollbars)
Definition: AWT_canvas.cxx:112
GB_transaction ta(gb_var)
void set_horizontal_change_callback(const WindowCallback &wcb)
Definition: AW_window.cxx:1049
bool box(int gc, AW::FillStyle filled, const AW::Rectangle &rect, AW_bitset filteri=AW_ALL_DEVICES_SCALED)
Definition: aw_device.hxx:471
void set_vertical_change_callback(const WindowCallback &wcb)
Definition: AW_window.cxx:1033
AWT_COMMAND_MODE mode
Definition: awt_canvas.hxx:343
AWT_zoom_mode zoom_mode
Definition: awt_canvas.hxx:127
GBDATA * gb_main
Definition: adname.cxx:32
AW_window * aww
Definition: awt_canvas.hxx:337
void TRACE_UPDATE(const char *)
Definition: AWT_canvas.cxx:36
#define min(a, b)
Definition: f2c.h:153
int slider_pos_vertical
window id
Definition: aw_window.hxx:349
AWT_zoom_mode
Definition: awt_canvas.hxx:75
static void canvas_focus_cb(AW_window *, AWT_canvas *scr)
Definition: AWT_canvas.cxx:409
void set_input_callback(AW_area area, const WindowCallback &wcb)
Definition: AW_window.cxx:806
const double & x() const
void notify_synchronized(GBDATA *gb_main) OVERRIDE
Definition: AWT_canvas.cxx:842
void AWT_GC_changed_cb(GcChange whatChanged, AWT_canvas *scr)
Definition: AWT_canvas.cxx:394
GBDATA * gb_main
Definition: awt_canvas.hxx:336
void request_resize()
Definition: awt_canvas.hxx:363
virtual void show(AW_device *device)=0
#define max(a, b)
Definition: f2c.h:154