flattr_ed.cpp 30.7 KB
Newer Older
1
2
3
4
/* 

flext - C++ layer for Max/MSP and pd (pure data) externals

thomas's avatar
thomas committed
5
Copyright (c) 2001-2005 Thomas Grill (gr@grrrr.org)
6
7
8
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.  

thomas's avatar
thomas committed
9
10
11
$LastChangedRevision$
$LastChangedDate$
$LastChangedBy$
12
13
14
15
16
17
*/

/*! \file flattr_ed.cpp
    \brief Attribute editor (property dialog) for PD
*/

thomas's avatar
thomas committed
18
#include "flext.h"
19

thomas's avatar
thomas committed
20
21
22
23
24
#if FLEXT_SYS == FLEXT_SYS_PD 

#ifdef _MSC_VER
#pragma warning( disable : 4091 ) 
#endif
25

thomas's avatar
thomas committed
26
27
28
29
30
31
32
33
34
35
36
37

#if defined(FLEXT_ATTRHIDE) || PD_MINOR_VERSION < 37
#define __FLEXT_WIDGETBEHAVIOR
#endif

//////////////////////////////////////////////////////
#ifdef __FLEXT_WIDGETBEHAVIOR
// we need non-public headers!
#pragma message("Attention: non-public headers used - binary is bound to a specific version")

#include <g_canvas.h>

thomas's avatar
thomas committed
38
/*
39
#ifdef PD_DEVEL_VERSION
thomas's avatar
thomas committed
40
#define __FLEXT_CLONEWIDGET
41
#endif
thomas's avatar
thomas committed
42
*/
43

thomas's avatar
thomas committed
44
#ifndef __FLEXT_CLONEWIDGET
45
#include <m_imp.h>
46
47
#endif

thomas's avatar
thomas committed
48
49
50
#endif
//////////////////////////////////////////////////////

51
52
53
54

#include <string.h>
#include <stdio.h>

thomas's avatar
thomas committed
55

thomas's avatar
thomas committed
56
57
#ifdef FLEXT_ATTRHIDE
#ifndef __FLEXT_CLONEWIDGET
58
59
static t_visfn ori_vis = NULL;
static t_selectfn ori_select = NULL;
thomas's avatar
thomas committed
60
#endif
thomas's avatar
thomas committed
61
62
63
#endif


thomas's avatar
thomas committed
64
65
66
67
68
#ifdef FLEXT_ATTRHIDE
#define ST_DISABLED ""
#else
#define ST_DISABLED " -state disabled"
#endif
thomas's avatar
thomas committed
69
70
71
72


#ifndef FLEXT_NOATTREDIT

