Line data Source code
1 : /* Copyright (C) 2000-2012 by George Williams */
2 : /*
3 : * Redistribution and use in source and binary forms, with or without
4 : * modification, are permitted provided that the following conditions are met:
5 :
6 : * Redistributions of source code must retain the above copyright notice, this
7 : * list of conditions and the following disclaimer.
8 :
9 : * Redistributions in binary form must reproduce the above copyright notice,
10 : * this list of conditions and the following disclaimer in the documentation
11 : * and/or other materials provided with the distribution.
12 :
13 : * The name of the author may not be used to endorse or promote products
14 : * derived from this software without specific prior written permission.
15 :
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : */
27 : #include "gdraw.h"
28 : #include "gresource.h"
29 : #include "ggadgetP.h"
30 : #include "gwidget.h"
31 : #include "ustring.h"
32 : #include "gkeysym.h"
33 :
34 : static GBox gtabset_box = GBOX_EMPTY; /* Don't initialize here */
35 : static GBox gvtabset_box = GBOX_EMPTY; /* Don't initialize here */
36 : static FontInstance *gtabset_font = NULL;
37 : static int gtabset_inited = false;
38 :
39 : static GResInfo gtabset_ri, gvtabset_ri;
40 :
41 : static GResInfo gtabset_ri = {
42 : &gvtabset_ri, &ggadget_ri, &gvtabset_ri, NULL,
43 : >abset_box,
44 : NULL,
45 : NULL,
46 : NULL,
47 : N_("TabSet"),
48 : N_("Tab Set"),
49 : "GTabSet",
50 : "Gdraw",
51 : false,
52 : omf_border_width|omf_border_shape,
53 : NULL,
54 : GBOX_EMPTY,
55 : NULL,
56 : NULL,
57 : NULL
58 : };
59 :
60 : /* Dummy gadget for styling vertical layout */
61 : static GResInfo gvtabset_ri = {
62 : NULL, >abset_ri, >abset_ri, NULL,
63 : &gvtabset_box,
64 : NULL,
65 : NULL,
66 : NULL,
67 : N_("VerticalTabSet"),
68 : N_("Vertical Tab Set"),
69 : "GVTabSet",
70 : "Gdraw",
71 : false,
72 : 0,
73 : NULL,
74 : GBOX_EMPTY,
75 : NULL,
76 : NULL,
77 : NULL
78 : };
79 : #define NEST_INDENT 4
80 :
81 0 : static void GTabSetInit() {
82 :
83 0 : if ( gtabset_inited )
84 0 : return;
85 :
86 0 : GGadgetInit();
87 :
88 0 : _GGadgetCopyDefaultBox(>abset_box);
89 0 : gtabset_box.border_width = 1; gtabset_box.border_shape = bs_rect;
90 : /*gtabset_box.flags = 0;*/
91 0 : gtabset_font = _GGadgetInitDefaultBox("GTabSet.",>abset_box,NULL);
92 :
93 0 : gvtabset_box = gtabset_box; /* needs this to figure inheritance */
94 0 : _GGadgetInitDefaultBox("GVTabSet.",&gvtabset_box,NULL);
95 :
96 0 : gtabset_inited = true;
97 : }
98 :
99 0 : static void GTabSetChanged(GTabSet *gts,int oldsel) {
100 : GEvent e;
101 :
102 0 : e.type = et_controlevent;
103 0 : e.w = gts->g.base;
104 0 : e.u.control.subtype = et_radiochanged;
105 0 : e.u.control.g = >s->g;
106 0 : if ( gts->g.handle_controlevent != NULL )
107 0 : (gts->g.handle_controlevent)(>s->g,&e);
108 : else
109 0 : GDrawPostEvent(&e);
110 0 : }
111 :
112 0 : static int DrawLeftArrowTab(GWindow pixmap, GTabSet *gts, int x, int y ) {
113 0 : Color fg = gts->g.box->main_foreground;
114 : GPoint pts[5];
115 0 : int retx = x + gts->arrow_width, cnt;
116 :
117 0 : if ( fg==COLOR_DEFAULT ) fg = GDrawGetDefaultForeground(GDrawGetDisplayOfWindow(pixmap));
118 0 : GBoxDrawTabOutline(pixmap,>s->g,x,y,gts->arrow_width,gts->rowh,false);
119 0 : gts->haslarrow = true;
120 0 : y += (gts->rowh-gts->arrow_size)/2;
121 0 : x += (gts->arrow_width-gts->arrow_size/2)/2;
122 0 : cnt = 4;
123 0 : pts[0].y = (y+(gts->arrow_size-1)/2); pts[0].x = x;
124 0 : pts[1].y = y; pts[1].x = x + (gts->arrow_size-1)/2;
125 0 : pts[2].y = y+gts->arrow_size-1; pts[2].x = pts[1].x;
126 0 : pts[3] = pts[0];
127 0 : if ( !(gts->arrow_size&1 )) {
128 0 : ++pts[3].y;
129 0 : pts[4] = pts[0];
130 0 : cnt = 5;
131 : }
132 0 : GDrawFillPoly(pixmap,pts,cnt,fg);
133 0 : return( retx );
134 : }
135 :
136 0 : static int DrawRightArrowTab(GWindow pixmap, GTabSet *gts, int x, int y ) {
137 0 : Color fg = gts->g.box->main_foreground;
138 : GPoint pts[5];
139 0 : int retx = x + gts->arrow_width, cnt;
140 :
141 0 : if ( fg==COLOR_DEFAULT ) fg = GDrawGetDefaultForeground(GDrawGetDisplayOfWindow(pixmap));
142 0 : GBoxDrawTabOutline(pixmap,>s->g,x,y,gts->arrow_width,gts->rowh,false);
143 0 : gts->hasrarrow = true;
144 0 : y += (gts->rowh-gts->arrow_size)/2;
145 0 : x += (gts->arrow_width-gts->arrow_size/2)/2;
146 0 : cnt = 4;
147 0 : pts[0].y = (y+(gts->arrow_size-1)/2); pts[0].x = x + (gts->arrow_size-1)/2;
148 0 : pts[1].y = y; pts[1].x = x;
149 0 : pts[2].y = y+gts->arrow_size-1; pts[2].x = pts[1].x;
150 0 : pts[3] = pts[0];
151 0 : if ( !(gts->arrow_size&1 )) {
152 0 : ++pts[3].y;
153 0 : pts[4] = pts[0];
154 0 : cnt = 5;
155 : }
156 0 : GDrawFillPoly(pixmap,pts,cnt,fg);
157 0 : return( retx );
158 : }
159 :
160 0 : static int DrawTab(GWindow pixmap, GTabSet *gts, int i, int x, int y ) {
161 0 : Color fg = gts->tabs[i].disabled?gts->g.box->disabled_foreground:gts->g.box->main_foreground;
162 :
163 0 : if ( fg==COLOR_DEFAULT ) fg = GDrawGetDefaultForeground(GDrawGetDisplayOfWindow(pixmap));
164 0 : GBoxDrawTabOutline(pixmap,>s->g,x,y,gts->tabs[i].width,gts->rowh,i==gts->sel);
165 :
166 0 : if ( (i==gts->sel) && (gts->g.box->flags&box_active_border_inner) ) {
167 : GRect r;
168 0 : r.x = x+2;
169 0 : r.y = y+1;
170 0 : r.width = gts->tabs[i].width-4;
171 0 : r.height = gts->rowh-2;
172 0 : GDrawFillRect(pixmap,&r,gts->g.box->active_border);
173 : }
174 :
175 0 : GDrawDrawText(pixmap,x+(gts->tabs[i].width-gts->tabs[i].tw)/2,y+gts->rowh-gts->ds,
176 0 : gts->tabs[i].name,-1,fg);
177 0 : gts->tabs[i].x = x;
178 0 : x += gts->tabs[i].width;
179 0 : return( x );
180 : }
181 :
182 0 : static int gtabset_expose(GWindow pixmap, GGadget *g, GEvent *event) {
183 0 : GTabSet *gts = (GTabSet *) g;
184 : int x,y,i,rd, dsel;
185 : GRect old1, bounds;
186 0 : int bw = GBoxBorderWidth(pixmap,g->box);
187 0 : int yoff = ( gts->rcnt==1 ? bw : 0 );
188 : Color fg;
189 0 : int ni = GDrawPointsToPixels(pixmap,NEST_INDENT);
190 :
191 0 : if ( g->state == gs_invisible )
192 0 : return( false );
193 :
194 0 : GDrawPushClip(pixmap,&g->r,&old1);
195 :
196 0 : GBoxDrawBackground(pixmap,&g->r,g->box,g->state,false);
197 0 : bounds = g->r;
198 :
199 0 : if ( !gts->vertical ) {
200 : /* make room for tabs */
201 0 : bounds.y += gts->rcnt*gts->rowh+yoff-1;
202 0 : bounds.height -= gts->rcnt*gts->rowh+yoff-1;
203 : /* draw border around horizontal tabs only */
204 0 : GBoxDrawBorder(pixmap,&bounds,g->box,g->state,false);
205 : }
206 0 : else if ( g->state==gs_enabled ) {
207 : /* background for labels */
208 0 : GRect old2, vertListRect = g->r;
209 0 : vertListRect.width = gts->vert_list_width+bw-1;
210 0 : GDrawPushClip(pixmap,&vertListRect,&old2);
211 0 : GBoxDrawBackground(pixmap,&g->r,g->box,gs_pressedactive,false);
212 0 : GDrawPopClip(pixmap,&old2);
213 : }
214 :
215 0 : GDrawSetFont(pixmap,gts->font);
216 :
217 0 : if ( gts->vertical ) {
218 0 : x = g->r.x + bw + 3;
219 0 : y = g->r.y + bw + 3;
220 0 : for ( i=gts->offtop; i<gts->tabcnt; ++i ) {
221 0 : fg = gts->tabs[i].disabled?gts->g.box->disabled_foreground:gts->g.box->main_foreground;
222 0 : if ( fg==COLOR_DEFAULT ) fg = GDrawGetDefaultForeground(GDrawGetDisplayOfWindow(pixmap));
223 0 : if ( i==gts->sel ) {
224 : GRect r;
225 0 : r.x = x; r.y = y;
226 0 : r.width = gts->vert_list_width-10; r.height = gts->fh;
227 0 : GDrawFillRect(pixmap,&r,gts->g.box->active_border);
228 : }
229 0 : GDrawDrawText(pixmap,x+gts->tabs[i].nesting*ni,y + gts->as,gts->tabs[i].name,-1,fg);
230 0 : y += gts->fh;
231 : }
232 0 : fg = gts->g.box->main_foreground;
233 0 : if ( fg==COLOR_DEFAULT ) fg = GDrawGetDefaultForeground(GDrawGetDisplayOfWindow(pixmap));
234 0 : GDrawDrawLine(pixmap,x + gts->vert_list_width-4, g->r.y + bw,
235 0 : x + gts->vert_list_width-4, g->r.y + g->r.height - (bw+1),
236 : fg);
237 0 : if ( gts->vsb != NULL )
238 0 : gts->vsb->funcs->handle_expose(pixmap,gts->vsb,event);
239 : } else {
240 0 : gts->haslarrow = gts->hasrarrow = false;
241 0 : if ( gts->scrolled ) {
242 0 : x = g->r.x + GBoxBorderWidth(pixmap,gts->g.box);
243 0 : y = g->r.y+yoff;
244 0 : dsel = 0;
245 0 : if ( gts->toff!=0 )
246 0 : x = DrawLeftArrowTab(pixmap,gts,x,y);
247 0 : for ( i=gts->toff;
248 0 : (i==gts->tabcnt-1 && x+gts->tabs[i].width < g->r.width) ||
249 0 : (i<gts->tabcnt-1 && x+gts->tabs[i].width < g->r.width-gts->arrow_width ) ;
250 0 : ++i ) {
251 0 : if ( i!=gts->sel )
252 0 : x = DrawTab(pixmap,gts,i,x,y);
253 : else {
254 0 : gts->tabs[i].x = x;
255 0 : x += gts->tabs[i].width;
256 0 : dsel = 1;
257 : }
258 : }
259 0 : if ( i!=gts->tabcnt ) {
260 0 : int p = gts->g.inner.x+gts->g.inner.width - gts->arrow_width;
261 0 : if ( p>x ) x=p;
262 0 : x = DrawRightArrowTab(pixmap,gts,x,y);
263 0 : gts->tabs[i].x = 0x7fff;
264 : }
265 : /* This one draws on top of the others, must come last */
266 0 : if ( dsel )
267 0 : DrawTab(pixmap,gts,gts->sel,gts->tabs[gts->sel].x, g->r.y + (gts->rcnt-1) * gts->rowh + yoff );
268 : } else {
269 : /* r is real row, rd is drawn pos */
270 : /* rd is 0 at the top of the ggadget */
271 : /* r is 0 when it contains tabs[0], (the index in the rowstarts array) */
272 0 : for ( rd = 0; rd<gts->rcnt; ++rd ) {
273 0 : int r = (gts->rcnt-1-rd+gts->active_row)%gts->rcnt;
274 0 : y = g->r.y + rd * gts->rowh + yoff;
275 0 : x = g->r.x + (gts->rcnt-1-rd) * gts->offset_per_row + GBoxBorderWidth(pixmap,gts->g.box);
276 0 : for ( i = gts->rowstarts[r]; i<gts->rowstarts[r+1]; ++i )
277 0 : if ( i==gts->sel ) {
278 0 : gts->tabs[i].x = x;
279 0 : x += gts->tabs[i].width;
280 : } else
281 0 : x = DrawTab(pixmap,gts,i,x,y);
282 : }
283 : /* This one draws on top of the others, must come last */
284 0 : DrawTab(pixmap,gts,gts->sel,gts->tabs[gts->sel].x, g->r.y + (gts->rcnt-1) * gts->rowh + yoff );
285 : }
286 : }
287 0 : if ( gts->nested_expose )
288 0 : (gts->nested_expose)(pixmap,g,event);
289 0 : GDrawPopClip(pixmap,&old1);
290 0 : return( true );
291 : }
292 :
293 0 : static int GTabSetRCnt(GTabSet *gts, int totwidth) {
294 : int i, off, r, width;
295 0 : int bp = GBoxBorderWidth(gts->g.base,gts->g.box) + GDrawPointsToPixels(gts->g.base,5);
296 :
297 0 : width = totwidth;
298 0 : for ( i = off = r = 0; i<gts->tabcnt; ++i ) {
299 0 : if ( off!=0 && width-(gts->tabs[i].tw+2*bp)< 0 ) {
300 0 : off = 0; ++r;
301 0 : width = totwidth;
302 : }
303 0 : width -= gts->tabs[i].width;
304 0 : gts->tabs[i].x = off;
305 0 : off ++;
306 : }
307 0 : return( r+1 );
308 : }
309 :
310 0 : static int GTabSetGetLineWidth(GTabSet *gts,int r) {
311 0 : int i, width = 0;
312 :
313 0 : for ( i=gts->rowstarts[r]; i<gts->rowstarts[r+1]; ++i )
314 0 : width += gts->tabs[i].width;
315 0 : return( width );
316 : }
317 :
318 0 : static void GTabSetDistributePixels(GTabSet *gts,int r, int widthdiff) {
319 : int diff, off, i;
320 :
321 0 : diff = widthdiff/(gts->rowstarts[r+1]-gts->rowstarts[r]);
322 0 : off = widthdiff-diff*(gts->rowstarts[r+1]-gts->rowstarts[r]);
323 0 : for ( i=gts->rowstarts[r]; i<gts->rowstarts[r+1]; ++i ) {
324 0 : gts->tabs[i].width += diff;
325 0 : if ( off ) {
326 0 : ++gts->tabs[i].width;
327 0 : --off;
328 : }
329 : }
330 0 : }
331 :
332 : /* We have rearranged the rows of tabs. We want to make sure that each row */
333 : /* row is at least as wide as the row above it */
334 0 : static void GTabSetFigureWidths(GTabSet *gts) {
335 0 : int bp = GBoxBorderWidth(gts->g.base,gts->g.box) + GDrawPointsToPixels(gts->g.base,5);
336 : int i, rd;
337 0 : int oldwidth=0, width;
338 :
339 : /* set all row widths to default values */
340 0 : for ( i=0; i<gts->tabcnt; ++i ) {
341 0 : gts->tabs[i].width = gts->tabs[i].tw + 2*bp;
342 : }
343 : /* r is real row, rd is drawn pos */
344 : /* rd is 0 at the top of the ggadget */
345 : /* r is 0 when it contains tabs[0], (the index in the rowstarts array) */
346 0 : if ( ( gts->filllines && gts->rcnt>1 ) || (gts->fill1line && gts->rcnt==1) ) {
347 0 : for ( rd = 0; rd<gts->rcnt; ++rd ) {
348 0 : int r = (rd+gts->rcnt-1-gts->active_row)%gts->rcnt;
349 0 : int totwidth = gts->g.r.width-2*GBoxBorderWidth(gts->g.base,gts->g.box) -
350 0 : (gts->rcnt-1-rd)*gts->offset_per_row;
351 0 : width = GTabSetGetLineWidth(gts,r);
352 0 : GTabSetDistributePixels(gts,r,totwidth-width);
353 : }
354 : } else {
355 0 : for ( rd = 0; rd<gts->rcnt; ++rd ) { /* r is real row, rd is drawn pos */
356 0 : int r = (rd+gts->rcnt-1-gts->active_row)%gts->rcnt;
357 0 : width = GTabSetGetLineWidth(gts,r) + (gts->rcnt-1-rd)*gts->offset_per_row;
358 0 : if ( rd==0 )
359 0 : oldwidth = width;
360 0 : else if ( oldwidth>width )
361 0 : GTabSetDistributePixels(gts,r,oldwidth-width);
362 : else
363 0 : oldwidth = width;
364 : }
365 : }
366 0 : }
367 :
368 : /* Something happened which would change how many things fit on a line */
369 : /* (initialization, change of font, addition or removal of tab, etc.) */
370 : /* Figure out how many rows we need and then how best to divide the tabs */
371 : /* between those rows, and then the widths of each tab */
372 0 : static void GTabSet_Remetric(GTabSet *gts) {
373 0 : int bbp = GBoxBorderWidth(gts->g.base,gts->g.box);
374 0 : int bp = bbp + GDrawPointsToPixels(gts->g.base,5);
375 : int r, r2, width, i;
376 : int as, ds, ld;
377 0 : int ni = GDrawPointsToPixels(gts->g.base,NEST_INDENT), in;
378 :
379 0 : GDrawSetFont(gts->g.base,gts->font);
380 0 : GDrawWindowFontMetrics(gts->g.base,gts->font,&as,&ds,&ld);
381 0 : gts->as = as; gts->fh = as+ds;
382 0 : gts->rowh = as+ds + bbp+GDrawPointsToPixels(gts->g.base,3);
383 0 : gts->ds = ds + bbp+GDrawPointsToPixels(gts->g.base,1);
384 0 : gts->arrow_size = as+ds;
385 0 : gts->arrow_width = gts->arrow_size + 2*GBoxBorderWidth(gts->g.base,gts->g.box);
386 0 : gts->vert_list_width = 0;
387 :
388 0 : for ( i=0; i<gts->tabcnt; ++i ) {
389 0 : gts->tabs[i].tw = GDrawGetTextWidth(gts->g.base,gts->tabs[i].name,-1);
390 0 : gts->tabs[i].width = gts->tabs[i].tw + 2*bp;
391 0 : in = gts->tabs[i].nesting*ni;
392 0 : if ( gts->tabs[i].tw+in > gts->vert_list_width )
393 0 : gts->vert_list_width = gts->tabs[i].tw+in;
394 : }
395 0 : if ( gts->vsb ) {
396 0 : gts->vert_list_width += gts->vsb->r.width;
397 0 : if ( gts->g.inner.height>26 ) {
398 0 : int bp = GBoxBorderWidth(gts->g.base,gts->g.box);
399 0 : GScrollBarSetBounds(gts->vsb,0,gts->tabcnt,(gts->g.r.height-2*bp-6)/gts->fh);
400 : }
401 : }
402 0 : gts->vert_list_width += 8;
403 :
404 0 : if ( gts->vertical ) {
405 : /* Nothing much to do */
406 0 : } else if ( gts->scrolled ) {
407 0 : free(gts->rowstarts);
408 0 : gts->rowstarts = malloc(2*sizeof(int16));
409 0 : gts->rowstarts[0] = 0; gts->rowstarts[1] = gts->tabcnt;
410 0 : gts->rcnt = 1;
411 : } else {
412 0 : width = gts->g.r.width-2*GBoxBorderWidth(gts->g.base,gts->g.box);
413 0 : r = GTabSetRCnt(gts,width);
414 0 : if ( gts->offset_per_row!=0 && r>1 )
415 0 : while ( (r2 = GTabSetRCnt(gts,width-(r-1)*gts->offset_per_row))!=r )
416 0 : r = r2;
417 0 : free(gts->rowstarts);
418 0 : gts->rowstarts = malloc((r+1)*sizeof(int16));
419 0 : gts->rcnt = r;
420 0 : gts->rowstarts[r] = gts->tabcnt;
421 0 : for ( i=r=0; i<gts->tabcnt; ++i ) {
422 0 : if ( gts->tabs[i].x==0 )
423 0 : gts->rowstarts[r++] = i;
424 : }
425 : /* if there is a single tab on the last line and there are more on */
426 : /* the previous line, then things look nicer if we move one of the */
427 : /* tabs from the previous line onto the last line */
428 : /* Providing it fits, of course */
429 0 : if ( gts->rowstarts[r]-gts->rowstarts[r-1]==1 && r>1 &&
430 0 : gts->rowstarts[r-1]-gts->rowstarts[r-2]>1 &&
431 0 : gts->tabs[i-1].width+gts->tabs[i-2].width < width-(r-1)*gts->offset_per_row )
432 0 : --gts->rowstarts[r-1];
433 :
434 0 : GTabSetFigureWidths(gts);
435 : }
436 0 : }
437 :
438 0 : static void GTabSetChangeSel(GTabSet *gts, int sel,int sendevent) {
439 : int i, width;
440 0 : int oldsel = gts->sel;
441 :
442 0 : if ( sel==-2 ) /* left arrow */
443 0 : --gts->toff;
444 0 : else if ( sel==-3 )
445 0 : ++gts->toff;
446 0 : else if ( sel<0 || sel>=gts->tabcnt || gts->tabs[sel].disabled )
447 0 : return;
448 : else {
449 0 : if ( gts->vertical )
450 0 : gts->sel = sel;
451 : else {
452 0 : for ( i=0; i<gts->rcnt && sel>=gts->rowstarts[i+1]; ++i );
453 0 : if ( gts->active_row != i ) {
454 0 : gts->active_row = i;
455 0 : if ( gts->rcnt>1 && (!gts->filllines || gts->offset_per_row!=0))
456 0 : GTabSetFigureWidths(gts);
457 : }
458 0 : gts->sel = sel;
459 0 : if ( sel<gts->toff )
460 0 : gts->toff = sel;
461 0 : else if ( gts->scrolled ) {
462 0 : for ( i=gts->toff; i<sel && gts->tabs[i].x!=0x7fff; ++i );
463 0 : if ( gts->tabs[i].x==0x7fff ) {
464 0 : width = gts->g.r.width-2*gts->arrow_width; /* it will have a left arrow */
465 0 : if ( sel!=gts->tabcnt )
466 0 : width -= gts->arrow_width; /* it might have a right arrow */
467 0 : for ( i=sel; i>=0 && width-gts->tabs[i].width>=0; --i )
468 0 : width -= gts->tabs[i].width;
469 0 : if ( ++i>sel ) i = sel;
470 0 : gts->toff = i;
471 : }
472 : }
473 : }
474 0 : if ( oldsel!=sel ) {
475 0 : if ( sendevent )
476 0 : GTabSetChanged(gts,oldsel);
477 0 : if ( gts->tabs[oldsel].w!=NULL )
478 0 : GDrawSetVisible(gts->tabs[oldsel].w,false);
479 0 : if ( gts->tabs[gts->sel].w!=NULL )
480 0 : GDrawSetVisible(gts->tabs[gts->sel].w,true);
481 : }
482 : }
483 0 : _ggadget_redraw(>s->g);
484 : }
485 :
486 0 : static int gtabset_mouse(GGadget *g, GEvent *event) {
487 0 : GTabSet *gts = (GTabSet *) g;
488 :
489 0 : if ( !g->takes_input || (g->state!=gs_enabled && g->state!=gs_active && g->state!=gs_focused ))
490 0 : return( false );
491 0 : if ( gts->nested_mouse!=NULL )
492 0 : if ( (gts->nested_mouse)(g,event))
493 0 : return( true );
494 :
495 0 : if ( event->type == et_crossing ) {
496 0 : return( true );
497 0 : } else if ( event->type == et_mousemove ) {
498 0 : return( true );
499 : } else {
500 0 : int i, sel= -1, l;
501 0 : if ( event->u.mouse.y < gts->g.r.y ||
502 0 : ( !gts->vertical && event->u.mouse.y >= gts->g.inner.y ) ||
503 0 : ( gts->vertical && event->u.mouse.x >= gts->g.inner.x ))
504 0 : return( false );
505 0 : else if ( gts->vertical ) {
506 0 : int y = g->r.y + GBoxBorderWidth(g->base,g->box) + 5;
507 0 : sel = (event->u.mouse.y-y)/gts->fh + gts->offtop;
508 0 : if ( sel<0 || sel>=gts->tabcnt )
509 0 : return(false);
510 0 : } else if ( gts->scrolled ) {
511 0 : if ( gts->haslarrow && event->u.mouse.x<gts->tabs[gts->toff].x )
512 0 : sel = -2; /* left arrow */
513 : else {
514 0 : for ( i=gts->toff;
515 0 : i<gts->tabcnt && event->u.mouse.x>=gts->tabs[i].x+gts->tabs[i].width;
516 0 : ++i );
517 0 : if ( gts->hasrarrow && gts->tabs[i].x==0x7fff &&
518 0 : event->u.mouse.x>=gts->tabs[i-1].x+gts->tabs[i-1].width )
519 0 : sel = -3;
520 : else
521 0 : sel = i;
522 : }
523 : } else {
524 0 : l = (event->u.mouse.y-gts->g.r.y)/gts->rowh; /* screen row */
525 0 : if ( l>=gts->rcnt ) l = gts->rcnt-1; /* can happen on single line tabsets (there's extra space then) */
526 0 : l = (gts->rcnt-1-l+gts->active_row)%gts->rcnt; /* internal row number */
527 0 : if ( event->u.mouse.x<gts->tabs[gts->rowstarts[l]].x )
528 0 : sel = -1;
529 0 : else if ( event->u.mouse.x>=gts->tabs[gts->rowstarts[l+1]-1].x+gts->tabs[gts->rowstarts[l+1]-1].width )
530 0 : sel = -1;
531 : else {
532 0 : for ( i=gts->rowstarts[l]; i<gts->rowstarts[l+1] &&
533 0 : event->u.mouse.x>=gts->tabs[i].x+gts->tabs[i].width; ++i );
534 0 : sel = i;
535 : }
536 : }
537 0 : if ( event->type==et_mousedown ) {
538 0 : gts->pressed = true;
539 0 : gts->pressed_sel = sel;
540 : } else {
541 0 : if ( gts->pressed && gts->pressed_sel == sel )
542 0 : GTabSetChangeSel(gts,sel,true);
543 0 : gts->pressed = false;
544 0 : gts->pressed_sel = -1;
545 : }
546 : }
547 0 : return( true );
548 : }
549 :
550 0 : static int gtabset_key(GGadget *g, GEvent *event) {
551 0 : GTabSet *gts = (GTabSet *) g;
552 : int i;
553 :
554 0 : if ( !g->takes_input || !g->takes_keyboard || (g->state!=gs_enabled && g->state!=gs_active && g->state!=gs_focused ))
555 0 : return(false);
556 0 : if ( event->type == et_charup )
557 0 : return( true );
558 :
559 0 : if (event->u.chr.keysym == GK_Left || event->u.chr.keysym == GK_KP_Left ||
560 0 : (event->u.chr.keysym == GK_Tab && (event->u.chr.state&ksm_shift)) ||
561 0 : event->u.chr.keysym == GK_BackTab ||
562 0 : event->u.chr.keysym == GK_Up || event->u.chr.keysym == GK_KP_Up ) {
563 0 : for ( i = gts->sel-1; i>0 && gts->tabs[i].disabled; --i );
564 0 : GTabSetChangeSel(gts,i,true);
565 0 : return( true );
566 0 : } else if (event->u.chr.keysym == GK_Right || event->u.chr.keysym == GK_KP_Right ||
567 0 : event->u.chr.keysym == GK_Tab ||
568 0 : event->u.chr.keysym == GK_Down || event->u.chr.keysym == GK_KP_Down ) {
569 0 : for ( i = gts->sel+1; i<gts->tabcnt-1 && gts->tabs[i].disabled; ++i );
570 0 : GTabSetChangeSel(gts,i,true);
571 0 : return( true );
572 : }
573 0 : return( false );
574 : }
575 :
576 0 : static int gtabset_focus(GGadget *g, GEvent *UNUSED(event)) {
577 :
578 0 : if ( !g->takes_input || (g->state!=gs_enabled && g->state!=gs_active ))
579 0 : return(false);
580 :
581 0 : return( true );
582 : }
583 :
584 0 : static void gtabset_destroy(GGadget *g) {
585 0 : GTabSet *gts = (GTabSet *) g;
586 : int i;
587 :
588 0 : if ( gts==NULL )
589 0 : return;
590 0 : free(gts->rowstarts);
591 0 : for ( i=0; i<gts->tabcnt; ++i ) {
592 0 : free(gts->tabs[i].name);
593 : /* This has already been done */
594 : /* if ( gts->tabs[i].w!=NULL ) */
595 : /* GDrawDestroyWindow(gts->tabs[i].w); */
596 : }
597 0 : free(gts->tabs);
598 0 : _ggadget_destroy(g);
599 : }
600 :
601 0 : static void GTabSetSetFont(GGadget *g,FontInstance *new) {
602 0 : GTabSet *gts = (GTabSet *) g;
603 0 : gts->font = new;
604 0 : GTabSet_Remetric(gts);
605 0 : }
606 :
607 0 : static FontInstance *GTabSetGetFont(GGadget *g) {
608 0 : GTabSet *gts = (GTabSet *) g;
609 0 : return( gts->font );
610 : }
611 :
612 0 : static void _gtabset_redraw(GGadget *g) {
613 0 : GTabSet *gts = (GTabSet *) g;
614 : int i;
615 :
616 0 : GDrawRequestExpose(g->base, &g->r, false);
617 0 : i = gts->sel;
618 0 : if ( gts->tabs[i].w!=NULL )
619 0 : GDrawRequestExpose(gts->tabs[i].w, NULL, false);
620 0 : }
621 :
622 0 : static void _gtabset_move(GGadget *g, int32 x, int32 y ) {
623 0 : GTabSet *gts = (GTabSet *) g;
624 : int i;
625 0 : int32 nx = x+g->inner.x-g->r.x, ny = y+g->inner.y-g->r.y;
626 :
627 0 : for ( i=0; i<gts->tabcnt; ++i ) if ( gts->tabs[i].w!=NULL )
628 0 : GDrawMove(gts->tabs[i].w,nx,ny);
629 0 : _ggadget_move(g,x,y);
630 0 : if ( gts->vsb!=NULL ) {
631 0 : int bp = GBoxBorderWidth(gts->g.base,gts->g.box);
632 0 : GGadgetMove(gts->vsb,g->r.x +bp+ gts->vert_list_width - gts->vsb->r.width,
633 0 : gts->g.r.y+bp);
634 : }
635 0 : }
636 :
637 0 : static void _gtabset_resize(GGadget *g, int32 width, int32 height ) {
638 0 : GTabSet *gts = (GTabSet *) g;
639 : int i;
640 :
641 0 : _ggadget_resize(g,width,height);
642 0 : for ( i=0; i<gts->tabcnt; ++i ) if ( gts->tabs[i].w!=NULL )
643 0 : GDrawResize(gts->tabs[i].w,g->inner.width,g->inner.height);
644 0 : if ( gts->vsb!=NULL ) {
645 0 : int off = gts->offtop;
646 0 : int bp = GBoxBorderWidth(gts->g.base,gts->g.box);
647 0 : GGadgetResize(gts->vsb,gts->vsb->r.width, gts->g.r.height-2*bp);
648 0 : GScrollBarSetBounds(gts->vsb,0,gts->tabcnt,(gts->g.r.height-2*bp-6)/gts->fh);
649 0 : if ( gts->offtop + (gts->g.r.height-2*bp-6)/gts->fh > gts->tabcnt )
650 0 : off = gts->tabcnt - (gts->g.r.height-2*bp-6)/gts->fh;
651 0 : if ( off<0 )
652 0 : off = 0;
653 0 : if ( off!=gts->offtop ) {
654 0 : gts->offtop = off;
655 0 : GScrollBarSetPos(gts->vsb, off );
656 0 : GGadgetRedraw(>s->g);
657 : }
658 : }
659 0 : }
660 :
661 0 : static void _gtabset_setvisible(GGadget *g,int visible) {
662 0 : GTabSet *gts = (GTabSet *) g;
663 :
664 0 : _ggadget_setvisible(g,visible);
665 0 : if ( gts->tabs[gts->sel].w!=NULL )
666 0 : GDrawSetVisible(gts->tabs[gts->sel].w, visible);
667 0 : if ( gts->vsb!=NULL )
668 0 : GGadgetSetVisible(gts->vsb,visible);
669 0 : }
670 :
671 0 : static int gtabset_FillsWindow(GGadget *g) {
672 0 : return( g->prev==NULL && _GWidgetGetGadgets(g->base)==g );
673 : }
674 :
675 0 : static void gtabset_GetDesiredSize(GGadget *g, GRect *outer, GRect *inner) {
676 0 : GTabSet *gts = (GTabSet *) g;
677 0 : int bp = GBoxBorderWidth(g->base,g->box);
678 : GRect nested, test;
679 : int i;
680 :
681 0 : memset(&nested,0,sizeof(nested));
682 0 : for ( i=0; i<gts->tabcnt; ++i ) {
683 0 : GGadget *last = _GWidgetGetGadgets(gts->tabs[i].w);
684 0 : if ( last!=NULL ) {
685 0 : while ( last->prev!=NULL )
686 0 : last=last->prev;
687 0 : GGadgetGetDesiredSize(last,&test,NULL);
688 0 : if ( GGadgetFillsWindow(last)) {
689 0 : test.width += 2*last->r.x;
690 0 : test.height += 2*last->r.y;
691 : }
692 0 : if ( test.width>nested.width ) nested.width = test.width;
693 0 : if ( test.height>nested.height ) nested.height = test.height;
694 : }
695 : }
696 0 : if ( gts->vertical ) {
697 0 : if ( gts->vsb==NULL && gts->rcnt*gts->fh+10 > nested.height )
698 0 : nested.height = gts->tabcnt*gts->fh+10;
699 0 : else if ( gts->vsb!=NULL && 2*gts->vsb->r.width + 20 > nested.height )
700 0 : nested.height = 2*gts->vsb->r.width + 20; /* Minimum size for scrollbar arrows, vaguely */
701 : }
702 :
703 0 : if ( g->desired_width>=0 ) nested.width = g->desired_width - 2*bp;
704 0 : if ( g->desired_height>=0 ) nested.height = g->desired_height - 2*bp;
705 0 : if ( nested.width==0 ) nested.width = 100;
706 0 : if ( nested.height==0 ) nested.height = 100;
707 :
708 0 : if ( inner != NULL )
709 0 : *inner = nested;
710 0 : if ( gts->vertical ) {
711 0 : if ( outer != NULL ) {
712 0 : *outer = nested;
713 0 : outer->width += gts->vert_list_width + 2*bp;
714 0 : outer->height += 2*bp;
715 : }
716 : } else {
717 0 : if ( outer != NULL ) {
718 0 : *outer = nested;
719 0 : outer->width += 2*bp;
720 0 : outer->height += gts->rcnt*gts->rowh + bp;
721 : }
722 : }
723 0 : }
724 :
725 : struct gfuncs gtabset_funcs = {
726 : 0,
727 : sizeof(struct gfuncs),
728 :
729 : gtabset_expose,
730 : gtabset_mouse,
731 : gtabset_key,
732 : NULL,
733 : gtabset_focus,
734 : NULL,
735 : NULL,
736 :
737 : _gtabset_redraw,
738 : _gtabset_move,
739 : _gtabset_resize,
740 : _gtabset_setvisible,
741 : _ggadget_setenabled, /* Doesn't work right */
742 : _ggadget_getsize,
743 : _ggadget_getinnersize,
744 :
745 : gtabset_destroy,
746 :
747 : NULL,
748 : NULL,
749 : NULL,
750 : NULL,
751 : NULL,
752 : GTabSetSetFont,
753 : GTabSetGetFont,
754 :
755 : NULL,
756 : NULL,
757 : NULL,
758 : NULL,
759 : NULL,
760 : NULL,
761 : NULL,
762 : NULL,
763 : NULL,
764 : NULL,
765 : NULL,
766 :
767 : gtabset_GetDesiredSize,
768 : _ggadget_setDesiredSize,
769 : gtabset_FillsWindow,
770 : NULL
771 : };
772 :
773 0 : static int sendtoparent_eh(GWindow gw, GEvent *event) {
774 0 : switch ( event->type ) {
775 : case et_controlevent: case et_char: case et_drop:
776 0 : event->w = GDrawGetParentWindow(gw);
777 0 : GDrawPostEvent(event);
778 0 : break;
779 : case et_resize:
780 0 : GDrawRequestExpose(gw,NULL,false);
781 0 : break;
782 : }
783 :
784 0 : return( true );
785 : }
786 :
787 0 : static int gtabset_vscroll(GGadget *g, GEvent *event) {
788 0 : enum sb sbt = event->u.control.u.sb.type;
789 0 : GTabSet *gts = (GTabSet *) (g->data);
790 0 : int loff = gts->offtop;
791 0 : int page = (g->inner.height-6)/gts->fh- ((g->inner.height-6)/gts->fh>2?1:0);
792 :
793 0 : if ( sbt==et_sb_top )
794 0 : loff = 0;
795 0 : else if ( sbt==et_sb_bottom ) {
796 0 : loff = gts->tabcnt - (gts->g.inner.height-6)/gts->fh;
797 0 : } else if ( sbt==et_sb_up ) {
798 0 : --loff;
799 0 : } else if ( sbt==et_sb_down ) {
800 0 : ++loff;
801 0 : } else if ( sbt==et_sb_uppage ) {
802 0 : loff -= page;
803 0 : } else if ( sbt==et_sb_downpage ) {
804 0 : loff += page;
805 : } else /* if ( sbt==et_sb_thumb || sbt==et_sb_thumbrelease ) */ {
806 0 : loff = event->u.control.u.sb.pos;
807 : }
808 0 : if ( loff + (gts->g.inner.height-6)/gts->fh > gts->tabcnt )
809 0 : loff = gts->tabcnt - (gts->g.inner.height-6)/gts->fh;
810 0 : if ( loff<0 )
811 0 : loff = 0;
812 0 : if ( loff!=gts->offtop ) {
813 0 : gts->offtop = loff;
814 0 : GScrollBarSetPos(gts->vsb, loff );
815 0 : GGadgetRedraw(>s->g);
816 : }
817 0 : return( true );
818 : }
819 :
820 0 : GGadget *GTabSetCreate(struct gwindow *base, GGadgetData *gd,void *data) {
821 0 : GTabSet *gts = calloc(1,sizeof(GTabSet));
822 : int i, bp;
823 : GRect r;
824 : GWindowAttrs childattrs;
825 :
826 0 : memset(&childattrs,0,sizeof(childattrs));
827 0 : childattrs.mask = wam_events;
828 0 : childattrs.event_masks = -1;
829 :
830 0 : if ( !gtabset_inited )
831 0 : GTabSetInit();
832 0 : gts->g.funcs = >abset_funcs;
833 0 : _GGadget_Create(>s->g,base,gd,data, gd->flags&gg_tabset_vert ? &gvtabset_box : >abset_box);
834 0 : gts->font = gtabset_font;
835 :
836 0 : gts->g.takes_input = true; gts->g.takes_keyboard = true; gts->g.focusable = true;
837 :
838 0 : GDrawGetSize(base,&r);
839 0 : if ( gd->pos.x <= 0 )
840 0 : gts->g.r.x = GDrawPointsToPixels(base,2);
841 0 : if ( gd->pos.y <= 0 )
842 0 : gts->g.r.y = GDrawPointsToPixels(base,2);
843 0 : if ( gd->pos.width<=0 )
844 0 : gts->g.r.width = r.width - gts->g.r.x - GDrawPointsToPixels(base,2);
845 0 : if ( gd->pos.height<=0 ) {
846 0 : if ( gd->flags&gg_tabset_nowindow )
847 0 : gts->g.r.height = GDrawPointsToPixels(base,20);
848 : else
849 0 : gts->g.r.height = r.height - gts->g.r.y - GDrawPointsToPixels(base,26);
850 : }
851 :
852 0 : for ( i=0; gd->u.tabs[i].text!=NULL; ++i );
853 0 : gts->tabcnt = i;
854 0 : gts->tabs = malloc(i*sizeof(struct tabs));
855 0 : for ( i=0; gd->u.tabs[i].text!=NULL; ++i ) {
856 0 : if ( gd->u.tabs[i].text_in_resource )
857 0 : gts->tabs[i].name = u_copy(GStringGetResource((intpt) (gd->u.tabs[i].text),NULL));
858 0 : else if ( gd->u.tabs[i].text_is_1byte )
859 0 : gts->tabs[i].name = utf82u_copy((char *) (gd->u.tabs[i].text));
860 : else
861 0 : gts->tabs[i].name = u_copy(gd->u.tabs[i].text);
862 0 : gts->tabs[i].disabled = gd->u.tabs[i].disabled;
863 0 : gts->tabs[i].nesting = gd->u.tabs[i].nesting;
864 0 : if ( gd->u.tabs[i].selected && !gts->tabs[i].disabled )
865 0 : gts->sel = i;
866 : }
867 0 : if ( gd->flags&gg_tabset_scroll ) gts->scrolled = true;
868 0 : if ( gd->flags&gg_tabset_filllines ) gts->filllines = true;
869 0 : if ( gd->flags&gg_tabset_fill1line ) gts->fill1line = true;
870 0 : if ( gd->flags&gg_tabset_vert ) gts->vertical = true;
871 0 : gts->offset_per_row = GDrawPointsToPixels(base,2);
872 0 : if ( gts->vertical && gts->scrolled ) {
873 : GGadgetData gd;
874 0 : memset(&gd,'\0',sizeof(gd));
875 0 : gd.pos.y = gts->g.r.y; gd.pos.height = gts->g.inner.height;
876 0 : gd.pos.width = GDrawPointsToPixels(gts->g.base,_GScrollBar_Width);
877 0 : gd.pos.x = gts->g.inner.x;
878 0 : gd.flags = (gts->g.state==gs_invisible?0:gg_visible)|gg_enabled|gg_pos_in_pixels|gg_sb_vert;
879 0 : gd.handle_controlevent = gtabset_vscroll;
880 0 : gts->vsb = GScrollBarCreate(gts->g.base,&gd,gts);
881 0 : gts->vsb->contained = true;
882 : }
883 0 : GTabSet_Remetric(gts);
884 0 : _GGadget_FinalPosition(>s->g,base,gd);
885 :
886 0 : bp = GBoxBorderWidth(base,gts->g.box);
887 0 : gts->g.inner = gts->g.r;
888 0 : if ( gts->vertical ) {
889 0 : gts->g.inner.x += bp+gts->vert_list_width; gts->g.inner.width -= 2*bp+gts->vert_list_width;
890 0 : gts->g.inner.y += bp; gts->g.inner.height -= 2*bp;
891 : } else {
892 0 : gts->g.inner.x += bp; gts->g.inner.width -= 2*bp;
893 0 : gts->g.inner.y += gts->rcnt*gts->rowh+bp; gts->g.inner.height -= 2*bp+gts->rcnt*gts->rowh;
894 : }
895 0 : if ( gts->rcnt==1 ) {
896 0 : gts->g.inner.y += bp; gts->g.inner.height -= bp;
897 : }
898 0 : if ( gts->vsb!=NULL ) {
899 0 : GGadgetMove(gts->vsb, gts->g.r.x + bp + gts->vert_list_width - gts->vsb->r.width, gts->g.r.y + bp);
900 0 : GGadgetResize(gts->vsb, gts->vsb->r.width, gts->g.r.height-2*bp);
901 0 : if ( gts->g.inner.height>26 )
902 0 : GScrollBarSetBounds(gts->vsb,0,gts->tabcnt,(gts->g.r.height-2*bp-6)/gts->fh);
903 : }
904 :
905 0 : if ( gd->flags&gg_tabset_nowindow ) gts->nowindow = true;
906 :
907 0 : for ( i=0; gd->u.tabs[i].text!=NULL; ++i )
908 0 : if ( !(gd->flags&gg_tabset_nowindow)) {
909 0 : gts->tabs[i].w = GDrawCreateSubWindow(base,>s->g.inner,sendtoparent_eh,GDrawGetUserData(base),&childattrs);
910 0 : if ( gd->u.tabs[i].gcd!=NULL )
911 0 : GGadgetsCreate(gts->tabs[i].w,gd->u.tabs[i].gcd);
912 0 : if ( gts->sel==i && (gd->flags & gg_visible ))
913 0 : GDrawSetVisible(gts->tabs[i].w,true);
914 : } else
915 0 : gts->tabs[i].w = NULL;
916 :
917 0 : if ( gd->flags & gg_group_end )
918 0 : _GGadgetCloseGroup(>s->g);
919 :
920 0 : for ( i=0; gd->u.tabs[i].text!=NULL && !gd->u.tabs[i].selected; ++i );
921 0 : if ( i!=0 && gd->u.tabs[i].text!=NULL )
922 0 : GTabSetChangeSel(gts,i,false);
923 :
924 0 : return( >s->g );
925 : }
926 :
927 0 : int GTabSetGetSel(GGadget *g) {
928 0 : GTabSet *gts = (GTabSet *) g;
929 0 : return( gts->sel );
930 : }
931 :
932 0 : void GTabSetSetSel(GGadget *g,int sel) {
933 0 : GTabSet *gts = (GTabSet *) g;
934 0 : GTabSetChangeSel(gts,sel,false);
935 0 : }
936 :
937 0 : void GTabSetSetEnabled(GGadget *g,int pos,int enabled) {
938 0 : GTabSet *gts = (GTabSet *) g;
939 :
940 0 : if ( pos>=0 && pos<gts->tabcnt ) {
941 0 : gts->tabs[pos].disabled = !enabled;
942 : }
943 0 : GDrawRequestExpose(g->base, &g->r, false);
944 0 : }
945 :
946 0 : GWindow GTabSetGetSubwindow(GGadget *g,int pos) {
947 0 : GTabSet *gts = (GTabSet *) g;
948 :
949 0 : if ( pos>=0 && pos<gts->tabcnt )
950 0 : return( gts->tabs[pos].w );
951 :
952 0 : return( NULL );
953 : }
954 :
955 0 : int GTabSetGetTabLines(GGadget *g) {
956 0 : GTabSet *gts = (GTabSet *) g;
957 0 : return( gts->rcnt );
958 : }
959 :
960 0 : void GTabSetSetNestedExpose(GGadget *g, void (*ne)(GWindow,GGadget *,GEvent *)) {
961 0 : GTabSet *gts = (GTabSet *) g;
962 0 : gts->nested_expose = ne;
963 0 : }
964 :
965 0 : void GTabSetSetNestedMouse(GGadget *g, int (*nm)(GGadget *,GEvent *)) {
966 0 : GTabSet *gts = (GTabSet *) g;
967 0 : gts->nested_mouse = nm;
968 0 : }
969 :
970 0 : void GTabSetChangeTabName(GGadget *g, const char *name, int pos) {
971 0 : GTabSet *gts = (GTabSet *) g;
972 :
973 0 : if ( pos==gts->tabcnt && gts->nowindow ) {
974 0 : gts->tabs = realloc(gts->tabs,(pos+1)*sizeof(struct tabs));
975 0 : memset(>s->tabs[pos],0,sizeof(struct tabs));
976 0 : ++gts->tabcnt;
977 : }
978 0 : if ( pos<gts->tabcnt ) {
979 0 : free(gts->tabs[pos].name);
980 0 : gts->tabs[pos].name = utf82u_copy(name);
981 : }
982 0 : }
983 :
984 0 : void GTabSetRemetric(GGadget *g) {
985 0 : GTabSet *gts = (GTabSet *) g;
986 0 : GTabSet_Remetric(gts);
987 0 : }
988 :
989 0 : void GTabSetRemoveTabByPos(GGadget *g, int pos) {
990 0 : GTabSet *gts = (GTabSet *) g;
991 : int i;
992 :
993 0 : if ( gts->nowindow && pos>=0 && pos<gts->tabcnt && gts->tabcnt>1 ) {
994 0 : free(gts->tabs[pos].name);
995 0 : for ( i=pos+1; i<gts->tabcnt; ++i )
996 0 : gts->tabs[i-1] = gts->tabs[i];
997 0 : --gts->tabcnt;
998 0 : if ( gts->sel==pos ) {
999 0 : if ( gts->sel==gts->tabcnt )
1000 0 : --gts->sel;
1001 0 : GTabSetChanged(gts,pos);
1002 : }
1003 : }
1004 0 : }
1005 :
1006 0 : void GTabSetRemoveTabByName(GGadget *g, char *name) {
1007 0 : GTabSet *gts = (GTabSet *) g;
1008 : int pos;
1009 0 : unichar_t *uname = utf82u_copy(name);
1010 :
1011 0 : for ( pos=0; pos<gts->tabcnt; ++pos ) {
1012 0 : if ( u_strcmp(uname,gts->tabs[pos].name)==0 ) {
1013 0 : GTabSetRemoveTabByPos(g,pos);
1014 0 : break;
1015 : }
1016 : }
1017 :
1018 0 : free(uname);
1019 0 : }
1020 :
1021 0 : GResInfo *_GTabSetRIHead(void) {
1022 0 : if ( !gtabset_inited )
1023 0 : GTabSetInit();
1024 0 : return( >abset_ri );
1025 : }
|