source: branches/profile/WINDOW/AW_device.cxx

Last change on this file was 10988, checked in by westram, 10 years ago
  • remove unused function 'clear_text' from AW_device + AW_device_Xm (might be unused because overload was broken)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.5 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_msg.h>
16
17#if defined(DEBUG)
18// #define SHOW_CLIP_STACK_CHANGES
19#endif // DEBUG
20
21class AW_clip_scale_stack {
22    // completely private, but accessible by AW_device
23    friend class AW_device;
24
25    AW_screen_area  clip_rect;
26    AW_font_overlap font_overlap;
27
28    AW::Vector offset;
29    AW_pos scale;
30
31    class AW_clip_scale_stack *next;
32};
33
34#if defined(SHOW_CLIP_STACK_CHANGES)
35static const char *clipstatestr(AW_device *device) {
36    static char buffer[1024];
37
38    const AW_screen_area&  clip_rect = device->get_cliprect();
39    const AW_font_overlap& fo        = device->get_font_overlap();
40    const AW::Vector&      offset    = device->get_offset();
41
42    sprintf(buffer,
43            "clip_rect={t=%i, b=%i, l=%i, r=%i} "
44            "font_overlap={t=%i, b=%i, l=%i, r=%i} "
45            "scale=%f unscale=%f "
46            "offset={x=%f y=%f}" ,
47            clip_rect.t, clip_rect.b, clip_rect.l, clip_rect.r,
48            fo.top, fo.bottom, fo.left, fo.right,
49            device->get_scale(), device->get_unscale(), 
50            offset.x(), offset.y());
51
52    return buffer;
53}
54#endif // SHOW_CLIP_STACK_CHANGES
55
56const AW_screen_area& AW_device::get_area_size() const {
57    return get_common()->get_screen();
58}
59
60
61void AW_device::pop_clip_scale() {
62    if (!clip_scale_stack) {
63        aw_assert(0); // Too many pop_clip_scale on that device
64        return;
65    }
66
67#if defined(SHOW_CLIP_STACK_CHANGES)
68    char *state_before_pop = strdup(clipstatestr(this));
69#endif // SHOW_CLIP_STACK_CHANGES
70
71    AW_zoomable::reset();
72    set_offset(clip_scale_stack->offset); // needs to be called before zoom()
73    zoom(clip_scale_stack->scale);
74    set_cliprect(clip_scale_stack->clip_rect);
75    set_font_overlap(clip_scale_stack->font_overlap);
76
77    aw_assert(get_scale() == clip_scale_stack->scale);
78
79    AW_clip_scale_stack *oldstack = clip_scale_stack;
80    clip_scale_stack              = clip_scale_stack->next;
81    delete oldstack;
82
83#if defined(SHOW_CLIP_STACK_CHANGES)
84    printf(" pop_clip_scale: %s\n", state_before_pop);
85    printf("    [after pop]: %s\n\n", clipstatestr(this));
86    free(state_before_pop);
87#endif // SHOW_CLIP_STACK_CHANGES
88}
89
90void AW_device::push_clip_scale() {
91    AW_clip_scale_stack *stack = new AW_clip_scale_stack;
92
93    stack->next      = clip_scale_stack;
94    clip_scale_stack = stack;
95
96    stack->scale        = get_scale();
97    stack->offset       = get_offset();
98    stack->font_overlap = get_font_overlap();
99    stack->clip_rect    = get_cliprect();
100
101#if defined(SHOW_CLIP_STACK_CHANGES)
102    printf("push_clip_scale: %s\n", clipstatestr(this));
103#endif // SHOW_CLIP_STACK_CHANGES
104}
105
106bool AW_device::text_overlay(int gc, const char *opt_str, long opt_len,  // either string or strlen != 0
107                             const AW::Position& pos, AW_pos alignment, AW_bitset filteri, AW_CL cduser,
108                             AW_pos opt_ascent, AW_pos opt_descent,             // optional height (if == 0 take font height)
109                             TextOverlayCallback toc)
110{
111    const AW_GC           *gcm         = get_common()->map_gc(gc);
112    const AW_font_limits&  font_limits = gcm->get_font_limits();
113
114    long   textlen;
115    int    xi;
116    int    h;
117    int    start;
118    int    l;
119    AW_pos X0, Y0;              // Transformed pos
120
121    bool inside_clipping_left  = true; // clipping at the left edge of the screen is different from clipping right of the left edge.
122    bool inside_clipping_right = true;
123
124    // es gibt 4 clipping Moeglichkeiten:
125    // 1. man will fuer den Fall clippen, dass man vom linken display-Rand aus druckt   => clipping rechts vom 1. Buchstaben
126    // 2. man will fuer den Fall clippen, dass man mitten im Bildschirm ist             => clipping links vom 1. Buchstaben
127    // 3. man will fuer den Fall clippen, dass man mitten im Bildschirm ist             => clipping links vom letzten Buchstaben
128    // 4. man will fuer den Fall clippen, dass man bis zum rechten display-Rand druckt  => clipping rechts vom letzten Buchstaben
129
130    if (!(filter & filteri)) return 0;
131
132    const AW_screen_area& screen   = get_common()->get_screen();
133    const AW_screen_area& clipRect = get_cliprect();
134
135    if (allow_left_font_overlap() || screen.l == clipRect.l) inside_clipping_left = false;
136    if (allow_right_font_overlap() || clipRect.r == screen.r) inside_clipping_right = false;
137
138    transform(pos.xpos(), pos.ypos(), X0, Y0);
139
140    if (allow_top_font_overlap() || clipRect.t == 0) {             // check clip border inside screen
141        if (Y0+font_limits.descent < clipRect.t) return 0; // draw outside screen
142    }
143    else {
144        if (Y0-font_limits.ascent < clipRect.t) return 0;  // don't cross the clip border
145    }
146
147    if (allow_bottom_font_overlap() || clipRect.b == screen.b) {   // check clip border inside screen
148        if (Y0-font_limits.ascent > clipRect.b) return 0;  // draw outside screen
149    }
150    else {
151        if (Y0+font_limits.descent> clipRect.b) return 0;  // don't cross the clip border
152    }
153
154    if (!opt_len) {
155        opt_len = textlen = strlen(opt_str);
156    }
157    else {
158        textlen = opt_len;
159    }
160
161    aw_assert(opt_len == textlen);
162
163
164#if defined(DEBUG)
165    int opt_str_len = int(strlen(opt_str));
166    aw_assert(opt_str_len >= textlen);
167#endif
168
169    if (alignment) {
170        AW_pos width = get_string_size(gc, opt_str, textlen);
171        X0 = X0-alignment*width;
172    }
173    xi = AW_INT(X0);
174    if (X0 > clipRect.r) return 0; // right of screen
175
176    l = (int)clipRect.l;
177    if (xi + textlen*font_limits.width < l) return 0; // left of screen
178
179    start = 0;
180
181    // now clip left side
182    if (xi < l) {
183        if (font_limits.is_monospaced()) {
184            h = (l - xi)/font_limits.width;
185            if (inside_clipping_left) {
186                if ((l-xi)%font_limits.width  >0) h += 1;
187            }
188            if (h >= textlen) return 0;
189            start    = h;
190            xi      += h*font_limits.width;
191            textlen -= h;
192
193            if (textlen < 0) return 0;
194            aw_assert(int(strlen(opt_str)) >= textlen);
195        }
196        else { // proportional font
197            int c = 0;
198            for (h=0; xi < l; h++) {
199                if (!(c = opt_str[h])) return 0;
200                xi += gcm->get_width_of_char(c);
201            }
202            if (!inside_clipping_left) {
203                h-=1;
204                xi -= gcm->get_width_of_char(c);
205            }
206            start    = h;
207            textlen -= h;
208
209            if (textlen < 0) return 0;
210            aw_assert(int(strlen(opt_str)) >= textlen);
211        }
212    }
213
214    // now clip right side
215    if (font_limits.is_monospaced()) {
216        h = ((int)clipRect.r - xi) / font_limits.width;
217        if (h < textlen) {
218            if (inside_clipping_right) {
219                textlen = h;
220            }
221            else {
222                textlen = h+1;
223            }
224        }
225
226        if (textlen < 0) return 0;
227        aw_assert(int(strlen(opt_str)) >= textlen);
228    }
229    else { // proportional font
230        l = (int)clipRect.r - xi;
231        for (h = start; l >= 0 && textlen > 0;  h++, textlen--) { // was textlen >= 0
232            l -= gcm->get_width_of_char(opt_str[h]);
233        }
234        textlen = h - start;
235        if (l <= 0 && inside_clipping_right && textlen  > 0) {
236            textlen -= 1;
237        }
238
239        if (textlen < 0) return 0;
240        aw_assert(int(strlen(opt_str)) >= textlen);
241    }
242    X0 = (AW_pos)xi;
243
244    AW_pos corrx, corry;
245    rtransform(X0, Y0, corrx, corry);
246
247    aw_assert(opt_len >= textlen);
248    aw_assert(textlen >= 0 && int(strlen(opt_str)) >= textlen);
249
250    return toc(this, gc, opt_str, opt_len, start, (size_t)textlen, corrx, corry, opt_ascent, opt_descent, cduser);
251}
252
253bool AW_device::generic_filled_area(int gc, int npos, const AW::Position *pos, AW_bitset filteri) {
254    bool drawflag = false;
255    if (filteri & filter) {
256        int p = npos-1;
257        for (int n = 0; n<npos; ++n) {
258            drawflag |= line(gc, pos[p], pos[n], filteri);
259            p = n;
260        }
261    }
262    return drawflag;
263}
264
265void AW_device::move_region(AW_pos /* src_x */, AW_pos /* src_y */, AW_pos /* width */, AW_pos /* height */, 
266                            AW_pos /* dest_x */, AW_pos /* dest_y */) {
267    // empty default
268}
269
270void AW_device::flush() {
271    // empty default
272}
273
274static const AW_screen_area& get_universe() {
275    // "unrestricted" area
276    const int UMIN = INT_MIN/10;
277    const int UMAX = INT_MAX/10;
278    static AW_screen_area universe = { UMIN, UMAX, UMIN, UMAX };
279    return universe;
280}
281
282void AW_device::reset() {
283    while (clip_scale_stack) {
284        pop_clip_scale();
285    }
286    if (type() == AW_DEVICE_SIZE) {
287        set_cliprect(get_universe());
288    }
289    else {
290        set_cliprect(get_area_size());
291    }
292    AW_zoomable::reset();
293    specific_reset();
294}
295
296bool AW_device::generic_invisible(const AW::Position& pos, AW_bitset filteri) {
297    return (filter & filteri) ? !is_outside_clip(transform(pos)) : false;
298}
299
300const AW_screen_area& AW_device::get_common_screen(const AW_common *common_) {
301    return common_->get_screen();
302}
303
304bool AW_device::generic_box(int gc, bool /*filled*/, const AW::Rectangle& rect, AW_bitset filteri) {
305    // Note: 'filled' is not supported on this device
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        realloc_unleaked(gcs, sizeof(*gcs)*new_count);
432        if (!gcs) GBK_terminate("out of memory");
433        memset(&gcs[count], 0, sizeof(*gcs)*(new_count-count));
434        count = new_count;
435    }
436    if (gcs[gi]) delete gcs[gi];
437    gcs[gi] = agc;
438}
439
440int AW_stylable::get_string_size(int gc, const char *str, long textlen) const {
441    return get_common()->map_gc(gc)->get_string_size(str, textlen);
442}
443void AW_stylable::new_gc(int gc) { get_common()->new_gc(gc); }
444void AW_stylable::set_grey_level(int gc, AW_grey_level grey_level) {
445    // <0 = don't fill, 0.0 = white, 1.0 = black
446    get_common()->map_mod_gc(gc)->set_grey_level(grey_level);
447}
448void AW_stylable::set_font(int gc, AW_font font_nr, int size, int *found_size) {
449    // if found_size != 0 -> return value for used font size
450    get_common()->map_mod_gc(gc)->set_font(font_nr, size, found_size);
451}
452int AW_stylable::get_available_fontsizes(int gc, AW_font font_nr, int *available_sizes) {
453    return get_common()->map_gc(gc)->get_available_fontsizes(font_nr, available_sizes);
454}
455void AW_stylable::set_line_attributes(int gc, short width, AW_linestyle style) {
456    get_common()->map_mod_gc(gc)->set_line_attributes(width, style);
457}
458void AW_stylable::set_function(int gc, AW_function function) {
459    get_common()->map_mod_gc(gc)->set_function(function);
460}
461void AW_stylable::set_foreground_color(int gc, AW_color_idx color) {
462    get_common()->map_mod_gc(gc)->set_fg_color(get_common()->get_color(color));
463}
464void AW_stylable::establish_default(int gc) {
465    get_common()->map_mod_gc(gc)->establish_default();
466}
467void AW_stylable::reset_style() {
468    get_common()->reset_style();
469}
470
471static void AW_get_common_extends_cb(AW_window *, AW_common_Xm *common) {
472    Window        root;
473    unsigned int  width, height;
474    unsigned int  depth, borderwidth; // unused
475    int           x_offset, y_offset; // unused
476
477    XGetGeometry(common->get_display(), common->get_window_id(),
478                 &root,
479                 &x_offset,
480                 &y_offset,
481                 &width,
482                 &height,
483                 &borderwidth,  // border width
484                 &depth);       // depth of display
485
486    common->set_screen_size(width, height);
487}
488
489void AW_common_Xm::install_common_extends_cb(AW_window *aww, AW_area area) {
490    aww->set_resize_callback(area, makeWindowCallback(AW_get_common_extends_cb, this));
491    AW_get_common_extends_cb(aww, this);
492}
493
Note: See TracBrowser for help on using the repository browser.