73
74
//! generate the script for the property dialog
static void tclscript()
75
{
76
77
78
    static bool havecode = false;
    if(havecode) return;
    else havecode = true;
thomas's avatar
thomas committed
79

80
    sys_vgui(
81
82
83
        "proc flext_escatoms {lst} {\n"
            "set tmp {}\n"
            "foreach a $lst {\n"
thomas's avatar
thomas committed
84
//                "set a [regsub {\\\\} $a \\\\\\\\]\n"  // replace \ with \\  ... must be first
85
                "set a [regsub {\\$} $a \\\\$]\n"  // replace $ with \$
thomas's avatar
thomas committed
86
87
88
//                "set a [regsub {\\{} $a \\\\\\{]\n"  // replace { with \{
//                "set a [regsub {\\}} $a \\\\\\}]\n"  // replace } with \}
//                "set a [regsub {\\ } $a \\\\\\ ]\n"  // replace space with \space
89
90
91
92
93
94
                "set a [regsub {,} $a \\\\,]\n"  // replace , with \,
                "set a [regsub {;} $a \\\\\\;]\n"  // replace ; with \;
                "lappend tmp $a\n"
            "}\n"
            "return $tmp\n"
        "}\n"
95
96
    );
    sys_vgui(
thomas's avatar
thomas committed
97
        "proc flext_makevalue {id ix} {\n"
thomas's avatar
thomas committed
98
99
            // strip "." from the TK id to make a variable name suffix
            "set vid [string trimleft $id .]\n"
100

thomas's avatar
thomas committed
101
102
103
104
105
            "set var_attr_name [concat [concat var_name_$ix]_$vid ]\n"
            "set var_attr_init [concat [concat var_init_$ix]_$vid ]\n"
            "set var_attr_val [concat [concat var_val_$ix]_$vid ]\n"
            "set var_attr_save [concat [concat var_save_$ix]_$vid ]\n"
            "set var_attr_type [concat [concat var_type_$ix]_$vid ]\n"
thomas's avatar
thomas committed
106

thomas's avatar
thomas committed
107
            "global $var_attr_name $var_attr_init $var_attr_val $var_attr_save $var_attr_type\n"
thomas's avatar
thomas committed
108

109
110
            "set lst {}\n"

thomas's avatar
thomas committed
111
112
113
114
115
116
            "if { [expr $$var_attr_type] != 0 } {\n"
                // attribute is puttable

                "lappend lst [eval concat $$var_attr_name]\n" 

                // process current value
117
118
                "set tmp [flext_escatoms [eval concat $$var_attr_val]]\n"
                "set lst [concat $lst [llength $tmp] $tmp]\n" 
119

thomas's avatar
thomas committed
120
                // process init value
121
122
                "set tmp [flext_escatoms [eval concat $$var_attr_init]]\n"
                "set lst [concat $lst [llength $tmp] $tmp]\n" 
thomas's avatar
thomas committed
123

124
                "lappend lst [eval concat $$var_attr_save]\n" 
thomas's avatar
thomas committed
125
            "}\n"
126
127
128

            // return list
            "return $lst\n" 
thomas's avatar
thomas committed
129
        "}\n"
130
131
    );
    sys_vgui(
thomas's avatar
thomas committed
132
133
        "proc flext_apply {id ix} {\n"
            "set lst [flext_makevalue $id $ix]\n"
134
135
            "set lst [eval concat $lst]\n" // remove curly braces from character escaping
            "pd [concat $id attributedialog $lst \\;]\n"
thomas's avatar
thomas committed
136
137
138
139
140
141
142
        "}\n"

        "proc flext_applyall {id alen} {\n"
            // make a list of the attribute values (including save flags)

            "set lst {}\n"
            "for {set ix 1} {$ix <= $alen} {incr ix} {\n"
143
                "set lst [concat $lst [flext_makevalue $id $ix]]\n" 
thomas's avatar
thomas committed
144
            "}\n"
145
            "set lst [eval concat $lst]\n" // remove curly braces from character escaping
146

147
            "pd [concat $id attributedialog $lst \\;]\n"
thomas's avatar
thomas committed
148
        "}\n"
149

thomas's avatar
thomas committed
150
        "proc flext_cancel {id} {\n"
151
            "pd [concat $id cancel \\;]\n"
thomas's avatar
thomas committed
152
        "}\n"
153

thomas's avatar
thomas committed
154
        "proc flext_ok {id alen} {\n"
thomas's avatar
thomas committed
155
            "flext_applyall $id $alen\n"
thomas's avatar
thomas committed
156
157
            "flext_cancel $id\n"
        "}\n"
158
159
    );
    sys_vgui(
thomas's avatar
thomas committed
160
        "proc flext_help {id} {\n"
thomas's avatar
thomas committed
161
            "toplevel $id.hw\n"
thomas's avatar
thomas committed
162
163
164
165
166
167
168
169
170
171
172
173
            "wm title $id.hw \"Flext attribute editor help\"\n"

            "frame $id.hw.buttons\n"
            "pack $id.hw.buttons -side bottom -fill x -pady 2m\n"

            "text $id.hw.text -relief sunken -bd 2 -yscrollcommand \"$id.hw.scroll set\" -setgrid 1 -width 80 -height 10 -wrap word\n"
            "scrollbar $id.hw.scroll -command \"$id.hw.text yview\"\n"
            "pack $id.hw.scroll -side right -fill y\n"
            "pack $id.hw.text -expand yes -fill both\n"

            "button $id.hw.buttons.ok -text OK -command \"destroy $id.hw\"\n"
            "pack $id.hw.buttons.ok -side left -expand 1\n"
thomas's avatar
thomas committed
174
            "bind $id.hw {<KeyPress-Escape>} \"destroy $id.hw\"\n"
thomas's avatar
thomas committed
175
176
177
178
179
180
181
182
183
184

            "$id.hw.text tag configure big -font {Arial 10 bold}\n"
            "$id.hw.text configure -font {Arial 8 bold}\n"
            "$id.hw.text insert end \""
                "The flext attribute editor lets you query or change attribute values exposed by an external object. \" big \"\n\n"
                "Local variable names ($-values) will only be saved as such for init values. "
                "Alternatively, # can be used instead of $.\n"
                "Ctrl-Button on a text field will open an editor window where text can be entered more comfortably.\n"
            "\"\n"
            "$id.hw.text configure -state disabled\n"
thomas's avatar
thomas committed
185
        "}\n"
186
187
    );
    sys_vgui(
thomas's avatar
thomas committed
188
189
190
191
        "proc flext_copyval {dst src} {\n"
            "global $src $dst\n"
            "set $dst [expr $$src]\n"
        "}\n"
192

thomas's avatar
thomas committed
193
194
        "proc flext_textcopy {id idtxt var} {\n"
            "global $var\n"
195
196
197
198
199
            "set txt [eval $idtxt get 0.0 end]\n"
            // strip newline characters
            "set tmp {}\n"
            "foreach t $txt { lappend tmp [string trim $t] }\n"
            "set $var $tmp\n"
thomas's avatar
thomas committed
200
            "destroy $id\n"
thomas's avatar
thomas committed
201
        "}\n"
202
203
    );
    sys_vgui(
thomas's avatar
thomas committed
204
205
206
        "proc flext_textzoom {id var title attr edit} {\n"
            "global $var\n"
            "toplevel $id.w\n"
thomas's avatar
thomas committed
207
208
209
210
211
212
213
            "wm title $id.w [concat $title \" @\" $attr]\n"
//            "wm iconname $w \"text\"\n"
//            "positionWindow $id.w\n"

            "frame $id.w.buttons\n"
            "pack $id.w.buttons -side bottom -fill x -pady 2m\n"

thomas's avatar
thomas committed
214
            "text $id.w.text -relief sunken -bd 2 -yscrollcommand \"$id.w.scroll set\" -setgrid 1 -width 80 -height 20\n"
thomas's avatar
thomas committed
215
216
217
218
            "scrollbar $id.w.scroll -command \"$id.w.text yview\"\n"
            "pack $id.w.scroll -side right -fill y\n"
            "pack $id.w.text -expand yes -fill both\n"

219
220
221
222
223
224
225
226
227
            // insert text with newlines
            "set txt [split [expr $$var] ,]\n"
            "set lines [llength $txt]\n"
            "for {set ix 0} {$ix < ($lines-1)} {incr ix} {\n"
                "$id.w.text insert end [string trim [lindex $txt $ix] ]\n"
                "$id.w.text insert end \" ,\\n\"\n"
            "}\n"
            "$id.w.text insert end [string trim [lindex $txt end] ]\n"

thomas's avatar
thomas committed
228
229
            "$id.w.text mark set insert 0.0\n"

thomas's avatar
thomas committed
230
            "if { $edit != 0 } then {\n"
thomas's avatar
thomas committed
231
232
                "button $id.w.buttons.ok -text OK -command \"flext_textcopy $id.w $id.w.text $var\"\n"
                "pack $id.w.buttons.ok -side left -expand 1\n"
thomas's avatar
thomas committed
233
//              "bind $id.w {<Shift-KeyPress-Return>} \"flext_textcopy $id.w $id.w.text $var\"\n"
thomas's avatar
thomas committed
234
235
            "} "
            "else { $id.w.text configure -state disabled }\n"
thomas's avatar
thomas committed
236
237
238

            "button $id.w.buttons.cancel -text Cancel -command \"destroy $id.w\"\n"
            "pack $id.w.buttons.cancel -side left -expand 1\n"
thomas's avatar
thomas committed
239
            "bind $id.w {<KeyPress-Escape>} \"destroy $id.w\"\n"
thomas's avatar
thomas committed
240
        "}\n"
241
242
    );
    sys_vgui(
thomas's avatar
thomas committed
243
244
245
        "proc pdtk_flext_dialog {id title attrlist} {\n"
                "set vid [string trimleft $id .]\n"
                "set alen [expr [llength $attrlist] / 6 ]\n"
246

thomas's avatar
thomas committed
247
248
249
                "toplevel $id\n"
                "wm title $id $title\n" 
                "wm protocol $id WM_DELETE_WINDOW [concat flext_cancel $id]\n"
250

251
                "frame $id.frame\n"
thomas's avatar
thomas committed
252
                "set row 0\n"
253

thomas's avatar
thomas committed
254
                // set grow parameters
255
256
257
258
259
                "grid columnconfigure $id.frame 0 -weight 1\n"  // label
                "grid columnconfigure $id.frame {1 4} -weight 3\n" // value entry
                "grid columnconfigure $id.frame {2 3} -weight 0\n"  // copy buttons
                "grid columnconfigure $id.frame 5 -weight 1\n"  // apply button
                "grid columnconfigure $id.frame {6 7 8} -weight 0\n" // radio buttons
thomas's avatar
thomas committed
260

261
                "grid rowconfigure $id.frame {0 1} -weight 0\n"
thomas's avatar
thomas committed
262

thomas's avatar
thomas committed
263
                // set column labels
264
265
266
267
268
                "label $id.frame.label -text {attribute} -font {Helvetica 9 bold}\n"
                "label $id.frame.init  -text {initial value} -font {Helvetica 9 bold}\n"
                "label $id.frame.copy  -text {copy} -font {Helvetica 9 bold}\n"
                "label $id.frame.val   -text {current value} -font {Helvetica 9 bold}\n"
                "label $id.frame.apply -text {} -font {Helvetica 9 bold}\n" // why must this be empty?
thomas's avatar
thomas committed
269
                "foreach {i txt} {0 {don't\rsave} 1 {do\rinit} 2 {always\rsave} } {\n"
270
                    "label $id.frame.b$i -text $txt -font {Helvetica 7 bold}\n"
thomas's avatar
thomas committed
271
                "}\n"
272
273
274
275
276
277
278

                "grid config $id.frame.label -column 0 -row $row \n"
                "grid config $id.frame.init  -column 1 -row $row \n"
                "grid config $id.frame.copy  -column 2 -columnspan 2 -row $row \n"
                "grid config $id.frame.val   -column 4 -row $row \n"
                "grid config $id.frame.apply  -column 5 -row $row \n"
                "foreach i {0 1 2} { grid config $id.frame.b$i -column [expr $i + 6] -row $row }\n"
thomas's avatar
thomas committed
279
280
281
                "incr row\n"

                // Separator
282
283
                "frame $id.frame.sep -relief ridge -bd 1 -height 2\n"
                "grid config $id.frame.sep -column 0 -columnspan 9 -row $row -pady 2 -sticky {snew}\n"
thomas's avatar
thomas committed
284
                "incr row\n"
285
286
    );
    sys_vgui(
thomas's avatar
thomas committed
287
288
                "set ix 1\n"
                "foreach {an av ai atp asv afl} $attrlist {\n"
289
                    "grid rowconfigure $id.frame $row -weight 1\n"
thomas's avatar
thomas committed
290
291

                    // get attribute name
thomas's avatar
thomas committed
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
                    "set var_attr_name [concat [concat var_name_$ix]_$vid ]\n"
                    "global $var_attr_name\n"
                    "set $var_attr_name $an\n"

                    // get attribute init value (list)
                    "set var_attr_init [concat [concat var_init_$ix]_$vid ]\n"
                    "global $var_attr_init\n"
                    "set $var_attr_init $ai\n"

                    // get attribute value (list)
                    "set var_attr_val [concat [concat var_val_$ix]_$vid ]\n"
                    "global $var_attr_val\n"
                    "set $var_attr_val $av\n"

                    // get save flag
                    "set var_attr_save [concat [concat var_save_$ix]_$vid ]\n"
                    "global $var_attr_save\n"
                    "set $var_attr_save $asv\n"

                    // get type flag
                    "set var_attr_type [concat [concat var_type_$ix]_$vid ]\n"
                    "global $var_attr_type\n"
                    "set $var_attr_type $afl\n"

                    // add dialog elements to window

                    // attribute label
319
320
                    "label $id.frame.label-$ix -text \"$an :\" -font {Helvetica 8 bold}\n"
                    "grid config $id.frame.label-$ix -column 0 -row $row -padx 5 -sticky {e}\n"
321
322
    );
    sys_vgui(
thomas's avatar
thomas committed
323
324
325
326
327
328
329
330
331
                    "if { $afl != 0 } {\n"
                        // attribute is puttable

                        // entry field for initial value
                        // entry field for current value

                        // choose entry field type
                        "switch $atp {\n"
                            "0 - 1 {\n"  // int or float
thomas's avatar
thomas committed
332
                                "entry $id.frame.init-$ix -textvariable $var_attr_init" ST_DISABLED "\n"
333
                                "entry $id.frame.val-$ix -textvariable $var_attr_val\n"
thomas's avatar
thomas committed
334
335
                            "}\n"
                            "2 {\n"  // boolean
thomas's avatar
thomas committed
336
                                "checkbutton $id.frame.init-$ix -variable $var_attr_init" ST_DISABLED "\n"
337
                                "checkbutton $id.frame.val-$ix -variable $var_attr_val\n"
thomas's avatar
thomas committed
338
339
                            "}\n"
                            "3 {\n"  // symbol
thomas's avatar
thomas committed
340
                                "entry $id.frame.init-$ix -textvariable $var_attr_init" ST_DISABLED "\n"
341
                                "entry $id.frame.val-$ix -textvariable $var_attr_val\n"
thomas's avatar
thomas committed
342
343
                            "}\n"
                            "4 - 5 {\n"  // list or unknown
thomas's avatar
thomas committed
344
                                "entry $id.frame.init-$ix -textvariable $var_attr_init" ST_DISABLED "\n"
345
346
347
                                "bind $id.frame.init-$ix {<Control-Button-1>} \" flext_textzoom $id.frame.init-$ix $var_attr_init { $title } $an 1\"\n"
                                "entry $id.frame.val-$ix -textvariable $var_attr_val\n"
                                "bind $id.frame.val-$ix {<Control-Button-1>} \" flext_textzoom $id.frame.val-$ix $var_attr_val { $title } $an 1\"\n"
thomas's avatar
thomas committed
348
349
350
                            "}\n"
                        "}\n"

351
352
                        "grid config $id.frame.init-$ix  -column 1 -row $row -padx 5 -sticky {ew}\n"
                        "grid config $id.frame.val-$ix   -column 4 -row $row -padx 5 -sticky {ew}\n"
thomas's avatar
thomas committed
353

thomas's avatar
thomas committed
354
                        // copy buttons
thomas's avatar
thomas committed
355
                        "button $id.frame.b2i-$ix -text {<-} -height 1 -command \" flext_copyval $var_attr_init $var_attr_val \"" ST_DISABLED "\n"
356
357
358
                        "grid config $id.frame.b2i-$ix  -column 2 -row $row  -sticky {ew}\n"
                        "button $id.frame.b2c-$ix -text {->} -height 1 -command \" flext_copyval $var_attr_val $var_attr_init \"\n"
                        "grid config $id.frame.b2c-$ix  -column 3 -row $row  -sticky {ew}\n"
thomas's avatar
thomas committed
359

thomas's avatar
thomas committed
360
                        // apply button
361
362
                        "button $id.frame.apply-$ix -text {Apply} -height 1 -command \" flext_apply $id $ix \"\n"
                        "grid config $id.frame.apply-$ix -column 5 -row $row  -sticky {ew}\n"
thomas's avatar
thomas committed
363
364
365

                        // radiobuttons
                        "foreach {i c} {0 black 1 blue 2 red} {\n"
thomas's avatar
thomas committed
366
367
                            "radiobutton $id.frame.b$i-$ix -value $i -foreground $c -variable $var_attr_save" ST_DISABLED "\n"
                            "grid config $id.frame.b$i-$ix -column [expr $i + 6] -row $row\n"
thomas's avatar
thomas committed
368
                        "}\n"
369
370
    );
    sys_vgui(
thomas's avatar
thomas committed
371
372
373
374
375
376
377
378
                    "} else {\n"
                        // attribute is gettable only

                        // entry field for current value (read-only)

                        // choose display field type
                        "switch $atp {\n"
                            "0 - 1 {\n"  // int or float
379
                                "entry $id.frame.val-$ix -textvariable $var_attr_val -state disabled\n"
thomas's avatar
thomas committed
380
381
                            "}\n"
                            "2 {\n"  // boolean
382
                                "checkbutton $id.frame.val-$ix -variable $var_attr_val -state disabled\n"
thomas's avatar
thomas committed
383
384
                            "}\n"
                            "3 {\n"  // symbol
385
                                "entry $id.frame.val-$ix -textvariable $var_attr_val -state disabled\n"
thomas's avatar
thomas committed
386
387
                            "}\n"
                            "4 - 5 {\n"  // list or unknown
388
389
                                "entry $id.frame.val-$ix -textvariable $var_attr_val -state disabled\n"
                                "bind $id.frame.val-$ix {<Control-Button-1>} \" flext_textzoom $id.frame.val-$ix $var_attr_val { $title } $an 0\"\n"
thomas's avatar
thomas committed
390
391
                            "}\n"
                        "}\n"
thomas's avatar
thomas committed
392

393
394
//                      "entry $id.fval.val-$ix -textvariable $var_attr_val -state disabled\n"
                        "grid config $id.frame.val-$ix -column 4 -row $row -padx 5 -sticky {ew}\n"
395

396
397
                        "label $id.frame.readonly-$ix -text \"read-only\"\n"
                        "grid config $id.frame.readonly-$ix -column 6 -columnspan 3 -row $row -padx 5 -sticky {ew}\n"
thomas's avatar
thomas committed
398
                    "}\n"
thomas's avatar
thomas committed
399

thomas's avatar
thomas committed
400
401
402
403
                    // increase counter
                    "incr ix\n"
                    "incr row\n"
                "}\n"
404
405
406
407
408
409

                // empty space
                "grid rowconfigure $id.frame $row -weight 1\n"
                "frame $id.frame.dummy\n"
                "grid config $id.frame.dummy -column 0 -columnspan 9 -row $row\n"
                "incr row\n"
410
411
    );
    sys_vgui(
thomas's avatar
thomas committed
412
413
                // Separator
                "frame $id.sep2 -relief ridge -bd 1 -height 2\n"
414

thomas's avatar
thomas committed
415
416
                // Buttons
                "frame $id.buttonframe\n"
417

thomas's avatar
thomas committed
418
419
420
                "button $id.buttonframe.cancel -text {Leave} -width 20 -command \" flext_cancel $id \"\n"
                "button $id.buttonframe.apply -text {Apply all} -width 20 -command \" flext_applyall $id $alen \"\n"
                "button $id.buttonframe.ok -text {Apply & Leave} -width 20 -command \" flext_ok $id $alen \"\n"
thomas's avatar
thomas committed
421
                "button $id.buttonframe.help -text {Help} -width 10 -command \" flext_help $id \"\n"
422

423
424
425
426
                "grid columnconfigure $id.buttonframe {0 1 2 3} -weight 1\n"
                "grid config $id.buttonframe.cancel $id.buttonframe.apply $id.buttonframe.ok $id.buttonframe.help -padx 2 -sticky {snew}\n"

//                "scrollbar $id.scroll -command \"$id.frame yview\"\n"
427

428
429
430
                "pack $id.buttonframe $id.sep2 -pady 2 -expand 0 -side bottom -fill x\n"
//                "pack $id.scroll -side right -fill y\n"
                "pack $id.frame -expand 1 -side top -fill both\n"
thomas's avatar
thomas committed
431
432
433
434

                // Key bindings
                "bind $id {<KeyPress-Escape>} \" flext_cancel $id \"\n"
                "bind $id {<KeyPress-Return>} \" flext_ok $id $alen \"\n"
thomas's avatar
thomas committed
435
                "bind $id {<Shift-KeyPress-Return>} \" flext_applyall $id $alen \"\n"
thomas's avatar
thomas committed
436
437
        "}\n"
    );
438
439
}

