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