1V-code Technical Reference 2 3 4 5------------------------------------------------- 6 7== Introduction == 8 9V-code got its name from a void pointer. As bytecode is comprised of 'char', so 10V-code is of 'void *'. Therefore, "V". 11 12V-code engine runs mtPaint's GUI - and its commandline and scripts - but it is 13less a widget toolkit per se, than a technique of abstraction. The idea was to 14decouple the semantics of controls from the particulars of implementation - and 15to get rid of the mind-numbing boilerplate that invariably accompanies anything 16having to do with a GUI. And when I compare what it takes to create a new dialog 17now with V-code, to what it had taken without - I much prefer the new way. 18 19V-code is declarative. I describe an interface component, and leave it to the 20engine to make it - or to pretend convincingly enough, so that the rest of the 21program does not notice a difference. Whatever specialcasing is needed, is done 22within the engine, never to poke its ugly snout outside. 23 24While the declarative part is quite extensive, the runtime API is simplistic. It 25does not need complexity; when creation is firmly separated into its own phase, 26only a few tweaks remain to be done at runtime. 27 28Another reason for the simplicity is that I made things interchangeable. There 29are no special accessor functions for any type of widget, and callback signatures 30never differ without a very compelling reason. This way, one event handler can 31serve a number of different widgets with minimal effort. 32 33This absence of widget functions/methods is an intentional feature and the core 34difference of V-code from usual GUI toolkits. All actions are done through a 35compact set of call points, and while internally tasks get routed to specific 36effector modules, calling code takes no part in the decisions what to use, how, 37and when. Interdependences of some operations arising in some cases are thus 38easily tracked and handled, entirely within the engine. Equally easy are 39conditional replacements of a component with a differently implemented, or a 40simulated one. 41 42V-code is not told what to do; it receives commands as to what it should make 43happen. It is the principle of the thing. 44 45The function handlers are minimalistic. No sanity checks; if something is done 46wrong, code signals that by crashing. But no strictness either; if a function is 47called on an unhandled widget type, it simply does nothing. Default values are 48sometimes substituted, but only where doing it once in the handler made more 49sense than repeating the same at several call sites. 50 51Neither declarative nor runtime part is providing complete coverage; only the 52widgets and operations needed by mtPaint. When for a new feature I need something 53that is not yet there, I extend the V-code engine. 54 55 56== Overview == 57 58The pegasus-eye view of how V-code is used, is this. 59- You prepare a V-code description of, say, a dialog window. 60- You fill a struct with initial values for it. 61- You hand off both to **run_create_()**. 62- It executes the description: allocates memory, copies the struct in there, 63 creates widgets, setups callbacks, does initializations, and shows the finished 64 result to the user. 65- User does some things to controls in the dialog, changing some values, then 66 presses "OK". 67- The callback sees that it was "OK", calls **run_query()** to read back values 68 from all the controls. 69- The new values in the copy of struct and/or in global variables are used to do 70 something. 71- The callback calls **run_destroy()** to finish off the window, and returns. 72- Done. 73 74 75There are ways and means to do more complicated things, but this simple scenario 76is done this simply; in exactly 3 function calls. 77 78This is how it can work. 79 80Every V-code command describing a control - say, a spinbutton or a text entry - 81has a memory reference; either to a global variable, or to a field in a struct. 82When the control is created, it is initialized from that memory; when it is read, 83the result goes to that memory. When **run_create()** makes that control, it 84saves the address of that V-code command, and the widget it created, into its 85"tape" (a flat array of "slots"). When you call **run_query()**, it iterates over 86slots in the "tape" and looks at commands; it reads back values from every control 87it finds, each into the place that its command refers to. When you call 88**run_destroy()**, after the widgets get destroyed it again iterates over slots 89and looks at commands, to do cleanup actions if needed; after that, the attached 90struct and "tape" are freed. 91 92When you need to add a callback, you put an //EVENT()// command, with a type ID 93and a function reference, after a control; this command also gets a slot in the 94"tape". The function gets called when the control sitting before it in the "tape" 95wants to raise an event of that type. With the //TRIGGER// command, you can raise 96the preceding //EVENT()// just after **run_create()** finishes creating things; 97doing it to a list control's //SELECT// event is the natural way to make other 98controls reflect initial selection in the list. Some commands that create 99controls, have //EVENT()// built in, some even two of them; for them, function 100references go as parameters to the commands. A //TRIGGER// command after a 101two-event control triggers its second builtin //EVENT()//. 102 103When you need to, say, hide a control, you pass address of its slot to 104**cmd_showhide()**. To get that address, you put a //REF()// command right before 105the command that creates the control. //REF()//, again, has a memory reference 106(to a field of type **void**** ; for a variable, you use //REFv()//); into that 107memory, **run_create()** will put the current position in the "tape". 108 109For a container widget, you create it with a command such as //VBOX//, and 110everything you create after it will go into it, till you close it with //WEND//. 111One-place containers, such as //FRAME()//, close by themselves after accepting a 112widget (or you can close them by //WEND// leaving them empty). One command can 113also create more than one container; //DOCK()// has two panes, each filled 114separately and finished by its own //WEND//. 115 116Most container widgets do not get slots of their own, but are fill-and-forget. If 117you need to interact with them, say hide a box with all its contents, you need a 118version with a slot; those are tagged with "r", like //VBOXr// vs //VBOX//. 119 120When you want to include some commands only if a condition holds (say, with an 121RGB image you offer to select red, green, or blue channel, and with indexed ones 122you don't), you can use simple conditionals //IF()// and //UNLESS()//, affecting 123one command, or extended ones //IFx()// and //UNLESSx()// that affect everything 124till the matching //ENDIF()//. They get a memory reference (to an **int**), and 125check it for being zero or nonzero. 126 127When you need to allocate some memory (say, a buffer for a histogram image to be 128displayed), you use the //TALLOC()// command; it takes two fields - from one it 129takes the size, into the other it puts the resulting pointer. Such memory is 130allocated as part of the same memory block that holds the struct and the "tape", 131so if there isn't enough memory for it, then nothing at all gets allocated and 132**run_create()** itself fails (returning NULL). 133 134If you put a pointer to some separately allocated object into the struct, you can 135even tell **run_destroy()** to free it along with everything else; for that, you 136use the //CLEANUP()// command. 137 138A complete command sequence is one that creates a self-contained interface 139element (usually a toplevel window, but not necessarily). There are two things 140required from it. It has to define something in where all the controls will go; 141a //WINDOW()//, //TOPVBOX// etc. And it has to terminate the sequence, telling 142**run_create()** what to do with it; use //WDIALOG()// command to run it as a 143dialog, //WSHOW// to show it to the user, or //WEND// to hand it off to the 144program to be shown later. 145 146 147== V-code as written == 148 149Declarative V-code is an array of pointers to void: 150 151**void *whatever_code[] = { ... };** 152 153The array is initialized by a sequence of command macros, with their parameters. 154In case the commands are referring to **ddata** fields, the struct type to use 155must be set before that, as the //WBbase// macro: 156 157**#define WBbase whatever_dd** 158 159So nearly all V-code chunks in mtPaint look like this: 160``` 161#define WBbase whatever_dd 162void *whatever_code[] = { ... }; 163#undef WBbase 164``` 165 166In a simplest case, one V-code chunk creates something from beginning to end, but 167there are also other possibilities. 168 169The most complex part of mtPaint, the main window, is defined part by part in 170several chunks in several source files, which the main chunk, fittingly named 171**main_code[]**, calls one by one using the //CALL()// command; some then call 172yet other chunks in their turn. 173 174The least complex parts, the lowly filter windows, use a reverse approach; a 175small filter-specific code chunk which is a V-code subroutine, indirectly called 176(with //CALLp()// command) by **filterwindow_code[]** chunk between it building 177the generic top part and the equally generic bottom part of the window. 178 179 180== In-memory structure == 181 182The memory block allocated by **run_create_()** is structured this way: 183 184| ddata | User-provided backing struct | 185| vdata | Internal window-info struct | 186| wdata | "Tape" of "slots" referring to widgets, events, etc. | 187| dtail | Extra memory allocated to widgets and to/by other V-code commands | 188 189All this is allocated as one single block, which not only greatly simplifies 190memory management, but also, with all references to anything of note sitting in a 191flat array of "slots", makes all kinds of reflection trivial. This is by virtue 192of V-code being processed in two passes; first, **predict_size()** counts how 193many "slots" and how much extra memory the V-code sequence wants, then memory for 194all that is allocated and partitioned up, the user-provided struct copied in, and 195only then the commands actually get executed one after another; creating and 196setting up widgets, taking up chunks of dtail area, and filling "slots". 197 198A canonical reference to a block is the address of its **wdata**; i.e. it points 199into middle of the block. The reason for that is purely historical; nothing 200prevents setting up **ddata** and **vdata** after **dtail** area instead, but 201given that a block should never be deallocated in any other way than by calling 202**run_destroy()**, the arrangement is not relevant to anything. 203 204A "slot" in **wdata** consists of 3 pointers: 205| 0 | Widget/something else | 206| 1 | V-code command that set up the slot | 207| 2 | Dtail chunk | 208 209Slot where "something else" is its **dtail** chunk (i.e. 0th cell equals 2nd) is 210considered "unreal"; such slots are set up by pseudo-widgets used to simulate 211real ones when running scripts, thus the name. With the V-code command obviously 212being the same in either case (real and simulated), this is the only way to tell 213the two apart. 214 215The first slot of **wdata** is a fake one, used for linking all this together: 216| 0 | **ddata** | 217| 1 | **vdata** | 218| 2 | Dtail chunk | 219The **vdata** structure masquerades as a V-code command //WDONE//; as no regular 220//WDONE// gets a slot of its own, the slot is thus unique. The **wdata_slot()** 221function just steps through the "tape" before a slot till it finds this marker, 222and returns its address. 223 224The second slot must belong to a toplevel widget. No other thing should be put 225into the "tape" before it. 226 227And the last slot in **wdata**, marking its end, is all NULLs; all functions 228iterating over slots, depend on it being there. //WEND//, //WSHOW// and 229//WDIALOG()// put it into the "tape", before doing all other finishing touches. 230 231Macro **GET_DDATA()** gets from **wdata** to **ddata** (just reads the 0th cell 232of the first slot). The macro GET_VDATA(), internal to vcode.c, gets from 233**wdata** to **vdata** (by reading the 1st cell). 234 235 236== Structure of V-codes == 237 238As said above, V-code is an array of pointers to void. The array contains a 239sequence of commands - each consisting of one or more pointer values: an 240instruction header, and a specified number of parameters. 241 242The parameters can be either constants, or memory references. The latter may be 243either addresses of globals (string constants, variables, cells in global arrays, 244functions), or offsets in **ddata** struct, of the type designated by the 245//WBbase// macro. Encoding the field references is done with the //WBfield()// 246macro: 247 248**..., WBfield(field), ...** 249 250Other things are encoded as per usual; variables with the "&" operator, strings, 251arrays and functions as is, constants with a "(void *)" cast: 252 253**&(variable), "string", array, array + 2, function, (void *)1** 254 255The responsibility of a high-level command macro is to pack its parameters in the 256way and order that the underlying instruction code expects them. Like this: 257 258**OKBTN(_("OK"), conf_done)** 259 260translates to this: 261 262**WBr2h_x(OKBTN, 1 + 2), (_("OK")), EVENT(OK, conf_done)** 263 264Here you see a command macro expanding into an instruction header macro, a string 265constant (wrapped in a no-op translation marker), and a nested command macro 266which in its turn expands to another header and a function constant: 267 268**WBrh(EVT_OK, 1), (conf_done)** 269 270Instruction headers are in fact 31-bit integer values, to be able to comfortably 271reside in a pointer on a 32-bit system, and to avoid the signed/unsigned hassle. 272As of mtPaint 3.50, the bits are allocated this way: 273 274|| Bits | Function | Values | 275| 0-11 | Instruction code | op_* | 276| 12-15 | Packing mode | pk_* | 277| 16-17 | Number of slots | WB_REF* | 278| 18 | Indirection flag | WB_NFLAG | 279| 19 | Field flag | WB_FFLAG | 280| 20 | Script flag | WB_SFLAG | 281| 21-23 | Reserved | 0 | 282| 24-30 | Number of parameters | 0-127 | 283 284 285The number of parameters is how many pointers after the header are part of the 286command in question; i.e. how many to skip to get to the next header. In the 287example above it is 1 + 2: 1 for the string, and 2 more for the nested 288//EVENT()// command (which in its own header has 1, for the function). 289 290The first pointer after the header (given the number of parameters is nonzero) is 291intended to be interpreted as pointer to data; this is in no way a hard 292requirement, and many instructions use it for constants instead, but the prologue 293code in V-code functions pre-interprets this field in accordance to field flag and 294indirection flag, so if an instruction refers to in-memory data, it is easiest to 295place the most used (or only) location in there. 296 297- Initially, the first pointer is read as, well, a pointer (and by default, left 298unmodified); 299- With the field flag on, it is reinterpreted as an integer offset from the start 300of **ddata**, and the current **ddata** base address gets added to it; 301- With the indirection flag on, it is interpreted as a pointer to a pointer, and 302that pointer is read in. 303 304 305The script flag, if set, selects nondefault scripting-related behaviour for some 306few commands (specifics depend on command). Not even looked at for all the rest 307of them. 308 309The number of slots (from 0 to 3) tells //run_create_()// how many slots in the 310"tape" this command needs. The first slot refers to the command itself, the 311second and third are set up for its builtin //EVENT()// subcommands (each one a 312pair of pointers at end of the parameters area). A command not taking any slots, 313is executed and forgotten; this fits the widgets that do not need any interaction 314(such as most containers) and modifier commands. The example command above takes 315two slots; it is what the "r2" in its header macro means. The //EVENT// command 316on its own takes one, thus the plain "r" in its. 317 318The packing mode denotes how the widget the command creates should be packed into 319its container, in case the container supports this mode of packing. The small 320assortment of choices is this: 321 322| pk_NONE | not intended to be packed (modifier, event, etc.) | 323| pk_PACK | from beginning of container, not expanding | 324| pk_XPACK | from beginning, expanding | 325| pk_EPACK | from end, expanding | 326| pk_PACKEND | from end, not expanding | 327| pk_TABLE1x | into first free cell in first/second column of a table, not expanding | 328| pk_TABLE | into specified row and column(s) of a table, not expanding | 329| pk_TABLEx | into specified row and column(s) of a table, expanding | 330 331- //pk_PACK// and //pk_XPACK// are allowed for any kind of container, other modes 332require a matching container type. 333- //pk_TABLE// and //pk_TABLEx// take an extra pointer value, from the very end 334of command's parameters, and interpret it as 3 byte values denoting X, Y, and 335length, as packed by the //WBxyl()// macro. Like in this command macro for a 336horizontal box that can take several table columns: 337**#define TLHBOXl(X,Y,L) WBh_t(HBOX, 1), WBxyl(X, Y, L)** 338 339 340Returning to the example, //OKBTN()// command does //pk_XPACK//, as denoted by 341the "_x" in its header macro; the //EVENT()// command does //pk_NONE//, as 342denoted by the lack of "_" in its. 343 344And finally, the instruction code tells //run_create_()// what to do with it all 345(and later, is used to recognize the objects to which the slots in the "tape" 346refer). In the example, it is //op_OKBTN// for the command itself, and 347//op_EVT_OK// for its builtin //EVENT()// command. 348 349On the preprocessor side of things, instruction codes are assembled in stages. 350First, a set of macros is used as shorthand representations for every combination 351of flags and slots that ever arises in some command. For example, //WB_R2F// 352denotes two slots asked for, and the field flag set: 353 354**#define WB_R2F (WB_REF2 + WB_FFLAG)** 355 356Then goes the basic macro encoding the instruction header: //WBp_()//, taking 357instruction code, length, packing mode, and a flags and slots combination. 358However, for brevity, actual command macros use one of the many pre-encoded 359//WB*h*()// macros that need take only instruction name and length. Like the one 360from the example: 361 362**#define WBr2h_x(NM,L) WBp_(op_##NM, L, XPACK, R2)** 363 364In these macros, the part between "WB" and "h" denotes the slots and flags, and 365the part after "h", packing mode. 366 367Additionally, there is a set of helper macros that some commands use to pack two 368byte values into a single pointer: //WBwh()//, //WBnh()//, and //WBbs()//; the 369difference is purely semantic, they do the same thing. And another set for three 370values: //WBpbs()// and //WBppa()//, again doing the same. 371 372 373== V-code commands == 374 375All high-level command macros are listed below. The list is not final, for new 376commands can be derived from opcodes and lower-level macros any time when existing 377combinations of parameters do not cover a new use case. 378 379In the descriptions below, unless noted differently, the string parameters are 380constants or global **char** arrays, the numeric parameters are constants. 381 382Packing mode for the commands producing widgets (controls and containers), 383unless noted differently, is the default one, //pk_PACK//. 384 385Naming guidelines (not 100% followed) for the macros: 386- "**u**" prefixed to "unreal" (script-only, simulated) version of a widget: 387 //uSPIN()// 388- "**a**" affixed to a version that takes an array instead of several constant 389 parameters: //TSPINa()// 390- "**c**" affixed to a version that is centered: //MLABELc()// 391- "**e**" affixed to a version that has a builtin event: //RPACKe()// 392- "**p**" affixed to a version that takes string parameter by reference instead 393 of a string constant: //WINDOWp()// 394- "**r**" affixed to a version that has a slot in the "tape": //VBOXr// 395- "**s**" affixed to a version that is scriptable: //MENUITEMs()// 396- "**v**" affixed to a version that refers to a variable/array instead of a field: 397 //CSCROLLv()// 398- "**x**" affixed to a version that has extra parameters: //TLABELx()// 399- "**T**" or "**T1**" prefixed to a version packed in first/second table column: 400 //TLABEL()//, //TSPIN()//, //T1SPIN()// 401- "**TL**" prefixed to a version packed into table at (//x, y//): //TLLABEL()// 402- "**TL...l**" circumfixed to a version packed into table at (//x, y//) 403 taking //length// cells: //TLLABELl()// 404- "**X**" prefixed to a version that is packed expanding: //XTABLE()// 405- "**F**" prefixed to a version that has a frame around: //FTABLE()// 406 407 408=== Finalizers === 409 410All these commands finish element creation and cause **run_create()** to return. 411They differ in what else they do between those two points. 412 413: //WDONE// : 414 do nothing extra 415: //WSHOW// : 416 show the toplevel 417: //WDIALOG(field)// : 418 show, then process input till the **void**** field changes to non-NULL 419 420 421=== Toplevels === 422 423All toplevels are one-place containers, unless noted differently. All have a slot 424in the "tape" (and extra slots for builtin events, if have any). 425 426: //MAINWINDOW(title, icon, width, height)// : 427 program's main window, with specified title, XPM icon, default width and height 428: //WINDOW(title)// : 429 a regular non-modal window with specified title 430: //WINDOWp(field)// : 431 as above, with title passed in a **char*** field 432: //WINDOWm(title)// : 433 a regular modal window with title 434: //WINDOWpm(field)// : 435 as above, with title in a **char*** field 436: //DIALOGpm(field)// : 437 a modal dialog, with title in a **char*** field; is a double container: the top 438 (the first accessible) is dialog's "content area" (a vertical box), the 439 bottom/second is its "action area" (the one with buttons, a horizontal box) 440: //FPICKpm(title_field, mode_field, filename_field, OK_handler, CANCEL_handler)// : 441 a file selector window, with **char*** title, **int** mode, and **char[]** 442 filename (in system encoding) in fields, and handlers for //OK// and //CANCEL// 443 events; is a box container (horizontal) for extra controls 444: //POPUP(title)// : 445 a popup window with specified title (which, while not shown, is still useful for 446 identifying the window in window manager's lists) 447: //TOPVBOX// : 448 a pseudo-toplevel, for elements created to sit in //MOUNT// containers or purely 449 for scripting; is a box container (vertical) 450: //TOPVBOXV// : 451 same thing but with different sizing: fills space vertically, but horizontally 452 is only centered, not stretched 453: //IDENT(id)// : 454 set a non-default identifying string for the toplevel; is needed when one 455 toplevel has separate V-code descriptions for different parts: the case in point 456 is file selector, where the //FPICKpm()// command builds its fixed part through 457 a nested **run_create()** using an //IDENT()// 458 459 460=== Containers === 461 462Table containers have a border area by default; its size can be set by 463//BORDER(TABLE)// (see "Sizing and placement" category below). Other containers 464do not, unless specifically noted. 465 466: //WEND// : 467 close the current container 468: //TABLE(columns, rows)// : 469 a table of given dimensions (those currently are initial, not a hard limit) 470: //TABLE2(rows)// : 471 a two-column table 472: //TABLEs(columns, rows, spacing)// : 473 a table with specified spacing (same for rows and columns) 474: //TABLEr(columns, rows)// : 475 a table that gets a slot in the "tape" 476: //XTABLE(columns, rows)// : 477 a table that is packed expanding (//pk_XPACK//) 478: //ETABLE(columns, rows)// : 479 a table that is packed from the end (//pk_PACKEND//) 480: //VBOX// : 481 a vertical box 482: //VBOXr// : 483 a vertical box with slot in the "tape" 484: //VBOXbp(spacing, border, padding)// : 485 a vertical box with specified spacing, border, and padding 486: //VBOXP// : 487 a vertical box with padding of default size (5 pixels) 488: //VBOXB// : 489 a vertical box with border of default size (5 pixels) 490: //VBOXS// : 491 a vertical box with spacing of default size (5 pixels) 492: //VBOXPS// : 493 a vertical box with padding and spacing of default size (5 pixels each) 494: //VBOXBS// : 495 a vertical box with border and spacing of default size (5 pixels each) 496: //VBOXPBS// : 497 a vertical box with padding, border and spacing of default size (5 pixels each) 498: //XVBOX// : 499 a vertical box that is packed expanding 500: //XVBOXbp(spacing, border, padding)// : 501 same, with specified spacing, border, and padding 502: //XVBOXP// : 503 a vertical box, packed expanding, with default padding 504: //XVBOXB// : 505 a vertical box, packed expanding, with default border 506: //XVBOXBS// : 507 a vertical box, packed expanding, with default border and spacing 508: //EVBOX// : 509 a vertical box, packed from the end 510: //HBOX// : 511 a horizontal box 512: //HBOXbp(spacing, border, padding)// : 513 a horizontal box with specified spacing, border, and padding 514: //HBOXP// : 515 a horizontal box, with default padding 516: //HBOXPr// : 517 same, with slot in the "tape" 518: //HBOXB// : 519 a horizontal box, with default border 520: //XHBOX// : 521 a horizontal box, packed expanding 522: //XHBOXbp(spacing, border, padding)// : 523 same, with specified spacing, border, and padding 524: //XHBOXP// : 525 a horizontal box, packed expanding, with default padding 526: //XHBOXS// : 527 a horizontal box, packed expanding, with default spacing 528: //XHBOXBS// : 529 a horizontal box, packed expanding, with default border and spacing 530: //TLHBOXl(x, y, length)// : 531 a horizontal box, packed into //length// columns in a table, starting at 532 column //x//, row //y// 533: //TLHBOXpl(x, y, length)// : 534 same, with default padding 535: //EQBOX// : 536 a horizontal box with equal space allocated to contents 537: //EQBOXbp(spacing, border, padding)// : 538 same, with specified spacing, border, and padding 539: //EQBOXP// : 540 a horizontal box with equal space, with default padding 541: //EQBOXB// : 542 a horizontal box with equal space, with default border 543: //EQBOXS// : 544 a horizontal box with equal space, with default spacing 545: //EEQBOX// : 546 a horizontal box with equal space, packed from the end 547 548 549==== Frames ==== 550 551Frames have an empty border area around them by default, its size can be set by 552//BORDER(FRAME)//. A container sitting inside a frame can also have a border of 553its own, even if both are created by one command. 554 555: //FRAME(name)// : 556 a frame with specified name 557: //XFRAME(name)// : 558 same, packed expanding 559: //XFRAMEp(field)// : 560 a frame, packed expanding, with name passed in a **char*** field 561: //EFRAME// : 562 a frame without name, with an "etched out" look 563: //FTABLE(name, columns, rows)// : 564 a table of given dimensions sitting in a named frame 565: //FVBOX(name)// : 566 a vertical box sitting in a named frame 567: //FVBOXB(name)// : 568 a vertical box in a named frame, with default border 569: //FVBOXBS(name)// : 570 a vertical box in a named frame, with default border and spacing 571: //FXVBOX(name)// : 572 a vertical box in a named frame, packed expanding 573: //FXVBOXB(name)// : 574 same, with default border 575: //EFVBOX// : 576 a vertical box with twice the default border (10 pixels), sitting in an 577 "etched out" nameless frame 578: //FHBOXB(name)// : 579 a horizontal box in a named frame, with default border 580 581 582==== Scrolling ==== 583 584Scrolling containers have a default border area: //BORDER(SCROLL)//. 585 586: //SCROLL(horiz_mode, vert_mode)// : 587 a scrolling container, with display modes for its horizontal and vertical 588 scrollbar: 0 - do not show, 1 - show when needed, 2 - show always 589: //XSCROLL(horiz_mode, vert_mode)// : 590 same, packed expanding 591: //FSCROLL(horiz_mode, vert_mode)// : 592 a scrolling container in an unnamed frame, packed expanding 593: //CSCROLLv(array)// : 594 a scrolling container acting as a control: with its own slot, and with 595 horizontal and vertical positions read into/reset from **int[2]** array 596 (zeroed out by **run_create()**); horizontal and vertical scrollbars are shown 597 when needed 598 599 600==== Notebook ==== 601 602Regular notebook widgets have a default border area: //BORDER(NBOOK)//. 603 604: //NBOOK// : 605 a notebook with tabs on top, packed expanding; is a container for //PAGE//'s 606: //NBOOKr// : 607 same, with a slot in the "tape" 608: //NBOOKl// : 609 a notebook with tabs on the left, packed expanding 610: //PAGE(name)// : 611 a page for a notebook, with a name; is a box container (vertical) 612: //PAGEvp(var)// : 613 same, with name passed in a **char*** variable 614: //PAGEi(icon, spacing)// : 615 a page for a notebook, with an icon instead of name, and specified spacing 616: //PAGEir(icon, spacing)// : 617 same, with a slot in the "tape" 618: //PLAINBOOK// : 619 a "notebook" without any visible trappings, just to show either of two boxes in 620 same place; has a slot in the "tape", through which to command it to switch 621 pages; is a double container - page 0 is the top, all pages vertical boxes 622: //PLAINBOOKn(num_pages)// : 623 same but with specified number of pages (3 or more); a multiple container, page 624 0 is the top 625: //BOOKBTN(name, field)// : 626 a toggle button with a name, for switching pages of a //PLAINBOOK// whose slot 627 is in the **void**** field: show page 1 if toggled, page 0 if not 628 629 630==== Special ==== 631 632: //DOCK(ini_var_name)// : 633 a splitter adding a dock pane on the right, that can be hidden/shown; the 634 specified inifile variable (integer) holds the pane's width when it is shown; 635 has a slot in the "tape"; is a double container, with left (main) pane the top, 636 and dock pane the bottom, both panes are vertical boxes 637: //HVSPLIT// : 638 a splitter that can be switched between single-pane, horizontal, and vertical; 639 packed expanding, has a slot; is a container for two widgets, the first for 640 single/left/top pane, the second for hidden/right/bottom one; still needs 641 //WEND// after them 642: //VSPLIT// : 643 a regular vertical splitter, packed expanding, has a slot; a container for two 644 widgets, first is for the top pane, the second for the bottom, needs //WEND// 645 after them 646: //TWOBOX// : 647 a container for two widgets, holding them in one row if enough horizontal space, 648 or in two rows if not 649: //MOUNT(field, create_func, CHANGE_handler)// : 650 a container holding and "leasing" an element created by a specified **mnt_fn** 651 function (returns **wdata**), with **int** field set to TRUE while holding it, 652 and a handler for //CHANGE// event, triggered when leasing/unleasing; has a 653 slot for itself and another for the event 654: //PMOUNT(field, create_func, CHANGE_handler, ini_var_name, def_height)// : 655 same, but with the element held in a resizable vertical pane with specified 656 default height, with specified inifile variable (integer) storing modified 657 height 658: //REMOUNTv(var)// : 659 a container that, when created, "leases" the element from the //MOUNT// whose 660 slot is in the **void**** variable, and when destroyed, returns it back; is 661 packed expanding, has a slot 662: //HEIGHTBAR// : 663 a modifier that requests the max height of all the widgets following it in the 664 same container, whether visible or not; used to prevent jitter when those 665 widgets get shown/hidden later 666 667 668==== Statusbar ==== 669 670: //STATUSBAR// : 671 a statusbar, packed from the end, has a slot, is a box container (horizontal) 672: //STLABEL(width, align)// : 673 a statusbar label, with specified width and alignment: 0 - left, 1 - center, 674 2 - right; has a slot 675: //STLABELe(width, align)// : 676 same, packed from the end 677 678 679=== Separators === 680 681: //HSEP// : 682 a horizontal separator 683: //HSEPl(width)// : 684 same, with specified minimum width 685: //HSEPt// : 686 a thin (minimum height) horizontal separator 687 688 689=== Labels === 690 691All labels, when packed into boxes and tables, have padding by default; its size 692can be set by //BORDER(LABEL)//. Labels are left aligned by default. 693 694Labels identify adjacent controls to scripts, unless prevented from it or have no 695control to attach to. 696 697: //MLABEL(text)// : 698 a regular label with text 699: //MLABELr(text)// : 700 same, with a slot of its own 701: //MLABELc(text)// : 702 a centered label with text 703: //MLABELcp(field)// : 704 same, with text passed in a **char*** field 705: //MLABELxr(text, x_padding, y_padding, x_align)// : 706 a label with text, with specified extra horizontal and vertical padding, and 707 horizontal alignment at //x_align/10//: 0 - left, 5 - center, 10 - right; has 708 a slot 709: //MLABELpx(field, x_padding, y_padding, x_align)// : 710 same, but with text passed in a **char*** field, and without a slot of its own 711: //WLABELp(field)// : 712 a centered label with text passed in a **char*** field, packed expanding, 713 ignored by scripts 714: //XLABELcr(text)// : 715 a centered label with text, packed expanding, has a slot 716: //TLABEL(text)// : 717 a label with text, packed into the first free cell of the first column of a 718 table 719: //TLABELr(text)// : 720 same, with a slot of its own 721: //TLABELx(text, x_padding, y_padding, x_align)// : 722 same, with specified padding and alignment, and without a slot 723: //TLLABELl(text, x, y, length)// : 724 a label with text, packed into //length// columns in a table, starting at 725 column //x//, row //y// 726: //TLLABEL(text, x, y)// : 727 same, packed into one column 728: //TLLABELx(text, x, y, x_padding, y_padding, x_align)// : 729 same, with specified padding and alignment 730: //TLLABELxr(text, x, y, x_padding, y_padding, x_align)// : 731 same, with a slot of its own 732: //TLLABELp(field, x, y)// : 733 a label with text passed in a **char*** field, packed into a table at 734 column //x//, row //y// 735: //TLLABELpx(field, x, y, x_padding, y_padding, x_align)// : 736 same, with specified padding and alignment 737: //TXLABEL(text, x, y)// : 738 a label with text, packed expanding into a table at column //x//, row //y//, 739 aligned at 0.3 of its width 740: //HLABELp(field)// : 741 a helptext label with text passed in a **char*** field 742: //HLABELmp(field)// : 743 same with monospace font 744: //TLTEXT(text, x, y)// : 745 text, separated into columns by tabs and into rows by newlines, is placed into 746 a table starting at column //x//, row //y// 747: //TLTEXTf(field, x, y)// : 748 same, with text stored in a **char** array field 749: //TLTEXTp(field, x, y)// : 750 same, but with text passed in a **char*** field 751 752 753=== Image display === 754 755All widgets in this group have slots in the "tape". 756 757: //COLORPATCHv(rgb_array, width, height)// : 758 areа of specified size, filled with RGB color passed in an **unsigned char[3]** 759 array (or a string constant), packed expanding 760: //RGBIMAGE(image_field, w_h_array_field)// : 761 area of size passed in **int[2]** array field, displaying an image pointed to 762 by **unsigned char*** field 763: //TLRGBIMAGE(image_field, w_h_array_field, x, y)// : 764 same, packed into a table at column //x//, row //y// 765: //RGBIMAGEP(array_field, width, height)// : 766 area of specified size, displaying an image stored in **unsigned char[]** 767 array field 768: //CANVASIMGv(array, width, height)// : 769 framed canvas widget (one able to properly receive clicks, releases, and 770 movement, and efficiently handle scrolling) of specified size, displaying an 771 image stored in **unsigned char[]** array 772: //CCANVASIMGv(array, width, height)// : 773 same, packed from the end, expanding (//pk_EPACK//) 774: //CANVASIMGB(image_field, w_h_bkg_array_field)// : 775 framed canvas widget of minimum size passed in first 2 cells of **int[3]** array 776 field, displaying an image pointed to by **unsigned char*** field, and filling 777 the extra space, if any, with RGB color packed in an **int** in the cell 2 of 778 the **int[3]** array 779: //FCIMAGEP(image_field, x_y_array_field, w_h_array_field)// : 780 focusable widget displaying an image pointed to by **unsigned char*** field, 781 of size passed in **int[2]** array field, contoured by a frame, with a 782 ring-shaped location marker on it at coordinates given in another **int[2]** 783 array field 784: //TLFCIMAGEP(image_field, x_y_array_field, w_h_array_field, x, y)// : 785 same, packed into a table at column //x//, row //y// 786: //TLFCIMAGEPn(image_field, w_h_array_field, x, y)// : 787 same, but without a location marker 788: //CANVAS(init_width, init_height, cost, EXT_handler)// : 789 framed canvas widget of specified initial size, that triggers //EXT// event to 790 redraw an area (handled by an **evtxr_fn**); the //cost// value is defined as 791 how many pixels likely could be redrawn in the time needed to call the event 792 once more (i.e. its init+teardown cost), and is used for deciding whether to 793 redraw multiple subregions one by one, or their encompassing region once; has 794 a slot for itself and an extra one for the event 795 796 797The //EXT// handler of //CANVAS()// receives in its //xdata// parameter a pointer 798to **rgbcontext** (see mygtk.h). Its task is to render into the buffer there an 799RGB image of the denoted area of canvas, and return TRUE. 800 801 802=== Spinbuttons and spinsliders === 803 804All spinbuttons and spinsliders, when packed into boxes and tables, have padding 805by default; its size can be set by //BORDER(SPIN)// and //BORDER(SPINSLIDE)//. 806They all have slots in the "tape", unless specifically noted. 807 808: //NOSPINv(var)// : 809 displays an **int** variable in a non-modifiable spinbutton, has no slot 810: //TLNOSPIN(field, x, y)// : 811 displays an **int** field value in a non-modifiable spinbutton, packed into a 812 table at column //x//, row //y//, has no slot 813: //TLNOSPINr(field, x, y)// : 814 same but has a slot 815: //TLSPIN(field, min, max, x, y)// : 816 a spinbutton with **int** field, range //min// to //max//, packed into a table 817 at column //x//, row //y// 818: //TLXSPIN(field, min, max, x, y)// : 819 same, packed there expanding 820: //TLXSPINv(var, min, max, x, y)// : 821 same, with **int** variable 822: //T1SPIN(field, min, max)// : 823 a spinbutton with **int** field, packed into the first free cell of the second 824 column of a table 825: //TSPIN(text, field, min, max)// : 826 same combined with label that goes into the first column 827: //TSPINv(text, var, min, max)// : 828 same, with **int** variable 829: //TSPINa(text, array_field)// : 830 same, but with value, min and max in **int[3]** array field 831: //SPIN(field, min, max)// : 832 a spinbutton with **int** field, range //min// to //max// 833: //SPINv(var, min, max)// : 834 same, with **int** variable 835: //SPINc(field, min, max)// : 836 a spinbutton with **int** field, centering the value 837: //XSPIN(field, min, max)// : 838 a spinbutton with **int** field, packed expanding 839: //FSPIN(field, min, max)// : 840 a fixedpoint spinbutton with **int** field holding value * 100, range //min// 841 to //max// (both * 100) 842: //FSPINv(field, min, max)// : 843 same, with **int** variable 844: //TFSPIN(text, field, min, max)// : 845 a fixedpoint spinbutton with **int** field, packed into the second column of 846 a table, combined with label that goes into the first column 847: //FSPIN(field, min, max, x, y)// : 848 a fixedpoint spinbutton with **int** field, packed into a table at column //x//, 849 row //y// 850: //SPINa(array_field)// : 851 a spinbutton with value, min and max in **int[3]** array field 852: //XSPINa(array_field)// : 853 same, packed expanding 854: //uSPIN(field, min, max)// : 855 a script-only simulated spinbutton with **int** field, range //min// to //max// 856: //uSPINv(var, min, max)// : 857 same, with **int** variable 858: //uFSPINv(var, min, max)// : 859 same, but fixedpoint 860: //uSPINa(array_field)// : 861 a script-only simulated spinbutton with value, min and max in **int[3]** array 862 field 863: //uSCALE(field, min, max)// : 864 a script-only simulated spinbutton with **int** field, with extended syntax: 865 interprets values like "x1.5" as "original value multiplied by 1.5" 866: //TLSPINPACKv(array, count, CHANGE_handler, width, x, y)// : 867 a grid of //count// spinbuttons arranged in //width// columns, packed into a 868 table starting at column //x//, row //y//, with values, min and max for each in 869 **int[][3]** array which is automatically updated when any of values changes, 870 with a handler for //CHANGE// event that is triggered after (handled by an 871 **evtx_fn**); has a slot for itself and another for the event 872: //T1SPINSLIDE(field, min, max)// : 873 a spinslider with **int** field, range //min// to //max//, packed into the first 874 free cell of the second column of a table, with preset size (255 x 20 pixels) 875: //TSPINSLIDE(text, field, min, max)// : 876 same combined with label that goes into the first column 877: //TSPINSLIDEa(text, array_field)// : 878 same, but with value, min and max in **int[3]** array field 879: //TLSPINSLIDE(field, min, max, x, y)// : 880 a spinslider with **int** field, packed into a table at column //x//, row //y// 881: //TLSPINSLIDEvs(var, min, max, x, y)// : 882 same, with **int** variable and preset width (150 pixels) 883: //TLSPINSLIDExl(field, min, max, x, y, length)// : 884 a spinslider with **int** field, packed expanding into //length// columns in a 885 table, starting at column //x//, row //y// 886: //TLSPINSLIDEx(field, min, max, x, y)// : 887 same, packed into one column 888: //SPINSLIDEa(array_field)// : 889 a spinslider with value, min and max in **int[3]** array field 890: //XSPINSLIDEa(array_field)// : 891 same, packed expanding 892 893 894The //CHANGE// handler of //TLSPINPACKv()// receives in its //xdata// parameter 895an **int** index of the spinbutton that changed, cast into **void***. 896 897 898=== Checkbuttons === 899 900All checkbuttons have a default border area: //BORDER(CHECK)//. They all have 901slots in the "tape". 902 903: //CHECK(name, field)// : 904 a named checkbutton with **int** field 905: //CHECKv(name, var)// : 906 same, with **int** variable 907: //CHECKb(name, field, ini_var_name)// : 908 a named checkbutton with **int** field, with specified inifile variable 909 (integer) storing its value 910: //XCHECK(name, field)// : 911 a named checkbutton with **int** field, packed expanding 912: //TLCHECKl(name, field, x, y, length)// : 913 same, packed into //length// columns in a table, starting at column //x//, 914 row //y// 915: //TLCHECK(name, field, x, y)// : 916 same, packed into one column 917: //TLCHECKvl(name, var, x, y, length)// : 918 a named checkbutton with **int** variable, packed into //length// columns in a 919 table, starting at column //x//, row //y// 920: //TLCHECKv(name, var, x, y)// : 921 same, packed into one column 922: //uCHECK(name, field)// : 923 a script-only simulated named checkbutton with **int** field 924: //uCHECKv(name, var)// : 925 same, with **int** variable 926 927 928=== Radiobutton packs === 929 930All radiobutton packs have a default border area: //BORDER(RPACK)//. They all have 931slots in the "tape", those with a builtin event have an extra slot for the event. 932 933: //RPACK(names_array, count, height, field)// : 934 a box of radiobuttons with **int** field that stores the index of the active 935 one, with names in **char*[]** array, //count// of them in total (0 if array of 936 names is NULL-terminated), arranged in columns of no more than //height// (0 if 937 all in a single column), packed expanding 938: //RPACKv(names_array, count, height, var)// : 939 same, with **int** variable 940: //FRPACK(frame_name, names_array, count, height, field)// : 941 a box of radiobuttons with **int** field, sitting in a named frame 942: //FRPACKv(frame_name, names_array, count, height, var)// : 943 same, with **int** variable 944: //RPACKe(names_array, count, height, field, SELECT_handler)// : 945 a box of radiobuttons with **int** field and a handler for //SELECT// event, 946 packed expanding 947: //FRPACKe(frame_name, names_array, count, height, field, SELECT_handler)// : 948 same, sitting in a named frame 949: //RPACKD(names_field, height, field)// : 950 a box of radiobuttons with **int** field, with **char**** field pointing to a 951 NULL-terminated **char*[]** array of names, packed expanding 952: //RPACKDv(names_field, height, var)// : 953 same, with **int** variable 954: //RPACKDve(names_field, height, var, SELECT_handler)// : 955 same, with a handler for //SELECT// event 956 957 958In case a radiobutton's name is an empty string, the corresponding index is just 959skipped. 960 961 962=== Option menus and comboboxes === 963 964All option menus and comboboxes have a default border area: //BORDER(OPT)//. They 965all have slots in the "tape", those with a builtin event have an extra slot for 966the event. 967 968: //OPT(names_array, count, field)// : 969 an option menu with **int** field, with list of choices' names in **char*[]** 970 array, //count// of them in total (0 if array of choices is NULL-terminated) 971: //OPTv(names_array, count, var)// : 972 same, with **int** variable 973: //TOPTv(text, names_array, count, var)// : 974 same, packed into the second column of a table, combined with label that goes 975 into the first column 976: //TLOPT(names_array, count, field, x, y)// : 977 an option menu with **int** field, packed into a table at column //x//, 978 row //y// 979: //TLOPTv(names_array, count, var, x, y)// : 980 same, with **int** variable 981: //OPTe(names_array, count, field, SELECT_handler)// : 982 an option menu with **int** field and a handler for //SELECT// event 983: //OPTve(names_array, count, var, SELECT_handler)// : 984 same, with **int** variable 985: //XOPTe(names_array, count, field, SELECT_handler)// : 986 an option menu with **int** field and a handler for //SELECT// event, packed 987 expanding 988: //TLOPTle(names_array, count, field, SELECT_handler, x, y, length)// : 989 same, packed into //length// columns in a table, starting at column //x//, 990 row //y// 991: //TLOPTvle(names_array, count, var, SELECT_handler, x, y, length)// : 992 same, with **int** variable 993: //TLOPTve(names_array, count, var, SELECT_handler, x, y)// : 994 same, packed into one column 995: //OPTD(names_field, field)// : 996 an option menu with **int** field, with **char**** field pointing to a 997 NULL-terminated **char*[]** array of choices' names 998: //XOPTD(names_field, field)// : 999 same, packed expanding 1000: //TOPTDv(text, names_field, field)// : 1001 same with **int** variable, packed into the second column of a table, combined 1002 with label that goes into the first column 1003: //OPTDe(names_field, field, SELECT_handler)// : 1004 an option menu with **int** field, **char**** field pointing to choices' names, 1005 and a handler for //SELECT// event 1006: //XOPTDe(names_field, field, SELECT_handler)// : 1007 same, packed expanding 1008: //TOPTDe(text, names_field, field, SELECT_handler)// : 1009 same, packed into the second column of a table, combined with label that goes 1010 into the first column 1011: //COMBO(names_array, count, field)// : 1012 a combobox with **int** field, with list of choices' names in **char*[]** 1013 array, //count// of them in total (0 if array of choices is NULL-terminated) 1014: //PCTCOMBOv(var, array, CHANGE_handler)// : 1015 a combobox displaying percent zoom values, with **int** variable, an **int[]** 1016 array (0-terminated) of some values, and a handler for //CHANGE// event; has no 1017 border 1018 1019 1020In case a choice's name is an empty string, the corresponding index is just 1021skipped. 1022 1023 1024=== Specialized controls === 1025 1026All widgets in this group have slots in the "tape", those with a builtin event 1027have an extra slot for the event. 1028 1029: //PROGRESSp(text_field)// : 1030 a progressbar, with text for it passed in a **char*** field 1031: //GRADBAR(chan_field, idx_field, len_field, max, map_array_field, cmap_array_field, SELECT_handler)// : 1032 a "gradient bar" for displaying and selecting points in a gradient, with 1033 currently selected index in **int** //idx_field//, gradient's length in 1034 //len_field//, gradient's channel in **int** //chan_field//, colormap for 1035 non-RGB cases in **unsigned char[768]** //cmap_array_field//, gradient's 1036 values/colors at points in **unsigned char[]** //map_array_field//, and a 1037 handler for //SELECT// event 1038: //KEYBUTTON(field)// : 1039 a button for choosing key combos, with **char*** field where it places keyname 1040 string 1041: //TABLETBTN(name)// : 1042 a named button for calling up tablet configuration dialog 1043: //FONTSEL(array_field)// : 1044 a font chooser, with font description string and the text to render in a 1045 **char*[2]** array field, packed expanding 1046: //EYEDROPPER(field, CHANGE_handler, x, y)// : 1047 a button calling up eyedropper, with color it picked up in an **int** field, and 1048 a handler for //CHANGE// event, packed into a table at column //x//, row //y// 1049: //COLOR(array_field)// : 1050 a color chooser for opaque colors, with RGBA in **unsigned char[4]** array field 1051: //TCOLOR(array_field)// : 1052 same for colors with alpha 1053 1054 1055=== Lists === 1056 1057The //LISTCC*// widgets have a default border area: //BORDER(LISTCC)//. All list 1058widgets and columns have slots in the "tape", those with a builtin event have an 1059extra slot for the event, those with two, extra two slots. 1060 1061: //COLORLIST(names_field, idx_field, rgb_array_field, SELECT_handler, EXT_handler)// : 1062 a list of named colors, with currently selected index in **int** field, a 1063 **char**** field pointing to a NULL-terminated **char*[]** array of names, 1064 colors themselves in **unsigned char[]** array field, a handler for //SELECT// 1065 event, and a handler for //EXT// event (an **evtx_fn**) 1066: //COLORLISTN(cnt_field, idx_field, rgb_array_field, SELECT_handler, EXT_handler)// : 1067 same for numbered colors, with count of them in **int** field 1068: //LISTCCHr(idx_field, len_field, max, SELECT_handler)// : 1069 a simpler (headerless, unsorted) columned list, with index and length (dynamic, 1070 limited to //max// items) in **int** fields, and a handler for //SELECT// event 1071: //LISTCCHr(idx_field, len_field, SELECT_handler)// : 1072 same with static (unchanging) length 1073: //LISTC(idx_field, len_field, SELECT_handler)// : 1074 a complex (with column headers and sorting) columned list, with index and length 1075 in **int** fields, and a handler for //SELECT// event 1076: //LISTCu(idx_field, len_field, SELECT_handler)// : 1077 same, unsorted 1078: //LISTCd(idx_field, len_field, SELECT_handler)// : 1079 same, with draggable rows 1080: //LISTCS(idx_field, len_field, sortmode_field, SELECT_handler)// : 1081 a complex columned list, with selectable sort column and direction; the sort 1082 mode in **int** field is column+1 if sorted ascending, and the same negated if 1083 descending 1084: //LISTCX(idx_field, len_field, sortmode_field, map_field, SELECT_handler, EXT_handler)// : 1085 same, with user-resizable columns and filtering: **int**** field points to 1086 mapping array (row indices to display, in order; also used for sorting); and 1087 with a handler for //EXT// event (an **evtx_fn**) 1088 1089 1090Index in //LISTC()// and its brethren refers to raw (unsorted and unfiltered) 1091data. The //EXT// handler of //LISTCX()// is triggered by right click on a row, 1092and receives in its //xdata// parameter an **int** index of that row. 1093 1094The //EXT// handler of //COLORLIST()// and //COLORLISTN()// is triggered by click 1095on a color, and receives in its //xdata// parameter a pointer to **colorlist_ext**. 1096 1097The columns of a columned list sit between //WLIST// command and the list itself, 1098and describe what, how, and where from goes into each. They can refer either to 1099an array, or to a structure and a field in it; if the latter, the //COLUMNDATA()// 1100command is needed, describing an array of those structures. 1101 1102: //WLIST// : 1103 start a group of columns 1104: //COLUMNDATA(field, step)// : 1105 set a **void*** field as pointer to the array of data structures for columns in 1106 this group 1107: //IDXCOLUMN(init, step, width, align)// : 1108 add a column of indices, starting at //init// and changing by //step//, 1109 //width// pixels wide, aligned per //align//: 0 - left, 1 - center, 2 - right 1110: //TXTCOLUMNv(array, step, width, align)// : 1111 add a column of text strings from **char[]** array (buffers, not pointers), with 1112 specified step, width and alignment 1113: //XTXTCOLUMNv(array, step, width, align)// : 1114 same, expanding 1115: //NTXTCOLUMNv(name, array, step, width, align)// : 1116 add a column of text strings from **char[]** array, with column name/title 1117: //NTXTCOLUMND(name, struct_type, struct_field, width, align)// : 1118 same, from a **char[]** array field (buffer) in //COLUMNDATA// 1119: //PTXTCOLUMN(array_field, step, width, align)// : 1120 add a column of text strings from **char*[]** array field (pointers) 1121: //PTXTCOLUMNp(field, step, width, align)// : 1122 same, from **char*[]** array pointed to by //field// 1123: //RTXTCOLUMNDi(width, align)// : 1124 add a column of text strings relative to elements of **int[]** array that is 1125 //COLUMNDATA//: each element holds an offset **from itself** to the string 1126: //RTXTCOLUMND(struct_type, struct_field, width, align)// : 1127 same, relative to **int** field in //COLUMNDATA// 1128: //NRTXTCOLUMND(name, struct_type, struct_field, width, align)// : 1129 same, with column name/title 1130: //NRTXTCOLUMNDax(name, index, width, align, ini_var_name)// : 1131 same, relative to //index//-th element of **int[]** sub-array in //COLUMNDATA//, 1132 with inifile variable (integer) storing modified width 1133: //NRTXTCOLUMNDaxx(name, index, width, align, ini_var_name, test_string)// : 1134 same, at least wide enough for //test_string// 1135: //NRFILECOLUMNDax(name, index, width, align, ini_var_name)// : 1136 add a column of filenames relative to element of sub-array: the 0th character 1137 denotes the type: 'F' for file, 'D' for directory, ' ' for ".." 1138: //CHKCOLUMNv(array, step, width, align, CHANGE_handler)// : 1139 add a column of checkbuttons from **int[]** array, with a handler for //CHANGE// 1140 event (an **evtxr_fn**) 1141 1142 1143The //CHANGE// handler of //CHKCOLUMNv()// receives in its //xdata// parameter 1144an **int** index of the row that was toggled. 1145 1146 1147=== Text entry fields === 1148 1149All entry widgets, when packed into boxes and tables, have padding by default; 1150its size can be set by //BORDER(ENTRY)//. All pathboxes have a default border 1151area: //BORDER(PATH)//. All widgets in this group have slots in the "tape", those 1152with a builtin event have an extra slot for the event. 1153 1154: //XENTRY(field)// : 1155 an entry with **char*** field, packed expanding 1156: //XLENTRY(field, max)// : 1157 same, with max length in chars 1158: //TLENTRY(field, max, x, y, length)// : 1159 same, packed into //length// columns in a table, starting at column //x//, 1160 row //y// 1161: //MLENTRY(field)// : 1162 a multiline entry (accepts **Ctrl+Enter** for a newline) with **char*** field 1163: //XPENTRY(field, max)// : 1164 an entry for filenames (in system encoding) with **char*** field, with max 1165 length in chars, packed expanding 1166: //TPENTRYv(text, var, max)// : 1167 an entry for filenames with **char*** variable, with max length, packed into the 1168 second column of a table, combined with label that goes into the first column 1169: //PATH(name, fsel_name, mode, field)// : 1170 a pathbox (a named frame with entry in system encoding and button calling up 1171 file selector) with **char*** field, with name and mode for the fileselector 1172: //PATHv(name, fsel_name, mode, var)// : 1173 same, with **char*** variable 1174: //PATHv(name, fsel_name, mode, ini_var_name)// : 1175 same, with inifile variable (string) 1176: //TPATHv(name, fsel_name, mode, var)// : 1177 a frameless pathbox with **char*** variable, packed into the second column of a 1178 table, combined with label that goes into the first column 1179: //uPATHSTR(field)// : 1180 a script-only simulated entry for filenames with **char*** field 1181: //TEXT(field)// : 1182 a text widget with **char*** field, packed expanding 1183: //COMBOENTRY(field, list_field, OK_handler)// : 1184 an entry with dropdown list with **char*** field, with **char**** //list_field// 1185 pointing to NULL-terminated **char*[]** array of choices, and a handler for 1186 //OK// event, packed expanding 1187: //HEXENTRY(field, CHANGE_handler, x, y)// : 1188 an entry for color hex code / name, with **int** field (packed RGB), and a 1189 handler for //CHANGE// event, packed into a table at column //x//, row //y// 1190 1191 1192The //XENTRY//, //*LENTRY// and //COMBOENTRY// widgets immediately replace the 1193string values used for initialization with copies owned by the widgets, so that 1194there is no chance of incidental access if the original strings are freed after 1195**run_create()**. The //TEXT// widget just replaces it with NULL, for the same 1196reason. 1197 1198 1199=== Buttons === 1200 1201All buttons have a default border area: //BORDER(BUTTON)//. They all have two 1202slots in the "tape": for themselves and for their builtin event. 1203 1204Buttons, except toggle buttons, are not scriptable by default, unless explicitly 1205tagged by the "script flag"; some of macros below are for such buttons. 1206 1207: //OKBTN(name, OK_handler)// : 1208 a named button reacting to **Enter** key, with //OK// event handler, packed 1209 expanding 1210: //uOKBTN(OK_handler)// : 1211 a script-only simulated button with //OK// event handler 1212: //CANCELBTN(name, CANCEL_handler)// : 1213 a named button reacting to **Esc** key, with //CANCEL// event handler, packed 1214 expanding 1215: //CANCELBTNp(field, CANCEL_handler)// : 1216 same, with name in a **char*** field 1217: //UCANCELBTN(name, CANCEL_handler)// : 1218 a cancel button packed the default way (//pk_PACK//) 1219: //ECANCELBTN(name, CANCEL_handler)// : 1220 same, packed from the end 1221: //UDONEBTN(name, OK_handler)// : 1222 a named button reacting to **Enter** and **Esc** keys, with //OK// event handler 1223: //TOGGLE(name, field, CHANGE_handler)// : 1224 a named toggle button with an **int** field and //CHANGE// event handler, packed 1225 expanding 1226: //UTOGGLEv(name, var, CHANGE_handler)// : 1227 same with an **int** variable, packed the default way 1228: //BUTTON(name, CLICK_handler)// : 1229 a named button with //CLICK// event handler, packed expanding 1230: //BUTTONs(name, CLICK_handler)// : 1231 same, scriptable 1232: //BUTTONp(field, CLICK_handler)// : 1233 same, with name in a **char*** field, not scriptable 1234: //UBUTTON(name, CLICK_handler)// : 1235 a named button with //CLICK// event handler, packed the default way 1236: //EBUTTON(name, CLICK_handler)// : 1237 same, packed from the end 1238: //EBUTTONs(name, CLICK_handler)// : 1239 same, scriptable 1240: //TLBUTTON(name, CLICK_handler, x, y)// : 1241 a named button with //CLICK// event handler, packed into a table at column 1242 //x//, row //y// 1243: //TLBUTTONs(name, CLICK_handler, x, y)// : 1244 same, scriptable 1245: //uBUTTONs(name, CLICK_handler)// : 1246 a script-only simulated named button with //CLICK// event handler, scriptable 1247 (obviously) 1248: //OKBOX(ok_name, OK_handler, cancel_name, CANCEL_handler)// : 1249 a convenience macro creating an //EQBOX// with //CANCELBTN// and //OKBTN//; the 1250 box is left unclosed (without //WEND//) but no practical reason to add more 1251 things into it, and it is normally the last thing in a dialog anyway 1252: //OKBOXP(ok_name, OK_handler, cancel_name, CANCEL_handler)// : 1253 same, with a box with padding (//EQBOXP//) 1254: //OKBOXB(ok_name, OK_handler, cancel_name, CANCEL_handler)// : 1255 same, with a box with border (//EQBOXB//) 1256: //OKBOX3(ok_name, OK_handler, cancel_name, CANCEL_handler, button_name, CLICK_handler)// : 1257 an //EQBOX// with //CANCELBTN//, regular //BUTTON//, and //OKBTN// 1258: //OKBOX3B(ok_name, OK_handler, cancel_name, CANCEL_handler, button_name, CLICK_handler)// : 1259 same, with a box with border 1260 1261 1262=== Toolbar === 1263 1264Toolbars are containers for their buttons, and need //WEND// to close. 1265//TOOLBAR*// widgets have a default border area: //BORDER(TOOLBAR)//. All toolbars 1266and toolbar buttons have slots in the "tape"; the toolbars have an extra slot or 1267two for their builtin events. Toolbar buttons call their toolbar's event handlers 1268when things happen to them, so that they do not need //EVENT//s of their own. 1269 1270: //TOOLBAR(CHANGE_handler)// : 1271 a regular toolbar with //CHANGE// event handler (to which, despite the name, 1272 regular toolbuttons getting pressed is routed too) 1273: //TOOLBARx(CHANGE_handler, CLICK_handler)// : 1274 same, with also a //CLICK// event handler for right-clicking on a button 1275: //SMARTTBAR(CHANGE_handler)// : 1276 a toolbar that, if buttons do not fit, adds a dropdown with the overflow ones; 1277 with //CHANGE// event handler 1278: //SMARTTBARx(CHANGE_handler, CLICK_handler)// : 1279 same, with also a //CLICK// event handler 1280: //SMARTTBMORE(name)// : 1281 a button that shows said dropdown; after it go regular widgets (not toolbuttons) 1282 that will stay displayed regardless 1283: //TBBUTTON(name, icon, action)// : 1284 a toolbar button with icon, tooltip (also used for scripting), and action code 1285 (two numbers packed into one by //ACTMOD()// macro) 1286: //TBBUTTON(name, icon, action, rclick_action)// : 1287 same, with another action code for right click 1288: //TBTOGGLE(name, icon, action, field)// : 1289 a toolbar toggle button with an **int** field, icon, tooltip, and action code 1290: //TBTOGGLEv(name, icon, action, var)// : 1291 same, with an **int** variable 1292: //TBTOGGLExv(name, icon, action, rclick_action, var)// : 1293 same, with another action code for right click 1294: //TBBOXTOGxv(name, icon, action, rclick_action, var)// : 1295 a regular toggle button that actually goes into the container that the toolbar 1296 sits in, but still acts like //TBTOGGLExv// 1297: //TBRBUTTONv(name, icon, action, var)// : 1298 a toolbar radiobutton with an **int** variable, icon, tooltip, and action code 1299: //TBRBUTTONxv(name, icon, action, rclick_action, var)// : 1300 same, with another action code for right click 1301: //TBSPACE// : 1302 a toolbar separator 1303 1304 1305=== Menu === 1306 1307Menubars and submenus are containers for menuitems and submenus, and need //WEND// 1308to close. They and menuitems all have slots in the "tape"; the menubars have an 1309extra slot for their builtin event. Menuitems call their menubar's event handler 1310when they activate. 1311 1312Menuitems are not scriptable by default; those that are (tagged by "script flag") 1313have their macros' names ending in "s". 1314 1315: //MENUBAR(CHANGE_handler)// : 1316 a regular menubar with //CHANGE// event handler, to which all its menuitems' 1317 activations get routed 1318: //SMARTMENU(CHANGE_handler)// : 1319 a menubar that, if not wide enough, moves some of regular submenus into an 1320 overflow submenu; with //CHANGE// event handler 1321: //SUBMENU(name)// : 1322 a submenu 1323: //ESUBMENU(name)// : 1324 a submenu placed at the end of menubar 1325: //SSUBMENU(name)// : 1326 the overflow submenu 1327: //MENUITEM(name, action)// : 1328 a menuitem with action code (//ACTMOD()// made) 1329: //MENUITEMs(name, action)// : 1330 same, scriptable 1331: //MENUITEMi(name, action, icon)// : 1332 a menuitem with an icon, with action code 1333: //MENUITEMis(name, action, icon)// : 1334 same, scriptable 1335: //MENUCHECKv(name, action, var)// : 1336 a check menuitem with an **int** variable, with action code 1337: //MENUCHECKvs(name, action, var)// : 1338 same, scriptable 1339: //MENURITEMv(name, action, var)// : 1340 a radio menuitem with an **int** variable, with action code 1341: //MENURITEMvs(name, action, var)// : 1342 same, scriptable 1343: //MENUTEAR// : 1344 a tearoff menuitem 1345: //MENUSEP// : 1346 a menu separator 1347: //MENUSEPr// : 1348 same, with a slot of its own (to hide/show it) 1349: //uMENUBAR(CHANGE_handler)// : 1350 a script-only simulated menubar with //CHANGE// event handler 1351: //uMENUITEM(name, action)// : 1352 a script-only simulated menuitem; not scriptable, is used for keybindings 1353: //uMENUITEMs(name, action)// : 1354 same, scriptable 1355 1356 1357=== Control flow === 1358 1359The commands in this group control what other commands get executed after. 1360 1361: //GOTO(array)// : 1362 go execute specified V-code array 1363: //CALL(array)// : 1364 push current execution address onto return stack, and go execute specified 1365 V-code array 1366: //CALLp(field)// : 1367 same, with address of the array given in **void**** field 1368: //RET// : 1369 pop execution address from return stack, and continue from there 1370: //IF(field)// : 1371 if **int** field is 0, skip the next command (caution: do not put before those 1372 macros that are internally multiple commands) 1373: //IFv(var)// 1374 same, if **int** variable is 0 1375: //IFx(field, id)// : 1376 if **int** field is 0, skip the following commands till an //ENDIF()// with the 1377 same id number 1378: //IFx(var, id)// : 1379 same, if **int** variable is 0 1380: //UNLESS(field)// : 1381 if **int** field isn't 0, skip the next command 1382: //UNLESSv(field)// : 1383 same, if **int** variable isn't 0 1384: //UNLESSx(field, id)// : 1385 if **int** field isn't 0, skip the following commands till an //ENDIF()// with 1386 the same id 1387: //UNLESSbt(ini_var_name)// : 1388 if inifile variable (boolean) isn't FALSE, skip the next command 1389: //ENDIF(id)// : 1390 mark the point for //IFx/UNLESSx// with corresponding id, otherwise do nothing 1391 1392 1393Complex conditions can be implemented in three ways; either the flag 1394variable/field itself can be calculated from the condition, or //IFx/UNLESSx// can 1395be wrapped around another (sharing the same //ENDIF//), or //IF//UNLESS// can 1396precede another conditional to skip it: "//IF(A), IF(B), command//" results in 1397"if (!a || b) command". 1398 1399 1400=== Memory allocation and referencing === 1401 1402: //REF(field)// : 1403 put address of current slot in the "tape" into **void**** field 1404: //REFv(var)// : 1405 same, into **void**** variable 1406: //CLEANUP(field)// : 1407 in **run_destroy()** free the memory block pointed to by the **void*** field 1408: //TALLOC(field, length_field)// : 1409 in **run_create()** allocate **int** //length_field// bytes (**void*** aligned) 1410 below current **dtail** and put their address (new **dtail**) into **void*** 1411 field 1412: //TCOPY(field, length_field)// : 1413 same but copy whatever the **void*** field was pointing to into the allocated 1414 block before overwriting the field with its (now the copy's) address 1415 1416 1417In case //TALLOC()// is used to allocate **double** arrays on a 32-bit 1418architecture, the block will need be allocated with one **double** extra, and 1419properly aligned on **double** afterwards. 1420 1421 1422=== Keymap and action map === 1423 1424Action map serves to easily enable/disable or show/hide multiple widgets in 1425response to combinations of various conditions. 1426 1427: //VISMASK(mask)// : 1428 choose which bits of action map will control visibility instead of sensitivity 1429 (default is none) 1430: //ACTMAP(mask)// : 1431 the widget after whose slot in the "tape" this goes, will be sensitive/shown 1432 when any bits in the mask are set in the action map, and insensitive/hidden 1433 when none are 1434 1435 1436Keymap serves to dynamically map keys to widgets (represented as their slots in 1437the "tape"). The default mappings are set in V-code, and keymap allows to modify 1438them afterwards and saves/restores the modifications using the inifile. 1439 1440: //KEYMAP(field, name)// : 1441 add a named keymap, with **void**** field to put the found slot into 1442: //SHORTCUTs(string)// : 1443 add a shortcut represented in GTK+ string format, like "<Alt><Shift>F1" 1444: //SHORTCUT(keyval, mods)// : 1445 add a shortcut representes as keyname and modifiers, like //SHORTCUT(F2, CS)// 1446 for Ctrl+Shift+F2 1447: //SHORTCUT0// 1448 add no shortcut but tell the keymap to allow user to add one (or more) 1449 1450 1451All //SHORTCUT*// commands affect the last widget with a slot in the "tape" before 1452them, as does //ACTMAP// and other "postfix modifier" commands. 1453 1454 1455=== Grouping === 1456 1457Group marks serve to direct **cmd_reset()** to a range of widgets all at once, 1458and to differentiate groups of like-named widgets for scripting. They all have a 1459slot in the "tape". 1460 1461: //GROUPR// : 1462 begin a resetting-group 1463: //GROUPN// : 1464 begin a scripting-group, taking its name from the preceding label 1465: //GROUP(name)// : 1466 begin a scripting-group with specified name 1467: //GROUP0// : 1468 end the current group 1469 1470 1471=== Sizing and placement === 1472 1473: //BORDER(category, num)// : 1474 set border/spacing for specified category of widgets to specified number of 1475 pixels 1476: //DEFBORDER(category)// : 1477 set border/spacing for specified category of widgets to the default (5 pixels) 1478: The categories are: 1479| TABLE | tables 1480| NBOOK | notebooks 1481| SCROLL | scrolledwindows 1482| SPIN | spinbuttons 1483| SPINSLIDE | spinsliders 1484| LABEL | labels 1485| OPT | option menus 1486| BUTTON | buttons 1487| TOOLBAR | toolbars 1488| POPUP | popup windows 1489| TOPVBOX | toplevel vboxes 1490| CHECK | checkbuttons 1491| FRAME | frames 1492| RPACK | radiobutton packs 1493| ENTRY | text entries 1494| LISTCC | simple lists 1495| PATH | pathboxes 1496: //MKSHRINK// : 1497 make toplevel window shrinkable (to prevent it becoming larger than screen) 1498: //NORESIZE// : 1499 make toplevel window not user-resizable (to make it automatically shrink when 1500 widgets get hidden) 1501: //WANTMAX// : 1502 tell scrolledwindow that goes //after// it to request full size of its contents 1503: //WANTMAXW// : 1504 same, for width only 1505: //WXYWH(prefix, width, height)// 1506 make the toplevel save/restore its size and position using inifile variables 1507 with specified prefix, and set default width and height for it 1508: //DEFW(width)// : 1509 set default width for toplevel 1510: //DEFH(height)// : 1511 set default height for toplevel 1512: //DEFSIZE(width, height)// : 1513 set default width and height for toplevel 1514: //WPMOUSE// : 1515 tell window manager to show the toplevel at the mouse cursor location 1516: //WPWHEREVER// : 1517 tell window manager to show the toplevel wherever it chooses 1518: //WIDTH(width)// : 1519 set width for the next widget 1520: HEIGHT(height)// : 1521 set height for the next widget 1522: //MINWIDTH(width)// : 1523 set minimum width for the next widget 1524: //KEEPWIDTH// : 1525 make the //preceding// widget to never shrink in width 1526: //KEEPHEIGHT// : 1527 same in height 1528: //ONTOP(field)// : 1529 make the toplevel sit above the one whose **wdata** is passed in **void**** 1530 field (set it as its transient parent) 1531: //ONTOP0// : 1532 let the toplevel sit either over or under the main window (which is default 1533 transient parent of everything else **run_create()** makes); i.e. unset 1534 transient parent 1535 1536 1537By default, **run_create()** tells window manager to show the toplevels in the 1538center of the screen. 1539 1540 1541=== Initial state === 1542 1543: //HIDDEN// : 1544 make the preceding widget initially hidden 1545: //INSENS// : 1546 make it initially insensitive 1547: //FOCUS// : 1548 make it initially focused 1549: //RAISED// : 1550 initially raise the toplevel above other windows 1551 1552 1553=== Cursors === 1554 1555These commands make cursors for later use. They all have slots in the "tape", 1556by which the cursors can later be referred to. 1557 1558: //XBMCURSOR(xbm_name, x, y)// : 1559 a 21x21 cursor from two XBM bitmaps (image and mask) specified by the variable 1560 part of their filenames ("select" for xbm_select.xbm and xbm_select_mask.xbm, 1561 for example), with specified hotspot coordinates 1562: //SYSCURSOR(id)// : 1563 a builtin cursor, identified as per GdkCursorType 1564 1565 1566=== Events === 1567 1568Event handlers, in V-code, get a slot in the "tape" after the widget they are 1569attached to. There should be only one handler for a given event type per widget. 1570 1571: //EVENT(type, handler)// : 1572 add a handler for specified event type to the preceding widget 1573: //TRIGGER// : 1574 trigger the preceding event handler after **run_create()** finishes creating 1575 widgets (but before the toplevel gets shown); has a slot of its own 1576: //MTRIGGER(handler)// : 1577 trigger specified event handler (should be the same as on the menubar) for the 1578 preceding menuitem; has a slot of its own and another for the //CHANGE// event 1579: //WANTKEYS(handler)// : 1580 install priority //KEY// event handler for when the preceding widget is focused; 1581 has a slot of its own and another for the //KEY// event 1582 1583 1584The event types and their causes (widgets denoted by underlying opcodes): 1585: OK : 1586 - pressing //OKBTN// or //DONEBTN// 1587 - pressing //Enter// in text entry or pathbox's entry 1588 - choosing from list or pressing //Enter// in //COMBOENTRY// 1589 - double click or pressing //Enter// in a complex list 1590: CANCEL : 1591 - pressing //CANCELBTN// 1592 - closing a window (call **run_destroy()** if agreeing to it, return without 1593 doing that if ignoring the request) 1594: CLICK : 1595 - pressing //BUTTON// 1596 - right click on a toolbar button 1597: SELECT : 1598 - changing selection in radiobutton pack, option menu, list, or //GRADBAR// 1599: CHANGE : 1600 - changing value in spinbutton or spinslider 1601 - changing value in //TLSPINPACK//, //PCTCOMBO//, //HEXENTRY//, //EYEDROPPER// 1602 - changing text in text entry, pathbox, or //TEXT// 1603 - changing color in color selector 1604 - changing state of //TOGGLE// or checkbutton 1605 - pressing a toolbar button 1606 - selecting a menuitem 1607 - leasing/unleasing the element from //MOUNT// 1608 - scrolling a //CSCROLL// 1609 - resizing //CANVAS// 1610 - changing sort mode in //LISTCX// (should re-sort its map array) 1611: DESTROY : 1612 - running **run_destroy()** (after the toplevel is unrealized but before most 1613 everything else) 1614: SCRIPT : 1615 - setting value in the widget from a script 1616: MULTI : 1617 - setting a list of values to the widget from a script - **evtxr_fn** 1618: KEY : 1619 - pressing a key when focus is in the widget - **evtxr_fn** 1620: MOUSE and XMOUSE: 1621 - pressing a mouse button in the widget - **evtxr_fn** 1622: MMOUSE and MXMOUSE: 1623 - moving mouse in the widget - **evtxr_fn** 1624: RMOUSE and RXMOUSE: 1625 - releasing a mouse button after pressing it in the widget - **evtxr_fn** 1626: CROSS : 1627 - cursor entering or leaving the widget - **evtx_fn** 1628: SCROLL : 1629 - rotating mouse scroll wheel in the widget - **evtx_fn** 1630: EXT : 1631 - needing to render an area of //CANVAS// - **evtxr_fn** 1632 - right click in //LISTCX// - **evtx_fn** 1633 - click in //COLORLIST// - **evtx_fn** 1634: DRAGFROM : 1635 - dragging from //DRAGDROP//'s widget - **evtxr_fn** 1636: DROP : 1637 - dropping to //DRAGDROP//'s widget - **evtx_fn** 1638: COPY : 1639 - data request from //CLIPBOARD// - **evtx_fn** 1640: PASTE : 1641 - data received by //CLIPBOARD// - **evtxr_fn** 1642 1643 1644Unless otherwise noted, the event handlers are of type **evt_fn**. For those of 1645types **evtx_fn** and **evtxr_fn**, what they get in the extra parameter and what 1646their return value does, is described under "Callbacks" below. 1647 1648The difference between //MOUSE/MMOUSE/RMOUSE// and //XMOUSE/MXMOUSE/RXMOUSE// 1649events is, the latter 3 ask for, and report, tablet pressure. 1650 1651Outside //EVENT()// commands, event types are referred to by their opcodes, which 1652have "//op_EVT_//" prefix; like //op_EVT_OK// for //OK// event. 1653 1654 1655=== Clipboard and drag-drop === 1656 1657Clipboard and drag-drop use the same type of data format descriptions. The 1658//CLIPFORM// command prepares those descriptions for them; its slot in the "tape" 1659is then passed to the commands that use the formats. 1660 1661: //CLIPFORM(array, count)// : 1662 a group of formats from **clipform_dd[]** array; has a slot in the "tape" 1663: //DRAGDROP(field, DRAGFROM_handler, DROP_handler)// : 1664 add handlers for drag and/or drop to the preceding widgets, with formats in 1665 **void**** field; has a slot for itself and two more for the events 1666: //DRAGDROPm(field, DRAGFROM_handler, DROP_handler)// : 1667 the same but allows the "move" type of drop in addition to "copy" (some programs 1668 use the "move" type when they really should not) 1669: //CLIPBOARD(field, which, COPY_handler, PASTE_handler)// : 1670 add handlers for copy and paste for specified clipboards (//which//: 1 if the 1671 regular clipboard, 2 if the "primary selection" i.e. what is highlighted, 3 if 1672 both at once), with formats in **void**** field; has a slot for itself and two 1673 more for the events 1674 1675 1676The //DROP// event handler receives in its //xdata// parameter a pointer to 1677**drag_ext**; the //PASTE// event, to **copy_ext** and returns TRUE if 1678successfully imported the data. The //DRAGFROM// and //COPY// events are handled 1679differently from most others; their handlers receive in their //xdata// parameter 1680a slot (dynamically created) with which they then interact to send or receive the 1681data. //DRAGFROM// handler also should return TRUE if it agrees to initiate drag, 1682FALSE otherwise. 1683 1684 1685=== Scripting === 1686 1687The below commands exist solely to facilitate scripting. 1688 1689: //ALTNAME(name)// : 1690 add another name (identifier) for the preceding widget; has a slot in the 1691 "tape" 1692: //FLATTEN// : 1693 make option names from the preceding option menu or radiobutton pack be 1694 directly referrable from script like widget names (in addition to being 1695 referrable as values); has a slot in the "tape" 1696: //OPNAME(name)// : 1697 set (override) name for the preceding widget 1698: //OPNAME0// : 1699 unset the current name (the initial empty-string one, or the preceding 1700 unattached label) to prevent it mis-attaching to the next widget 1701: //UNNAME// : 1702 hide the preceding widget from scripts (by setting it an impossible name) 1703: //SCRIPTED// : 1704 tell **run_create()** to start a range of "live-scriptable" widgets (those 1705 get extra //ALTNAME// slots automatically added, to make them visible from 1706 script despite being real widgets) 1707: //ENDSCRIPT// : 1708 end a range of "live-scriptable" widgets; has a slot in the "tape" (to tell 1709 script interpreter where the range ends) 1710 1711 1712== Functions and macros == 1713 1714There are two main groups of functions; the **run_*()** that affect the entire 1715"tape", and the **cmd_*()** affecting a single slot. Also a few assorted helper 1716functions and macros. 1717 1718: **void **run_create_(void **ifcode, void *ddata, int ddsize, char **script);** 1719 build a dialog window out of V-code decription; takes an array with that 1720 description, address and size of the struct that will be copied into its 1721 **ddata**, and an array of script commands or NULL; returns **wdata** of what 1722 got built (possibly already freed, if script was passed in), or NULL if failed 1723: **void **run_create(void **ifcode, void *ddata, int ddsize);** 1724 same without script commands (a convenience macro) 1725: **void run_query(void **wdata);** 1726 query dialog contents using its "tape"; takes dialog's **wdata** 1727: **void run_destroy(void **wdata);** 1728 destroy a dialog; takes dialog's **wdata** 1729 1730 1731: **void cmd_event(void **slot, int op);** 1732 raise event (specified by opcode) on slot 1733: **void cmd_sensitive(void **slot, int state);** 1734 set sensitive state on slot 1735: **void cmd_showhide(void **slot, int state);** 1736 set visible state on slot 1737: **void cmd_set(void **slot, int v);** 1738 set value on slot 1739: **int cmd_setstr(void **slot, char *s);** 1740 set text-encoded value on slot; returns -1 if failed, 0 if value was left 1741 unused (when only the fact of setting something mattered), 1 if set 1742: **void *cmd_read(void **slot, void *ddata);** 1743 read back slot value (as is) given **ddata** (to calculate fields' addresses 1744 faster); returns the value's storage location 1745: **void cmd_repaint(void **slot);** 1746 repaint slot 1747: **void cmd_reset(void **slot, void *ddata);** 1748 reset slot or group given **ddata**; causes the widget(s) to reinitialize 1749: **void cmd_cursor(void **slot, void **cursor);** 1750 set cursor on slot (for its widget's window) given the cursor's slot 1751: **int cmd_run_script(void **slot, char **strs);** 1752 run script on slot; returns -1 if error happened, 0 if //OK// event handler got 1753 activated, 1 if not 1754 1755 1756: **void **get_wdata(GtkWidget *widget, char *id);** 1757 from widget to its **wdata** 1758: **void **wdata_slot(void **slot);** 1759 from slot to its **wdata** 1760: **void **origin_slot(void **slot);** 1761 from event to its originator 1762: **void *slot_data(void **slot, void *ddata);** 1763 from slot to its storage location (its own, //not// originator's), given 1764 **ddata** 1765: **void **find_slot(void **slot, char *id, int l, int mlevel);** 1766 find slot by text name (with explicit length) and menu level (//MLEVEL_*//) 1767: **void do_evt_1_d(void **slot);** 1768 run event handler in slot, defaulting to run_destroy() if NULL there 1769: **void dialog_event(void *ddata, void **wdata, int what, void **where);** 1770 handle dialog buttons' events (from //OKBTN// and //CANCELBTN//) 1771 1772 1773The next three are for those (widget-type-specific) actions that the above 1774functions do not cover. Such actions were not made into functions to avoid the 1775interface ballooning up with functions that are applicable to very few widgets 1776each. Sending requests and receiving responses through a generic interface 1777instead, is convenient enough in practice. 1778 1779: **void cmd_peekv(void **slot, void *res, int size, int idx);** 1780 read extra data from slot, given data's index/id, destination, and size 1781: **void cmd_setv(void **slot, void *res, int idx);** 1782 set extra data on slot, given data's index/id and source; for some functions, 1783 //res// itself is the value (**int** converted to pointer) 1784: **int cmd_checkv(void **slot, int idx);** 1785 check extra state on slot, given state's index/id 1786 1787 1788Now, the indices/ids per slot type, what each does, and what type of data expects. 1789Types are denoted by representative opcodes. Most actions are either get or set, 1790only very few are valid for both; the check actions are not valid for either get 1791or set and vice versa, as in totally unrelated. 1792 1793- //FPICK// : 1794 : //FPICK_VALUE// 1795 get/set the filename with full path, in system encoding: **char[]** 1796 : //FPICK_RAW// 1797 get/set the raw filename; only the file part without path, in UTF8: **char[]** 1798- //PATH// and //PENTRY// : 1799 : //PATH_VALUE// 1800 get/set the filename: **char[]** 1801 : //PATH_RAW// 1802 get/set the raw filename: **char[]** 1803- //LISTCC// : 1804 : //LISTCC_RESET_ROW// 1805 set the row index to reset: **int** 1806- //LISTC// : 1807 : //LISTC_RESET_ROW// 1808 set the row index to reset: **int** 1809 : //LISTC_ORDER// 1810 get sort order: **int[]** 1811 : //LISTC_SORT// 1812 set sort mode: **int** 1813- //LABEL// and //MENUITEM// : 1814 : //LABEL_VALUE// 1815 set label text: **char*** 1816- //NBOOK// : 1817 : //NBOOK_TABS// 1818 set show/hide tabs: **int** 1819- //ENTRY// and //COMBOENTRY// : 1820 : //ENTRY_VALUE// 1821 set value: **char*** 1822- //TEXT// : 1823 : //TEXT_VALUE// 1824 set value: **char*** 1825- **wdata** : 1826 : //WDATA_ACTMAP// 1827 set action map: **unsigned int** 1828 : //WDATA_TABLET// 1829 get name of tablet device: **char**** 1830- //WINDOW// : 1831 : //WINDOW_TITLE// 1832 set window title: **char*** 1833 : //WINDOW_ESC_BTN// 1834 set slot to react (get "clicked") to //Esc// keypress in window: **void**** 1835 : //WINDOW_FOCUS// 1836 set focus to slot (or to nowhere if NULL): **void**** 1837 : //WINDOW_RAISE// 1838 set window to raise; value is ignored: **void** 1839 : //WINDOW_DISAPPEAR// 1840 set window to hide from view (to allow a screenshot), or to unhide: **int** 1841 : //WINDOW_DPI// 1842 get DPI: **int*** 1843 : //WINDOW_TEXTENG// 1844 set to render text: **texteng_dd*** 1845- //COLOR// : 1846 : //COLOR_RGBA// 1847 set current color and alpha: **int[2]** 1848 : //COLOR_ALL// 1849 set current and previous color and alpha: **int[4]** 1850- //SPIN// and //SPINSLIDE// : 1851 : //SPIN_ALL// 1852 set value, min and max: **int[3]** 1853- //COLORLIST// : 1854 : //COLORLIST_RESET_ROW// 1855 set the row index to reset: **int** 1856- //PROGRESS// : 1857 : //PROGRESS_PERCENT// 1858 set progress percentage: **int** 1859- //CSCROLL// : 1860 : //CSCROLL_XYSIZE// 1861 get x offset, y offset, onscreen width, onscreen height: **int[4]** 1862 : //CSCROLL_LIMITS// 1863 get full width minus onscreen width, and full height minus onscreen height: 1864 **int[2]** 1865 : //CSCROLL_XYRANGE// 1866 set x offset, y offset, full width, and full height, for a delayed resize: 1867 **int[4]** 1868- //CANVASIMG//: 1869 : CANVAS_SIZE 1870 set full size: **int[2]** 1871- //CANVAS// : 1872 : CANVAS_SIZE 1873 get onscreen size / set full size: **int[2]** 1874 : CANVAS_VPORT 1875 get viewport (x, y, x + width, y + height): **int[4]** 1876 : CANVAS_REPAINT 1877 set area that needs repaint (x, y, x + width, y + height): **int[4]** 1878 : CANVAS_PAINT 1879 set area you want to repaint (//rgb// = NULL) - bounds will be modified and 1880 buffer allocated / set image data (//rgb// != NULL) - buffer will be painted 1881 into the bounded area: **rgbcontext*** 1882 : CANVAS_FIND_MOUSE 1883 get mouse state: **mouse_ext*** 1884 : CANVAS_BMOVE_MOUSE 1885 set to nudge mouse cursor by dx, dy: **int[2]** 1886- //FCIMAGE// : 1887 : //FCIMAGE_XY// 1888 set location marker to x, y: **int[2]** 1889- //KEYMAP// : 1890 : //KEYMAP_KEY// 1891 set key to map to slot: **key_ext*** 1892 : //KEYMAP_MAP// 1893 get/set keymap: **keymap_dd*** 1894- //EV_MOUSE// : 1895 : //MOUSE_BOUND// 1896 check to keep cursor inside canvas' visible area, by scrolling the canvas & 1897 moving the cursor back in; return TRUE if moved it 1898- //EV_DRAGFROM// : 1899 : //DRAG_DATA// 1900 set start & end of data exported through drag: **char*[2]** 1901 : //DRAG_ICON_RGB// 1902 set RGB color (packed) for drag icon (color patch): **int** 1903- //EV_COPY// : 1904 : //COPY_DATA// 1905 set start & end of data exported through copying: **char*[2]** 1906- //CLIPBOARD// : 1907 : //CLIP_TEXT// 1908 set text to export through clipboard: **char*** 1909 : //CLIP_OFFER// 1910 check to offer data through clipboard; return TRUE if successful 1911 : //CLIP_PROCESS// 1912 check to request data from clipboard; return TRUE if successful 1913- all regular widgets : 1914 : //SLOT_SENSITIVE// 1915 check sensitive state; return TRUE if sensitive 1916 : //SLOT_FOCUSED// 1917 check focused state; return TRUE if focus in toplevel window is inside the 1918 widget 1919 : //SLOT_SCRIPTABLE// 1920 check scriptability; return TRUE if script flag is set in opcode 1921 : //SLOT_UNREAL// 1922 check unreality; return TRUE if the widget is simulated 1923 : //SLOT_RADIO// 1924 check radio-ness; return TRUE if the widget is radio toolbutton or radio 1925 menuitem 1926- //FONTSEL// : 1927 : //FONTSEL_DPI// 1928 set DPI: **int** 1929 1930 1931Finally, the macros. 1932 1933: //VSLOT_SIZE// : 1934 size of a slot, in void pointers: 3 1935: //GET_DDATA(wdata)// : 1936 from **wdata** to **ddata**: **void*** 1937: //GET_WINDOW(wdata)// : 1938 from **wdata** to its toplevel widget's slot: **void**** 1939: //GET_REAL_WINDOW(wdata)// : 1940 from **wdata** to actual toplevel widget: **void***, in fact **GtkWidget*** 1941: //NEXT_SLOT(slot)// : 1942 from slot to the next one: **void**** 1943: //PREV_SLOT(slot)// : 1944 from slot to the previous one: **void**** 1945: //SLOT_N(slot, n)// : 1946 from slot to the n-th one after: **void**** 1947: //TOOL_ID(slot)// : 1948 get toolbutton's action code: **int** 1949: //TOOL_IR(slot)// : 1950 get toolbutton's right-click action code: **int** 1951: //ACTMOD(action, mode)// : 1952 combine action and mode into action code 1953 1954 1955== Callbacks == 1956 1957Most events are handled by **evt_fn** function (the default one): 1958 1959**void (*evt_fn)(void *ddata, void **wdata, int what, void **where);** 1960 1961The //ddata// and //wdata// parameters are precisely that; the backing struct, and 1962the "tape". The //what// parameter is the event's opcode, and the //where// is 1963its slot. 1964 1965One handler for all (or most) events happening in the dialog, is the usual 1966pattern when using V-code. When inside it need do different things depending on 1967what is happening to what, there are 3 ways to make the decision. 1968 1969One is to use the "//what//" parameter; it is mostly done to separate out final 1970button presses (the //op_EVT_OK// and //op_EVT_CANCEL//) from everything else. 1971 1972Another is to do "**void *cause = cmd_read(where, ddata);**" and compare the 1973"//cause//" to addresses of variables and/or fields that V-code commands refer to. 1974This serves for most types of controls, and with them **cmd_read()** is usually 1975needed anyway, to get the newly-modified value (a few are "self-reading" but that 1976is rarely significant; only affects when to save the previous value if you need 1977it). 1978 1979The third is to do "**void **slot = origin_slot(where);**" and compare the slot 1980with controls' slots stored using //REF()// commands. This in practice is only 1981needed when several //BUTTON()//s are in one dialog; with them all having 1982//CLICK// events and not referring to any memory locations, their slots are the 1983only thing differentiating them. 1984 1985Now, some events need send some extra data to their handler. Those are handled by 1986**evtx_fn** function: 1987 1988**void (*evtx_fn)(void *ddata, void **wdata, int what, void **where, void *xdata);** 1989 1990What, specifically, the handler receives in //xdata//, depends on the event. 1991 1992: //CROSS// : 1993 TRUE if entering, FALSE if leaving: **int** converted to pointer 1994: //SCROLL// : 1995 pointer to **scroll_ext** 1996: //EXT// from //LISTCX// : 1997 row index where right click happened: **int** converted to pointer 1998: //EXT// from //COLORLIST//: 1999 pointer to **colorlist_ext** 2000: //DROP// : 2001 pointer to **drag_ext** 2002: //COPY// : 2003 pointer to **copy_ext** 2004 2005 2006Yet other events not only send extra data to the handler, but also await a return 2007value from it. The value, for nearly all, is simply TRUE or FALSE, and the function 2008handling them is **evtxr_fn**: 2009 2010**int (*evtxr_fn)(void *ddata, void **wdata, int what, void **where, void *xdata);** 2011 2012What the handler receives in //xdata//, and what its return value means, again 2013depends on the event. 2014 2015: //KEY// : 2016 pointer to **key_ext**; return TRUE if the key was handled, FALSE otherwise 2017: //MOUSE//, //XMOUSE//, //MMOUSE//, //MXMOUSE//, //RMOUSE//, //RXMOUSE//: 2018 pointer to **mouse_ext**; return TRUE if the mouse event was handled 2019: //EXT// from //CANVAS//: 2020 pointer to **rgbcontext**; return TRUE if something was rendered into buffer 2021: //DRAGFROM// : 2022 pointer to **drag_ext**; return TRUE to initiate drag 2023: //PASTE// : 2024 pointer to **copy_ext**; return TRUE if data successfully imported 2025: //MULTI// : 2026 pointer to **multi_ext**; return 0 if error, 1 if success and the //xdata// not 2027 needed anymore, -1 if success and the struct should be kept (not freed) 2028 2029 2030Handling some events can include system-dependent interactions with their 2031//xdata//. Instead of saddling some poor unsuspecting widget with those, an 2032"intercessor" capable of processing that is passed as the originating event, in 2033the "//where//" parameter. The intercessors' opcodes are //op_EV_*// to their 2034events' //op_EVT_*//; their functions are described under the headings 2035//EV_MOUSE//, //EV_DRAGFROM//, and //EV_COPY// in the "Functions and macros" 2036chapter above. They are accessed like this: "**cmd_setv(where, pp, DRAG_DATA);**". 2037 2038 2039== THE END == 2040