thomas's avatar
thomas committed
440
441
442
443
444
445
446
447
#endif


#ifdef __FLEXT_WIDGETBEHAVIOR
static t_widgetbehavior widgetbehavior; 
#endif

void flext_base::SetGfx(t_classid c)
448
{
thomas's avatar
thomas committed
449
	t_class *cl = getClass(c);
thomas's avatar
thomas committed
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
    // widgetbehavior struct MUST be resident... (static is just ok here)

#ifdef __FLEXT_WIDGETBEHAVIOR
#ifndef __FLEXT_CLONEWIDGET
    widgetbehavior.w_visfn =        cl->c_wb->w_visfn; 
    widgetbehavior.w_selectfn =     cl->c_wb->w_selectfn; 
    widgetbehavior.w_getrectfn =    cl->c_wb->w_getrectfn; 
    widgetbehavior.w_displacefn =   cl->c_wb->w_displacefn; 
    widgetbehavior.w_activatefn =   cl->c_wb->w_activatefn; 
    widgetbehavior.w_deletefn =     cl->c_wb->w_deletefn; 
    widgetbehavior.w_selectfn =     cl->c_wb->w_selectfn;
    widgetbehavior.w_clickfn =      cl->c_wb->w_clickfn;
#else
    widgetbehavior.w_visfn =        text_widgetbehavior.w_visfn; 
    widgetbehavior.w_selectfn =     text_widgetbehavior.w_selectfn; 
    widgetbehavior.w_getrectfn =    text_widgetbehavior.w_getrectfn; 
    widgetbehavior.w_displacefn =   text_widgetbehavior.w_displacefn; 
    widgetbehavior.w_activatefn =   text_widgetbehavior.w_activatefn; 
    widgetbehavior.w_deletefn =     text_widgetbehavior.w_deletefn; 
    widgetbehavior.w_selectfn =     text_widgetbehavior.w_selectfn;
    widgetbehavior.w_clickfn =      text_widgetbehavior.w_clickfn;
#endif
472
473
#endif

thomas's avatar
thomas committed
474
475
476
477
478
479
#ifdef FLEXT_ATTRHIDE

#ifndef __FLEXT_CLONEWIDGET
    ori_vis = widgetbehavior.w_visfn; 
    ori_select = widgetbehavior.w_selectfn; 
#endif
thomas's avatar
thomas committed
480
481
    widgetbehavior.w_visfn =        (t_visfn)cb_GfxVis;
    widgetbehavior.w_selectfn =     (t_selectfn)cb_GfxSelect; 
thomas's avatar
thomas committed
482

483
#if PD_MINOR_VERSION >= 37
484
    class_setsavefn(cl,(t_savefn)cb_GfxSave);
485
#else
thomas's avatar
thomas committed
486
    widgetbehavior.w_savefn =       (t_savefn)cb_GfxSave;
487
488
#endif

thomas's avatar
thomas committed
489
490
491
492
493
494
#endif // FLEXT_ATTRHIDE


#ifndef FLEXT_NOATTREDIT

#if PD_MINOR_VERSION >= 37
495
    class_setpropertiesfn(cl,(t_propertiesfn)cb_GfxProperties);
thomas's avatar
thomas committed
496
#else
thomas's avatar
thomas committed
497
    widgetbehavior.w_propertiesfn = (t_propertiesfn)cb_GfxProperties;
thomas's avatar
thomas committed
498
499
#endif

500
    tclscript();
thomas's avatar
thomas committed
501
502
503
504
505
#endif // FLEXT_NOATTREDIT

#ifdef __FLEXT_WIDGETBEHAVIOR
    class_setwidget(cl, &widgetbehavior);
#endif
506
507
}

