1 | // =============================================================== // |
---|
2 | // // |
---|
3 | // File : AW_clipable.cxx // |
---|
4 | // Purpose : // |
---|
5 | // // |
---|
6 | // Institute of Microbiology (Technical University Munich) // |
---|
7 | // http://www.arb-home.de/ // |
---|
8 | // // |
---|
9 | // =============================================================== // |
---|
10 | |
---|
11 | #include "aw_window.hxx" |
---|
12 | #include "aw_root.hxx" |
---|
13 | #include "aw_common_xm.hxx" |
---|
14 | |
---|
15 | #include <arb_msg.h> |
---|
16 | |
---|
17 | using namespace AW; |
---|
18 | |
---|
19 | inline AW_pos clip_in_range(AW_pos low, AW_pos val, AW_pos high) { |
---|
20 | if (val <= low) return low; |
---|
21 | if (val >= high) return high; |
---|
22 | return val; |
---|
23 | } |
---|
24 | |
---|
25 | bool AW_clipable::box_clip(AW_pos x0, AW_pos y0, AW_pos x1, AW_pos y1, AW_pos& x0out, AW_pos& y0out, AW_pos& x1out, AW_pos& y1out) { |
---|
26 | // clip coordinates of a box |
---|
27 | |
---|
28 | aw_assert(x0 <= x1); |
---|
29 | aw_assert(y0 <= y1); |
---|
30 | |
---|
31 | if (x1<clip_rect.l || x0>clip_rect.r) return false; |
---|
32 | if (y1<clip_rect.t || y0>clip_rect.b) return false; |
---|
33 | |
---|
34 | if (completely_clipped()) return false; |
---|
35 | |
---|
36 | x0out = clip_in_range(clip_rect.l, x0, clip_rect.r); |
---|
37 | x1out = clip_in_range(clip_rect.l, x1, clip_rect.r); |
---|
38 | y0out = clip_in_range(clip_rect.t, y0, clip_rect.b); |
---|
39 | y1out = clip_in_range(clip_rect.t, y1, clip_rect.b); |
---|
40 | |
---|
41 | return true; |
---|
42 | } |
---|
43 | |
---|
44 | bool AW_clipable::box_clip(const Rectangle& rect, Rectangle& clippedRect) { // @@@ maybe return clippedRect as AW_screen_area |
---|
45 | if (completely_clipped()) return false; |
---|
46 | |
---|
47 | Rectangle clipRect(clip_rect, UPPER_LEFT_OUTLINE); |
---|
48 | if (rect.distinct_from(clipRect)) |
---|
49 | return false; |
---|
50 | |
---|
51 | clippedRect = rect.intersect_with(clipRect); |
---|
52 | return true; |
---|
53 | } |
---|
54 | |
---|
55 | |
---|
56 | bool AW_clipable::clip(AW_pos x0, AW_pos y0, AW_pos x1, AW_pos y1, AW_pos& x0out, AW_pos& y0out, AW_pos& x1out, AW_pos& y1out) { |
---|
57 | // clip coordinates of a line |
---|
58 | |
---|
59 | int outcodeout; |
---|
60 | AW_pos x = 0; |
---|
61 | AW_pos y = 0; |
---|
62 | |
---|
63 | bool is_visible = false; // indicates whether part of line is visible |
---|
64 | bool done = false; // true soon as line is completely inside or outside rectangle |
---|
65 | |
---|
66 | while (!done) { |
---|
67 | int outcode0 = compoutcode(x0, y0); |
---|
68 | int outcode1 = compoutcode(x1, y1); |
---|
69 | |
---|
70 | if ((outcode0 | outcode1) == 0) { // line is inside the rectangle |
---|
71 | x0out = x0; y0out = y0; // clipped coordinates of line |
---|
72 | x1out = x1; y1out = y1; |
---|
73 | |
---|
74 | done = true; |
---|
75 | is_visible = true; |
---|
76 | } |
---|
77 | else if ((outcode0 & outcode1) != 0) { // line is outside the rectangle |
---|
78 | done = true; |
---|
79 | } |
---|
80 | else { // line overlaps with at least one rectangle border |
---|
81 | outcodeout = outcode0>0 ? outcode0 : outcode1; |
---|
82 | |
---|
83 | if ((outcodeout & 8) != 0) { // overlap at top |
---|
84 | x = x0+(x1-x0)*(clip_rect.t-y0)/(y1-y0); |
---|
85 | y = clip_rect.t; |
---|
86 | } |
---|
87 | else if ((outcodeout & 4) != 0) { // overlap at bottom |
---|
88 | x = x0+(x1-x0)*(clip_rect.b-y0)/(y1-y0); |
---|
89 | y = clip_rect.b; |
---|
90 | } |
---|
91 | else if ((outcodeout & 2) != 0) { // overlap at right side |
---|
92 | y = y0+(y1-y0)*(clip_rect.r-x0)/(x1-x0); |
---|
93 | x = clip_rect.r; |
---|
94 | } |
---|
95 | else if ((outcodeout & 1) != 0) { |
---|
96 | y = y0+(y1-y0)*(clip_rect.l-x0)/(x1-x0); // overlap at left side |
---|
97 | x = clip_rect.l; |
---|
98 | } |
---|
99 | |
---|
100 | // set corrected point and iterate : |
---|
101 | if (outcode0 > 0) { |
---|
102 | x0 = x; |
---|
103 | y0 = y; |
---|
104 | } |
---|
105 | else { |
---|
106 | x1 = x; |
---|
107 | y1 = y; |
---|
108 | } |
---|
109 | } |
---|
110 | } |
---|
111 | |
---|
112 | return is_visible; |
---|
113 | } |
---|
114 | |
---|
115 | bool AW_clipable::clip(const LineVector& line, LineVector& clippedLine) { |
---|
116 | AW_pos x0, y0, x1, y1; |
---|
117 | bool drawflag = clip(line.start().xpos(), line.start().ypos(), line.head().xpos(), line.head().ypos(), |
---|
118 | x0, y0, x1, y1); |
---|
119 | if (drawflag) clippedLine = LineVector(x0, y0, x1, y1); |
---|
120 | return drawflag; |
---|
121 | } |
---|
122 | void AW_clipable::set_bottom_clip_border(int bottom, bool allow_oversize) { |
---|
123 | clip_rect.b = bottom; |
---|
124 | if (!allow_oversize) { |
---|
125 | if (clip_rect.b > get_screen().b) clip_rect.b = get_screen().b; |
---|
126 | } |
---|
127 | else { |
---|
128 | set_bottom_font_overlap(true); // added 21.6.02 --ralf |
---|
129 | } |
---|
130 | } |
---|
131 | |
---|
132 | void AW_clipable::set_left_clip_border(int left, bool allow_oversize) { |
---|
133 | clip_rect.l = left; |
---|
134 | if (!allow_oversize) { |
---|
135 | if (clip_rect.l < get_screen().l) clip_rect.l = get_screen().l; |
---|
136 | } |
---|
137 | else { |
---|
138 | set_left_font_overlap(true); // added 21.6.02 --ralf |
---|
139 | } |
---|
140 | } |
---|
141 | |
---|
142 | void AW_clipable::set_right_clip_border(int right, bool allow_oversize) { |
---|
143 | clip_rect.r = right; |
---|
144 | if (!allow_oversize) { |
---|
145 | if (clip_rect.r > get_screen().r) clip_rect.r = get_screen().r; |
---|
146 | } |
---|
147 | else { |
---|
148 | set_right_font_overlap(true); // added to correct problem with last char skipped (added 21.6.02 --ralf) |
---|
149 | } |
---|
150 | } |
---|
151 | |
---|
152 | void AW_clipable::set_top_clip_border(int top, bool allow_oversize) { |
---|
153 | clip_rect.t = top; |
---|
154 | if (!allow_oversize) { |
---|
155 | if (clip_rect.t < get_screen().t) clip_rect.t = get_screen().t; |
---|
156 | } |
---|
157 | else { |
---|
158 | set_top_font_overlap(true); // added 21.6.02 --ralf |
---|
159 | } |
---|
160 | } |
---|
161 | |
---|
162 | |
---|
163 | int AW_clipable::reduceClipBorders(int top, int bottom, int left, int right) { |
---|
164 | // return 0 if no clipping area left |
---|
165 | if (top > clip_rect.t) clip_rect.t = top; |
---|
166 | if (bottom < clip_rect.b) clip_rect.b = bottom; |
---|
167 | if (left > clip_rect.l) clip_rect.l = left; |
---|
168 | if (right < clip_rect.r) clip_rect.r = right; |
---|
169 | |
---|
170 | return !(clip_rect.b<clip_rect.t || clip_rect.r<clip_rect.l); |
---|
171 | } |
---|
172 | |
---|
173 | void AW_clipable::set_cliprect_oversize(const AW_screen_area& rect, bool allow_oversize) { |
---|
174 | clip_rect = rect; |
---|
175 | |
---|
176 | const AW_screen_area& screen = get_screen(); |
---|
177 | if (!allow_oversize) { |
---|
178 | if (clip_rect.t < screen.t) clip_rect.t = screen.t; |
---|
179 | if (clip_rect.b > screen.b) clip_rect.b = screen.b; |
---|
180 | if (clip_rect.l < screen.l) clip_rect.l = screen.l; |
---|
181 | if (clip_rect.r > screen.r) clip_rect.r = screen.r; |
---|
182 | } |
---|
183 | |
---|
184 | set_font_overlap(false); |
---|
185 | |
---|
186 | if (allow_oversize) { // added 21.6.02 --ralf |
---|
187 | if (clip_rect.t < screen.t) set_top_font_overlap(true); |
---|
188 | if (clip_rect.b > screen.b) set_bottom_font_overlap(true); |
---|
189 | if (clip_rect.l < screen.l) set_left_font_overlap(true); |
---|
190 | if (clip_rect.r > screen.r) set_right_font_overlap(true); |
---|
191 | } |
---|
192 | } |
---|
193 | |
---|
194 | void AW_clipable::reduce_top_clip_border(int top) { |
---|
195 | if (top > clip_rect.t) clip_rect.t = top; |
---|
196 | } |
---|
197 | void AW_clipable::reduce_bottom_clip_border(int bottom) { |
---|
198 | if (bottom < clip_rect.b) clip_rect.b = bottom; |
---|
199 | } |
---|
200 | void AW_clipable::reduce_left_clip_border(int left) { |
---|
201 | if (left > clip_rect.l)clip_rect.l = left; |
---|
202 | } |
---|
203 | void AW_clipable::reduce_right_clip_border(int right) { |
---|
204 | if (right < clip_rect.r) clip_rect.r = right; |
---|
205 | } |
---|
206 | |
---|
207 | void AW_clipable::set_bottom_clip_margin(int bottom, bool allow_oversize) { |
---|
208 | clip_rect.b -= bottom; |
---|
209 | if (!allow_oversize) { |
---|
210 | if (clip_rect.b > get_screen().b) clip_rect.b = get_screen().b; |
---|
211 | } |
---|
212 | else { |
---|
213 | set_bottom_font_overlap(true); // added 21.6.02 --ralf |
---|
214 | } |
---|
215 | } |
---|
216 | bool AW_clipable::force_into_clipbox(const Position& pos, Position& forcedPos) { |
---|
217 | // force 'pos' inside 'clip_rect' |
---|
218 | if (completely_clipped()) return false; |
---|
219 | |
---|
220 | forcedPos.setx(clip_in_range(clip_rect.l, pos.xpos(), clip_rect.r)); |
---|
221 | forcedPos.sety(clip_in_range(clip_rect.t, pos.ypos(), clip_rect.b)); |
---|
222 | return true; |
---|
223 | } |
---|
224 | |
---|