1 //
2 // "$Id$"
3 //
4 // Widget type code for the Fast Light Tool Kit (FLTK).
5 //
6 // Each object described by Fluid is one of these objects. They
7 // are all stored in a double-linked list.
8 //
9 // They "type" of the object is covered by the virtual functions.
10 // There will probably be a lot of these virtual functions.
11 //
12 // The type browser is also a list of these objects, but they
13 // are "factory" instances, not "real" ones. These objects exist
14 // only so the "make" method can be called on them. They are
15 // not in the linked list and are not written to files or
16 // copied or otherwise examined.
17 //
18 // Copyright 1998-2016 by Bill Spitzak and others.
19 //
20 // This library is free software. Distribution and use rights are outlined in
21 // the file "COPYING" which should have been included with this file. If this
22 // file is missing or damaged, see the license at:
23 //
24 // http://www.fltk.org/COPYING.php
25 //
26 // Please report all bugs and problems on the following page:
27 //
28 // http://www.fltk.org/str.php
29 //
30
31 #include <FL/Fl.H>
32 #include <FL/Fl_Browser_.H>
33 #include <FL/fl_draw.H>
34 #include <stdlib.h>
35 #include "../src/flstring.h"
36 #include <stdio.h>
37
38 #include "Fl_Type.h"
39 #include "undo.h"
40
41 #include <FL/Fl_Pixmap.H>
42 #include "pixmaps/lock.xpm"
43 #include "pixmaps/protected.xpm"
44 //#include "pixmaps/unlock.xpm"
45
46 static Fl_Pixmap lock_pixmap(lock_xpm);
47 static Fl_Pixmap protected_pixmap(protected_xpm);
48 //static Fl_Pixmap unlock_pixmap(unlock_xpm);
49
50 #include "pixmaps/flWindow.xpm"
51 #include "pixmaps/flButton.xpm"
52 #include "pixmaps/flCheckButton.xpm"
53 #include "pixmaps/flRoundButton.xpm"
54 #include "pixmaps/flBox.xpm"
55 #include "pixmaps/flGroup.xpm"
56 #include "pixmaps/flFunction.xpm"
57 #include "pixmaps/flCode.xpm"
58 #include "pixmaps/flCodeBlock.xpm"
59 #include "pixmaps/flComment.xpm"
60 #include "pixmaps/flData.xpm"
61 #include "pixmaps/flDeclaration.xpm"
62 #include "pixmaps/flDeclarationBlock.xpm"
63 #include "pixmaps/flClass.xpm"
64 #include "pixmaps/flTabs.xpm"
65 #include "pixmaps/flInput.xpm"
66 #include "pixmaps/flChoice.xpm"
67 #include "pixmaps/flMenuitem.xpm"
68 #include "pixmaps/flMenubar.xpm"
69 #include "pixmaps/flSubmenu.xpm"
70 #include "pixmaps/flScroll.xpm"
71 #include "pixmaps/flTile.xpm"
72 #include "pixmaps/flWizard.xpm"
73 #include "pixmaps/flPack.xpm"
74 #include "pixmaps/flReturnButton.xpm"
75 #include "pixmaps/flLightButton.xpm"
76 #include "pixmaps/flRepeatButton.xpm"
77 #include "pixmaps/flMenuButton.xpm"
78 #include "pixmaps/flOutput.xpm"
79 #include "pixmaps/flTextDisplay.xpm"
80 #include "pixmaps/flTextEdit.xpm"
81 #include "pixmaps/flFileInput.xpm"
82 #include "pixmaps/flBrowser.xpm"
83 #include "pixmaps/flCheckBrowser.xpm"
84 #include "pixmaps/flFileBrowser.xpm"
85 #include "pixmaps/flClock.xpm"
86 #include "pixmaps/flHelp.xpm"
87 #include "pixmaps/flProgress.xpm"
88 #include "pixmaps/flSlider.xpm"
89 #include "pixmaps/flScrollBar.xpm"
90 #include "pixmaps/flValueSlider.xpm"
91 #include "pixmaps/flAdjuster.xpm"
92 #include "pixmaps/flCounter.xpm"
93 #include "pixmaps/flDial.xpm"
94 #include "pixmaps/flRoller.xpm"
95 #include "pixmaps/flValueInput.xpm"
96 #include "pixmaps/flValueOutput.xpm"
97 #include "pixmaps/flSpinner.xpm"
98 #include "pixmaps/flWidgetClass.xpm"
99 #include "pixmaps/flTree.xpm"
100 #include "pixmaps/flTable.xpm"
101
102 static Fl_Pixmap window_pixmap(flWindow_xpm);
103 static Fl_Pixmap button_pixmap(flButton_xpm);
104 static Fl_Pixmap checkbutton_pixmap(flCheckButton_xpm);
105 static Fl_Pixmap roundbutton_pixmap(flRoundButton_xpm);
106 static Fl_Pixmap box_pixmap(flBox_xpm);
107 static Fl_Pixmap group_pixmap(flGroup_xpm);
108 static Fl_Pixmap function_pixmap(flFunction_xpm);
109 static Fl_Pixmap code_pixmap(flCode_xpm);
110 static Fl_Pixmap codeblock_pixmap(flCodeBlock_xpm);
111 static Fl_Pixmap comment_pixmap(flComment_xpm);
112 static Fl_Pixmap declaration_pixmap(flDeclaration_xpm);
113 static Fl_Pixmap declarationblock_pixmap(flDeclarationBlock_xpm);
114 static Fl_Pixmap class_pixmap(flClass_xpm);
115 static Fl_Pixmap tabs_pixmap(flTabs_xpm);
116 static Fl_Pixmap input_pixmap(flInput_xpm);
117 static Fl_Pixmap choice_pixmap(flChoice_xpm);
118 static Fl_Pixmap menuitem_pixmap(flMenuitem_xpm);
119 static Fl_Pixmap menubar_pixmap(flMenubar_xpm);
120 static Fl_Pixmap submenu_pixmap(flSubmenu_xpm);
121 static Fl_Pixmap scroll_pixmap(flScroll_xpm);
122 static Fl_Pixmap tile_pixmap(flTile_xpm);
123 static Fl_Pixmap wizard_pixmap(flWizard_xpm);
124 static Fl_Pixmap pack_pixmap(flPack_xpm);
125 static Fl_Pixmap returnbutton_pixmap(flReturnButton_xpm);
126 static Fl_Pixmap lightbutton_pixmap(flLightButton_xpm);
127 static Fl_Pixmap repeatbutton_pixmap(flRepeatButton_xpm);
128 static Fl_Pixmap menubutton_pixmap(flMenuButton_xpm);
129 static Fl_Pixmap output_pixmap(flOutput_xpm);
130 static Fl_Pixmap textdisplay_pixmap(flTextDisplay_xpm);
131 static Fl_Pixmap textedit_pixmap(flTextEdit_xpm);
132 static Fl_Pixmap fileinput_pixmap(flFileInput_xpm);
133 static Fl_Pixmap browser_pixmap(flBrowser_xpm);
134 static Fl_Pixmap checkbrowser_pixmap(flCheckBrowser_xpm);
135 static Fl_Pixmap filebrowser_pixmap(flFileBrowser_xpm);
136 static Fl_Pixmap clock_pixmap(flClock_xpm);
137 static Fl_Pixmap help_pixmap(flHelp_xpm);
138 static Fl_Pixmap progress_pixmap(flProgress_xpm);
139 static Fl_Pixmap slider_pixmap(flSlider_xpm);
140 static Fl_Pixmap scrollbar_pixmap(flScrollBar_xpm);
141 static Fl_Pixmap valueslider_pixmap(flValueSlider_xpm);
142 static Fl_Pixmap adjuster_pixmap(flAdjuster_xpm);
143 static Fl_Pixmap counter_pixmap(flCounter_xpm);
144 static Fl_Pixmap dial_pixmap(flDial_xpm);
145 static Fl_Pixmap roller_pixmap(flRoller_xpm);
146 static Fl_Pixmap valueinput_pixmap(flValueInput_xpm);
147 static Fl_Pixmap valueoutput_pixmap(flValueOutput_xpm);
148 static Fl_Pixmap spinner_pixmap(flSpinner_xpm);
149 static Fl_Pixmap widgetclass_pixmap(flWidgetClass_xpm);
150 static Fl_Pixmap data_pixmap(flData_xpm);
151 static Fl_Pixmap tree_pixmap(flTree_xpm);
152 static Fl_Pixmap table_pixmap(flTable_xpm);
153
154 Fl_Pixmap *pixmap[] = { 0, &window_pixmap, &button_pixmap, &checkbutton_pixmap, &roundbutton_pixmap, /* 0..4 */
155 &box_pixmap, &group_pixmap, &function_pixmap, &code_pixmap, &codeblock_pixmap, &declaration_pixmap, /* 5..10 */
156 &declarationblock_pixmap, &class_pixmap, &tabs_pixmap, &input_pixmap, &choice_pixmap, /* 11..15 */
157 &menuitem_pixmap, &menubar_pixmap, &submenu_pixmap, &scroll_pixmap, &tile_pixmap, &wizard_pixmap, /* 16..21 */
158 &pack_pixmap, &returnbutton_pixmap, &lightbutton_pixmap, &repeatbutton_pixmap, &menubutton_pixmap, /* 22..26 */
159 &output_pixmap, &textdisplay_pixmap, &textedit_pixmap, &fileinput_pixmap, &browser_pixmap, /* 27..32 */
160 &checkbrowser_pixmap, &filebrowser_pixmap, &clock_pixmap, &help_pixmap, &progress_pixmap, /* 33..36 */
161 &slider_pixmap, &scrollbar_pixmap, &valueslider_pixmap, &adjuster_pixmap, &counter_pixmap, /* 37..41 */
162 &dial_pixmap, &roller_pixmap, &valueinput_pixmap, &valueoutput_pixmap, &comment_pixmap, /* 42..46 */
163 &spinner_pixmap, &widgetclass_pixmap, &data_pixmap, &tree_pixmap, &table_pixmap }; /* 47..51 */
164
165 extern int show_comments;
166
167 ////////////////////////////////////////////////////////////////
168
169 // Copy the given string str to buffer p with no more than maxl characters.
170 // Add "..." if string was truncated.
171 // If parameter quote is true (not 0) the string is quoted with "".
172 // Quote characters are NOT counted.
173 // The returned buffer (string) is terminated with a null byte.
174 // Returns pointer to end of string (before terminating null byte).
175 // Note: the buffer p must be large enough to hold (4 * (maxl+1) + 1) bytes
176 // or (4 * (maxl+1) + 3) bytes if quoted, e.g. "123..." because each UTF-8
177 // character can consist of 4 bytes, "..." adds 3 bytes, quotes '""' add two
178 // bytes, and the terminating null byte adds another byte.
179 // This supports Unicode code points up to U+10FFFF (standard as of 10/2016).
180 // Sanity checks for illegal UTF-8 sequences are included.
181
copy_trunc(char * p,const char * str,int maxl,int quote)182 static char *copy_trunc(char *p, const char *str, int maxl, int quote) {
183
184 int size = 0; // truncated string size in characters
185 int bs; // size of UTF-8 character in bytes
186 const char *end = str + strlen(str); // end of input string
187 if (quote) *p++ = '"'; // opening quote
188 while (size < maxl) { // maximum <maxl> characters
189 if (!(*str & (-32))) break; // end of string (0 or control char)
190 bs = fl_utf8len(*str); // size of next character
191 if (bs <= 0) break; // some error - leave
192 if (str + bs > end) break; // UTF-8 sequence beyond end of string
193 while (bs--) *p++ = *str++; // copy that character into the buffer
194 size++; // count copied characters
195 }
196 if (*str) { // string was truncated
197 strcpy(p,"..."); p += 3;
198 }
199 if (quote) *p++ = '"'; // closing quote
200 *p = 0; // terminating null byte
201 return p;
202 }
203
204 ////////////////////////////////////////////////////////////////
205
206 class Widget_Browser : public Fl_Browser_ {
207 friend class Fl_Type;
208
209 // required routines for Fl_Browser_ subclass:
210 void *item_first() const ;
211 void *item_next(void *) const ;
212 void *item_prev(void *) const ;
213 int item_selected(void *) const ;
214 void item_select(void *,int);
215 int item_width(void *) const ;
216 int item_height(void *) const ;
217 void item_draw(void *,int,int,int,int) const ;
218 int incr_height() const ;
219
220 public:
221
222 int handle(int);
223 void callback();
224 Widget_Browser(int,int,int,int,const char * =0);
225 };
226
227 static Widget_Browser *widget_browser;
make_widget_browser(int x,int y,int w,int h)228 Fl_Widget *make_widget_browser(int x,int y,int w,int h) {
229 return (widget_browser = new Widget_Browser(x,y,w,h));
230 }
231
redraw_widget_browser(Fl_Type * caller)232 void redraw_widget_browser(Fl_Type *caller)
233 {
234 if (caller) {
235 widget_browser->display(caller);
236 }
237 widget_browser->redraw();
238 }
239
select(Fl_Type * o,int v)240 void select(Fl_Type *o, int v) {
241 widget_browser->select(o,v,1);
242 // Fl_Type::current = o;
243 }
244
select_only(Fl_Type * o)245 void select_only(Fl_Type *o) {
246 widget_browser->select_only(o,1);
247 }
248
deselect()249 void deselect() {
250 widget_browser->deselect();
251 //Fl_Type::current = 0; // this breaks the paste & merge functions
252 }
253
254 Fl_Type *Fl_Type::first;
255 Fl_Type *Fl_Type::last;
256
Widget_Browser_callback(Fl_Widget * o,void *)257 static void Widget_Browser_callback(Fl_Widget *o,void *) {
258 ((Widget_Browser *)o)->callback();
259 }
260
Widget_Browser(int X,int Y,int W,int H,const char * l)261 Widget_Browser::Widget_Browser(int X,int Y,int W,int H,const char*l)
262 : Fl_Browser_(X,Y,W,H,l) {
263 type(FL_MULTI_BROWSER);
264 Fl_Widget::callback(Widget_Browser_callback);
265 when(FL_WHEN_RELEASE);
266 }
267
item_first() const268 void *Widget_Browser::item_first() const {return Fl_Type::first;}
269
item_next(void * l) const270 void *Widget_Browser::item_next(void *l) const {return ((Fl_Type*)l)->next;}
271
item_prev(void * l) const272 void *Widget_Browser::item_prev(void *l) const {return ((Fl_Type*)l)->prev;}
273
item_selected(void * l) const274 int Widget_Browser::item_selected(void *l) const {return ((Fl_Type*)l)->new_selected;}
275
item_select(void * l,int v)276 void Widget_Browser::item_select(void *l,int v) {((Fl_Type*)l)->new_selected = v;}
277
item_height(void * l) const278 int Widget_Browser::item_height(void *l) const {
279 Fl_Type *t = (Fl_Type*)l;
280 if (t->visible) {
281 if (show_comments && t->comment())
282 return textsize()*2+4;
283 else
284 return textsize()+5;
285 }
286 return 0;
287 }
288
incr_height() const289 int Widget_Browser::incr_height() const {return textsize()+2;}
290
291 static Fl_Type* pushedtitle;
292
293 // Generate a descriptive text for this item, to put in browser & window titles
title()294 const char* Fl_Type::title() {
295 const char* c = name(); if (c) return c;
296 return type_name();
297 }
298
299 extern const char* subclassname(Fl_Type*);
300
301
302 /**
303 Draw an item in the widget browser.
304
305 A browser line starts with a variable size space. This space directly
306 relates to the level of the type entry.
307
308 If this type has the ability to store children, a triangle follows,
309 pointing right (closed) or pointing down (open, children shown).
310
311 Next follows an icon that is specific to the type. This makes it easy to
312 spot certain types.
313
314 Now follows some text. For classes and widgets, this is the type itself,
315 followed by the name of the object. Other objects show their content as
316 text, possibly abbreviated with an ellipsis.
317
318 \param v v is a pointer to the actual widget type and can be cast safely
319 to Fl_Type
320 \param X,Y these give the position in window coordinates of the top left
321 corner of this line
322 */
item_draw(void * v,int X,int Y,int,int) const323 void Widget_Browser::item_draw(void *v, int X, int Y, int, int) const {
324 // cast to a more general type
325 Fl_Type *l = (Fl_Type *)v;
326
327 char buf[340]; // edit buffer: large enough to hold 80 UTF-8 chars + nul
328
329 // calculate the horizontal start position of this item
330 // 3 is the edge of the browser
331 // 13 is the width of the arrow that indicates children for the item
332 // 18 is the width of the icon
333 // 12 is the indent per level
334 X += 3 + 13 + 18 + l->level * 12;
335
336 // calculate the horizontal start position and width of the separator line
337 int x1 = X;
338 int w1 = w() - x1;
339
340 // items can contain a comment. If they do, the comment gets a second text
341 // line inside this browser line
342 int comment_incr = 0;
343 if (show_comments && l->comment()) {
344 copy_trunc(buf, l->comment(), 80, 0);
345 comment_incr = textsize()-1;
346 if (l->new_selected) fl_color(fl_contrast(FL_DARK_GREEN,FL_SELECTION_COLOR));
347 else fl_color(fl_contrast(FL_DARK_GREEN,color()));
348 fl_font(textfont()+FL_ITALIC, textsize()-2);
349 fl_draw(buf, X, Y+12);
350 Y += comment_incr/2;
351 comment_incr -= comment_incr/2;
352 }
353
354 if (l->new_selected) fl_color(fl_contrast(FL_FOREGROUND_COLOR,FL_SELECTION_COLOR));
355 else fl_color(FL_FOREGROUND_COLOR);
356
357 // Width=10: Draw the triangle that indicates possible children
358 if (l->is_parent()) {
359 X = X - 18 - 13;
360 if (!l->next || l->next->level <= l->level) {
361 if (l->open_!=(l==pushedtitle)) {
362 // an outlined triangle to the right indicates closed item, no children
363 fl_loop(X,Y+7,X+5,Y+12,X+10,Y+7);
364 } else {
365 // an outlined triangle to the bottom indicates open item, no children
366 fl_loop(X+2,Y+2,X+7,Y+7,X+2,Y+12);
367 }
368 } else {
369 if (l->open_!=(l==pushedtitle)) {
370 // a filled triangle to the right indicates closed item, with children
371 fl_polygon(X,Y+7,X+5,Y+12,X+10,Y+7);
372 } else {
373 // a filled triangle to the bottom indicates open item, with children
374 fl_polygon(X+2,Y+2,X+7,Y+7,X+2,Y+12);
375 }
376 }
377 X = X + 13 + 18;
378 }
379
380 // Width=18: Draw the icon associated with the type.
381 Fl_Pixmap *pm = pixmap[l->pixmapID()];
382 if (pm) pm->draw(X-18, Y);
383
384 // Add tags on top of the icon for locked and protected types.
385 switch (l->is_public()) {
386 case 0: lock_pixmap.draw(X - 17, Y); break;
387 case 2: protected_pixmap.draw(X - 17, Y); break;
388 }
389
390 // Indent=12 per level: Now write the text that comes after the graphics representation
391 Y += comment_incr;
392 if (l->is_widget() || l->is_class()) {
393 const char* c = subclassname(l);
394 if (!strncmp(c,"Fl_",3)) c += 3;
395 fl_font(textfont(), textsize());
396 fl_draw(c, X, Y+13);
397 X += int(fl_width(c)+fl_width('n'));
398 c = l->name();
399 if (c) {
400 fl_font(textfont()|FL_BOLD, textsize());
401 fl_draw(c, X, Y+13);
402 } else if ((c = l->label())) {
403 copy_trunc(buf, c, 20, 1); // quoted string
404 fl_draw(buf, X, Y+13);
405 }
406 } else {
407 copy_trunc(buf, l->title(), 55, 0);
408 fl_font(textfont() | (l->is_code_block() && (l->level==0 || l->parent->is_class())?0:FL_BOLD), textsize());
409 fl_draw(buf, X, Y+13);
410 }
411
412 // draw a thin line below the item if this item is not selected
413 // (if it is selected this additional line would look bad)
414 if (!l->new_selected) {
415 fl_color(fl_lighter(FL_GRAY));
416 fl_line(x1,Y+16,x1+w1,Y+16);
417 }
418 }
419
item_width(void * v) const420 int Widget_Browser::item_width(void *v) const {
421
422 char buf[340]; // edit buffer: large enough to hold 80 UTF-8 chars + nul
423
424 Fl_Type *l = (Fl_Type *)v;
425
426 if (!l->visible) return 0;
427
428 int W = 3 + 13 + 18 + l->level * 12;
429
430 if (l->is_widget() || l->is_class()) {
431 const char* c = l->type_name();
432 if (!strncmp(c,"Fl_",3)) c += 3;
433 fl_font(textfont(), textsize());
434 W += int(fl_width(c) + fl_width('n'));
435 c = l->name();
436 if (c) {
437 fl_font(textfont()|FL_BOLD, textsize());
438 W += int(fl_width(c));
439 } else if (l->label()) {
440 copy_trunc(buf, l->label(), 20, 1); // quoted string
441 W += int(fl_width(buf));
442 }
443 } else {
444 copy_trunc(buf, l->title(), 55, 0);
445 fl_font(textfont() | (l->is_code_block() && (l->level==0 || l->parent->is_class())?0:FL_BOLD), textsize());
446 W += int(fl_width(buf));
447 }
448
449 return W;
450 }
451
redraw_browser()452 void redraw_browser() {
453 widget_browser->redraw();
454 }
455
callback()456 void Widget_Browser::callback() {
457 selection_changed((Fl_Type*)selection());
458 }
459
460
461 /**
462 Override the event handling for this browser.
463
464 The vertical mouse position corresponds to an entry in the type tree.
465 The horizontal position has the following hot zones:
466 - 0-3 is the widget frame and ignored
467 - the next hot zone starts 12*indent pixels further to the right
468 - the next 13 pixels refer to the arrow that indicates children for the item
469 - 18 pixels follow for the icon
470 - the remaining part is filled with text
471
472 \param[in] e the incoming event type
473 \return 0 if the event is not supported, and 1 if the event was "used up"
474 */
handle(int e)475 int Widget_Browser::handle(int e) {
476 static Fl_Type *title;
477 Fl_Type *l;
478 int X,Y,W,H; bbox(X,Y,W,H);
479 switch (e) {
480 case FL_PUSH:
481 if (!Fl::event_inside(X,Y,W,H)) break;
482 l = (Fl_Type*)find_item(Fl::event_y());
483 if (l) {
484 X += 3 + 12*l->level - hposition();
485 if (l->is_parent() && Fl::event_x()>X && Fl::event_x()<X+13) {
486 title = pushedtitle = l;
487 redraw_line(l);
488 return 1;
489 }
490 }
491 break;
492 case FL_DRAG:
493 if (!title) break;
494 l = (Fl_Type*)find_item(Fl::event_y());
495 if (l) {
496 X += 3 + 12*l->level - hposition();
497 if (l->is_parent() && Fl::event_x()>X && Fl::event_x()<X+13) ;
498 else l = 0;
499 }
500 if (l != pushedtitle) {
501 if (pushedtitle) redraw_line(pushedtitle);
502 if (l) redraw_line(l);
503 pushedtitle = l;
504 }
505 return 1;
506 case FL_RELEASE:
507 if (!title) {
508 l = (Fl_Type*)find_item(Fl::event_y());
509 if (l && l->new_selected && (Fl::event_clicks() || Fl::event_state(FL_CTRL)))
510 l->open();
511 break;
512 }
513 l = pushedtitle;
514 title = pushedtitle = 0;
515 if (l) {
516 if (l->open_) {
517 l->open_ = 0;
518 for (Fl_Type*k = l->next; k&&k->level>l->level; k = k->next)
519 k->visible = 0;
520 } else {
521 l->open_ = 1;
522 for (Fl_Type*k=l->next; k&&k->level>l->level;) {
523 k->visible = 1;
524 if (k->is_parent() && !k->open_) {
525 Fl_Type *j;
526 for (j = k->next; j && j->level>k->level; j = j->next) {/*empty*/}
527 k = j;
528 } else
529 k = k->next;
530 }
531 }
532 redraw();
533 }
534 return 1;
535 }
536 return Fl_Browser_::handle(e);
537 }
538
Fl_Type()539 Fl_Type::Fl_Type() {
540 factory = 0;
541 parent = 0;
542 next = prev = 0;
543 selected = new_selected = 0;
544 visible = 0;
545 name_ = 0;
546 label_ = 0;
547 user_data_ = 0;
548 user_data_type_ = 0;
549 callback_ = 0;
550 comment_ = 0;
551 rtti = 0;
552 level = 0;
553 code_position = header_position = -1;
554 code_position_end = header_position_end = -1;
555 }
556
fixvisible(Fl_Type * p)557 static void fixvisible(Fl_Type *p) {
558 Fl_Type *t = p;
559 for (;;) {
560 if (t->parent) t->visible = t->parent->visible && t->parent->open_;
561 else t->visible = 1;
562 t = t->next;
563 if (!t || t->level <= p->level) break;
564 }
565 }
566
567 // turn a click at x,y on this into the actual picked object:
click_test(int,int)568 Fl_Type* Fl_Type::click_test(int,int) {return 0;}
add_child(Fl_Type *,Fl_Type *)569 void Fl_Type::add_child(Fl_Type*, Fl_Type*) {}
move_child(Fl_Type *,Fl_Type *)570 void Fl_Type::move_child(Fl_Type*, Fl_Type*) {}
remove_child(Fl_Type *)571 void Fl_Type::remove_child(Fl_Type*) {}
572
573 // add a list of widgets as a new child of p:
add(Fl_Type * p)574 void Fl_Type::add(Fl_Type *p) {
575 if (p && parent == p) return;
576 undo_checkpoint();
577 parent = p;
578 Fl_Type *end = this;
579 while (end->next) end = end->next;
580 Fl_Type *q;
581 int newlevel;
582 if (p) {
583 for (q = p->next; q && q->level > p->level; q = q->next) {/*empty*/}
584 newlevel = p->level+1;
585 } else {
586 q = 0;
587 newlevel = 0;
588 }
589 for (Fl_Type *t = this->next; t; t = t->next) t->level += (newlevel-level);
590 level = newlevel;
591 if (q) {
592 prev = q->prev;
593 prev->next = this;
594 q->prev = end;
595 end->next = q;
596 } else if (first) {
597 prev = last;
598 prev->next = this;
599 end->next = 0;
600 last = end;
601 } else {
602 first = this;
603 last = end;
604 prev = end->next = 0;
605 }
606 if (p) p->add_child(this,0);
607 open_ = 1;
608 fixvisible(this);
609 set_modflag(1);
610 widget_browser->redraw();
611 }
612
613 // add to a parent before another widget:
insert(Fl_Type * g)614 void Fl_Type::insert(Fl_Type *g) {
615 Fl_Type *end = this;
616 while (end->next) end = end->next;
617 parent = g->parent;
618 int newlevel = g->level;
619 visible = g->visible;
620 for (Fl_Type *t = this->next; t; t = t->next) t->level += newlevel-level;
621 level = newlevel;
622 prev = g->prev;
623 if (prev) prev->next = this; else first = this;
624 end->next = g;
625 g->prev = end;
626 fixvisible(this);
627 if (parent) parent->add_child(this, g);
628 widget_browser->redraw();
629 }
630
631 // Return message number for I18N...
632 int
msgnum()633 Fl_Type::msgnum() {
634 int count;
635 Fl_Type *p;
636
637 for (count = 0, p = this; p;) {
638 if (p->label()) count ++;
639 if (p != this && p->is_widget() && ((Fl_Widget_Type *)p)->tooltip()) count ++;
640
641 if (p->prev) p = p->prev;
642 else p = p->parent;
643 }
644
645 return count;
646 }
647
648
649 // delete from parent:
remove()650 Fl_Type *Fl_Type::remove() {
651 Fl_Type *end = this;
652 for (;;) {
653 if (!end->next || end->next->level <= level) break;
654 end = end->next;
655 }
656 if (prev) prev->next = end->next;
657 else first = end->next;
658 if (end->next) end->next->prev = prev;
659 else last = prev;
660 Fl_Type *r = end->next;
661 prev = end->next = 0;
662 if (parent) parent->remove_child(this);
663 parent = 0;
664 widget_browser->redraw();
665 selection_changed(0);
666 return r;
667 }
668
669 // update a string member:
storestring(const char * n,const char * & p,int nostrip)670 int storestring(const char *n, const char * & p, int nostrip) {
671 if (n == p) return 0;
672 undo_checkpoint();
673 int length = 0;
674 if (n) { // see if blank, strip leading & trailing blanks
675 if (!nostrip) while (isspace((int)(unsigned char)*n)) n++;
676 const char *e = n + strlen(n);
677 if (!nostrip) while (e > n && isspace((int)(unsigned char)*(e-1))) e--;
678 length = e-n;
679 if (!length) n = 0;
680 }
681 if (n == p) return 0;
682 if (n && p && !strncmp(n,p,length) && !p[length]) return 0;
683 if (p) free((void *)p);
684 if (!n || !*n) {
685 p = 0;
686 } else {
687 char *q = (char *)malloc(length+1);
688 strlcpy(q,n,length+1);
689 p = q;
690 }
691 set_modflag(1);
692 return 1;
693 }
694
name(const char * n)695 void Fl_Type::name(const char *n) {
696 int nostrip = is_comment();
697 if (storestring(n,name_,nostrip)) {
698 if (visible) widget_browser->redraw();
699 }
700 }
701
label(const char * n)702 void Fl_Type::label(const char *n) {
703 if (storestring(n,label_,1)) {
704 setlabel(label_);
705 if (visible && !name_) widget_browser->redraw();
706 }
707 }
708
callback(const char * n)709 void Fl_Type::callback(const char *n) {
710 storestring(n,callback_);
711 }
712
user_data(const char * n)713 void Fl_Type::user_data(const char *n) {
714 storestring(n,user_data_);
715 }
716
user_data_type(const char * n)717 void Fl_Type::user_data_type(const char *n) {
718 storestring(n,user_data_type_);
719 }
720
comment(const char * n)721 void Fl_Type::comment(const char *n) {
722 if (storestring(n,comment_,1)) {
723 if (visible) widget_browser->redraw();
724 }
725 }
726
open()727 void Fl_Type::open() {
728 printf("Open of '%s' is not yet implemented\n",type_name());
729 }
730
setlabel(const char *)731 void Fl_Type::setlabel(const char *) {}
732
~Fl_Type()733 Fl_Type::~Fl_Type() {
734 // warning: destructor only works for widgets that have been add()ed.
735 if (widget_browser) widget_browser->deleting(this);
736 if (prev) prev->next = next; else first = next;
737 if (next) next->prev = prev; else last = prev;
738 if (current == this) current = 0;
739 if (parent) parent->remove_child(this);
740 if (name_) free((void*)name_);
741 if (label_) free((void*)label_);
742 if (callback_) free((void*)callback_);
743 if (user_data_) free((void*)user_data_);
744 if (user_data_type_) free((void*)user_data_type_);
745 if (comment_) free((void*)comment_);
746 }
747
is_parent() const748 int Fl_Type::is_parent() const {return 0;}
is_widget() const749 int Fl_Type::is_widget() const {return 0;}
is_valuator() const750 int Fl_Type::is_valuator() const {return 0;}
is_spinner() const751 int Fl_Type::is_spinner() const {return 0;}
is_button() const752 int Fl_Type::is_button() const {return 0;}
is_input() const753 int Fl_Type::is_input() const {return 0;}
is_value_input() const754 int Fl_Type::is_value_input() const {return 0;}
is_text_display() const755 int Fl_Type::is_text_display() const {return 0;}
is_menu_item() const756 int Fl_Type::is_menu_item() const {return 0;}
is_menu_button() const757 int Fl_Type::is_menu_button() const {return 0;}
is_group() const758 int Fl_Type::is_group() const {return 0;}
is_window() const759 int Fl_Type::is_window() const {return 0;}
is_code() const760 int Fl_Type::is_code() const {return 0;}
is_code_block() const761 int Fl_Type::is_code_block() const {return 0;}
is_decl_block() const762 int Fl_Type::is_decl_block() const {return 0;}
is_comment() const763 int Fl_Type::is_comment() const {return 0;}
is_class() const764 int Fl_Type::is_class() const {return 0;}
is_public() const765 int Fl_Type::is_public() const {return 1;}
766
is_public() const767 int Fl_Code_Type::is_public()const { return -1; }
is_public() const768 int Fl_CodeBlock_Type::is_public()const { return -1; }
769
770
771 ////////////////////////////////////////////////////////////////
772
773 Fl_Type *in_this_only; // set if menu popped-up in window
774
select_all_cb(Fl_Widget *,void *)775 void select_all_cb(Fl_Widget *,void *) {
776 Fl_Type *p = Fl_Type::current ? Fl_Type::current->parent : 0;
777 if (in_this_only) {
778 Fl_Type *t = p;
779 for (; t && t != in_this_only; t = t->parent) {/*empty*/}
780 if (t != in_this_only) p = in_this_only;
781 }
782 for (;;) {
783 if (p) {
784 int foundany = 0;
785 for (Fl_Type *t = p->next; t && t->level>p->level; t = t->next) {
786 if (!t->new_selected) {widget_browser->select(t,1,0); foundany = 1;}
787 }
788 if (foundany) break;
789 p = p->parent;
790 } else {
791 for (Fl_Type *t = Fl_Type::first; t; t = t->next)
792 widget_browser->select(t,1,0);
793 break;
794 }
795 }
796 selection_changed(p);
797 }
798
select_none_cb(Fl_Widget *,void *)799 void select_none_cb(Fl_Widget *,void *) {
800 Fl_Type *p = Fl_Type::current ? Fl_Type::current->parent : 0;
801 if (in_this_only) {
802 Fl_Type *t = p;
803 for (; t && t != in_this_only; t = t->parent) {/*empty*/}
804 if (t != in_this_only) p = in_this_only;
805 }
806 for (;;) {
807 if (p) {
808 int foundany = 0;
809 for (Fl_Type *t = p->next; t && t->level>p->level; t = t->next) {
810 if (t->new_selected) {widget_browser->select(t,0,0); foundany = 1;}
811 }
812 if (foundany) break;
813 p = p->parent;
814 } else {
815 for (Fl_Type *t = Fl_Type::first; t; t = t->next)
816 widget_browser->select(t,0,0);
817 break;
818 }
819 }
820 selection_changed(p);
821 }
822
delete_children(Fl_Type * p)823 static void delete_children(Fl_Type *p) {
824 Fl_Type *f;
825 for (f = p; f && f->next && f->next->level > p->level; f = f->next) {/*empty*/}
826 for (; f != p; ) {
827 Fl_Type *g = f->prev;
828 delete f;
829 f = g;
830 }
831 }
832
delete_all(int selected_only)833 void delete_all(int selected_only) {
834 for (Fl_Type *f = Fl_Type::first; f;) {
835 if (f->selected || !selected_only) {
836 delete_children(f);
837 Fl_Type *g = f->next;
838 delete f;
839 f = g;
840 } else f = f->next;
841 }
842 if(!selected_only) {
843 include_H_from_C=1;
844 use_FL_COMMAND=0;
845 }
846
847 selection_changed(0);
848 }
849
850 // move f (and it's children) into list before g:
851 // returns pointer to whatever is after f & children
move_before(Fl_Type * g)852 void Fl_Type::move_before(Fl_Type* g) {
853 if (level != g->level) printf("move_before levels don't match! %d %d\n",
854 level, g->level);
855 Fl_Type* n;
856 for (n = next; n && n->level > level; n = n->next) {/*empty*/}
857 if (n == g) return;
858 Fl_Type *l = n ? n->prev : Fl_Type::last;
859 prev->next = n;
860 if (n) n->prev = prev; else Fl_Type::last = prev;
861 prev = g->prev;
862 l->next = g;
863 if (prev) prev->next = this; else Fl_Type::first = this;
864 g->prev = l;
865 if (parent && is_widget()) parent->move_child(this,g);
866 widget_browser->inserting(g, this);
867 widget_browser->display(this);
868 widget_browser->redraw();
869 }
870
871
872 // move selected widgets in their parent's list:
earlier_cb(Fl_Widget *,void *)873 void earlier_cb(Fl_Widget*,void*) {
874 Fl_Type *f;
875 int mod = 0;
876 for (f = Fl_Type::first; f; ) {
877 Fl_Type* nxt = f->next;
878 if (f->selected) {
879 Fl_Type* g;
880 for (g = f->prev; g && g->level > f->level; g = g->prev) {/*empty*/}
881 if (g && g->level == f->level && !g->selected) {
882 f->move_before(g);
883 mod = 1;
884 }
885 }
886 f = nxt;
887 }
888 if (mod) set_modflag(1);
889 }
890
later_cb(Fl_Widget *,void *)891 void later_cb(Fl_Widget*,void*) {
892 Fl_Type *f;
893 int mod = 0;
894 for (f = Fl_Type::last; f; ) {
895 Fl_Type* prv = f->prev;
896 if (f->selected) {
897 Fl_Type* g;
898 for (g = f->next; g && g->level > f->level; g = g->next) {/*empty*/}
899 if (g && g->level == f->level && !g->selected) {
900 g->move_before(f);
901 mod = 1;
902 }
903 }
904 f = prv;
905 }
906 if (mod) set_modflag(1);
907 }
908
909 ////////////////////////////////////////////////////////////////
910
911 // write a widget and all it's children:
write()912 void Fl_Type::write() {
913 write_indent(level);
914 write_word(type_name());
915
916 if (is_class()) {
917 const char * p = ((Fl_Class_Type*)this)->prefix();
918 if (p && strlen(p))
919 write_word(p);
920 }
921
922 write_word(name());
923 write_open(level);
924 write_properties();
925 write_close(level);
926 if (!is_parent()) return;
927 // now do children:
928 write_open(level);
929 Fl_Type *child;
930 for (child = next; child && child->level > level; child = child->next)
931 if (child->level == level+1) child->write();
932 write_close(level);
933 }
934
write_properties()935 void Fl_Type::write_properties() {
936 // repeat this for each attribute:
937 if (label()) {
938 write_indent(level+1);
939 write_word("label");
940 write_word(label());
941 }
942 if (user_data()) {
943 write_indent(level+1);
944 write_word("user_data");
945 write_word(user_data());
946 }
947 if (user_data_type()) {
948 write_word("user_data_type");
949 write_word(user_data_type());
950 }
951 if (callback()) {
952 write_indent(level+1);
953 write_word("callback");
954 write_word(callback());
955 }
956 if (comment()) {
957 write_indent(level+1);
958 write_word("comment");
959 write_word(comment());
960 }
961 if (is_parent() && open_) write_word("open");
962 if (selected) write_word("selected");
963 }
964
read_property(const char * c)965 void Fl_Type::read_property(const char *c) {
966 if (!strcmp(c,"label"))
967 label(read_word());
968 else if (!strcmp(c,"user_data"))
969 user_data(read_word());
970 else if (!strcmp(c,"user_data_type"))
971 user_data_type(read_word());
972 else if (!strcmp(c,"callback"))
973 callback(read_word());
974 else if (!strcmp(c,"comment"))
975 comment(read_word());
976 else if (!strcmp(c,"open"))
977 open_ = 1;
978 else if (!strcmp(c,"selected"))
979 select(this,1);
980 else
981 read_error("Unknown property \"%s\"", c);
982 }
983
read_fdesign(const char *,const char *)984 int Fl_Type::read_fdesign(const char*, const char*) {return 0;}
985
986 /**
987 Return 1 if the list contains a function with the given signature at the top level.
988 */
has_toplevel_function(const char * rtype,const char * sig)989 int has_toplevel_function(const char *rtype, const char *sig) {
990 Fl_Type *child;
991 for (child = Fl_Type::first; child; child = child->next) {
992 if (!child->is_in_class() && strcmp(child->type_name(), "Function")==0) {
993 const Fl_Function_Type *fn = (const Fl_Function_Type*)child;
994 if (fn->has_signature(rtype, sig))
995 return 1;
996 }
997 }
998 return 0;
999 }
1000
1001 /**
1002 Write a comment into the header file.
1003 */
write_comment_h(const char * pre)1004 void Fl_Type::write_comment_h(const char *pre)
1005 {
1006 if (comment() && *comment()) {
1007 write_h("%s/**\n", pre);
1008 const char *s = comment();
1009 write_h("%s ", pre);
1010 while(*s) {
1011 if (*s=='\n') {
1012 if (s[1]) {
1013 write_h("\n%s ", pre);
1014 }
1015 } else {
1016 write_h("%c", *s); // FIXME this is much too slow!
1017 }
1018 s++;
1019 }
1020 write_h("\n%s*/\n", pre);
1021 }
1022 }
1023
1024 /**
1025 Write a comment into the source file.
1026 */
write_comment_c(const char * pre)1027 void Fl_Type::write_comment_c(const char *pre)
1028 {
1029 if (comment() && *comment()) {
1030 write_c("%s/**\n", pre);
1031 const char *s = comment();
1032 write_c("%s ", pre);
1033 while(*s) {
1034 if (*s=='\n') {
1035 if (s[1]) {
1036 write_c("\n%s ", pre);
1037 }
1038 } else {
1039 write_c("%c", *s); // FIXME this is much too slow!
1040 }
1041 s++;
1042 }
1043 write_c("\n%s*/\n", pre);
1044 }
1045 }
1046
1047 /**
1048 Write a comment into the source file.
1049 */
write_comment_inline_c(const char * pre)1050 void Fl_Type::write_comment_inline_c(const char *pre)
1051 {
1052 if (comment() && *comment()) {
1053 const char *s = comment();
1054 if (strchr(s, '\n')==0L) {
1055 // single line comment
1056 if (pre) write_c("%s", pre);
1057 write_c("// %s\n", s);
1058 if (!pre) write_c("%s ", indent());
1059 } else {
1060 write_c("%s/*\n", pre?pre:"");
1061 if (pre) write_c("%s ", pre); else write_c("%s ", indent());
1062 while(*s) {
1063 if (*s=='\n') {
1064 if (s[1]) {
1065 if (pre) write_c("\n%s ", pre); else write_c("\n%s ", indent());
1066 }
1067 } else {
1068 write_c("%c", *s); // FIXME this is much too slow!
1069 }
1070 s++;
1071 }
1072 if (pre) write_c("\n%s */\n", pre); else write_c("\n%s */\n", indent());
1073 if (!pre) write_c("%s ", indent());
1074 }
1075 }
1076 }
1077
1078 /**
1079 Make sure that the given item is visible in the browser by opening
1080 all parent groups and moving the item into the visible space.
1081 */
reveal_in_browser(Fl_Type * t)1082 void reveal_in_browser(Fl_Type *t) {
1083 Fl_Type *p = t->parent;
1084 if (p) {
1085 for (;;) {
1086 if (!p->open_)
1087 p->open_ = 1;
1088 if (!p->parent) break;
1089 p = p->parent;
1090 }
1091 fixvisible(p);
1092 }
1093 widget_browser->display(t);
1094 redraw_browser();
1095 }
1096
1097 /**
1098 Build widgets and dataset needed in live mode.
1099 \return a widget pointer that the live mode initiator can 'show()'
1100 \see leave_live_mode()
1101 */
enter_live_mode(int)1102 Fl_Widget *Fl_Type::enter_live_mode(int) {
1103 return 0L;
1104 }
1105
1106 /**
1107 Release all resources created when entering live mode.
1108 \see enter_live_mode()
1109 */
leave_live_mode()1110 void Fl_Type::leave_live_mode() {
1111 }
1112
1113 /**
1114 Copy all needed properties for this type into the live object.
1115 */
copy_properties()1116 void Fl_Type::copy_properties() {
1117 }
1118
1119 /**
1120 Check whether callback \p cbname is declared anywhere else by the user.
1121
1122 \b Warning: this just checks that the name is declared somewhere,
1123 but it should probably also check that the name corresponds to a
1124 plain function or a member function within the same class and that
1125 the parameter types match.
1126 */
user_defined(const char * cbname) const1127 int Fl_Type::user_defined(const char* cbname) const {
1128 for (Fl_Type* p = Fl_Type::first; p ; p = p->next)
1129 if (strcmp(p->type_name(), "Function") == 0 && p->name() != 0)
1130 if (strncmp(p->name(), cbname, strlen(cbname)) == 0)
1131 if (p->name()[strlen(cbname)] == '(')
1132 return 1;
1133 return 0;
1134 }
1135
1136
1137 //
1138 // End of "$Id$".
1139 //
1140