thomas's avatar
thomas committed
508
509
510

#ifndef FLEXT_NOATTREDIT

511
512
static size_t escapeit(char *dst,size_t maxlen,const char *src)
{
thomas's avatar
thomas committed
513
514
    char *d;
    for(d = dst; *src && (d-dst) < (int)maxlen; ++src) {
515
516
517
518
519
520
521
522
523
        if(*src == '%')
            *(d++) = '%',*(d++) = '%';
        else
            *(d++) = *src;
    }
    *d = 0;
    return d-dst;
}

524
void flext_base::cb_GfxProperties(flext_hdr *c, t_glist *)
525
{
thomas's avatar
thomas committed
526
    flext_base *th = thisObject(c);
thomas's avatar
thomas committed
527
    char buf[1000];
thomas's avatar
thomas committed
528

thomas's avatar
thomas committed
529
530
     // beginning of proc
    sys_vgui("proc pdtk_flext_dialog_%p {title} {\n",th);
thomas's avatar
thomas committed
531

thomas's avatar
thomas committed
532
533
534
    sys_vgui("pdtk_flext_dialog $title {\n");

    // add title
thomas's avatar
thomas committed
535
536
537
538
539
540
    t_text *x = (t_text *)c;
    FLEXT_ASSERT(x->te_binbuf);

    int argc = binbuf_getnatom(x->te_binbuf);
    t_atom *argv = binbuf_getvec(x->te_binbuf);

thomas's avatar
thomas committed
541
542
    PrintList(argc,argv,buf,sizeof(buf));
    sys_vgui("%s } {\n",buf);
thomas's avatar
thomas committed
543

544
    AtomListStatic<32> la;
thomas's avatar
thomas committed
545
546
547
548
549
550
551
552
553
554
555
556
557
558
    th->ListAttrib(la);
    int cnt = la.Count();

    for(int i = 0; i < cnt; ++i) {
        const t_symbol *sym = GetSymbol(la[i]); 

        // get attribute
        AttrItem *gattr = th->FindAttrib(sym,true);
        // get puttable attribute
        AttrItem *pattr = gattr?gattr->Counterpart():th->FindAttrib(sym,false);

        // get flags
        int sv;
        const AtomList *initdata;
559
560
561
562
        const AttrData *a = th->attrdata->find(sym);
//        AttrDataCont::iterator it = th->attrdata->find(sym);
//        if(it == th->attrdata->end())
        if(!a)
thomas's avatar
thomas committed
563
564
            sv = 0,initdata = NULL;
        else {
565
566
//            const AttrData &a = *it.data();
            if(a->IsSaved())
thomas's avatar
thomas committed
567
                sv = 2;
568
            else if(a->IsInit())
thomas's avatar
thomas committed
569
570
571
                sv = 1;
            else 
                sv = 0;
572
            initdata = a->IsInitValue()?&a->GetInitValue():NULL;
thomas's avatar
thomas committed
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
        }

        // get attribute type
        int tp;
        bool list;
        switch((gattr?gattr:pattr)->argtp) {
            case a_int: tp = 0; list = false; break;
            case a_float: tp = 1; list = false; break;
            case a_bool: tp = 2; list = false; break;
            case a_symbol: tp = 3; list = true; break;
            case a_list: 
            case a_LIST: tp = 4; list = true; break;
            default: 
                tp = 5; list = true; 
                FLEXT_ASSERT(false);
        }

590
        sys_vgui(const_cast<char *>(list?"%s {":"%s "),GetString(sym));
thomas's avatar
thomas committed
591

592
        AtomListStatic<32> lv;
thomas's avatar
thomas committed
593
594
595
596
        if(gattr) { // gettable attribute is present
            // Retrieve attribute value
            th->GetAttrib(sym,gattr,lv);

thomas's avatar
thomas committed
597
            char *b = buf; *b = 0;
598
599
600
601
            for(int i = 0; i < lv.Count(); ++i) {
                char tmp[100];
                PrintAtom(lv[i],tmp,sizeof tmp);
                b += escapeit(b,sizeof(buf)+buf-b,tmp);
602
                if(i < lv.Count()-1) { *(b++) = ' '; *b = 0; }
603
            }
604
            sys_vgui("%s",buf);
thomas's avatar
thomas committed
605
        }
thomas's avatar
thomas committed
606
        else
607
            sys_vgui("{}");
thomas's avatar
thomas committed
608

609
        sys_vgui(const_cast<char *>(list?"} {":" "));
thomas's avatar
thomas committed
610
611
612

        if(pattr) {
            // if there is initialization data take this, otherwise take the current data
thomas's avatar
thomas committed
613
            const AtomList &lp = initdata?*initdata:static_cast<const AtomList &>(lv);
thomas's avatar
thomas committed
614

thomas's avatar
thomas committed
615
            char *b = buf; *b = 0;
616
            for(int i = 0; i < lp.Count(); ++i) {
617
                char tmp[256];
618
619
                PrintAtom(lp[i],tmp,sizeof(tmp)); 
                b += escapeit(b,sizeof(buf)+buf-b,tmp);
620
                if(i < lp.Count()-1) { *(b++) = ' '; *b = 0; }
621
            }
622
            sys_vgui("%s",buf);
thomas's avatar
thomas committed
623
        }
thomas's avatar
thomas committed
624
        else
625
            sys_vgui("{}");
thomas's avatar
thomas committed
626
627


thomas's avatar
thomas committed
628
        sys_vgui(const_cast<char *>(list?"} %i %i %i \n":" %i %i %i \n"),tp,sv,pattr?(pattr->BothExist()?2:1):0);
thomas's avatar
thomas committed
629
630
    }

thomas's avatar
thomas committed
631
632
633
634
    sys_vgui(" } }\n"); // end of proc

    STD::sprintf(buf,"pdtk_flext_dialog_%p %%s\n",th);
    gfxstub_new((t_pd *)th->thisHdr(), th->thisHdr(),buf);
thomas's avatar
thomas committed
635

thomas's avatar
thomas committed
636
    //! \todo delete proc in TCL space
637
638
639
640
}

