source: tags/ms_r16q2/WINDOW/aw_device_click.hxx

Last change on this file was 14197, checked in by westram, 9 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.9 KB
Line 
1// ================================================================ //
2//                                                                  //
3//   File      : aw_device_click.hxx                                //
4//   Purpose   : Detect which graphical element is "nearby"         //
5//               a given mouse position                             //
6//                                                                  //
7//   Institute of Microbiology (Technical University Munich)        //
8//   http://www.arb-home.de/                                        //
9//                                                                  //
10// ================================================================ //
11
12#ifndef AW_DEVICE_CLICK_HXX
13#define AW_DEVICE_CLICK_HXX
14
15#ifndef AW_DEVICE_HXX
16#include "aw_device.hxx"
17#endif
18
19class AW_clicked_element {
20    AW_CL client_data1;
21    AW_CL client_data2;
22
23    bool   exists;          // true if a drawn element was clicked, else false
24    int    distance;        // distance in pixel to nearest line/text
25    AW_pos nearest_rel_pos; // 0 = at left(upper) small-side, 1 = at right(lower) small-side of textArea or line (does not make sense for box or polygon)
26
27    void copy_cds(const AW_click_cd *click_cd) {
28        if (click_cd) {
29            client_data1 = click_cd->get_cd1();
30            client_data2 = click_cd->get_cd2();
31        }
32        else {
33            client_data1 = 0;
34            client_data2 = 0;
35        }
36    }
37    void set_rel_pos(double rel) { aw_assert(rel >= 0.0 && rel <= 1.0); nearest_rel_pos = rel; }
38
39protected:
40
41    AW_clicked_element()
42        : client_data1(0),
43          client_data2(0),
44          exists(false),
45          distance(-1),
46          nearest_rel_pos(0)
47    {}
48
49    void assign(int distance_, const AW_pos& nearest_rel_pos_, const AW_click_cd *click_cd_) {
50        distance = distance_;
51        set_rel_pos(nearest_rel_pos_);
52        copy_cds(click_cd_);
53        exists   = true;
54    }
55
56public:
57    virtual ~AW_clicked_element() {}
58
59    AW_CL cd1() const { return client_data1; }
60    AW_CL cd2() const { return client_data2; }
61
62    virtual AW::Position get_attach_point() const  = 0;
63    virtual AW::Rectangle get_bounding_box() const = 0;
64    virtual AW_clicked_element *clone() const      = 0;
65
66    bool does_exist() const { return exists; }
67
68    inline bool is_text() const;
69    inline bool is_line() const;
70    inline bool is_box() const;
71    inline bool is_polygon() const;
72
73    double get_rel_pos() const { return nearest_rel_pos; }
74    int get_distance() const { return distance; }
75    AW::LineVector get_connecting_line(const AW_clicked_element& other) const {
76        //! determine LineVector between two clicked elements (e.g. for drag&drop)
77        return AW::LineVector(get_attach_point(), other.get_attach_point());
78    }
79
80    virtual bool operator==(const AW_clicked_element& other) const = 0;
81    virtual int indicate_selected(AW_device *d, int gc) const  = 0;
82};
83
84class AW_clicked_line : public AW_clicked_element {
85    AW::LineVector line; // world coordinates of clicked line
86public:
87    void assign(const AW::LineVector& line_, int distance_, const AW_pos& nearest_rel_pos_, const AW_click_cd *click_cd_) {
88        AW_clicked_element::assign(distance_, nearest_rel_pos_, click_cd_);
89        line = line_;
90    }
91
92    bool operator == (const AW_clicked_element& other) const OVERRIDE {
93        const AW_clicked_line *otherLine = dynamic_cast<const AW_clicked_line*>(&other);
94        return otherLine ? nearlyEqual(get_line(), otherLine->get_line()) : false;
95    }
96
97    AW::Position get_attach_point() const OVERRIDE {
98        double nrp = get_rel_pos();
99        return line.start() + nrp*line.line_vector();
100    }
101    AW::Rectangle get_bounding_box() const OVERRIDE { return AW::Rectangle(line); }
102    const AW::LineVector& get_line() const { return line; }
103
104    int indicate_selected(AW_device *d, int gc) const OVERRIDE;
105    AW_clicked_element *clone() const OVERRIDE { return new AW_clicked_line(*this); }
106};
107
108class AW_clicked_text : public AW_clicked_element {
109    AW::Rectangle textArea; // world coordinates of clicked text
110public:
111    void assign(AW::Rectangle textArea_, int distance_, const AW_pos& nearest_rel_pos_, const AW_click_cd *click_cd_) {
112        AW_clicked_element::assign(distance_, nearest_rel_pos_, click_cd_);
113        textArea = textArea_;
114    }
115
116    bool operator == (const AW_clicked_element& other) const OVERRIDE {
117        const AW_clicked_text *otherText = dynamic_cast<const AW_clicked_text*>(&other);
118        return otherText ? nearlyEqual(textArea, otherText->textArea) : false;
119    }
120
121    AW::Position get_attach_point() const OVERRIDE { return textArea.centroid(); }
122    AW::Rectangle get_bounding_box() const OVERRIDE { return textArea; }
123
124    int indicate_selected(AW_device *d, int gc) const OVERRIDE;
125    AW_clicked_element *clone() const OVERRIDE { return new AW_clicked_text(*this); }
126};
127
128class AW_clicked_box : public AW_clicked_element {
129    AW::Rectangle box; // world coordinates of clicked box
130public:
131    void assign(AW::Rectangle box_, int distance_, const AW_pos& nearest_rel_pos_, const AW_click_cd *click_cd_) {
132        AW_clicked_element::assign(distance_, nearest_rel_pos_, click_cd_);
133        box    = box_;
134    }
135
136    bool operator == (const AW_clicked_element& other) const OVERRIDE {
137        const AW_clicked_box *otherBox = dynamic_cast<const AW_clicked_box*>(&other);
138        return otherBox ? nearlyEqual(box, otherBox->box) : false;
139    }
140
141    AW::Position get_attach_point() const OVERRIDE { return box.centroid(); }
142    AW::Rectangle get_bounding_box() const OVERRIDE { return box; }
143    int indicate_selected(AW_device *d, int gc) const OVERRIDE;
144    AW_clicked_element *clone() const OVERRIDE { return new AW_clicked_box(*this); }
145};
146
147class AW_clicked_polygon : public AW_clicked_element {
148    int           npos; // number of corners
149    AW::Position *pos;  // world coordinates of clicked polygon
150
151public:
152    AW_clicked_polygon()
153        : npos(0),
154          pos(NULL)
155    {}
156    AW_clicked_polygon(const AW_clicked_polygon& other)
157        : AW_clicked_element(other),
158          npos(other.npos)
159    {
160        if (other.pos) {
161            pos = new AW::Position[npos];
162            for (int i = 0; i<npos; ++i) pos[i] = other.pos[i];
163        }
164        else {
165            pos = NULL;
166        }
167    }
168    DECLARE_ASSIGNMENT_OPERATOR(AW_clicked_polygon);
169    ~AW_clicked_polygon() {
170        delete [] pos;
171    }
172
173    void assign(int npos_, const AW::Position *pos_, int distance_, const AW_pos& nearest_rel_pos_, const AW_click_cd *click_cd_) {
174        if (pos) delete [] pos;
175
176        AW_clicked_element::assign(distance_, nearest_rel_pos_, click_cd_);
177
178        npos = npos_;
179        pos  = new AW::Position[npos];
180        for (int i = 0; i<npos; ++i) pos[i] = pos_[i];
181    }
182
183    bool operator == (const AW_clicked_element& other) const OVERRIDE {
184        const AW_clicked_polygon *otherPoly = dynamic_cast<const AW_clicked_polygon*>(&other);
185        if (otherPoly) {
186            if (npos == otherPoly->npos) {
187                for (int i = 0; i<npos; ++i) {
188                    if (!nearlyEqual(pos[i], otherPoly->pos[i])) {
189                        return false;
190                    }
191                }
192                return true;
193            }
194        }
195        return false;
196    }
197
198    AW::Position get_attach_point() const OVERRIDE {
199        AW::Position c = pos[0];
200        for (int i = 1; i<npos; ++i) {
201            c += AW::Vector(pos[i]);
202        }
203        return AW::Position(c.xpos()/npos, c.ypos()/npos);
204    }
205    AW::Rectangle get_bounding_box() const OVERRIDE;
206    int indicate_selected(AW_device *d, int gc) const OVERRIDE;
207    AW_clicked_element *clone() const OVERRIDE {
208        return new AW_clicked_polygon(*this);
209    }
210
211    const AW::Position *get_polygon(int& posCount) const {
212        aw_assert(does_exist());
213        posCount = npos;
214        return pos;
215    }
216};
217
218
219// ---------------------
220//      type checks
221
222inline bool AW_clicked_element::is_text()    const { return dynamic_cast<const AW_clicked_text*>(this); }
223inline bool AW_clicked_element::is_line()    const { return dynamic_cast<const AW_clicked_line*>(this); }
224inline bool AW_clicked_element::is_box()     const { return dynamic_cast<const AW_clicked_box*>(this); }
225inline bool AW_clicked_element::is_polygon() const { return dynamic_cast<const AW_clicked_polygon*>(this); }
226
227#define AWT_CATCH    30         // max-pixel distance to graphical element (to accept a click or command)
228#define AWT_NO_CATCH -1
229
230class AW_device_click : public AW_simple_device {
231    AW::Position mouse;
232
233    int max_distance_line;
234    int max_distance_text;
235
236    AW_clicked_line    opt_line;
237    AW_clicked_text    opt_text;
238    AW_clicked_box     opt_box;
239    AW_clicked_polygon opt_polygon;
240
241    bool line_impl(int gc, const AW::LineVector& Line, AW_bitset filteri) OVERRIDE;
242    bool text_impl(int gc, const char *str, const AW::Position& pos, AW_pos alignment, AW_bitset filteri, long opt_strlen) OVERRIDE;
243    bool box_impl(int gc, AW::FillStyle filled, const AW::Rectangle& rect, AW_bitset filteri) OVERRIDE;
244    bool polygon_impl(int gc, AW::FillStyle filled, int npos, const AW::Position *pos, AW_bitset filteri) OVERRIDE;
245
246    // completely ignore clicks to circles and arcs
247    bool circle_impl(int, AW::FillStyle, const AW::Position&, const AW::Vector&, AW_bitset) OVERRIDE { return false; }
248    bool arc_impl(int, AW::FillStyle, const AW::Position&, const AW::Vector&, int, int, AW_bitset) OVERRIDE { return false; }
249
250    bool invisible_impl(const AW::Position& pos, AW_bitset filteri) OVERRIDE { return generic_invisible(pos, filteri); }
251    void specific_reset() OVERRIDE {}
252   
253public:
254    AW_device_click(AW_common *common_);
255
256    AW_DEVICE_TYPE type() OVERRIDE;
257
258    void init_click(const AW::Position& click, int max_distance, AW_bitset filteri);
259
260    enum ClickPreference { PREFER_NEARER, PREFER_LINE, PREFER_TEXT };
261    const AW_clicked_element *best_click(ClickPreference prefer = PREFER_NEARER);
262};
263
264#else
265#error aw_device_click.hxx included twice
266#endif // AW_DEVICE_CLICK_HXX
Note: See TracBrowser for help on using the repository browser.