source: branches/stable/AWT/awt_canvas.hxx

Last change on this file was 16763, checked in by westram, 6 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.0 KB
Line 
1#ifndef AWT_CANVAS_HXX
2#define AWT_CANVAS_HXX
3
4#ifndef AW_WINDOW_HXX
5#include <aw_window.hxx>
6#endif
7#ifndef AW_DEVICE_HXX
8#include <aw_device.hxx>
9#endif
10#ifndef AW_DEVICE_CLICK_HXX
11#include <aw_device_click.hxx>
12#endif
13#ifndef ATTRIBUTES_H
14#include <attributes.h>
15#endif
16#ifndef ARB_ASSERT_H
17#include <arb_assert.h>
18#endif
19
20#define awt_assert(cond) arb_assert(cond)
21
22class AWT_canvas;
23class AW_device;
24
25enum AWT_COMMAND_MODE {
26    AWT_MODE_NONE,
27    AWT_MODE_EMPTY, // placeholder (currently used in PARSIMONY)
28
29    // NTREE, PARSIMONY, GENEMAP and SECEDIT:
30    AWT_MODE_ZOOM,
31
32    // NTREE, PARSIMONY and GENEMAP:
33    AWT_MODE_SELECT,
34    AWT_MODE_INFO, // (=ED4_SM_INFO in EDIT4)
35
36    // NTREE, PARSIMONY and SECEDIT:
37    AWT_MODE_SETROOT,
38
39    // NTREE and PARSIMONY:
40    AWT_MODE_MOVE,
41    AWT_MODE_MARK,
42    AWT_MODE_GROUP,
43    AWT_MODE_LZOOM,
44    AWT_MODE_SWAP,
45
46    // NTREE and SECEDIT:
47    AWT_MODE_ROTATE,
48
49    // NTREE only:
50    AWT_MODE_LINE,
51    AWT_MODE_WWW,
52    AWT_MODE_SPREAD,
53    AWT_MODE_LENGTH,
54    AWT_MODE_MULTIFURC,
55
56    // PARSIMONY only:
57    AWT_MODE_KERNINGHAN,
58    AWT_MODE_NNI,
59    AWT_MODE_OPTIMIZE,
60
61    // SECEDIT only:
62    AWT_MODE_FOLD,
63    AWT_MODE_CURSOR,
64    AWT_MODE_EDIT,
65    AWT_MODE_PINFO,
66    AWT_MODE_STRETCH,
67    AWT_MODE_SET_CURSOR
68};
69
70#define STANDARD_PADDING 10
71
72// --------------------------------------------------------------------------------
73// AWT_zoom_mode + AWT_fit_mode are correlated, but not strictly coupled
74
75enum AWT_zoom_mode { // bit values!
76    AWT_ZOOM_NEVER = 0,
77    AWT_ZOOM_X     = 1,
78    AWT_ZOOM_Y     = 2,
79    AWT_ZOOM_BOTH  = 3,
80};
81
82enum AWT_fit_mode {
83    AWT_FIT_NEVER,
84    AWT_FIT_LARGER, 
85    AWT_FIT_SMALLER, 
86    AWT_FIT_X, 
87    AWT_FIT_Y, 
88};
89
90// used combinations are:
91// AWT_ZOOM_NEVER + AWT_FIT_NEVER (NDS list, others)
92// AWT_ZOOM_X + AWT_FIT_X (dendrogram tree)
93// AWT_ZOOM_Y + AWT_FIT_Y
94// AWT_ZOOM_BOTH + AWT_FIT_LARGER (radial tree/gene-map; secedit)
95// AWT_ZOOM_BOTH + AWT_FIT_SMALLER (book-style gene-map)
96//
97// other combinations may work as well. some combinations make no sense.
98// --------------------------------------------------------------------------------
99
100
101class AWT_graphic_exports {
102    AW_borders default_padding;
103    AW_borders padding;
104
105    // sync-flags to update between
106    // - internal structure of AWT_graphic (e.g. AP_tree)
107    // - stored representation (normally in DB)
108    // - display/userinput
109    unsigned int refresh : 1;          // 1 -> do a refresh
110    unsigned int resize : 1;           // 1 -> size of graphic might have changed (implies 'refresh')
111    unsigned int zoom_reset : 1;       // 1 -> do a zoom-reset (implies 'resize')
112    unsigned int supdate : 1;          // 1 -> internal structure needs update; calls update_structure() (implies 'resize')
113    unsigned int save : 1;             // 1 -> save structure to DB (implies 'supdate')
114
115    int modifying; // number of AWT_auto_refresh instances.
116                   // !=0 -> flag modification allowed
117                   // >=0 -> AWT_auto_refresh instanciation allowed
118                   // -1 is used while performing updates
119
120    friend class AWT_auto_refresh;
121#if defined(UNIT_TESTS)
122    friend class fake_AWT_graphic_tree;
123#endif
124
125public:
126
127    AWT_zoom_mode zoom_mode;
128    AWT_fit_mode  fit_mode;
129
130    unsigned int dont_scroll : 1; // normally 0 (1 for IRS tree)
131
132    void init();     // like clear, but resets fit, scroll state and padding
133
134    bool inside_auto_refresh() const { return modifying>0; } // returns true if AWT_auto_refresh instance exists
135    bool inside_update() const { return modifying<0; }       // returns true during update (=destruction of initial AWT_auto_refresh instance)
136
137    bool flags_clearable() const { return inside_update(); }
138    bool flags_writeable() const {
139        // returns true if sync-flags may be modified.
140        // In that case, no explicit refresh etc. shall happen.
141        return inside_auto_refresh() || inside_update();
142    }
143    int& get_modifying_flag_ref() { return modifying; } // do not use!
144
145    // clear sync request (should happen outside of AWT_auto_refresh)
146    void clear_refresh_request()          { awt_assert(flags_clearable()); refresh    = false; }
147    void clear_resize_request()           { awt_assert(flags_clearable()); resize     = false; }
148    void clear_zoom_reset_request()       { awt_assert(flags_clearable()); zoom_reset = false; }
149    void clear_structure_update_request() { awt_assert(flags_clearable()); supdate    = false; }
150    void clear_save_request()             { awt_assert(flags_clearable()); save       = false; }
151
152    // request sync:
153    void request_refresh()             { awt_assert(flags_writeable()); refresh    = true; }
154    void request_resize()              { awt_assert(flags_writeable()); resize     = true; }
155    void request_zoom_reset()          { awt_assert(flags_writeable()); zoom_reset = true; }
156    void request_structure_update()    { awt_assert(flags_writeable()); supdate    = true; }
157    void request_save()                { awt_assert(flags_writeable()); save       = true; }
158    // common combinations:
159    void request_save_and_zoom_reset() { awt_assert(flags_writeable()); save = true; zoom_reset = true; }
160
161    // sync requested?:
162    bool needs_structure_update() const { return supdate; }
163    bool needs_save() const { return save; }
164
165    inline void update_display_as_requested(AWT_canvas *scr, bool perform_refresh); // handles zoom_reset + resize + refresh
166
167    void set_default_padding(int t, int b, int l, int r) {
168        default_padding.t = t;
169        default_padding.b = b;
170        default_padding.l = l;
171        default_padding.r = r;
172
173        padding = default_padding;
174    }
175
176    void set_equilateral_default_padding(int pad) { set_default_padding(pad, pad, pad, pad); }
177    void set_standard_default_padding() { set_equilateral_default_padding(STANDARD_PADDING); }
178
179    void set_extra_text_padding(const AW_borders& text_padding) {
180        padding.t = default_padding.t + text_padding.t;
181        padding.b = default_padding.b + text_padding.b;
182        padding.l = default_padding.l + text_padding.l;
183        padding.r = default_padding.r + text_padding.r;
184    }
185
186    int get_x_padding() const { return padding.l+padding.r; }
187    int get_y_padding() const { return padding.t+padding.b; }
188    int get_top_padding() const { return padding.t; }
189    int get_left_padding() const { return padding.l; }
190
191    AW::Vector zoomVector(double transToFit) const {
192        return AW::Vector(zoom_mode&AWT_ZOOM_X ? transToFit : 1.0,
193                          zoom_mode&AWT_ZOOM_Y ? transToFit : 1.0);
194    }
195};
196
197class AWT_graphic_event : virtual Noncopyable {
198    AWT_COMMAND_MODE M_cmd;  // currently active mode
199
200    AW_MouseButton M_button;
201    AW_key_mod     M_key_modifier;
202    AW_key_code    M_key_code;
203    char           M_key_char;
204    AW_event_type  M_type;
205
206    AW::Position mousepos;
207
208    AW_device_click *click_dev;
209
210public:
211    AWT_graphic_event(AWT_COMMAND_MODE cmd_, const AW_event& event, bool is_drag, AW_device_click *click_dev_)
212        : M_cmd(cmd_),
213          M_button(event.button),
214          M_key_modifier(event.keymodifier),
215          M_key_code(event.keycode),
216          M_key_char(event.character),
217          M_type(is_drag ? AW_Mouse_Drag : event.type),
218          mousepos(event.x, event.y),
219          click_dev(click_dev_)
220    {}
221
222    AWT_COMMAND_MODE cmd() const { return M_cmd; }
223    AW_MouseButton button() const { return M_button; }
224
225    AW_key_mod key_modifier() const { return M_key_modifier; }
226    AW_key_code key_code() const { return M_key_code; }
227    char key_char() const { return M_key_char; }
228
229    AW_event_type type() const { return M_type; }
230
231    const AW::Position& position() const { return mousepos; } // screen-coordinates
232
233    const AW_clicked_element *best_click(AW_device_click::ClickPreference prefer = AW_device_click::PREFER_NEARER) {
234        return click_dev ? click_dev->best_click(prefer) : NULp;
235    }
236};
237
238class AWT_graphic {
239    friend class AWT_canvas;
240
241    void update_DB_and_model_as_requested(GBDATA *gb_main);
242
243    bool detect_drag_target;
244
245protected:
246    int drag_gc;
247
248public:
249    AWT_graphic_exports exports;
250
251    AWT_graphic() { exports.init(); }
252    virtual ~AWT_graphic() {}
253
254    // pure virtual interface (methods implemented by AWT_nonDB_graphic)
255
256    virtual GB_ERROR load_from_DB(GBDATA *gb_main, const char *name) = 0;
257    virtual GB_ERROR save_to_DB(GBDATA *gb_main, const char *name)   = 0;
258    virtual void check_for_DB_update(GBDATA *gb_main)                = 0; // check whether anything changed in DB (and reload internal structure if needed)
259    virtual void notify_synchronized(GBDATA *gb_main)                = 0; // mark the database content and internal structure of AWT_graphic as synchronized
260
261    // pure virtual interface (rest)
262
263    virtual void show(AW_device *device) = 0;
264
265    virtual AW_gc_manager *init_devices(AW_window *, AW_device *, AWT_canvas *scr) = 0; /* init gcs, if any gc is changed AWT_GC_changed_cb() is called */
266
267    virtual void handle_command(AW_device *device, AWT_graphic_event& event) = 0;
268    virtual void update_structure()                                          = 0; // called when exports.needs_structure_update()
269
270    bool wants_drag_target() const { return detect_drag_target; }
271    void drag_target_detection(bool detect) { detect_drag_target = detect; }
272
273    int get_drag_gc() const { return drag_gc; }
274};
275
276class AWT_nonDB_graphic : public AWT_graphic { // @@@ check AWT_nonDB_graphic
277    void update_structure() OVERRIDE {}
278    // a partly implementation of AWT_graphic
279public:
280    AWT_nonDB_graphic() {}
281    ~AWT_nonDB_graphic() OVERRIDE {}
282
283    // dummy functions, only spittings out warnings:
284    GB_ERROR load_from_DB(GBDATA *gb_main, const char *name) OVERRIDE __ATTR__USERESULT;
285    GB_ERROR save_to_DB(GBDATA *gb_main, const char *name) OVERRIDE __ATTR__USERESULT;
286    void check_for_DB_update(GBDATA *gb_main) OVERRIDE;
287    void notify_synchronized(GBDATA *gb_main) OVERRIDE;
288};
289
290
291#define EPS               0.0001 // div zero check
292#define CLIP_OVERLAP      15
293#define AWT_ZOOM_OUT_STEP 40    // (pixel) rand um screen
294#define AWT_MIN_WIDTH     100   // Minimum center screen (= screen-offset)
295
296typedef void (*screen_update_callback)(AWT_canvas*, AW_CL cd);
297
298class AWT_canvas : virtual Noncopyable {
299    bool  consider_text_for_size;
300    char *gc_base_name;
301
302protected:
303    // callback called after each screen-update (set by derived class; currently only by TREE_canvas)
304    screen_update_callback announce_update_cb;
305    AW_CL                  user_data;
306
307public:
308    // @@@ make members private!
309
310    AW_pos trans_to_fit;
311    AW_pos shift_x_to_fit;
312    AW_pos shift_y_to_fit;
313
314    int old_hor_scroll_pos;
315    int old_vert_scroll_pos;
316    AW_screen_area rect;  // screen coordinates
317    AW_world worldinfo; // real coordinates without transform.
318    AW_world worldsize;
319    int zoom_drag_sx;
320    int zoom_drag_sy;
321    int zoom_drag_ex;
322    int zoom_drag_ey;
323    int drag;
324
325    void init_device(AW_device *device);
326
327    void set_scrollbars();
328    void set_dragEndpoint(int x, int y);
329
330    void set_horizontal_scrollbar_position(AW_window *aww, int pos);
331    void set_vertical_scrollbar_position(AW_window *aww, int pos);
332
333    // public (read only)
334    // @@@ make members private!
335
336    GBDATA      *gb_main;
337    AW_window   *aww;
338    AW_root     *awr;
339    AWT_graphic *gfx;
340
341    AW_gc_manager *gc_manager;
342
343    AWT_COMMAND_MODE mode;
344
345    // real public
346
347    AWT_canvas(GBDATA *gb_main_, AW_window *aww_, const char *gc_base_name_, AWT_graphic *gfx_);
348    virtual ~AWT_canvas() {}
349
350    inline void push_transaction() const;
351    inline void pop_transaction() const;
352
353#if defined(ASSERTION_USED)
354    bool inside_auto_refresh() const {
355        // returns true if AWT_auto_refresh instance exists for this canvas
356        return gfx->exports.inside_auto_refresh();
357    }
358#endif
359#define assert_no_auto_refresh_for(CANVAS) awt_assert(!(CANVAS)->inside_auto_refresh())
360
361    // request updates from underlaying AWT_graphic
362    void request_refresh()          { if (gfx) gfx->exports.request_refresh(); }
363    void request_resize()           { if (gfx) gfx->exports.request_resize(); }
364    void request_zoom_reset()       { if (gfx) gfx->exports.request_zoom_reset(); }
365    void request_structure_update() { if (gfx) gfx->exports.request_structure_update(); }
366    void request_save()             { if (gfx) gfx->exports.request_save(); }
367    // common combinations:
368    void request_save_and_zoom_reset() { if (gfx) gfx->exports.request_save_and_zoom_reset(); }
369
370    // instant refresh functions (unrecommended, should only be used internally)
371    // -> instead use AWT_auto_refresh + request_XXX-functions above!
372    void instant_refresh();
373    void instant_resize(bool adjust_scrollbars); // [Note: should normally be called with 'true']
374    void instant_zoom_reset();
375
376    // --------------------
377
378    void set_consider_text_for_zoom_reset(bool consider) { consider_text_for_size = consider; }
379
380    void zoom(AW_device *device, bool zoomIn, const AW::Rectangle& wanted_part, const AW::Rectangle& current_part, int percent);
381
382    void set_mode(AWT_COMMAND_MODE mo) { mode = mo; }
383
384    void scroll(int delta_x, int delta_y, bool dont_update_scrollbars = false);
385    void scroll(const AW::Vector& delta, bool dont_update_scrollbars = false) {
386        scroll(int(delta.x()), int(delta.y()), dont_update_scrollbars);
387    }
388
389    bool handleWheelEvent(AW_device *device, const AW_event& event);
390
391    const char *get_gc_base_name() const { return gc_base_name; }
392
393    void sync_DB_model_and_view(bool perform_refresh);
394
395    void announce_screen_update() { if (announce_update_cb) announce_update_cb(this, user_data); }
396
397    bool is_shown() const { return aww->is_shown(); }
398};
399
400class AWT_auto_refresh {
401    // While instance exists -> sync flags of AWT_graphic_exports may be modified
402    // Creating additional instances just incs/decs a counter.
403    // When initial instance gets destroyed
404    // => AWT_canvas::sync_DB_model_and_view() handles all requests (save, update, resize, refresh)
405
406    RefPtr<AWT_canvas> scr;
407
408    // @@@ delay non-instant refresh into idle callback?
409    // bool instant_refresh; // true -> do instant refresh (only has effect on first instance!) @@@ unused atm
410
411public:
412    AWT_auto_refresh(AWT_canvas *scr_) :
413        scr(scr_)
414    {
415        AWT_graphic_exports& exports = scr->gfx->exports;
416        awt_assert(exports.modifying >= 0); // otherwise you try to instanciate from inside sync_DB_model_and_view()
417        if (exports.modifying++ == 0) {
418            // test for already set export-flags here? might indicate wrong logic
419            scr->gfx->check_for_DB_update(scr->gb_main);
420        }
421    }
422    ~AWT_auto_refresh() {
423        AWT_graphic_exports& exports = scr->gfx->exports;
424        if (--exports.modifying <= 0) {
425            awt_assert(exports.modifying == 0);
426            scr->sync_DB_model_and_view(true);
427        }
428    }
429
430    void suppress_update_and_refresh() {
431        // use at end of scope of initial AWT_auto_refresh to suppress any updates of model + view
432        // Note: use carefully, may cause model inconsistencies!!!
433
434        AWT_graphic_exports& exports = scr->gfx->exports;
435        LocallyModify<int>   permit_suppression(exports.get_modifying_flag_ref(), -1);
436
437        exports.clear_structure_update_request();
438        exports.clear_zoom_reset_request();
439        exports.clear_resize_request();
440        exports.clear_refresh_request();
441    }
442};
443
444inline void AWT_graphic_exports::update_display_as_requested(AWT_canvas *scr, bool perform_refresh) {
445    assert_no_auto_refresh_for(scr);
446
447    if (zoom_reset) {
448        scr->instant_zoom_reset(); // also does resize
449        awt_assert(!zoom_reset && !resize && refresh);
450    }
451    else if (resize) {
452        scr->instant_resize(true);
453        awt_assert(!resize && refresh);
454    }
455
456    if (refresh && perform_refresh) {
457        scr->instant_refresh();
458        awt_assert(!refresh);
459    }
460}
461
462void AWT_expose_cb(UNFIXED, AWT_canvas *scr);
463void AWT_resize_cb(UNFIXED, AWT_canvas *scr);
464void AWT_GC_changed_cb(GcChange whatChanged, AWT_canvas *scr);
465
466void AWT_popup_tree_export_window(AW_window *parent_win, AWT_canvas *scr);
467void AWT_popup_sec_export_window (AW_window *parent_win, AWT_canvas *scr);
468void AWT_popup_print_window      (AW_window *parent_win, AWT_canvas *scr);
469
470
471#endif
Note: See TracBrowser for help on using the repository browser.