bool flext_base::cb_AttrDialog(flext_base *th,int argc,const t_atom *argv)
{
641
    for(int i = 0; i < argc; ) {
thomas's avatar
thomas committed
642
643
644
645
646
647
648
        FLEXT_ASSERT(IsSymbol(argv[i]));

        // get name
        const t_symbol *aname = GetSymbol(argv[i]);
        i++;

        // get current value
649
        FLEXT_ASSERT(CanbeInt(argv[i]));
thomas's avatar
thomas committed
650
        int ccnt,coffs;
651
652
        ccnt = GetAInt(argv[i]);
        coffs = ++i;
thomas's avatar
thomas committed
653
654
655
        i += ccnt;

        // get init value
656
        FLEXT_ASSERT(CanbeInt(argv[i]));
thomas's avatar
thomas committed
657
        int icnt,ioffs;
658
659
        icnt = GetAInt(argv[i]);
        ioffs = ++i;
thomas's avatar
thomas committed
660
661
662
663
664
665
666
667
668
669
670
671
        i += icnt;

        FLEXT_ASSERT(i < argc);
        int sv = GetAInt(argv[i]);
        ++i;

        // find puttable attribute
        AttrItem *attr = th->FindAttrib(aname,false);
        if(attr) {
            bool ret = th->SetAttrib(aname,attr,ccnt,argv+coffs);
            FLEXT_ASSERT(ret);

672
            AttrData *a = th->attrdata->find(aname);
thomas's avatar
thomas committed
673
674
            if(sv >= 1) {
                // if data not present create it
675
676
677
678
                if(!a) {
                    AttrData *old = th->attrdata->insert(aname,a = new AttrData);
                    FLEXT_ASSERT(!old);
                }
679
680
681
682

                a->SetSave(sv == 2);
                a->SetInit(true);
                a->SetInitValue(icnt,argv+ioffs);
thomas's avatar
thomas committed
683
684
            }
            else {
685
686
687
688
689
                if(a) {
                    // if data is present reset flags
                    a->SetSave(false);
                    a->SetInit(false);

thomas's avatar
thomas committed
690
691
692
693
694
695
696
697
698
                    // let init data as is
                }
            }
        }
        else {
            post("%s - Attribute %s can't be set",th->thisName(),GetString(aname));
        }
    }
    return true;
699
700
}

