1 //
2 // "$Id$"
3 //
4 // Fl_Group object code for the Fast Light Tool Kit (FLTK).
5 //
6 // Object describing an Fl_Group and links to Fl_Window_Type.C and
7 // the Fl_Tabs widget, with special stuff to select tab items and
8 // insure that only one is visible.
9 //
10 // Copyright 1998-2010 by Bill Spitzak and others.
11 //
12 // This library is free software. Distribution and use rights are outlined in
13 // the file "COPYING" which should have been included with this file. If this
14 // file is missing or damaged, see the license at:
15 //
16 // http://www.fltk.org/COPYING.php
17 //
18 // Please report all bugs and problems on the following page:
19 //
20 // http://www.fltk.org/str.php
21 //
22
23 #include <FL/Fl.H>
24 #include <FL/Fl_Group.H>
25 #include <FL/Fl_Table.H>
26 #include <FL/fl_message.H>
27 #include "Fl_Widget_Type.h"
28 #include "../src/flstring.h"
29
30 // Override group's resize behavior to do nothing to children:
resize(int X,int Y,int W,int H)31 void igroup::resize(int X, int Y, int W, int H) {
32 Fl_Widget::resize(X,Y,W,H);
33 redraw();
34 }
35
36 Fl_Group_Type Fl_Group_type; // the "factory"
37
make()38 Fl_Type *Fl_Group_Type::make() {
39 return Fl_Widget_Type::make();
40 }
41
fix_group_size(Fl_Type * tt)42 void fix_group_size(Fl_Type *tt) {
43 if (!tt || !tt->is_group()) return;
44 Fl_Group_Type* t = (Fl_Group_Type*)tt;
45 int X = t->o->x();
46 int Y = t->o->y();
47 int R = X+t->o->w();
48 int B = Y+t->o->h();
49 for (Fl_Type *nn = t->next; nn && nn->level > t->level; nn = nn->next) {
50 if (!nn->is_widget() || nn->is_menu_item()) continue;
51 Fl_Widget_Type* n = (Fl_Widget_Type*)nn;
52 int x = n->o->x(); if (x < X) X = x;
53 int y = n->o->y(); if (y < Y) Y = y;
54 int r = x+n->o->w();if (r > R) R = r;
55 int b = y+n->o->h();if (b > B) B = b;
56 }
57 t->o->resize(X,Y,R-X,B-Y);
58 }
59
60 extern int force_parent;
61
group_cb(Fl_Widget *,void *)62 void group_cb(Fl_Widget *, void *) {
63 // Find the current widget:
64 Fl_Type *qq = Fl_Type::current;
65 while (qq && (!qq->is_widget() || qq->is_menu_item())) qq = qq->parent;
66 if (!qq || qq->level < 1 || (qq->level == 1 && !strcmp(qq->type_name(), "widget_class"))) {
67 fl_message("Please select widgets to group");
68 return;
69 }
70 Fl_Widget_Type* q = (Fl_Widget_Type*)qq;
71 force_parent = 1;
72 Fl_Group_Type *n = (Fl_Group_Type*)(Fl_Group_type.make());
73 n->move_before(q);
74 n->o->resize(q->o->x(),q->o->y(),q->o->w(),q->o->h());
75 for (Fl_Type *t = Fl_Type::first; t;) {
76 if (t->level != n->level || t == n || !t->selected) {
77 t = t->next; continue;}
78 Fl_Type *nxt = t->remove();
79 t->add(n);
80 t = nxt;
81 }
82 fix_group_size(n);
83 }
84
ungroup_cb(Fl_Widget *,void *)85 void ungroup_cb(Fl_Widget *, void *) {
86 // Find the group:
87 Fl_Type *q = Fl_Type::current;
88 while (q && (!q->is_widget() || q->is_menu_item())) q = q->parent;
89 if (q) q = q->parent;
90 if (!q || q->level < 1 || (q->level == 1 && !strcmp(q->type_name(), "widget_class"))) {
91 fl_message("Please select widgets in a group");
92 return;
93 }
94 Fl_Type* n;
95 for (n = q->next; n && n->level > q->level; n = n->next) {
96 if (n->level == q->level+1 && !n->selected) {
97 fl_message("Please select all widgets in group");
98 return;
99 }
100 }
101 for (n = q->next; n && n->level > q->level;) {
102 Fl_Type *nxt = n->remove();
103 n->insert(q);
104 n = nxt;
105 }
106 delete q;
107 }
108
109 ////////////////////////////////////////////////////////////////
110
111 #include <stdio.h>
112
write_code1()113 void Fl_Group_Type::write_code1() {
114 Fl_Widget_Type::write_code1();
115 }
116
write_code2()117 void Fl_Group_Type::write_code2() {
118 const char *var = name() ? name() : "o";
119 write_extra_code();
120 write_c("%s%s->end();\n", indent(), var);
121 if (resizable()) {
122 write_c("%sFl_Group::current()->resizable(%s);\n", indent(), var);
123 }
124 write_block_close();
125 }
126
127 ////////////////////////////////////////////////////////////////
128
129 const char pack_type_name[] = "Fl_Pack";
130
131 Fl_Menu_Item pack_type_menu[] = {
132 {"HORIZONTAL", 0, 0, (void*)Fl_Pack::HORIZONTAL},
133 {"VERTICAL", 0, 0, (void*)Fl_Pack::VERTICAL},
134 {0}};
135
136 Fl_Pack_Type Fl_Pack_type; // the "factory"
137
138 ////////////////////////////////////////////////////////////////
139
140 static const int MAX_ROWS = 14;
141 static const int MAX_COLS = 7;
142
143 // this is a minimal table widget used as an example when adding tables in Fluid
144 class Fluid_Table : public Fl_Table {
145 int data[MAX_ROWS][MAX_COLS]; // data array for cells
146
147 // Draw the row/col headings
148 // Make this a dark thin upbox with the text inside.
149 //
DrawHeader(const char * s,int X,int Y,int W,int H)150 void DrawHeader(const char *s, int X, int Y, int W, int H) {
151 fl_push_clip(X,Y,W,H);
152 fl_draw_box(FL_THIN_UP_BOX, X,Y,W,H, row_header_color());
153 fl_color(FL_BLACK);
154 fl_draw(s, X,Y,W,H, FL_ALIGN_CENTER);
155 fl_pop_clip();
156 }
157 // Draw the cell data
158 // Dark gray text on white background with subtle border
159 //
DrawData(const char * s,int X,int Y,int W,int H)160 void DrawData(const char *s, int X, int Y, int W, int H) {
161 fl_push_clip(X,Y,W,H);
162 // Draw cell bg
163 fl_color(FL_WHITE); fl_rectf(X,Y,W,H);
164 // Draw cell data
165 fl_color(FL_GRAY0); fl_draw(s, X,Y,W,H, FL_ALIGN_CENTER);
166 // Draw box border
167 fl_color(color()); fl_rect(X,Y,W,H);
168 fl_pop_clip();
169 }
170 // Handle drawing table's cells
171 // Fl_Table calls this function to draw each visible cell in the table.
172 // It's up to us to use FLTK's drawing functions to draw the cells the way we want.
173 //
draw_cell(TableContext context,int ROW=0,int COL=0,int X=0,int Y=0,int W=0,int H=0)174 void draw_cell(TableContext context, int ROW=0, int COL=0, int X=0, int Y=0, int W=0, int H=0) {
175 static char s[40];
176 switch ( context ) {
177 case CONTEXT_STARTPAGE: // before page is drawn..
178 fl_font(FL_HELVETICA, 16); // set the font for our drawing operations
179 return;
180 case CONTEXT_COL_HEADER: // Draw column headers
181 sprintf(s,"%c",'A'+COL); // "A", "B", "C", etc.
182 DrawHeader(s,X,Y,W,H);
183 return;
184 case CONTEXT_ROW_HEADER: // Draw row headers
185 sprintf(s,"%03d:",ROW); // "001:", "002:", etc
186 DrawHeader(s,X,Y,W,H);
187 return;
188 case CONTEXT_CELL: // Draw data in cells
189 sprintf(s,"%d",data[ROW][COL]);
190 DrawData(s,X,Y,W,H);
191 return;
192 default:
193 return;
194 }
195 }
196 public:
Fluid_Table(int x,int y,int w,int h,const char * l=0L)197 Fluid_Table(int x, int y, int w, int h, const char *l=0L)
198 : Fl_Table(x, y, w, h, l) {
199 end();
200 for ( int r=0; r<MAX_ROWS; r++ )
201 for ( int c=0; c<MAX_COLS; c++ )
202 data[r][c] = 1000+(r*1000)+c;
203 // Rows
204 rows(MAX_ROWS); // how many rows
205 row_header(1); // enable row headers (along left)
206 row_height_all(20); // default height of rows
207 row_resize(0); // disable row resizing
208 // Cols
209 cols(MAX_COLS); // how many columns
210 col_header(1); // enable column headers (along top)
211 col_width_all(80); // default width of columns
212 col_resize(1); // enable column resizing
213 }
214 };
215
216 const char table_type_name[] = "Fl_Table";
217
218 Fl_Table_Type Fl_Table_type; // the "factory"
219
widget(int X,int Y,int W,int H)220 Fl_Widget *Fl_Table_Type::widget(int X,int Y,int W,int H) {
221 Fluid_Table *table = new Fluid_Table(X, Y, W, H);
222 return table;
223 }
224
225 ////////////////////////////////////////////////////////////////
226
227 const char tabs_type_name[] = "Fl_Tabs";
228
229 // Override group's resize behavior to do nothing to children:
resize(int X,int Y,int W,int H)230 void itabs::resize(int X, int Y, int W, int H) {
231 Fl_Widget::resize(X,Y,W,H);
232 redraw();
233 }
234
235 Fl_Tabs_Type Fl_Tabs_type; // the "factory"
236
237 // This is called when user clicks on a widget in the window. See
238 // if it is a tab title, and adjust visibility and return new selection:
239 // If none, return o unchanged:
240
click_test(int x,int y)241 Fl_Type* Fl_Tabs_Type::click_test(int x, int y) {
242 Fl_Tabs *t = (Fl_Tabs*)o;
243 Fl_Widget *a = t->which(x,y);
244 if (!a) return 0; // didn't click on tab
245 // changing the visible tab has an impact on the generated
246 // source code, so mark this project as changed.
247 int changed = (a!=t->value());
248 // okay, run the tabs ui until they let go of mouse:
249 t->handle(FL_PUSH);
250 Fl::pushed(t);
251 while (Fl::pushed()==t) Fl::wait();
252 if (changed) set_modflag(1);
253 return (Fl_Type*)(t->value()->user_data());
254 }
255
256 ////////////////////////////////////////////////////////////////
257
258 const char wizard_type_name[] = "Fl_Wizard";
259
260 // Override group's resize behavior to do nothing to children:
resize(int X,int Y,int W,int H)261 void iwizard::resize(int X, int Y, int W, int H) {
262 Fl_Widget::resize(X,Y,W,H);
263 redraw();
264 }
265
266 Fl_Wizard_Type Fl_Wizard_type; // the "factory"
267
268 // This is called when o is created. If it is in the tab group make
269 // sure it is visible:
270
add_child(Fl_Type * cc,Fl_Type * before)271 void Fl_Group_Type::add_child(Fl_Type* cc, Fl_Type* before) {
272 Fl_Widget_Type* c = (Fl_Widget_Type*)cc;
273 Fl_Widget* b = before ? ((Fl_Widget_Type*)before)->o : 0;
274 ((Fl_Group*)o)->insert(*(c->o), b);
275 o->redraw();
276 }
277
add_child(Fl_Type * c,Fl_Type * before)278 void Fl_Tabs_Type::add_child(Fl_Type* c, Fl_Type* before) {
279 Fl_Group_Type::add_child(c, before);
280 }
281
add_child(Fl_Type * cc,Fl_Type * before)282 void Fl_Table_Type::add_child(Fl_Type* cc, Fl_Type* before) {
283 Fl_Widget_Type* c = (Fl_Widget_Type*)cc;
284 Fl_Widget* b = before ? ((Fl_Widget_Type*)before)->o : 0;
285 if (((Fl_Table*)o)->children()==1) { // the FLuid_Table has one extra child
286 fl_message("Inserting child widgets into an Fl_Table is not recommended.\n"
287 "Please refer to the documentation on Fl_Table.");
288 }
289 ((Fl_Table*)o)->insert(*(c->o), b);
290 o->redraw();
291 }
292
293
294 // This is called when o is deleted. If it is in the tab group make
295 // sure it is not visible:
296
remove_child(Fl_Type * cc)297 void Fl_Group_Type::remove_child(Fl_Type* cc) {
298 Fl_Widget_Type* c = (Fl_Widget_Type*)cc;
299 ((Fl_Group*)o)->remove(c->o);
300 o->redraw();
301 }
302
remove_child(Fl_Type * cc)303 void Fl_Tabs_Type::remove_child(Fl_Type* cc) {
304 Fl_Widget_Type* c = (Fl_Widget_Type*)cc;
305 Fl_Tabs *t = (Fl_Tabs*)o;
306 if (t->value() == c->o) t->value(0);
307 Fl_Group_Type::remove_child(c);
308 }
309
remove_child(Fl_Type * cc)310 void Fl_Table_Type::remove_child(Fl_Type* cc) {
311 Fl_Widget_Type* c = (Fl_Widget_Type*)cc;
312 ((Fl_Table*)o)->remove(*(c->o));
313 o->redraw();
314 }
315
316 // move, don't change selected value:
317
move_child(Fl_Type * cc,Fl_Type * before)318 void Fl_Group_Type::move_child(Fl_Type* cc, Fl_Type* before) {
319 Fl_Widget_Type* c = (Fl_Widget_Type*)cc;
320 Fl_Widget* b = before ? ((Fl_Widget_Type*)before)->o : 0;
321 ((Fl_Group*)o)->remove(c->o);
322 ((Fl_Group*)o)->insert(*(c->o), b);
323 o->redraw();
324 }
325
move_child(Fl_Type * cc,Fl_Type * before)326 void Fl_Table_Type::move_child(Fl_Type* cc, Fl_Type* before) {
327 Fl_Widget_Type* c = (Fl_Widget_Type*)cc;
328 Fl_Widget* b = before ? ((Fl_Widget_Type*)before)->o : 0;
329 ((Fl_Table*)o)->remove(*(c->o));
330 ((Fl_Table*)o)->insert(*(c->o), b);
331 o->redraw();
332 }
333
334 ////////////////////////////////////////////////////////////////
335 // live mode support
336
enter_live_mode(int)337 Fl_Widget *Fl_Group_Type::enter_live_mode(int) {
338 Fl_Group *grp = new Fl_Group(o->x(), o->y(), o->w(), o->h());
339 live_widget = grp;
340 if (live_widget) {
341 copy_properties();
342 Fl_Type *n;
343 for (n = next; n && n->level > level; n = n->next) {
344 if (n->level == level+1)
345 n->enter_live_mode();
346 }
347 grp->end();
348 }
349 return live_widget;
350 }
351
enter_live_mode(int)352 Fl_Widget *Fl_Tabs_Type::enter_live_mode(int) {
353 Fl_Tabs *grp = new Fl_Tabs(o->x(), o->y(), o->w(), o->h());
354 live_widget = grp;
355 if (live_widget) {
356 copy_properties();
357 Fl_Type *n;
358 for (n = next; n && n->level > level; n = n->next) {
359 if (n->level == level+1)
360 n->enter_live_mode();
361 }
362 grp->end();
363 }
364 grp->value(((Fl_Tabs*)o)->value());
365 return live_widget;
366 }
367
enter_live_mode(int)368 Fl_Widget *Fl_Table_Type::enter_live_mode(int) {
369 Fl_Group *grp = new Fluid_Table(o->x(), o->y(), o->w(), o->h());
370 live_widget = grp;
371 if (live_widget) {
372 copy_properties();
373 grp->end();
374 }
375 return live_widget;
376 }
377
leave_live_mode()378 void Fl_Group_Type::leave_live_mode() {
379 }
380
381 /**
382 * copy all properties from the edit widget to the live widget
383 */
copy_properties()384 void Fl_Group_Type::copy_properties() {
385 Fl_Widget_Type::copy_properties();
386 }
387
388 ////////////////////////////////////////////////////////////////
389 // some other group subclasses that fluid does not treat specially:
390
391 #include <FL/Fl_Scroll.H>
392
393 const char scroll_type_name[] = "Fl_Scroll";
394
enter_live_mode(int)395 Fl_Widget *Fl_Scroll_Type::enter_live_mode(int) {
396 Fl_Group *grp = new Fl_Scroll(o->x(), o->y(), o->w(), o->h());
397 grp->show();
398 live_widget = grp;
399 if (live_widget) {
400 copy_properties();
401 Fl_Type *n;
402 for (n = next; n && n->level > level; n = n->next) {
403 if (n->level == level+1)
404 n->enter_live_mode();
405 }
406 grp->end();
407 }
408 return live_widget;
409 }
410
411 Fl_Menu_Item scroll_type_menu[] = {
412 {"BOTH", 0, 0, 0/*(void*)Fl_Scroll::BOTH*/},
413 {"HORIZONTAL", 0, 0, (void*)Fl_Scroll::HORIZONTAL},
414 {"VERTICAL", 0, 0, (void*)Fl_Scroll::VERTICAL},
415 {"HORIZONTAL_ALWAYS", 0, 0, (void*)Fl_Scroll::HORIZONTAL_ALWAYS},
416 {"VERTICAL_ALWAYS", 0, 0, (void*)Fl_Scroll::VERTICAL_ALWAYS},
417 {"BOTH_ALWAYS", 0, 0, (void*)Fl_Scroll::BOTH_ALWAYS},
418 {0}};
419
420 Fl_Scroll_Type Fl_Scroll_type; // the "factory"
421
copy_properties()422 void Fl_Scroll_Type::copy_properties() {
423 Fl_Group_Type::copy_properties();
424 Fl_Scroll *s = (Fl_Scroll*)o, *d = (Fl_Scroll*)live_widget;
425 d->position(s->xposition(), s->yposition());
426 d->type(s->type()); // TODO: get this flag from Fl_Scroll_Type!
427 d->scrollbar.align(s->scrollbar.align());
428 d->hscrollbar.align(s->hscrollbar.align());
429 }
430
431 ////////////////////////////////////////////////////////////////
432
433 const char tile_type_name[] = "Fl_Tile";
434
435 Fl_Tile_Type Fl_Tile_type; // the "factory"
436
copy_properties()437 void Fl_Tile_Type::copy_properties() {
438 Fl_Group_Type::copy_properties();
439 // no additional properties
440 }
441
442 //
443 // End of "$Id$".
444 //
445