source: tags/arb-6.0-rc3/AWT/AWT_canvas.cxx

Last change on this file was 11464, checked in by westram, 10 years ago
  • un-dummy-fied transaction (renames only)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.8 KB
Line 
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 <arbdbt.h>
17
18#include <algorithm>
19
20using namespace std;
21using namespace AW;
22
23void AWT_graphic_exports::clear() {
24    zoom_reset       = 0;
25    resize           = 0;
26    refresh          = 0;
27    save             = 0;
28    structure_change = 0;
29}
30
31void AWT_graphic_exports::init() {
32    clear();
33    padding.clear();
34
35    zoom_mode = AWT_ZOOM_BOTH;
36    fit_mode  = AWT_FIT_LARGER;
37
38    dont_scroll = 0;
39}
40
41inline void AWT_canvas::push_transaction() const { if (gb_main) GB_push_transaction(gb_main); }
42inline void AWT_canvas::pop_transaction() const { if (gb_main) GB_pop_transaction(gb_main); }
43
44void AWT_canvas::set_horizontal_scrollbar_position(AW_window *, int pos) {
45    int maxpos = int(worldsize.r-rect.r)-1;
46    if (pos>maxpos) pos = maxpos;
47    if (pos<0) pos = 0;
48    aww->set_horizontal_scrollbar_position(pos);
49}
50
51void AWT_canvas::set_vertical_scrollbar_position(AW_window *, int pos) {
52    int maxpos = int(worldsize.b-rect.b)-1;
53    if (pos>maxpos) pos = maxpos;
54    if (pos<0) pos = 0;
55    aww->set_vertical_scrollbar_position(pos);
56}
57
58void AWT_canvas::set_scrollbars() {
59    AW_pos width  = this->worldinfo.r - this->worldinfo.l;
60    AW_pos height = this->worldinfo.b - this->worldinfo.t;
61
62    worldsize.l = 0;
63    worldsize.t = 0;
64
65    AW::Vector zv = gfx->exports.zoomVector(trans_to_fit);
66
67    worldsize.r = width *zv.x() + gfx->exports.get_x_padding();
68    worldsize.b = height*zv.y() + gfx->exports.get_y_padding();
69
70    aww->tell_scrolled_picture_size(worldsize);
71
72    aww->calculate_scrollbars();
73
74    this->old_hor_scroll_pos = (int)((-this->worldinfo.l -
75                                      this->shift_x_to_fit)*
76                                     this->trans_to_fit +
77                                     gfx->exports.get_left_padding());
78    this->set_horizontal_scrollbar_position(this->aww, old_hor_scroll_pos);
79
80    this->old_vert_scroll_pos = (int)((-this->worldinfo.t -
81                                       this->shift_y_to_fit)*
82                                      this->trans_to_fit+
83                                      gfx->exports.get_top_padding());
84
85    this->set_vertical_scrollbar_position(this->aww, old_vert_scroll_pos);
86}
87
88void AWT_canvas::init_device(AW_device *device) {
89    device->reset();
90    device->shift(AW::Vector(shift_x_to_fit, shift_y_to_fit));
91    device->zoom(this->trans_to_fit);
92}
93
94void AWT_canvas::recalc_size(bool adjust_scrollbars) {
95    GB_transaction  ta(this->gb_main);
96    AW_device_size *size_device = aww->get_size_device(AW_MIDDLE_AREA);
97
98    size_device->set_filter(AW_SIZE|(consider_text_for_size ? AW_SIZE_UNSCALED : 0));
99    size_device->reset();
100
101    gfx->show(size_device);
102
103    if (consider_text_for_size) {
104        gfx->exports.set_extra_text_padding(size_device->get_unscaleable_overlap());
105    }
106
107    size_device->get_size_information(&(this->worldinfo));
108    rect = size_device->get_area_size();   // real world size (no offset)
109
110    if (adjust_scrollbars) set_scrollbars();
111}
112
113void AWT_canvas::zoom_reset() {
114    recalc_size(false);
115
116    AW_pos width  = this->worldinfo.r - this->worldinfo.l;
117    AW_pos height = this->worldinfo.b - this->worldinfo.t;
118
119    AW_pos net_window_width  = rect.r - rect.l - gfx->exports.get_x_padding();
120    AW_pos net_window_height = rect.b - rect.t - gfx->exports.get_y_padding();
121   
122    if (net_window_width<AWT_MIN_WIDTH) net_window_width   = AWT_MIN_WIDTH;
123    if (net_window_height<AWT_MIN_WIDTH) net_window_height = AWT_MIN_WIDTH;
124
125    if (width <EPS) width   = EPS;
126    if (height <EPS) height = EPS;
127
128    AW_pos x_scale = net_window_width/width;
129    AW_pos y_scale = net_window_height/height;
130
131    trans_to_fit = -1;
132    switch (gfx->exports.fit_mode) {
133        case AWT_FIT_NEVER:   trans_to_fit = 1.0; break;
134        case AWT_FIT_X:       trans_to_fit = x_scale; break;
135        case AWT_FIT_Y:       trans_to_fit = y_scale; break;
136        case AWT_FIT_LARGER:  trans_to_fit = std::min(x_scale, y_scale); break;
137        case AWT_FIT_SMALLER: trans_to_fit = std::max(x_scale, y_scale); break;
138    }
139    aw_assert(trans_to_fit > 0);
140
141    AW_pos center_shift_x = 0;
142    AW_pos center_shift_y = 0;
143
144    if (gfx->exports.zoom_mode&AWT_ZOOM_X) center_shift_x = (net_window_width /trans_to_fit - width)/2;
145    if (gfx->exports.zoom_mode&AWT_ZOOM_Y) center_shift_y = (net_window_height/trans_to_fit - height)/2;
146
147    // complete, upper left corner
148    this->shift_x_to_fit = - this->worldinfo.l + gfx->exports.get_left_padding()/trans_to_fit + center_shift_x;
149    this->shift_y_to_fit = - this->worldinfo.t + gfx->exports.get_top_padding()/trans_to_fit  + center_shift_y;
150
151    this->old_hor_scroll_pos  = 0;
152    this->old_vert_scroll_pos = 0;
153
154    // scale
155
156    this->set_scrollbars();
157}
158
159void AWT_canvas::zoom(AW_device *device, bool zoomIn, const Rectangle& wanted_part, const Rectangle& current_part, int percent) {
160    // zooms the device.
161    //
162    // zoomIn == true -> wanted_part is zoomed to current_part
163    // zoomIn == false -> current_part is zoomed to wanted_part
164    //
165    // If wanted_part is very small -> assume mistake (act like single click)
166    // Single click zooms by 'percent' % centering on click position
167
168    init_device(device);
169
170    if (!gfx) {
171        awt_assert(0); // we have no display - does this occur?
172                       // if yes, pls inform devel@arb-home.de about circumstances
173        return;
174    }
175
176    AW_pos width  = worldinfo.r-worldinfo.l;
177    AW_pos height = worldinfo.b-worldinfo.t;
178
179    if (width<EPS) width = EPS;
180    if (height<EPS) height = EPS;
181
182    AWT_zoom_mode zoom_mode = gfx->exports.zoom_mode;
183    if (zoom_mode == AWT_ZOOM_NEVER) {
184        aw_message("Zoom does not work in this mode");
185        return;
186    }
187
188    Rectangle current(device->rtransform(current_part));
189    Rectangle wanted;
190
191    bool isClick = false;
192    switch (zoom_mode) {
193        case AWT_ZOOM_BOTH: isClick = wanted_part.line_vector().length()<40.0; break;
194        case AWT_ZOOM_X:    isClick = wanted_part.width()<30.0;                break;
195        case AWT_ZOOM_Y:    isClick = wanted_part.height()<30.0;               break;
196
197        case AWT_ZOOM_NEVER: awt_assert(0); break;
198    }
199
200    if (isClick) { // very small part or single click
201        // -> zoom by 'percent' % on click position
202        Position clickPos = device->rtransform(wanted_part.centroid());
203
204        Vector click2UpperLeft  = current.upper_left_corner()-clickPos;
205        Vector click2LowerRight = current.lower_right_corner()-clickPos;
206
207        double scale = (100-percent)/100.0;
208
209        wanted = Rectangle(clickPos+scale*click2UpperLeft, clickPos+scale*click2LowerRight);
210    }
211    else {
212        wanted = Rectangle(device->rtransform(wanted_part));
213    }
214
215    if (!zoomIn) {
216        // calculate big rectangle (outside of viewport), which is zoomed into viewport
217
218        if (zoom_mode == AWT_ZOOM_BOTH) {
219            double    factor = current.diagonal().length()/wanted.diagonal().length();
220            Vector    curr2wanted(current.upper_left_corner(), wanted.upper_left_corner());
221            Rectangle big(current.upper_left_corner()+(curr2wanted*-factor), current.diagonal()*factor);
222
223            wanted = big;
224        }
225        else {
226            double factor;
227            if (zoom_mode == AWT_ZOOM_X) {
228                factor = current.width()/wanted.width();
229            }
230            else {
231                awt_assert(zoom_mode == AWT_ZOOM_Y);
232                factor = current.height()/wanted.height();
233            }
234            Vector    curr2wanted_start(current.upper_left_corner(), wanted.upper_left_corner());
235            Vector    curr2wanted_end(current.lower_right_corner(), wanted.lower_right_corner());
236            Rectangle big(current.upper_left_corner()+(curr2wanted_start*-factor),
237                          current.lower_right_corner()+(curr2wanted_end*-factor));
238
239            wanted = big;
240        }
241    }
242
243    // scroll
244    shift_x_to_fit = (zoom_mode&AWT_ZOOM_X) ? -wanted.start().xpos() : (shift_x_to_fit+worldinfo.l)*trans_to_fit;
245    shift_y_to_fit = (zoom_mode&AWT_ZOOM_Y) ? -wanted.start().ypos() : (shift_y_to_fit+worldinfo.t)*trans_to_fit;
246
247    // scale
248    if ((rect.r-rect.l)<EPS) rect.r = rect.l+1;
249    if ((rect.b-rect.t)<EPS) rect.b = rect.t+1;
250
251    AW_pos max_trans_to_fit;
252   
253    switch (zoom_mode) {
254        case AWT_ZOOM_BOTH:
255            trans_to_fit     = max((rect.r-rect.l)/wanted.width(), (rect.b-rect.t)/wanted.height());
256            max_trans_to_fit = 32000.0/max(width, height);
257            break;
258
259        case AWT_ZOOM_X:
260            trans_to_fit     = (rect.r-rect.l)/wanted.width();
261            max_trans_to_fit = 32000.0/width;
262            break;
263
264        case AWT_ZOOM_Y:
265            trans_to_fit     = (rect.b-rect.t)/wanted.height();
266            max_trans_to_fit = 32000.0/height;
267            break;
268
269        case AWT_ZOOM_NEVER: awt_assert(0); break;
270    }
271    trans_to_fit = std::min(trans_to_fit, max_trans_to_fit);
272
273    // correct scrolling for "dont_fit"-direction
274    if (zoom_mode == AWT_ZOOM_Y) shift_x_to_fit = (shift_x_to_fit/trans_to_fit)-worldinfo.l;
275    if (zoom_mode == AWT_ZOOM_X) shift_y_to_fit = (shift_y_to_fit/trans_to_fit)-worldinfo.t;
276
277    set_scrollbars();
278}
279
280inline void nt_draw_zoom_box(AW_device *device, int gc, AW_pos x1, AW_pos y1, AW_pos x2, AW_pos y2) {
281    device->box(gc, false, x1, y1, x2-x1, y2-y1);
282}
283inline void nt_draw_zoom_box(AW_device *device, AWT_canvas *scr) {
284    nt_draw_zoom_box(device, scr->drag_gc,
285                     scr->zoom_drag_sx, scr->zoom_drag_sy,
286                     scr->zoom_drag_ex, scr->zoom_drag_ey);
287}
288
289static void clip_expose(AW_window *aww, AWT_canvas *scr,
290                        int left_border, int right_border,
291                        int top_border, int bottom_border,
292                        int hor_overlap, int ver_overlap)
293{
294    AW_device *device = aww->get_device (AW_MIDDLE_AREA);
295    device->set_filter(AW_SCREEN);
296    device->reset();
297
298    device->set_top_clip_border(top_border);
299    device->set_bottom_clip_border(bottom_border);
300    device->set_left_clip_border(left_border);
301    device->set_right_clip_border(right_border);
302
303    device->clear_part(left_border, top_border, right_border-left_border,
304                       bottom_border-top_border, -1);
305
306    GB_transaction ta(scr->gb_main);
307
308    if (scr->gfx->check_update(scr->gb_main)>0) {
309        scr->zoom_reset();
310    }
311
312    scr->init_device(device);
313
314    if (hor_overlap> 0.0) {
315        device->set_right_clip_border(right_border + hor_overlap);
316    }
317    if (hor_overlap< 0.0) {
318        device->set_left_clip_border(left_border + hor_overlap);
319    }
320    if (ver_overlap> 0.0) {
321        device->set_bottom_clip_border(bottom_border + ver_overlap);
322    }
323    if (ver_overlap< 0.0) {
324        device->set_top_clip_border(top_border + ver_overlap);
325    }
326    scr->gfx->show(device);
327}
328
329void AWT_expose_cb(UNFIXED, AWT_canvas *scr) {
330    scr->refresh();
331}
332
333void AWT_canvas::refresh() {
334    AW_device *device = this->aww->get_device (AW_MIDDLE_AREA);
335    device->clear(-1);
336    clip_expose(this->aww, this, this->rect.l, this->rect.r,
337                this->rect.t, this->rect.b, 0, 0);
338}
339
340void AWT_resize_cb(UNFIXED, AWT_canvas *scr) {
341    scr->zoom_reset();
342    AWT_expose_cb(NULL, scr);
343}
344
345static void canvas_focus_cb(AW_window *, AWT_canvas *scr) {
346    if (scr->gb_main) {
347        scr->push_transaction();
348
349        int flags = scr->gfx->check_update(scr->gb_main);
350        if (flags) scr->recalc_size_and_refresh();
351
352        scr->pop_transaction();
353    }
354}
355
356const int ZOOM_SPEED_CLICK = 10;
357const int ZOOM_SPEED_WHEEL = 4;
358
359static bool handleZoomEvent(AWT_canvas *scr, AW_device *device, const AW_event& event, int percent) {
360    bool handled = false;
361    bool zoomIn  = true;
362
363    if      (event.button == AW_BUTTON_LEFT)  { handled = true; }
364    else if (event.button == AW_BUTTON_RIGHT) { handled = true; zoomIn  = false; }
365
366    if (handled) {
367        if (event.type == AW_Mouse_Press) {
368            scr->drag = 1;
369            scr->zoom_drag_sx = scr->zoom_drag_ex = event.x;
370            scr->zoom_drag_sy = scr->zoom_drag_ey = event.y;
371        }
372        else {
373            // delete last box
374            nt_draw_zoom_box(device, scr);
375            scr->drag = 0;
376
377            Rectangle screen(scr->rect, INCLUSIVE_OUTLINE);
378            Rectangle drag(scr->zoom_drag_sx, scr->zoom_drag_sy, scr->zoom_drag_ex, scr->zoom_drag_ey);
379
380            scr->zoom(device, zoomIn, drag, screen, percent);
381            AWT_expose_cb(NULL, scr);
382        }
383    }
384    else if (event.keycode == AW_KEY_ASCII && event.character == '0') { // reset zoom (as promised by MODE_TEXT_STANDARD_ZOOMMODE)
385        scr->zoom_reset_and_refresh();
386        handled = true;
387    }
388    return handled;
389}
390
391bool AWT_canvas::handleWheelEvent(AW_device *device, const AW_event& event) {
392    if (event.button != AW_WHEEL_UP && event.button != AW_WHEEL_DOWN)  {
393        return false; // not handled
394    }
395    if (event.type == AW_Mouse_Press) {
396        if (event.keymodifier & AW_KEYMODE_CONTROL) {
397            AW_event faked = event;
398
399            faked.button = (event.button == AW_WHEEL_UP) ? AW_BUTTON_LEFT : AW_BUTTON_RIGHT;
400            handleZoomEvent(this, device, faked, ZOOM_SPEED_WHEEL);
401            faked.type   = AW_Mouse_Release;
402            handleZoomEvent(this, device, faked, ZOOM_SPEED_WHEEL);
403        }
404        else {
405            bool horizontal = event.keymodifier & AW_KEYMODE_ALT;
406
407            int viewport_size = horizontal ? (rect.r-rect.l+1) : (rect.b-rect.t+1);
408            int gfx_size      = horizontal ? (worldsize.r-worldsize.l) : (worldsize.b-worldsize.t);
409           
410            // scroll 10% of screen or 10% of graphic size (whichever is smaller):
411            int dist      = std::min(viewport_size / 20, gfx_size / 30);
412            int direction = event.button == AW_WHEEL_UP ? -dist : dist;
413
414            int dx = horizontal ? direction : 0;
415            int dy = horizontal ? 0 : direction;
416
417            scroll(dx, dy);
418        }
419    }
420    return true;
421}
422
423void AWT_graphic::postevent_handler(GBDATA *gb_main) {
424    // handle AWT_graphic_exports
425
426    if (exports.save) {
427        GB_ERROR error = save(gb_main, 0, 0, 0);
428        if (error) {
429            aw_message(error);
430            load(gb_main, 0, 0, 0);
431        }
432        exports.structure_change = 1;
433    }
434    if (exports.structure_change) {
435        update_structure();
436        exports.resize = 1;
437    }
438    if (gb_main) update(gb_main);
439}
440
441void AWT_canvas::postevent_handler() {
442    gfx->postevent_handler(gb_main);
443    gfx->refresh_by_exports(this);
444}
445
446static void input_event(AW_window *aww, AWT_canvas *scr) {
447    awt_assert(aww = scr->aww);
448
449    AW_event event;
450    aww->get_event(&event);
451   
452    AW_device *device = aww->get_device(AW_MIDDLE_AREA);
453    device->set_filter(AW_SCREEN);
454    device->reset();
455
456    scr->gfx->exports.clear();
457    scr->push_transaction();
458
459    scr->gfx->check_update(scr->gb_main);
460
461    bool event_handled = false;
462
463    if (event.button == AW_BUTTON_MIDDLE) {
464        event_handled = true; // only set zoom_drag_e.. below
465    }
466    else if (scr->mode == AWT_MODE_ZOOM) { // zoom mode is identical for all applications, so handle it here
467        event_handled = handleZoomEvent(scr, device, event, ZOOM_SPEED_CLICK);
468    }
469
470    if (!event_handled) {
471        event_handled = scr->handleWheelEvent(device, event);
472    }
473
474    if (!event_handled) {
475        AW_device_click *click_device = aww->get_click_device(AW_MIDDLE_AREA, event.x, event.y, AWT_CATCH);
476        click_device->set_filter(AW_CLICK);
477        device->set_filter(AW_SCREEN);
478
479        scr->init_device(click_device);
480        scr->init_device(device);
481
482        scr->gfx->show(click_device);
483        click_device->get_clicked_line(&scr->clicked_line);
484        click_device->get_clicked_text(&scr->clicked_text);
485
486        AWT_graphic_event gevent(scr->mode, event, false, &scr->clicked_line, &scr->clicked_text);
487        scr->gfx->handle_command(device, gevent);
488
489        scr->postevent_handler();
490    }
491
492    scr->zoom_drag_ex = event.x;
493    scr->zoom_drag_ey = event.y;
494    scr->pop_transaction();
495}
496
497
498void AWT_canvas::set_dragEndpoint(int dragx, int dragy) {
499    switch (gfx->exports.zoom_mode) {
500        case AWT_ZOOM_NEVER: {
501            awt_assert(0);
502            break;
503        }
504        case AWT_ZOOM_X: {
505            zoom_drag_sy = rect.t;
506            zoom_drag_ey = rect.b-1;
507            zoom_drag_ex = dragx;
508            break;
509        }
510        case AWT_ZOOM_Y: {
511            zoom_drag_sx = rect.l;
512            zoom_drag_ex = rect.r-1;
513            zoom_drag_ey = dragy;
514            break;
515        }
516        case AWT_ZOOM_BOTH: {
517            zoom_drag_ex = dragx;
518            zoom_drag_ey = dragy;
519
520            int drag_sx = zoom_drag_ex-zoom_drag_sx;
521            int drag_sy = zoom_drag_ey-zoom_drag_sy;
522
523            bool   correct_x = false;
524            bool   correct_y = false;
525            double factor;
526
527            int scr_sx = rect.r-rect.l;
528            int scr_sy = rect.b-rect.t;
529
530            if (drag_sx == 0) {
531                if (drag_sy != 0) { factor = double(drag_sy)/scr_sy; correct_x = true; }
532            }
533            else {
534                if (drag_sy == 0) { factor = double(drag_sx)/scr_sx; correct_y = true; }
535                else {
536                    double facx = double(drag_sx)/scr_sx;
537                    double facy = double(drag_sy)/scr_sy;
538
539                    if (fabs(facx)>fabs(facy)) { factor = facx; correct_y = true; }
540                    else                       { factor = facy; correct_x = true; }
541                }
542            }
543
544            if (correct_x) {
545                int width    = int(scr_sx*factor) * ((drag_sx*drag_sy) < 0 ? -1 : 1);
546                zoom_drag_ex = zoom_drag_sx+width;
547            }
548            else if (correct_y) {
549                int height = int(scr_sy*factor) * ((drag_sx*drag_sy) < 0 ? -1 : 1);
550                zoom_drag_ey = zoom_drag_sy+height;
551            }
552            break;
553        }
554    }
555}
556
557static void motion_event(AW_window *aww, AWT_canvas *scr) {
558    AW_device *device = aww->get_device(AW_MIDDLE_AREA);
559    device->reset();
560    device->set_filter(AW_SCREEN);
561
562    scr->push_transaction();
563
564    AW_event event;
565    aww->get_event(&event);
566
567    if (event.button == AW_BUTTON_MIDDLE) {
568        // shift display in ALL modes
569        int dx = event.x - scr->zoom_drag_ex;
570        int dy = event.y - scr->zoom_drag_ey;
571
572        scr->zoom_drag_ex = event.x;
573        scr->zoom_drag_ey = event.y;
574
575        // display
576        scr->scroll(-dx*3, -dy*3);
577    }
578    else {
579        bool run_command = true;
580
581        if (event.button == AW_BUTTON_LEFT || event.button == AW_BUTTON_RIGHT) {
582            switch (scr->mode) {
583                case AWT_MODE_ZOOM:
584                    nt_draw_zoom_box(device, scr);
585                    scr->set_dragEndpoint(event.x, event.y);
586                    nt_draw_zoom_box(device, scr);
587                    run_command = false;
588                    break;
589
590                case AWT_MODE_MOVE: {
591                    scr->init_device(device);
592                    AW_device_click *click_device = aww->get_click_device(AW_MIDDLE_AREA, event.x, event.y, AWT_CATCH);
593                    click_device->set_filter(AW_CLICK_DROP);
594                    scr->init_device(click_device);
595                    scr->gfx->show(click_device);
596                    click_device->get_clicked_line(&scr->clicked_line);
597                    click_device->get_clicked_text(&scr->clicked_text);
598                    run_command  = true;
599                    break;
600                }
601                default:
602                    break;
603            }
604        }
605
606        if (run_command) {
607            scr->init_device(device);
608
609            AWT_graphic_event gevent(scr->mode, event, true, &scr->clicked_line, &scr->clicked_text);
610            scr->gfx->handle_command(device, gevent);
611        }
612    }
613
614    scr->postevent_handler();
615    scr->pop_transaction();
616}
617
618void AWT_canvas::scroll(int dx, int dy, bool dont_update_scrollbars) {
619    int csx, cdx, cwidth, csy, cdy, cheight;
620    AW_device *device;
621    if (!dont_update_scrollbars) {
622        this->old_hor_scroll_pos += dx;
623        this->set_horizontal_scrollbar_position(aww, this->old_hor_scroll_pos);
624        this->old_vert_scroll_pos += dy;
625        this->set_vertical_scrollbar_position(aww, this->old_vert_scroll_pos);
626    }
627    device = aww->get_device (AW_MIDDLE_AREA);
628    device->set_filter(AW_SCREEN);
629    device->reset();
630    int screenwidth = this->rect.r-this->rect.l;
631    int screenheight = this->rect.b-this->rect.t;
632
633    // compute move area params
634
635    if (dx>0) {
636        csx = dx;
637        cdx = 0;
638        cwidth = screenwidth-dx;
639    }
640    else {
641        csx = 0;
642        cdx = -dx;
643        cwidth = screenwidth+dx;
644    }
645    if (dy>0) {
646        csy = dy;
647        cdy = 0;
648        cheight = screenheight-dy;
649    }
650    else {
651        csy = 0;
652        cdy = -dy;
653        cheight = screenheight+dy;
654    }
655
656    // move area
657    if (!gfx->exports.dont_scroll) {
658        device->move_region(csx, csy, cwidth, cheight, cdx, cdy);
659        // redraw stripes
660        this->shift_x_to_fit -= dx/this->trans_to_fit;
661        this->shift_y_to_fit -= dy/this->trans_to_fit;
662
663        // x-stripe
664        if ((int)dx>0) {
665            clip_expose(aww, this,
666                        screenwidth-dx, screenwidth, 0, screenheight,
667                        -CLIP_OVERLAP,  0);
668        }
669        if ((int)dx<0) {
670            clip_expose(aww, this,
671                        0, -dx, 0, screenheight,
672                        CLIP_OVERLAP, 0);
673        }
674
675        // y-stripe
676        if ((int)dy>0) {
677            clip_expose(aww, this,
678                        0, screenwidth, screenheight-dy, screenheight,
679                        0, -CLIP_OVERLAP);
680        }
681        if ((int)dy<0) {
682            clip_expose(aww, this,
683                        0, screenwidth, 0,  -dy,
684                        0,  CLIP_OVERLAP);
685        }
686    }
687    else {          // redraw everything
688        // redraw stripes
689        this->shift_x_to_fit -= dx/this->trans_to_fit;
690        this->shift_y_to_fit -= dy/this->trans_to_fit;
691        AWT_expose_cb(NULL, this);
692    }
693    this->refresh();
694}
695
696static void scroll_vert_cb(AW_window *aww, AWT_canvas* scr) {
697    int new_vert       = aww->slider_pos_vertical;
698    int delta_screen_y = (new_vert - scr->old_vert_scroll_pos);
699
700    scr->scroll(0, delta_screen_y, true);
701    scr->old_vert_scroll_pos = new_vert;
702}
703
704static void scroll_hor_cb(AW_window *aww, AWT_canvas* scr) {
705    int new_hor        = aww->slider_pos_horizontal;
706    int delta_screen_x = (new_hor - scr->old_hor_scroll_pos);
707
708    scr->scroll(delta_screen_x, 0, true);
709    scr->old_hor_scroll_pos = new_hor;
710}
711
712
713AWT_canvas::AWT_canvas(GBDATA *gb_maini, AW_window *awwi, const char *gc_base_name_, AWT_graphic *awd, const char *user_awari)
714    : consider_text_for_size(true)
715    , gc_base_name(strdup(gc_base_name_))
716    , user_awar(strdup(user_awari))
717    , shift_x_to_fit(0)
718    , shift_y_to_fit(0)
719    , gb_main(gb_maini)
720    , aww(awwi)
721    , awr(aww->get_root())
722    , gfx(awd)
723    , gc_manager(gfx->init_devices(aww, aww->get_device(AW_MIDDLE_AREA), this))
724    , drag_gc(aww->main_drag_gc)
725    , mode(AWT_MODE_NONE)
726{
727    gfx->drag_gc   = drag_gc;
728
729    AWT_resize_cb(NULL, this);
730
731    aww->set_expose_callback(AW_MIDDLE_AREA, makeWindowCallback(AWT_expose_cb, this));
732    aww->set_resize_callback(AW_MIDDLE_AREA, makeWindowCallback(AWT_resize_cb, this));
733    aww->set_input_callback(AW_MIDDLE_AREA, makeWindowCallback(input_event, this));
734    aww->set_focus_callback(makeWindowCallback(canvas_focus_cb, this));
735
736    aww->set_motion_callback(AW_MIDDLE_AREA, makeWindowCallback(motion_event, this));
737    aww->set_horizontal_change_callback(makeWindowCallback(scroll_hor_cb, this));
738    aww->set_vertical_change_callback(makeWindowCallback(scroll_vert_cb, this));
739}
740
741// --------------------------
742//      AWT_nonDB_graphic
743
744GB_ERROR AWT_nonDB_graphic::load(GBDATA *, const char *, AW_CL, AW_CL) {
745    return "AWT_nonDB_graphic cannot be loaded";
746}
747
748GB_ERROR AWT_nonDB_graphic::save(GBDATA *, const char *, AW_CL, AW_CL) {
749    return "AWT_nonDB_graphic cannot be saved";
750}
751
752int AWT_nonDB_graphic::check_update(GBDATA *) {
753#if defined(DEBUG)
754    printf("AWT_nonDB_graphic can't be check for update\n");
755#endif // DEBUG
756    return -1;
757}
758void AWT_nonDB_graphic::update(GBDATA *) {
759#if defined(DEBUG)
760    printf("AWT_nonDB_graphic can't be updated\n");
761#endif // DEBUG
762}
763
764const AW_clicked_element *AWT_graphic_event::best_click(ClickPreference prefer) {
765    // returns the element with lower distance (to mouse-click- or key-"click"-position).
766    // or NULL (if no element was found inside catch-distance)
767
768    const AW_clicked_element *bestClick = 0;
769
770    if (M_cl->exists) {
771        if (M_ct->exists) {
772            switch (prefer) {
773                case PREFER_NEARER:
774                    if (M_cl->distance < M_ct->distance) {
775                        bestClick = M_cl;
776                    }
777                    else {
778                        bestClick = M_ct;
779                    }
780                    break;
781
782                case PREFER_LINE: bestClick = M_cl; break;
783                case PREFER_TEXT: bestClick = M_ct; break;
784            }
785        }
786        else {
787            bestClick = M_cl;
788        }
789    }
790    else if (M_ct->exists) {
791        bestClick = M_ct;
792    }
793
794#if defined(DEBUG) && 0
795    if (bestClick) {
796        const char *type = bestClick == M_cl ? "line" : "text";
797        printf("best click catches '%s' (distance=%i)\n", type, bestClick->distance);
798    }
799    else {
800        printf("click catched nothing\n");
801    }
802#endif
803
804    return bestClick;
805}
806
807
Note: See TracBrowser for help on using the repository browser.