]> git.decadent.org.uk Git - ion3.git/blob - de/brush.c
90a57a9b69e9c96ec32fea35a5caf3513d81579f
[ion3.git] / de / brush.c
1 /*
2  * ion/de/brush.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2008. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <string.h>
10
11 #include <libtu/objp.h>
12 #include <libextl/extl.h>
13
14 #include <ioncore/common.h>
15 #include <ioncore/rootwin.h>
16 #include <ioncore/extlconv.h>
17 #include <ioncore/ioncore.h>
18
19 #include "brush.h"
20 #include "style.h"
21 #include "font.h"
22 #include "colour.h"
23 #include "private.h"
24
25
26 /*{{{ Brush creation and releasing */
27
28
29 #define MATCHES(S, A) (gr_stylespec_score(&(S), A)>0)
30 #define MATCHES2(S, A1, A2) (gr_stylespec_score2(&(S), A1, A2)>0)
31
32 #define ENSURE_INITSPEC(S, NM) \
33     if((S).attrs==NULL) gr_stylespec_load(&(S), NM);
34
35
36 static GrStyleSpec tabframe_spec=GR_STYLESPEC_INIT;
37 static GrStyleSpec tabinfo_spec=GR_STYLESPEC_INIT;
38 static GrStyleSpec tabmenuentry_spec=GR_STYLESPEC_INIT;
39
40
41 bool debrush_init(DEBrush *brush, Window win,
42                   const GrStyleSpec *spec, DEStyle *style)
43 {
44     GrStyleSpec tmp;
45     
46     brush->d=style;
47     brush->extras_fn=NULL;
48     brush->indicator_w=0;
49     brush->win=win;
50     brush->clip_set=FALSE;
51     
52     gr_stylespec_init(&brush->current_attr);
53     
54     style->usecount++;
55
56     if(!grbrush_init(&(brush->grbrush))){
57         style->usecount--;
58         return FALSE;
59     }
60     
61     ENSURE_INITSPEC(tabframe_spec, "tab-frame");
62     ENSURE_INITSPEC(tabinfo_spec, "tab-info");
63     ENSURE_INITSPEC(tabmenuentry_spec, "tab-menuentry");
64     
65     if(MATCHES(tabframe_spec, spec) || MATCHES(tabinfo_spec, spec)){
66         brush->extras_fn=debrush_tab_extras;
67         if(!style->tabbrush_data_ok)
68             destyle_create_tab_gcs(style);
69     }else if(MATCHES(tabmenuentry_spec, spec)){
70         brush->extras_fn=debrush_menuentry_extras;
71         brush->indicator_w=grbrush_get_text_width((GrBrush*)brush, 
72                                                   DE_SUB_IND, 
73                                                   DE_SUB_IND_LEN);
74     }
75     
76     return TRUE;
77 }
78
79
80 DEBrush *create_debrush(Window win, const GrStyleSpec *spec, DEStyle *style)
81 {
82     CREATEOBJ_IMPL(DEBrush, debrush, (p, win, spec, style));
83 }
84
85
86 static DEBrush *do_get_brush(Window win, WRootWin *rootwin, 
87                              const char *stylename, bool slave)
88 {
89     DEStyle *style;
90     DEBrush *brush;
91     GrStyleSpec spec;
92     
93     if(!gr_stylespec_load(&spec, stylename))
94         return NULL;
95     
96     style=de_get_style(rootwin, &spec);
97     
98     if(style==NULL){
99         gr_stylespec_unalloc(&spec);
100         return NULL;
101     }
102     
103     brush=create_debrush(win, &spec, style);
104
105     gr_stylespec_unalloc(&spec);
106     
107     /* Set background colour */
108     if(brush!=NULL && !slave){
109         grbrush_enable_transparency(&(brush->grbrush), 
110                                     GR_TRANSPARENCY_DEFAULT);
111     }
112     
113     return brush;
114 }
115
116
117 DEBrush *de_get_brush(Window win, WRootWin *rootwin, const char *stylename)
118 {
119     return do_get_brush(win, rootwin, stylename, FALSE);
120 }
121
122
123 DEBrush *debrush_get_slave(DEBrush *master, WRootWin *rootwin, 
124                            const char *stylename)
125 {
126     return do_get_brush(master->win, rootwin, stylename, TRUE);
127 }
128
129
130 void debrush_deinit(DEBrush *brush)
131 {
132     destyle_unref(brush->d);
133     brush->d=NULL;
134     gr_stylespec_unalloc(&brush->current_attr);
135     grbrush_deinit(&(brush->grbrush));
136 }
137
138
139 void debrush_release(DEBrush *brush)
140 {
141     destroy_obj((Obj*)brush);
142 }
143
144
145 /*}}}*/
146
147
148 /*{{{ Attributes */
149
150
151 void debrush_init_attr(DEBrush *brush, const GrStyleSpec *spec)
152 {
153     gr_stylespec_unalloc(&brush->current_attr);
154
155     if(spec!=NULL)
156         gr_stylespec_append(&brush->current_attr, spec);
157 }
158
159     
160 void debrush_set_attr(DEBrush *brush, GrAttr attr)
161 {
162     gr_stylespec_set(&brush->current_attr, attr);
163 }
164
165
166 void debrush_unset_attr(DEBrush *brush, GrAttr attr)
167 {
168     gr_stylespec_unset(&brush->current_attr, attr);
169 }
170
171
172 GrStyleSpec *debrush_get_current_attr(DEBrush *brush)
173 {
174     return &brush->current_attr;
175 }
176
177
178 /*}}}*/
179
180
181
182 /*{{{ Border widths and extra information */
183
184
185 void debrush_get_border_widths(DEBrush *brush, GrBorderWidths *bdw)
186 {
187     DEStyle *style=brush->d;
188     DEBorder *bd=&(style->border);
189     uint tmp=0;
190     uint tbf=1, lrf=1;
191     uint pad=bd->pad;
192     uint spc=style->spacing;
193     
194     switch(bd->sides){
195     case DEBORDER_TB:
196         lrf=0;
197         break;
198     case DEBORDER_LR:
199         tbf=0;
200         break;
201     }
202     
203     /* Ridge/groove styles use 'padding' for the spacing between the
204      * 'highlight' and 'shadow' portions of the border, and 'spacing'
205      * between the border and contents. Inlaid style also uses 'spacing'
206      * between the contents and the border, and padding as its outer
207      * component. Elevated style does not use spacing.
208      */
209     switch(bd->style){
210     case DEBORDER_RIDGE:
211     case DEBORDER_GROOVE:
212         tmp=bd->sh+bd->hl+pad;
213         bdw->top=tbf*tmp+spc; bdw->bottom=tbf*tmp+spc; 
214         bdw->left=lrf*tmp+spc; bdw->right=lrf*tmp+spc;
215         break;
216     case DEBORDER_INLAID:
217         tmp=bd->sh+pad; bdw->top=tbf*tmp+spc; bdw->left=lrf*tmp+spc;
218         tmp=bd->hl+pad; bdw->bottom=tbf*tmp+spc; bdw->right=lrf*tmp+spc;
219         break;
220     case DEBORDER_ELEVATED:
221     default:
222         tmp=bd->hl; bdw->top=tbf*tmp+pad; bdw->left=lrf*tmp+pad;
223         tmp=bd->sh; bdw->bottom=tbf*tmp+pad; bdw->right=lrf*tmp+pad;
224         break;
225     }
226     
227     bdw->right+=brush->indicator_w;
228
229     bdw->tb_ileft=bdw->left;
230     bdw->tb_iright=bdw->right;
231     bdw->spacing=style->spacing;
232 }
233
234
235 bool debrush_get_extra(DEBrush *brush, const char *key, char type, void *data)
236 {
237     DEStyle *style=brush->d;
238     while(style!=NULL){
239         if(extl_table_get(style->extras_table, 's', type, key, data))
240             return TRUE;
241         style=style->based_on;
242     }
243     return FALSE;
244 }
245
246
247
248 /*}}}*/
249
250
251 /*{{{ Class implementation */
252
253
254 static DynFunTab debrush_dynfuntab[]={
255     {grbrush_release, debrush_release},
256     {grbrush_draw_border, debrush_draw_border},
257     {grbrush_draw_borderline, debrush_draw_borderline},
258     {grbrush_get_border_widths, debrush_get_border_widths},
259     {grbrush_draw_string, debrush_draw_string},
260     {debrush_do_draw_string, debrush_do_draw_string_default},
261     {grbrush_get_font_extents, debrush_get_font_extents},
262     {(DynFun*)grbrush_get_text_width, (DynFun*)debrush_get_text_width},
263     {grbrush_draw_textbox, debrush_draw_textbox},
264     {grbrush_draw_textboxes, debrush_draw_textboxes},
265     {grbrush_set_window_shape, debrush_set_window_shape},
266     {grbrush_enable_transparency, debrush_enable_transparency},
267     {grbrush_clear_area, debrush_clear_area},
268     {grbrush_fill_area, debrush_fill_area},
269     {(DynFun*)grbrush_get_extra, (DynFun*)debrush_get_extra},
270     {(DynFun*)grbrush_get_slave, (DynFun*)debrush_get_slave},
271     {grbrush_begin, debrush_begin},
272     {grbrush_end, debrush_end},
273     {grbrush_init_attr, debrush_init_attr},
274     {grbrush_set_attr, debrush_set_attr},
275     {grbrush_unset_attr, debrush_unset_attr},
276     END_DYNFUNTAB
277 };
278
279
280 IMPLCLASS(DEBrush, GrBrush, debrush_deinit, debrush_dynfuntab);
281
282
283 /*}}}*/
284
285
286