source: trunk/AWT/AWT_canvas.cxx

Last change on this file was 18730, checked in by westram, 3 years ago
  • remove trailing whitespace from c source.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.7 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
22#if defined(DEVEL_RALF)
23// # define TRACE_MODEL_VIEW_UPDATES
24#endif
25
26#if defined(TRACE_MODEL_VIEW_UPDATES)
27inline 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
36inline void TRACE_UPDATE(const char *) {}
37#endif
38
39using namespace std;
40using namespace AW;
41
42void AWT_graphic_exports::init() {
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
59inline void AWT_canvas::push_transaction() const { if (gb_main) GB_push_transaction(gb_main); }
60inline void AWT_canvas::pop_transaction() const { if (gb_main) GB_pop_transaction(gb_main); }
61
62void AWT_canvas::set_horizontal_scrollbar_position(AW_window *, int pos) {
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
69void AWT_canvas::set_vertical_scrollbar_position(AW_window *, int pos) {
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
76void AWT_canvas::set_scrollbars() {
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
106void AWT_canvas::init_device(AW_device *device) {
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
112void AWT_canvas::instant_resize(bool adjust_scrollbars) {
113    TRACE_UPDATE("resize");
114
115    assert_no_auto_refresh_for(this);
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
156void AWT_canvas::instant_zoom_reset() {
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
205void 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
326inline 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}
329inline 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
336static 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
373void AWT_canvas::instant_refresh() {
374    TRACE_UPDATE("refresh");
375    assert_no_auto_refresh_for(this);
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
385void AWT_expose_cb(UNFIXED, AWT_canvas *scr) {
386    AWT_auto_refresh allowed_on(scr);
387    scr->request_refresh();
388}
389static void canvas_resize_cb(UNFIXED, AWT_canvas *scr) {
390    AWT_auto_refresh allowed_on(scr);
391    scr->request_zoom_reset();
392}
393
394void 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:
400        case GC_COLOR_GROUP_USE_CHANGED:
401            scr->request_refresh();
402            break;
403        case GC_FONT_CHANGED:
404            scr->request_resize();
405            break;
406    }
407}
408
409static 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
419const int ZOOM_SPEED_CLICK = 10;
420const int ZOOM_SPEED_WHEEL = 4;
421
422static 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
454bool 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
488void 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
515void 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
535static 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
589void 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
648static 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
703void 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
781static 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
789static 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
798AWT_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{
812    gfx->drag_gc   = AW_get_drag_gc(gc_manager);
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
829GB_ERROR AWT_nonDB_graphic::load_from_DB(GBDATA *, const char *) {
830    return "AWT_nonDB_graphic cannot be loaded";
831}
832
833GB_ERROR AWT_nonDB_graphic::save_to_DB(GBDATA *, const char *) {
834    return "AWT_nonDB_graphic cannot be saved";
835}
836
837void 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}
842void AWT_nonDB_graphic::notify_synchronized(GBDATA *) {
843#if defined(DEBUG)
844    printf("AWT_nonDB_graphic can't notify_synchronized\n");
845#endif // DEBUG
846}
847
848
849
Note: See TracBrowser for help on using the repository browser.