| 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 | |
|---|