1"====================================================================== 2| 3| Smalltalk Tk-based GUI building blocks (basic widget classes). 4| 5| 6 ======================================================================" 7 8"====================================================================== 9| 10| Copyright 1999, 2000, 2001, 2002, 2009 Free Software Foundation, Inc. 11| Written by Paolo Bonzini. 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 -font {' , self class defaultFont , '}'. 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 699 create: '-anchor nw -takefocus 0 -font {' , self class defaultFont , '}'. 700 self tclEval: 'bind %1 <Configure> "+%1 configure -wraplength %%w"' 701 with: self connected 702 ] 703 704 initialize: parentWidget [ 705 <category: 'private'> 706 super initialize: parentWidget. 707 parentWidget isNil 708 ifFalse: [self backgroundColor: parentWidget backgroundColor] 709 ] 710 711 setInitialSize [ 712 "Make the Tk placer's status, the receiver's properties and the 713 window status (as returned by winfo) consistent. Occupy the 714 area indicated by the widget itself, at the top left corner" 715 716 <category: 'private'> 717 self x: 0 y: 0 718 ] 719 720 widgetType [ 721 <category: 'private'> 722 ^'label' 723 ] 724] 725 726 727 728BPrimitive subclass: BButton [ 729 | callback | 730 731 <comment: 'I am a button that a user can click. In fact I am at the head 732of a small hierarchy of objects which exhibit button-like look 733and behavior'> 734 <category: 'Graphics-Windows'> 735 736 BButton class >> new: parent label: label [ 737 "Answer a new BButton widget laid inside the given parent widget, 738 showing by default the `label' String." 739 740 <category: 'instance creation'> 741 ^(self new: parent) 742 label: label; 743 yourself 744 ] 745 746 backgroundColor [ 747 "Answer the value of the backgroundColor option for the widget. 748 749 Specifies the normal background color to use when displaying the widget." 750 751 <category: 'accessing'> 752 self properties at: #background ifPresent: [:value | ^value]. 753 self 754 tclEval: '%1 cget -background' 755 with: self connected 756 with: self container. 757 ^self properties at: #background put: self tclResult 758 ] 759 760 backgroundColor: value [ 761 "Set the value of the backgroundColor option for the widget. 762 763 Specifies the normal background color to use when displaying the widget." 764 765 <category: 'accessing'> 766 self 767 tclEval: '%1 configure -background %3' 768 with: self connected 769 with: self container 770 with: value asTkString. 771 self properties at: #background put: value 772 ] 773 774 callback [ 775 "Answer a DirectedMessage that is sent when the receiver is clicked, 776 or nil if none has been set up." 777 778 <category: 'accessing'> 779 ^callback 780 ] 781 782 callback: aReceiver message: aSymbol [ 783 "Set up so that aReceiver is sent the aSymbol message (the name of 784 a zero- or one-argument selector) when the receiver is clicked. 785 If the method accepts an argument, the receiver is passed." 786 787 <category: 'accessing'> 788 | arguments selector numArgs | 789 selector := aSymbol asSymbol. 790 numArgs := selector numArgs. 791 arguments := #(). 792 numArgs = 1 ifTrue: [arguments := Array with: self]. 793 callback := DirectedMessage 794 selector: selector 795 arguments: arguments 796 receiver: aReceiver 797 ] 798 799 font [ 800 "Answer the value of the font option for the widget. 801 802 Specifies the font to use when drawing text inside the widget. The font 803 can be given as either an X font name or a Blox font description string. 804 805 X font names are given as many fields, each led by a minus, and each of 806 which can be replaced by an * to indicate a default value is ok: 807 foundry, family, weight, slant, setwidth, addstyle, pixel size, point size 808 (the same as pixel size for historical reasons), horizontal resolution, 809 vertical resolution, spacing, width, charset and character encoding. 810 811 Blox font description strings have three fields, which must be separated by 812 a space and of which only the first is mandatory: the font family, the font 813 size in points (or in pixels if a negative value is supplied), and a number 814 of styles separated by a space (valid styles are normal, bold, italic, 815 underline and overstrike). Examples of valid fonts are ``Helvetica 10 Bold'', 816 ``Times -14'', ``Futura Bold Underline''. You must enclose the font family 817 in braces if it is made of two or more words." 818 819 <category: 'accessing'> 820 self properties at: #font ifPresent: [:value | ^value]. 821 self 822 tclEval: '%1 cget -font' 823 with: self connected 824 with: self container. 825 ^self properties at: #font put: self tclResult 826 ] 827 828 font: value [ 829 "Set the value of the font option for the widget. 830 831 Specifies the font to use when drawing text inside the widget. The font 832 can be given as either an X font name or a Blox font description string. 833 834 X font names are given as many fields, each led by a minus, and each of 835 which can be replaced by an * to indicate a default value is ok: 836 foundry, family, weight, slant, setwidth, addstyle, pixel size, point size 837 (the same as pixel size for historical reasons), horizontal resolution, 838 vertical resolution, spacing, width, charset and character encoding. 839 840 Blox font description strings have three fields, which must be separated by 841 a space and of which only the first is mandatory: the font family, the font 842 size in points (or in pixels if a negative value is supplied), and a number 843 of styles separated by a space (valid styles are normal, bold, italic, 844 underline and overstrike). Examples of valid fonts are ``Helvetica 10 Bold'', 845 ``Times -14'', ``Futura Bold Underline''. You must enclose the font family 846 in braces if it is made of two or more words." 847 848 <category: 'accessing'> 849 self 850 tclEval: '%1 configure -font %3' 851 with: self connected 852 with: self container 853 with: value asTkString. 854 self properties at: #font put: value 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 properties at: #text ifPresent: [:value | ^value]. 901 self 902 tclEval: '%1 cget -text' 903 with: self connected 904 with: self container. 905 ^self properties at: #text put: self tclResult 906 ] 907 908 label: value [ 909 "Set the value of the label option for the widget. 910 911 Specifies a string to be displayed inside the widget. The way in which the 912 string is displayed depends on the particular widget and may be determined 913 by other options, such as anchor. For windows, this is the title of the window." 914 915 <category: 'accessing'> 916 self 917 tclEval: '%1 configure -text %3' 918 with: self connected 919 with: self container 920 with: value asTkString. 921 self properties at: #text put: value 922 ] 923 924 create [ 925 <category: 'private'> 926 self 927 create: '-highlightthickness 0 -takefocus 1 -command {callback %1 invokeCallback} -font {%2}' 928 % 929 {self asOop. 930 self class defaultFont} 931 ] 932 933 setInitialSize [ 934 "Make the Tk placer's status, the receiver's properties and the 935 window status (as returned by winfo) consistent. Occupy the 936 area indicated by the widget itself, at the top left corner" 937 938 <category: 'private'> 939 self x: 0 y: 0 940 ] 941 942 widgetType [ 943 <category: 'private'> 944 ^'button' 945 ] 946] 947 948 949 950BPrimitive subclass: BForm [ 951 952 <comment: 'I am used to group many widgets together. I leave the heavy 953task of managing their position to the user.'> 954 <category: 'Graphics-Windows'> 955 956 backgroundColor [ 957 "Answer the value of the backgroundColor option for the widget. 958 959 Specifies the normal background color to use when displaying the widget." 960 961 <category: 'accessing'> 962 self properties at: #background ifPresent: [:value | ^value]. 963 self 964 tclEval: '%1 cget -background' 965 with: self connected 966 with: self container. 967 ^self properties at: #background put: self tclResult 968 ] 969 970 backgroundColor: value [ 971 "Set the value of the backgroundColor option for the widget. 972 973 Specifies the normal background color to use when displaying the widget." 974 975 <category: 'accessing'> 976 self 977 tclEval: '%1 configure -background %3' 978 with: self connected 979 with: self container 980 with: value asTkString. 981 self properties at: #background put: value 982 ] 983 984 defaultHeight [ 985 "Answer the value of the defaultHeight option for the widget. 986 987 Specifies the desired height for the form in pixels. If this option 988 is less than or equal to zero then the window will not request any size at all." 989 990 <category: 'accessing'> 991 self properties at: #height ifPresent: [:value | ^value]. 992 self 993 tclEval: '%1 cget -height' 994 with: self connected 995 with: self container. 996 ^self properties at: #height put: self tclResult asNumber 997 ] 998 999 defaultHeight: value [ 1000 "Set the value of the defaultHeight option for the widget. 1001 1002 Specifies the desired height for the form in pixels. If this option 1003 is less than or equal to zero then the window will not request any size at all." 1004 1005 <category: 'accessing'> 1006 self 1007 tclEval: '%1 configure -height %3' 1008 with: self connected 1009 with: self container 1010 with: value printString asTkString. 1011 self properties at: #height put: value 1012 ] 1013 1014 defaultWidth [ 1015 "Answer the value of the defaultWidth option for the widget. 1016 1017 Specifies the desired width for the form in pixels. If this option 1018 is less than or equal to zero then the window will not request any size at all." 1019 1020 <category: 'accessing'> 1021 self properties at: #width ifPresent: [:value | ^value]. 1022 self 1023 tclEval: '%1 cget -width' 1024 with: self connected 1025 with: self container. 1026 ^self properties at: #width put: self tclResult asNumber 1027 ] 1028 1029 defaultWidth: value [ 1030 "Set the value of the defaultWidth option for the widget. 1031 1032 Specifies the desired width for the form in pixels. If this option 1033 is less than or equal to zero then the window will not request any size at all." 1034 1035 <category: 'accessing'> 1036 self 1037 tclEval: '%1 configure -width %3' 1038 with: self connected 1039 with: self container 1040 with: value printString asTkString. 1041 self properties at: #width put: value 1042 ] 1043 1044 create [ 1045 <category: 'private'> 1046 self create: '-highlightthickness 0 -takefocus 0' 1047 ] 1048 1049 initialize: parentWidget [ 1050 <category: 'private'> 1051 super initialize: parentWidget. 1052 parentWidget isNil 1053 ifFalse: [self backgroundColor: parentWidget backgroundColor] 1054 ] 1055 1056 widgetType [ 1057 <category: 'private'> 1058 ^'frame' 1059 ] 1060] 1061 1062 1063 1064BForm subclass: BContainer [ 1065 | side fill | 1066 1067 <comment: 'I am used to group many widgets together. I can perform simple 1068management by putting widgets next to each other, from left to 1069right or from top to bottom.'> 1070 <category: 'Graphics-Windows'> 1071 1072 setVerticalLayout: aBoolean [ 1073 "Answer whether the container will align the widgets vertically or 1074 horizontally. Horizontal alignment means that widgets are 1075 packed from left to right, while vertical alignment means that 1076 widgets are packed from the top to the bottom of the widget. 1077 1078 Widgets that are set to be ``stretched'' will share all the 1079 space that is not allocated to non-stretched widgets. 1080 1081 The layout of the widget can only be set before the first child 1082 is inserted in the widget." 1083 1084 <category: 'accessing'> 1085 children isEmpty 1086 ifFalse: [^self error: 'cannot set layout after the first child is created']. 1087 fill := aBoolean ifTrue: [' -fill x'] ifFalse: [' -fill y']. 1088 side := aBoolean ifTrue: [' -side top'] ifFalse: [' -side left'] 1089 ] 1090 1091 addChild: child [ 1092 "Private - The widget identified by child has been added to the 1093 receiver. This method is public not because you can call it, 1094 but because it can be useful to override it, not forgetting the 1095 call to either the superclass implementation or #basicAddChild:, 1096 to perform some initialization on the children just added. Answer 1097 the new child." 1098 1099 <category: 'private'> 1100 side isNil ifTrue: [self setVerticalLayout: true]. 1101 self tclEval: 'pack ' , child container , ' -anchor nw ' , side , fill. 1102 ^self basicAddChild: child 1103 ] 1104 1105 child: child height: value [ 1106 <category: 'private'> 1107 1108 ] 1109 1110 child: child heightOffset: value [ 1111 <category: 'private'> 1112 1113 ] 1114 1115 child: child stretch: aBoolean [ 1116 <category: 'private'> 1117 | fillMethod | 1118 fillMethod := aBoolean 1119 ifTrue: [' -expand 1 -fill both'] 1120 ifFalse: [' -expand 0 ' , fill]. 1121 self tclEval: 'pack ' , child container , fillMethod 1122 ] 1123 1124 child: child width: value [ 1125 <category: 'private'> 1126 1127 ] 1128 1129 child: child widthOffset: value [ 1130 <category: 'private'> 1131 1132 ] 1133 1134 child: child x: value [ 1135 <category: 'private'> 1136 1137 ] 1138 1139 child: child xOffset: value [ 1140 <category: 'private'> 1141 1142 ] 1143 1144 child: child y: value [ 1145 <category: 'private'> 1146 1147 ] 1148 1149 child: child yOffset: value [ 1150 <category: 'private'> 1151 1152 ] 1153 1154 heightChild: child [ 1155 <category: 'private'> 1156 | w | 1157 w := self toplevel. 1158 Blox idle. 1159 w isMapped 1160 ifTrue: [self tclEval: 'winfo height ' , child container] 1161 ifFalse: [self tclEval: 'winfo reqheight ' , child container]. 1162 ^self tclResult asInteger 1163 ] 1164 1165 setInitialSize [ 1166 "Make the Tk placer's status, the receiver's properties and the 1167 window status (as returned by winfo) consistent. Occupy the 1168 area indicated by the widget itself, at the top left corner" 1169 1170 <category: 'private'> 1171 self x: 0 y: 0. 1172 1173 "A hack..." 1174 self parent isNil ifTrue: [^self]. 1175 (self parent isKindOf: BContainer) 1176 ifFalse: [self tclEval: 'pack propagate ' , self container , ' 0'] 1177 ] 1178 1179 widthChild: child [ 1180 <category: 'private'> 1181 | w | 1182 w := self toplevel. 1183 Blox idle. 1184 w isMapped 1185 ifTrue: [self tclEval: 'winfo width ' , child container] 1186 ifFalse: [self tclEval: 'winfo reqwidth ' , child container]. 1187 ^self tclResult asInteger 1188 ] 1189 1190 xChild: child [ 1191 <category: 'private'> 1192 ^child xAbsolute 1193 ] 1194 1195 yChild: child [ 1196 <category: 'private'> 1197 ^child yAbsolute 1198 ] 1199] 1200 1201 1202 1203BContainer subclass: BRadioGroup [ 1204 | lastValue lastAssignedValue | 1205 1206 <comment: 'I am used to group many mutually-exclusive radio buttons together. 1207In addition, just like every BContainer I can perform simple management 1208by putting widgets next to each other, from left to right or (which is 1209more useful in this particular case...) from top to bottom.'> 1210 <category: 'Graphics-Windows'> 1211 1212 value [ 1213 "Answer the index of the button that is currently selected, 1214 1 being the first button added to the radio button group. 1215 0 means that no button is selected" 1216 1217 <category: 'accessing'> 1218 self tclEval: 'return ${var' , self connected , '}'. 1219 ^self tclResult asInteger 1220 ] 1221 1222 value: value [ 1223 "Force the value-th button added to the radio button group 1224 to be the selected one." 1225 1226 <category: 'accessing'> 1227 self tclEval: 'set var' , self connected , ' ' , value printString 1228 ] 1229 1230 initialize: parentWidget [ 1231 <category: 'private'> 1232 super initialize: parentWidget. 1233 lastAssignedValue := lastValue := 0. 1234 self tclEval: 'set ' , self variable , ' 1' 1235 ] 1236 1237 lastValue [ 1238 <category: 'private'> 1239 ^lastValue 1240 ] 1241 1242 lastValue: value [ 1243 <category: 'private'> 1244 lastValue := value 1245 ] 1246 1247 newButtonValue [ 1248 <category: 'private'> 1249 ^lastAssignedValue := lastAssignedValue + 1 1250 ] 1251 1252 variable [ 1253 <category: 'private'> 1254 ^'var' , self connected 1255 ] 1256 1257 destroyed [ 1258 "Private - The receiver has been destroyed, clear the corresponding 1259 Tcl variable to avoid memory leaks." 1260 1261 <category: 'widget protocol'> 1262 self tclEval: 'unset var' , self connected. 1263 super destroyed 1264 ] 1265] 1266 1267 1268 1269BButton subclass: BRadioButton [ 1270 | variableValue | 1271 1272 <comment: 'I am just one in a group of mutually exclusive buttons.'> 1273 <category: 'Graphics-Windows'> 1274 1275 callback: aReceiver message: aSymbol [ 1276 "Set up so that aReceiver is sent the aSymbol message (the name of 1277 a selector accepting at most two arguments) when the receiver is 1278 clicked. If the method accepts two arguments, the receiver is 1279 passed as the first parameter. If the method accepts one or two 1280 arguments, true is passed as the last parameter for interoperability 1281 with BToggle widgets." 1282 1283 <category: 'accessing'> 1284 | arguments selector numArgs | 1285 selector := aSymbol asSymbol. 1286 numArgs := selector numArgs. 1287 arguments := #(). 1288 numArgs = 1 ifTrue: [arguments := #(true)]. 1289 numArgs = 2 1290 ifTrue: 1291 [arguments := 1292 {self. 1293 true}]. 1294 callback := DirectedMessage 1295 selector: selector 1296 arguments: arguments 1297 receiver: aReceiver 1298 ] 1299 1300 value [ 1301 "Answer whether this widget is the selected one in its radio 1302 button group." 1303 1304 <category: 'accessing'> 1305 ^self parent value = variableValue 1306 ] 1307 1308 value: aBoolean [ 1309 "Answer whether this widget is the selected one in its radio 1310 button group. Setting this property to false for a group's 1311 currently selected button unhighlights all the buttons in that 1312 group." 1313 1314 <category: 'accessing'> 1315 aBoolean 1316 ifTrue: 1317 [self parent value: variableValue. 1318 ^self]. 1319 1320 "aBoolean is false - unhighlight everything if we're active" 1321 self value ifTrue: [self parent value: 0] 1322 ] 1323 1324 initialize: parentWidget [ 1325 <category: 'private'> 1326 super initialize: parentWidget. 1327 variableValue := self parent newButtonValue. 1328 self 1329 tclEval: self connected , ' configure -anchor nw'; 1330 variableValue: variableValue; 1331 variable: self parent variable; 1332 backgroundColor: parentWidget backgroundColor. 1333 variableValue = 1 ifTrue: [self parent value: 1] 1334 ] 1335 1336 variable: value [ 1337 "Set the value of Tk's variable option for the widget." 1338 1339 <category: 'private'> 1340 self 1341 tclEval: '%1 configure -variable %3' 1342 with: self connected 1343 with: self container 1344 with: value asTkString. 1345 self properties at: #variable put: value 1346 ] 1347 1348 variableValue: value [ 1349 "Set the value of Tk's value option for the widget." 1350 1351 <category: 'private'> 1352 self 1353 tclEval: '%1 configure -value %3' 1354 with: self connected 1355 with: self container 1356 with: value printString asTkString. 1357 self properties at: #value put: value 1358 ] 1359 1360 widgetType [ 1361 <category: 'private'> 1362 ^'radiobutton' 1363 ] 1364] 1365 1366 1367 1368BButton subclass: BToggle [ 1369 | value variableReturn | 1370 1371 <comment: 'I represent a button whose choice can be included (by checking 1372me) or excluded (by leaving me unchecked).'> 1373 <category: 'Graphics-Windows'> 1374 1375 callback: aReceiver message: aSymbol [ 1376 "Set up so that aReceiver is sent the aSymbol message (the name of 1377 a selector accepting at most two arguments) when the receiver is 1378 clicked. If the method accepts two arguments, the receiver is 1379 passed as the first parameter. If the method accepts one or two 1380 arguments, the state of the widget (true if it is selected, false 1381 if it is not) is passed as the last parameter." 1382 1383 <category: 'accessing'> 1384 | arguments selector numArgs | 1385 selector := aSymbol asSymbol. 1386 numArgs := selector numArgs. 1387 arguments := #(). 1388 numArgs = 1 ifTrue: [arguments := {nil}]. 1389 numArgs = 2 1390 ifTrue: 1391 [arguments := 1392 {self. 1393 nil}]. 1394 callback := DirectedMessage 1395 selector: selector 1396 arguments: arguments 1397 receiver: aReceiver 1398 ] 1399 1400 invokeCallback [ 1401 "Generate a synthetic callback." 1402 1403 <category: 'accessing'> 1404 self callback isNil ifTrue: [^self]. 1405 self callback arguments size > 0 1406 ifTrue: 1407 [self callback arguments at: self callback arguments size put: self value]. 1408 super invokeCallback 1409 ] 1410 1411 value [ 1412 "Answer whether the button is in a selected (checked) state." 1413 1414 <category: 'accessing'> 1415 self tclEval: 'return ${var' , self connected , '}'. 1416 ^self tclResult = '1' 1417 ] 1418 1419 value: aBoolean [ 1420 "Set whether the button is in a selected (checked) state and 1421 generates a callback accordingly." 1422 1423 <category: 'accessing'> 1424 aBoolean 1425 ifTrue: [self tclEval: 'set var' , self connected , ' 1'] 1426 ifFalse: [self tclEval: 'set var' , self connected , ' 0'] 1427 ] 1428 1429 variable: value [ 1430 "Set the value of Tk's variable option for the widget." 1431 1432 <category: 'accessing'> 1433 self 1434 tclEval: '%1 configure -variable %3' 1435 with: self connected 1436 with: self container 1437 with: value asTkString. 1438 self properties at: #variable put: value 1439 ] 1440 1441 initialize: parentWidget [ 1442 <category: 'private'> 1443 | variable | 1444 super initialize: parentWidget. 1445 self tclEval: self connected , ' configure -anchor nw'. 1446 self tclEval: 'variable var' , self connected. 1447 self variable: 'var' , self connected. 1448 self backgroundColor: parentWidget backgroundColor 1449 ] 1450 1451 widgetType [ 1452 <category: 'private'> 1453 ^'checkbutton' 1454 ] 1455] 1456 1457 1458 1459BPrimitive subclass: BImage [ 1460 1461 <comment: 'I can display colorful images.'> 1462 <category: 'Graphics-Windows'> 1463 1464 BImage class >> downArrow [ 1465 "Answer the XPM representation of a 12x12 arrow pointing downwards." 1466 1467 <category: 'arrows'> 1468 ^'/* XPM */ 1469static char * downarrow_xpm[] = { 1470/* width height ncolors chars_per_pixel */ 1471"12 12 2 1", 1472/* colors */ 1473" c None m None s None", 1474"o c black m black", 1475/* pixels */ 1476" ", 1477" ", 1478" ", 1479" ", 1480" ooooooo ", 1481" ooooo ", 1482" ooo ", 1483" o ", 1484" ", 1485" ", 1486" ", 1487" "}; 1488' 1489 ] 1490 1491 BImage class >> leftArrow [ 1492 "Answer the XPM representation of a 12x12 arrow pointing leftwards." 1493 1494 <category: 'arrows'> 1495 ^'/* XPM */ 1496static char * leftarrow_xpm[] = { 1497/* width height ncolors chars_per_pixel */ 1498"12 12 2 1", 1499/* colors */ 1500" c None m None s None", 1501"o c black m black", 1502/* pixels */ 1503" ", 1504" ", 1505" o ", 1506" oo ", 1507" ooo ", 1508" oooo ", 1509" ooo ", 1510" oo ", 1511" o ", 1512" ", 1513" ", 1514" "}; 1515' 1516 ] 1517 1518 BImage class >> upArrow [ 1519 "Answer the XPM representation of a 12x12 arrow pointing upwards." 1520 1521 <category: 'arrows'> 1522 ^'/* XPM */ 1523static char * uparrow_xpm[] = { 1524/* width height ncolors chars_per_pixel */ 1525"12 12 2 1", 1526/* colors */ 1527" c None m None s None", 1528"o c black m black", 1529/* pixels */ 1530" ", 1531" ", 1532" ", 1533" ", 1534" o ", 1535" ooo ", 1536" ooooo ", 1537" ooooooo ", 1538" ", 1539" ", 1540" ", 1541" "}; 1542' 1543 ] 1544 1545 BImage class >> rightArrow [ 1546 "Answer the XPM representation of a 12x12 arrow pointing rightwards." 1547 1548 <category: 'arrows'> 1549 ^'/* XPM */ 1550static char * rightarrow_xpm[] = { 1551/* width height ncolors chars_per_pixel */ 1552"12 12 2 1", 1553/* colors */ 1554" c None m None s None", 1555"o c black m black", 1556/* pixels */ 1557" ", 1558" ", 1559" o ", 1560" oo ", 1561" ooo ", 1562" oooo ", 1563" ooo ", 1564" oo ", 1565" o ", 1566" ", 1567" ", 1568" "}; 1569' 1570 ] 1571 1572 BImage class >> gnu [ 1573 "Answer the XPM representation of a 48x48 GNU." 1574 1575 <category: 'GNU'> 1576 ^'/* XPM */ 1577/*****************************************************************************/ 1578/* GNU Emacs bitmap conv. to pixmap by Przemek Klosowski (przemek@nist.gov) */ 1579/*****************************************************************************/ 1580static char * image_name [] = { 1581/* width height ncolors chars_per_pixel */ 1582"48 48 7 1", 1583/* colors */ 1584" s mask c none", 1585"B c blue", 1586"x c black", 1587": c SandyBrown", 1588"+ c SaddleBrown", 1589"o c grey", 1590". c white", 1591/* pixels */ 1592" ", 1593" x ", 1594" :x ", 1595" :::x ", 1596" ::x ", 1597" x ::x ", 1598" x: xxx :::x ", 1599" x: xxx xxx:xxx x::x ", 1600" x:: xxxx::xxx:::::xx x::x ", 1601" x:: x:::::::xx::::::xx x::x ", 1602" x:: xx::::::::x:::::::xx xx::x ", 1603" x:: xx::::::::::::::::::x xx::xx ", 1604" x::x xx:::::xxx:::::::xxx:xxx xx:::xx ", 1605" x:::x xx:::::xx...xxxxxxxxxxxxxxx:::xx ", 1606" x:::x xx::::::xx..xxx...xxxx...xxxxxxxx ", 1607" x:::x x::::::xx.xxx.......x.x.......xxxx ", 1608" x:::xx x:::x::xx.xx..........x.xx.........x ", 1609" x::::xx::xx:::x.xx....ooooxoxoxoo.xxx.....x ", 1610" xx::::xxxx::xx.xx.xxxx.ooooooo.xxx xxxx ", 1611" xx::::::::xx..x.xxx..ooooooooo.xx ", 1612" xxx:::::xxx..xx.xx.xx.xxx.ooooo.xx ", 1613" xxx::xx...xx.xx.BBBB..xxooooooxx ", 1614" xxxx.....xx.xxBB:BB.xxoooooooxx ", 1615" xx.....xx...x.BBBx.xxxooooooxx ", 1616" x....xxxx..xx...xxxooooooooooxx ", 1617" x..xxxxxx..x.......x..ooooooooxx ", 1618" x.x xxx.x.x.x...xxxx.oooooooooxx ", 1619" x xxx.x.x.xx...xx..oooooooooxx ", 1620" xx.x..x.x.xx........oooooooox ", 1621" xxo.xx.x.x.x.x.......ooooooooox ", 1622" xxo..xxxx..x...x.......ooooooox ", 1623" xxoo.xx.x..xx...x.......ooo.xxx ", 1624" xxoo..x.x.x.x.x.xx.xxxxx.o.xx+xx ", 1625" xxoo..x.xx..xx.x.x.x+++xxxxx+++x ", 1626" xxooo.x..xxx.x.x.x.x+++++xxx+xxx ", 1627" xxoo.xx..x..xx.xxxx++x+++x++xxx ", 1628" xxoo..xx.xxx.xxx.xxx++xx+x++xx ", 1629" xxooo.xx.xx..xx.xxxx++x+++xxx ", 1630" xxooo.xxx.xx.xxxxxxxxx++++xxx ", 1631" xxoo...xx.xx.xxxxxx++xxxxxxx ", 1632" xxoooo..x..xxx..xxxx+++++xx ", 1633" xxoooo..x..xx..xxxx++++xx ", 1634" xxxooooox.xx.xxxxxxxxxxx ", 1635" xxxooooo..xxx xxxxx ", 1636" xxxxooooxxxx ", 1637" xxxoooxxx ", 1638" xxxxx ", 1639" " 1640};' 1641 ] 1642 1643 BImage class >> exclaim [ 1644 "Answer the XPM representation of a 32x32 exclamation mark icon." 1645 1646 <category: 'icons'> 1647 ^'/* XPM */ 1648static char * exclaim_xpm[] = { 1649/* width height ncolors chars_per_pixel */ 1650"32 32 6 1", 1651/* colors */ 1652" c None m None s None", 1653". c yellow m white", 1654"X c black m black", 1655"x c gray50 m black", 1656"o c gray m white", 1657"b c yellow4 m black", 1658/* pixels */ 1659" bbb ", 1660" b..oX ", 1661" b....oXx ", 1662" b.....Xxx ", 1663" b......oXxx ", 1664" b.......Xxx ", 1665" b........oXxx ", 1666" b.........Xxx ", 1667" b..........oXxx ", 1668" b...oXXXo...Xxx ", 1669" b....XXXXX...oXxx ", 1670" b....XXXXX....Xxx ", 1671" b.....XXXXX....oXxx ", 1672" b.....XXXXX.....Xxx ", 1673" b......XXXXX.....oXxx ", 1674" b......bXXXb......Xxx ", 1675" b.......oXXXo......oXxx ", 1676" b........XXX........Xxx ", 1677" b.........bXb........oXxx ", 1678" b.........oXo.........Xxx ", 1679" b...........X..........oXxx ", 1680" b.......................Xxx ", 1681" b...........oXXo.........oXxx ", 1682" b...........XXXX..........Xxx ", 1683"b............XXXX..........oXxx ", 1684"b............oXXo...........Xxx ", 1685"b...........................Xxxx", 1686"b..........................oXxxx", 1687" b........................oXxxxx", 1688" bXXXXXXXXXXXXXXXXXXXXXXXXxxxxx", 1689" xxxxxxxxxxxxxxxxxxxxxxxxxxx ", 1690" xxxxxxxxxxxxxxxxxxxxxxxxx "}; 1691' 1692 ] 1693 1694 BImage class >> info [ 1695 "Answer the XPM representation of a 32x32 `information' icon." 1696 1697 <category: 'icons'> 1698 ^'/* XPM */ 1699static char * info_xpm[] = { 1700/* width height ncolors chars_per_pixel */ 1701"32 32 6 1", 1702/* colors */ 1703" c None m None s None", 1704". c white m white", 1705"X c black m black", 1706"x c gray50 m black", 1707"o c gray m white", 1708"b c blue m black", 1709/* pixels */ 1710" xxxxxxxx ", 1711" xxxo......oxxx ", 1712" xxo............oxx ", 1713" xo................ox ", 1714" x.......obbbbo.......X ", 1715" x........bbbbbb........X ", 1716" x.........bbbbbb.........X ", 1717" xo.........obbbbo.........oX ", 1718" x..........................Xx ", 1719"xo..........................oXx ", 1720"x..........bbbbbbb...........Xx ", 1721"x............bbbbb...........Xxx", 1722"x............bbbbb...........Xxx", 1723"x............bbbbb...........Xxx", 1724"x............bbbbb...........Xxx", 1725"xo...........bbbbb..........oXxx", 1726" x...........bbbbb..........Xxxx", 1727" xo..........bbbbb.........oXxxx", 1728" x........bbbbbbbbb.......Xxxx ", 1729" X......................Xxxxx ", 1730" X....................Xxxxx ", 1731" Xo................oXxxxx ", 1732" XXo............oXXxxxx ", 1733" xXXXo......oXXXxxxxx ", 1734" xxxXXXo...Xxxxxxxx ", 1735" xxxxX...Xxxxxx ", 1736" xX...Xxx ", 1737" X..Xxx ", 1738" X.Xxx ", 1739" XXxx ", 1740" xxx ", 1741" xx "}; 1742' 1743 ] 1744 1745 BImage class >> question [ 1746 "Answer the XPM representation of a 32x32 question mark icon." 1747 1748 <category: 'icons'> 1749 ^'/* XPM */ 1750static char * question_xpm[] = { 1751/* width height ncolors chars_per_pixel */ 1752"32 32 6 1", 1753/* colors */ 1754" c None m None s None", 1755". c white m white", 1756"X c black m black", 1757"x c gray50 m black", 1758"o c gray m white", 1759"b c blue m black", 1760/* pixels */ 1761" xxxxxxxx ", 1762" xxxo......oxxx ", 1763" xxo............oxx ", 1764" xo................ox ", 1765" x....................X ", 1766" x.......obbbbbbo.......X ", 1767" x.......obo..bbbbo.......X ", 1768" xo.......bb....bbbb.......oX ", 1769" x........bbbb..bbbb........Xx ", 1770"xo........bbbb.obbbb........oXx ", 1771"x.........obbo.bbbb..........Xx ", 1772"x.............obbb...........Xxx", 1773"x.............bbb............Xxx", 1774"x.............bbo............Xxx", 1775"x.............bb.............Xxx", 1776"xo..........................oXxx", 1777" x...........obbo...........Xxxx", 1778" xo..........bbbb..........oXxxx", 1779" x..........bbbb..........Xxxx ", 1780" X.........obbo.........Xxxxx ", 1781" X....................Xxxxx ", 1782" Xo................oXxxxx ", 1783" XXo............oXXxxxx ", 1784" xXXXo......oXXXxxxxx ", 1785" xxxXXXo...Xxxxxxxx ", 1786" xxxxX...Xxxxxx ", 1787" xX...Xxx ", 1788" X..Xxx ", 1789" X.Xxx ", 1790" XXxx ", 1791" xxx ", 1792" xx "}; 1793' 1794 ] 1795 1796 BImage class >> stop [ 1797 "Answer the XPM representation of a 32x32 `critical stop' icon." 1798 1799 <category: 'icons'> 1800 ^'/* XPM */ 1801static char * stop_xpm[] = { 1802/* width height ncolors chars_per_pixel */ 1803"32 32 5 1", 1804/* colors */ 1805" c None m None s None", 1806". c red m white", 1807"o c DarkRed m black", 1808"X c white m black", 1809"x c gray50 m black", 1810/* pixels */ 1811" oooooooo ", 1812" ooo........ooo ", 1813" o..............o ", 1814" oo................oo ", 1815" o....................o ", 1816" o......................o ", 1817" o......................ox ", 1818" o......X..........X......ox ", 1819" o......XXX........XXX......o ", 1820" o.....XXXXX......XXXXX.....ox ", 1821" o......XXXXX....XXXXX......oxx ", 1822"o........XXXXX..XXXXX........ox ", 1823"o.........XXXXXXXXXX.........ox ", 1824"o..........XXXXXXXX..........oxx", 1825"o...........XXXXXX...........oxx", 1826"o...........XXXXXX...........oxx", 1827"o..........XXXXXXXX..........oxx", 1828"o.........XXXXXXXXXX.........oxx", 1829"o........XXXXX..XXXXX........oxx", 1830" o......XXXXX....XXXXX......oxxx", 1831" o.....XXXXX......XXXXX.....oxxx", 1832" o......XXX........XXX......oxx ", 1833" o......X..........X......oxxx ", 1834" o......................oxxxx ", 1835" o......................oxxx ", 1836" o....................oxxx ", 1837" oo................ooxxxx ", 1838" xo..............oxxxxx ", 1839" xooo........oooxxxxx ", 1840" xxooooooooxxxxxx ", 1841" xxxxxxxxxxxxxx ", 1842" xxxxxxxx "}; 1843' 1844 ] 1845 1846 BImage class >> new: parent data: aString [ 1847 "Answer a new BImage widget laid inside the given parent widget, 1848 loading data from the given string (Base-64 encoded GIF, XPM, 1849 PPM are supported)." 1850 1851 <category: 'instance creation'> 1852 ^(self new: parent) 1853 data: aString; 1854 yourself 1855 ] 1856 1857 BImage class >> new: parent image: aFileStream [ 1858 "Answer a new BImage widget laid inside the given parent widget, 1859 loading data from the given file (GIF, XPM, PPM are supported)." 1860 1861 <category: 'instance creation'> 1862 ^(self new: parent) 1863 image: aFileStream; 1864 yourself 1865 ] 1866 1867 BImage class >> new: parent size: aPoint [ 1868 "Answer a new BImage widget laid inside the given parent widget, 1869 showing by default a transparent image of aPoint size." 1870 1871 <category: 'instance creation'> 1872 ^(self new: parent) 1873 displayWidth: aPoint x; 1874 displayHeight: aPoint y; 1875 blank; 1876 yourself 1877 ] 1878 1879 BImage class >> directory [ 1880 "Answer the Base-64 GIF representation of a `directory folder' icon." 1881 1882 <category: 'small icons'> 1883 ^'R0lGODdhEAAQAPIAAAAAAHh4eLi4uPj4+P///wAAAAAAAAAAACwAAAAAEAAQAAADPkixzPOD 1884yADrWE8qC8WN0+BZAmBq1GMOqwigXFXCrGk/cxjjr27fLtout6n9eMIYMTXsFZsogXRKJf6u 1885P0kCADv/' 1886 ] 1887 1888 BImage class >> file [ 1889 "Answer the Base-64 GIF representation of a `file' icon." 1890 1891 <category: 'small icons'> 1892 ^'R0lGODdhEAAQAPIAAAAAAHh4eLi4uPj4APj4+P///wAAAAAAACwAAAAAEAAQAAADPVi63P4w 1893LkKCtTTnUsXwQqBtAfh910UU4ugGAEucpgnLNY3Gop7folwNOBOeiEYQ0acDpp6pGAFArVqt 1894hQQAO///' 1895 ] 1896 1897 backgroundColor [ 1898 "Answer the value of the backgroundColor option for the widget. 1899 1900 Specifies the normal background color to use when displaying the widget." 1901 1902 <category: 'accessing'> 1903 self properties at: #background ifPresent: [:value | ^value]. 1904 self 1905 tclEval: '%1 cget -background' 1906 with: self connected 1907 with: self container. 1908 ^self properties at: #background put: self tclResult 1909 ] 1910 1911 backgroundColor: value [ 1912 "Set the value of the backgroundColor option for the widget. 1913 1914 Specifies the normal background color to use when displaying the widget." 1915 1916 <category: 'accessing'> 1917 self 1918 tclEval: '%1 configure -background %3' 1919 with: self connected 1920 with: self container 1921 with: value asTkString. 1922 self properties at: #background put: value 1923 ] 1924 1925 displayHeight [ 1926 "Answer the value of the displayHeight option for the widget. 1927 1928 Specifies the height of the image in pixels. This is not the height of the 1929 widget, but specifies the area of the widget that will be taken by the image." 1930 1931 <category: 'accessing'> 1932 self properties at: #displayHeight ifPresent: [:value | ^value]. 1933 self 1934 tclEval: 'img%1 cget -width' 1935 with: self connected 1936 with: self container. 1937 ^self properties at: #displayHeight put: self tclResult asNumber 1938 ] 1939 1940 displayHeight: value [ 1941 "Set the value of the displayHeight option for the widget. 1942 1943 Specifies the height of the image in pixels. This is not the height of the 1944 widget, but specifies the area of the widget that will be taken by the image." 1945 1946 <category: 'accessing'> 1947 self 1948 tclEval: 'img%1 configure -width %3' 1949 with: self connected 1950 with: self container 1951 with: value asFloat printString asTkString. 1952 self properties at: #displayHeight put: value 1953 ] 1954 1955 displayWidth [ 1956 "Answer the value of the displayWidth option for the widget. 1957 1958 Specifies the width of the image in pixels. This is not the width of the 1959 widget, but specifies the area of the widget that will be taken by the image." 1960 1961 <category: 'accessing'> 1962 self properties at: #displayWidth ifPresent: [:value | ^value]. 1963 self 1964 tclEval: 'img%1 cget -width' 1965 with: self connected 1966 with: self container. 1967 ^self properties at: #displayWidth put: self tclResult asNumber 1968 ] 1969 1970 displayWidth: value [ 1971 "Set the value of the displayWidth option for the widget. 1972 1973 Specifies the width of the image in pixels. This is not the width of the 1974 widget, but specifies the area of the widget that will be taken by the image." 1975 1976 <category: 'accessing'> 1977 self 1978 tclEval: 'img%1 configure -width %3' 1979 with: self connected 1980 with: self container 1981 with: value asFloat printString asTkString. 1982 self properties at: #displayWidth put: value 1983 ] 1984 1985 foregroundColor [ 1986 "Answer the value of the foregroundColor option for the widget. 1987 1988 Specifies the normal foreground color to use when displaying the widget." 1989 1990 <category: 'accessing'> 1991 self properties at: #foreground ifPresent: [:value | ^value]. 1992 self 1993 tclEval: '%1 cget -foreground' 1994 with: self connected 1995 with: self container. 1996 ^self properties at: #foreground put: self tclResult 1997 ] 1998 1999 foregroundColor: value [ 2000 "Set the value of the foregroundColor option for the widget. 2001 2002 Specifies the normal foreground color to use when displaying the widget." 2003 2004 <category: 'accessing'> 2005 self 2006 tclEval: '%1 configure -foreground %3' 2007 with: self connected 2008 with: self container 2009 with: value asTkString. 2010 self properties at: #foreground put: value 2011 ] 2012 2013 gamma [ 2014 "Answer the value of the gamma option for the widget. 2015 2016 Specifies that the colors allocated for displaying the image widget 2017 should be corrected for a non-linear display with the specified gamma exponent 2018 value. (The intensity produced by most CRT displays is a power function 2019 of the input value, to a good approximation; gamma is the exponent and 2020 is typically around 2). The value specified must be greater than zero. The 2021 default value is one (no correction). In general, values greater than one 2022 will make the image lighter, and values less than one will make it darker." 2023 2024 <category: 'accessing'> 2025 self properties at: #gamma ifPresent: [:value | ^value]. 2026 self 2027 tclEval: 'img%1 cget -gamma' 2028 with: self connected 2029 with: self container. 2030 ^self properties at: #gamma put: self tclResult asNumber 2031 ] 2032 2033 gamma: value [ 2034 "Set the value of the gamma option for the widget. 2035 2036 Specifies that the colors allocated for displaying the image widget 2037 should be corrected for a non-linear display with the specified gamma exponent 2038 value. (The intensity produced by most CRT displays is a power function 2039 of the input value, to a good approximation; gamma is the exponent and 2040 is typically around 2). The value specified must be greater than zero. The 2041 default value is one (no correction). In general, values greater than one 2042 will make the image lighter, and values less than one will make it darker." 2043 2044 <category: 'accessing'> 2045 self 2046 tclEval: 'img%1 configure -gamma %3' 2047 with: self connected 2048 with: self container 2049 with: value asFloat printString asTkString. 2050 self properties at: #gamma put: value 2051 ] 2052 2053 blank [ 2054 "Blank the corresponding image" 2055 2056 <category: 'image management'> 2057 self tclEval: 'img' , self connected , ' blank' 2058 ] 2059 2060 data: aString [ 2061 "Set the image to be drawn to aString, which can be a GIF 2062 in Base-64 representation or an X pixelmap." 2063 2064 <category: 'image management'> 2065 self tclEval: 'img' , self connected , ' configure -data ' 2066 , aString asTkImageString 2067 ] 2068 2069 dither [ 2070 "Recalculate the dithered image in the window where the 2071 image is displayed. The dithering algorithm used in 2072 displaying images propagates quantization errors from 2073 one pixel to its neighbors. If the image data is supplied 2074 in pieces, the dithered image may not be exactly correct. 2075 Normally the difference is not noticeable, but if it is a 2076 problem, this command can be used to fix it." 2077 2078 <category: 'image management'> 2079 self tclEval: 'img' , self connected , ' redither' 2080 ] 2081 2082 fillFrom: origin extent: extent color: color [ 2083 "Fill a rectangle with the given origin and extent, using 2084 the given color." 2085 2086 <category: 'image management'> 2087 self 2088 fillFrom: origin 2089 to: origin + extent 2090 color: color 2091 ] 2092 2093 fillFrom: origin to: corner color: color [ 2094 "Fill a rectangle between the given corners, using 2095 the given color." 2096 2097 <category: 'image management'> 2098 self 2099 tclEval: 'img%1 put { %2 } -to %3 %4' 2100 with: self connected 2101 with: color 2102 with: origin x printString , ' ' , origin y printString 2103 with: corner x printString , ' ' , corner y printString 2104 ] 2105 2106 fillRectangle: rectangle color: color [ 2107 "Fill a rectangle having the given bounding box, using 2108 the given color." 2109 2110 <category: 'image management'> 2111 self 2112 fillFrom: rectangle origin 2113 to: rectangle corner 2114 color: color 2115 ] 2116 2117 image: aFileStream [ 2118 "Read a GIF or XPM image from aFileStream. The whole contents 2119 of the file are read, not only from the file position." 2120 2121 <category: 'image management'> 2122 self 2123 tclEval: 'img' , self connected , ' read ' , aFileStream name asTkString 2124 ] 2125 2126 imageHeight [ 2127 "Specifies the height of the image, in pixels. This option is useful 2128 primarily in situations where you wish to build up the contents of 2129 the image piece by piece. A value of zero (the default) allows the 2130 image to expand or shrink vertically to fit the data stored in it." 2131 2132 <category: 'image management'> 2133 self tclEval: 'image height img' , self connected. 2134 ^self tclResult asInteger 2135 ] 2136 2137 imageWidth [ 2138 "Specifies the width of the image, in pixels. This option is useful 2139 primarily in situations where you wish to build up the contents of 2140 the image piece by piece. A value of zero (the default) allows the 2141 image to expand or shrink horizontally to fit the data stored in it." 2142 2143 <category: 'image management'> 2144 self tclEval: 'image width img' , self connected. 2145 ^self tclResult asInteger 2146 ] 2147 2148 lineFrom: origin extent: extent color: color [ 2149 "Draw a line with the given origin and extent, using 2150 the given color." 2151 2152 <category: 'image management'> 2153 self 2154 lineFrom: origin 2155 to: origin + extent 2156 color: color 2157 ] 2158 2159 lineFrom: origin to: corner color: color [ 2160 <category: 'image management'> 2161 self notYetImplemented 2162 ] 2163 2164 lineFrom: origin toX: endX color: color [ 2165 "Draw an horizontal line between the given corners, using 2166 the given color." 2167 2168 <category: 'image management'> 2169 self 2170 tclEval: 'img%1 put { %2 } -to %3 %4' 2171 with: self connected 2172 with: color 2173 with: origin x printString , ' ' , origin y printString 2174 with: endX printString , ' ' , origin y printString 2175 ] 2176 2177 lineInside: rectangle color: color [ 2178 "Draw a line having the given bounding box, using 2179 the given color." 2180 2181 <category: 'image management'> 2182 self 2183 lineFrom: rectangle origin 2184 to: rectangle corner 2185 color: color 2186 ] 2187 2188 lineFrom: origin toY: endY color: color [ 2189 "Draw a vertical line between the given corners, using 2190 the given color." 2191 2192 <category: 'image management'> 2193 self 2194 tclEval: 'img%1 put { %2 } -to %3 %4' 2195 with: self connected 2196 with: color 2197 with: origin x printString , ' ' , origin y printString 2198 with: origin x printString , ' ' , endY printString 2199 ] 2200 2201 destroyed [ 2202 "Private - The receiver has been destroyed, clear the corresponding 2203 Tcl image to avoid memory leaks." 2204 2205 <category: 'widget protocol'> 2206 primitive isNil 2207 ifFalse: [self tclEval: 'image delete img' , self connected]. 2208 super destroyed 2209 ] 2210 2211 create [ 2212 <category: 'private'> 2213 self tclEval: 'image create photo img' , self connected. 2214 self create: '-anchor nw -image img' , self connected 2215 ] 2216 2217 setInitialSize [ 2218 "Make the Tk placer's status, the receiver's properties and the 2219 window status (as returned by winfo) consistent. Occupy the 2220 area indicated by the widget itself, at the top left corner" 2221 2222 <category: 'private'> 2223 self x: 0 y: 0 2224 ] 2225 2226 widgetType [ 2227 <category: 'private'> 2228 ^'label' 2229 ] 2230] 2231 2232 2233 2234BViewport subclass: BList [ 2235 | labels items callback | 2236 2237 <comment: 'I represent a list box from which you can choose one or more 2238elements.'> 2239 <category: 'Graphics-Windows'> 2240 2241 add: anObject afterIndex: index [ 2242 "Add an element with the given value after another element whose 2243 index is contained in the index parameter. The label displayed 2244 in the widget is anObject's displayString. Answer anObject." 2245 2246 <category: 'accessing'> 2247 ^self 2248 add: nil 2249 element: anObject 2250 afterIndex: index 2251 ] 2252 2253 add: aString element: anObject afterIndex: index [ 2254 "Add an element with the aString label after another element whose 2255 index is contained in the index parameter. This method allows 2256 the client to decide autonomously the label that the widget will 2257 display. 2258 2259 If anObject is nil, then string is used as the element as well. 2260 If aString is nil, then the element's displayString is used as 2261 the label. 2262 2263 Answer anObject or, if it is nil, aString." 2264 2265 <category: 'accessing'> 2266 | elem label | 2267 label := aString isNil ifTrue: [anObject displayString] ifFalse: [aString]. 2268 elem := anObject isNil ifTrue: [aString] ifFalse: [anObject]. 2269 labels isNil 2270 ifTrue: 2271 [index > 0 2272 ifTrue: [^SystemExceptions.IndexOutOfRange signalOn: self withIndex: index]. 2273 labels := OrderedCollection with: label. 2274 items := OrderedCollection with: elem] 2275 ifFalse: 2276 [labels add: label afterIndex: index. 2277 items add: elem afterIndex: index]. 2278 self tclEval: self connected , ' insert ' , index printString , ' ' 2279 , label asTkString. 2280 ^elem 2281 ] 2282 2283 addLast: anObject [ 2284 "Add an element with the given value at the end of the listbox. 2285 The label displayed in the widget is anObject's displayString. 2286 Answer anObject." 2287 2288 <category: 'accessing'> 2289 ^self 2290 add: nil 2291 element: anObject 2292 afterIndex: items size 2293 ] 2294 2295 addLast: aString element: anObject [ 2296 "Add an element with the given value at the end of the listbox. 2297 This method allows the client to decide autonomously the label 2298 that the widget will display. 2299 2300 If anObject is nil, then string is used as the element as well. 2301 If aString is nil, then the element's displayString is used as 2302 the label. 2303 2304 Answer anObject or, if it is nil, aString." 2305 2306 <category: 'accessing'> 2307 ^self 2308 add: aString 2309 element: anObject 2310 afterIndex: items size 2311 ] 2312 2313 associationAt: anIndex [ 2314 "Answer an association whose key is the item at the given position 2315 in the listbox and whose value is the label used to display that 2316 item." 2317 2318 <category: 'accessing'> 2319 ^(items at: anIndex) -> (labels at: anIndex) 2320 ] 2321 2322 at: anIndex [ 2323 "Answer the element displayed at the given position in the list 2324 box." 2325 2326 <category: 'accessing'> 2327 ^items at: anIndex 2328 ] 2329 2330 backgroundColor [ 2331 "Answer the value of the backgroundColor option for the widget. 2332 2333 Specifies the normal background color to use when displaying the widget." 2334 2335 <category: 'accessing'> 2336 self properties at: #background ifPresent: [:value | ^value]. 2337 self 2338 tclEval: '%1 cget -background' 2339 with: self connected 2340 with: self container. 2341 ^self properties at: #background put: self tclResult 2342 ] 2343 2344 backgroundColor: value [ 2345 "Set the value of the backgroundColor option for the widget. 2346 2347 Specifies the normal background color to use when displaying the widget." 2348 2349 <category: 'accessing'> 2350 self 2351 tclEval: '%1 configure -background %3' 2352 with: self connected 2353 with: self container 2354 with: value asTkString. 2355 self properties at: #background put: value 2356 ] 2357 2358 contents: elementList [ 2359 "Set the elements displayed in the listbox, and set the labels 2360 to be their displayStrings." 2361 2362 <category: 'accessing'> 2363 | newLabels | 2364 newLabels := elementList collect: [:each | each displayString]. 2365 ^self contents: newLabels elements: elementList 2366 ] 2367 2368 contents: stringCollection elements: elementList [ 2369 "Set the elements displayed in the listbox to be those in elementList, 2370 and set the labels to be the corresponding elements in stringCollection. 2371 The two collections must have the same size." 2372 2373 <category: 'accessing'> 2374 | stream | 2375 (elementList notNil and: [elementList size ~= stringCollection size]) 2376 ifTrue: 2377 [^self 2378 error: 'label collection must have the same size as element collection']. 2379 labels := stringCollection isNil 2380 ifTrue: 2381 [elementList asOrderedCollection collect: [:each | each displayString]] 2382 ifFalse: [stringCollection asOrderedCollection]. 2383 items := elementList isNil 2384 ifTrue: [labels copy] 2385 ifFalse: [elementList asOrderedCollection]. 2386 self tclEval: self connected , ' delete 0 end'. 2387 stream := WriteStream on: (String new: 1000). 2388 stream 2389 nextPutAll: self connected; 2390 nextPutAll: ' insert 0'. 2391 stringCollection do: 2392 [:each | 2393 stream space. 2394 stream nextPutAll: each asTkString]. 2395 self tclEval: stream contents 2396 ] 2397 2398 do: aBlock [ 2399 "Iterate over each element of the listbox and pass it to aBlock." 2400 2401 <category: 'accessing'> 2402 items do: aBlock 2403 ] 2404 2405 elements [ 2406 "Answer the collection of objects that represent the elements 2407 displayed by the list box." 2408 2409 <category: 'accessing'> 2410 ^items copy 2411 ] 2412 2413 elements: elementList [ 2414 "Set the elements displayed in the listbox, and set the labels 2415 to be their displayStrings." 2416 2417 <category: 'accessing'> 2418 | newLabels | 2419 newLabels := elementList collect: [:each | each displayString]. 2420 ^self contents: newLabels elements: elementList 2421 ] 2422 2423 font [ 2424 "Answer the value of the font option for the widget. 2425 2426 Specifies the font to use when drawing text inside the widget. The font 2427 can be given as either an X font name or a Blox font description string. 2428 2429 X font names are given as many fields, each led by a minus, and each of 2430 which can be replaced by an * to indicate a default value is ok: 2431 foundry, family, weight, slant, setwidth, addstyle, pixel size, point size 2432 (the same as pixel size for historical reasons), horizontal resolution, 2433 vertical resolution, spacing, width, charset and character encoding. 2434 2435 Blox font description strings have three fields, which must be separated by 2436 a space and of which only the first is mandatory: the font family, the font 2437 size in points (or in pixels if a negative value is supplied), and a number 2438 of styles separated by a space (valid styles are normal, bold, italic, 2439 underline and overstrike). Examples of valid fonts are ``Helvetica 10 Bold'', 2440 ``Times -14'', ``Futura Bold Underline''. You must enclose the font family 2441 in braces if it is made of two or more words." 2442 2443 <category: 'accessing'> 2444 self properties at: #font ifPresent: [:value | ^value]. 2445 self 2446 tclEval: '%1 cget -font' 2447 with: self connected 2448 with: self container. 2449 ^self properties at: #font put: self tclResult 2450 ] 2451 2452 font: value [ 2453 "Set the value of the font option for the widget. 2454 2455 Specifies the font to use when drawing text inside the widget. The font 2456 can be given as either an X font name or a Blox font description string. 2457 2458 X font names are given as many fields, each led by a minus, and each of 2459 which can be replaced by an * to indicate a default value is ok: 2460 foundry, family, weight, slant, setwidth, addstyle, pixel size, point size 2461 (the same as pixel size for historical reasons), horizontal resolution, 2462 vertical resolution, spacing, width, charset and character encoding. 2463 2464 Blox font description strings have three fields, which must be separated by 2465 a space and of which only the first is mandatory: the font family, the font 2466 size in points (or in pixels if a negative value is supplied), and a number 2467 of styles separated by a space (valid styles are normal, bold, italic, 2468 underline and overstrike). Examples of valid fonts are ``Helvetica 10 Bold'', 2469 ``Times -14'', ``Futura Bold Underline''. You must enclose the font family 2470 in braces if it is made of two or more words." 2471 2472 <category: 'accessing'> 2473 self 2474 tclEval: '%1 configure -font %3' 2475 with: self connected 2476 with: self container 2477 with: value asTkString. 2478 self properties at: #font put: value 2479 ] 2480 2481 foregroundColor [ 2482 "Answer the value of the foregroundColor option for the widget. 2483 2484 Specifies the normal foreground color to use when displaying the widget." 2485 2486 <category: 'accessing'> 2487 self properties at: #foreground ifPresent: [:value | ^value]. 2488 self 2489 tclEval: '%1 cget -foreground' 2490 with: self connected 2491 with: self container. 2492 ^self properties at: #foreground put: self tclResult 2493 ] 2494 2495 foregroundColor: value [ 2496 "Set the value of the foregroundColor option for the widget. 2497 2498 Specifies the normal foreground color to use when displaying the widget." 2499 2500 <category: 'accessing'> 2501 self 2502 tclEval: '%1 configure -foreground %3' 2503 with: self connected 2504 with: self container 2505 with: value asTkString. 2506 self properties at: #foreground put: value 2507 ] 2508 2509 highlightBackground [ 2510 "Answer the value of the highlightBackground option for the widget. 2511 2512 Specifies the background color to use when displaying selected items 2513 in the widget." 2514 2515 <category: 'accessing'> 2516 self properties at: #selectbackground ifPresent: [:value | ^value]. 2517 self 2518 tclEval: '%1 cget -selectbackground' 2519 with: self connected 2520 with: self container. 2521 ^self properties at: #selectbackground put: self tclResult 2522 ] 2523 2524 highlightBackground: value [ 2525 "Set the value of the highlightBackground option for the widget. 2526 2527 Specifies the background color to use when displaying selected items 2528 in the widget." 2529 2530 <category: 'accessing'> 2531 self 2532 tclEval: '%1 configure -selectbackground %3' 2533 with: self connected 2534 with: self container 2535 with: value asTkString. 2536 self properties at: #selectbackground put: value 2537 ] 2538 2539 highlightForeground [ 2540 "Answer the value of the highlightForeground option for the widget. 2541 2542 Specifies the foreground color to use when displaying selected items 2543 in the widget." 2544 2545 <category: 'accessing'> 2546 self properties at: #selectforeground ifPresent: [:value | ^value]. 2547 self 2548 tclEval: '%1 cget -selectforeground' 2549 with: self connected 2550 with: self container. 2551 ^self properties at: #selectforeground put: self tclResult 2552 ] 2553 2554 highlightForeground: value [ 2555 "Set the value of the highlightForeground option for the widget. 2556 2557 Specifies the foreground color to use when displaying selected items 2558 in the widget." 2559 2560 <category: 'accessing'> 2561 self 2562 tclEval: '%1 configure -selectforeground %3' 2563 with: self connected 2564 with: self container 2565 with: value asTkString. 2566 self properties at: #selectforeground put: value 2567 ] 2568 2569 index [ 2570 "Answer the value of the index option for the widget. 2571 2572 Indicates the element that has the location cursor. This item will be 2573 displayed in the highlightForeground color, and with the corresponding 2574 background color." 2575 2576 <category: 'accessing'> 2577 self properties at: #index ifPresent: [:value | ^value]. 2578 self 2579 tclEval: '%1 index active' 2580 with: self connected 2581 with: self container. 2582 ^self properties at: #index put: self tclResult asInteger 2583 ] 2584 2585 indexAt: point [ 2586 "Answer the index of the element that covers the point in the 2587 listbox window specified by x and y (in pixel coordinates). If no 2588 element covers that point, then the closest element to that point 2589 is used." 2590 2591 <category: 'accessing'> 2592 self 2593 tclEval: self connected , ' index @%1,%2' 2594 with: point x printString 2595 with: point y printString. 2596 ^self tclResult asInteger + 1 2597 ] 2598 2599 isSelected: index [ 2600 "Answer whether the element indicated by index is currently selected." 2601 2602 <category: 'accessing'> 2603 self tclEval: self connected , ' selection includes ' , index printString. 2604 ^self tclResult = '1' 2605 ] 2606 2607 label [ 2608 "Return nil, it is here for Gtk+ support" 2609 2610 <category: 'accessing'> 2611 ^nil 2612 ] 2613 2614 label: aString [ 2615 "Do nothing, it is here for Gtk+ support" 2616 2617 <category: 'accessing'> 2618 2619 ] 2620 2621 labelAt: anIndex [ 2622 "Answer the label displayed at the given position in the list 2623 box." 2624 2625 <category: 'accessing'> 2626 ^labels at: anIndex 2627 ] 2628 2629 labels [ 2630 "Answer the labels displayed by the list box." 2631 2632 <category: 'accessing'> 2633 ^labels copy 2634 ] 2635 2636 labelsDo: aBlock [ 2637 "Iterate over each listbox element's label and pass it to aBlock." 2638 2639 <category: 'accessing'> 2640 labels do: aBlock 2641 ] 2642 2643 mode [ 2644 "Answer the value of the mode option for the widget. 2645 2646 Specifies one of several styles for manipulating the selection. The value 2647 of the option may be either single, browse, multiple, or extended. 2648 2649 If the selection mode is single or browse, at most one element can be selected in 2650 the listbox at once. Clicking button 1 on an unselected element selects it and 2651 deselects any other selected item, while clicking on a selected element 2652 has no effect. In browse mode it is also possible to drag the selection 2653 with button 1. That is, moving the mouse while button 1 is pressed keeps 2654 the item under the cursor selected. 2655 2656 If the selection mode is multiple or extended, any number of elements may be 2657 selected at once, including discontiguous ranges. In multiple mode, clicking button 2658 1 on an element toggles its selection state without affecting any other elements. 2659 In extended mode, pressing button 1 on an element selects it, deselects 2660 everything else, and sets the anchor to the element under the mouse; dragging the 2661 mouse with button 1 down extends the selection to include all the elements between 2662 the anchor and the element under the mouse, inclusive. 2663 2664 In extended mode, the selected range can be adjusted by pressing button 1 2665 with the Shift key down: this modifies the selection to consist of the elements 2666 between the anchor and the element under the mouse, inclusive. The 2667 un-anchored end of this new selection can also be dragged with the button 2668 down. Also in extended mode, pressing button 1 with the Control key down starts a 2669 toggle operation: the anchor is set to the element under the mouse, and its 2670 selection state is reversed. The selection state of other elements is not 2671 changed. If the mouse is dragged with button 1 down, then the selection 2672 state of all elements between the anchor and the element under the mouse is 2673 set to match that of the anchor element; the selection state of all other 2674 elements remains what it was before the toggle operation began. 2675 2676 Most people will probably want to use browse mode for single selections and 2677 extended mode for multiple selections; the other modes appear to be useful only in 2678 special situations." 2679 2680 <category: 'accessing'> 2681 self properties at: #selectmode ifPresent: [:value | ^value]. 2682 self 2683 tclEval: '%1 cget -selectmode' 2684 with: self connected 2685 with: self container. 2686 ^self properties at: #selectmode put: self tclResult asSymbol 2687 ] 2688 2689 mode: value [ 2690 "Set the value of the mode option for the widget. 2691 2692 Specifies one of several styles for manipulating the selection. The value 2693 of the option may be either single, browse, multiple, or extended. 2694 2695 If the selection mode is single or browse, at most one element can be selected in 2696 the listbox at once. Clicking button 1 on an unselected element selects it and 2697 deselects any other selected item, while clicking on a selected element 2698 has no effect. In browse mode it is also possible to drag the selection 2699 with button 1. That is, moving the mouse while button 1 is pressed keeps 2700 the item under the cursor selected. 2701 2702 If the selection mode is multiple or extended, any number of elements may be 2703 selected at once, including discontiguous ranges. In multiple mode, clicking button 2704 1 on an element toggles its selection state without affecting any other elements. 2705 In extended mode, pressing button 1 on an element selects it, deselects 2706 everything else, and sets the anchor to the element under the mouse; dragging the 2707 mouse with button 1 down extends the selection to include all the elements between 2708 the anchor and the element under the mouse, inclusive. 2709 2710 In extended mode, the selected range can be adjusted by pressing button 1 2711 with the Shift key down: this modifies the selection to consist of the elements 2712 between the anchor and the element under the mouse, inclusive. The 2713 un-anchored end of this new selection can also be dragged with the button 2714 down. Also in extended mode, pressing button 1 with the Control key down starts a 2715 toggle operation: the anchor is set to the element under the mouse, and its 2716 selection state is reversed. The selection state of other elements is not 2717 changed. If the mouse is dragged with button 1 down, then the selection 2718 state of all elements between the anchor and the element under the mouse is 2719 set to match that of the anchor element; the selection state of all other 2720 elements remains what it was before the toggle operation began. 2721 2722 Most people will probably want to use browse mode for single selections and 2723 extended mode for multiple selections; the other modes appear to be useful only in 2724 special situations." 2725 2726 <category: 'accessing'> 2727 self 2728 tclEval: '%1 configure -selectmode %3' 2729 with: self connected 2730 with: self container 2731 with: value asTkString. 2732 self properties at: #selectmode put: value 2733 ] 2734 2735 numberOfStrings [ 2736 "Answer the number of items in the list box" 2737 2738 <category: 'accessing'> 2739 ^labels size 2740 ] 2741 2742 removeAtIndex: index [ 2743 "Remove the item at the given index in the list box, answering 2744 the object associated to the element (i.e. the value that #at: 2745 would have returned for the given index)" 2746 2747 <category: 'accessing'> 2748 | result | 2749 labels removeAtIndex: index. 2750 result := items removeAtIndex: index. 2751 self tclEval: self connected , 'delete ' , index printString. 2752 ^result 2753 ] 2754 2755 size [ 2756 "Answer the number of items in the list box" 2757 2758 <category: 'accessing'> 2759 ^labels size 2760 ] 2761 2762 itemSelected: receiver at: index [ 2763 <category: 'private - examples'> 2764 stdout 2765 nextPutAll: 'List item '; 2766 print: index; 2767 nextPutAll: ' selected!'; 2768 nl. 2769 stdout 2770 nextPutAll: 'Contents: '; 2771 nextPutAll: (items at: index); 2772 nl 2773 ] 2774 2775 create [ 2776 <category: 'private'> 2777 self 2778 create: '-highlightthickness 0 -takefocus 1 \ 2779 -exportselection no -font {' 2780 , self class defaultFont , '}'; 2781 horizontal: true; 2782 vertical: true. 2783 2784 "Tcl hack to get the callback upon activate. See analogous 2785 trick for text boxes in BText>>#initialize:." 2786 self 2787 tclEval: ' 2788 rename %1 .%1 2789 bind %1 <<ListboxSelect>> { callback %2 invokeCallback: [%1 index active] } 2790 proc %1 args { 2791 if [regexp {^activate} [lindex $args 0]] { 2792 callback %2 invokeCallback: [%1 index [lindex $args 1]] 2793 } 2794 uplevel .%1 $args 2795 }' 2796 with: self connected 2797 with: self asOop printString 2798 ] 2799 2800 initialize: parentWidget [ 2801 <category: 'private'> 2802 super initialize: parentWidget. 2803 self properties at: #index put: nil. 2804 labels := OrderedCollection new 2805 ] 2806 2807 invokeCallback: indexString [ 2808 <category: 'private'> 2809 | index | 2810 items isNil ifTrue: [^self]. 2811 index := indexString asInteger. 2812 self properties at: #index put: index + 1. 2813 self invokeCallback 2814 ] 2815 2816 widgetType [ 2817 <category: 'private'> 2818 ^'listbox' 2819 ] 2820 2821 callback [ 2822 "Answer a DirectedMessage that is sent when the active item in 2823 the receiver changes, or nil if none has been set up." 2824 2825 <category: 'widget protocol'> 2826 ^callback 2827 ] 2828 2829 callback: aReceiver message: aSymbol [ 2830 "Set up so that aReceiver is sent the aSymbol message (the name of 2831 a selector with at most two arguemtnts) when the active item in 2832 the receiver changegs. If the method accepts two arguments, the 2833 receiver is passed as the first parameter. If the method accepts 2834 one or two arguments, the selected index is passed as the last 2835 parameter." 2836 2837 <category: 'widget protocol'> 2838 | arguments selector numArgs | 2839 selector := aSymbol asSymbol. 2840 numArgs := selector numArgs. 2841 arguments := #(). 2842 numArgs = 1 ifTrue: [arguments := {nil}]. 2843 numArgs = 2 2844 ifTrue: 2845 [arguments := 2846 {self. 2847 nil}]. 2848 callback := DirectedMessage 2849 selector: selector 2850 arguments: arguments 2851 receiver: aReceiver 2852 ] 2853 2854 highlight: index [ 2855 "Highlight the item at the given position in the listbox." 2856 2857 <category: 'widget protocol'> 2858 index = self index ifTrue: [^self]. 2859 (self mode = #single or: [self mode = #browse]) ifTrue: [self unhighlight]. 2860 self select: index 2861 ] 2862 2863 invokeCallback [ 2864 "Generate a synthetic callback." 2865 2866 <category: 'widget protocol'> 2867 self callback notNil 2868 ifTrue: 2869 [self callback arguments isEmpty 2870 ifFalse: 2871 [self callback arguments at: self callback arguments size 2872 put: (self properties at: #index)]. 2873 self callback send] 2874 ] 2875 2876 select: index [ 2877 "Highlight the item at the given position in the listbox, 2878 without unhighlighting other items. This is meant for 2879 multiple- or extended-mode listboxes, but can be used 2880 with other selection mode in particular cases." 2881 2882 <category: 'widget protocol'> 2883 self properties at: #index put: index. 2884 self 2885 tclEval: '%1 selection set %2 2886 %1 activate %2 2887 %1 see %2' 2888 with: self connected 2889 with: (index - 1) printString 2890 ] 2891 2892 show: index [ 2893 "Ensure that the item at the given position in the listbox is 2894 visible." 2895 2896 <category: 'widget protocol'> 2897 self tclEval: self connected , ' see ' , (index - 1) printString 2898 ] 2899 2900 unhighlight [ 2901 "Unhighlight all the items in the listbox." 2902 2903 <category: 'widget protocol'> 2904 self tclEval: self connected , ' selection clear 0 end' 2905 ] 2906 2907 unselect: index [ 2908 "Unhighlight the item at the given position in the listbox, 2909 without affecting the state of the other items." 2910 2911 <category: 'widget protocol'> 2912 self 2913 tclEval: self connected , ' selection clear ' , (index - 1) printString 2914 ] 2915] 2916 2917 2918 2919BForm subclass: BWindow [ 2920 | isMapped callback x y width height | 2921 2922 <comment: 'I am the boss. Nothing else could be viewed or interacted with if 2923it wasn''t for me... )):->'> 2924 <category: 'Graphics-Windows'> 2925 2926 TopLevel := nil. 2927 Grab := nil. 2928 2929 BWindow class >> initializeOnStartup [ 2930 <category: 'private - initialization'> 2931 self tclEval: 'wm withdraw .'. 2932 TopLevel := OrderedCollection new. 2933 Grab := nil 2934 ] 2935 2936 BWindow class >> new [ 2937 "Answer a new top-level window." 2938 2939 <category: 'instance creation'> 2940 ^TopLevel add: (super new: nil) 2941 ] 2942 2943 BWindow class >> new: label [ 2944 "Answer a new top-level window with `label' as its title bar caption." 2945 2946 <category: 'instance creation'> 2947 ^self new label: label 2948 ] 2949 2950 BWindow class >> popup: initializationBlock [ 2951 <category: 'instance creation'> 2952 self shouldNotImplement 2953 ] 2954 2955 callback [ 2956 "Answer a DirectedMessage that is sent to verify whether the 2957 receiver must be destroyed when the user asks to unmap it." 2958 2959 <category: 'accessing'> 2960 ^callback 2961 ] 2962 2963 callback: aReceiver message: aSymbol [ 2964 "Set up so that aReceiver is sent the aSymbol message (the name of 2965 a zero- or one-argument selector) when the user asks to unmap the 2966 receiver. If the method accepts an argument, the receiver is passed. 2967 2968 If the method returns true, the window and its children are 2969 destroyed (which is the default action, taken if no callback is 2970 set up). If the method returns false, the window is left in 2971 place." 2972 2973 <category: 'accessing'> 2974 | arguments selector numArgs | 2975 selector := aSymbol asSymbol. 2976 numArgs := selector numArgs. 2977 arguments := #(). 2978 numArgs = 1 ifTrue: [arguments := Array with: self]. 2979 callback := DirectedMessage 2980 selector: selector 2981 arguments: arguments 2982 receiver: aReceiver 2983 ] 2984 2985 invokeCallback [ 2986 "Generate a synthetic callback, destroying the window if no 2987 callback was set up or if the callback method answers true." 2988 2989 <category: 'accessing'> 2990 | result | 2991 result := self callback isNil or: [self callback send]. 2992 result ifTrue: [self destroy]. 2993 isMapped := result not 2994 ] 2995 2996 label [ 2997 "Answer the value of the label option for the widget. 2998 2999 Specifies a string to be displayed inside the widget. The way in which the 3000 string is displayed depends on the particular widget and may be determined 3001 by other options, such as anchor. For windows, this is the title of the window." 3002 3003 <category: 'accessing'> 3004 self properties at: #label ifPresent: [:value | ^value]. 3005 self 3006 tclEval: 'wm title %1' 3007 with: self connected 3008 with: self container. 3009 ^self properties at: #label put: self tclResult 3010 ] 3011 3012 label: value [ 3013 "Set the value of the label option for the widget. 3014 3015 Specifies a string to be displayed inside the widget. The way in which the 3016 string is displayed depends on the particular widget and may be determined 3017 by other options, such as anchor. For windows, this is the title of the window." 3018 3019 <category: 'accessing'> 3020 self 3021 tclEval: 'wm title %1 %3' 3022 with: self connected 3023 with: self container 3024 with: value asTkString. 3025 self properties at: #label put: value 3026 ] 3027 3028 menu: value [ 3029 "Set the value of the menu option for the widget. 3030 3031 Specifies a menu widget to be used as a menubar. On the Macintosh, the 3032 menubar will be displayed accross the top of the main monitor. On Microsoft 3033 Windows and all UNIX platforms, the menu will appear accross the toplevel 3034 window as part of the window dressing maintained by the window manager." 3035 3036 <category: 'accessing'> 3037 self 3038 tclEval: '%1 configure -menu %3' 3039 with: self connected 3040 with: self container 3041 with: value container asTkString. 3042 self properties at: #menu put: value 3043 ] 3044 3045 resizable [ 3046 "Answer the value of the resizable option for the widget. 3047 3048 Answer whether the user can be resize the window or not. If resizing is 3049 disabled, then the window's size will be the size from the most recent 3050 interactive resize or geometry-setting method. If there has been no such 3051 operation then the window's natural size will be used." 3052 3053 <category: 'accessing'> 3054 self properties at: #resizable ifPresent: [:value | ^value]. 3055 self 3056 tclEval: 'wm resizable %1' 3057 with: self connected 3058 with: self container. 3059 ^self properties at: #resizable put: self tclResult = '{1 1}' 3060 ] 3061 3062 resizable: value [ 3063 "Set the value of the resizable option for the widget. 3064 3065 Answer whether the user can be resize the window or not. If resizing is 3066 disabled, then the window's size will be the size from the most recent 3067 interactive resize or geometry-setting method. If there has been no such 3068 operation then the window's natural size will be used." 3069 3070 <category: 'accessing'> 3071 self 3072 tclEval: 'wm resizable %1 %3 %3' 3073 with: self connected 3074 with: self container 3075 with: value asCBooleanValue printString asTkString. 3076 self properties at: #resizable put: value 3077 ] 3078 3079 cacheWindowSize [ 3080 <category: 'private'> 3081 | stream | 3082 self tclEval: 'update; wm geometry ' , self container. 3083 stream := ReadStream on: self tclResult. 3084 width := (stream upTo: $x) asInteger. 3085 height := (stream upTo: $+) asInteger. 3086 x := (stream upTo: $+) asInteger. 3087 y := stream upToEnd asInteger 3088 ] 3089 3090 create [ 3091 <category: 'private'> 3092 self create: '-takefocus 0' 3093 ] 3094 3095 create: options [ 3096 <category: 'private'> 3097 super create: options. 3098 self isMapped: false. 3099 self 3100 bind: '<Configure>' 3101 to: #resized 3102 of: self 3103 parameters: ''. 3104 self 3105 tclEval: ' 3106 wm withdraw %1 3107 wm protocol %1 WM_DELETE_WINDOW { callback %2 invokeCallback }' 3108 with: self connected 3109 with: self asOop printString 3110 ] 3111 3112 destroyed [ 3113 "Private - The receiver has been destroyed, remove it from the 3114 list of toplevel windows to avoid memory leaks." 3115 3116 <category: 'private'> 3117 super destroyed. 3118 TopLevel remove: self ifAbsent: [] 3119 ] 3120 3121 isMapped: aBoolean [ 3122 <category: 'private'> 3123 isMapped := aBoolean 3124 ] 3125 3126 resetGeometry: pattern x: xPos y: yPos width: xSize height: ySize [ 3127 <category: 'private'> 3128 | s mapped | 3129 (x = xPos and: [y = yPos and: [width = xSize and: [height = ySize]]]) 3130 ifTrue: [^self]. 3131 s := WriteStream on: (String new: 50). 3132 (mapped := self isMapped) 3133 ifTrue: 3134 [s 3135 nextPutAll: 'wm withdraw ' , self connected; 3136 nl. 3137 self isMapped: false]. 3138 s 3139 nextPutAll: 'wm geometry '; 3140 nextPutAll: self connected; 3141 space; 3142 nextPutAll: pattern; 3143 nl; 3144 nextPutAll: 'update'. 3145 self 3146 tclEval: s contents 3147 with: xSize printString 3148 with: ySize printString 3149 with: xPos printString 3150 with: yPos printString. 3151 x := xPos. 3152 y := yPos. 3153 width := xSize. 3154 height := ySize. 3155 mapped ifTrue: [self map] 3156 ] 3157 3158 resized [ 3159 <category: 'private'> 3160 self isMapped ifFalse: [^self]. 3161 x := y := width := height := nil 3162 ] 3163 3164 setInitialSize [ 3165 <category: 'private'> 3166 self 3167 x: 20 3168 y: 20 3169 width: 300 3170 height: 300 3171 ] 3172 3173 widgetType [ 3174 <category: 'private'> 3175 ^'toplevel' 3176 ] 3177 3178 center [ 3179 "Center the window in the screen" 3180 3181 <category: 'widget protocol'> 3182 | screenSize | 3183 screenSize := Blox screenSize. 3184 self x: screenSize x // 2 - (self width // 2) 3185 y: screenSize y // 2 - (self height // 2) 3186 ] 3187 3188 centerIn: view [ 3189 "Center the window in the given widget" 3190 3191 <category: 'widget protocol'> 3192 self x: view x + (view width // 2) - (self parent width // 2) 3193 y: view x + (view height // 2) - (self parent height // 2) 3194 ] 3195 3196 height [ 3197 "Answer the height of the window, as deduced from the geometry 3198 that the window manager imposed on the window." 3199 3200 <category: 'widget protocol'> 3201 height isNil ifTrue: [self cacheWindowSize]. 3202 ^height 3203 ] 3204 3205 height: anInteger [ 3206 "Ask the window manager to give the given height to the window." 3207 3208 <category: 'widget protocol'> 3209 width isNil ifTrue: [self cacheWindowSize]. 3210 self 3211 resetGeometry: '=%1x%2' 3212 x: x 3213 y: y 3214 width: width 3215 height: anInteger 3216 ] 3217 3218 heightAbsolute [ 3219 "Answer the height of the window, as deduced from the geometry 3220 that the window manager imposed on the window." 3221 3222 <category: 'widget protocol'> 3223 height isNil ifTrue: [self cacheWindowSize]. 3224 ^height 3225 ] 3226 3227 heightOffset: value [ 3228 <category: 'widget protocol'> 3229 self shouldNotImplement 3230 ] 3231 3232 iconify [ 3233 "Map a window and in iconified state. If a window has not been 3234 mapped yet, this is achieved by mapping the window in withdrawn 3235 state first, and then iconifying it." 3236 3237 <category: 'widget protocol'> 3238 self isMapped ifFalse: [self tclEval: 'wm withdraw ' , self connected]. 3239 self tclEval: 'wm iconify ' , self connected. 3240 self isMapped: false 3241 ] 3242 3243 isMapped [ 3244 "Answer whether the window is mapped" 3245 3246 <category: 'widget protocol'> 3247 ^isMapped 3248 ] 3249 3250 isWindow [ 3251 <category: 'widget protocol'> 3252 ^true 3253 ] 3254 3255 map [ 3256 "Map the window and bring it to the topmost position in the Z-order." 3257 3258 <category: 'widget protocol'> 3259 self isMapped ifTrue: [^self]. 3260 self tclEval: ' 3261 wm deiconify %1 3262 focus [ tk_focusNext %1 ]' 3263 with: self container. 3264 self isMapped: true 3265 ] 3266 3267 modalMap [ 3268 "Map the window while establishing an application-local grab for it. 3269 An event loop is started that ends only after the window has been 3270 destroyed. 3271 3272 When a grab is set for a particular window, all pointer events are 3273 restructed to the grab window and its descendants in Blox's window 3274 hierarchy. Whenever the pointer is within the grab window's subtree, 3275 the pointer will behave exactly the same as if there had been no grab 3276 grab at all and all events will be reported in the normal fashion. 3277 When the pointer is outside the window's tree, button presses and 3278 releases and mouse motion events are reported to the grabbing window, 3279 and window entry and window exit events are ignored. In other words, 3280 windows outside the grab subtree will be visible on the screen but 3281 they will be insensitive until the grab is released. The 3282 tree of windows underneath the grab window can include top-level windows, 3283 in which case all of those top-level windows and their descendants will 3284 continue to receive mouse events during the grab. Keyboard events (key 3285 presses and key releases) are delivered as usual: the window manager 3286 controls which application receives keyboard events, and 3287 if they are sent to any window in the grabbing application then 3288 they are redirected to the window owning the focus." 3289 3290 <category: 'widget protocol'> 3291 | previousGrab terminate | 3292 previousGrab := Grab. 3293 Grab := self connected. 3294 self 3295 map; 3296 tclEval: 'grab set ' , Grab. 3297 Blox dispatchEvents: self. 3298 previousGrab isNil 3299 ifTrue: [self tclEval: 'grab release ' , Grab] 3300 ifFalse: [self tclEval: 'grab set ' , previousGrab]. 3301 Grab := previousGrab 3302 ] 3303 3304 state [ 3305 "Set the value of the state option for the window. 3306 3307 Specifies one of four states for the window: either normal, iconic, 3308 withdrawn, or (Windows only) zoomed." 3309 3310 <category: 'widget protocol'> 3311 self tclEval: 'wm state ' , self connected. 3312 ^self tclResult asSymbol 3313 ] 3314 3315 state: aSymbol [ 3316 "Raise an error. To set a BWindow's state, use #map and #unmap." 3317 3318 <category: 'widget protocol'> 3319 self error: 'To set a BWindow''s state, use #map and #unmap.' 3320 ] 3321 3322 unmap [ 3323 "Unmap a window, causing it to be forgotten about by the window manager" 3324 3325 <category: 'widget protocol'> 3326 self isMapped ifFalse: [^self]. 3327 self tclEval: 'wm withdraw ' , self connected. 3328 self isMapped: false 3329 ] 3330 3331 width [ 3332 "Answer the width of the window, as deduced from the geometry 3333 that the window manager imposed on the window." 3334 3335 <category: 'widget protocol'> 3336 width isNil ifTrue: [self cacheWindowSize]. 3337 ^width 3338 ] 3339 3340 width: anInteger [ 3341 "Ask the window manager to give the given width to the window." 3342 3343 <category: 'widget protocol'> 3344 height isNil ifTrue: [self cacheWindowSize]. 3345 self 3346 resetGeometry: '=%1x%2' 3347 x: x 3348 y: y 3349 width: anInteger 3350 height: height 3351 ] 3352 3353 width: xSize height: ySize [ 3354 "Ask the window manager to give the given width and height to 3355 the window." 3356 3357 <category: 'widget protocol'> 3358 self 3359 resetGeometry: '=%1x%2' 3360 x: x 3361 y: y 3362 width: xSize 3363 height: ySize 3364 ] 3365 3366 widthAbsolute [ 3367 "Answer the width of the window, as deduced from the geometry 3368 that the window manager imposed on the window." 3369 3370 <category: 'widget protocol'> 3371 width isNil ifTrue: [self cacheWindowSize]. 3372 ^width 3373 ] 3374 3375 widthOffset: value [ 3376 <category: 'widget protocol'> 3377 self shouldNotImplement 3378 ] 3379 3380 window [ 3381 <category: 'widget protocol'> 3382 ^self 3383 ] 3384 3385 x [ 3386 "Answer the x coordinate of the window's top-left corner, as 3387 deduced from the geometry that the window manager imposed on 3388 the window." 3389 3390 <category: 'widget protocol'> 3391 x isNil ifTrue: [self cacheWindowSize]. 3392 ^x 3393 ] 3394 3395 x: anInteger [ 3396 "Ask the window manager to move the window's left border 3397 to the given x coordinate, keeping the size unchanged" 3398 3399 <category: 'widget protocol'> 3400 y isNil ifTrue: [self cacheWindowSize]. 3401 self 3402 resetGeometry: '+%3+%4' 3403 x: anInteger 3404 y: y 3405 width: width 3406 height: height 3407 ] 3408 3409 x: xPos y: yPos [ 3410 "Ask the window manager to move the window's top-left corner 3411 to the given coordinates, keeping the size unchanged" 3412 3413 <category: 'widget protocol'> 3414 self 3415 resetGeometry: '+%3+%4' 3416 x: xPos 3417 y: yPos 3418 width: width 3419 height: height 3420 ] 3421 3422 x: xPos y: yPos width: xSize height: ySize [ 3423 "Ask the window manager to give the requested geometry 3424 to the window." 3425 3426 <category: 'widget protocol'> 3427 self 3428 resetGeometry: '=%1x%2+%3+%4' 3429 x: xPos 3430 y: yPos 3431 width: xSize 3432 height: ySize 3433 ] 3434 3435 xAbsolute [ 3436 "Answer the x coordinate of the window's top-left corner, as 3437 deduced from the geometry that the window manager imposed on 3438 the window." 3439 3440 <category: 'widget protocol'> 3441 x isNil ifTrue: [self cacheWindowSize]. 3442 ^x 3443 ] 3444 3445 xOffset: value [ 3446 <category: 'widget protocol'> 3447 self shouldNotImplement 3448 ] 3449 3450 y [ 3451 "Answer the y coordinate of the window's top-left corner, as 3452 deduced from the geometry that the window manager imposed on 3453 the window." 3454 3455 <category: 'widget protocol'> 3456 y isNil ifTrue: [self cacheWindowSize]. 3457 ^y 3458 ] 3459 3460 y: anInteger [ 3461 "Ask the window manager to move the window's left border 3462 to the given y coordinate, keeping the size unchanged" 3463 3464 <category: 'widget protocol'> 3465 x isNil ifTrue: [self cacheWindowSize]. 3466 self 3467 resetGeometry: '+%3+%4' 3468 x: x 3469 y: anInteger 3470 width: width 3471 height: height 3472 ] 3473 3474 yAbsolute [ 3475 "Answer the y coordinate of the window's top-left corner, as 3476 deduced from the geometry that the window manager imposed on 3477 the window." 3478 3479 <category: 'widget protocol'> 3480 y isNil ifTrue: [self cacheWindowSize]. 3481 ^y 3482 ] 3483 3484 yOffset: value [ 3485 <category: 'widget protocol'> 3486 self shouldNotImplement 3487 ] 3488] 3489 3490 3491 3492BWindow subclass: BTransientWindow [ 3493 3494 <comment: 'I am almost a boss. I represent a window which is logically linked 3495to another which sits higher in the widget hierarchy, e.g. a dialog 3496box'> 3497 <category: 'Graphics-Windows'> 3498 3499 BTransientWindow class >> new [ 3500 <category: 'instance creation'> 3501 self shouldNotImplement 3502 ] 3503 3504 BTransientWindow class >> new: parentWindow [ 3505 "Answer a new transient window attached to the given 3506 parent window and with nothing in its title bar caption." 3507 3508 <category: 'instance creation'> 3509 ^(self basicNew) 3510 initialize: parentWindow; 3511 yourself 3512 ] 3513 3514 BTransientWindow class >> new: label in: parentWindow [ 3515 "Answer a new transient window attached to the given 3516 parent window and with `label' as its title bar caption." 3517 3518 <category: 'instance creation'> 3519 ^(self basicNew) 3520 initialize: parentWindow; 3521 label: label; 3522 yourself 3523 ] 3524 3525 setWidgetName: parentWidget [ 3526 <category: 'private'> 3527 | unique | 3528 unique := '.w' , (self asOop printString: 36). 3529 parentWidget isNil ifTrue: [^unique]. 3530 ^parentWidget parent isNil 3531 ifTrue: [unique] 3532 ifFalse: [parentWidget parent container , unique] 3533 ] 3534 3535 map [ 3536 "Map the window and inform the windows manager that the 3537 receiver is a transient window working on behalf of its 3538 parent. The window is also put in its parent window's 3539 window group: the window manager might use this information, 3540 for example, to unmap all of the windows in a group when the 3541 group's leader is iconified." 3542 3543 <category: 'widget protocol'> 3544 super map. 3545 self parent isNil ifTrue: [^self]. 3546 self 3547 tclEval: 'wm transient ' , self connected , ' ' , self parent connected. 3548 self 3549 tclEval: 'wm group ' , self connected , ' ' , self parent connected 3550 ] 3551] 3552 3553 3554 3555BWindow subclass: BPopupWindow [ 3556 3557 <comment: 'I am a pseudo-window that has no decorations and no ability to interact 3558with the user. My main usage, as my name says, is to provide pop-up 3559functionality for other widgets. Actually there should be no need to 3560directly use me - always rely on the #new and #popup: class methods.'> 3561 <category: 'Graphics-Windows'> 3562 3563 addChild: w [ 3564 "Private - The widget identified by child has been added to the 3565 receiver. This method is public not because you can call it, 3566 but because it can be useful to override it, not forgetting the 3567 call to either the superclass implementation or #basicAddChild:, 3568 to perform some initialization on the children just added. Answer 3569 the new child." 3570 3571 <category: 'geometry management'> 3572 self tclEval: 'place forget ' , w container. 3573 self 3574 tclEval: 'pack ' , w container , ' -fill both -side left -padx 1 -pady 1'. 3575 w onDestroySend: #destroy to: self. 3576 ^self basicAddChild: w 3577 ] 3578 3579 child: child height: value [ 3580 "Set the given child's height. This is done by setting 3581 its parent window's (that is, our) height." 3582 3583 "Only act after #addChild:" 3584 3585 <category: 'geometry management'> 3586 self childrenCount = 0 ifTrue: [^self]. 3587 self tclEval: 'pack ' , child container , ' -expand 1'. 3588 self height: value 3589 ] 3590 3591 child: child heightOffset: value [ 3592 <category: 'geometry management'> 3593 self shouldNotImplement 3594 ] 3595 3596 child: child width: value [ 3597 "Set the given child's width. This is done by setting 3598 its parent window's (that is, our) width." 3599 3600 "Only act after #addChild:" 3601 3602 <category: 'geometry management'> 3603 self childrenCount = 0 ifTrue: [^self]. 3604 self tclEval: 'pack ' , child container , ' -expand 1'. 3605 self width: value 3606 ] 3607 3608 child: child widthOffset: value [ 3609 <category: 'geometry management'> 3610 self shouldNotImplement 3611 ] 3612 3613 child: child x: value [ 3614 "Set the x coordinate of the given child's top-left corner. 3615 This is done by setting its parent window's (that is, our) x." 3616 3617 <category: 'geometry management'> 3618 self x: value 3619 ] 3620 3621 child: child xOffset: value [ 3622 <category: 'geometry management'> 3623 self shouldNotImplement 3624 ] 3625 3626 child: child y: value [ 3627 "Set the y coordinate of the given child's top-left corner. 3628 This is done by setting its parent window's (that is, our) y." 3629 3630 <category: 'geometry management'> 3631 self y: value 3632 ] 3633 3634 child: child yOffset: value [ 3635 <category: 'geometry management'> 3636 self shouldNotImplement 3637 ] 3638 3639 heightChild: child [ 3640 "Answer the given child's height, which is the height that 3641 was imposed on the popup window." 3642 3643 <category: 'geometry management'> 3644 ^self height 3645 ] 3646 3647 widthChild: child [ 3648 "Answer the given child's width in pixels, which is the width that 3649 was imposed on the popup window." 3650 3651 <category: 'geometry management'> 3652 ^self width 3653 ] 3654 3655 xChild: child [ 3656 "Answer the x coordinate of the given child's top-left corner, 3657 which is desumed by the position of the popup window." 3658 3659 <category: 'geometry management'> 3660 ^self x 3661 ] 3662 3663 yChild: child [ 3664 "Answer the y coordinate of the given child's top-left corner, 3665 which is desumed by the position of the popup window." 3666 3667 <category: 'geometry management'> 3668 ^self y 3669 ] 3670 3671 create [ 3672 <category: 'private'> 3673 self 3674 create: '-takefocus 0 -background black'; 3675 tclEval: 'wm overrideredirect ' , self connected , ' 1'; 3676 resizable: false 3677 ] 3678 3679 setInitialSize [ 3680 <category: 'private'> 3681 self cacheWindowSize 3682 ] 3683] 3684 3685 3686 3687BForm subclass: BDialog [ 3688 | callbacks initInfo | 3689 3690 <comment: 'I am a facility for implementing dialogs with many possible choices 3691and requests. In addition I provide support for a few platform native 3692common dialog boxes, such as choose-a-file and choose-a-color.'> 3693 <category: 'Graphics-Windows'> 3694 3695 BDialog class >> new: parent [ 3696 "Answer a new dialog handler (containing a label widget and 3697 some button widgets) laid out within the given parent window. 3698 The label widget, when it is created, is empty." 3699 3700 <category: 'instance creation'> 3701 ^(self basicNew) 3702 initInfo: '' -> nil; 3703 initialize: parent 3704 ] 3705 3706 BDialog class >> new: parent label: aLabel [ 3707 "Answer a new dialog handler (containing a label widget and 3708 some button widgets) laid out within the given parent window. 3709 The label widget, when it is created, contains aLabel." 3710 3711 <category: 'instance creation'> 3712 ^(self basicNew) 3713 initInfo: aLabel -> nil; 3714 initialize: parent 3715 ] 3716 3717 BDialog class >> new: parent label: aLabel prompt: aString [ 3718 "Answer a new dialog handler (containing a label widget, some 3719 button widgets, and an edit window showing aString by default) 3720 laid out within the given parent window. 3721 The label widget, when it is created, contains aLabel." 3722 3723 <category: 'instance creation'> 3724 ^(self basicNew) 3725 initInfo: aLabel -> aString; 3726 initialize: parent 3727 ] 3728 3729 BDialog class >> chooseFile: operation parent: parent label: aLabel default: name defaultExtension: ext types: typeList [ 3730 <category: 'private'> 3731 | stream strictMotif file | 3732 stream := WriteStream on: String new. 3733 stream 3734 nextPutAll: 'tk_get'; 3735 nextPutAll: operation; 3736 nextPutAll: 'File -parent '; 3737 nextPutAll: parent container; 3738 nextPutAll: ' -title '; 3739 nextPutAll: aLabel asTkString; 3740 nextPutAll: ' -defaultextension '; 3741 nextPutAll: ext asTkString; 3742 nextPutAll: ' -filetypes {'. 3743 typeList do: 3744 [:each | 3745 stream 3746 nextPut: ${; 3747 nextPutAll: (each at: 1) asTkString; 3748 nextPutAll: ' {'. 3749 each size > 1 3750 ifTrue: 3751 [each 3752 from: 2 3753 to: each size 3754 do: 3755 [:type | 3756 stream 3757 nextPutAll: type; 3758 space]]. 3759 stream nextPutAll: '}} ']. 3760 stream nextPutAll: '{"All files" * }}'. 3761 (name notNil and: [name notEmpty]) 3762 ifTrue: 3763 [stream 3764 nextPutAll: ' -initialfile '; 3765 nextPutAll: name asTkString]. 3766 strictMotif := BText emacsLike. 3767 BText emacsLike: Blox platform ~= 'unix'. 3768 parent map. 3769 self tclEval: stream contents. 3770 file := self tclResult. 3771 file isEmpty ifTrue: [file := nil]. 3772 BText emacsLike: strictMotif. 3773 ^file 3774 ] 3775 3776 BDialog class >> chooseColor: parent label: aLabel default: color [ 3777 "Prompt for a color. The dialog box is created with the given 3778 parent window and with aLabel as its title bar text, and initially 3779 it selects the color given in the color parameter. 3780 3781 If the dialog box is canceled, nil is answered, else the 3782 selected color is returned as a String with its RGB value." 3783 3784 <category: 'prompters'> 3785 | result | 3786 parent map. 3787 self 3788 tclEval: 'tk_chooseColor -parent %1 -title %2 -initialcolor %3' 3789 with: parent container 3790 with: aLabel asTkString 3791 with: color asTkString. 3792 result := self tclResult. 3793 result isEmpty ifTrue: [result := nil]. 3794 ^result 3795 ] 3796 3797 BDialog class >> chooseFileToOpen: parent label: aLabel default: name defaultExtension: ext types: typeList [ 3798 "Pop up a dialog box for the user to select a file to open. 3799 Its purpose is for the user to select an existing file only. 3800 If the user enters an non-existent file, the dialog box gives 3801 the user an error prompt and requires the user to give an 3802 alternative selection or to cancel the selection. If an 3803 application allows the user to create new files, it should 3804 do so by providing a separate New menu command. 3805 3806 If the dialog box is canceled, nil is answered, else the 3807 selected file name is returned as a String. 3808 3809 The dialog box is created with the given parent window 3810 and with aLabel as its title bar text. The name parameter 3811 indicates which file is initially selected, and the default 3812 extension specifies a string that will be appended to the 3813 filename if the user enters a filename without an extension. 3814 3815 The typeList parameter is an array of arrays, like 3816 #(('Text files' '.txt' '.diz') ('Smalltalk files' '.st')), 3817 and is used to construct a listbox of file types. When the user 3818 chooses a file type in the listbox, only the files of that type 3819 are listed. Each item in the array contains a list of strings: 3820 the first one is the name of the file type described by a particular 3821 file pattern, and is the text string that appears in the File types 3822 listbox, while the other ones are the possible extensions that 3823 belong to this particular file type." 3824 3825 "e.g. 3826 fileName := BDialog 3827 chooseFileToOpen: aWindow 3828 label: 'Open file' 3829 default: nil 3830 defaultExtension: 'gif' 3831 types: #( 3832 ('Text files' '.txt' '.diz') 3833 ('Smalltalk files' '.st') 3834 ('C source files' '.c') 3835 ('GIF files' '.gif'))" 3836 3837 <category: 'prompters'> 3838 ^self 3839 chooseFile: 'Open' 3840 parent: parent 3841 label: aLabel 3842 default: name 3843 defaultExtension: ext 3844 types: typeList 3845 ] 3846 3847 BDialog class >> chooseFileToSave: parent label: aLabel default: name defaultExtension: ext types: typeList [ 3848 "Pop up a dialog box for the user to select a file to save; 3849 this differs from the file open dialog box in that non-existent 3850 file names are accepted and existing file names trigger a 3851 confirmation dialog box, asking the user whether the file 3852 should be overwritten or not. 3853 3854 If the dialog box is canceled, nil is answered, else the 3855 selected file name is returned as a String. 3856 3857 The dialog box is created with the given parent window 3858 and with aLabel as its title bar text. The name parameter 3859 indicates which file is initially selected, and the default 3860 extension specifies a string that will be appended to the 3861 filename if the user enters a filename without an extension. 3862 3863 The typeList parameter is an array of arrays, like 3864 #(('Text files' '.txt' '.diz') ('Smalltalk files' '.st')), 3865 and is used to construct a listbox of file types. When the user 3866 chooses a file type in the listbox, only the files of that type 3867 are listed. Each item in the array contains a list of strings: 3868 the first one is the name of the file type described by a particular 3869 file pattern, and is the text string that appears in the File types 3870 listbox, while the other ones are the possible extensions that 3871 belong to this particular file type." 3872 3873 <category: 'prompters'> 3874 ^self 3875 chooseFile: 'Save' 3876 parent: parent 3877 label: aLabel 3878 default: name 3879 defaultExtension: ext 3880 types: typeList 3881 ] 3882 3883 addButton: aLabel receiver: anObject index: anInt [ 3884 "Add a button to the dialog box that, when clicked, will 3885 cause the #dispatch: method to be triggered in anObject, 3886 passing anInt as the argument of the callback. The 3887 caption of the button is set to aLabel." 3888 3889 <category: 'accessing'> 3890 ^self 3891 addButton: aLabel 3892 receiver: anObject 3893 message: #dispatch: 3894 argument: anInt 3895 ] 3896 3897 addButton: aLabel receiver: anObject message: aSymbol [ 3898 "Add a button to the dialog box that, when clicked, will 3899 cause the aSymbol unary selector to be sent to anObject. 3900 The caption of the button is set to aLabel." 3901 3902 <category: 'accessing'> 3903 callbacks addLast: (DirectedMessage 3904 selector: aSymbol 3905 arguments: #() 3906 receiver: anObject). 3907 self addButton: aLabel 3908 ] 3909 3910 addButton: aLabel receiver: anObject message: aSymbol argument: arg [ 3911 "Add a button to the dialog box that, when clicked, will 3912 cause the aSymbol one-argument selector to be sent to anObject, 3913 passing arg as the argument of the callback. The 3914 caption of the button is set to aLabel." 3915 3916 <category: 'accessing'> 3917 callbacks addLast: (DirectedMessage 3918 selector: aSymbol 3919 arguments: {arg} 3920 receiver: anObject). 3921 self addButton: aLabel 3922 ] 3923 3924 contents: newText [ 3925 "Display newText in the entry widget associated to the dialog box." 3926 3927 <category: 'accessing'> 3928 self tclEval: 'set var' , self connected , ' ' , newText asTkString 3929 ] 3930 3931 contents [ 3932 "Answer the text that is displayed in the entry widget associated 3933 to the dialog box." 3934 3935 <category: 'accessing'> 3936 self tclEval: 'return ${var' , self connected , '}'. 3937 ^self tclResult 3938 ] 3939 3940 addButton: aLabel [ 3941 <category: 'private'> 3942 self 3943 tclEval: 'button %1.buttons.b%2 -text %3 -highlightthickness 0 -takefocus 1 -command { 3944 callback %4 "invokeCallback:" %2 3945 destroy %1 3946 } 3947 pack %1.buttons.b%2 -side left -expand 1' 3948 with: self container 3949 with: callbacks size printString 3950 with: aLabel asTkString 3951 with: self asOop printString 3952 ] 3953 3954 create [ 3955 <category: 'private'> 3956 super create. 3957 self 3958 tclEval: ' 3959 label %1.msg -padx 5 -pady 5 -anchor nw -text ' 3960 , initInfo key asTkString 3961 , ' 3962 place %1.msg -x 0.0 -y 0.0 -relwidth 1.0 3963 bind %1.msg <Configure> { %1.msg configure -wraplength %%w } 3964 %1.msg configure -background [ %1 cget -background ] 3965 frame %1.buttons -highlightthickness 0 -takefocus 0 3966 %1.buttons configure -background [ %1 cget -background ] 3967 place %1.buttons -anchor sw -x 0.0 -rely 1.0 -relwidth 1.0 -height 14m 3968 lower %1.buttons 3969 lower %1.msg' 3970 with: self connected. 3971 initInfo value isNil ifTrue: [^self]. 3972 self 3973 tclEval: ' 3974 set var%1 %2 3975 entry %1.text -textvariable var%1 -highlightthickness 0 -takefocus 1 3976 place %1.text -in %1.msg -x 5 -y 5 -width -10 -rely 1.0 -relwidth 1.0 3977 raise %1.text' 3978 with: self connected 3979 with: initInfo value asTkString 3980 ] 3981 3982 initInfo: assoc [ 3983 <category: 'private'> 3984 initInfo := assoc 3985 ] 3986 3987 initialize: parentWidget [ 3988 <category: 'private'> 3989 super initialize: parentWidget. 3990 callbacks := OrderedCollection new 3991 ] 3992 3993 center [ 3994 "Center the dialog box's parent window in the screen" 3995 3996 <category: 'widget protocol'> 3997 self parent center 3998 ] 3999 4000 centerIn: view [ 4001 "Center the dialog box's parent window in the given widget" 4002 4003 <category: 'widget protocol'> 4004 self parent centerIn: view 4005 ] 4006 4007 destroyed [ 4008 "Private - The receiver has been destroyed, clear the corresponding 4009 Tcl variable to avoid memory leaks." 4010 4011 <category: 'widget protocol'> 4012 self tclEval: 'catch { unset var' , self connected , '}'. 4013 super destroyed 4014 ] 4015 4016 invokeCallback: index [ 4017 "Generate a synthetic callback corresponding to the index-th 4018 button being pressed, and destroy the parent window (triggering 4019 its callback if one was established)." 4020 4021 <category: 'widget protocol'> 4022 (callbacks at: index asInteger) send. 4023 self parent destroy 4024 ] 4025 4026 loop [ 4027 "Map the parent window modally. In other words, an event loop 4028 is started that ends only after the window has been destroyed. 4029 For more information on the treatment of events for modal windows, 4030 refer to BWindow>>#modalMap." 4031 4032 "self parent width: (self parent width min: 200)." 4033 4034 <category: 'widget protocol'> 4035 self parent modalMap 4036 ] 4037] 4038 4039 4040 4041BMenuObject subclass: BMenuBar [ 4042 4043 <comment: 'I am the Menu Bar, the top widget in a full menu structure.'> 4044 <category: 'Graphics-Windows'> 4045 4046 add: aMenu [ 4047 "Add aMenu to the menu bar" 4048 4049 <category: 'accessing'> 4050 aMenu create. 4051 ^self addChild: aMenu 4052 ] 4053 4054 remove: aMenu [ 4055 "Remove aMenu from the menu bar" 4056 4057 <category: 'accessing'> 4058 self 4059 tclEval: 'catch { %1 delete %2 }' 4060 with: self connected 4061 with: aMenu connected 4062 ] 4063 4064 connected [ 4065 <category: 'private'> 4066 ^primitive 4067 ] 4068 4069 container [ 4070 <category: 'private'> 4071 ^primitive 4072 ] 4073 4074 initialize: parentWidget [ 4075 <category: 'private'> 4076 super initialize: parentWidget. 4077 primitive := self parent isNil 4078 ifTrue: ['.popup'] 4079 ifFalse: [self parent container , '.menu']. 4080 4081 "BMenuBar is NOT a BPrimitive, so it has to explicitly create itself" 4082 self 4083 tclEval: 'menu ' , self connected , ' -font {' , self class defaultFont 4084 , '} -tearoff 0'. 4085 self parent isNil ifFalse: [self parent menu: self] 4086 ] 4087] 4088 4089 4090 4091BMenuObject subclass: BMenu [ 4092 | label exists | 4093 4094 <comment: 'I am a Menu that is part of a menu bar.'> 4095 <category: 'Graphics-Windows'> 4096 4097 BMenu class >> new: parent label: label [ 4098 "Add a new menu to the parent window's menu bar, with `label' as 4099 its caption (for popup menus, parent is the widget over which the 4100 menu pops up as the right button is pressed)." 4101 4102 <category: 'instance creation'> 4103 ^(self basicNew) 4104 initialize: parent; 4105 label: label; 4106 yourself 4107 ] 4108 4109 label [ 4110 "Answer the value of the label option for the widget. 4111 4112 Specifies a string to be displayed inside the widget. The way in which the 4113 string is displayed depends on the particular widget and may be determined 4114 by other options, such as anchor. For windows, this is the title of the window." 4115 4116 <category: 'accessing'> 4117 ^label 4118 ] 4119 4120 label: value [ 4121 "Set the value of the label option for the widget. 4122 4123 Specifies a string to be displayed inside the widget. The way in which the 4124 string is displayed depends on the particular widget and may be determined 4125 by other options, such as anchor. For windows, this is the title of the window." 4126 4127 <category: 'accessing'> 4128 label := value. 4129 exists 4130 ifTrue: 4131 [self 4132 tclEval: ' %1 configure -title %2' 4133 with: self connected 4134 with: value asTkString] 4135 ] 4136 4137 addLine [ 4138 "Add a separator item at the end of the menu" 4139 4140 <category: 'callback registration'> 4141 ^self addMenuItemFor: #() notifying: self "self is dummy" 4142 ] 4143 4144 addMenuItemFor: anArray notifying: receiver [ 4145 "Add a menu item described by anArray at the end of the menu. 4146 If anArray is empty, insert a separator line. If anArray 4147 has a single item, a menu item is created without a callback. 4148 If anArray has two or three items, the second one is used as 4149 the selector sent to receiver, and the third one (if present) 4150 is passed to the selector." 4151 4152 "Receiver will be sent the callback messages. anArray 4153 is something that responds to at: and size. Possible types are: 4154 #() insert a seperator line 4155 #(name) create a menu item with name, but no callback 4156 #(name symbol) create a menu item with the given name and 4157 no parameter callback. 4158 #(name symbol arg) create a menu item with the given name and 4159 one parameter callback." 4160 4161 <category: 'callback registration'> 4162 | item | 4163 item := self newMenuItemFor: anArray notifying: receiver. 4164 exists ifTrue: [item create] 4165 ] 4166 4167 callback: receiver using: selectorPairs [ 4168 "Add menu items described by anArray at the end of the menu. 4169 Each element of selectorPairs must be in the format described 4170 in BMenu>>#addMenuItemFor:notifying:. All the callbacks will 4171 be sent to receiver." 4172 4173 <category: 'callback registration'> 4174 selectorPairs do: [:pair | self addMenuItemFor: pair notifying: receiver] 4175 ] 4176 4177 empty [ 4178 "Empty the menu widget; that is, remove all the children" 4179 4180 <category: 'callback registration'> 4181 self tclEval: self connected , ' delete 0 end'. 4182 children := OrderedCollection new. 4183 childrensUnderline := nil 4184 ] 4185 4186 destroy [ 4187 "Destroy the menu widget; that is, simply remove ourselves from 4188 the parent menu bar." 4189 4190 <category: 'callback registration'> 4191 self parent remove: self 4192 ] 4193 4194 addChild: menuItem [ 4195 <category: 'private'> 4196 menuItem menuIndex: self childrenCount. 4197 super addChild: menuItem. 4198 self exists ifTrue: [menuItem create]. 4199 ^menuItem 4200 ] 4201 4202 connected [ 4203 <category: 'private'> 4204 ^primitive 4205 ] 4206 4207 container [ 4208 <category: 'private'> 4209 ^primitive 4210 ] 4211 4212 create [ 4213 <category: 'private'> 4214 | s | 4215 s := WriteStream on: (String new: 80). 4216 s 4217 nextPutAll: 'menu '; 4218 nextPutAll: self connected; 4219 nextPutAll: ' -tearoff 0 -postcommand { callback '; 4220 print: self asOop; 4221 nextPutAll: ' invokeCallback }'; 4222 nl; 4223 nextPutAll: self parent container; 4224 nextPutAll: ' add cascade -label '; 4225 nextPutAll: self label asTkString; 4226 nextPutAll: ' -menu '; 4227 nextPutAll: self connected; 4228 nextPutAll: ' -underline '; 4229 print: (self parent underline: self label). 4230 self tclEval: s contents. 4231 4232 "Set the title for torn-off menus" 4233 self label: self label. 4234 self childrenDo: [:each | each create]. 4235 exists := true 4236 ] 4237 4238 exists [ 4239 <category: 'private'> 4240 ^exists 4241 ] 4242 4243 initialize: parentWidget [ 4244 <category: 'private'> 4245 super initialize: parentWidget. 4246 label := ''. 4247 exists := false. 4248 primitive := '%1.w%2' % 4249 {self parent container. 4250 self asOop printString: 36} 4251 ] 4252 4253 newMenuItemFor: pair notifying: receiver [ 4254 <category: 'private'> 4255 | item size | 4256 size := pair size. 4257 pair size = 0 ifTrue: [^BMenuItem new: self]. 4258 (size >= 2 and: [pair last isArray]) 4259 ifTrue: 4260 [size := size - 1. 4261 item := BMenu new: self label: (pair at: 1). 4262 pair last 4263 do: [:each | item add: (item newMenuItemFor: each notifying: receiver)]] 4264 ifFalse: [item := BMenuItem new: self label: (pair at: 1)]. 4265 size = 1 ifTrue: [^item]. 4266 size = 2 ifTrue: [^item callback: receiver message: (pair at: 2)]. 4267 ^item 4268 callback: receiver 4269 message: (pair at: 2) 4270 argument: (pair at: 3) 4271 ] 4272] 4273 4274 4275 4276BMenu subclass: BPopupMenu [ 4277 4278 <comment: 'I am a class that provides the ability to show popup menus when the 4279right button (Button 3) is clicked on another window.'> 4280 <category: 'Graphics-Windows'> 4281 4282 PopupMenuBar := nil. 4283 PopupMenus := nil. 4284 4285 BPopupMenu class >> initializeOnStartup [ 4286 <category: 'private - accessing'> 4287 PopupMenuBar := nil. 4288 PopupMenus := WeakKeyIdentityDictionary new 4289 ] 4290 4291 BPopupMenu class >> popupMenuBar [ 4292 <category: 'private - accessing'> 4293 PopupMenuBar isNil ifTrue: [PopupMenuBar := BMenuBar new: nil]. 4294 ^PopupMenuBar 4295 ] 4296 4297 initialize: parentWindow [ 4298 <category: 'private'> 4299 super initialize: self class popupMenuBar. 4300 self parent add: self. 4301 PopupMenus at: self parent ifPresent: [:menu | menu destroy]. 4302 PopupMenus at: self parent put: self. 4303 parentWindow 4304 bind: '<Button-3>' 4305 to: #popup:y: 4306 of: self 4307 parameters: '%X %Y'. 4308 parentWindow 4309 bind: '<Shift-F10>' 4310 to: #popup:y: 4311 of: self 4312 parameters: '[expr 2+[winfo rootx %W]] [expr 2+[winfo rooty %W]]' 4313 ] 4314 4315 popup: x y: y [ 4316 "Note that x and y are strings!" 4317 4318 <category: 'private'> 4319 self tclEval: 'tk_popup ' , self connected , ' ' , x , ' ' , y 4320 ] 4321 4322 popup [ 4323 "Generate a synthetic menu popup event" 4324 4325 <category: 'widget protocol'> 4326 self tclEval: 'event generate %1 <Shift-F10>' with: self parent connected 4327 ] 4328] 4329 4330 4331 4332BMenuObject subclass: BMenuItem [ 4333 | index createCode | 4334 4335 <comment: 'I am the tiny and humble Menu Item, a single command choice in the 4336menu structure. But if it wasn''t for me, nothing could be done... 4337eh eh eh!!'> 4338 <category: 'Graphics-Windows'> 4339 4340 BMenuItem class >> new: parent [ 4341 "Add a new separator item to the specified menu." 4342 4343 <category: 'instance creation'> 4344 ^self basicNew initialize: parent 4345 ] 4346 4347 BMenuItem class >> new: parent label: label [ 4348 "Add a new menu item to the specified menu (parent) , with `label' 4349 as its caption." 4350 4351 <category: 'instance creation'> 4352 ^self basicNew initialize: parent label: label 4353 ] 4354 4355 label [ 4356 "Answer the value of the label option for the widget. 4357 4358 Specifies a string to be displayed inside the widget. The way in which the 4359 string is displayed depends on the particular widget and may be determined 4360 by other options, such as anchor. For windows, this is the title of the window." 4361 4362 <category: 'accessing'> 4363 ^self properties at: #label 4364 ] 4365 4366 label: value [ 4367 "Set the value of the label option for the widget. 4368 4369 Specifies a string to be displayed inside the widget. The way in which the 4370 string is displayed depends on the particular widget and may be determined 4371 by other options, such as anchor. For windows, this is the title of the window." 4372 4373 <category: 'accessing'> 4374 (self properties at: #label) isNil 4375 ifTrue: [^self error: 'no label for separator lines']. 4376 self parent exists 4377 ifTrue: 4378 [self 4379 tclEval: self container , ' entryconfigure ' , self connected , ' -label ' 4380 , value asTkString]. 4381 self properties at: #label put: value 4382 ] 4383 4384 connected [ 4385 <category: 'private'> 4386 ^index 4387 ] 4388 4389 container [ 4390 <category: 'private'> 4391 ^self parent container 4392 ] 4393 4394 create [ 4395 <category: 'private'> 4396 | label | 4397 label := self label ifNil: [''] ifNotNil: [:lab | lab asTkString]. 4398 self 4399 tclEval: createCode 4400 with: label 4401 with: self widgetType. 4402 createCode := '' "free some memory" 4403 ] 4404 4405 initialize: parentWidget [ 4406 <category: 'private'> 4407 super initialize: parentWidget. 4408 createCode := self container , ' add separator'. 4409 self properties at: #label put: nil. 4410 parent addChild: self 4411 ] 4412 4413 initialize: parentWidget label: label [ 4414 <category: 'private'> 4415 | s | 4416 super initialize: parentWidget. 4417 s := WriteStream on: (String new: 80). 4418 s 4419 nextPutAll: self container; 4420 nextPutAll: ' add %2 -label %1 -font {' , self class defaultFont 4421 , '} -underline '; 4422 print: (self parent underline: label); 4423 nextPutAll: ' -command { callback '; 4424 print: self asOop; 4425 nextPutAll: ' invokeCallback }'. 4426 createCode := s contents. 4427 self properties at: #label put: label. 4428 parent addChild: self. 4429 parent exists ifTrue: [self create] 4430 ] 4431 4432 menuIndex: anIndex [ 4433 <category: 'private'> 4434 index := anIndex printString 4435 ] 4436 4437 widgetType [ 4438 <category: 'private'> 4439 ^'command' 4440 ] 4441] 4442 4443 4444 4445BMenuItem subclass: BCheckMenuItem [ 4446 | status | 4447 4448 <comment: 'I am a menu item which can be toggled between two states, marked 4449and unmarked.'> 4450 <category: 'Graphics-Windows'> 4451 4452 BCheckMenuItem class >> new: parent [ 4453 <category: 'instance creation'> 4454 self shouldNotImplement 4455 ] 4456 4457 invokeCallback [ 4458 "Generate a synthetic callback" 4459 4460 <category: 'accessing'> 4461 self properties removeKey: #value ifAbsent: []. 4462 self callback isNil ifFalse: [self callback send] 4463 ] 4464 4465 value [ 4466 "Answer whether the menu item is in a selected (checked) state." 4467 4468 <category: 'accessing'> 4469 ^self properties at: #value ifAbsentPut: [false] 4470 ] 4471 4472 value: aBoolean [ 4473 "Set whether the button is in a selected (checked) state and 4474 generates a callback accordingly." 4475 4476 <category: 'accessing'> 4477 self properties at: #value put: aBoolean. 4478 self tclEval: 'set ' , self variable , self valueString. 4479 self callback isNil ifFalse: [self callback send] 4480 ] 4481 4482 create [ 4483 <category: 'private'> 4484 super create. 4485 self 4486 tclEval: '%1 entryconfigure %2 -onvalue 1 -offvalue 0 -variable %3' 4487 with: self container 4488 with: self connected 4489 with: self variable 4490 ] 4491 4492 destroyed [ 4493 "Private - The receiver has been destroyed, clear the corresponding 4494 Tcl variable to avoid memory leaks." 4495 4496 <category: 'private'> 4497 self tclEval: 'unset ' , self variable. 4498 super destroyed 4499 ] 4500 4501 valueString [ 4502 <category: 'private'> 4503 ^self value ifTrue: [' 1'] ifFalse: [' 0'] 4504 ] 4505 4506 variable [ 4507 <category: 'private'> 4508 ^'var' , self connected , self container copyWithout: $. 4509 ] 4510 4511 widgetType [ 4512 <category: 'private'> 4513 ^'checkbutton' 4514 ] 4515] 4516 4517 4518 4519"-------------------------- BEdit class -----------------------------" 4520 4521 4522 4523"-------------------------- BLabel class -----------------------------" 4524 4525 4526 4527Eval [ 4528 BLabel initialize 4529] 4530 4531 4532 4533"-------------------------- BButton class -----------------------------" 4534 4535 4536 4537"-------------------------- BForm class -----------------------------" 4538 4539 4540 4541"-------------------------- BContainer class -----------------------------" 4542 4543 4544 4545"-------------------------- BRadioGroup class -----------------------------" 4546 4547 4548 4549"-------------------------- BRadioButton class -----------------------------" 4550 4551 4552 4553"-------------------------- BToggle class -----------------------------" 4554 4555 4556 4557"-------------------------- BImage class -----------------------------" 4558 4559 4560 4561"-------------------------- BList class -----------------------------" 4562 4563 4564 4565"-------------------------- BWindow class -----------------------------" 4566 4567 4568 4569"-------------------------- BTransientWindow class -----------------------------" 4570 4571 4572 4573"-------------------------- BPopupWindow class -----------------------------" 4574 4575 4576 4577"-------------------------- BDialog class -----------------------------" 4578 4579 4580 4581"-------------------------- BMenuBar class -----------------------------" 4582 4583 4584 4585"-------------------------- BMenu class -----------------------------" 4586 4587 4588 4589"-------------------------- BPopupMenu class -----------------------------" 4590 4591 4592 4593"-------------------------- BMenuItem class -----------------------------" 4594 4595 4596 4597"-------------------------- BCheckMenuItem class -----------------------------" 4598 4599