thomas's avatar
thomas committed
701
702
703
704
#endif // FLEXT_NOATTREDIT


#ifdef FLEXT_ATTRHIDE
705

thomas's avatar
thomas committed
706
static void BinbufAdd(t_binbuf *b,const t_atom &at,bool transdoll)
707
{
thomas's avatar
thomas committed
708
709
    if(transdoll && at.a_type == A_DOLLAR) {
        char tbuf[MAXPDSTRING];
710
711
712
        sprintf(tbuf, "$%d", at.a_w.w_index);
        binbuf_addv(b,"s",flext::MakeSymbol(tbuf));
    }
thomas's avatar
thomas committed
713
714
    else if(transdoll && at.a_type == A_DOLLSYM) {
        char tbuf[MAXPDSTRING];
715
716
717
718
        sprintf(tbuf, "$%s", at.a_w.w_symbol->s_name);
        binbuf_addv(b,"s",flext::MakeSymbol(tbuf));
    }
    else
thomas's avatar
thomas committed
719
        binbuf_add(b,1,const_cast<t_atom *>(&at));
720
721
}

thomas's avatar
thomas committed
722
void flext_base::BinbufArgs(t_binbuf *b,t_binbuf *args,bool withname,bool transdoll)
723
724
725
726
727
{
    int argc = binbuf_getnatom(args);
    t_atom *argv = binbuf_getvec(args);
    int i,cnt = CheckAttrib(argc,argv);
    // process the creation arguments
thomas's avatar
thomas committed
728
    for(i = withname?0:1; i < cnt; ++i) BinbufAdd(b,argv[i],transdoll);
729
730
}

