Advanced Visual Age Development Eric Clayberg Vice President
Advanced Visual. Age Development Eric Clayberg Vice President of Product Development Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 clayberg@smalltalksystems. com http: //www. instantiations. com 978 -750 -3621 Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 1
Who Am I? l First used Smalltalk in late ‘ 80 s; full-time since 1991 l Co-Founder of (the original) Object. Share in 1992 l Developer & Chief Architect of Window. Builder Pro and over a dozen other commercial Smalltalk add-on products (VA Assist Pro, Widget. Kits, etc. ) l Vice President of Development for Parc. Place-Digitalk 1996 -97 l Vice President of Product Development for Instantiations 1997 -present l Smalltalk Editor for VA Magazine l Usenet Junkie Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 2
Who Is Instantiations? Tektronix Instantiations DIGITALK Parc. Place Digitalk Objectshare Systems Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 3
Tutorial Roadmap l Advanced GUI Techniques l Custom Widget Development l Complex Configuration Management l Development Tool (Browser) Enhancements Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 4
Advanced GUI Techniques l Widget Callbacks & Event Handlers l Using Pointer Motion l Using Timers & Delays l Determining Key State l Creating Screen Snapshots l Printing Images l Clipboard l Attachments l Morphing Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 5
Structure of Visual. Age Widgets Visual. Parts (Abt. Primitive. View) • Composition Editor #primary. Widget Extended Widgets #primary. Widget Common Widgets (Cw. Widget) • Browsers • Window. Builder Pro #os. Widget OS Specific Widgets (OSWidget) Windows, OS/2, Unix Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division • Hands Off March 14, 1999 S 2 - 6
Widget Callbacks & Event Handlers l Why use Callbacks and Events? l l What is the different between callback and event handlers? l l l Abt layer exposes a subset of available protocol More control Create complex interactions Not much Syntactically similar Events are low-level occurrences like mouse down/up/move, pointer motion, key press/release, etc. Events are generated constantly (and may not be meaningful) Callbacks are higher-level occurrences that imply some semantic meaning like button clicks, text input, focus changes Abt-layer “events” are very high-level occurrences that wrapper a subset of Cwlayer callbacks Given an Abt. Part, how do you get to its Common. Widget component? l l Send the #primary. Widget message to the part Do this in a method overriding #open. In. Shell. View or in a script triggered by the #opened. Widget event (prior to opening, the primary widget is nil) Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 7
Setting up a Callback Handler l Use the #add. Callback: receiver: selector: client. Data: method l l l First parameter - the name of the callback (e. g. , Xm. Nactivate. Callback) “receiver” - the object to send the callback message to “selector” - the 3 -parameter message selector to send “client. Data” - an object to be passed to the receiver of the callback message as the client. Data parameter when the callback is invoked, or nil Example: <cw. Widget> add. Callback: Xm. Nactivate. Callback receiver: self selector: #clicked: client. Data: call. Data: client. Data: nil l Create the handler method l l First argument - the widget that triggered the event “client. Data” - the object specified when the callback was set up (usually nil) “call. Data” - data specific to the specified callback type Example: clicked: a. Widget client. Data: client. Data call. Data: call. Data System message: ‘Hello World’ Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 8
Setting up an Event Handler l Use the #add. Event. Handler: receiver: selector: client. Data: method l First parameter - an integer event mask identifying the desired events. One or more of the following OR’ed together: l l l l Key. Press. Mask - Keyboard down events Key. Release. Mask - Keyboard up events Button. Press. Mask - Pointer button down events Button. Release. Mask - Pointer button up events Pointer. Motion. Mask - All pointer motion events Button 1 Motion. Mask - Pointer motion while button 1 down Button 2 Motion. Mask - Pointer motion while button 2 down Button 3 Motion. Mask - Pointer motion while button 3 down Button. Motion. Mask - Pointer motion while any button down Button. Menu. Mask - Menu request events “receiver” - the object to send the event handler message to “selector” - the 3 -parameter message selector to send “client. Data” - an object to be passed to the receiver of the event handler message as the client. Data parameter when the event handler is invoked, or nil Example: <cw. Widget> add. Event. Handler: Key. Press. Mask | Key. Release. Mask receiver: self selector: #key. Pressed: client. Data: call. Data: client. Data: nil Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 9
Callback/Event Handler Tricks l Use 3 -argument blocks to avoid the need for handler methods l l l Block arguments should be “widget”, “client. Data” and “call. Data” (or any name if you don’t care) The “selector” should be #value: Example: <cw. Widget> add. Callback: Xm. Nactivate. Callback receiver: [: widget : client. Data : call. Data | System message: ‘Hello World’] selector: #value: client. Data: nil Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 10
Callback/Event Handler Tricks - 2 l Support unary & 1 -argument callback handlers (like VSE) l Add the following method to Cw. Primitive (and Cw. Composite) to override the Cw. Basic. Widget>>add. Callback: receiver: client. Data: method add. Callback: callback. Name receiver: receiver selector: selector client. Data: client. Data selector argument. Count <= 1 if. True: [ super add. Callback: callback. Name receiver: (selector argument. Count == 0 if. True: [: a : b : c | receiver perform: selector] if. False: [: a : b : c | receiver perform: selector with: client. Data value]) selector: #value: client. Data] if. False: [ super add. Callback: callback. Name receiver: receiver selector: selector client. Data: client. Data] Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 11
Callback/Event Handler Tricks - 3 l Now you can set up callback handlers like this: button. Widget add. Callback: Xm. Nactivate. Callback receiver: self selector: #clicked client. Data: nil list. Widget add. Callback: Xm. Nsingle. Selection. Callback receiver: self selector: #selected: client. Data: [list. Widget selected. Item] the argument to the #selected: method Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 12
Using Event Handlers l What are some useful things you can do with event handlers? l l l Detect clicks on static labels (using Button. Release. Mask ) Detect when the mouse passes over a widget (using Pointer. Motion. Mask) l Implement hover/balloon help l Implement simple status line help Example (click on a static label) l Add the following event handler to a Cw. Label <a. Cw. Label> add. Event. Handler: Button. Release. Mask receiver: self selector: #clicked: client. Data: call. Data: client. Data: nil l Implement the #clicked: client. Data: call. Data: method clicked: widget client. Data: client. Data call. Data: call. Data System message: ‘I’’m clicked’ Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 13
Using Pointer Motion l Example (status line help) l Add the following event handler to every widget in the window (including the main form so that you can detect when the pointer isn’t over a widget) <a. Cw. Widget> add. Event. Handler: Pointer. Motion. Mask receiver: self selector: #pointer. Motion: client. Data: call. Data: client. Data: nil l Add a static text label name “status. Line” to the bottom of the window Implement a dictionary named “help. Dict” that maps widget names to help text Implement the #pointer. Motion: client. Data: call. Data: method pointer. Motion: widget client. Data: client. Data call. Data: call. Data self status. Line label. String: (self help. Dict at: widget name) l Let’s build it. . . Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 14
Pointer Motion Example Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 15
Using Delays l Goal: execute some code after a fixed amount of time l Solutions l l l Use a Delay Use a Timer Example: l Delay for one second and then execute some code (Delay for. Milliseconds: 1000) wait. self do. Something l l Problem: blocks the current process Solution: fork the code as a background process: [(Delay for. Milliseconds: 1000) wait. self do. Something] fork. At: Processor user. Background. Priority l Example: Ring Bell every second for five seconds 5 times. Repeat: [ (Delay for. Milliseconds: 1000) wait. Cg. Display default bell: 0]. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 16
Using Timers l Create a one shot timer l l l Use the Cw. App. Context>>add. Timeout: receiver: selector: client. Data: First argument - integer specifying the time interval in milliseconds “receiver” - the object which is the receiver of the work procedure message “selector” - the Symbol which is the 1 -parameter message selector to send. “client. Data” - any object which is to be passed as the parameter to the work procedure message Example: Cw. App. Context default add. Timeout: 1000 “one second” receiver: [: client. Data | Cg. Display default bell: 0] selector: #value: client. Data: nil Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 17
Using Timers - 2 l Create a recurring timer to update a clock l l Create a static text widget named “clock” Create a #start. Clock: method start. Clock: milliseconds self clock label. String: Time now print. String. Cw. App. Context default add. Timeout: milliseconds receiver: self selector: #update. Clock: client. Data: milliseconds l Create an #update. Clock: method update. Clock: milliseconds self clock is. Mapped if. False: [^self]. self clock label. String: Time now print. String. Cw. App. Context default add. Timeout: (milliseconds (Time millisecond. Clock. Value \ milliseconds)) receiver: self selector: #update. Clock: client. Data: milliseconds l Start the clock so that it updates every second: self start. Clock: 1000 Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 18
Clock Example Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 19
Another Way to Delay l Use the Cw. App. Context>>async. Exec. In. UI: (a. Block) method l l A favorite “magic” method for executing a block code after a short delay Technically, what does it do? l Evaluates a. Block in the UI Process. No result is returned. l Processes with higher priority than the UI will NOT block. l In this case, a. Block is executed the next time the UI becomes active. l If this message is sent by the UI process, then a. Block will be executed after all previously queued background graphic requests have been executed l Example: . . . Cw. App. Context default async. Exec. In. UI: [Transcript cr; show: ‘ 1’]. Transcript cr; show: ‘ 2’. . l Result: . . . 2 1. . . Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 20
Determining Key State l Why would you need to do this? l l Constrain behavior (e. g. , Extended Select List Boxes) ALT-key hacks Conditional breakpoints How do you determine whether an arbitrary modifier key is depressed? l Look at the Cg. Display>>os. Get. Modifier. State method l Can be sent to any Cg. Display instance at any time. For example: Cg. Display default os. Get. Modifier. State Returns an integer encoding the key state l Use the Integer>>any. Mask: method to test for different keys (returns a Boolean) Examine the event hander data l l Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 21
Determining Key State - 2 l Useful methods to add to Object l Is any key down? is. Key. Down: key. Mask Cg. Display default os. Get. Modifier. State any. Mask: key. Mask l Is Alt key down? is. Alt. Key. Down self is. Key. Down: Cw. Constants: : Mod 1 Mask l Is Ctrl key down? is. Control. Key. Down self is. Key. Down: Cw. Constants: : Control. Mask l Is Shift key down? is. Shift. Key. Down self is. Key. Down: Cw. Constants: : Shift. Mask l Is Caps Lock key down? is. Caps. Lock. Key. Down self is. Key. Down: Cw. Constants: : Lock. Mask l Is Left Mouse Button down? is. Left. Mouse. Button. Down self is. Key. Down: Cw. Constants: : Button 1 Mask Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 22
Creating Screen Snapshots l Why is this useful? l l Useful for creating documentation Runtime error reporting Simple reports Cw. Shell>>get. Snapshot Here’s a handy method for creating a pixmap from any window l l l The OSWidget>>screen. Rect method answers the rectangle of the receiver in screen coordinates (this is different from the Cw. Widget bounding. Box method which answers the inner bound) The Cg. Drawable>> create. Pixmap: height: depth: method create a pixmap (bitmap) The Cg. Drawable>>copy. Area: gc: src. X: src. Y: width: height: dest. X: dest. Y: method copies an area of one image into another | rect def. Win pixmap | rect : = self os. Widget screen. Rect. def. Win : = Cg. Window default. pixmap : = def. Win create. Pixmap: (rect right - rect left) abs height: (rect bottom - rect top) abs depth: def. Win depth. def. Win copy. Area: pixmap gc: Cg. GC default src. X: rect left src. Y: rect top width: (rect right - rect left) abs height: (rect bottom - rect top) abs dest. X: 0 dest. Y: 0. ^pixmap Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 23
Copying Graphics to the Clipboard l Once we have the screen snapshot, it would be nice to do something with it l Here’s a handy method for copying a pixmap to the clipboard l l l The Cg. Display>>clipboard. Start. Copy: clip. Label: item. Id. Return: method message sets up storage and data structures to receive clipboard data The Cg. Display>>clipboard. Copy: item. Id: format. Name: buffer: private. Id: method copies a data item to temporary storage The Cg. Display>>clipboard. End. Copy: item. Id: method locks the clipboard from access by other applications, places data in the clipboard data structure, and unlocks the clipboard Cg. Pixmap>>copy. To. Clipboard | default. Display window item. Id | default. Display : = Cg. Display default. window : = Cg. Window default. item. Id : = Return. Parameter new. default. Display clipboard. Start. Copy: window clip. Label: 'Pixmap Copy' item. Id. Return: item. Id. default. Display clipboard. Copy: window item. Id: item. Id value format. Name: 'PIXMAP' buffer: self private. Id: 0. default. Display clipboard. End. Copy: window item. Id: item. Id value. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 24
Copying Text to the Clipboard l l The same technique works for text as well Here’s a handy method for copying a text to the clipboard Es. String>>copy. To. Clipboard | display window item. Id | display : = Cg. Display default. window : = Cg. Window default. item. Id : = Return. Parameter new. display clipboard. Start. Copy: window clip. Label: 'Text Copy' item. Id. Return: item. Id. display clipboard. Copy: window item. Id: item. Id value format. Name: 'STRING' buffer: self private. Id: 0. display clipboard. End. Copy: window item. Id: item. Id value. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 25
Printing Images l Just in case you want to know how to print a Pixmap, here’s how to do it: Cg. Pixmap>>copy. To. Printer | image print. Display printer. Shell default prompter | Cg. Display all. Printer. Display. Names is. Empty if. True: [^System message: 'There are no printers available. ']. (prompter : = Cw. Printer. Prompter new) prompt is. Nil if. True: [^self]. image : = self get. Device. Independent. Image: self rectangle. default : = prompter display. Name. print. Display : = Cw. App. Context default open. Display: default application. Name: 'Print Pixmap' application. Class: nil. printer. Shell : = Cw. Printer. Shell app. Create. Shell: 'Printer Shell' application. Class: nil display: print. Display arg. Block: [: w | w job. Attributes: prompter job. Attributes]. . Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 26
Printing Images - 2 Cg. Pixmap>>copy. To. Printer continued: . . . printer. Shell add. Callback: Xm. Nmap. Callback receiver: [: shell : client. Data : call. Data | printer. Shell start. Job if. True: [printer. Shell start. Page] if. False: [printer. Shell destroy. Widget]] selector: #value: client. Data: nil. . Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 27
Printing Images - 3 Cg. Pixmap>>copy. To. Printer continued: . . . printer. Shell add. Callback: Xm. Nexpose. Callback receiver: [: shell : client. Data : call. Data | | scale print. GC | scale : = printer. Shell width / image width min: printer. Shell height / image height. print. GC : = printer. Shell window create. GC: 0 values: nil. printer. Shell window put. Device. Independent. Image : print. GC image: image src. Rect: (0 @ 0 extent: image extent) dest. Rect: (0 @ 0 extent: (image extent * scale) truncated). print. GC free. GC. printer. Shell end. Page; end. Job; destroy. Widget. printer. Shell display close] selector: #value: client. Data: nil. printer. Shell realize. Widget l Thus you can print any screen like this: Transcript shell get. Snapshot copy. To. Printer Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 28
Attachments l By default all widgets are locked to the upper left corner of a window l For example: Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 29
Attachments - The Ideal l Ideally, we would like to specify what happens to each widget when the window resizes l For example: Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 30
Attachments - VA Editor l Here’s the lame attachment editor supplied with Visual. Age Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 31
Attachments - Sample Code l With very little effort, we can dramatically simply the process l l There are hundreds of possible attachment combinations But only a few (10 -20) that are commonly used By optimizing those cases, we can dramatically speed up the GUI layout process Sample code to add a “Set Attachments” cascaded menu to the popup widget menu in the Composition Editor l Add the following method to Abt. Primitive. View (and Abt. Composite. View) abt. Add. Own. Items. To. Pop. Up. Menu: a. Pop. Up. Menu for: an. Edit. Part super abt. Add. Own. Items. To. Pop. Up. Menu: a. Pop. Up. Menu for: an. Edit. Part add. Attachment. Items. To. Pop. Up. Menu: a. Pop. Up. Menu Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 32
Attachments - Sample Code 2 l Add the following methods to Abt. Cw. Edit. Part attach. All. Sides self perform. Blocked. Update: [| fs | (fs : = self visual. Policy visual. Part. Framing. Spec. Translate. By : 0@0) left. Edge: (fs left. Edge attachment: Xm. ATTACHFORM current. View : self part); right. Edge: (fs right. Edge attachment: Xm. ATTACHFORM current. View : self part); top. Edge: (fs top. Edge attachment: Xm. ATTACHFORM current. View : self part); bottom. Edge: (fs bottom. Edge attachment: Xm. ATTACHFORM current. View : self part). self frame. Visual. Part: fs] attach. Bottom. Right. Corner self perform. Blocked. Update: [| fs | (fs : = self visual. Policy visual. Part. Framing. Spec. Translate. By : 0@0) left. Edge: (fs left. Edge attachment: Abt. Attachments. Constants : : Xm. ATTACHSELFOPPOSITE current. View: self part); right. Edge: (fs right. Edge attachment: Xm. ATTACHFORM current. View : self part); top. Edge: (fs top. Edge attachment: Abt. Attachments. Constants : : Xm. ATTACHSELFOPPOSITE current. View: self part); bottom. Edge: (fs bottom. Edge attachment: Xm. ATTACHFORM current. View : self part). self frame. Visual. Part: fs] Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 33
Attachments - Sample Code 3 l Add the following methods to Abt. Cw. Edit. Part (continued) attach. Bottom. Left. Corner self perform. Blocked. Update: [| fs | (fs : = self visual. Policy visual. Part. Framing. Spec. Translate. By : 0@0) left. Edge: (fs left. Edge attachment: Xm. ATTACHFORM current. View : self part); right. Edge: (fs right. Edge attachment: Abt. Attachments. Constants : : Xm. ATTACHSELFOPPOSITE current. View: self part); top. Edge: (fs top. Edge attachment: Abt. Attachments. Constants : : Xm. ATTACHSELFOPPOSITE current. View: self part); bottom. Edge: (fs bottom. Edge attachment: Xm. ATTACHFORM current. View : self part). self frame. Visual. Part: fs] attach. Top. Bottom. Right. Sides self perform. Blocked. Update: [| fs | (fs : = self visual. Policy visual. Part. Framing. Spec. Translate. By : 0@0) left. Edge: (fs left. Edge attachment: Abt. Attachments. Constants : : Xm. ATTACHSELFOPPOSITE current. View: self part); right. Edge: (fs right. Edge attachment: Xm. ATTACHFORM current. View : self part); top. Edge: (fs top. Edge attachment: Xm. ATTACHFORM current. View : self part); bottom. Edge: (fs bottom. Edge attachment: Xm. ATTACHFORM current. View : self part). self frame. Visual. Part: fs] Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 34
Attachments - Sample Code 4 l Add the following methods to Abt. Cw. Edit. Part (continued) add. Attachment. Items. To. Pop. Up. Menu : a. Pop. Up. Menu | cascade. Menu : = a. Pop. Up. Menu create. Pulldown. Menu : 'Set Attachments' arg. Block: nil. (a. Pop. Up. Menu create. Cascade. Button : 'Set Attachments' arg. Block: [: w | w sub. Menu. Id: cascade. Menu]) manage. Child. (cascade. Menu create. Toggle. Button : 'All Sides' arg. Block: nil) add. Callback: Xm. Nvalue. Changed. Callback receiver: [: edit. Part : client. Date : call. Data | self attach. All. Sides] selector: #value: client. Data: nil; manage. Child. . Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 35
Attachments - Sample Code 5 l The # add. Attachment. Items. To. Pop. Up. Menu: method continued. . . (cascade. Menu create. Toggle. Button : 'Lower Left Corner' arg. Block: nil) add. Callback: Xm. Nvalue. Changed. Callback receiver: [: edit. Part : client. Date : call. Data | self attach. Bottom. Left. Corner] selector: #value: client. Data: nil; manage. Child. (cascade. Menu create. Toggle. Button : 'Lower Right Corner' arg. Block: nil) add. Callback: Xm. Nvalue. Changed. Callback receiver: [: edit. Part : client. Date : call. Data | self attach. Bottom. Right. Corner ] selector: #value: client. Data: nil; manage. Child. (cascade. Menu create. Toggle. Button : 'Top Bottom Right Sides' arg. Block: nil) add. Callback: Xm. Nvalue. Changed. Callback receiver: [: edit. Part : client. Date : call. Data | self attach. Top. Bottom. Right. Sides ] selector: #value: client. Data: nil; manage. Child. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 36
Attachments - New Menu l Now we can set attachments like this Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 37
Morphing l What is “morphing”? l l Replace any widget in the Composition Editor with another Maintain any common attributes Maintain any links that still make sense Visual. Age has a built-in framework that is used in only one place! l l l Morphing obsolete Abt. Notebook. View to Abt. Portable. PMNotebook. View Very easy to extend Just add a #abt. Isomorphic. Classes class method to any Abt. Part subclass l Answer a collection of symbols representing the classes that are valid replacements l Examples: Abt. List. View class>>abt. Isomorphic. Classes ^#(#Abt. Drop. Down. List. Combo. Box #Abt. Combo. Box. View #Abt. Container. Details. View #Abt. Multiple. Select. List. View #Abt. Spin. Button. View) Abt. Multiple. Select. List. View class>>abt. Isomorphic. Classes ^#(#Abt. Drop. Down. List. Combo. Box #Abt. Combo. Box. View #Abt. Container. Details. View #Abt. List. View #Abt. Spin. Button. View) Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 38
Morphing Example - Before Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 39
Morphing Example - After Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 40
Custom Visual Part Development l General Process l l l l Subclass Abt. Primitive. View Define Accessors Define Helper Methods Define Properties Edit-time Extensions Add to Tool Palette Example l l l Visual. Age contains a nice progress bar widget called Ew. Progress. Bar is a Cw. Widget-layer component We’ll make an Abt. Part layer component out of it Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 41
Subclass Abt. Primitive. View l Create My. Abt. Progress. Bar. View as a subclass of Abt. Primitive. View l Specify which Cw. Widget subclass to use at the core of the part by adding a #cw. Widget. Class class method to My. Abt. Progress. Bar. View cw. Widget. Class ^Ew. Progress. Bar l Add instance variables to hold the various attributes needed by the part l l l l l shadow. Type shadow. Width orientation direction fraction. Complete show. Percentage image. Color graphics. Descriptor ribbon. Graphics. Descriptor Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 42
Define Accessors l Create accessor methods for the various properties direction == nil if. True: [^Xm. FORWARD]. ^direction: an. Int direction : = an. Int. widget not. Nil if. True: [widget direction: an. Int]. self signal. Event: #direction. Changed with: an. Int. fraction. Complete == nil if. True: [^0]. ^fraction. Complete: an. Int fraction. Complete : = an. Int. widget not. Nil if. True: [widget fraction. Complete: an. Int / 100]. self signal. Event: #fraction. Complete. Changed with: an. Int. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 43
Define Accessors - 2 l Create accessor methods for the various properties (continued) orientation == nil if. True: [^Xm. HORIZONTAL]. ^orientation: an. Int orientation : = an. Int. widget not. Nil if. True: [widget orientation: an. Int]. self signal. Event: #orientation. Changed with: an. Int. shadow. Type == nil if. True: [^Xm. SHADOWIN]. ^shadow. Type: an. Int shadow. Type : = an. Int. widget not. Nil if. True: [widget shadow. Type: an. Int]. self signal. Event: #shadow. Type. Changed with: an. Int. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 44
Define Accessors - 3 l Create accessor methods for the various properties (continued) shadow. Width == nil if. True: [^1]. ^shadow. Width: an. Int shadow. Width : = an. Int. widget not. Nil if. True: [widget shadow. Width: an. Int]. self signal. Event: #shadow. Width. Changed with: an. Int. show. Percentage == nil if. True: [^false]. ^show. Percentage: a. Boolean show. Percentage : = a. Boolean. widget not. Nil if. True: [widget show. Percentage: a. Boolean]. self signal. Event: #show. Percentage. Changed with: a. Boolean. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 45
Define Accessors - 3 l Create accessor methods for the various properties (continued) image. Color ^image. Color: a. String (a. String = image. Color or: [a. String no. Nil and: [a. String is. Empty]]) if. True: [^nil]]. image. Color : = a. String. widget not. Nil if. True: [widget image. Color: (self as. Rgb: image. Color)]. self signal. Event: #image. Color. Changed with: image. Color. l The #as. Rgb: method converts color strings (e. g. , “red”) into instances of Cg. RGBColor (e. g. , Cg. RGBColor red: 65536 green: 0 blue: 0) Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 46
Define Accessors - 5 l Create accessor methods for the various properties (continued) graphics. Descriptor ^graphics. Descriptor: a. Graphics. Descriptor graphics. Descriptor : = a. Graphics. Descriptor. widget not. Nil if. True: [self update. Graphic: widget]. self signal. Event: #graphics. Descriptor. Changed with: a. Graphics. Descriptor. ribbon. Graphics. Descriptor ^ribbon. Graphics. Descriptor: a. Graphics. Descriptor ribbon. Graphics. Descriptor : = a. Graphics. Descriptor. widget not. Nil if. True: [self update. Graphic: widget]. self signal. Event: #ribbon. Graphics. Descriptor. Changed with: a. Graphics. Descriptor. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 47
Helper Methods l Create helper methods for handling graphic descriptors calc. Graphic. Label. Type ^((graphics. Descriptor is. Nil or: [graphics. Descriptor is. Icon. Descriptor ]) and: [ribbon. Graphics. Descriptor is. Nil or: [ribbon. Graphics. Descriptor is. Icon. Descriptor ]]) if. True: [Xm. ICON] if. False: [Xm. PIXMAP] update. Graphic: a. Widget self calc. Graphic. Label. Type == Xm. ICON if. True: [ graphics. Descriptor is. Nil if. False: [a. Widget image: graphics. Descriptor icon]. ribbon. Graphics. Descriptor is. Nil if. False: [a. Widget ribbon. Image: ribbon. Graphics. Descriptor icon]] if. False: [ graphics. Descriptor is. Nil if. False: [a. Widget image: graphics. Descriptor pixmap]. ribbon. Graphics. Descriptor is. Nil if. False: [ a. Widget ribbon. Image : ribbon. Graphics. Descriptor pixmap]]. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 48
#widget. Creation. Arg. Block Method l Create #widget. Creation. Arg. Block method widget. Creation. Arg. Block ^[: w | super widget. Creation. Arg. Block value: w. direction == nil if. False: [w direction: direction]. orientation == nil if. False: [w orientation: orientation]. shadow. Type == nil if. False: [w shadow. Type: shadow. Type]. shadow. Width == nil if. False: [w shadow. Width: shadow. Width]. fraction. Complete == nil if. False: [w fraction. Complete: fraction. Complete / 100]. show. Percentage == nil if. False: [w show. Percentage: show. Percentage]. (graphics. Descriptor == nil and: [ribbon. Graphics. Descriptor == nil]) if. False: [self update. Graphic: w]]. l Used during the creation of the Cw. Widget-layer component (“w” in the above is an instance of Ew. Progress. Bar) Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 49
Define Properties l Next we open the Public Interface Editor to define all of the properties l Here’s an example of adding the #direction property l l Get Selector = “direction” Set Selector = “direction: ” Changed event symbol = “direction. Changed” Attribute data type = “Integer” l Some attributes need special edit-time only attributes l Only stored in library!! Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 50
Define Properties - 2 l Here’s an example of adding the #image. Color property l l Get Selector = “image. Color” Set Selector = “image. Color: ” Changed event symbol = “image. Color. Changed” Attribute data type = “String” Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 51
Edit-time Extensions l Define edit-time property methods (these provide the values for any attributes with a drop-down selection list) direction. Valid. Values: a. Part. Property. Data ^Dictionary new at: 'Xm. FORWARD' put: Xm. FORWARD; at: 'Xm. REVERSE' put: Xm. REVERSE; yourself orientation. Valid. Values: a. Part. Property. Data ^Dictionary new at: 'Xm. HORIZONTAL' put: Xm. HORIZONTAL; at: 'Xm. VERTICAL' put: Xm. VERTICAL; yourself shadow. Type. Valid. Values: a. Part. Property. Data ^Dictionary new at: 'Xm. SHADOWNONE' put: Xm. SHADOWNONE; at: 'Xm. SHADOWIN' put: Xm. SHADOWIN; at: 'Xm. SHADOWOUT' put: Xm. SHADOWOUT; yourself Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 52
Edit-time Extensions - 2 l Define edit-time edit policy methods (these set up the editors for any special properties) image. Color. Edit. Policy: initial. Value property. Data: a. Part. Property. Data ^Abt. Ew. Object. Prompter. Edit. Policy new editable: true; value: initial. Value; prompter: Abt. Color. Name. Prompter new; yourself Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 53
Edit-time Extensions - 3 l Define miscellaneous class-side edit methods l Answer the part's name default size in the Composition Editor default. Edit. Size ^160 @ 20 l Answer the part's name to be displayed in the status area of the Composition Editor display. Name ^'Progress Bar' l Return the descriptor for the icon representing the class abt. Instance. Graphics. Descriptor ^Abt. Icon. Descriptor new module. Name: self abt. Graphics. Module. Name; id: 360 l Magic methods needed to make the part show up at the right size attachment. Spec. At: point ^self attachment. Spec. From. Rect: (point extent: self default. Edit. Size) position. Spec. At: point ^self position. Spec. From. Rect: (point extent: self default. Edit. Size) Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 54
Add to Tool Palette l Add class methods to My. Application to register our new part to the part palette l Answer the list of parts abt. Palette. Parts ^#(My. Abt. Progress. Bar. View) l Answer the name of the part category (new or existing) abt. Palette. Category. Name ^'Progress Bars' l Answer the category icons (if new category) abt. Palette. Category. Graphics. Descriptor ^Abt. Icon. Descriptor new module. Name: self abt. Graphics. Module. Name; id: 360 abt. Palette. Category. Open. Graphics. Descriptor ^self abt. Palette. Category. Graphics. Descriptor l Install and remove our parts when the application is loaded or unloaded self abt. Add. Parts. To. Catalog removing self abt. Remove. Parts. From. Catalog Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 55
My. Abt. Progress. Bar. View in Action Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 56
My. Abt. Split. Bar. View Example l Create My. Abt. Split. Bar. View as a subclass of Abt. Primitive. View l Specific which Cw. Widget subclass to use at the core of the part by adding a #cw. Widget. Class class method to My. Abt. Progress. Bar. View cw. Widget. Class ^Cw. Sash l Add instance variable to hold the various attributes needed by the part l l l orientation top. Limit. Widget, bottom. Limit. Widget, left. Limit. Widget, right. Limit. Widget Create accessor methods for the various properties orientation == nil if. True: [^Xm. HORIZONTAL]. ^orientation: an. Int orientation : = an. Int. widget not. Nil if. True: [widget orientation: an. Int]. self signal. Event: #orientation. Changed with: an. Int. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 57
My. Abt. Split. Bar. View Example - 2 l Create accessor methods for the various properties (continued) top. Limit. Widget ^top. Limit. Widget: an. Abt. Basic. View top. Limit. Widget : = an. Abt. Basic. View. widget not. Nil if. True: [widget top. Limit. Widget: an. Abt. Basic. View widget]. self signal. Event: #top. Limit. Widget. Changed with: an. Abt. Basic. View. bottom. Limit. Widget ^bottom. Limit. Widget: an. Abt. Basic. View bottom. Limit. Widget : = an. Abt. Basic. View. widget not. Nil if. True: [widget bottom. Limit. Widget: an. Abt. Basic. View widget]. self signal. Event: #bottom. Limit. Widget. Changed with: an. Abt. Basic. View. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 58
My. Abt. Split. Bar. View Example - 3 l Create accessor methods for the various properties (continued) left. Limit. Widget ^left. Limit. Widget: an. Abt. Basic. View left. Limit. Widget : = an. Abt. Basic. View. widget not. Nil if. True: [widget left. Limit. Widget: an. Abt. Basic. View widget]. self signal. Event: #left. Limit. Widget. Changed with: an. Abt. Basic. View. right. Limit. Widget ^right. Limit. Widget: an. Abt. Basic. View right. Limit. Widget : = an. Abt. Basic. View. widget not. Nil if. True: [widget right. Limit. Widget: an. Abt. Basic. View widget]. self signal. Event: #right. Limit. Widget. Changed with: an. Abt. Basic. View. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 59
My. Abt. Split. Bar. View Example - 4 l Create #widget. Creation. Arg. Block method widget. Creation. Arg. Block ^[: w | super widget. Creation. Arg. Block value: w. w orientation: orientation. top. Limit. Widget == nil if. False: [ w top. Limit. Widget: top. Limit. Widget widget]. left. Limit. Widget == nil if. False: [ w left. Limit. Widget: left. Limit. Widget widget]. right. Limit. Widget == nil if. False: [ w right. Limit. Widget: right. Limit. Widget widget ]. bottom. Limit. Widget == nil if. False: [ w bottom. Limit. Widget: bottom. Limit. Widget widget]] l Define edit-time property methods (these provide the values for any attributes with a drop-down selection list) orientation. Valid. Values: a. Part. Property. Data ^Dictionary new at: 'Xm. HORIZONTAL' put: Xm. HORIZONTAL; at: 'Xm. VERTICAL' put: Xm. VERTICAL; yourself Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 60
My. Abt. Split. Bar. View Example - 5 l Define miscellaneous class-side edit methods l Answer the part's name default size in the Composition Editor default. Edit. Size ^200 @ 4 l Answer the part's name to be displayed in the status area of the Composition Editor display. Name ^'Split Bar' l Return the descriptor for the icon representing the class abt. Instance. Graphics. Descriptor ^Abt. Icon. Descriptor new module. Name: self abt. Graphics. Module. Name; id: 317 l Magic methods needed to make the part show up at the right size attachment. Spec. At: point ^self attachment. Spec. From. Rect: (point extent: self default. Edit. Size) position. Spec. At: point ^self position. Spec. From. Rect: (point extent: self default. Edit. Size) Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 61
My. Abt. Split. Bar. View Example - 6 l Example of adding the #top. Limit. Widget property l l Get Selector = “top. Limit. Widget” Set Selector = “top. Limit. Widget: ” Changed event symbol = “top. Limit. Widget. Changed” Attribute data type = “Abt. Basic. View” Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 62
My. Abt. Split. Bar. View Example - 7 l My. Abt. Split. Bar. View in action Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 63
Complex Configuration Management l Hiding Source l Sub. App Configurations l Load/Unload Features -. CTL Files l Version Renaming l Locating Dependent Configs Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 64
Hiding Source l l Why hide source? l Black Box deployment with no “user-serviceable” parts l Hide implementation so that a vendor has more freedom to change the guts later on l Hide security features (e. g. , eval testing / unlocking code) Pitfalls l Once source is hidden and imported into a manager that DOES have source code, that source code may be wiped out such that developers can no longer view the source to their methods l Hiding source for any method that is forced to be recompiled (such as for compile time constants) will break for any VM updates l Hiding source should be used SPARINGLY Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 65
Hiding Source - 2 l Mechanics l l l Date Structure l l Source is hidden on export to DAT files Source is hidden on an export by export basis (controlled by the Configuration Maps Browser’s “Names | Settings | Remove Source” command) What is hidden is stored in an application specific data structure (a Dictionary) that is stored in the library (as an inherited user field) Use the Sub. Application class>>remove. Source. Structure method to retrieve the current settings Use the Sub. Application class>>remove. Source. Structure: method to change the current settings Dictionary of class symbols Values are either l “nil” meaning “hide all the source in the class” l an Association where the – key is either • the collection of instance method symbols that should be hidden • “nil” to hide all instance methods – value is either • the collection of class method symbols that should be hidden • “nil” to hide all class methods Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 66
Hiding Source - 3 l Example Application: Foo. Bar l l Foo. Bar remove. Source. Structure: (Dictionary new at: #Foo put: nil; at: #Boo put: nil; yourself) Class: Foo l Class Methods – class. Method 1 – class. Method 2 l Instance Methods l Class: Bar l Class Methods – class. Method 1 – class. Method 2 l l Hide all class methods in Bar Foo. Bar remove. Source. Structure: (Dictionary new at: #Bar put: (Association key: #() value: nil); yourself) Instance Methods – instance. Method 1 – instance. Method 2 Hide all instance methods in Foo. Bar remove. Source. Structure: (Dictionary new at: #Foo put: (Association key: nil value: #()); yourself) – instance. Method 1 – instance. Method 2 l Hide everything in Foo. Bar l Hide one class and one instance method in Foo. Bar remove. Source. Structure: (Dictionary new at: #Foo put: (Association key: #(#instance. Method 1) value: #(#class. Method 2)); yourself) Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 67
Sub. App Configurations l Why Use? l l Organize functionality Custom Loading l OS-specific l Other conditions Example l Sample config expressions l l l Load always true Window only #('WIN 32 s' 'WIN-NT') includes: (System subsystem. Type: 'CW') OS/2 only #('PM') includes: (System subsystem. Type: 'CW') Only if OLE is loaded Smalltalk includes. Key: #Abt. Base. Ole. App Only if Foo is loaded Smalltalk includes. Key: #Foo l My. App l My. Sub. App 1 l My. Sub. App 2 l My. Sub. App 3 … l My. Sub. App. N Problem l l Combinatorial explosion l 2 subapps = 4 possible configs l 3 subapps = 8 possible configs l 4 subapps = 16 possible configs l Etc. Must be a better way. . . Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 68
Two-Tier Config Expressions l Solution to the combinatorial explosion problem l Rather than l l My. App l My. Sub. App 1 l My. Sub. App 2 l My. Sub. App 3 l In first case, My. App would need up to 8 different complex configs to support loading each subapp independently from its siblings l In the second case, My. App would need only one config (i. e. , “true”) that would load all of its subapps l Each sub app would then have simple configs that only controlled the loading of its single subapp l This technique can also be used at the config map and application level to solve the problem of context-sensitive prereqs Use l My. App l My. Sub. App 1 Stub – My. Sub. App 1 l My. Sub. App 2 Stub – My. Sub. App 2 l My. Sub. App 3 Stub – My. Sub. App 3 Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 69
Two-Tier Config Expressions Example l Two-Tier Configs can be used by third-parties to avoid loading collisions l Example l l The ubiquitous Object>>as. String method l Not part of the Visual. Age base l Supplied by several third parties l Common source of conflicts Solution: Two-Tier Configs l My. App l My. Object_as. String. Stub – My. Object_as. String. App l Configuration Expression (Object responds. To: #as. String) not or: [(Object>>#as. String) application name == #My. App] Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 70
Expression Indicator l Here’s a handy mod which will make it easy for you to tell when a config expression is currently true or not l First, implement the following method in Et. Window: expression. Indicator. Block ^[: exp | ([Compiler evaluate: exp] when: Ex. Error do: [: sig | sig exit. With: nil]) == true if. True: [Et. Tools loaded. Indicator] if. False: [Et. Tools blank. Loaded. Indicator]] l Second, modify any #expressions. List. Widget method to set the #status. Block: parameter to “self expression. Indicator. Block”. Here are two: l Et. Application. Editions. Browser>> expressions. List. Widget l Et. Configuration. Maps. Browser>> expressions. List. Widget Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 71
Load/Unload Features -. CTL Files l Here’s the Load/Unload Features Dialog: Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 72
Load/Unload Features How Does a Feature Appear? l Each feature has a corresponding. CTL file in the FEATURE subdirectory l The CTL file encodes l l l The name of the feature An expression that determines whether the feature is relevant Any dependent CTL files Each configuration map and version that should be loaded The CTL file name encodes which list the feature appears l l l Visual. Age Section: fourth letter must be “T” (e. g. , ABTTSM 40. CTL) IBM Smalltalk Section: fourth letter must be “E” (e. g. , ABTEDD 40. CTL) Other Section: use any name you like Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 73
Load/Unload Features CTL File Structure l Feature Identification l l Prerequisite Loading l l Text up to first double quote identifies the feature name The #product. Id parameter identifies whether a product is for evaluation or production (use “sdcs 00001267” to track the status of the base product) The #platforms parameter encodes the platforms that the feature may be loaded on (use “any” to allow loading on any platform) One or more “include” statements that load other CTL files Feature Loading l l l Multiple lines for each config map to load First string is the config map name Second string is the time stamp of the specific config edition to load Third string is the file name of the DAT file containing the config Last string is a comment describing the config Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 74
Load/Unload Features Example l Line 1: l l Line 2 & 3: l l The name of the feature is “SOMsupport, Base” The product is Visual. Age 4. 5 (product ID = ‘sdcs 00001267’) The product may be loaded on Win 95, Win. NT, OS/2 or Unix Specifies two imports/includes Line 4 & 5: l l The name of the configurations are “Abt. SOMsupport Run” & “Abt. SOMsupport Edit” The time stamp on the specific edition of the configs is “ 3069315125” The config can be found in the file “ABTTSM 40. DAT” The config comments are “Abt. SOMsupport Run V 4. 5” & “Abt. SOMsupport Edit V 4. 5” Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 75
Version Renaming l Why rename versions? l l Consistency Baselining apps and classes for delivery Correcting naming mistakes Why isn’t this dangerous? l l l The ENVY library only cares about time stamps APIs exist to change version names after they have been set These APIs have remained consistent for many years IBM/OTI uses this technique to baseline Visual. Age releases All version sorting is done by timestamp. Version names are cosmetic only Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 76
Version Renaming - Applications l Pick a version name and select the applications to modify l Iterate over the application list l For each application, compare its version name to the new desired name (no point in changing the name if it isn’t necessary) l For each application that needs changing, update the edition record | version. Name applications | version. Name : = <New Version Name>. applications : = Array with: <App 1> with: <App 2>. applications do: [: application | application time. Stamp version. Name = version. Name if. False: [ application update. Edition: [: edition. Record | edition. Record set. Version. Name: version. Name; insert]]]. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 77
Version Renaming - Classes l Pick a version name, an application and a set of classes to modify l Iterate over the class list l For each class, compare its version name to the new desired name l For each class that needs changing, update the edition record | version. Name application classes | version. Name : = <New Version Name>. application : = <Application>. classes : = Array with: <Class 1> with: <Class 2>. classes do: [: class | time. Stamp : = class time. Stamp. In: application. time. Stamp version. Name = version. Name if. False: [ time. Stamp version. Name : version. Name. class update. In: application with: [: editions. Record | | entry old. Length | entry : = editions. Record current. Entry. old. Length : = entry version. Name size. entry replace. Element : 2 with: version. Name; length: entry length - old. Length + version. Name size; yourself]]]. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 78
Version Renaming - Config Maps l Pick a version name and select the configuration map to modify l Find the most recent edition of the config map l Update the edition record of the config map edition with the new version name | version. Name config. Map. Edition | version. Name : = <New Version Name>. config. Map. Name : = <Config Map Name>. config. Map. Edition : = (Em. Configuration. Map editions. For: config. Map. Name) first. config. Map. Edition relocate. Record. With: [: edition. Record | edition. Record replace. Element: 2 with: version. Name; insert]. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 79
Locating Dependent Configs For an (Sub)Application l Get the name of the root application l Scan through all Config Map names in the system l For each configuration, find the first (most recent edition) l Check to see whether its application names include the target | app. Name dependent. Configs | app. Name : = <Application> root. Application name as. String. dependent. Configs : = Em. Configuration. Map configuration. Map. Names select: [: map. Name | | editions : = Em. Configuration. Map editions. For: map. Name. editions first application. Names includes: app. Name]. ^dependent. Configs Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 80
Locating Dependent Configs For a Config Map (Direct) l Specify the name of the configuration map l Scan through all Config Map names in the system l For each configuration, find the first (most recent edition) l Check to see whether its required maps names include the target | config. Name dependent. Configs | config. Name : = <Configuration Map Name>. dependent. Configs : = Em. Configuration. Map configuration. Map. Names select: [: map. Name | | map : = (Em. Configuration. Map editions. For: map. Name) first. (map all. Possible. Required. Maps detect: [: mp | mp name = config. Name] if. None: []) not. Nil]. ^dependent. Configs Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 81
Locating Dependent Configs For a Config Map (Indirect) l Collect the names of all of the application names contained by the map l Scan through all Config Map names in the system l For each configuration, find the first (most recent edition) l Check to see whether its application names include the all of the application names in the target | config. Name application. Names dependent. Configs | config. Name : = <Configuration Map Name>. application. Names : = (Em. Configuration. Map editions. For: config. Name) first application. Names. dependent. Configs : = Em. Configuration. Map configuration. Map. Names select: [: map. Name | | editions names | map. Name ~= config. Name and: [ editions : = Em. Configuration. Map editions. For: map. Name. names : = editions first application. Names conform: [: app | names includes: app]]]. ^dependent. Configs Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 82
Development Tool (Browser) Enhancements l Extension API l Subclassing Text. Selection. Manager l Hooking Key. Press in Text Widgets l Enhanced Text Menu Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 83
Extension API l What is it? l l Create by Joseph Pelrine Public domain Easy way for multiple vendors (and users) to extend the Visual. Age browsers without collision How does it work? l Overrides the normal #classes. Menu (and other menu creation methods) with code that (essentially) looks like this: classes. Menu | a. Menu : = super classes. Menu. Sub. Application currently. Loaded reverse. Do: [: app | app add. To. Classes. Menu: a. Menu browser: self]. ^a. Menu l l Adds a #add. To. Classes. Menu: browser: method (and siblings) to Sub. Application that does nothing l First argument is the menu being added to l Second argument is the current browser (a source of valuable state information) Other applications override these methods to add in their own menu commands Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 84
Example - Adding All Instances l Create an application called My. Application l Add the following class method to the My. Application class: add. To. Classes. Menu: a. Menu browser: a. Browser ^a. Menu add. Line; add: #all. Selected. Class. Instances label: 'All ~Instances' enable: [a. Browser is. One. Class. Selected]; yourself l Add the following method to the Et. Code. Window class: all. Selected. Class. Instances self selected. Class all. Instances inspect l All of the Classes menus in all of the browsers should now have an “All Instances” method which will automatically enable/disable whenever a class is selected or not Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 85
Using Progress Dialogs l Visual. Age has a nice progress dialog facility you can use for managing long running, interruptible tasks l Use the Et. Window>> exec. Long. Operation: message: allow. Cancel: show. Progress: method l l l First parameter is a one-argument block of code that will be forked to a background process. The block argument is the dialog itself The “message” parameter is the text displayed in the dialog The “allow. Cancel” parameter determines whether a Cancel button is available The “show. Progress” parameter determines whether a progress bar is displayed Several messages can be sent to the block argument (dialog) above l l l #fraction. Complete: - set the value shown on the progress bar (a fraction between 0 and 100) #message. String: - sets the message string in the dialog #cancelled - answers a boolean specifying whether the Cancel button was clicked Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 86
Example - Finding Strings l Modify our #add. To. Classes. Menu: browser: method like this: add. To. Classes. Menu: a. Menu browser: a. Browser ^a. Menu add. Line; add: #all. Selected. Class. Instances label: 'All ~Instances' enable: [a. Browser is. One. Class. Selected]; add: #find. String. In. Class label: 'Find String In Class' enable: [a. Browser is. One. Class. Selected]; yourself Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 87
Example - Finding Strings - 2 l Add the following method to the Et. Code. Window class: find. String. In. Class | a. String found | a. String : = System prompt: 'Methods including string? '. (a. String is. Nil or: [a. String is. Empty]) if. True: [^self]. self exec. Long. Operation: [: dialog | found : = self find. String : a. String in. Class: self selected. Class dialog: dialog] message: 'Gathering methods. . . ' allow. Cancel: true show. Progress: true. found is. Empty if. True: [System message: 'None found. '] if. False: [ ((Et. Tools browser: #highlighting. Methods) on: (found as. Set as. Sorted. Collection : Compiled. Method sort. Block) labeled: ('Methods in %1 including %2' bind. With : self selected. Class with: a. String print. String) highlighting: a. String) owning. Image : System image; open] Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 88
Example - Finding Strings - 3 l Also add this method to the Et. Code. Window class: find. String: a. String in. Class: a. Class dialog: dialog | methods size found cancelled | methods : = Ordered. Collection new. a. Class method. Dictionary do: [: method | methods add: method]. a. Class class method. Dictionary do: [: method | methods add: method]. size : = methods size. dialog fraction. Complete: 0. dialog message. String: 'Found: 0'. found : = Ordered. Collection new. cancelled : = false. methods do. With. Index: [: method : index | | source | (cancelled : = cancelled or: [dialog cancelled]) if. False: [ source : = method record source. (source not. Nil and: [ (source index. Of. Sub. Collection : a. String starting. At : 1 if. Absent: [0]) > 0]) if. True : [ found add: method. dialog message. String: 'Found: ', found size print. String]. dialog fraction. Complete: index / size]]. ^found Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 89
Enhancing the Text Selection Manager l What is the Text Selection Manager? l l l What can we do to enhance it? l l l Handles double-click word select Handles finding matching parens and brackets Add double-click line select Watch for special key strokes to insert text or expand abbreviations How do we start? l l Subclass Cw. Smalltalk. Text. Selection. Manager with My. Text. Selection. Manager Override the #new method so that we get our version instead: new ^My. Text. Selection. Manager basic. New l Override the #double. Click method like this: Very Sneaky double. Click super double. Click if. True: [^true]. self select. Line if. True: [^true]. ^false Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 90
Enhancing the Text Selection Manager - 2 l Override the #select. Word method like this: select. Word | left. Pos right. Pos | left. Pos : = self find. Separator. Left. right. Pos : = self find. Separator. Right. left. Pos == right. Pos if. True: [^false]. Cw. App. Context default async. Exec. In. UI: [ self owner set. Selection: left. Pos @ right. Pos]. ^true l Implement the #select. Line method like this: select. Line | left. Pos right. Pos | left. Pos : = self find. Line. End. Left. right. Pos : = self find. Line. End. Right. Cw. App. Context default async. Exec. In. UI: [ self owner set. Selection: left. Pos @ right. Pos]. ^true Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 91
Enhancing the Text Selection Manager - 3 l Implement the #find. Line. End. Left method like this: find. Line. End. Left | find. Stream line. Delimiter position start | find. Stream : = self content. Stream. line. Delimiter : = find. Stream line. Delimiter. (position : = self cursor. Pos) == 0 if. True: [^0]. [position > 0 and: [start is. Nil]] while. True: [ position : = position - 1. find. Stream position: position. (line. Delimiter includes: find. Stream peek) if. True: [start : = position + 1]]. position : = start. [find. Stream at. End] while. False: [ find. Stream next is. Separator if. False: [^find. Stream position - 1]]. ^self owner. Size Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 92
Enhancing the Text Selection Manager - 4 l Implement the #find. Line. End. Right method like this: find. Line. End. Right | find. Stream line. Delimiter position | (find. Stream : = self content. Stream) position: self cursor. Pos. line. Delimiter : = find. Stream line. Delimiter. [find. Stream at. End not and: [position is. Nil]] while. True: [ (line. Delimiter includes: find. Stream next) if. True: [position : = find. Stream position - 1]]. position is. Nil if. True: [^self owner. Size]. [position = 0] while. False: [ position : = position - 1. find. Stream position: position. find. Stream peek is. Separator if. False: [^position + 1]]. ^0 Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 93
Hooking Key. Press in Browser Text Widgets l What else can we do with our new Text Selection Manager? l l Watch for special key strokes Examples l VW goodies - Ctrl+g/f/t l Inserting parens, brackets, etc. l Expanding Abbreviations l Let’s start with the first one: “VW Goodies” l How do we do it? l Override the Cw. Text. Manager class>>for: method for: a. Cw. Text | manager : = super for: a. Cw. Text add. Event. Handler: Key. Press. Mask receiver: self selector: #key. Press: client. Data: call. Data: client. Data: manager. ^manager Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 94
VW Goodies - Ctrl+G/F/T l Visual. Works implements several keyboard macros l l Ctrl+G inserts “: =” Ctrl+T inserts “if. True: ” Ctrl+F inserts “if. False: ” Implement the My. Text. Selection. Manager>> insert. String: method insert. String: a. String | pos : = self owner get. Insertion. Position. self owner set. Input. Focus; replace: pos to. Pos: pos + 1 value: a. String Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 95
VW Goodies - Ctrl+G/F/T - 2 l Implement the My. Text. Selection. Manager>> key. Press: client. Data: call. Data: method key. Press: text. Widget client. Data: client. Data call. Data: call. Data | ctrl shift | ctrl : = call. Data state any. Mask: Control. Mask. shift : = call. Data state any. Mask: Shift. Mask. ctrl & shift if. True: [ call. Data keysym == XKT if. True: [self insert. String: 'if. True: [']. call. Data keysym == XKF if. True: [self insert. String: 'if. False: [']. call. Data keysym == XKG if. True: [self insert. String: ': = ']]. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 96
Inserting Matching Parens l Implement the My. Text. Selection. Manager>> parenthesize. Selected. Text method parenthesize. Selected. Text | selection. Position | (selection. Position : = self owner get. Selection. Position) = (0@0) if. True: [^self]. self owner replace: selection. Position x to. Pos: selection. Position y value: '(', self owner get. Selection, ')'; set. Selection: selection. Position x @ (selection. Position y + 2); set. Input. Focus Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 97
Inserting Matching Parens - 2 l Modify the My. Text. Selection. Manager>> key. Press: client. Data: call. Data: method key. Press: text. Widget client. Data: client. Data call. Data: call. Data | ctrl shift | ctrl : = call. Data state any. Mask: Control. Mask. shift : = call. Data state any. Mask: Shift. Mask. ctrl & shift if. True: [ call. Data keysym == XKT if. True: [self insert. String: 'if. True: [']. call. Data keysym == XKF if. True: [self insert. String: 'if. False: [']. call. Data keysym == XKG if. True: [self insert. String: ': =']]. ctrl if. True: [ (call. Data keysym == XKparenleft or: [call. Data keysym == XK 9]) if. True: [^self parenthesize. Selected. Text]]. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 98
Expanding Abbreviations l Implement the My. Text. Selection. Manager>>insert. Abbreviation method insert. Abbreviation | pos start abbrev expansion | pos : = self owner get. Insertion. Position - 1. start : = self find. Separator. Left. Starting. At: pos. abbrev : = self owner value copy. From: start + 1 to: pos. expansion : = self class abbreviations at: abbrev if. Absent: [^nil]. self owner set. Input. Focus; replace: start to. Pos: pos + 1 value: expansion l Implement the #find. Separator. Left. Starting. At: method find. Separator. Left. Starting. At: an. Integer | find. Stream position | find. Stream : = Read. Stream on: self owner value. position : = an. Integer. [position = 0] while. False: [ position : = position - 1. find. Stream position: position. find. Stream peek is. Alpha. Numeric if. False: [^position + 1]]. ^0 Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 99
Expanding Abbreviations - 2 l Implement the My. Text. Selection. Manager class>>abbreviations method abbreviations ^Dictionary new at: ‘int’ put: ‘is. Nil if. True: []’; at: ‘inf’ put: ‘is. Nil if. False: []’; . . . yourself l Modify the My. Text. Selection. Manager>> key. Press: client. Data: call. Data: method key. Press: text. Widget client. Data: client. Data call. Data: call. Data | ctrl shift | ctrl : = call. Data state any. Mask: Control. Mask. shift : = call. Data state any. Mask: Shift. Mask. ctrl & shift if. True: [. . . ]. ctrl if. True: [. . . ]. shift if. True: [ call. Data character == Cldt. Constants: : Space if. True: [^self insert. Abbreviation]]. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 100
The Joy of Parse Trees l Visual. Age has a very powerful built in parser l What is a parse tree? l l l A top down, hierarchical representation of a method Ammo for countless browser hacks! What can you use it for? l l Color syntax highlighting Senders and Implementors Spell Checking Limited static analysis Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 101
Parse Tree Example l Example Method foo self do. Something. ^self foo: self bar: foo. l Parse Tree Es. Method “foo” statements: Es. Statement “self do. Something” Es. Message. Expression receiver: Es. Variable. With. Binding “self” message. Pattern : Es. Unary. Pattern “do. Something” Es. Statement “self foo: self bar: foo” Es. Message. Expression receiver: Es. Variable. With. Binding “self” message. Pattern : Es. Keyword. Pattern “foo: self bar: foo” selector: #(# foo: #bar: ) arguments: Es. Message. Expression “self bar” receiver: Es. Variable. With. Binding “self” message. Pattern : Es. Unary. Pattern “bar” Es. Variable. With. Binding “foo”. Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 102
Creating a Parse Tree l The Es. Compiler>>parse: for. Evaluation: environment: error. Handler: method answers an Es. Complilation. Result that holds onto a parse tree l The “for. Evaluation” parameter should be false for a method and true for a Do. It. l The “environment” parameter provides a default namespace that the compiler can use to resolve the variables l The “error. Handler” parameter is set to an Es. Silent. Error. Handler (we don’t care about errors) parse. Tree. For: a. String ^(Compiler parse: a. String for. Evaluation: false environment: (Es. Name. Environment new environment: Smalltalk; source. Class: Object) error. Handler: Es. Silent. Error. Handler new) parse. Tree Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 103
Find the Selector at the Cursor l Get the index of the cursor in the browser text widget l Generate the parse tree for the text in the browser l Loop through all of the parse tree nodes looking for the node containing the cursor index l Answer the selector held by the parse node or nil if the parse node does not represent a selector (e. g. , a global, a literal, self, super, etc. ) Et. Window>>selector. At. Cursor | text. Widget index parse. Tree | index : = (text. Widget : = self target. Text. Widget) cursor. Position. (parse. Tree : = self parse. Tree. For: text. Widget get. String) not. Nil if. True: [| target. Node | parse. Tree all. Nodes. Do : [: node | (node source. Start - 1 <= index and: [node source. End > index]) if. True : [target. Node : = node]]. (target. Node not. Nil and: [target. Node selector not. Nil]) if. True: [^target. Node selector]]. ^nil Es. Parse. Node>>selector ^nil Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 104
Sender & Implementors l Senders l l Find the selector at the cursor Ask the system for all senders of that method Et. Window>>senders | symbol | (symbol : = self selector. At. Cursor) is. Nil if. False: [ self owning. Image all. Methods. Sending: symbol] l Implementors l l Find the selector at the cursor Ask the system for all methods by that name Et. Window>>implementors | symbol | (symbol : = self selector. At. Cursor) is. Nil if. False: [ self owning. Image all. Methods. Named: symbol] Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 105
Enhancing the Popup Text Menu l Use the Extension API to enhance the Et. Window>>default. Text. Menu method l Add the following class method to the My. Application class to add new “Senders” and “Implementors” items add. To. Default. Text. Menu: a. Menu browser: a. Browser ^a. Menu add: #senders label: 'Senders' enable: true after: #menu. Edit. File. In; add: #implementors label: 'Implementors' enable: true after: #senders; add. Line. After: #implementors; yourself Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 106
Other Visual. Age & ENVY (& Related) Sessions l M 2 - Web Application Solutions Using Smalltalk - Lawrence Smith l M 5 - Visual. Age Smalltalk Server Tips for Success - Dan Lesage l M 8 - JWARS - Donald Mac. Queen l W 5 - ENVY 101 - Jan Steinman l Th 1 - Refactory Techniques and Tools - Don Roberts & John Bryant l Th 2 - Secrets of Visual Programming - Joe Winchester l Th 3 - Building Web Applications - John Lord l N 2 - Advanced ENVY Systems Programming - Joseph Pelrine & Alan Knight l N 4 - Testing Smalltalk Applications - Michael Silverstein …and don’t forget: W 12 - GO SMALLTALK! Smalltalk Advocacy in the Shadow of Java Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 107
Visual. Age Resources l IBM l l l l Smalltalk Home Page http: //www. software. ibm. com/ad/smalltalk/ Support Page http: //www. software. ibm. com/ad/smalltalk/support/ Tips page http: //www. software. ibm. com/ad/smalltalk/support/tips 45. html Add-on products http: //www. software. ibm. com/ad/visage/rc/rcst 5. html Newsgroup news: //news. software. ibm. com/ibm. software. vasmalltalk FTP patches ftp: //ps. boulder. ibm. com/ps/products/visualage/fixes/ General l l Smalltalk Language Newsgroup comp. lang. smalltalk Smalltalk Industry Council http: //www. stic. org Smalltalk Systems Web Site http: //www. smalltalksystems. com Me ; -) mailto: clayberg@smalltalksystems. com Eric Clayberg - Instantiations, Inc. , Smalltalk Systems Division March 14, 1999 S 2 - 108
- Slides: 108