source: tags/ms_r16q3/WINDOW/AW_device.cxx

Last change on this file was 15251, checked in by westram, 8 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.4 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : AW_device.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_mem.h>
16#include <arb_msg.h>
17
18#if defined(DEBUG)
19// #define SHOW_CLIP_STACK_CHANGES
20#endif // DEBUG
21
22class AW_clip_scale_stack {
23    // completely private, but accessible by AW_device
24    friend class AW_device;
25
26    AW_screen_area  clip_rect;
27    AW_font_overlap font_overlap;
28
29    AW::Vector offset;
30    AW_pos scale;
31
32    class AW_clip_scale_stack *next;
33};
34
35#if defined(SHOW_CLIP_STACK_CHANGES)
36static const char *clipstatestr(AW_device *device) {
37    static char buffer[1024];
38
39    const AW_screen_area&  clip_rect = device->get_cliprect();
40    const AW_font_overlap& fo        = device->get_font_overlap();
41    const AW::Vector&      offset    = device->get_offset();
42
43    sprintf(buffer,
44            "clip_rect={t=%i, b=%i, l=%i, r=%i} "
45            "font_overlap={t=%i, b=%i, l=%i, r=%i} "
46            "scale=%f unscale=%f "
47            "offset={x=%f y=%f}" ,
48            clip_rect.t, clip_rect.b, clip_rect.l, clip_rect.r,
49            fo.top, fo.bottom, fo.left, fo.right,
50            device->get_scale(), device->get_unscale(),
51            offset.x(), offset.y());
52
53    return buffer;
54}
55#endif // SHOW_CLIP_STACK_CHANGES
56
57const AW_screen_area& AW_device::get_area_size() const {
58    return get_common()->get_screen();
59}
60
61
62void AW_device::pop_clip_scale() {
63    if (!clip_scale_stack) {
64        aw_assert(0); // Too many pop_clip_scale on that device
65        return;
66    }
67
68#if defined(SHOW_CLIP_STACK_CHANGES)
69    char *state_before_pop = strdup(clipstatestr(this));
70#endif // SHOW_CLIP_STACK_CHANGES
71
72    AW_zoomable::reset();
73    set_offset(clip_scale_stack->offset); // needs to be called before zoom()
74    zoom(clip_scale_stack->scale);
75    set_cliprect(clip_scale_stack->clip_rect);
76    set_font_overlap(clip_scale_stack->font_overlap);
77
78    aw_assert(get_scale() == clip_scale_stack->scale);
79
80    AW_clip_scale_stack *oldstack = clip_scale_stack;
81    clip_scale_stack              = clip_scale_stack->next;
82    delete oldstack;
83
84#if defined(SHOW_CLIP_STACK_CHANGES)
85    printf(" pop_clip_scale: %s\n", state_before_pop);
86    printf("    [after pop]: %s\n\n", clipstatestr(this));
87    free(state_before_pop);
88#endif // SHOW_CLIP_STACK_CHANGES
89}
90
91void AW_device::push_clip_scale() {
92    AW_clip_scale_stack *stack = new AW_clip_scale_stack;
93
94    stack->next      = clip_scale_stack;
95    clip_scale_stack = stack;
96
97    stack->scale        = get_scale();
98    stack->offset       = get_offset();
99    stack->font_overlap = get_font_overlap();
100    stack->clip_rect    = get_cliprect();
101
102#if defined(SHOW_CLIP_STACK_CHANGES)
103    printf("push_clip_scale: %s\n", clipstatestr(this));
104#endif // SHOW_CLIP_STACK_CHANGES
105}
106
107bool AW_device::text_overlay(int gc, const char *opt_str, long opt_len,  // either string or strlen != 0
108                             const AW::Position& pos, AW_pos alignment, AW_bitset filteri, AW_CL cduser,
109                             AW_pos opt_ascent, AW_pos opt_descent,             // optional height (if == 0 take font height)
110                             TextOverlayCallback toc)
111{
112    const AW_GC           *gcm  = get_common()->map_gc(gc);
113    const AW_font_limits&  font = gcm->get_font_limits();
114
115    long   textlen;
116    int    xi;
117    int    h;
118    int    start;
119    int    l;
120    AW_pos X0, Y0;              // Transformed pos
121
122    bool inside_clipping_left  = true; // clipping at the left edge of the screen is different from clipping right of the left edge.
123    bool inside_clipping_right = true;
124
125    // es gibt 4 clipping Moeglichkeiten:
126    // 1. man will fuer den Fall clippen, dass man vom linken display-Rand aus druckt   => clipping rechts vom 1. Buchstaben
127    // 2. man will fuer den Fall clippen, dass man mitten im Bildschirm ist             => clipping links vom 1. Buchstaben
128    // 3. man will fuer den Fall clippen, dass man mitten im Bildschirm ist             => clipping links vom letzten Buchstaben
129    // 4. man will fuer den Fall clippen, dass man bis zum rechten display-Rand druckt  => clipping rechts vom letzten Buchstaben
130
131    if (!(filter & filteri)) return 0;
132
133    const AW_screen_area& screen   = get_common()->get_screen();
134    const AW_screen_area& clipRect = get_cliprect();
135
136    if (allow_left_font_overlap() || screen.l == clipRect.l) inside_clipping_left = false;
137    if (allow_right_font_overlap() || clipRect.r == screen.r) inside_clipping_right = false;
138
139    transform(pos.xpos(), pos.ypos(), X0, Y0);
140
141    if (allow_top_font_overlap() || clipRect.t == 0) {             // check clip border inside screen
142        if (Y0+font.descent < clipRect.t) return 0; // draw outside screen
143    }
144    else {
145        if (Y0-font.ascent < clipRect.t) return 0;  // don't cross the clip border
146    }
147
148    if (allow_bottom_font_overlap() || clipRect.b == screen.b) {   // check clip border inside screen
149        if (Y0-font.ascent > clipRect.b) return 0;  // draw outside screen
150    }
151    else {
152        if (Y0+font.descent> clipRect.b) return 0;  // don't cross the clip border
153    }
154
155    if (!opt_len) {
156        opt_len = textlen = strlen(opt_str);
157    }
158    else {
159        textlen = opt_len;
160    }
161
162    aw_assert(opt_len == textlen);
163
164
165#if defined(DEBUG)
166    int opt_str_len = int(strlen(opt_str));
167    aw_assert(opt_str_len >= textlen);
168#endif
169
170    if (alignment) {
171        AW_pos width = get_string_size(gc, opt_str, textlen);
172        X0 = X0-alignment*width;
173    }
174    xi = AW_INT(X0);
175    if (X0 > clipRect.r) return 0; // right of screen
176
177    l = (int)clipRect.l;
178    if (xi + textlen*font.width < l) return 0; // left of screen
179
180    start = 0;
181
182    // now clip left side
183    if (xi < l) {
184        if (font.is_monospaced()) {
185            h = (l - xi)/font.width;
186            if (inside_clipping_left) {
187                if ((l-xi)%font.width  >0) h += 1;
188            }
189            if (h >= textlen) return 0;
190            start    = h;
191            xi      += h*font.width;
192            textlen -= h;
193
194            if (textlen < 0) return 0;
195            aw_assert(int(strlen(opt_str)) >= textlen);
196        }
197        else { // proportional font
198            int c = 0;
199            for (h=0; xi < l; h++) {
200                if (!(c = opt_str[h])) return 0;
201                xi += gcm->get_width_of_char(c);
202            }
203            if (!inside_clipping_left) {
204                h-=1;
205                xi -= gcm->get_width_of_char(c);
206            }
207            start    = h;
208            textlen -= h;
209
210            if (textlen < 0) return 0;
211            aw_assert(int(strlen(opt_str)) >= textlen);
212        }
213    }
214
215    // now clip right side
216    if (font.is_monospaced()) {
217        h = ((int)clipRect.r - xi) / font.width;
218        if (h < textlen) {
219            if (inside_clipping_right) {
220                textlen = h;
221            }
222            else {
223                textlen = h+1;
224            }
225        }
226
227        if (textlen < 0) return 0;
228        aw_assert(int(strlen(opt_str)) >= textlen);
229    }
230    else { // proportional font
231        l = (int)clipRect.r - xi;
232        for (h = start; l >= 0 && textlen > 0;  h++, textlen--) { // was textlen >= 0
233            l -= gcm->get_width_of_char(opt_str[h]);
234        }
235        textlen = h - start;
236        if (l <= 0 && inside_clipping_right && textlen  > 0) {
237            textlen -= 1;
238        }
239
240        if (textlen < 0) return 0;
241        aw_assert(int(strlen(opt_str)) >= textlen);
242    }
243    X0 = (AW_pos)xi;
244
245    AW_pos corrx, corry;
246    rtransform(X0, Y0, corrx, corry);
247
248    aw_assert(opt_len >= textlen);
249    aw_assert(textlen >= 0 && int(strlen(opt_str)) >= textlen);
250
251    return toc(this, gc, opt_str, opt_len, start, (size_t)textlen, corrx, corry, opt_ascent, opt_descent, cduser);
252}
253
254bool AW_device::generic_polygon(int gc, int npos, const AW::Position *pos, AW_bitset filteri) {
255    bool drawflag = false;
256    if (filteri & filter) {
257        int p = npos-1;
258        for (int n = 0; n<npos; ++n) {
259            drawflag |= line(gc, pos[p], pos[n], filteri);
260            p = n;
261        }
262    }
263    return drawflag;
264}
265
266void AW_device::move_region(AW_pos /* src_x */, AW_pos /* src_y */, AW_pos /* width */, AW_pos /* height */,
267                            AW_pos /* dest_x */, AW_pos /* dest_y */) {
268    // empty default
269}
270
271void AW_device::flush() {
272    // empty default
273}
274
275static const AW_screen_area& get_universe() {
276    // "unrestricted" area
277    const int UMIN = INT_MIN/10;
278    const int UMAX = INT_MAX/10;
279    static AW_screen_area universe = { UMIN, UMAX, UMIN, UMAX };
280    return universe;
281}
282
283void AW_device::reset() {
284    while (clip_scale_stack) {
285        pop_clip_scale();
286    }
287    if (type() == AW_DEVICE_SIZE) {
288        set_cliprect(get_universe());
289    }
290    else {
291        set_cliprect(get_area_size());
292    }
293    AW_zoomable::reset();
294    specific_reset();
295}
296
297bool AW_device::generic_invisible(const AW::Position& pos, AW_bitset filteri) {
298    return (filter & filteri) ? !is_outside_clip(transform(pos)) : false;
299}
300
301const AW_screen_area& AW_device::get_common_screen(const AW_common *common_) {
302    return common_->get_screen();
303}
304
305bool AW_device::generic_box(int gc, const AW::Rectangle& rect, AW_bitset filteri) {
306    int drawflag = 0;
307    if (filteri & filter) {
308        drawflag |= line_impl(gc, rect.upper_edge(), filteri);
309        drawflag |= line_impl(gc, rect.lower_edge(), filteri);
310        drawflag |= line_impl(gc, rect.left_edge(),  filteri);
311        drawflag |= line_impl(gc, rect.right_edge(), filteri);
312    }
313    return drawflag;
314}
315
316void AW_device::clear(AW_bitset) {
317    // nothing to do
318}
319
320void AW_device::clear_part(const AW::Rectangle&, AW_bitset) {
321    // nothing to do
322}
323
324void AW_device::set_filter(AW_bitset filteri) {
325    filter = filteri;
326}
327
328void AW_device::fast() {}
329void AW_device::slow() {}
330bool AW_device::ready_to_draw(int gc) {
331    return get_common()->gc_mapable(gc);
332}
333
334void AW_zoomable::reset() {
335    unscale = scale   = 1.0;
336    offset  = AW::Vector(0, 0);
337}
338
339void AW_zoomable::zoom(AW_pos val) {
340    scale   *= val;
341    unscale  = 1.0/scale;
342}
343
344// -----------------
345//      AW_GC_Xm
346
347const int GC_DEFAULT_LINE_STYLE = LineSolid;
348const int GC_DEFAULT_CAP_STYLE  = CapProjecting;
349const int GC_JOIN_STYLE         = JoinMiter;
350
351AW_GC_Xm::AW_GC_Xm(AW_common *common_)
352    : AW_GC(common_)
353{
354    XGCValues val;
355
356    val.line_width = GC_DEFAULT_LINE_WIDTH;
357    val.line_style = GC_DEFAULT_LINE_STYLE;
358    val.cap_style  = GC_DEFAULT_CAP_STYLE;
359    val.join_style = GC_JOIN_STYLE;
360
361    unsigned long value_mask = GCLineWidth|GCLineStyle|GCCapStyle|GCJoinStyle;
362
363    gc = XCreateGC(get_common()->get_display(), get_common()->get_window_id(), value_mask, &val);
364    wm_set_function(get_function());
365}
366AW_GC_Xm::~AW_GC_Xm() {
367    if (gc) XFreeGC(get_common()->get_display(), gc);
368}
369void AW_GC_Xm::wm_set_lineattributes(short lwidth, AW_linestyle lstyle) {
370    Display            *display = get_common()->get_display();
371    aw_assert(lwidth>0);
372
373    switch (lstyle) {
374        case AW_SOLID:
375            XSetLineAttributes(display, gc, lwidth, LineSolid, GC_DEFAULT_CAP_STYLE, GC_JOIN_STYLE);
376            break;
377
378        case AW_DOTTED:
379        case AW_DASHED: {
380            static char dashes[] = { 5, 2 };
381            static char dots[]   = { 1, 1 };
382            XSetDashes(display, gc, 0, lstyle == AW_DOTTED ? dots : dashes, 2);
383            XSetLineAttributes(display, gc, lwidth, LineOnOffDash, CapButt, GC_JOIN_STYLE);
384            break;
385        }
386    }
387}
388void AW_GC_Xm::wm_set_function(AW_function mode) {
389    switch (mode) {
390        case AW_XOR:
391            XSetFunction(get_common()->get_display(), gc, GXxor);
392            break;
393        case AW_COPY:
394            XSetFunction(get_common()->get_display(), gc, GXcopy);
395            break;
396    }
397}
398void AW_GC_Xm::wm_set_foreground_color(AW_rgb col) {
399    XSetForeground(get_common()->get_display(), gc, col);
400}
401
402const AW_font_limits& AW_stylable::get_font_limits(int gc, char c) const {
403    return get_common()->get_font_limits(gc, c);
404}
405
406int AW_GC::get_string_size(const char *str, long textlen) const {
407    // calculate display size of 'str'
408    // 'str' and/or 'textlen' may be 0
409    // 'str'     == 0 -> calculate max width of any text with length 'textlen'
410    // 'textlen' == 0 -> calls strlen when needed
411    // both 0 -> return 0
412
413    int width = 0;
414    if (font_limits.is_monospaced() || !str) {
415        if (!textlen && str) textlen = strlen(str);
416        width = textlen * font_limits.width;
417    }
418    else {
419        for (int c = *(str++); c; c = *(str++)) width += width_of_chars[c];
420    }
421    return width;
422}
423
424AW_GC *AW_common_Xm::create_gc() {
425    return new AW_GC_Xm(this);
426}
427
428void AW_GC_set::add_gc(int gi, AW_GC *agc) {
429    if (gi >= count) {
430        int new_count = gi+10;
431        ARB_recalloc(gcs, count, new_count);
432        count = new_count;
433    }
434    if (gcs[gi]) delete gcs[gi];
435    gcs[gi] = agc;
436}
437
438int AW_stylable::get_string_size(int gc, const char *str, long textlen) const {
439    return get_common()->map_gc(gc)->get_string_size(str, textlen);
440}
441void AW_stylable::new_gc(int gc) { get_common()->new_gc(gc); }
442void AW_stylable::set_grey_level(int gc, AW_grey_level grey_level) {
443    // <0 = don't fill, 0.0 = white, 1.0 = black
444    get_common()->map_mod_gc(gc)->set_grey_level(grey_level);
445}
446AW_grey_level AW_stylable::get_grey_level(int gc) {
447    return get_common()->map_gc(gc)->get_grey_level();
448}
449
450void AW_stylable::set_font(int gc, AW_font font_nr, int size, int *found_size) {
451    // if found_size != 0 -> return value for used font size
452    get_common()->map_mod_gc(gc)->set_font(font_nr, size, found_size);
453}
454int AW_stylable::get_available_fontsizes(int gc, AW_font font_nr, int *available_sizes) {
455    return get_common()->map_gc(gc)->get_available_fontsizes(font_nr, available_sizes);
456}
457void AW_stylable::set_line_attributes(int gc, short width, AW_linestyle style) {
458    get_common()->map_mod_gc(gc)->set_line_attributes(width, style);
459}
460void AW_stylable::set_function(int gc, AW_function function) {
461    get_common()->map_mod_gc(gc)->set_function(function);
462}
463void AW_stylable::set_foreground_color(int gc, AW_color_idx color) {
464    get_common()->map_mod_gc(gc)->set_fg_color(get_common()->get_color(color));
465}
466void AW_stylable::establish_default(int gc) {
467    get_common()->map_mod_gc(gc)->establish_default();
468}
469void AW_stylable::reset_style() {
470    get_common()->reset_style();
471}
472
473static void AW_get_common_extends_cb(AW_window *, AW_common_Xm *common) {
474    Window        root;
475    unsigned int  width, height;
476    unsigned int  depth, borderwidth; // unused
477    int           x_offset, y_offset; // unused
478
479    XGetGeometry(common->get_display(), common->get_window_id(),
480                 &root,
481                 &x_offset,
482                 &y_offset,
483                 &width,
484                 &height,
485                 &borderwidth,  // border width
486                 &depth);       // depth of display
487
488    common->set_screen_size(width, height);
489}
490
491void AW_common_Xm::install_common_extends_cb(AW_window *aww, AW_area area) {
492    aww->set_resize_callback(area, makeWindowCallback(AW_get_common_extends_cb, this));
493    AW_get_common_extends_cb(aww, this);
494}
495
Note: See TracBrowser for help on using the repository browser.