thomas's avatar
thomas committed
731
void flext_base::BinbufAttr(t_binbuf *b,bool transdoll)
732
733
{
    // process the attributes
734
    AtomListStatic<32> la,lv;
735
736
737
738
739
740
    ListAttrib(la);
    int i,cnt = la.Count();

    for(i = 0; i < cnt; ++i) {
        const t_symbol *sym = GetSymbol(la[i]);
        const AtomList *lref = NULL;
thomas's avatar
thomas committed
741

742
743
744
745
746
747
        AttrData *a = attrdata->find(sym);
        if(a) {
            if(a->IsInit() && a->IsInitValue()) {
                lref = &a->GetInitValue();

#if 0 /////////////////////////////////////////////////////////////
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
                // check for $-parameters
                lv = lref->Count();
                for(int j = 0; j < lref->Count(); ++j) {
                    const char *s = IsSymbol((*lref)[j])?GetString((*lref)[j]):NULL;
                    if(s && s[0] == '$') { // TODO: More refined checking?
                        // prepend a "\"
                        char tmp[256]; *tmp = '\\';
                        strcpy(tmp+1,s);
                        SetString(lv[j],tmp);
                    }
                    else
                        lv[i] = (*lref)[j];
                }

                lref = &lv;
763
#endif /////////////////////////////////////////////////////////////
764
            }
765
766
//            else if(a.IsSaved()) {
            else if(a->IsSaved()) {
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
                AttrItem *attr = FindAttrib(sym,true);

                // attribute must be gettable (so that the data can be retrieved) and puttable (so that the data can be inited)
                if(attr && attr->BothExist()) {
                    GetAttrib(sym,attr,lv); 
                    lref = &lv;
                }
            }
        }

        if(lref) {
            char attrname[256]; *attrname= '@';
            // store name
            strcpy(attrname+1,GetString(sym));
            binbuf_addv(b,"s",MakeSymbol(attrname));

            // store value
thomas's avatar
thomas committed
784
            for(int j = 0; j < lref->Count(); ++j) BinbufAdd(b,(*lref)[j],transdoll);
785
786
787
788
        }
    }
}

