source: tags/ms_r16q3/AWT/AWT_canvas.cxx

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