1"====================================================================== 2| 3| Smalltalk Tk-based GUI building blocks (basic widget classes). 4| 5| 6 ======================================================================" 7 8"====================================================================== 9| 10| Copyright 1999, 2000, 2001, 2002, 2008 Free Software Foundation, Inc. 11| Written by Paolo Bonzini and Robert Collins. 12| 13| This file is part of the GNU Smalltalk class library. 14| 15| The GNU Smalltalk class library is free software; you can redistribute it 16| and/or modify it under the terms of the GNU Lesser General Public License 17| as published by the Free Software Foundation; either version 2.1, or (at 18| your option) any later version. 19| 20| The GNU Smalltalk class library is distributed in the hope that it will be 21| useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 22| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 23| General Public License for more details. 24| 25| You should have received a copy of the GNU Lesser General Public License 26| along with the GNU Smalltalk class library; see the file COPYING.LESSER. 27| If not, write to the Free Software Foundation, 59 Temple Place - Suite 28| 330, Boston, MA 02110-1301, USA. 29| 30 ======================================================================" 31 32 33 34BPrimitive subclass: BEdit [ 35 | callback | 36 37 <comment: 'I am a widget showing one line of modifiable text.'> 38 <category: 'Graphics-Windows'> 39 40 Initialized := nil. 41 42 BEdit class >> new: parent contents: aString [ 43 "Answer a new BEdit widget laid inside the given parent widget, 44 with a default content of aString" 45 46 <category: 'instance creation'> 47 ^(self new: parent) 48 contents: aString; 49 yourself 50 ] 51 52 BEdit class >> initializeOnStartup [ 53 <category: 'private'> 54 Initialized := false 55 ] 56 57 backgroundColor [ 58 "Answer the value of the backgroundColor option for the widget. 59 60 Specifies the normal background color to use when displaying the widget." 61 62 <category: 'accessing'> 63 self properties at: #background ifPresent: [:value | ^value]. 64 self 65 tclEval: '%1 cget -background' 66 with: self connected 67 with: self container. 68 ^self properties at: #background put: self tclResult 69 ] 70 71 backgroundColor: value [ 72 "Set the value of the backgroundColor option for the widget. 73 74 Specifies the normal background color to use when displaying the widget." 75 76 <category: 'accessing'> 77 self 78 tclEval: '%1 configure -background %3' 79 with: self connected 80 with: self container 81 with: value asTkString. 82 self properties at: #background put: value 83 ] 84 85 callback [ 86 "Answer a DirectedMessage that is sent when the receiver is modified, 87 or nil if none has been set up." 88 89 <category: 'accessing'> 90 ^callback 91 ] 92 93 callback: aReceiver message: aSymbol [ 94 "Set up so that aReceiver is sent the aSymbol message (the name of 95 a zero- or one-argument selector) when the receiver is modified. 96 If the method accepts an argument, the receiver is passed." 97 98 <category: 'accessing'> 99 | arguments selector numArgs | 100 selector := aSymbol asSymbol. 101 numArgs := selector numArgs. 102 arguments := #(). 103 numArgs = 1 ifTrue: [arguments := Array with: self]. 104 callback := DirectedMessage 105 selector: selector 106 arguments: arguments 107 receiver: aReceiver 108 ] 109 110 contents [ 111 "Return the contents of the widget" 112 113 <category: 'accessing'> 114 self tclEval: 'return ${var' , self connected , '}'. 115 ^self tclResult 116 ] 117 118 contents: newText [ 119 "Set the contents of the widget" 120 121 <category: 'accessing'> 122 self tclEval: 'set var' , self connected , ' ' , newText asTkString 123 ] 124 125 font [ 126 "Answer the value of the font option for the widget. 127 128 Specifies the font to use when drawing text inside the widget. The font 129 can be given as either an X font name or a Blox font description string. 130 131 X font names are given as many fields, each led by a minus, and each of 132 which can be replaced by an * to indicate a default value is ok: 133 foundry, family, weight, slant, setwidth, addstyle, pixel size, point size 134 (the same as pixel size for historical reasons), horizontal resolution, 135 vertical resolution, spacing, width, charset and character encoding. 136 137 Blox font description strings have three fields, which must be separated by 138 a space and of which only the first is mandatory: the font family, the font 139 size in points (or in pixels if a negative value is supplied), and a number 140 of styles separated by a space (valid styles are normal, bold, italic, 141 underline and overstrike). Examples of valid fonts are ``Helvetica 10 Bold'', 142 ``Times -14'', ``Futura Bold Underline''. You must enclose the font family 143 in braces if it is made of two or more words." 144 145 <category: 'accessing'> 146 self properties at: #font ifPresent: [:value | ^value]. 147 self 148 tclEval: '%1 cget -font' 149 with: self connected 150 with: self container. 151 ^self properties at: #font put: self tclResult 152 ] 153 154 font: value [ 155 "Set the value of the font option for the widget. 156 157 Specifies the font to use when drawing text inside the widget. The font 158 can be given as either an X font name or a Blox font description string. 159 160 X font names are given as many fields, each led by a minus, and each of 161 which can be replaced by an * to indicate a default value is ok: 162 foundry, family, weight, slant, setwidth, addstyle, pixel size, point size 163 (the same as pixel size for historical reasons), horizontal resolution, 164 vertical resolution, spacing, width, charset and character encoding. 165 166 Blox font description strings have three fields, which must be separated by 167 a space and of which only the first is mandatory: the font family, the font 168 size in points (or in pixels if a negative value is supplied), and a number 169 of styles separated by a space (valid styles are normal, bold, italic, 170 underline and overstrike). Examples of valid fonts are ``Helvetica 10 Bold'', 171 ``Times -14'', ``Futura Bold Underline''. You must enclose the font family 172 in braces if it is made of two or more words." 173 174 <category: 'accessing'> 175 self 176 tclEval: '%1 configure -font %3' 177 with: self connected 178 with: self container 179 with: value asTkString. 180 self properties at: #font put: value 181 ] 182 183 foregroundColor [ 184 "Answer the value of the foregroundColor option for the widget. 185 186 Specifies the normal foreground color to use when displaying the widget." 187 188 <category: 'accessing'> 189 self properties at: #foreground ifPresent: [:value | ^value]. 190 self 191 tclEval: '%1 cget -foreground' 192 with: self connected 193 with: self container. 194 ^self properties at: #foreground put: self tclResult 195 ] 196 197 foregroundColor: value [ 198 "Set the value of the foregroundColor option for the widget. 199 200 Specifies the normal foreground color to use when displaying the widget." 201 202 <category: 'accessing'> 203 self 204 tclEval: '%1 configure -foreground %3' 205 with: self connected 206 with: self container 207 with: value asTkString. 208 self properties at: #foreground put: value 209 ] 210 211 selectBackground [ 212 "Answer the value of the selectBackground option for the widget. 213 214 Specifies the background color to use when displaying selected parts 215 of the widget." 216 217 <category: 'accessing'> 218 self properties at: #selectbackground ifPresent: [:value | ^value]. 219 self 220 tclEval: '%1 cget -selectbackground' 221 with: self connected 222 with: self container. 223 ^self properties at: #selectbackground put: self tclResult 224 ] 225 226 selectBackground: value [ 227 "Set the value of the selectBackground option for the widget. 228 229 Specifies the background color to use when displaying selected parts 230 of the widget." 231 232 <category: 'accessing'> 233 self 234 tclEval: '%1 configure -selectbackground %3' 235 with: self connected 236 with: self container 237 with: value asTkString. 238 self properties at: #selectbackground put: value 239 ] 240 241 selectForeground [ 242 "Answer the value of the selectForeground option for the widget. 243 244 Specifies the foreground color to use when displaying selected parts 245 of the widget." 246 247 <category: 'accessing'> 248 self properties at: #selectforeground ifPresent: [:value | ^value]. 249 self 250 tclEval: '%1 cget -selectforeground' 251 with: self connected 252 with: self container. 253 ^self properties at: #selectforeground put: self tclResult 254 ] 255 256 selectForeground: value [ 257 "Set the value of the selectForeground option for the widget. 258 259 Specifies the foreground color to use when displaying selected parts 260 of the widget." 261 262 <category: 'accessing'> 263 self 264 tclEval: '%1 configure -selectforeground %3' 265 with: self connected 266 with: self container 267 with: value asTkString. 268 self properties at: #selectforeground put: value 269 ] 270 271 create [ 272 "Private - Set up the widget and Tcl hooks to get callbacks from 273 it." 274 275 <category: 'private'> 276 self create: ' -width 0'. 277 Initialized ifFalse: [self defineCallbackProcedure]. 278 self 279 tclEval: ' 280 set var%1 {} 281 bind %1 <<Changed>> {callback %2 invokeCallback} 282 trace variable var%1 w doEditCallback 283 %1 configure -textvariable var%1 -highlightthickness 0 -takefocus 1' 284 with: self connected 285 with: self asOop printString 286 ] 287 288 defineCallbackProcedure [ 289 "Private - Set up a Tcl hook to generate Changed events for entry widgets" 290 291 <category: 'private'> 292 Initialized := true. 293 self 294 tclEval: ' 295 proc doEditCallback { name el op } { 296 regsub ^var $name {} widgetName 297 event generate $widgetName <<Changed>> 298 }' 299 ] 300 301 setInitialSize [ 302 "Make the Tk placer's status, the receiver's properties and the 303 window status (as returned by winfo) consistent. Occupy the 304 height indicated by the widget itself and the whole of the 305 parent's width, at the top left corner" 306 307 <category: 'private'> 308 self 309 x: 0 y: 0; 310 width: self parent width 311 ] 312 313 widgetType [ 314 <category: 'private'> 315 ^'entry' 316 ] 317 318 destroyed [ 319 "Private - The receiver has been destroyed, clear the corresponding 320 Tcl variable to avoid memory leaks." 321 322 <category: 'widget protocol'> 323 self tclEval: 'unset var' , self connected. 324 super destroyed 325 ] 326 327 hasSelection [ 328 "Answer whether there is selected text in the widget" 329 330 <category: 'widget protocol'> 331 self tclEval: self connected , ' selection present'. 332 ^self tclResult = '1' 333 ] 334 335 insertAtEnd: aString [ 336 "Clear the selection and append aString at the end of the 337 widget." 338 339 <category: 'widget protocol'> 340 self 341 tclEval: '%1 selection clear 342 %1 insert end %2 343 %1 see end' 344 with: self connected 345 with: aString asTkString 346 ] 347 348 insertText: aString [ 349 "Insert aString in the widget at the current insertion point, 350 replacing the currently selected text (if any)." 351 352 <category: 'widget protocol'> 353 self 354 tclEval: 'catch { %1 delete sel.first sel.last } 355 %1 insert insert %2 356 %1 see insert' 357 with: self connected 358 with: aString asTkString 359 ] 360 361 invokeCallback [ 362 "Generate a synthetic callback." 363 364 <category: 'widget protocol'> 365 self callback isNil ifFalse: [self callback send] 366 ] 367 368 nextPut: aCharacter [ 369 "Clear the selection and append aCharacter at the end of the 370 widget." 371 372 <category: 'widget protocol'> 373 self insertAtEnd: (String with: aCharacter) 374 ] 375 376 nextPutAll: aString [ 377 "Clear the selection and append aString at the end of the 378 widget." 379 380 <category: 'widget protocol'> 381 self insertAtEnd: aString 382 ] 383 384 nl [ 385 "Clear the selection and append a linefeed character at the 386 end of the widget." 387 388 <category: 'widget protocol'> 389 self insertAtEnd: Character nl asString 390 ] 391 392 replaceSelection: aString [ 393 "Insert aString in the widget at the current insertion point, 394 replacing the currently selected text (if any), and leaving 395 the text selected." 396 397 <category: 'widget protocol'> 398 self 399 tclEval: 'catch { 400 %1 icursor sel.first 401 %1 delete sel.first sel.last 402 } 403 %1 insert insert %2 404 %1 select insert [expr %3 + [%1 index insert]] 405 %1 see insert' 406 with: self connected 407 with: aString asTkString 408 with: aString size printString 409 ] 410 411 selectAll [ 412 "Select the whole contents of the widget." 413 414 <category: 'widget protocol'> 415 self tclEval: self connected , ' selection range 0 end' 416 ] 417 418 selectFrom: first to: last [ 419 "Sets the selection to include the characters starting with the one 420 indexed by first (the very first character in the widget having 421 index 1) and ending with the one just before last. If last 422 refers to the same character as first or an earlier one, then the 423 widget's selection is cleared." 424 425 <category: 'widget protocol'> 426 self 427 tclEval: '%1 selection range %2 %3' 428 with: self connected 429 with: (first - 1) printString 430 with: (last - 1) printString 431 ] 432 433 selection [ 434 "Answer an empty string if the widget has no selection, else answer 435 the currently selected text" 436 437 <category: 'widget protocol'> 438 | stream first | 439 self 440 tclEval: 'if [%1 selection present] { 441 return [string range ${var%1} [%1 index sel.first] [%1 index sel.last]]" 442 }' 443 with: self connected. 444 ^self tclResult 445 ] 446 447 selectionRange [ 448 "Answer nil if the widget has no selection, else answer 449 an Interval object whose first item is the index of the 450 first character in the selection, and whose last item is the 451 index of the character just after the last one in the 452 selection." 453 454 <category: 'widget protocol'> 455 | stream first | 456 self 457 tclEval: 'if [%1 selection present] { 458 return "[%1 index sel.first] [%1 index sel.last]" 459 }' 460 with: self connected. 461 stream := ReadStream on: self tclResult. 462 stream atEnd ifTrue: [^nil]. 463 first := (stream upTo: $ ) asInteger + 1. 464 ^first to: stream upToEnd asInteger + 1 465 ] 466 467 space [ 468 "Clear the selection and append a space at the end of the 469 widget." 470 471 <category: 'widget protocol'> 472 self insertAtEnd: ' ' 473 ] 474] 475 476 477 478BPrimitive subclass: BLabel [ 479 480 <comment: 'I am a label showing static text.'> 481 <category: 'Graphics-Windows'> 482 483 AnchorPoints := nil. 484 485 BLabel class >> initialize [ 486 "Private - Initialize the receiver's class variables." 487 488 <category: 'initialization'> 489 (AnchorPoints := IdentityDictionary new: 15) 490 at: #topLeft put: 'nw'; 491 at: #topCenter put: 'n'; 492 at: #topRight put: 'ne'; 493 at: #leftCenter put: 'w'; 494 at: #center put: 'center'; 495 at: #rightCenter put: 'e'; 496 at: #bottomLeft put: 'sw'; 497 at: #bottomCenter put: 's'; 498 at: #bottomRight put: 'se' 499 ] 500 501 BLabel class >> new: parent label: label [ 502 "Answer a new BLabel widget laid inside the given parent widget, 503 showing by default the `label' String." 504 505 <category: 'instance creation'> 506 ^(self new: parent) 507 label: label; 508 yourself 509 ] 510 511 alignment [ 512 "Answer the value of the anchor option for the widget. 513 514 Specifies how the information in a widget (e.g. text or a bitmap) is to be 515 displayed in the widget. Must be one of the symbols #topLeft, #topCenter, 516 #topRight, #leftCenter, #center, #rightCenter, #bottomLeft, #bottomCenter, 517 #bottomRight. For example, #topLeft means display the information such that 518 its top-left corner is at the top-left corner of the widget." 519 520 <category: 'accessing'> 521 ^self properties at: #alignment ifAbsent: [#topLeft] 522 ] 523 524 alignment: aSymbol [ 525 "Set the value of the anchor option for the widget. 526 527 Specifies how the information in a widget (e.g. text or a bitmap) is to be 528 displayed in the widget. Must be one of the symbols #topLeft, #topCenter, 529 #topRight, #leftCenter, #center, #rightCenter, #bottomLeft, #bottomCenter, 530 #bottomRight. For example, #topLeft means display the information such that 531 its top-left corner is at the top-left corner of the widget." 532 533 <category: 'accessing'> 534 self anchor: (AnchorPoints at: aSymbol). 535 self properties at: #alignment put: aSymbol 536 ] 537 538 backgroundColor [ 539 "Answer the value of the backgroundColor option for the widget. 540 541 Specifies the normal background color to use when displaying the widget." 542 543 <category: 'accessing'> 544 self properties at: #background ifPresent: [:value | ^value]. 545 self 546 tclEval: '%1 cget -background' 547 with: self connected 548 with: self container. 549 ^self properties at: #background put: self tclResult 550 ] 551 552 backgroundColor: value [ 553 "Set the value of the backgroundColor option for the widget. 554 555 Specifies the normal background color to use when displaying the widget." 556 557 <category: 'accessing'> 558 self 559 tclEval: '%1 configure -background %3' 560 with: self connected 561 with: self container 562 with: value asTkString. 563 self properties at: #background put: value 564 ] 565 566 font [ 567 "Answer the value of the font option for the widget. 568 569 Specifies the font to use when drawing text inside the widget. The font 570 can be given as either an X font name or a Blox font description string. 571 572 X font names are given as many fields, each led by a minus, and each of 573 which can be replaced by an * to indicate a default value is ok: 574 foundry, family, weight, slant, setwidth, addstyle, pixel size, point size 575 (the same as pixel size for historical reasons), horizontal resolution, 576 vertical resolution, spacing, width, charset and character encoding. 577 578 Blox font description strings have three fields, which must be separated by 579 a space and of which only the first is mandatory: the font family, the font 580 size in points (or in pixels if a negative value is supplied), and a number 581 of styles separated by a space (valid styles are normal, bold, italic, 582 underline and overstrike). Examples of valid fonts are ``Helvetica 10 Bold'', 583 ``Times -14'', ``Futura Bold Underline''. You must enclose the font family 584 in braces if it is made of two or more words." 585 586 <category: 'accessing'> 587 self properties at: #font ifPresent: [:value | ^value]. 588 self 589 tclEval: '%1 cget -font' 590 with: self connected 591 with: self container. 592 ^self properties at: #font put: self tclResult 593 ] 594 595 font: value [ 596 "Set the value of the font option for the widget. 597 598 Specifies the font to use when drawing text inside the widget. The font 599 can be given as either an X font name or a Blox font description string. 600 601 X font names are given as many fields, each led by a minus, and each of 602 which can be replaced by an * to indicate a default value is ok: 603 foundry, family, weight, slant, setwidth, addstyle, pixel size, point size 604 (the same as pixel size for historical reasons), horizontal resolution, 605 vertical resolution, spacing, width, charset and character encoding. 606 607 Blox font description strings have three fields, which must be separated by 608 a space and of which only the first is mandatory: the font family, the font 609 size in points (or in pixels if a negative value is supplied), and a number 610 of styles separated by a space (valid styles are normal, bold, italic, 611 underline and overstrike). Examples of valid fonts are ``Helvetica 10 Bold'', 612 ``Times -14'', ``Futura Bold Underline''. You must enclose the font family 613 in braces if it is made of two or more words." 614 615 <category: 'accessing'> 616 self 617 tclEval: '%1 configure -font %3' 618 with: self connected 619 with: self container 620 with: value asTkString. 621 self properties at: #font put: value 622 ] 623 624 foregroundColor [ 625 "Answer the value of the foregroundColor option for the widget. 626 627 Specifies the normal foreground color to use when displaying the widget." 628 629 <category: 'accessing'> 630 self properties at: #foreground ifPresent: [:value | ^value]. 631 self 632 tclEval: '%1 cget -foreground' 633 with: self connected 634 with: self container. 635 ^self properties at: #foreground put: self tclResult 636 ] 637 638 foregroundColor: value [ 639 "Set the value of the foregroundColor option for the widget. 640 641 Specifies the normal foreground color to use when displaying the widget." 642 643 <category: 'accessing'> 644 self 645 tclEval: '%1 configure -foreground %3' 646 with: self connected 647 with: self container 648 with: value asTkString. 649 self properties at: #foreground put: value 650 ] 651 652 label [ 653 "Answer the value of the label option for the widget. 654 655 Specifies a string to be displayed inside the widget. The way in which the 656 string is displayed depends on the particular widget and may be determined 657 by other options, such as anchor. For windows, this is the title of the window." 658 659 <category: 'accessing'> 660 self properties at: #text ifPresent: [:value | ^value]. 661 self 662 tclEval: '%1 cget -text' 663 with: self connected 664 with: self container. 665 ^self properties at: #text put: self tclResult 666 ] 667 668 label: value [ 669 "Set the value of the label option for the widget. 670 671 Specifies a string to be displayed inside the widget. The way in which the 672 string is displayed depends on the particular widget and may be determined 673 by other options, such as anchor. For windows, this is the title of the window." 674 675 <category: 'accessing'> 676 self 677 tclEval: '%1 configure -text %3' 678 with: self connected 679 with: self container 680 with: value asTkString. 681 self properties at: #text put: value 682 ] 683 684 anchor: value [ 685 "Private - Set the value of the Tk anchor option for the widget." 686 687 <category: 'private'> 688 self 689 tclEval: '%1 configure -anchor %3' 690 with: self connected 691 with: self container 692 with: value asTkString. 693 self properties at: #anchor put: value 694 ] 695 696 create [ 697 <category: 'private'> 698 self create: '-anchor nw -takefocus 0'. 699 self tclEval: 'bind %1 <Configure> "+%1 configure -wraplength %%w"' 700 with: self connected 701 ] 702 703 initialize: parentWidget [ 704 <category: 'private'> 705 super initialize: parentWidget. 706 parentWidget isNil 707 ifFalse: [self backgroundColor: parentWidget backgroundColor] 708 ] 709 710 setInitialSize [ 711 "Make the Tk placer's status, the receiver's properties and the 712 window status (as returned by winfo) consistent. Occupy the 713 area indicated by the widget itself, at the top left corner" 714 715 <category: 'private'> 716 self x: 0 y: 0 717 ] 718 719 widgetType [ 720 <category: 'private'> 721 ^'label' 722 ] 723] 724 725 726 727BPrimitive subclass: BButton [ 728 | callback | 729 730 <comment: 'I am a button that a user can click. In fact I am at the head 731of a small hierarchy of objects which exhibit button-like look 732and behavior'> 733 <category: 'Graphics-Windows'> 734 735 BButton class >> new: parent label: label [ 736 "Answer a new BButton widget laid inside the given parent widget, 737 showing by default the `label' String." 738 739 <category: 'instance creation'> 740 ^(self new: parent) 741 label: label; 742 yourself 743 ] 744 745 backgroundColor [ 746 "Answer the value of the backgroundColor option for the widget. 747 748 Specifies the normal background color to use when displaying the widget." 749 750 <category: 'accessing'> 751 self properties at: #background ifPresent: [:value | ^value]. 752 self 753 tclEval: '%1 cget -background' 754 with: self connected 755 with: self container. 756 ^self properties at: #background put: self tclResult 757 ] 758 759 backgroundColor: value [ 760 "Set the value of the backgroundColor option for the widget. 761 762 Specifies the normal background color to use when displaying the widget." 763 764 <category: 'accessing'> 765 self 766 tclEval: '%1 configure -background %3' 767 with: self connected 768 with: self container 769 with: value asTkString. 770 self properties at: #background put: value 771 ] 772 773 callback [ 774 "Answer a DirectedMessage that is sent when the receiver is clicked, 775 or nil if none has been set up." 776 777 <category: 'accessing'> 778 ^callback 779 ] 780 781 callback: aReceiver message: aSymbol [ 782 "Set up so that aReceiver is sent the aSymbol message (the name of 783 a zero- or one-argument selector) when the receiver is clicked. 784 If the method accepts an argument, the receiver is passed." 785 786 <category: 'accessing'> 787 | arguments selector numArgs | 788 selector := aSymbol asSymbol. 789 numArgs := selector numArgs. 790 arguments := #(). 791 numArgs = 1 ifTrue: [arguments := Array with: self]. 792 callback := DirectedMessage 793 selector: selector 794 arguments: arguments 795 receiver: aReceiver 796 ] 797 798 font [ 799 "Answer the value of the font option for the widget. 800 801 Specifies the font to use when drawing text inside the widget. The font 802 can be given as either an X font name or a Blox font description string. 803 804 X font names are given as many fields, each led by a minus, and each of 805 which can be replaced by an * to indicate a default value is ok: 806 foundry, family, weight, slant, setwidth, addstyle, pixel size, point size 807 (the same as pixel size for historical reasons), horizontal resolution, 808 vertical resolution, spacing, width, charset and character encoding. 809 810 Blox font description strings have three fields, which must be separated by 811 a space and of which only the first is mandatory: the font family, the font 812 size in points (or in pixels if a negative value is supplied), and a number 813 of styles separated by a space (valid styles are normal, bold, italic, 814 underline and overstrike). Examples of valid fonts are ``Helvetica 10 Bold'', 815 ``Times -14'', ``Futura Bold Underline''. You must enclose the font family 816 in braces if it is made of two or more words." 817 818 <category: 'accessing'> 819 self properties at: #font ifPresent: [:value | ^value]. 820 self 821 tclEval: '%1 cget -font' 822 with: self connected 823 with: self container. 824 ^self properties at: #font put: self tclResult 825 ] 826 827 font: value [ 828 "Set the value of the font option for the widget. 829 830 Specifies the font to use when drawing text inside the widget. The font 831 can be given as either an X font name or a Blox font description string. 832 833 X font names are given as many fields, each led by a minus, and each of 834 which can be replaced by an * to indicate a default value is ok: 835 foundry, family, weight, slant, setwidth, addstyle, pixel size, point size 836 (the same as pixel size for historical reasons), horizontal resolution, 837 vertical resolution, spacing, width, charset and character encoding. 838 839 Blox font description strings have three fields, which must be separated by 840 a space and of which only the first is mandatory: the font family, the font 841 size in points (or in pixels if a negative value is supplied), and a number 842 of styles separated by a space (valid styles are normal, bold, italic, 843 underline and overstrike). Examples of valid fonts are ``Helvetica 10 Bold'', 844 ``Times -14'', ``Futura Bold Underline''. You must enclose the font family 845 in braces if it is made of two or more words." 846 847 "self tclEval: '%1 configure -font %3' 848 with: self connected 849 with: self container 850 with: (value asTkString). 851 self properties at: #font put: value" 852 853 <category: 'accessing'> 854 855 ] 856 857 foregroundColor [ 858 "Answer the value of the foregroundColor option for the widget. 859 860 Specifies the normal foreground color to use when displaying the widget." 861 862 <category: 'accessing'> 863 self properties at: #foreground ifPresent: [:value | ^value]. 864 self 865 tclEval: '%1 cget -foreground' 866 with: self connected 867 with: self container. 868 ^self properties at: #foreground put: self tclResult 869 ] 870 871 foregroundColor: value [ 872 "Set the value of the foregroundColor option for the widget. 873 874 Specifies the normal foreground color to use when displaying the widget." 875 876 <category: 'accessing'> 877 self 878 tclEval: '%1 configure -foreground %3' 879 with: self connected 880 with: self container 881 with: value asTkString. 882 self properties at: #foreground put: value 883 ] 884 885 invokeCallback [ 886 "Generate a synthetic callback" 887 888 <category: 'accessing'> 889 self callback isNil ifFalse: [self callback send] 890 ] 891 892 label [ 893 "Answer the value of the label option for the widget. 894 895 Specifies a string to be displayed inside the widget. The way in which the 896 string is displayed depends on the particular widget and may be determined 897 by other options, such as anchor. For windows, this is the title of the window." 898 899 <category: 'accessing'> 900 ^self connected getLabel 901 ] 902 903 label: value [ 904 "Set the value of the label option for the widget. 905 906 Specifies a string to be displayed inside the widget. The way in which the 907 string is displayed depends on the particular widget and may be determined 908 by other options, such as anchor. For windows, this is the title of the window." 909 910 <category: 'accessing'> 911 self connected setLabel: value 912 ] 913 914 create [ 915 <category: 'private'> 916 self connected: GTK.GtkButton new. 917 self connected 918 connectSignal: 'clicked' 919 to: self 920 selector: #onClicked:data: 921 userData: nil 922 ] 923 924 onClicked: aButton data: userData [ 925 <category: 'private'> 926 self invokeCallback 927 ] 928 929 setInitialSize [ 930 "Make the Tk placer's status, the receiver's properties and the 931 window status (as returned by winfo) consistent. Occupy the 932 area indicated by the widget itself, at the top left corner" 933 934 <category: 'private'> 935 936 ] 937] 938 939 940 941BPrimitive subclass: BForm [ 942 943 <comment: 'I am used to group many widgets together.'> 944 <category: 'Graphics-Windows'> 945 946 backgroundColor [ 947 "Answer the value of the backgroundColor option for the widget. 948 949 Specifies the normal background color to use when displaying the widget." 950 951 <category: 'accessing'> 952 | style | 953 style := self container getStyle. 954 'FIXME ok, backGroundColor isn"t trivial to get' printNl 955 "self properties at: #background ifPresent: [ :value | ^value ]. 956 self tclEval: '%1 cget -background' 957 with: self connected 958 with: self container. 959 ^self properties at: #background put: (self tclResult )" 960 ] 961 962 backgroundColor: value [ 963 "Set the value of the backgroundColor option for the widget. 964 965 Specifies the normal background color to use when displaying the widget." 966 967 <category: 'accessing'> 968 | color | 969 value printNl. 970 'fixme implement bg color, will need CStruct Color' printNl 971 "color:=GTK.GdkColor new. 972 GTK.GdkColor parse: value color: color. 973 self container modifyBg: GTK.Gtk gtkStateNormal color: (nil)" 974 ] 975 976 defaultHeight [ 977 "Answer the value of the defaultHeight option for the widget. 978 979 Specifies the desired height for the form in pixels. If this option 980 is less than or equal to zero then the window will not request any size at all." 981 982 <category: 'accessing'> 983 self properties at: #height ifPresent: [:value | ^value]. 984 self 985 tclEval: '%1 cget -height' 986 with: self connected 987 with: self container. 988 ^self properties at: #height put: self tclResult asNumber 989 ] 990 991 defaultHeight: value [ 992 "Set the value of the defaultHeight option for the widget. 993 994 Specifies the desired height for the form in pixels. If this option 995 is less than or equal to zero then the window will not request any size at all." 996 997 <category: 'accessing'> 998 self 999 tclEval: '%1 configure -height %3' 1000 with: self connected 1001 with: self container 1002 with: value printString asTkString. 1003 self properties at: #height put: value 1004 ] 1005 1006 defaultWidth [ 1007 "Answer the value of the defaultWidth option for the widget. 1008 1009 Specifies the desired width for the form in pixels. If this option 1010 is less than or equal to zero then the window will not request any size at all." 1011 1012 <category: 'accessing'> 1013 self properties at: #width ifPresent: [:value | ^value]. 1014 self 1015 tclEval: '%1 cget -width' 1016 with: self connected 1017 with: self container. 1018 ^self properties at: #width put: self tclResult asNumber 1019 ] 1020 1021 defaultWidth: value [ 1022 "Set the value of the defaultWidth option for the widget. 1023 1024 Specifies the desired width for the form in pixels. If this option 1025 is less than or equal to zero then the window will not request any size at all." 1026 1027 <category: 'accessing'> 1028 self 1029 tclEval: '%1 configure -width %3' 1030 with: self connected 1031 with: self container 1032 with: value printString asTkString. 1033 self properties at: #width put: value 1034 ] 1035 1036 create [ 1037 <category: 'private'> 1038 self connected: GTK.GtkPlacer new 1039 ] 1040 1041 addChild: child [ 1042 <category: 'private'> 1043 (self connected) 1044 add: child container; 1045 moveRel: child container 1046 relX: 0 1047 relY: 0. 1048 ^child 1049 ] 1050 1051 child: child height: value [ 1052 "Set the given child's height to value. The default implementation of 1053 this method uses `rubber-sheet' geometry management as explained in 1054 the comment to BWidget's #height method. You should not use this 1055 method, which is automatically called by the child's #height: method, 1056 but you might want to override it. The child's property slots whose 1057 name ends with `Geom' are reserved for this method. This method 1058 should never fail -- if it doesn't apply to the kind of geometry 1059 management that the receiver does, just do nothing." 1060 1061 <category: 'geometry'> 1062 | relative heightParent | 1063 heightParent := self height. 1064 heightParent <= 0 ifTrue: [^self]. 1065 relative := value * 32767 // heightParent. 1066 relative := relative min: 32767. 1067 relative := relative max: 0. 1068 self connected 1069 resizeRel: child container 1070 relWidth: (child properties at: #widthGeom ifAbsent: [32767]) 1071 relHeight: (child properties at: #heightGeom put: relative) 1072 ] 1073 1074 child: child heightOffset: value [ 1075 "Adjust the given child's height by a fixed amount of value pixel. This 1076 is meaningful for the default implementation, using `rubber-sheet' 1077 geometry management as explained in the comment to BWidget's #height and 1078 #heightOffset: methods. You should not use this method, which is 1079 automatically called by the child's #heightOffset: method, but you 1080 might want to override it. if it doesn't apply to the kind of 1081 geometry management that the receiver does, just add value to the 1082 current height of the widget." 1083 1084 <category: 'geometry'> 1085 self connected 1086 resize: child container 1087 width: (child properties at: #widthGeomOfs ifAbsent: [0]) 1088 height: value 1089 ] 1090 1091 child: child inset: pixels [ 1092 <category: 'geometry'> 1093 ^child 1094 xOffset: self xOffset + pixels; 1095 yOffset: self yOffset + pixels; 1096 widthOffset: self widthOffset - (pixels * 2); 1097 heightOffset: self heightOffset - (pixels * 2) 1098 ] 1099 1100 child: child stretch: aBoolean [ 1101 "This method is only used when on the path from the receiver 1102 to its toplevel there is a BContainer. It decides whether child is 1103 among the widgets that are stretched to fill the entire width of 1104 the BContainer; if this has not been set for this widget, it 1105 is propagated along the widget hierarchy." 1106 1107 <category: 'geometry'> 1108 self properties at: #stretch 1109 ifAbsent: 1110 [self parent isNil ifTrue: [^self]. 1111 self parent child: self stretch: aBoolean] 1112 ] 1113 1114 child: child width: value [ 1115 "Set the given child's width to value. The default implementation of 1116 this method uses `rubber-sheet' geometry management as explained in 1117 the comment to BWidget's #width method. You should not use this 1118 method, which is automatically called by the child's #width: method, 1119 but you might want to override it. The child's property slots whose 1120 name ends with `Geom' are reserved for this method. This method 1121 should never fail -- if it doesn't apply to the kind of geometry 1122 management that the receiver does, just do nothing." 1123 1124 <category: 'geometry'> 1125 | relative widthParent | 1126 widthParent := self width. 1127 widthParent <= 0 ifTrue: [^self]. 1128 relative := value * 32767 // widthParent. 1129 relative := relative min: 32767. 1130 relative := relative max: 0. 1131 self connected 1132 resizeRel: child container 1133 relWidth: (child properties at: #widthGeom put: relative) 1134 relHeight: (child properties at: #widthGeom ifAbsent: [32767]) 1135 ] 1136 1137 child: child widthOffset: value [ 1138 "Adjust the given child's width by a fixed amount of value pixel. This 1139 is meaningful for the default implementation, using `rubber-sheet' 1140 geometry management as explained in the comment to BWidget's #width and 1141 #widthOffset: methods. You should not use this method, which is 1142 automatically called by the child's #widthOffset: method, but you 1143 might want to override it. if it doesn't apply to the kind of 1144 geometry management that the receiver does, just add value to the 1145 current width of the widget." 1146 1147 <category: 'geometry'> 1148 self connected 1149 resize: child container 1150 width: value 1151 height: (child properties at: #widthGeomOfs ifAbsent: [0]) 1152 ] 1153 1154 child: child x: value [ 1155 "Set the given child's x to value. The default implementation of 1156 this method uses `rubber-sheet' geometry management as explained in 1157 the comment to BWidget's #x method. You should not use this 1158 method, which is automatically called by the child's #x: method, 1159 but you might want to override it. The child's property slots whose 1160 name ends with `Geom' are reserved for this method. This method 1161 should never fail -- if it doesn't apply to the kind of geometry 1162 management that the receiver does, just do nothing." 1163 1164 <category: 'geometry'> 1165 | relative widthParent | 1166 widthParent := self width. 1167 widthParent <= 0 ifTrue: [^self]. 1168 relative := value * 32767 // widthParent. 1169 relative := relative min: 32767. 1170 relative := relative max: 0. 1171 self connected 1172 moveRel: child container 1173 relX: (child properties at: #xGeom put: relative) 1174 relY: (child properties at: #yGeom ifAbsent: [0]) 1175 ] 1176 1177 child: child xOffset: value [ 1178 "Adjust the given child's x by a fixed amount of value pixel. This 1179 is meaningful for the default implementation, using `rubber-sheet' 1180 geometry management as explained in the comment to BWidget's #x and 1181 #xOffset: methods. You should not use this method, which is 1182 automatically called by the child's #xOffset: method, but you 1183 might want to override it. if it doesn't apply to the kind of 1184 geometry management that the receiver does, just add value to the 1185 current x of the widget." 1186 1187 <category: 'geometry'> 1188 self connected 1189 move: child container 1190 x: value 1191 y: (child properties at: #yGeomOfs ifAbsent: [0]) 1192 ] 1193 1194 child: child y: value [ 1195 "Set the given child's y to value. The default implementation of 1196 this method uses `rubber-sheet' geometry management as explained in 1197 the comment to BWidget's #y method. You should not use this 1198 method, which is automatically called by the child's #y: method, 1199 but you might want to override it. The child's property slots whose 1200 name ends with `Geom' are reserved for this method. This method 1201 should never fail -- if it doesn't apply to the kind of geometry 1202 management that the receiver does, just do nothing." 1203 1204 <category: 'geometry'> 1205 | relative heightParent | 1206 heightParent := self height. 1207 heightParent <= 0 ifTrue: [^self]. 1208 relative := value * 32767 // heightParent. 1209 relative := relative min: 32767. 1210 relative := relative max: 0. 1211 self connected 1212 moveRel: child container 1213 relX: (child properties at: #xGeom ifAbsent: [0]) 1214 relY: (child properties at: #yGeom put: relative) 1215 ] 1216 1217 child: child yOffset: value [ 1218 "Adjust the given child's y by a fixed amount of value pixel. This 1219 is meaningful for the default implementation, using `rubber-sheet' 1220 geometry management as explained in the comment to BWidget's #y and 1221 #yOffset: methods. You should not use this method, which is 1222 automatically called by the child's #yOffset: method, but you 1223 might want to override it. if it doesn't apply to the kind of 1224 geometry management that the receiver does, just add value to the 1225 current y of the widget." 1226 1227 <category: 'geometry'> 1228 self connected 1229 move: child container 1230 x: (child properties at: #xGeomOfs ifAbsent: [0]) 1231 y: value 1232 ] 1233 1234 heightChild: child [ 1235 "Answer the given child's height. The default implementation of this 1236 method uses `rubber-sheet' geometry management as explained in 1237 the comment to BWidget's #height method. You should not use this 1238 method, which is automatically called by the child's #height method, 1239 but you might want to override. The child's property slots whose 1240 name ends with `Geom' are reserved for this method. This method 1241 should never fail -- if it doesn't apply to the kind of geometry 1242 management that the receiver does, just return 0." 1243 1244 <category: 'geometry'> 1245 ^(child properties at: #heightGeom ifAbsentPut: [32767]) * self height 1246 // 32767 1247 ] 1248 1249 widthChild: child [ 1250 "Answer the given child's width. The default implementation of this 1251 method uses `rubber-sheet' geometry management as explained in 1252 the comment to BWidget's #width method. You should not use this 1253 method, which is automatically called by the child's #width method, 1254 but you might want to override. The child's property slots whose 1255 name ends with `Geom' are reserved for this method. This method 1256 should never fail -- if it doesn't apply to the kind of geometry 1257 management that the receiver does, just return 0." 1258 1259 <category: 'geometry'> 1260 ^(child properties at: #widthGeom ifAbsentPut: [32767]) * self width 1261 // 32767 1262 ] 1263 1264 xChild: child [ 1265 "Answer the given child's x. The default implementation of this 1266 method uses `rubber-sheet' geometry management as explained in 1267 the comment to BWidget's #x method. You should not use this 1268 method, which is automatically called by the child's #x method, 1269 but you might want to override. The child's property slots whose 1270 name ends with `Geom' are reserved for this method. This method 1271 should never fail -- if it doesn't apply to the kind of geometry 1272 management that the receiver does, just return 0." 1273 1274 <category: 'geometry'> 1275 ^(child properties at: #xGeom ifAbsentPut: [0]) * self width // 32767 1276 ] 1277 1278 yChild: child [ 1279 "Answer the given child's y. The default implementation of this 1280 method uses `rubber-sheet' geometry management as explained in 1281 the comment to BWidget's #y method. You should not use this 1282 method, which is automatically called by the child's #y method, 1283 but you might want to override. The child's property slots whose 1284 name ends with `Geom' are reserved for this method. This method 1285 should never fail -- if it doesn't apply to the kind of geometry 1286 management that the receiver does, just return 0." 1287 1288 <category: 'geometry'> 1289 ^(child properties at: #yGeom ifAbsentPut: [0]) * self height // 32767 1290 ] 1291] 1292 1293 1294 1295BForm subclass: BContainer [ 1296 | verticalLayout | 1297 1298 <comment: 'I am used to group many widgets together. I can perform simple 1299management by putting widgets next to each other, from left to 1300right or from top to bottom.'> 1301 <category: 'Graphics-Windows'> 1302 1303 addChild: child [ 1304 "The widget identified by child has been added to the receiver. 1305 This method is public not because you can call it, but because 1306 it can be useful to override it to perform some initialization on 1307 the children just added. Answer the new child." 1308 1309 <category: 'accessing'> 1310 self connected 1311 packStart: child container 1312 expand: false 1313 fill: false 1314 padding: 0. 1315 ^child 1316 ] 1317 1318 setVerticalLayout: aBoolean [ 1319 "Answer whether the container will align the widgets vertically or 1320 horizontally. Horizontal alignment means that widgets are 1321 packed from left to right, while vertical alignment means that 1322 widgets are packed from the top to the bottom of the widget. 1323 1324 Widgets that are set to be ``stretched'' will share all the 1325 space that is not allocated to non-stretched widgets. 1326 1327 The layout of the widget can only be set before the first child 1328 is inserted in the widget." 1329 1330 <category: 'accessing'> 1331 children isEmpty 1332 ifFalse: [^self error: 'cannot set layout after the first child is created']. 1333 verticalLayout := aBoolean 1334 ] 1335 1336 create [ 1337 <category: 'private'> 1338 self verticalLayout 1339 ifTrue: [self connected: (GTK.GtkVBox new: false spacing: 0)] 1340 ifFalse: [self connected: (GTK.GtkHBox new: false spacing: 0)] 1341 ] 1342 1343 verticalLayout [ 1344 "answer true if objects should be laid out vertically" 1345 1346 <category: 'private'> 1347 verticalLayout isNil ifTrue: [verticalLayout := true]. 1348 ^verticalLayout 1349 ] 1350 1351 initialize: parentWidget [ 1352 "This is called by #new: to initialize the widget (as the name 1353 says...). The default implementation calls all the other 1354 methods in the `customization' protocol and some private 1355 ones that take care of making the receiver's status consistent, 1356 so you should usually call it instead of doing everything by 1357 hand. This method is public not because you can call it, but 1358 because it might be useful to override it. Always answer the 1359 receiver." 1360 1361 <category: 'private'> 1362 parent := parentWidget. 1363 properties := IdentityDictionary new. 1364 children := OrderedCollection new 1365 ] 1366 1367 child: child height: value [ 1368 <category: 'private'> 1369 (child -> value -> (self heightChild: child)) printNl. 1370 ^child container setSizeRequest: (self widthChild: child) height: value 1371 ] 1372 1373 child: child heightOffset: value [ 1374 <category: 'private'> 1375 1376 ] 1377 1378 child: child inset: value [ 1379 <category: 'private'> 1380 | stretch | 1381 stretch := child properties at: #stretchGeom ifAbsent: [false]. 1382 self connected 1383 setChildPacking: child container 1384 expand: stretch 1385 fill: stretch 1386 padding: (child properties at: #paddingGeom put: value) 1387 packType: GTK.Gtk gtkPackStart 1388 ] 1389 1390 child: child stretch: aBoolean [ 1391 <category: 'private'> 1392 child properties at: #stretchGeom put: aBoolean. 1393 self connected 1394 setChildPacking: child container 1395 expand: aBoolean 1396 fill: aBoolean 1397 padding: (child properties at: #paddingGeom ifAbsent: [0]) 1398 packType: GTK.Gtk gtkPackStart 1399 ] 1400 1401 child: child width: value [ 1402 <category: 'private'> 1403 ^child container setSizeRequest: value height: (self heightChild: child) 1404 ] 1405 1406 child: child widthOffset: value [ 1407 <category: 'private'> 1408 1409 ] 1410 1411 child: child x: value [ 1412 <category: 'private'> 1413 1414 ] 1415 1416 child: child xOffset: value [ 1417 <category: 'private'> 1418 1419 ] 1420 1421 child: child y: value [ 1422 <category: 'private'> 1423 1424 ] 1425 1426 child: child yOffset: value [ 1427 <category: 'private'> 1428 1429 ] 1430 1431 heightChild: child [ 1432 <category: 'private'> 1433 ^child container getSizeRequest at: 2 1434 ] 1435 1436 widthChild: child [ 1437 <category: 'private'> 1438 ^child container getSizeRequest at: 1 1439 ] 1440 1441 xChild: child [ 1442 <category: 'private'> 1443 ^child xAbsolute 1444 ] 1445 1446 yChild: child [ 1447 <category: 'private'> 1448 ^child yAbsolute 1449 ] 1450] 1451 1452 1453 1454BContainer subclass: BRadioGroup [ 1455 | value | 1456 1457 <comment: 'I am used to group many mutually-exclusive radio buttons together. 1458In addition, just like every BContainer I can perform simple management 1459by putting widgets next to each other, from left to right or (which is 1460more useful in this particular case...) from top to bottom.'> 1461 <category: 'Graphics-Windows'> 1462 1463 value [ 1464 "Answer the index of the button that is currently selected, 1465 1 being the first button added to the radio button group. 1466 0 means that no button is selected" 1467 1468 <category: 'accessing'> 1469 ^value 1470 ] 1471 1472 value: anInteger [ 1473 "Force the value-th button added to the radio button group 1474 to be the selected one." 1475 1476 <category: 'accessing'> 1477 value = anInteger ifTrue: [^self]. 1478 self childrenCount = 0 ifTrue: [^self]. 1479 value = 0 ifFalse: [(children at: value) connected setActive: false]. 1480 value := anInteger. 1481 anInteger = 0 ifFalse: [(children at: value) connected setActive: true] 1482 ] 1483 1484 addChild: child [ 1485 <category: 'private'> 1486 super addChild: child. 1487 child assignedValue: self childrenCount. 1488 self childrenCount = 1 ifTrue: [self value: 1]. 1489 child connected 1490 connectSignal: 'toggled' 1491 to: self 1492 selector: #onToggle:data: 1493 userData: self childrenCount. 1494 ^child 1495 ] 1496 1497 onToggle: widget data: userData [ 1498 <category: 'private'> 1499 value := userData. 1500 (children at: userData) invokeCallback 1501 ] 1502 1503 group [ 1504 "answer the radio group my children are in" 1505 1506 <category: 'private'> 1507 | child | 1508 child := children at: 1. 1509 ^child exists ifFalse: [nil] ifTrue: [child connected getGroup] 1510 ] 1511 1512 initialize: parentWidget [ 1513 <category: 'private'> 1514 super initialize: parentWidget. 1515 value := 0 1516 ] 1517] 1518 1519 1520 1521BButton subclass: BRadioButton [ 1522 | assignedValue | 1523 1524 <comment: 'I am just one in a group of mutually exclusive buttons.'> 1525 <category: 'Graphics-Windows'> 1526 1527 callback: aReceiver message: aSymbol [ 1528 "Set up so that aReceiver is sent the aSymbol message (the name of 1529 a selector accepting at most two arguments) when the receiver is 1530 clicked. If the method accepts two arguments, the receiver is 1531 passed as the first parameter. If the method accepts one or two 1532 arguments, true is passed as the last parameter for interoperability 1533 with BToggle widgets." 1534 1535 <category: 'accessing'> 1536 | arguments selector numArgs | 1537 selector := aSymbol asSymbol. 1538 numArgs := selector numArgs. 1539 arguments := #(). 1540 numArgs = 1 ifTrue: [arguments := #(true)]. 1541 numArgs = 2 1542 ifTrue: 1543 [arguments := 1544 {self. 1545 true}]. 1546 callback := DirectedMessage 1547 selector: selector 1548 arguments: arguments 1549 receiver: aReceiver 1550 ] 1551 1552 value [ 1553 "Answer whether this widget is the selected one in its radio 1554 button group." 1555 1556 <category: 'accessing'> 1557 ^self parent value = assignedValue 1558 ] 1559 1560 value: aBoolean [ 1561 "Answer whether this widget is the selected one in its radio 1562 button group. Setting this property to false for a group's 1563 currently selected button unhighlights all the buttons in that 1564 group." 1565 1566 <category: 'accessing'> 1567 aBoolean 1568 ifTrue: 1569 [self parent value: assignedValue. 1570 ^self]. 1571 1572 "aBoolean is false - unhighlight everything if we're active" 1573 self value ifTrue: [self parent value: 0] 1574 ] 1575 1576 assignedValue: anInteger [ 1577 <category: 'private'> 1578 assignedValue := anInteger 1579 ] 1580 1581 create [ 1582 <category: 'private'> 1583 self 1584 connected: (GTK.GtkRadioButton newWithLabel: self parent group label: '') 1585 ] 1586] 1587 1588 1589 1590BButton subclass: BToggle [ 1591 | value | 1592 1593 <comment: 'I represent a button whose choice can be included (by checking 1594me) or excluded (by leaving me unchecked).'> 1595 <category: 'Graphics-Windows'> 1596 1597 callback: aReceiver message: aSymbol [ 1598 "Set up so that aReceiver is sent the aSymbol message (the name of 1599 a selector accepting at most two arguments) when the receiver is 1600 clicked. If the method accepts two arguments, the receiver is 1601 passed as the first parameter. If the method accepts one or two 1602 arguments, the state of the widget (true if it is selected, false 1603 if it is not) is passed as the last parameter." 1604 1605 <category: 'accessing'> 1606 | arguments selector numArgs | 1607 selector := aSymbol asSymbol. 1608 numArgs := selector numArgs. 1609 arguments := #(). 1610 numArgs = 1 ifTrue: [arguments := {nil}]. 1611 numArgs = 2 1612 ifTrue: 1613 [arguments := 1614 {self. 1615 nil}]. 1616 callback := DirectedMessage 1617 selector: selector 1618 arguments: arguments 1619 receiver: aReceiver 1620 ] 1621 1622 invokeCallback [ 1623 "Generate a synthetic callback." 1624 1625 <category: 'accessing'> 1626 self callback isNil ifTrue: [^self]. 1627 self callback arguments size > 0 1628 ifTrue: 1629 [self callback arguments at: self callback arguments size put: self value]. 1630 super invokeCallback 1631 ] 1632 1633 value [ 1634 "Answer whether the button is in a selected (checked) state." 1635 1636 <category: 'accessing'> 1637 self tclEval: 'return ${var' , self connected , '}'. 1638 ^self tclResult = '1' 1639 ] 1640 1641 value: aBoolean [ 1642 "Set whether the button is in a selected (checked) state and 1643 generates a callback accordingly." 1644 1645 <category: 'accessing'> 1646 aBoolean 1647 ifTrue: [self tclEval: 'set var' , self connected , ' 1'] 1648 ifFalse: [self tclEval: 'set var' , self connected , ' 0'] 1649 ] 1650 1651 variable: value [ 1652 "Set the value of Tk's variable option for the widget." 1653 1654 <category: 'accessing'> 1655 self 1656 tclEval: '%1 configure -variable %3' 1657 with: self connected 1658 with: self container 1659 with: value asTkString. 1660 self properties at: #variable put: value 1661 ] 1662 1663 initialize: parentWidget [ 1664 <category: 'private'> 1665 | variable | 1666 super initialize: parentWidget. 1667 self tclEval: self connected , ' configure -anchor nw'. 1668 self tclEval: 'variable var' , self connected. 1669 self variable: 'var' , self connected. 1670 self backgroundColor: parentWidget backgroundColor 1671 ] 1672 1673 widgetType [ 1674 <category: 'private'> 1675 ^'checkbutton' 1676 ] 1677] 1678 1679 1680 1681BPrimitive subclass: BImage [ 1682 1683 <comment: 'I can display colorful images.'> 1684 <category: 'Graphics-Windows'> 1685 1686 BImage class >> downArrow [ 1687 "Answer the XPM representation of a 12x12 arrow pointing downwards." 1688 1689 <category: 'arrows'> 1690 ^'/* XPM */ 1691static char * downarrow_xpm[] = { 1692/* width height ncolors chars_per_pixel */ 1693"12 12 2 1", 1694/* colors */ 1695" c None m None s None", 1696"o c black m black", 1697/* pixels */ 1698" ", 1699" ", 1700" ", 1701" ", 1702" ooooooo ", 1703" ooooo ", 1704" ooo ", 1705" o ", 1706" ", 1707" ", 1708" ", 1709" "}; 1710' 1711 ] 1712 1713 BImage class >> leftArrow [ 1714 "Answer the XPM representation of a 12x12 arrow pointing leftwards." 1715 1716 <category: 'arrows'> 1717 ^'/* XPM */ 1718static char * leftarrow_xpm[] = { 1719/* width height ncolors chars_per_pixel */ 1720"12 12 2 1", 1721/* colors */ 1722" c None m None s None", 1723"o c black m black", 1724/* pixels */ 1725" ", 1726" ", 1727" o ", 1728" oo ", 1729" ooo ", 1730" oooo ", 1731" ooo ", 1732" oo ", 1733" o ", 1734" ", 1735" ", 1736" "}; 1737' 1738 ] 1739 1740 BImage class >> upArrow [ 1741 "Answer the XPM representation of a 12x12 arrow pointing upwards." 1742 1743 <category: 'arrows'> 1744 ^'/* XPM */ 1745static char * uparrow_xpm[] = { 1746/* width height ncolors chars_per_pixel */ 1747"12 12 2 1", 1748/* colors */ 1749" c None m None s None", 1750"o c black m black", 1751/* pixels */ 1752" ", 1753" ", 1754" ", 1755" ", 1756" o ", 1757" ooo ", 1758" ooooo ", 1759" ooooooo ", 1760" ", 1761" ", 1762" ", 1763" "}; 1764' 1765 ] 1766 1767 BImage class >> rightArrow [ 1768 "Answer the XPM representation of a 12x12 arrow pointing rightwards." 1769 1770 <category: 'arrows'> 1771 ^'/* XPM */ 1772static char * rightarrow_xpm[] = { 1773/* width height ncolors chars_per_pixel */ 1774"12 12 2 1", 1775/* colors */ 1776" c None m None s None", 1777"o c black m black", 1778/* pixels */ 1779" ", 1780" ", 1781" o ", 1782" oo ", 1783" ooo ", 1784" oooo ", 1785" ooo ", 1786" oo ", 1787" o ", 1788" ", 1789" ", 1790" "}; 1791' 1792 ] 1793 1794 BImage class >> gnu [ 1795 "Answer the XPM representation of a 48x48 GNU." 1796 1797 <category: 'GNU'> 1798 ^'/* XPM */ 1799/*****************************************************************************/ 1800/* GNU Emacs bitmap conv. to pixmap by Przemek Klosowski (przemek@nist.gov) */ 1801/*****************************************************************************/ 1802static char * image_name [] = { 1803/* width height ncolors chars_per_pixel */ 1804"48 48 7 1", 1805/* colors */ 1806" s mask c none", 1807"B c blue", 1808"x c black", 1809": c SandyBrown", 1810"+ c SaddleBrown", 1811"o c grey", 1812". c white", 1813/* pixels */ 1814" ", 1815" x ", 1816" :x ", 1817" :::x ", 1818" ::x ", 1819" x ::x ", 1820" x: xxx :::x ", 1821" x: xxx xxx:xxx x::x ", 1822" x:: xxxx::xxx:::::xx x::x ", 1823" x:: x:::::::xx::::::xx x::x ", 1824" x:: xx::::::::x:::::::xx xx::x ", 1825" x:: xx::::::::::::::::::x xx::xx ", 1826" x::x xx:::::xxx:::::::xxx:xxx xx:::xx ", 1827" x:::x xx:::::xx...xxxxxxxxxxxxxxx:::xx ", 1828" x:::x xx::::::xx..xxx...xxxx...xxxxxxxx ", 1829" x:::x x::::::xx.xxx.......x.x.......xxxx ", 1830" x:::xx x:::x::xx.xx..........x.xx.........x ", 1831" x::::xx::xx:::x.xx....ooooxoxoxoo.xxx.....x ", 1832" xx::::xxxx::xx.xx.xxxx.ooooooo.xxx xxxx ", 1833" xx::::::::xx..x.xxx..ooooooooo.xx ", 1834" xxx:::::xxx..xx.xx.xx.xxx.ooooo.xx ", 1835" xxx::xx...xx.xx.BBBB..xxooooooxx ", 1836" xxxx.....xx.xxBB:BB.xxoooooooxx ", 1837" xx.....xx...x.BBBx.xxxooooooxx ", 1838" x....xxxx..xx...xxxooooooooooxx ", 1839" x..xxxxxx..x.......x..ooooooooxx ", 1840" x.x xxx.x.x.x...xxxx.oooooooooxx ", 1841" x xxx.x.x.xx...xx..oooooooooxx ", 1842" xx.x..x.x.xx........oooooooox ", 1843" xxo.xx.x.x.x.x.......ooooooooox ", 1844" xxo..xxxx..x...x.......ooooooox ", 1845" xxoo.xx.x..xx...x.......ooo.xxx ", 1846" xxoo..x.x.x.x.x.xx.xxxxx.o.xx+xx ", 1847" xxoo..x.xx..xx.x.x.x+++xxxxx+++x ", 1848" xxooo.x..xxx.x.x.x.x+++++xxx+xxx ", 1849" xxoo.xx..x..xx.xxxx++x+++x++xxx ", 1850" xxoo..xx.xxx.xxx.xxx++xx+x++xx ", 1851" xxooo.xx.xx..xx.xxxx++x+++xxx ", 1852" xxooo.xxx.xx.xxxxxxxxx++++xxx ", 1853" xxoo...xx.xx.xxxxxx++xxxxxxx ", 1854" xxoooo..x..xxx..xxxx+++++xx ", 1855" xxoooo..x..xx..xxxx++++xx ", 1856" xxxooooox.xx.xxxxxxxxxxx ", 1857" xxxooooo..xxx xxxxx ", 1858" xxxxooooxxxx ", 1859" xxxoooxxx ", 1860" xxxxx ", 1861" " 1862};' 1863 ] 1864 1865 BImage class >> exclaim [ 1866 "Answer the XPM representation of a 32x32 exclamation mark icon." 1867 1868 <category: 'icons'> 1869 ^'/* XPM */ 1870static char * exclaim_xpm[] = { 1871/* width height ncolors chars_per_pixel */ 1872"32 32 6 1", 1873/* colors */ 1874" c None m None s None", 1875". c yellow m white", 1876"X c black m black", 1877"x c gray50 m black", 1878"o c gray m white", 1879"b c yellow4 m black", 1880/* pixels */ 1881" bbb ", 1882" b..oX ", 1883" b....oXx ", 1884" b.....Xxx ", 1885" b......oXxx ", 1886" b.......Xxx ", 1887" b........oXxx ", 1888" b.........Xxx ", 1889" b..........oXxx ", 1890" b...oXXXo...Xxx ", 1891" b....XXXXX...oXxx ", 1892" b....XXXXX....Xxx ", 1893" b.....XXXXX....oXxx ", 1894" b.....XXXXX.....Xxx ", 1895" b......XXXXX.....oXxx ", 1896" b......bXXXb......Xxx ", 1897" b.......oXXXo......oXxx ", 1898" b........XXX........Xxx ", 1899" b.........bXb........oXxx ", 1900" b.........oXo.........Xxx ", 1901" b...........X..........oXxx ", 1902" b.......................Xxx ", 1903" b...........oXXo.........oXxx ", 1904" b...........XXXX..........Xxx ", 1905"b............XXXX..........oXxx ", 1906"b............oXXo...........Xxx ", 1907"b...........................Xxxx", 1908"b..........................oXxxx", 1909" b........................oXxxxx", 1910" bXXXXXXXXXXXXXXXXXXXXXXXXxxxxx", 1911" xxxxxxxxxxxxxxxxxxxxxxxxxxx ", 1912" xxxxxxxxxxxxxxxxxxxxxxxxx "}; 1913' 1914 ] 1915 1916 BImage class >> info [ 1917 "Answer the XPM representation of a 32x32 `information' icon." 1918 1919 <category: 'icons'> 1920 ^'/* XPM */ 1921static char * info_xpm[] = { 1922/* width height ncolors chars_per_pixel */ 1923"32 32 6 1", 1924/* colors */ 1925" c None m None s None", 1926". c white m white", 1927"X c black m black", 1928"x c gray50 m black", 1929"o c gray m white", 1930"b c blue m black", 1931/* pixels */ 1932" xxxxxxxx ", 1933" xxxo......oxxx ", 1934" xxo............oxx ", 1935" xo................ox ", 1936" x.......obbbbo.......X ", 1937" x........bbbbbb........X ", 1938" x.........bbbbbb.........X ", 1939" xo.........obbbbo.........oX ", 1940" x..........................Xx ", 1941"xo..........................oXx ", 1942"x..........bbbbbbb...........Xx ", 1943"x............bbbbb...........Xxx", 1944"x............bbbbb...........Xxx", 1945"x............bbbbb...........Xxx", 1946"x............bbbbb...........Xxx", 1947"xo...........bbbbb..........oXxx", 1948" x...........bbbbb..........Xxxx", 1949" xo..........bbbbb.........oXxxx", 1950" x........bbbbbbbbb.......Xxxx ", 1951" X......................Xxxxx ", 1952" X....................Xxxxx ", 1953" Xo................oXxxxx ", 1954" XXo............oXXxxxx ", 1955" xXXXo......oXXXxxxxx ", 1956" xxxXXXo...Xxxxxxxx ", 1957" xxxxX...Xxxxxx ", 1958" xX...Xxx ", 1959" X..Xxx ", 1960" X.Xxx ", 1961" XXxx ", 1962" xxx ", 1963" xx "}; 1964' 1965 ] 1966 1967 BImage class >> question [ 1968 "Answer the XPM representation of a 32x32 question mark icon." 1969 1970 <category: 'icons'> 1971 ^'/* XPM */ 1972static char * question_xpm[] = { 1973/* width height ncolors chars_per_pixel */ 1974"32 32 6 1", 1975/* colors */ 1976" c None m None s None", 1977". c white m white", 1978"X c black m black", 1979"x c gray50 m black", 1980"o c gray m white", 1981"b c blue m black", 1982/* pixels */ 1983" xxxxxxxx ", 1984" xxxo......oxxx ", 1985" xxo............oxx ", 1986" xo................ox ", 1987" x....................X ", 1988" x.......obbbbbbo.......X ", 1989" x.......obo..bbbbo.......X ", 1990" xo.......bb....bbbb.......oX ", 1991" x........bbbb..bbbb........Xx ", 1992"xo........bbbb.obbbb........oXx ", 1993"x.........obbo.bbbb..........Xx ", 1994"x.............obbb...........Xxx", 1995"x.............bbb............Xxx", 1996"x.............bbo............Xxx", 1997"x.............bb.............Xxx", 1998"xo..........................oXxx", 1999" x...........obbo...........Xxxx", 2000" xo..........bbbb..........oXxxx", 2001" x..........bbbb..........Xxxx ", 2002" X.........obbo.........Xxxxx ", 2003" X....................Xxxxx ", 2004" Xo................oXxxxx ", 2005" XXo............oXXxxxx ", 2006" xXXXo......oXXXxxxxx ", 2007" xxxXXXo...Xxxxxxxx ", 2008" xxxxX...Xxxxxx ", 2009" xX...Xxx ", 2010" X..Xxx ", 2011" X.Xxx ", 2012" XXxx ", 2013" xxx ", 2014" xx "}; 2015' 2016 ] 2017 2018 BImage class >> stop [ 2019 "Answer the XPM representation of a 32x32 `critical stop' icon." 2020 2021 <category: 'icons'> 2022 ^'/* XPM */ 2023static char * stop_xpm[] = { 2024/* width height ncolors chars_per_pixel */ 2025"32 32 5 1", 2026/* colors */ 2027" c None m None s None", 2028". c red m white", 2029"o c DarkRed m black", 2030"X c white m black", 2031"x c gray50 m black", 2032/* pixels */ 2033" oooooooo ", 2034" ooo........ooo ", 2035" o..............o ", 2036" oo................oo ", 2037" o....................o ", 2038" o......................o ", 2039" o......................ox ", 2040" o......X..........X......ox ", 2041" o......XXX........XXX......o ", 2042" o.....XXXXX......XXXXX.....ox ", 2043" o......XXXXX....XXXXX......oxx ", 2044"o........XXXXX..XXXXX........ox ", 2045"o.........XXXXXXXXXX.........ox ", 2046"o..........XXXXXXXX..........oxx", 2047"o...........XXXXXX...........oxx", 2048"o...........XXXXXX...........oxx", 2049"o..........XXXXXXXX..........oxx", 2050"o.........XXXXXXXXXX.........oxx", 2051"o........XXXXX..XXXXX........oxx", 2052" o......XXXXX....XXXXX......oxxx", 2053" o.....XXXXX......XXXXX.....oxxx", 2054" o......XXX........XXX......oxx ", 2055" o......X..........X......oxxx ", 2056" o......................oxxxx ", 2057" o......................oxxx ", 2058" o....................oxxx ", 2059" oo................ooxxxx ", 2060" xo..............oxxxxx ", 2061" xooo........oooxxxxx ", 2062" xxooooooooxxxxxx ", 2063" xxxxxxxxxxxxxx ", 2064" xxxxxxxx "}; 2065' 2066 ] 2067 2068 BImage class >> new: parent data: aString [ 2069 "Answer a new BImage widget laid inside the given parent widget, 2070 loading data from the given string (Base-64 encoded GIF, XPM, 2071 PPM are supported)." 2072 2073 <category: 'instance creation'> 2074 ^(self new: parent) 2075 data: aString; 2076 yourself 2077 ] 2078 2079 BImage class >> new: parent image: aFileStream [ 2080 "Answer a new BImage widget laid inside the given parent widget, 2081 loading data from the given file (GIF, XPM, PPM are supported)." 2082 2083 <category: 'instance creation'> 2084 ^(self new: parent) 2085 image: aFileStream; 2086 yourself 2087 ] 2088 2089 BImage class >> new: parent size: aPoint [ 2090 "Answer a new BImage widget laid inside the given parent widget, 2091 showing by default a transparent image of aPoint size." 2092 2093 <category: 'instance creation'> 2094 ^(self new: parent) 2095 displayWidth: aPoint x; 2096 displayHeight: aPoint y; 2097 blank; 2098 yourself 2099 ] 2100 2101 BImage class >> directory [ 2102 "Answer the Base-64 GIF representation of a `directory folder' icon." 2103 2104 <category: 'small icons'> 2105 ^'R0lGODdhEAAQAPIAAAAAAHh4eLi4uPj4+P///wAAAAAAAAAAACwAAAAAEAAQAAADPkixzPOD 2106yADrWE8qC8WN0+BZAmBq1GMOqwigXFXCrGk/cxjjr27fLtout6n9eMIYMTXsFZsogXRKJf6u 2107P0kCADv/' 2108 ] 2109 2110 BImage class >> file [ 2111 "Answer the Base-64 GIF representation of a `file' icon." 2112 2113 <category: 'small icons'> 2114 ^'R0lGODdhEAAQAPIAAAAAAHh4eLi4uPj4APj4+P///wAAAAAAACwAAAAAEAAQAAADPVi63P4w 2115LkKCtTTnUsXwQqBtAfh910UU4ugGAEucpgnLNY3Gop7folwNOBOeiEYQ0acDpp6pGAFArVqt 2116hQQAO///' 2117 ] 2118 2119 backgroundColor [ 2120 "Answer the value of the backgroundColor option for the widget. 2121 2122 Specifies the normal background color to use when displaying the widget." 2123 2124 <category: 'accessing'> 2125 self properties at: #background ifPresent: [:value | ^value]. 2126 self 2127 tclEval: '%1 cget -background' 2128 with: self connected 2129 with: self container. 2130 ^self properties at: #background put: self tclResult 2131 ] 2132 2133 backgroundColor: value [ 2134 "Set the value of the backgroundColor option for the widget. 2135 2136 Specifies the normal background color to use when displaying the widget." 2137 2138 <category: 'accessing'> 2139 self 2140 tclEval: '%1 configure -background %3' 2141 with: self connected 2142 with: self container 2143 with: value asTkString. 2144 self properties at: #background put: value 2145 ] 2146 2147 displayHeight [ 2148 "Answer the value of the displayHeight option for the widget. 2149 2150 Specifies the height of the image in pixels. This is not the height of the 2151 widget, but specifies the area of the widget that will be taken by the image." 2152 2153 <category: 'accessing'> 2154 self properties at: #displayHeight ifPresent: [:value | ^value]. 2155 self 2156 tclEval: 'img%1 cget -width' 2157 with: self connected 2158 with: self container. 2159 ^self properties at: #displayHeight put: self tclResult asNumber 2160 ] 2161 2162 displayHeight: value [ 2163 "Set the value of the displayHeight option for the widget. 2164 2165 Specifies the height of the image in pixels. This is not the height of the 2166 widget, but specifies the area of the widget that will be taken by the image." 2167 2168 <category: 'accessing'> 2169 self 2170 tclEval: 'img%1 configure -width %3' 2171 with: self connected 2172 with: self container 2173 with: value asFloat printString asTkString. 2174 self properties at: #displayHeight put: value 2175 ] 2176 2177 displayWidth [ 2178 "Answer the value of the displayWidth option for the widget. 2179 2180 Specifies the width of the image in pixels. This is not the width of the 2181 widget, but specifies the area of the widget that will be taken by the image." 2182 2183 <category: 'accessing'> 2184 self properties at: #displayWidth ifPresent: [:value | ^value]. 2185 self 2186 tclEval: 'img%1 cget -width' 2187 with: self connected 2188 with: self container. 2189 ^self properties at: #displayWidth put: self tclResult asNumber 2190 ] 2191 2192 displayWidth: value [ 2193 "Set the value of the displayWidth option for the widget. 2194 2195 Specifies the width of the image in pixels. This is not the width of the 2196 widget, but specifies the area of the widget that will be taken by the image." 2197 2198 <category: 'accessing'> 2199 self 2200 tclEval: 'img%1 configure -width %3' 2201 with: self connected 2202 with: self container 2203 with: value asFloat printString asTkString. 2204 self properties at: #displayWidth put: value 2205 ] 2206 2207 foregroundColor [ 2208 "Answer the value of the foregroundColor option for the widget. 2209 2210 Specifies the normal foreground color to use when displaying the widget." 2211 2212 <category: 'accessing'> 2213 self properties at: #foreground ifPresent: [:value | ^value]. 2214 self 2215 tclEval: '%1 cget -foreground' 2216 with: self connected 2217 with: self container. 2218 ^self properties at: #foreground put: self tclResult 2219 ] 2220 2221 foregroundColor: value [ 2222 "Set the value of the foregroundColor option for the widget. 2223 2224 Specifies the normal foreground color to use when displaying the widget." 2225 2226 <category: 'accessing'> 2227 self 2228 tclEval: '%1 configure -foreground %3' 2229 with: self connected 2230 with: self container 2231 with: value asTkString. 2232 self properties at: #foreground put: value 2233 ] 2234 2235 gamma [ 2236 "Answer the value of the gamma option for the widget. 2237 2238 Specifies that the colors allocated for displaying the image widget 2239 should be corrected for a non-linear display with the specified gamma exponent 2240 value. (The intensity produced by most CRT displays is a power function 2241 of the input value, to a good approximation; gamma is the exponent and 2242 is typically around 2). The value specified must be greater than zero. The 2243 default value is one (no correction). In general, values greater than one 2244 will make the image lighter, and values less than one will make it darker." 2245 2246 <category: 'accessing'> 2247 self properties at: #gamma ifPresent: [:value | ^value]. 2248 self 2249 tclEval: 'img%1 cget -gamma' 2250 with: self connected 2251 with: self container. 2252 ^self properties at: #gamma put: self tclResult asNumber 2253 ] 2254 2255 gamma: value [ 2256 "Set the value of the gamma option for the widget. 2257 2258 Specifies that the colors allocated for displaying the image widget 2259 should be corrected for a non-linear display with the specified gamma exponent 2260 value. (The intensity produced by most CRT displays is a power function 2261 of the input value, to a good approximation; gamma is the exponent and 2262 is typically around 2). The value specified must be greater than zero. The 2263 default value is one (no correction). In general, values greater than one 2264 will make the image lighter, and values less than one will make it darker." 2265 2266 <category: 'accessing'> 2267 self 2268 tclEval: 'img%1 configure -gamma %3' 2269 with: self connected 2270 with: self container 2271 with: value asFloat printString asTkString. 2272 self properties at: #gamma put: value 2273 ] 2274 2275 blank [ 2276 "Blank the corresponding image" 2277 2278 <category: 'image management'> 2279 self tclEval: 'img' , self connected , ' blank' 2280 ] 2281 2282 data: aString [ 2283 "Set the image to be drawn to aString, which can be a GIF 2284 in Base-64 representation or an X pixelmap." 2285 2286 <category: 'image management'> 2287 self tclEval: 'img' , self connected , ' configure -data ' 2288 , aString asTkImageString 2289 ] 2290 2291 dither [ 2292 "Recalculate the dithered image in the window where the 2293 image is displayed. The dithering algorithm used in 2294 displaying images propagates quantization errors from 2295 one pixel to its neighbors. If the image data is supplied 2296 in pieces, the dithered image may not be exactly correct. 2297 Normally the difference is not noticeable, but if it is a 2298 problem, this command can be used to fix it." 2299 2300 <category: 'image management'> 2301 self tclEval: 'img' , self connected , ' redither' 2302 ] 2303 2304 fillFrom: origin extent: extent color: color [ 2305 "Fill a rectangle with the given origin and extent, using 2306 the given color." 2307 2308 <category: 'image management'> 2309 self 2310 fillFrom: origin 2311 to: origin + extent 2312 color: color 2313 ] 2314 2315 fillFrom: origin to: corner color: color [ 2316 "Fill a rectangle between the given corners, using 2317 the given color." 2318 2319 <category: 'image management'> 2320 self 2321 tclEval: 'img%1 put { %2 } -to %3 %4' 2322 with: self connected 2323 with: color 2324 with: origin x printString , ' ' , origin y printString 2325 with: corner x printString , ' ' , corner y printString 2326 ] 2327 2328 fillRectangle: rectangle color: color [ 2329 "Fill a rectangle having the given bounding box, using 2330 the given color." 2331 2332 <category: 'image management'> 2333 self 2334 fillFrom: rectangle origin 2335 to: rectangle corner 2336 color: color 2337 ] 2338 2339 image: aFileStream [ 2340 "Read a GIF or XPM image from aFileStream. The whole contents 2341 of the file are read, not only from the file position." 2342 2343 <category: 'image management'> 2344 self 2345 tclEval: 'img' , self connected , ' read ' , aFileStream name asTkString 2346 ] 2347 2348 imageHeight [ 2349 "Specifies the height of the image, in pixels. This option is useful 2350 primarily in situations where you wish to build up the contents of 2351 the image piece by piece. A value of zero (the default) allows the 2352 image to expand or shrink vertically to fit the data stored in it." 2353 2354 <category: 'image management'> 2355 self tclEval: 'image height img' , self connected. 2356 ^self tclResult asInteger 2357 ] 2358 2359 imageWidth [ 2360 "Specifies the width of the image, in pixels. This option is useful 2361 primarily in situations where you wish to build up the contents of 2362 the image piece by piece. A value of zero (the default) allows the 2363 image to expand or shrink horizontally to fit the data stored in it." 2364 2365 <category: 'image management'> 2366 self tclEval: 'image width img' , self connected. 2367 ^self tclResult asInteger 2368 ] 2369 2370 lineFrom: origin extent: extent color: color [ 2371 "Draw a line with the given origin and extent, using 2372 the given color." 2373 2374 <category: 'image management'> 2375 self 2376 lineFrom: origin 2377 to: origin + extent 2378 color: color 2379 ] 2380 2381 lineFrom: origin to: corner color: color [ 2382 <category: 'image management'> 2383 self notYetImplemented 2384 ] 2385 2386 lineFrom: origin toX: endX color: color [ 2387 "Draw an horizontal line between the given corners, using 2388 the given color." 2389 2390 <category: 'image management'> 2391 self 2392 tclEval: 'img%1 put { %2 } -to %3 %4' 2393 with: self connected 2394 with: color 2395 with: origin x printString , ' ' , origin y printString 2396 with: endX printString , ' ' , origin y printString 2397 ] 2398 2399 lineInside: rectangle color: color [ 2400 "Draw a line having the given bounding box, using 2401 the given color." 2402 2403 <category: 'image management'> 2404 self 2405 lineFrom: rectangle origin 2406 to: rectangle corner 2407 color: color 2408 ] 2409 2410 lineFrom: origin toY: endY color: color [ 2411 "Draw a vertical line between the given corners, using 2412 the given color." 2413 2414 <category: 'image management'> 2415 self 2416 tclEval: 'img%1 put { %2 } -to %3 %4' 2417 with: self connected 2418 with: color 2419 with: origin x printString , ' ' , origin y printString 2420 with: origin x printString , ' ' , endY printString 2421 ] 2422 2423 destroyed [ 2424 "Private - The receiver has been destroyed, clear the corresponding 2425 Tcl image to avoid memory leaks." 2426 2427 <category: 'widget protocol'> 2428 'TODO' printNl. 2429 super destroyed 2430 ] 2431 2432 create [ 2433 <category: 'private'> 2434 self tclEval: 'image create photo img' , self connected. 2435 self create: '-anchor nw -image img' , self connected 2436 ] 2437 2438 setInitialSize [ 2439 "Make the Tk placer's status, the receiver's properties and the 2440 window status (as returned by winfo) consistent. Occupy the 2441 area indicated by the widget itself, at the top left corner" 2442 2443 <category: 'private'> 2444 self x: 0 y: 0 2445 ] 2446 2447 widgetType [ 2448 <category: 'private'> 2449 ^'label' 2450 ] 2451] 2452 2453 2454 2455BViewport subclass: BList [ 2456 | labels items callback gtkmodel connected gtkcolumn | 2457 2458 <comment: 'I represent a list box from which you can choose one or more 2459elements.'> 2460 <category: 'Graphics-Windows'> 2461 2462 add: anObject afterIndex: index [ 2463 "Add an element with the given value after another element whose 2464 index is contained in the index parameter. The label displayed 2465 in the widget is anObject's displayString. Answer anObject." 2466 2467 <category: 'accessing'> 2468 ^self 2469 add: nil 2470 element: anObject 2471 afterIndex: index 2472 ] 2473 2474 add: aString element: anObject afterIndex: index [ 2475 "Add an element with the aString label after another element whose 2476 index is contained in the index parameter. This method allows 2477 the client to decide autonomously the label that the widget will 2478 display. 2479 2480 If anObject is nil, then string is used as the element as well. 2481 If aString is nil, then the element's displayString is used as 2482 the label. 2483 2484 Answer anObject or, if it is nil, aString." 2485 2486 <category: 'accessing'> 2487 | elem label iter | 2488 label := aString isNil ifTrue: [anObject displayString] ifFalse: [aString]. 2489 elem := anObject isNil ifTrue: [aString] ifFalse: [anObject]. 2490 labels isNil 2491 ifTrue: 2492 [index > 0 2493 ifTrue: [^SystemExceptions.IndexOutOfRange signalOn: self withIndex: index]. 2494 labels := OrderedCollection with: label. 2495 items := OrderedCollection with: elem] 2496 ifFalse: 2497 [labels add: label afterIndex: index. 2498 items add: elem afterIndex: index]. 2499 iter := self gtkmodel insert: index. 2500 self gtkmodel 2501 setOop: iter 2502 column: 0 2503 value: label. 2504 ^elem 2505 ] 2506 2507 addLast: anObject [ 2508 "Add an element with the given value at the end of the listbox. 2509 The label displayed in the widget is anObject's displayString. 2510 Answer anObject." 2511 2512 <category: 'accessing'> 2513 ^self 2514 add: nil 2515 element: anObject 2516 afterIndex: items size 2517 ] 2518 2519 addLast: aString element: anObject [ 2520 "Add an element with the given value at the end of the listbox. 2521 This method allows the client to decide autonomously the label 2522 that the widget will display. 2523 2524 If anObject is nil, then string is used as the element as well. 2525 If aString is nil, then the element's displayString is used as 2526 the label. 2527 2528 Answer anObject or, if it is nil, aString." 2529 2530 <category: 'accessing'> 2531 ^self 2532 add: aString 2533 element: anObject 2534 afterIndex: items size 2535 ] 2536 2537 associationAt: anIndex [ 2538 "Answer an association whose key is the item at the given position 2539 in the listbox and whose value is the label used to display that 2540 item." 2541 2542 <category: 'accessing'> 2543 ^(items at: anIndex) -> (labels at: anIndex) 2544 ] 2545 2546 at: anIndex [ 2547 "Answer the element displayed at the given position in the list 2548 box." 2549 2550 <category: 'accessing'> 2551 ^items at: anIndex 2552 ] 2553 2554 backgroundColor [ 2555 "Answer the value of the backgroundColor option for the widget. 2556 2557 Specifies the normal background color to use when displaying the widget." 2558 2559 <category: 'accessing'> 2560 self properties at: #background ifPresent: [:value | ^value]. 2561 self 2562 tclEval: '%1 cget -background' 2563 with: self connected 2564 with: self container. 2565 ^self properties at: #background put: self tclResult 2566 ] 2567 2568 backgroundColor: value [ 2569 "Set the value of the backgroundColor option for the widget. 2570 2571 Specifies the normal background color to use when displaying the widget." 2572 2573 <category: 'accessing'> 2574 self 2575 tclEval: '%1 configure -background %3' 2576 with: self connected 2577 with: self container 2578 with: value asTkString. 2579 self properties at: #background put: value 2580 ] 2581 2582 contents: elementList [ 2583 "Set the elements displayed in the listbox, and set the labels 2584 to be their displayStrings." 2585 2586 <category: 'accessing'> 2587 | newLabels | 2588 newLabels := elementList collect: [:each | each displayString]. 2589 ^self contents: newLabels elements: elementList 2590 ] 2591 2592 contents: stringCollection elements: elementList [ 2593 "Set the elements displayed in the listbox to be those in elementList, 2594 and set the labels to be the corresponding elements in stringCollection. 2595 The two collections must have the same size." 2596 2597 <category: 'accessing'> 2598 | stream iter | 2599 (elementList notNil and: [elementList size ~= stringCollection size]) 2600 ifTrue: 2601 [^self 2602 error: 'label collection must have the same size as element collection']. 2603 labels := stringCollection isNil 2604 ifTrue: 2605 [elementList asOrderedCollection collect: [:each | each displayString]] 2606 ifFalse: [stringCollection asOrderedCollection]. 2607 items := elementList isNil 2608 ifTrue: [labels copy] 2609 ifFalse: [elementList asOrderedCollection]. 2610 self gtkmodel clear. 2611 iter := GTK.GtkTreeIter new. 2612 stringCollection do: 2613 [:each | 2614 self gtkmodel append: iter. 2615 self gtkmodel 2616 setOop: iter 2617 column: 0 2618 value: each] 2619 ] 2620 2621 do: aBlock [ 2622 "Iterate over each element of the listbox and pass it to aBlock." 2623 2624 <category: 'accessing'> 2625 items do: aBlock 2626 ] 2627 2628 elements [ 2629 "Answer the collection of objects that represent the elements 2630 displayed by the list box." 2631 2632 <category: 'accessing'> 2633 ^items copy 2634 ] 2635 2636 elements: elementList [ 2637 "Set the elements displayed in the listbox, and set the labels 2638 to be their displayStrings." 2639 2640 <category: 'accessing'> 2641 | newLabels | 2642 newLabels := elementList collect: [:each | each displayString]. 2643 ^self contents: newLabels elements: elementList 2644 ] 2645 2646 font [ 2647 "Answer the value of the font option for the widget. 2648 2649 Specifies the font to use when drawing text inside the widget. The font 2650 can be given as either an X font name or a Blox font description string. 2651 2652 X font names are given as many fields, each led by a minus, and each of 2653 which can be replaced by an * to indicate a default value is ok: 2654 foundry, family, weight, slant, setwidth, addstyle, pixel size, point size 2655 (the same as pixel size for historical reasons), horizontal resolution, 2656 vertical resolution, spacing, width, charset and character encoding. 2657 2658 Blox font description strings have three fields, which must be separated by 2659 a space and of which only the first is mandatory: the font family, the font 2660 size in points (or in pixels if a negative value is supplied), and a number 2661 of styles separated by a space (valid styles are normal, bold, italic, 2662 underline and overstrike). Examples of valid fonts are ``Helvetica 10 Bold'', 2663 ``Times -14'', ``Futura Bold Underline''. You must enclose the font family 2664 in braces if it is made of two or more words." 2665 2666 <category: 'accessing'> 2667 self properties at: #font ifPresent: [:value | ^value]. 2668 self 2669 tclEval: '%1 cget -font' 2670 with: self connected 2671 with: self container. 2672 ^self properties at: #font put: self tclResult 2673 ] 2674 2675 font: value [ 2676 "Set the value of the font option for the widget. 2677 2678 Specifies the font to use when drawing text inside the widget. The font 2679 can be given as either an X font name or a Blox font description string. 2680 2681 X font names are given as many fields, each led by a minus, and each of 2682 which can be replaced by an * to indicate a default value is ok: 2683 foundry, family, weight, slant, setwidth, addstyle, pixel size, point size 2684 (the same as pixel size for historical reasons), horizontal resolution, 2685 vertical resolution, spacing, width, charset and character encoding. 2686 2687 Blox font description strings have three fields, which must be separated by 2688 a space and of which only the first is mandatory: the font family, the font 2689 size in points (or in pixels if a negative value is supplied), and a number 2690 of styles separated by a space (valid styles are normal, bold, italic, 2691 underline and overstrike). Examples of valid fonts are ``Helvetica 10 Bold'', 2692 ``Times -14'', ``Futura Bold Underline''. You must enclose the font family 2693 in braces if it is made of two or more words." 2694 2695 <category: 'accessing'> 2696 self 2697 tclEval: '%1 configure -font %3' 2698 with: self connected 2699 with: self container 2700 with: value asTkString. 2701 self properties at: #font put: value 2702 ] 2703 2704 foregroundColor [ 2705 "Answer the value of the foregroundColor option for the widget. 2706 2707 Specifies the normal foreground color to use when displaying the widget." 2708 2709 <category: 'accessing'> 2710 self properties at: #foreground ifPresent: [:value | ^value]. 2711 self 2712 tclEval: '%1 cget -foreground' 2713 with: self connected 2714 with: self container. 2715 ^self properties at: #foreground put: self tclResult 2716 ] 2717 2718 foregroundColor: value [ 2719 "Set the value of the foregroundColor option for the widget. 2720 2721 Specifies the normal foreground color to use when displaying the widget." 2722 2723 <category: 'accessing'> 2724 self 2725 tclEval: '%1 configure -foreground %3' 2726 with: self connected 2727 with: self container 2728 with: value asTkString. 2729 self properties at: #foreground put: value 2730 ] 2731 2732 highlightBackground [ 2733 "Answer the value of the highlightBackground option for the widget. 2734 2735 Specifies the background color to use when displaying selected items 2736 in the widget." 2737 2738 <category: 'accessing'> 2739 self properties at: #selectbackground ifPresent: [:value | ^value]. 2740 self 2741 tclEval: '%1 cget -selectbackground' 2742 with: self connected 2743 with: self container. 2744 ^self properties at: #selectbackground put: self tclResult 2745 ] 2746 2747 highlightBackground: value [ 2748 "Set the value of the highlightBackground option for the widget. 2749 2750 Specifies the background color to use when displaying selected items 2751 in the widget." 2752 2753 <category: 'accessing'> 2754 self 2755 tclEval: '%1 configure -selectbackground %3' 2756 with: self connected 2757 with: self container 2758 with: value asTkString. 2759 self properties at: #selectbackground put: value 2760 ] 2761 2762 highlightForeground [ 2763 "Answer the value of the highlightForeground option for the widget. 2764 2765 Specifies the foreground color to use when displaying selected items 2766 in the widget." 2767 2768 <category: 'accessing'> 2769 self properties at: #selectforeground ifPresent: [:value | ^value]. 2770 self 2771 tclEval: '%1 cget -selectforeground' 2772 with: self connected 2773 with: self container. 2774 ^self properties at: #selectforeground put: self tclResult 2775 ] 2776 2777 highlightForeground: value [ 2778 "Set the value of the highlightForeground option for the widget. 2779 2780 Specifies the foreground color to use when displaying selected items 2781 in the widget." 2782 2783 <category: 'accessing'> 2784 self 2785 tclEval: '%1 configure -selectforeground %3' 2786 with: self connected 2787 with: self container 2788 with: value asTkString. 2789 self properties at: #selectforeground put: value 2790 ] 2791 2792 index [ 2793 "Answer the value of the index option for the widget. 2794 2795 Indicates the element that has the location cursor. This item will be 2796 displayed in the highlightForeground color, and with the corresponding 2797 background color." 2798 2799 <category: 'accessing'> 2800 ^self properties at: #index 2801 ifAbsentPut: 2802 [| iter | 2803 (iter := self connected getSelection getSelected) isNil 2804 ifTrue: [nil] 2805 ifFalse: [(self gtkmodel getStringFromIter: iter) asInteger]] 2806 ] 2807 2808 indexAt: point [ 2809 "Answer the index of the element that covers the point in the 2810 listbox window specified by x and y (in pixel coordinates). If no 2811 element covers that point, then the closest element to that point 2812 is used." 2813 2814 <category: 'accessing'> 2815 | pPath ok path index | 2816 pPath := GTK.GtkTreePath type ptrType gcNew. 2817 ok := self 2818 getPathAtPos: point x 2819 y: point y 2820 path: pPath 2821 column: nil 2822 cellX: nil 2823 cellY: nil. 2824 path := pPath value. 2825 index := ok ifTrue: [path getIndices value] ifFalse: [self elements size]. 2826 path free. 2827 ^index 2828 ] 2829 2830 isSelected: index [ 2831 "Answer whether the element indicated by index is currently selected." 2832 2833 <category: 'accessing'> 2834 | selected path | 2835 path := self pathAt: index. 2836 selected := self connected getSelection pathIsSelected: path. 2837 path free. 2838 ^selected 2839 ] 2840 2841 labelAt: anIndex [ 2842 "Answer the label displayed at the given position in the list 2843 box." 2844 2845 <category: 'accessing'> 2846 ^labels at: anIndex 2847 ] 2848 2849 labels [ 2850 "Answer the labels displayed by the list box." 2851 2852 <category: 'accessing'> 2853 ^labels copy 2854 ] 2855 2856 labelsDo: aBlock [ 2857 "Iterate over each listbox element's label and pass it to aBlock." 2858 2859 <category: 'accessing'> 2860 labels do: aBlock 2861 ] 2862 2863 mode [ 2864 "Answer the value of the mode option for the widget. 2865 2866 Specifies one of several styles for manipulating the selection. The value 2867 of the option may be either single, browse, multiple, or extended. 2868 2869 If the selection mode is single or browse, at most one element can be selected in 2870 the listbox at once. Clicking button 1 on an unselected element selects it and 2871 deselects any other selected item, while clicking on a selected element 2872 has no effect. In browse mode it is also possible to drag the selection 2873 with button 1. That is, moving the mouse while button 1 is pressed keeps 2874 the item under the cursor selected. 2875 2876 If the selection mode is multiple or extended, any number of elements may be 2877 selected at once, including discontiguous ranges. In multiple mode, clicking button 2878 1 on an element toggles its selection state without affecting any other elements. 2879 In extended mode, pressing button 1 on an element selects it, deselects 2880 everything else, and sets the anchor to the element under the mouse; dragging the 2881 mouse with button 1 down extends the selection to include all the elements between 2882 the anchor and the element under the mouse, inclusive. 2883 2884 In extended mode, the selected range can be adjusted by pressing button 1 2885 with the Shift key down: this modifies the selection to consist of the elements 2886 between the anchor and the element under the mouse, inclusive. The 2887 un-anchored end of this new selection can also be dragged with the button 2888 down. Also in extended mode, pressing button 1 with the Control key down starts a 2889 toggle operation: the anchor is set to the element under the mouse, and its 2890 selection state is reversed. The selection state of other elements is not 2891 changed. If the mouse is dragged with button 1 down, then the selection 2892 state of all elements between the anchor and the element under the mouse is 2893 set to match that of the anchor element; the selection state of all other 2894 elements remains what it was before the toggle operation began. 2895 2896 Most people will probably want to use browse mode for single selections and 2897 extended mode for multiple selections; the other modes appear to be useful only in 2898 special situations." 2899 2900 <category: 'accessing'> 2901 | mode | 2902 ^self properties at: #selectmode 2903 ifAbsentPut: 2904 [mode := self connected getSelection getMode. 2905 mode = GTK.Gtk gtkSelectionSingle 2906 ifTrue: [#single] 2907 ifFalse: 2908 [mode = GTK.Gtk gtkSelectionBrowse 2909 ifTrue: [#browse] 2910 ifFalse: [mode = GTK.Gtk gtkSelectionExtended ifTrue: [#extended]]]] 2911 ] 2912 2913 mode: value [ 2914 "Set the value of the mode option for the widget. 2915 2916 Specifies one of several styles for manipulating the selection. The value 2917 of the option may be either single, browse, multiple, or extended. 2918 2919 If the selection mode is single or browse, at most one element can be selected in 2920 the listbox at once. Clicking button 1 on an unselected element selects it and 2921 deselects any other selected item, while clicking on a selected element 2922 has no effect. In browse mode it is also possible to drag the selection 2923 with button 1. That is, moving the mouse while button 1 is pressed keeps 2924 the item under the cursor selected. 2925 2926 If the selection mode is multiple or extended, any number of elements may be 2927 selected at once, including discontiguous ranges. In multiple mode, clicking button 2928 1 on an element toggles its selection state without affecting any other elements. 2929 In extended mode, pressing button 1 on an element selects it, deselects 2930 everything else, and sets the anchor to the element under the mouse; dragging the 2931 mouse with button 1 down extends the selection to include all the elements between 2932 the anchor and the element under the mouse, inclusive. 2933 2934 In extended mode, the selected range can be adjusted by pressing button 1 2935 with the Shift key down: this modifies the selection to consist of the elements 2936 between the anchor and the element under the mouse, inclusive. The 2937 un-anchored end of this new selection can also be dragged with the button 2938 down. Also in extended mode, pressing button 1 with the Control key down starts a 2939 toggle operation: the anchor is set to the element under the mouse, and its 2940 selection state is reversed. The selection state of other elements is not 2941 changed. If the mouse is dragged with button 1 down, then the selection 2942 state of all elements between the anchor and the element under the mouse is 2943 set to match that of the anchor element; the selection state of all other 2944 elements remains what it was before the toggle operation began. 2945 2946 Most people will probably want to use browse mode for single selections and 2947 extended mode for multiple selections; the other modes appear to be useful only in 2948 special situations." 2949 2950 <category: 'accessing'> 2951 | mode | 2952 value = #single 2953 ifTrue: [mode := GTK.Gtk gtkSelectionSingle] 2954 ifFalse: 2955 [value = #browse 2956 ifTrue: [mode := GTK.Gtk gtkSelectionBrowse] 2957 ifFalse: 2958 [value = #multiple 2959 ifTrue: [mode := GTK.Gtk gtkSelectionExtended] 2960 ifFalse: 2961 [value = #extended 2962 ifTrue: [mode := GTK.Gtk gtkSelectionExtended] 2963 ifFalse: [^self error: 'invalid value for BList mode']]]]. 2964 self connected getSelection setMode: mode. 2965 self properties at: #selectmode put: value 2966 ] 2967 2968 numberOfStrings [ 2969 "Answer the number of items in the list box" 2970 2971 <category: 'accessing'> 2972 ^labels size 2973 ] 2974 2975 removeAtIndex: index [ 2976 "Remove the item at the given index in the list box, answering 2977 the object associated to the element (i.e. the value that #at: 2978 would have returned for the given index)" 2979 2980 <category: 'accessing'> 2981 | result | 2982 labels removeAtIndex: index. 2983 result := items removeAtIndex: index. 2984 self gtkmodel remove: (self iterAt: index). 2985 ^result 2986 ] 2987 2988 label [ 2989 "assign a new label to the list" 2990 2991 <category: 'accessing'> 2992 ^self gtkcolumn getTitle 2993 ] 2994 2995 label: aString [ 2996 "assign a new label to the list" 2997 2998 <category: 'accessing'> 2999 self gtkcolumn setTitle: aString 3000 ] 3001 3002 size [ 3003 "Answer the number of items in the list box" 3004 3005 <category: 'accessing'> 3006 ^labels size 3007 ] 3008 3009 itemSelected: receiver at: index [ 3010 <category: 'private - examples'> 3011 stdout 3012 nextPutAll: 'List item '; 3013 print: index; 3014 nextPutAll: ' selected!'; 3015 nl. 3016 stdout 3017 nextPutAll: 'Contents: '; 3018 nextPutAll: (items at: index); 3019 nl 3020 ] 3021 3022 gtkcolumn [ 3023 "answer the gtk column for the list" 3024 3025 <category: 'private'> 3026 gtkcolumn isNil ifTrue: [self createWidget]. 3027 ^gtkcolumn 3028 ] 3029 3030 gtkmodel [ 3031 "answer the gtk list model" 3032 3033 <category: 'private'> 3034 gtkmodel isNil ifTrue: [self createWidget]. 3035 ^gtkmodel 3036 ] 3037 3038 onChanged: selection data: userData [ 3039 <category: 'private'> 3040 | iter | 3041 (iter := selection getSelected) isNil 3042 ifFalse: [self invokeCallback: (self gtkmodel getStringFromIter: iter)] 3043 ] 3044 3045 pathAt: anIndex [ 3046 <category: 'private'> 3047 ^GTK.GtkTreePath newFromIndices: anIndex - 1 varargs: #() 3048 ] 3049 3050 iterAt: anIndex [ 3051 <category: 'private'> 3052 ^self gtkmodel iterNthChild: nil n: anIndex - 1 3053 ] 3054 3055 create [ 3056 <category: 'private'> 3057 | select renderer | 3058 renderer := GTK.GtkCellRendererText new. 3059 'phwoar... should not need the explicit calls, but something is bust in varargs passing' 3060 printNl. 3061 gtkcolumn := GTK.GtkTreeViewColumn new. 3062 gtkcolumn setTitle: 'List'. 3063 gtkcolumn packStart: renderer expand: true. 3064 gtkcolumn 3065 addAttribute: renderer 3066 attribute: 'text' 3067 column: 0. 3068 3069 "gtkcolumn := GTK.GtkTreeViewColumn newWithAttributes: 'List' cell: renderer varargs: {'text'. 0. nil}." 3070 gtkmodel := GTK.GtkListStore new: 1 varargs: {GTK.GValue gTypeString}. 3071 self connected: (GTK.GtkTreeView newWithModel: self gtkmodel). 3072 (self connected) 3073 appendColumn: self gtkcolumn; 3074 setSearchColumn: 0. 3075 select := self connected getSelection. 3076 select setMode: GTK.Gtk gtkSelectionSingle. 3077 select 3078 connectSignal: 'changed' 3079 to: self 3080 selector: #onChanged:data: 3081 userData: nil 3082 ] 3083 3084 show [ 3085 <category: 'private'> 3086 super show. 3087 self container setShadowType: GTK.Gtk gtkShadowIn 3088 ] 3089 3090 needsViewport [ 3091 <category: 'private'> 3092 ^false 3093 ] 3094 3095 initialize: parentWidget [ 3096 <category: 'private'> 3097 super initialize: parentWidget. 3098 self properties at: #index put: nil. 3099 labels := OrderedCollection new 3100 ] 3101 3102 invokeCallback: indexString [ 3103 <category: 'private'> 3104 | index | 3105 items isNil ifTrue: [^self]. 3106 index := indexString asInteger. 3107 self properties at: #index put: index + 1. 3108 self invokeCallback 3109 ] 3110 3111 callback [ 3112 "Answer a DirectedMessage that is sent when the active item in 3113 the receiver changes, or nil if none has been set up." 3114 3115 <category: 'widget protocol'> 3116 ^callback 3117 ] 3118 3119 callback: aReceiver message: aSymbol [ 3120 "Set up so that aReceiver is sent the aSymbol message (the name of 3121 a selector with at most two arguemtnts) when the active item in 3122 the receiver changegs. If the method accepts two arguments, the 3123 receiver is passed as the first parameter. If the method accepts 3124 one or two arguments, the selected index is passed as the last 3125 parameter." 3126 3127 <category: 'widget protocol'> 3128 | arguments selector numArgs | 3129 selector := aSymbol asSymbol. 3130 numArgs := selector numArgs. 3131 arguments := #(). 3132 numArgs = 1 ifTrue: [arguments := {nil}]. 3133 numArgs = 2 3134 ifTrue: 3135 [arguments := 3136 {self. 3137 nil}]. 3138 callback := DirectedMessage 3139 selector: selector 3140 arguments: arguments 3141 receiver: aReceiver 3142 ] 3143 3144 highlight: index [ 3145 "Highlight the item at the given position in the listbox." 3146 3147 <category: 'widget protocol'> 3148 index = self index ifTrue: [^self]. 3149 (self mode = #single or: [self mode = #browse]) ifTrue: [self unhighlight]. 3150 self select: index 3151 ] 3152 3153 invokeCallback [ 3154 "Generate a synthetic callback." 3155 3156 <category: 'widget protocol'> 3157 self callback notNil 3158 ifTrue: 3159 [self callback arguments isEmpty 3160 ifFalse: 3161 [self callback arguments at: self callback arguments size 3162 put: (self properties at: #index)]. 3163 self callback send] 3164 ] 3165 3166 select: index [ 3167 "Highlight the item at the given position in the listbox, 3168 without unhighlighting other items. This is meant for 3169 multiple- or extended-mode listboxes, but can be used 3170 with other selection mode in particular cases." 3171 3172 <category: 'widget protocol'> 3173 self properties at: #index put: index. 3174 self connected getSelection selectIter: (self iterAt: index) 3175 ] 3176 3177 show: index [ 3178 "Ensure that the item at the given position in the listbox is 3179 visible." 3180 3181 <category: 'widget protocol'> 3182 | path | 3183 path := self pathAt: index. 3184 self connected 3185 scrollToCell: path 3186 column: self gtkcolumn 3187 useAlign: false 3188 rowAlign: 0.0e 3189 colAlign: 0.0e. 3190 path free 3191 ] 3192 3193 unhighlight [ 3194 "Unhighlight all the items in the listbox." 3195 3196 <category: 'widget protocol'> 3197 self connected getSelection unselectAll 3198 ] 3199 3200 unselect: index [ 3201 "Unhighlight the item at the given position in the listbox, 3202 without affecting the state of the other items." 3203 3204 <category: 'widget protocol'> 3205 self connected getSelection unselectIter: (self iterAt: index) 3206 ] 3207] 3208 3209 3210 3211BForm subclass: BWindow [ 3212 | isMapped callback x y width height container uiBox uiManager | 3213 3214 <comment: 'I am the boss. Nothing else could be viewed or interacted with if 3215it wasn''t for me... )):->'> 3216 <category: 'Graphics-Windows'> 3217 3218 TopLevel := nil. 3219 3220 BWindow class >> initializeOnStartup [ 3221 <category: 'private - initialization'> 3222 TopLevel := OrderedCollection new 3223 ] 3224 3225 BWindow class >> new [ 3226 "Answer a new top-level window." 3227 3228 <category: 'instance creation'> 3229 ^TopLevel add: (super new: nil) 3230 ] 3231 3232 BWindow class >> new: label [ 3233 "Answer a new top-level window with `label' as its title bar caption." 3234 3235 <category: 'instance creation'> 3236 ^self new label: label 3237 ] 3238 3239 BWindow class >> popup: initializationBlock [ 3240 <category: 'instance creation'> 3241 self shouldNotImplement 3242 ] 3243 3244 callback [ 3245 "Answer a DirectedMessage that is sent to verify whether the 3246 receiver must be destroyed when the user asks to unmap it." 3247 3248 <category: 'accessing'> 3249 ^callback 3250 ] 3251 3252 callback: aReceiver message: aSymbol [ 3253 "Set up so that aReceiver is sent the aSymbol message (the name of 3254 a zero- or one-argument selector) when the user asks to unmap the 3255 receiver. If the method accepts an argument, the receiver is passed. 3256 3257 If the method returns true, the window and its children are 3258 destroyed (which is the default action, taken if no callback is 3259 set up). If the method returns false, the window is left in 3260 place." 3261 3262 <category: 'accessing'> 3263 | arguments selector numArgs | 3264 selector := aSymbol asSymbol. 3265 numArgs := selector numArgs. 3266 arguments := #(). 3267 numArgs = 1 ifTrue: [arguments := Array with: self]. 3268 callback := DirectedMessage 3269 selector: selector 3270 arguments: arguments 3271 receiver: aReceiver 3272 ] 3273 3274 invokeCallback [ 3275 "Generate a synthetic callback, destroying the window if no 3276 callback was set up or if the callback method answers true." 3277 3278 <category: 'accessing'> 3279 | result | 3280 result := self callback isNil or: [self callback send]. 3281 result 3282 ifTrue: 3283 [self destroy. 3284 isMapped := false]. 3285 ^result 3286 ] 3287 3288 label [ 3289 "Answer the value of the label option for the widget. 3290 3291 Specifies a string to be displayed inside the widget. The way in which the 3292 string is displayed depends on the particular widget and may be determined 3293 by other options, such as anchor. For windows, this is the title of the 3294 window." 3295 3296 <category: 'accessing'> 3297 ^self container getTitle 3298 ] 3299 3300 label: value [ 3301 "Set the value of the label option for the widget. 3302 3303 Specifies a string to be displayed inside the widget. The way in which the 3304 string is displayed depends on the particular widget and may be determined 3305 by other options, such as anchor. For windows, this is the title of the 3306 window." 3307 3308 <category: 'accessing'> 3309 self container setTitle: value 3310 ] 3311 3312 menu: aBMenuBar [ 3313 "Set the value of the menu option for the widget. 3314 3315 Specifies a menu widget to be used as a menubar." 3316 3317 <category: 'accessing'> 3318 self uiBox 3319 packStart: aBMenuBar connected 3320 expand: false 3321 fill: false 3322 padding: 0. 3323 self properties at: #menu put: aBMenuBar 3324 ] 3325 3326 resizable [ 3327 "Answer the value of the resizable option for the widget. 3328 3329 Answer whether the user can be resize the window or not. If resizing is 3330 disabled, then the window's size will be the size from the most recent 3331 interactive resize or geometry-setting method. If there has been no such 3332 operation then the window's natural size will be used." 3333 3334 <category: 'accessing'> 3335 ^self container getResizable 3336 ] 3337 3338 resizable: value [ 3339 "Set the value of the resizable option for the widget. 3340 3341 Answer whether the user can be resize the window or not. If resizing is 3342 disabled, then the window's size will be the size from the most recent 3343 interactive resize or geometry-setting method. If there has been no such 3344 operation then the window's natural size will be used." 3345 3346 <category: 'accessing'> 3347 ^self container setResizable: value 3348 ] 3349 3350 uiBox [ 3351 "answer the top level container for this window" 3352 3353 <category: 'accessing'> 3354 ^uiBox 3355 ] 3356 3357 uiManager [ 3358 <category: 'accessing'> 3359 uiManager isNil ifTrue: [uiManager := GTK.GtkUIManager new]. 3360 ^uiManager 3361 ] 3362 3363 cacheWindowSize [ 3364 "save the window position from gtk" 3365 3366 <category: 'private'> 3367 | px py | 3368 px := CIntType gcNew. 3369 py := CIntType gcNew. 3370 self container getPosition: px rootY: py. 3371 x := px value. 3372 y := py value. 3373 self isMapped 3374 ifTrue: [self container getSize: px height: py] 3375 ifFalse: [self container getDefaultSize: px height: py]. 3376 width := px value. 3377 height := py value. 3378 self isMapped 3379 ifTrue: [self container setDefaultSize: width height: height] 3380 ] 3381 3382 container [ 3383 <category: 'private'> 3384 container isNil ifTrue: [self error: 'GTK object not created yet']. 3385 ^container 3386 ] 3387 3388 container: aWidget [ 3389 <category: 'private'> 3390 container := aWidget 3391 ] 3392 3393 initialize: parentWidget [ 3394 <category: 'private'> 3395 super initialize: nil. 3396 self isMapped: false. 3397 self createWidget 3398 ] 3399 3400 create [ 3401 <category: 'private'> 3402 self container: (GTK.GtkWindow new: GTK.Gtk gtkWindowToplevel). 3403 self container 3404 connectSignal: 'delete-event' 3405 to: self 3406 selector: #onDelete:data: 3407 userData: nil. 3408 self container 3409 connectSignal: 'configure-event' 3410 to: self 3411 selector: #onConfigure:data: 3412 userData: nil. 3413 uiBox := GTK.GtkVBox new: false spacing: 0. 3414 self container add: uiBox. 3415 3416 "Create the GtkPlacer" 3417 super create. 3418 uiBox 3419 packEnd: self connected 3420 expand: true 3421 fill: true 3422 padding: 0 3423 ] 3424 3425 show [ 3426 "Do not show the GtkWindow until it is mapped!" 3427 3428 <category: 'private'> 3429 super show. 3430 uiBox show 3431 ] 3432 3433 onConfigure: object data: data [ 3434 <category: 'private'> 3435 self cacheWindowSize 3436 ] 3437 3438 onDelete: object data: data [ 3439 <category: 'private'> 3440 ^self callback notNil and: [self callback send not] 3441 ] 3442 3443 destroyed [ 3444 "Private - The receiver has been destroyed, remove it from the 3445 list of toplevel windows to avoid memory leaks." 3446 3447 <category: 'private'> 3448 super destroyed. 3449 TopLevel remove: self ifAbsent: []. 3450 (TopLevel isEmpty and: [DoDispatchEvents = 1]) 3451 ifTrue: [Blox terminateMainLoop] 3452 ] 3453 3454 isMapped: aBoolean [ 3455 <category: 'private'> 3456 isMapped := aBoolean 3457 ] 3458 3459 resetGeometry: xPos y: yPos width: xSize height: ySize [ 3460 <category: 'private'> 3461 (x = xPos and: [y = yPos and: [width = xSize and: [height = ySize]]]) 3462 ifTrue: [^self]. 3463 self isMapped 3464 ifFalse: [self container setDefaultSize: xSize height: ySize] 3465 ifTrue: [self container resize: xSize height: ySize]. 3466 x := xPos. 3467 y := yPos. 3468 width := xSize. 3469 height := ySize 3470 "mapped ifTrue: [ self map ]." 3471 ] 3472 3473 resized [ 3474 <category: 'private'> 3475 self isMapped ifFalse: [^self]. 3476 x := y := width := height := nil 3477 ] 3478 3479 setInitialSize [ 3480 <category: 'private'> 3481 self 3482 x: 0 3483 y: 0 3484 width: 300 3485 height: 300 3486 ] 3487 3488 center [ 3489 "Center the window in the screen" 3490 3491 <category: 'widget protocol'> 3492 | screenSize | 3493 screenSize := Blox screenSize. 3494 self x: screenSize x // 2 - (self width // 2) 3495 y: screenSize y // 2 - (self height // 2) 3496 ] 3497 3498 centerIn: view [ 3499 "Center the window in the given widget" 3500 3501 <category: 'widget protocol'> 3502 self x: view x + (view width // 2) - (self parent width // 2) 3503 y: view x + (view height // 2) - (self parent height // 2) 3504 ] 3505 3506 height [ 3507 "Answer the height of the window, as deduced from the geometry 3508 that the window manager imposed on the window." 3509 3510 <category: 'widget protocol'> 3511 height isNil ifTrue: [self cacheWindowSize]. 3512 ^height 3513 ] 3514 3515 height: anInteger [ 3516 "Ask the window manager to give the given height to the window." 3517 3518 <category: 'widget protocol'> 3519 width isNil ifTrue: [self cacheWindowSize]. 3520 self 3521 resetGeometry: x 3522 y: y 3523 width: width 3524 height: anInteger 3525 ] 3526 3527 heightAbsolute [ 3528 "Answer the height of the window, as deduced from the geometry 3529 that the window manager imposed on the window." 3530 3531 <category: 'widget protocol'> 3532 height isNil ifTrue: [self cacheWindowSize]. 3533 ^height 3534 ] 3535 3536 heightOffset: value [ 3537 <category: 'widget protocol'> 3538 self shouldNotImplement 3539 ] 3540 3541 iconify [ 3542 "Map a window and in iconified state. If a window has not been 3543 mapped yet, this is achieved by mapping the window in withdrawn 3544 state first, and then iconifying it." 3545 3546 <category: 'widget protocol'> 3547 self container iconify. 3548 self isMapped: false 3549 ] 3550 3551 isMapped [ 3552 "Answer whether the window is mapped" 3553 3554 <category: 'widget protocol'> 3555 isMapped isNil ifTrue: [isMapped := false]. 3556 ^isMapped 3557 ] 3558 3559 isWindow [ 3560 <category: 'widget protocol'> 3561 ^true 3562 ] 3563 3564 map [ 3565 "Map the window and bring it to the topmost position in the Z-order." 3566 3567 <category: 'widget protocol'> 3568 self container present. 3569 self isMapped: true 3570 ] 3571 3572 modalMap [ 3573 "Map the window while establishing an application-local grab for it. 3574 An event loop is started that ends only after the window has been 3575 destroyed." 3576 3577 <category: 'widget protocol'> 3578 self container setModal: true. 3579 self map. 3580 Blox dispatchEvents: self. 3581 self container setModal: false 3582 ] 3583 3584 state [ 3585 "Set the value of the state option for the window. 3586 3587 Specifies one of four states for the window: either normal, iconic, 3588 withdrawn, or (Windows only) zoomed." 3589 3590 <category: 'widget protocol'> 3591 self tclEval: 'wm state ' , self connected. 3592 ^self tclResult asSymbol 3593 ] 3594 3595 state: aSymbol [ 3596 "Raise an error. To set a BWindow's state, use #map and #unmap." 3597 3598 <category: 'widget protocol'> 3599 self error: 'To set a BWindow''s state, use #map and #unmap.' 3600 ] 3601 3602 unmap [ 3603 "Unmap a window, causing it to be forgotten about by the window manager" 3604 3605 <category: 'widget protocol'> 3606 self isMapped ifFalse: [^self]. 3607 self hide. 3608 self isMapped: false 3609 ] 3610 3611 width [ 3612 "Answer the width of the window, as deduced from the geometry 3613 that the window manager imposed on the window." 3614 3615 <category: 'widget protocol'> 3616 width isNil ifTrue: [self cacheWindowSize]. 3617 ^width 3618 ] 3619 3620 width: anInteger [ 3621 "Ask the window manager to give the given width to the window." 3622 3623 <category: 'widget protocol'> 3624 height isNil ifTrue: [self cacheWindowSize]. 3625 self 3626 resetGeometry: x 3627 y: y 3628 width: anInteger 3629 height: height 3630 ] 3631 3632 width: xSize height: ySize [ 3633 "Ask the window manager to give the given width and height to 3634 the window." 3635 3636 <category: 'widget protocol'> 3637 self 3638 resetGeometry: x 3639 y: y 3640 width: xSize 3641 height: ySize 3642 ] 3643 3644 widthAbsolute [ 3645 "Answer the width of the window, as deduced from the geometry 3646 that the window manager imposed on the window." 3647 3648 <category: 'widget protocol'> 3649 width isNil ifTrue: [self cacheWindowSize]. 3650 ^width 3651 ] 3652 3653 widthOffset: value [ 3654 <category: 'widget protocol'> 3655 self shouldNotImplement 3656 ] 3657 3658 window [ 3659 <category: 'widget protocol'> 3660 ^self 3661 ] 3662 3663 x [ 3664 "Answer the x coordinate of the window's top-left corner, as 3665 deduced from the geometry that the window manager imposed on 3666 the window." 3667 3668 <category: 'widget protocol'> 3669 x isNil ifTrue: [self cacheWindowSize]. 3670 ^x 3671 ] 3672 3673 x: anInteger [ 3674 "Ask the window manager to move the window's left border 3675 to the given x coordinate, keeping the size unchanged" 3676 3677 <category: 'widget protocol'> 3678 y isNil ifTrue: [self cacheWindowSize]. 3679 self 3680 resetGeometry: anInteger 3681 y: y 3682 width: width 3683 height: height 3684 ] 3685 3686 x: xPos y: yPos [ 3687 "Ask the window manager to move the window's top-left corner 3688 to the given coordinates, keeping the size unchanged" 3689 3690 <category: 'widget protocol'> 3691 self 3692 resetGeometry: xPos 3693 y: yPos 3694 width: width 3695 height: height 3696 ] 3697 3698 x: xPos y: yPos width: xSize height: ySize [ 3699 "Ask the window manager to give the requested geometry 3700 to the window." 3701 3702 "XXX gtk deprecates this sort of thing" 3703 3704 3705 3706 <category: 'widget protocol'> 3707 self 3708 resetGeometry: xPos 3709 y: yPos 3710 width: xSize 3711 height: ySize 3712 ] 3713 3714 xAbsolute [ 3715 "Answer the x coordinate of the window's top-left corner, as 3716 deduced from the geometry that the window manager imposed on 3717 the window." 3718 3719 <category: 'widget protocol'> 3720 x isNil ifTrue: [self cacheWindowSize]. 3721 ^x 3722 ] 3723 3724 xOffset: value [ 3725 <category: 'widget protocol'> 3726 self shouldNotImplement 3727 ] 3728 3729 y [ 3730 "Answer the y coordinate of the window's top-left corner, as 3731 deduced from the geometry that the window manager imposed on 3732 the window." 3733 3734 <category: 'widget protocol'> 3735 y isNil ifTrue: [self cacheWindowSize]. 3736 ^y 3737 ] 3738 3739 y: anInteger [ 3740 "Ask the window manager to move the window's left border 3741 to the given y coordinate, keeping the size unchanged" 3742 3743 <category: 'widget protocol'> 3744 x isNil ifTrue: [self cacheWindowSize]. 3745 self 3746 resetGeometry: x 3747 y: anInteger 3748 width: width 3749 height: height 3750 ] 3751 3752 yAbsolute [ 3753 "Answer the y coordinate of the window's top-left corner, as 3754 deduced from the geometry that the window manager imposed on 3755 the window." 3756 3757 <category: 'widget protocol'> 3758 y isNil ifTrue: [self cacheWindowSize]. 3759 ^y 3760 ] 3761 3762 yOffset: value [ 3763 <category: 'widget protocol'> 3764 self shouldNotImplement 3765 ] 3766] 3767 3768 3769 3770BWindow subclass: BTransientWindow [ 3771 3772 <comment: 'I am almost a boss. I represent a window which is logically linked 3773to another which sits higher in the widget hierarchy, e.g. a dialog 3774box'> 3775 <category: 'Graphics-Windows'> 3776 3777 BTransientWindow class >> new [ 3778 <category: 'instance creation'> 3779 self shouldNotImplement 3780 ] 3781 3782 BTransientWindow class >> new: parentWindow [ 3783 "Answer a new transient window attached to the given 3784 parent window and with nothing in its title bar caption." 3785 3786 <category: 'instance creation'> 3787 ^(self basicNew) 3788 initialize: parentWindow; 3789 yourself 3790 ] 3791 3792 BTransientWindow class >> new: label in: parentWindow [ 3793 "Answer a new transient window attached to the given 3794 parent window and with `label' as its title bar caption." 3795 3796 <category: 'instance creation'> 3797 ^(self basicNew) 3798 initialize: parentWindow; 3799 label: label; 3800 yourself 3801 ] 3802 3803 map [ 3804 "Map the window and inform the windows manager that the 3805 receiver is a transient window working on behalf of its 3806 parent. The window is also put in its parent window's 3807 window group: the window manager might use this information, 3808 for example, to unmap all of the windows in a group when the 3809 group's leader is iconified." 3810 3811 <category: 'widget protocol'> 3812 self parent isNil 3813 ifFalse: [self container setTransientFor: self parent container]. 3814 super map 3815 ] 3816] 3817 3818 3819 3820BWindow subclass: BPopupWindow [ 3821 3822 <comment: 'I am a pseudo-window that has no decorations and no ability to interact 3823with the user. My main usage, as my name says, is to provide pop-up 3824functionality for other widgets. Actually there should be no need to 3825directly use me - always rely on the #new and #popup: class methods.'> 3826 <category: 'Graphics-Windows'> 3827 3828 addChild: w [ 3829 "Private - The widget identified by child has been added to the 3830 receiver. This method is public not because you can call it, 3831 but because it can be useful to override it to perform some 3832 initialization on the children just added. Answer the new child." 3833 3834 <category: 'geometry management'> 3835 self uiBox 3836 packEnd: w 3837 expand: true 3838 fill: true 3839 padding: 1. 3840 w onDestroySend: #destroy to: self 3841 ] 3842 3843 child: child height: value [ 3844 "Set the given child's height. This is done by setting 3845 its parent window's (that is, our) height." 3846 3847 "Only act after #addChild:" 3848 3849 <category: 'geometry management'> 3850 self childrenCount = 0 ifTrue: [^self]. 3851 self height: value 3852 ] 3853 3854 child: child heightOffset: value [ 3855 <category: 'geometry management'> 3856 self shouldNotImplement 3857 ] 3858 3859 child: child width: value [ 3860 "Set the given child's width. This is done by setting 3861 its parent window's (that is, our) width." 3862 3863 "Only act after #addChild:" 3864 3865 <category: 'geometry management'> 3866 self childrenCount = 0 ifTrue: [^self]. 3867 self width: value 3868 ] 3869 3870 child: child widthOffset: value [ 3871 <category: 'geometry management'> 3872 self shouldNotImplement 3873 ] 3874 3875 child: child x: value [ 3876 "Set the x coordinate of the given child's top-left corner. 3877 This is done by setting its parent window's (that is, our) x." 3878 3879 <category: 'geometry management'> 3880 self x: value 3881 ] 3882 3883 child: child xOffset: value [ 3884 <category: 'geometry management'> 3885 self shouldNotImplement 3886 ] 3887 3888 child: child y: value [ 3889 "Set the y coordinate of the given child's top-left corner. 3890 This is done by setting its parent window's (that is, our) y." 3891 3892 <category: 'geometry management'> 3893 self y: value 3894 ] 3895 3896 child: child yOffset: value [ 3897 <category: 'geometry management'> 3898 self shouldNotImplement 3899 ] 3900 3901 heightChild: child [ 3902 "Answer the given child's height, which is the height that 3903 was imposed on the popup window." 3904 3905 <category: 'geometry management'> 3906 ^self height 3907 ] 3908 3909 widthChild: child [ 3910 "Answer the given child's width in pixels, which is the width that 3911 was imposed on the popup window." 3912 3913 <category: 'geometry management'> 3914 ^self width 3915 ] 3916 3917 xChild: child [ 3918 "Answer the x coordinate of the given child's top-left corner, 3919 which is desumed by the position of the popup window." 3920 3921 <category: 'geometry management'> 3922 ^self x 3923 ] 3924 3925 yChild: child [ 3926 "Answer the y coordinate of the given child's top-left corner, 3927 which is desumed by the position of the popup window." 3928 3929 <category: 'geometry management'> 3930 ^self y 3931 ] 3932 3933 create [ 3934 <category: 'private'> 3935 super create. 3936 self container setDecorated: false. 3937 self container setResizable: false 3938 ] 3939 3940 setInitialSize [ 3941 <category: 'private'> 3942 self cacheWindowSize 3943 ] 3944] 3945 3946 3947 3948BForm subclass: BDialog [ 3949 | callbacks initInfo buttonBox entry | 3950 3951 <comment: 'I am a facility for implementing dialogs with many possible choices 3952and requests. In addition I provide support for a few platform native 3953common dialog boxes, such as choose-a-file and choose-a-color.'> 3954 <category: 'Graphics-Windows'> 3955 3956 BDialog class >> new: parent [ 3957 "Answer a new dialog handler (containing a label widget and 3958 some button widgets) laid out within the given parent window. 3959 The label widget, when it is created, is empty." 3960 3961 <category: 'instance creation'> 3962 ^(self basicNew) 3963 initInfo: '' -> nil; 3964 initialize: parent 3965 ] 3966 3967 BDialog class >> new: parent label: aLabel [ 3968 "Answer a new dialog handler (containing a label widget and 3969 some button widgets) laid out within the given parent window. 3970 The label widget, when it is created, contains aLabel." 3971 3972 <category: 'instance creation'> 3973 ^(self basicNew) 3974 initInfo: aLabel -> nil; 3975 initialize: parent 3976 ] 3977 3978 BDialog class >> new: parent label: aLabel prompt: aString [ 3979 "Answer a new dialog handler (containing a label widget, some 3980 button widgets, and an edit window showing aString by default) 3981 laid out within the given parent window. 3982 The label widget, when it is created, contains aLabel." 3983 3984 <category: 'instance creation'> 3985 ^(self basicNew) 3986 initInfo: aLabel -> aString; 3987 initialize: parent 3988 ] 3989 3990 BDialog class >> chooseFile: operation parent: parent label: aLabel default: name defaultExtension: ext types: typeList action: action button: button [ 3991 <category: 'private'> 3992 | dialog result filename | 3993 'FIXME: implement the default, defaultExtension and typesList portions' 3994 printNl. 3995 parent map. 3996 dialog := GTK.GtkFileChooserDialog 3997 new: aLabel 3998 parent: parent container 3999 action: action 4000 varargs: 4001 {GTK.Gtk gtkStockCancel. 4002 GTK.Gtk gtkResponseCancel. 4003 button. 4004 GTK.Gtk gtkResponseAccept. 4005 nil}. 4006 result := dialog run. 4007 ^result = GTK.Gtk gtkResponseAccept 4008 ifFalse: 4009 [dialog destroy. 4010 nil] 4011 ifTrue: 4012 [filename := dialog getFilename. 4013 filename isEmpty ifTrue: [filename := nil]. 4014 dialog destroy. 4015 filename] 4016 ] 4017 4018 BDialog class >> chooseColor: parent label: aLabel default: color [ 4019 "Prompt for a color. The dialog box is created with the given 4020 parent window and with aLabel as its title bar text, and initially 4021 it selects the color given in the color parameter. 4022 4023 If the dialog box is canceled, nil is answered, else the 4024 selected color is returned as a String with its RGB value." 4025 4026 <category: 'prompters'> 4027 | result | 4028 parent map. 4029 self 4030 tclEval: 'tk_chooseColor -parent %1 -title %2 -initialcolor %3' 4031 with: parent container 4032 with: aLabel asTkString 4033 with: color asTkString. 4034 result := self tclResult. 4035 result isEmpty ifTrue: [result := nil]. 4036 ^result 4037 ] 4038 4039 BDialog class >> chooseFileToOpen: parent label: aLabel default: name defaultExtension: ext types: typeList [ 4040 "Pop up a dialog box for the user to select a file to open. 4041 Its purpose is for the user to select an existing file only. 4042 If the user enters an non-existent file, the dialog box gives 4043 the user an error prompt and requires the user to give an 4044 alternative selection or to cancel the selection. If an 4045 application allows the user to create new files, it should 4046 do so by providing a separate New menu command. 4047 4048 If the dialog box is canceled, nil is answered, else the 4049 selected file name is returned as a String. 4050 4051 The dialog box is created with the given parent window 4052 and with aLabel as its title bar text. The name parameter 4053 indicates which file is initially selected, and the default 4054 extension specifies a string that will be appended to the 4055 filename if the user enters a filename without an extension. 4056 4057 The typeList parameter is an array of arrays, like 4058 #(('Text files' '.txt' '.diz') ('Smalltalk files' '.st')), 4059 and is used to construct a listbox of file types. When the user 4060 chooses a file type in the listbox, only the files of that type 4061 are listed. Each item in the array contains a list of strings: 4062 the first one is the name of the file type described by a particular 4063 file pattern, and is the text string that appears in the File types 4064 listbox, while the other ones are the possible extensions that 4065 belong to this particular file type." 4066 4067 "e.g. 4068 fileName := BDialog 4069 chooseFileToOpen: aWindow 4070 label: 'Open file' 4071 default: nil 4072 defaultExtension: 'gif' 4073 types: #( 4074 ('Text files' '.txt' '.diz') 4075 ('Smalltalk files' '.st') 4076 ('C source files' '.c') 4077 ('GIF files' '.gif'))" 4078 4079 <category: 'prompters'> 4080 ^self 4081 chooseFile: 'Open' 4082 parent: parent 4083 label: aLabel 4084 default: name 4085 defaultExtension: ext 4086 types: typeList 4087 action: GTK.Gtk gtkFileChooserActionOpen 4088 button: GTK.Gtk gtkStockOpen 4089 ] 4090 4091 BDialog class >> chooseFileToSave: parent label: aLabel default: name defaultExtension: ext types: typeList [ 4092 "Pop up a dialog box for the user to select a file to save; 4093 this differs from the file open dialog box in that non-existent 4094 file names are accepted and existing file names trigger a 4095 confirmation dialog box, asking the user whether the file 4096 should be overwritten or not. 4097 4098 If the dialog box is canceled, nil is answered, else the 4099 selected file name is returned as a String. 4100 4101 The dialog box is created with the given parent window 4102 and with aLabel as its title bar text. The name parameter 4103 indicates which file is initially selected, and the default 4104 extension specifies a string that will be appended to the 4105 filename if the user enters a filename without an extension. 4106 4107 The typeList parameter is an array of arrays, like 4108 #(('Text files' '.txt' '.diz') ('Smalltalk files' '.st')), 4109 and is used to construct a listbox of file types. When the user 4110 chooses a file type in the listbox, only the files of that type 4111 are listed. Each item in the array contains a list of strings: 4112 the first one is the name of the file type described by a particular 4113 file pattern, and is the text string that appears in the File types 4114 listbox, while the other ones are the possible extensions that 4115 belong to this particular file type." 4116 4117 <category: 'prompters'> 4118 ^self 4119 chooseFile: 'Save' 4120 parent: parent 4121 label: aLabel 4122 default: name 4123 defaultExtension: ext 4124 types: typeList 4125 action: GTK.Gtk gtkFileChooserActionSave 4126 button: GTK.Gtk gtkStockSave 4127 ] 4128 4129 addButton: aLabel receiver: anObject index: anInt [ 4130 "Add a button to the dialog box that, when clicked, will 4131 cause the #dispatch: method to be triggered in anObject, 4132 passing anInt as the argument of the callback. The 4133 caption of the button is set to aLabel." 4134 4135 <category: 'accessing'> 4136 ^self 4137 addButton: aLabel 4138 receiver: anObject 4139 message: #dispatch: 4140 argument: anInt 4141 ] 4142 4143 addButton: aLabel receiver: anObject message: aSymbol [ 4144 "Add a button to the dialog box that, when clicked, will 4145 cause the aSymbol unary selector to be sent to anObject. 4146 The caption of the button is set to aLabel." 4147 4148 <category: 'accessing'> 4149 callbacks addLast: (DirectedMessage 4150 selector: aSymbol 4151 arguments: #() 4152 receiver: anObject). 4153 self addButton: aLabel 4154 ] 4155 4156 addButton: aLabel receiver: anObject message: aSymbol argument: arg [ 4157 "Add a button to the dialog box that, when clicked, will 4158 cause the aSymbol one-argument selector to be sent to anObject, 4159 passing arg as the argument of the callback. The 4160 caption of the button is set to aLabel." 4161 4162 <category: 'accessing'> 4163 callbacks addLast: (DirectedMessage 4164 selector: aSymbol 4165 arguments: {arg} 4166 receiver: anObject). 4167 self addButton: aLabel 4168 ] 4169 4170 contents: newText [ 4171 "Display newText in the entry widget associated to the dialog box." 4172 4173 <category: 'accessing'> 4174 entry setText: newText 4175 ] 4176 4177 contents [ 4178 "Answer the text that is displayed in the entry widget associated 4179 to the dialog box." 4180 4181 <category: 'accessing'> 4182 ^entry getText 4183 ] 4184 4185 addButton: aLabel [ 4186 <category: 'private'> 4187 | button | 4188 self buttonBox add: (button := GTK.GtkButton newWithLabel: aLabel). 4189 button show. 4190 button 4191 connectSignal: 'clicked' 4192 to: self 4193 selector: #clicked:data: 4194 userData: callbacks size 4195 ] 4196 4197 clicked: button data: data [ 4198 <category: 'private'> 4199 self invokeCallback: data. 4200 self toplevel destroy 4201 ] 4202 4203 buttonBox [ 4204 <category: 'private'> 4205 buttonBox isNil ifTrue: [self create]. 4206 ^buttonBox 4207 ] 4208 4209 create [ 4210 "We do not use BDialog. Instead, we work in the toplevel's 4211 uiBox, because Blox makes the BDialog live into a BWindow 4212 that provides space for other widgets." 4213 4214 <category: 'private'> 4215 | uiBox label separator | 4216 super create. 4217 uiBox := self toplevel uiBox. 4218 buttonBox := GTK.GtkHButtonBox new. 4219 buttonBox setSpacing: 5. 4220 buttonBox setLayout: GTK.Gtk gtkButtonboxEnd. 4221 uiBox 4222 packEnd: buttonBox 4223 expand: false 4224 fill: false 4225 padding: 5. 4226 buttonBox show. 4227 separator := GTK.GtkHSeparator new. 4228 uiBox 4229 packEnd: separator 4230 expand: false 4231 fill: false 4232 padding: 0. 4233 separator show. 4234 4235 "Put the GtkPlacer at the end of the list of the end-packed widgets, 4236 which puts it above our GtkHSeparator and GtkHButtonBox." 4237 uiBox reorderChild: self toplevel connected position: -1. 4238 initInfo isNil ifTrue: [^self]. 4239 label := GTK.GtkLabel new: initInfo key. 4240 label setAlignment: 0 yalign: 0. 4241 uiBox 4242 packStart: label 4243 expand: false 4244 fill: false 4245 padding: 5. 4246 label show. 4247 initInfo value isNil ifTrue: [^self]. 4248 entry := GTK.GtkEntry new. 4249 entry setText: initInfo value. 4250 uiBox 4251 packStart: entry 4252 expand: false 4253 fill: false 4254 padding: 0. 4255 entry show 4256 ] 4257 4258 initInfo: assoc [ 4259 <category: 'private'> 4260 initInfo := assoc 4261 ] 4262 4263 initialize: parentWidget [ 4264 <category: 'private'> 4265 super initialize: parentWidget. 4266 callbacks := OrderedCollection new 4267 ] 4268 4269 center [ 4270 "Center the dialog box's parent window in the screen" 4271 4272 <category: 'widget protocol'> 4273 self parent center 4274 ] 4275 4276 centerIn: view [ 4277 "Center the dialog box's parent window in the given widget" 4278 4279 <category: 'widget protocol'> 4280 self parent centerIn: view 4281 ] 4282 4283 invokeCallback: index [ 4284 "Generate a synthetic callback corresponding to the index-th 4285 button being pressed, and destroy the parent window (triggering 4286 its callback if one was established)." 4287 4288 <category: 'widget protocol'> 4289 (callbacks at: index asInteger) send 4290 "self parent destroy" 4291 ] 4292 4293 loop [ 4294 "Map the parent window modally. In other words, an event loop 4295 is started that ends only after the window has been destroyed. 4296 For more information on the treatment of events for modal windows, 4297 refer to BWindow>>#modalMap." 4298 4299 <category: 'widget protocol'> 4300 self toplevel container showAll. 4301 self toplevel modalMap 4302 ] 4303] 4304 4305 4306 4307BMenuObject subclass: BMenuBar [ 4308 | actionGroup uiManager | 4309 4310 <comment: 'I am the Menu Bar, the top widget in a full menu structure.'> 4311 <category: 'Graphics-Windows'> 4312 4313 add: aMenu [ 4314 "Add aMenu to the menu bar" 4315 4316 <category: 'accessing'> 4317 aMenu create. 4318 ^aMenu 4319 ] 4320 4321 remove: aMenu [ 4322 "Remove aMenu from the menu bar" 4323 4324 <category: 'accessing'> 4325 self 4326 tclEval: 'catch { %1 delete %2 }' 4327 with: self connected 4328 with: aMenu connected 4329 ] 4330 4331 uiManager [ 4332 <category: 'private'> 4333 uiManager isNil ifTrue: [self create]. 4334 ^uiManager 4335 ] 4336 4337 create [ 4338 <category: 'private'> 4339 uiManager := self parent isNil 4340 ifTrue: [GTK.GtkUIManager new] 4341 ifFalse: [self toplevel uiManager]. 4342 self uiManager 4343 addUi: self uiManager newMergeId 4344 path: '/' 4345 name: self name 4346 action: self name 4347 type: GTK.Gtk gtkUiManagerMenubar 4348 top: false. 4349 self parent isNil ifFalse: [self parent menu: self]. 4350 actionGroup := GTK.GtkActionGroup new: 'MenuActions'. 4351 self uiManager insertActionGroup: actionGroup pos: 0 4352 ] 4353 4354 exists [ 4355 <category: 'private'> 4356 ^uiManager notNil 4357 ] 4358 4359 name [ 4360 "answer the name" 4361 4362 <category: 'private'> 4363 ^'MainMenu' 4364 ] 4365 4366 path [ 4367 "answer the menu path" 4368 4369 <category: 'private'> 4370 ^'/MainMenu' 4371 ] 4372 4373 actionGroup [ 4374 "answer an actiongroup that menu entries should go in" 4375 4376 <category: 'private'> 4377 actionGroup isNil ifTrue: [self create]. 4378 ^actionGroup 4379 ] 4380] 4381 4382 4383 4384BMenuObject subclass: BMenu [ 4385 | connected label | 4386 4387 <comment: 'I am a Menu that is part of a menu bar.'> 4388 <category: 'Graphics-Windows'> 4389 4390 BMenu class >> new: parent label: label [ 4391 "Add a new menu to the parent window's menu bar, with `label' as 4392 its caption (for popup menus, parent is the widget over which the 4393 menu pops up as the right button is pressed)." 4394 4395 <category: 'instance creation'> 4396 ^(self basicNew) 4397 initialize: parent; 4398 label: label; 4399 yourself 4400 ] 4401 4402 label [ 4403 "Answer the value of the label option for the widget. 4404 4405 Specifies a string to be displayed inside the widget. The way in which the 4406 string is displayed depends on the particular widget and may be determined 4407 by other options, such as anchor. For windows, this is the title of the window." 4408 4409 <category: 'accessing'> 4410 ^label 4411 ] 4412 4413 label: value [ 4414 "Set the value of the label option for the widget. 4415 4416 Specifies a string to be displayed inside the widget. The way in which the 4417 string is displayed depends on the particular widget and may be determined 4418 by other options, such as anchor. For windows, this is the title of the window." 4419 4420 "TODO: save the merge id we used, remove the ui, and re-add the ui with the new label" 4421 4422 <category: 'accessing'> 4423 label := value 4424 ] 4425 4426 addLine [ 4427 "Add a separator item at the end of the menu" 4428 4429 <category: 'callback registration'> 4430 ^self addMenuItemFor: #() notifying: self "self is dummy" 4431 ] 4432 4433 addMenuItemFor: anArray notifying: receiver [ 4434 "Add a menu item described by anArray at the end of the menu. 4435 If anArray is empty, insert a separator line. If anArray 4436 has a single item, a menu item is created without a callback. 4437 If anArray has two or three items, the second one is used as 4438 the selector sent to receiver, and the third one (if present) 4439 is passed to the selector." 4440 4441 "Receiver will be sent the callback messages. anArray 4442 is something that responds to at: and size. Possible types are: 4443 #() insert a seperator line 4444 #(name) create a menu item with name, but no callback 4445 #(name symbol) create a menu item with the given name and 4446 no parameter callback. 4447 #(name symbol arg) create a menu item with the given name and 4448 one parameter callback." 4449 4450 <category: 'callback registration'> 4451 | item | 4452 item := self newMenuItemFor: anArray notifying: receiver. 4453 self exists ifFalse: [self create]. 4454 item create 4455 ] 4456 4457 callback: receiver using: selectorPairs [ 4458 "Add menu items described by anArray at the end of the menu. 4459 Each element of selectorPairs must be in the format described 4460 in BMenu>>#addMenuItemFor:notifying:. All the callbacks will 4461 be sent to receiver." 4462 4463 <category: 'callback registration'> 4464 selectorPairs do: [:pair | self addMenuItemFor: pair notifying: receiver] 4465 ] 4466 4467 empty [ 4468 "Empty the menu widget; that is, remove all the children" 4469 4470 <category: 'callback registration'> 4471 self tclEval: self connected , ' delete 0 end'. 4472 children := OrderedCollection new. 4473 childrensUnderline := nil 4474 ] 4475 4476 destroy [ 4477 "Destroy the menu widget; that is, simply remove ourselves from 4478 the parent menu bar." 4479 4480 <category: 'callback registration'> 4481 self parent remove: self 4482 ] 4483 4484 addChild: menuItem [ 4485 <category: 'private'> 4486 self exists ifFalse: [self create]. 4487 menuItem create. 4488 ^menuItem 4489 ] 4490 4491 actionGroup [ 4492 "answer the menu action group" 4493 4494 <category: 'private'> 4495 ^self parent actionGroup 4496 ] 4497 4498 name [ 4499 "answer the name the menu should get" 4500 4501 <category: 'private'> 4502 ^self label , 'Menu' 4503 ] 4504 4505 menuLabel [ 4506 "answer the label the menu should get" 4507 4508 <category: 'private'> 4509 ^'_' , self label 4510 ] 4511 4512 path [ 4513 "answer the path for the menu" 4514 4515 <category: 'private'> 4516 ^self parent path , '/' , self name 4517 ] 4518 4519 uiManager [ 4520 "answer the ui manager" 4521 4522 <category: 'private'> 4523 ^self parent uiManager 4524 ] 4525 4526 connected [ 4527 <category: 'private'> 4528 connected isNil ifTrue: [connected := self uiManager getWidget: self path]. 4529 ^connected 4530 ] 4531 4532 create [ 4533 <category: 'private'> 4534 | s menu u | 4535 self actionGroup addAction: (GTK.GtkAction 4536 new: self name 4537 label: self menuLabel 4538 tooltip: nil 4539 stockId: nil). 4540 self uiManager 4541 addUi: self uiManager newMergeId 4542 path: self parent path 4543 name: self name 4544 action: self name 4545 type: GTK.Gtk gtkUiManagerMenu 4546 top: false. 4547 self childrenDo: [:each | each create] 4548 ] 4549 4550 onDestroy: object data: data [ 4551 <category: 'private'> 4552 self destroyed 4553 ] 4554 4555 exists [ 4556 <category: 'private'> 4557 ^self connected notNil 4558 ] 4559 4560 initialize: parentWidget [ 4561 <category: 'private'> 4562 super initialize: parentWidget. 4563 label := '' 4564 ] 4565 4566 newMenuItemFor: pair notifying: receiver [ 4567 <category: 'private'> 4568 | item size | 4569 size := pair size. 4570 pair size = 0 ifTrue: [^BMenuItem new: self]. 4571 (size >= 2 and: [pair last isArray]) 4572 ifTrue: 4573 [size := size - 1. 4574 item := BMenu new: self label: (pair at: 1). 4575 pair last 4576 do: [:each | item add: (item newMenuItemFor: each notifying: receiver)]] 4577 ifFalse: [item := BMenuItem new: self label: (pair at: 1)]. 4578 size = 1 ifTrue: [^item]. 4579 size = 2 ifTrue: [^item callback: receiver message: (pair at: 2)]. 4580 ^item 4581 callback: receiver 4582 message: (pair at: 2) 4583 argument: (pair at: 3) 4584 ] 4585] 4586 4587 4588 4589BMenu subclass: BPopupMenu [ 4590 | attachedWidget | 4591 4592 <comment: 'I am a class that provides the ability to show popup menus when the 4593right button (Button 3) is clicked on another window.'> 4594 <category: 'Graphics-Windows'> 4595 4596 PopupMenuBar := nil. 4597 PopupMenus := nil. 4598 4599 BPopupMenu class >> initializeOnStartup [ 4600 <category: 'private - accessing'> 4601 PopupMenuBar := nil. 4602 PopupMenus := WeakKeyIdentityDictionary new 4603 ] 4604 4605 BPopupMenu class >> popupMenuBar [ 4606 "answer the menubar this menu conceptually exists in" 4607 4608 <category: 'private - accessing'> 4609 PopupMenuBar isNil ifTrue: [PopupMenuBar := BMenuBar new: nil]. 4610 ^PopupMenuBar 4611 ] 4612 4613 initialize: parentWindow [ 4614 "TODO: refactor so that 'self parent' is parentWindow. Start by 4615 writing (and using!) a menuBar method in BMenu and overriding it here." 4616 4617 <category: 'private'> 4618 self class popupMenuBar exists ifFalse: [self class popupMenuBar create]. 4619 super initialize: self class popupMenuBar. 4620 attachedWidget := parentWindow. 4621 PopupMenus at: parentWindow ifPresent: [:menu | menu destroy]. 4622 PopupMenus at: attachedWidget put: self 4623 ] 4624 4625 create [ 4626 <category: 'private'> 4627 super create. 4628 attachedWidget connected 4629 connectSignal: 'button-press-event' 4630 to: self 4631 selector: #onPopup:event:data: 4632 userData: nil 4633 ] 4634 4635 destroyed [ 4636 <category: 'private'> 4637 super destroyed. 4638 attachedWidget := nil 4639 ] 4640 4641 onPopup: widget event: event data: data [ 4642 <category: 'private'> 4643 | buttonEv | 4644 buttonEv := event castTo: GTK.GdkEventButton type. 4645 buttonEv button value = 3 ifFalse: [^false]. 4646 self connected getSubmenu 4647 popup: nil 4648 parentMenuItem: nil 4649 func: nil 4650 data: nil 4651 button: 3 4652 activateTime: buttonEv time value. 4653 ^true 4654 ] 4655 4656 popup [ 4657 "Generate a synthetic menu popup event" 4658 4659 <category: 'widget protocol'> 4660 self connected getSubmenu 4661 popup: attachedWidget connected 4662 parentMenuItem: nil 4663 func: nil 4664 data: nil 4665 button: 0 4666 activateTime: GTK.Gtk getCurrentEventTime 4667 ] 4668] 4669 4670 4671 4672BMenuObject subclass: BMenuItem [ 4673 | index | 4674 4675 <comment: 'I am the tiny and humble Menu Item, a single command choice in the 4676menu structure. But if it wasn''t for me, nothing could be done... 4677eh eh eh!!'> 4678 <category: 'Graphics-Windows'> 4679 4680 BMenuItem class >> new: parent [ 4681 "Add a new separator item to the specified menu." 4682 4683 <category: 'instance creation'> 4684 ^self basicNew initialize: parent 4685 ] 4686 4687 BMenuItem class >> new: parent label: label [ 4688 "Add a new menu item to the specified menu (parent) , with `label' 4689 as its caption." 4690 4691 <category: 'instance creation'> 4692 ^self basicNew initialize: parent label: label 4693 ] 4694 4695 label [ 4696 "Answer the value of the label option for the widget. 4697 4698 Specifies a string to be displayed inside the widget. The way in which the 4699 string is displayed depends on the particular widget and may be determined 4700 by other options, such as anchor. For windows, this is the title of the window." 4701 4702 <category: 'accessing'> 4703 ^self properties at: #label 4704 ] 4705 4706 label: value [ 4707 "Set the value of the label option for the widget. 4708 4709 Specifies a string to be displayed inside the widget. The way in which the 4710 string is displayed depends on the particular widget and may be determined 4711 by other options, such as anchor. For windows, this is the title of the window." 4712 4713 <category: 'accessing'> 4714 (self properties at: #label) isNil 4715 ifTrue: [^self error: 'no label for separator lines']. 4716 self parent exists 4717 ifTrue: 4718 [self 4719 tclEval: self container , ' entryconfigure ' , self connected , ' -label ' 4720 , value asTkString]. 4721 self properties at: #label put: value 4722 ] 4723 4724 actionGroup [ 4725 "answer the menu action group" 4726 4727 <category: 'private'> 4728 ^self parent actionGroup 4729 ] 4730 4731 uiManager [ 4732 <category: 'private'> 4733 ^self parent uiManager 4734 ] 4735 4736 name [ 4737 "answer the name of the item" 4738 4739 <category: 'private'> 4740 ^self label 4741 ] 4742 4743 menuLabel [ 4744 "answer the gtk label" 4745 4746 <category: 'private'> 4747 ^'_' , self name 4748 ] 4749 4750 path [ 4751 "answer the gtk uiManager path" 4752 4753 <category: 'private'> 4754 ^self parent path , '/' , self name 4755 ] 4756 4757 create [ 4758 <category: 'private'> 4759 | s u mergeid action | 4760 self name isNil 4761 ifTrue: 4762 [mergeid := self uiManager newMergeId. 4763 self properties at: #label put: 'separator' , (mergeid printString: 10). 4764 self uiManager 4765 addUi: mergeid 4766 path: self parent path 4767 name: self name 4768 action: nil 4769 type: GTK.Gtk gtkUiManagerSeparator 4770 top: false] 4771 ifFalse: 4772 [action := GTK.GtkAction 4773 new: self name 4774 label: self menuLabel 4775 tooltip: 'FIXME' 4776 stockId: nil. 4777 4778 "FIXME, when to use stock options? GTK.Gtk gtkStockOpen." 4779 action 4780 connectSignal: 'activate' 4781 to: self 4782 selector: #activated:data: 4783 userData: nil. 4784 4785 "FIXME when to trigger accelerators" 4786 "self actionGroup addActionWithAccel: foo accelerator: '<control>O'." 4787 self actionGroup addAction: action. 4788 self uiManager 4789 addUi: self uiManager newMergeId 4790 path: self parent path 4791 name: self name 4792 action: self name 4793 type: GTK.Gtk gtkUiManagerMenuitem 4794 top: false] 4795 ] 4796 4797 activated: action data: userData [ 4798 <category: 'private'> 4799 self invokeCallback 4800 ] 4801 4802 initialize: parentWidget [ 4803 "initialize a separator item" 4804 4805 <category: 'private'> 4806 super initialize: parentWidget. 4807 self properties at: #label put: nil 4808 ] 4809 4810 initialize: parentWidget label: label [ 4811 <category: 'private'> 4812 | s | 4813 super initialize: parentWidget. 4814 self properties at: #label put: label. 4815 parent exists ifTrue: [self create] 4816 ] 4817] 4818 4819 4820 4821BMenuItem subclass: BCheckMenuItem [ 4822 | status | 4823 4824 <comment: 'I am a menu item which can be toggled between two states, marked 4825and unmarked.'> 4826 <category: 'Graphics-Windows'> 4827 4828 BCheckMenuItem class >> new: parent [ 4829 <category: 'instance creation'> 4830 self shouldNotImplement 4831 ] 4832 4833 invokeCallback [ 4834 "Generate a synthetic callback" 4835 4836 <category: 'accessing'> 4837 self properties removeKey: #value ifAbsent: []. 4838 self callback isNil ifFalse: [self callback send] 4839 ] 4840 4841 value [ 4842 "Answer whether the menu item is in a selected (checked) state." 4843 4844 <category: 'accessing'> 4845 ^self properties at: #value ifAbsentPut: [false] 4846 ] 4847 4848 value: aBoolean [ 4849 "Set whether the button is in a selected (checked) state and 4850 generates a callback accordingly." 4851 4852 <category: 'accessing'> 4853 self properties at: #value put: aBoolean. 4854 self tclEval: 'set ' , self variable , self valueString. 4855 self callback isNil ifFalse: [self callback send] 4856 ] 4857 4858 create [ 4859 <category: 'private'> 4860 super create. 4861 self 4862 tclEval: '%1 entryconfigure %2 -onvalue 1 -offvalue 0 -variable %3' 4863 with: self container 4864 with: self connected 4865 with: self variable 4866 ] 4867 4868 destroyed [ 4869 "Private - The receiver has been destroyed, clear the corresponding 4870 Tcl variable to avoid memory leaks." 4871 4872 <category: 'private'> 4873 self tclEval: 'unset ' , self variable. 4874 super destroyed 4875 ] 4876 4877 valueString [ 4878 <category: 'private'> 4879 ^self value ifTrue: [' 1'] ifFalse: [' 0'] 4880 ] 4881 4882 variable [ 4883 <category: 'private'> 4884 ^'var' , self connected , self container copyWithout: $. 4885 ] 4886 4887 widgetType [ 4888 <category: 'private'> 4889 ^'checkbutton' 4890 ] 4891] 4892 4893 4894 4895"-------------------------- BEdit class -----------------------------" 4896 4897 4898 4899"-------------------------- BLabel class -----------------------------" 4900 4901 4902 4903Eval [ 4904 BLabel initialize 4905] 4906 4907 4908 4909"-------------------------- BButton class -----------------------------" 4910 4911 4912 4913"-------------------------- BForm class -----------------------------" 4914 4915 4916 4917"-------------------------- BContainer class -----------------------------" 4918 4919 4920 4921"-------------------------- BRadioGroup class -----------------------------" 4922 4923 4924 4925"-------------------------- BRadioButton class -----------------------------" 4926 4927 4928 4929"-------------------------- BToggle class -----------------------------" 4930 4931 4932 4933"-------------------------- BImage class -----------------------------" 4934 4935 4936 4937"-------------------------- BList class -----------------------------" 4938 4939 4940 4941"-------------------------- BWindow class -----------------------------" 4942 4943 4944 4945"-------------------------- BTransientWindow class -----------------------------" 4946 4947 4948 4949"-------------------------- BPopupWindow class -----------------------------" 4950 4951 4952 4953"-------------------------- BDialog class -----------------------------" 4954 4955 4956 4957"-------------------------- BMenuBar class -----------------------------" 4958 4959 4960 4961"-------------------------- BMenu class -----------------------------" 4962 4963 4964 4965"-------------------------- BPopupMenu class -----------------------------" 4966 4967 4968 4969"-------------------------- BMenuItem class -----------------------------" 4970 4971 4972 4973"-------------------------- BCheckMenuItem class -----------------------------" 4974 4975