thomas's avatar
thomas committed
789
//! Strip the attributes off the object command line
790
void flext_base::cb_GfxVis(flext_hdr *c, t_glist *gl, int vis)
thomas's avatar
thomas committed
791
792
793
{
    if(!gl->gl_isgraph || gl->gl_havewindow) {
        // show object if it's not inside a GOP
thomas's avatar
thomas committed
794

thomas's avatar
thomas committed
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
        flext_base *th = thisObject(c);
        t_text *x = (t_text *)c;
        FLEXT_ASSERT(x->te_binbuf);

        t_binbuf *b = binbuf_new();
        th->BinbufArgs(b,x->te_binbuf,true,false);

        // delete old object box text
        binbuf_free(x->te_binbuf);
        // set new one
        x->te_binbuf = b;

        t_rtext *rt = glist_findrtext(gl,x);
        rtext_retext(rt);

        // now display the changed text with the normal drawing function
    #ifdef __FLEXT_CLONEWIDGET
thomas's avatar
thomas committed
812
        text_widgetbehavior.w_visfn((t_gobj *)c,gl,vis);
thomas's avatar
thomas committed
813
    #else
thomas's avatar
thomas committed
814
        ori_vis((t_gobj *)c,gl,vis);
thomas's avatar
thomas committed
815
816
817
818
819
    #endif
    }
    // else don't show
}

820
void flext_base::cb_GfxSelect(flext_hdr *c,t_glist *gl,int state)
thomas's avatar
thomas committed
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
{
    t_text *x = (t_text *)c;
    flext_base *th = thisObject(c);

    if(!gl->gl_isgraph || gl->gl_havewindow) {
        if(state || !gl->gl_editor->e_textdirty) {
            // change text only on selection
            // OR if text has _not_ been changed 
            // ->  since object will not be recreated we have to get rid
            //     of the attribute text

            FLEXT_ASSERT(x->te_binbuf);

            t_binbuf *b = binbuf_new();
            th->BinbufArgs(b,x->te_binbuf,true,false);
            if(state) th->BinbufAttr(b,false);

            // delete old object box text
            binbuf_free(x->te_binbuf);
            // set new one
            x->te_binbuf = b;

            t_rtext *rt = glist_findrtext(gl,x);
            rtext_retext(rt);

            // fix lines
            canvas_fixlinesfor(gl,x);
        }

        // call original function
        #ifdef __FLEXT_CLONEWIDGET
thomas's avatar
thomas committed
852
            text_widgetbehavior.w_selectfn((t_gobj *)c,gl,state);
thomas's avatar
thomas committed
853
        #else
thomas's avatar
thomas committed
854
            ori_select((t_gobj *)c,gl,state);
thomas's avatar
thomas committed
855
856
857
        #endif
    }
}
858

859
void flext_base::cb_GfxSave(flext_hdr *c, t_binbuf *b)
thomas's avatar
thomas committed
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
{
    flext_base *th = thisObject(c);
    t_text *t = (t_text *)c;
    binbuf_addv(b, "ssiis", gensym("#X"),gensym("obj"), t->te_xpix, t->te_ypix,MakeSymbol(th->thisName()));

    // process the object arguments
    th->BinbufArgs(b,t->te_binbuf,false,true);
    // process the attributes
    th->BinbufAttr(b,true);
    // add end sign
    binbuf_addv(b, ";");
}

#endif // FLEXT_ATTRHIDE

#endif // FLEXT_SYS_PD