source: tags/arb-6.0/WINDOW/AW_device_click.cxx

Last change on this file was 11168, checked in by westram, 10 years ago
  • move AW_getBestClick from WINDOW → AWT
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.7 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : AW_device_click.cxx                               //
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#include "aw_common.hxx"
13#include "aw_device_click.hxx"
14#include <algorithm>
15
16using namespace AW;
17
18// ------------------------
19//      AW_device_click
20
21AW_device_click::AW_device_click(AW_common *common_)
22        : AW_simple_device(common_) {
23    init_click(0, 0, AWT_NO_CATCH, AW_ALL_DEVICES);
24}
25
26void AW_device_click::init_click(AW_pos mousex, AW_pos mousey, int max_distance, AW_bitset filteri) {
27    mouse_x = mousex;
28    mouse_y = mousey;
29
30    filter = filteri;
31
32    max_distance_line = max_distance;
33    max_distance_text = max_distance;
34
35    opt_line.clear();
36    opt_text.clear();
37}
38
39AW_DEVICE_TYPE AW_device_click::type() {
40    return AW_DEVICE_CLICK;
41}
42
43bool AW_device_click::line_impl(int /*gc*/, const AW::LineVector& Line, AW_bitset filteri) {
44    if (!(filteri & filter)) return false; // motif-only
45
46    LineVector transLine = transform(Line);
47    LineVector clippedLine;
48    bool       drawflag  = clip(transLine, clippedLine);
49    if (drawflag) {
50        Position mouse(mouse_x, mouse_y);
51        double   nearest_rel_pos;
52        Position nearest  = nearest_linepoint(mouse, clippedLine, nearest_rel_pos);
53        double   distance = Distance(mouse, nearest);
54
55        if (distance < max_distance_line) {
56            max_distance_line = distance;
57           
58            opt_line.x0 = Line.xpos();
59            opt_line.y0 = Line.ypos();
60            opt_line.x1 = Line.head().xpos();
61            opt_line.y1 = Line.head().ypos();
62
63            opt_line.distance = distance;
64            opt_line.set_rel_pos(nearest_rel_pos);
65
66            opt_line.copy_cds(click_cd);
67            opt_line.exists = true;
68        }
69    }
70    return drawflag;
71}
72
73
74bool AW_device_click::text_impl(int gc, const char *str, const AW::Position& pos, AW_pos alignment, AW_bitset filteri, long opt_strlen) {
75    if (!(filteri & filter)) return false; // motif only - gtk should
76
77    AW_pos X0, Y0;          // Transformed pos
78    this->transform(pos.xpos(), pos.ypos(), X0, Y0);
79
80    const AW_GC           *gcm         = get_common()->map_gc(gc);
81    const AW_font_limits&  font_limits = gcm->get_font_limits();
82
83    AW_pos Y1 = Y0+font_limits.descent;
84    Y0        = Y0-font_limits.ascent;
85
86    // Fast check text against top/bottom clip
87    const AW_screen_area& clipRect = get_cliprect();
88    if (clipRect.t == 0) {
89        if (Y1 < clipRect.t) return false;
90    }
91    else {
92        if (Y0 < clipRect.t) return false;
93    }
94
95    if (clipRect.b == get_common()->get_screen().b) {
96        if (Y0 > clipRect.b) return false;
97    }
98    else {
99        if (Y1 > clipRect.b) return false;
100    }
101
102    // vertical check mouse against textsurrounding
103    bool exact     = true;
104    int  dist2text = 0; // exact hit -> distance == 0
105
106    // vertical check against textborders
107    if (mouse_y > Y1) { // above text
108        int ydist = mouse_y-Y1;
109        if (ydist > max_distance_text) return false; // too far above
110        exact     = false;
111        dist2text = ydist;
112    }
113    else if (mouse_y < Y0) { // below text
114        int ydist = Y0-mouse_y;
115        if (ydist > max_distance_text) return false; // too far below
116        exact     = false;
117        dist2text = ydist;
118    }
119
120    // align text
121    int len        = opt_strlen ? opt_strlen : strlen(str);
122    int text_width = (int)get_string_size(gc, str, len);
123
124    X0        = x_alignment(X0, text_width, alignment);
125    AW_pos X1 = X0+text_width;
126
127    // check against left/right clipping areas
128    if (X1 < clipRect.l) return false;
129    if (X0 > clipRect.r) return false;
130
131    // horizontal check against textborders
132    if (mouse_x > X1) { // right of text
133        int xdist = mouse_x-X1;
134        if (xdist > max_distance_text) return false; // too far right
135        exact     = false;
136        dist2text = std::max(xdist, dist2text);
137    }
138    else if (mouse_x < X0) { // left of text
139        int xdist = X0-mouse_x;
140        if (xdist > max_distance_text) return false; // too far left
141        exact     = false;
142        dist2text = std::max(xdist, dist2text);
143    }
144
145    max_distance_text = dist2text; // exact hit -> distance = 0
146
147    int position = -1; // invalid (if not exact)
148    if (exact) {
149        if (font_limits.is_monospaced()) {
150            short letter_width = font_limits.width;
151            position = (int)((mouse_x-X0)/letter_width);
152            if (position<0) position = 0;
153            if (position>(len-1)) position = len-1;
154        }
155        else { // proportional font
156            position   = 0;
157            int tmp_offset = 0;
158            while (position<=len) {
159                tmp_offset += gcm->get_width_of_char(str[position]);
160                if (mouse_x <= X0+tmp_offset) break;
161                position++;
162            }
163        }
164    }
165
166    if (!opt_text.exists              || // first candidate
167        (!opt_text.exactHit && exact) || // previous candidate was no exact hit
168        (opt_text.distance>dist2text))   // previous candidate had greater distance to click
169    {
170        Rectangle textArea(LineVector(X0, Y0, X1, Y1));
171
172        LineVector orientation = textArea.bigger_extent();
173        LineVector clippedOrientation;
174
175        bool visible = clip(orientation, clippedOrientation);
176        if (visible) {
177            Position mouse(mouse_x, mouse_y);
178            double   nearest_rel_pos;
179            Position nearest = nearest_linepoint(mouse, clippedOrientation, nearest_rel_pos);
180
181            opt_text.textArea = rtransform(textArea);
182            opt_text.set_rel_pos(nearest_rel_pos);
183            opt_text.cursor   = position;
184
185            opt_text.distance = max_distance_text;
186            opt_text.exactHit = exact;
187
188            opt_text.copy_cds(click_cd);
189            opt_text.exists   = true;
190        }
191    }
192    return true;
193}
194
195
196void AW_device_click::get_clicked_line(AW_clicked_line *ptr) const {
197    *ptr = opt_line;
198}
199
200
201void AW_device_click::get_clicked_text(AW_clicked_text *ptr) const {
202    *ptr = opt_text;
203}
204
205int AW_clicked_line::indicate_selected(AW_device *d, int gc) const {
206    return d->line(gc, x0, y0, x1, y1);
207}
208int AW_clicked_text::indicate_selected(AW_device *d, int gc) const {
209    return d->box(gc, true, textArea);
210}
211
Note: See TracBrowser for help on using the repository browser.