Implement the remaining methods by, essentially, repeating steps 7 and 8 for each of the methods. That is: mark the code displayed in the description pane; delete it; replace it with a new method; and then save the new method.
The remaining methods are shown below. You can implement them in any order.
Method rectangle
rectangle "Private - Answers the current rectangle" ^rectangle
Method rectangle:
rectangle: aRectangle "Private - Sets the current rectangle" rectangle := aRectangle
Method initialize
initialize "Private - Sets intial values for some of the variable." gc := CgWindow default createGC: None values: nil. gc setFunction: GXhighlight. captureMode := #none.
Method createWindow
createWindow "Private - Creates the interface. The outside window is 'shell.' The form that manages layout of widgets is 'widgetManager.' The options are on the top. The buttons 'Capture' and 'Help' are on the bottom. The button 'Display Image' can be added, and CgImageViewer used to view the grabbed file." self createTopLevelShell. self createFrame. self createRadioRowColumn. self createRadioButton: ' Entire screen with this window ' clientData: #fullScreen. self createRadioButton: 'Entire screen without this window ' clientData: #fullScreenWithout. self createRadioButton: 'Partial screen with delay' clientData: #partialWithDelay. self createRadioButton: 'Partial screen without delay' clientData: #partial. self createCountLabel. self createText. self createButtonsRowColumn. self createCaptureButton. self createHelpButton. countDown := text. self initialize.
Method createTopLevelShell
createTopLevelShell "Private - Creates a window." shell := CwTopLevelShell createApplicationShell: 'shell' argBlock: [:w | w title: 'Screen Capture']. "This is to ensure that the CgGraphicsContext (gc) is freed when the window is closed." shell addCallback: XmNdestroyCallback receiver: self selector: #destroy:clientData:callData: clientData: nil.
Method createShell
createShell "Private - Creates a shell for aWidget." shell := CwTopLevelShell appCreateShell: self class name applicationClass: CwAppContext defaultApplicationClass display: CgDisplay default argBlock: nil.
Method createFrame
createFrame "Private - Creates the frame and a manager for widgets." widgetMan := shell createForm: 'widgetManager' argBlock: nil. widgetMan manageChild. frame := widgetMan createFrame: 'frame' argBlock: [:w | w topAttachment: XmATTACHFORM; topOffset: 2; leftAttachment: XmATTACHFORM; leftOffset: 5; rightAttachment: XmATTACHFORM; rightOffset: 5]. frame manageChild.
Method createRadioRowColumn
createRadioRowColumn "Private - Creates a row column to hold buttons." radio := frame createRowColumn: 'radio' argBlock: [:w | w radioBehavior: true]. radio manageChild.
Method createRadioButton:clientData:
createRadioButton: aString clientData: data "Private - Creates a radio button." | r | r := radio createToggleButton: aString argBlock: nil. r addCallback: XmNarmCallback receiver: self selector: #mode:clientData:callData: clientData: data. r manageChild. ^r
Method createCountLabel
createCountLabel "Private - Creates a label." countLabel := widgetMan createLabel: 'countLabel' argBlock: [:w| w labelString: 'Countdown : '; leftAttachment: XmATTACHPOSITION; leftPosition: 25; topAttachment: XmATTACHWIDGET; topWidget: frame; topOffset: 10]. countLabel manageChild.
Method createText
createText "Private - Creates a text field." text := widgetMan createText: 'text' argBlock: [:w | w topAttachment: XmATTACHWIDGET; topWidget: frame; leftAttachment: XmATTACHWIDGET; leftWidget: countLabel; topOffset: 10; columns: 2]. text setString: '5'. text manageChild.
Method createButtonsRowColumn
createButtonsRowColumn "Private - Creates a row column to hold buttons." buttons := widgetMan createRowColumn: 'buttons' argBlock: [:w | w orientation: XmVERTICAL; packing: XmPACKCOLUMN; numColumns: 2; topOffset: 10; leftOffset: 5; bottomOffset: 5; rightOffset: 5; topAttachment: XmATTACHWIDGET; topWidget: countLabel; leftAttachment: XmATTACHFORM; bottomAttachment: XmATTACHFORM]. buttons manageChild.
Method createCaptureButton
createCaptureButton "Private - Creates a button." | captureButton | captureButton := buttons createPushButton: 'capture' argBlock: [:w | w labelString: ' Capture ']. captureButton addCallback: XmNactivateCallback receiver: self selector: #captureCallback:clientData:callData: clientData: widgetMan. captureButton manageChild.
Method createHelpButton
createHelpButton "Private - Creates a button." | helpButton | helpButton := buttons createPushButton: 'help' argBlock: [:w | w labelString: ' Help '; marginTop: 3; marginBottom: 3]. helpButton addCallback: XmNactivateCallback receiver: self selector: #help:clientData:callData: clientData: nil. helpButton manageChild.
Method realizeWindow
realizeWindow "Private - Realizes the receiver's widget hierarchy." shell realizeWidget.
Method buttonPress:clientData:event:
buttonPress: aWidget clientData: widgetManager event: event "Private - The user has started to draw a rectangle." | point | point := widgetManager translateCoords: (event point). self rectangle: (Rectangle origin: (point x) @ (point y) extent: 0 @ 0 ). widgetManager removeEventHandler: ButtonPressMask receiver: self selector: #buttonPress:clientData:event: clientData: widgetManager.
Method buttonRelease:clientData:event:
buttonRelease: aWidget clientData: widgetManager event: event "Private - The user has finished drawing a rectangle." | point xE yE | point := widgetManager translateCoords: (event point). xE := (point x) - (self rectangle origin x). yE := (point y) - (self rectangle origin y). self rectangle extent: xE @ yE. widgetManager ungrabPointer. widgetManager removeEventHandler: ButtonReleaseMask receiver: self selector: #buttonRelease:clientData:event: clientData: widgetManager. self adjustRectangle. captureMode = #partial ifTrue: [ self eraseCurrentRectangle. self saveGraphicImage] ifFalse: [self delayAndGrab]
Method captureCallback:clientData:callData:
captureCallback: aWidget clientData: widgetManager callData: callData "Private - The Capture button has been pressed. Processes the capture according to the capture mode." captureMode = #fullScreen ifTrue: [ self setFullRectangle. ^self saveGraphicImage]. captureMode = #fullScreenWithout ifTrue: [ widgetManager shell unmapWidget. widgetManager updateDisplay. self setFullRectangle. self saveGraphicImage. ^widgetManager shell mapWidget]. captureMode = #none ifFalse: [ self getPartialFrom: widgetManager]
Method destroy:clientData:callData:
destroy: data1 clientData: data2 callData: data3 "Private - Frees the graphics context." gc == nil ifFalse: [gc freeGC]
Method help:clientData:callData:
help: aWidget clientData: clientData callData: callData "Private - Displays the help message." System message: 'Select the capture mode, then press capture to start. To draw a partial screen rectangle, point to any corner of the rectangle that you wish to capture. Press mouse button one and drag the rectangle to the correct size. Release the mouse button to capture. The delay option gives you a chance to arrange the windows AFTER you draw the rectangle, but BEFORE the image capture. You can capture window menus this way. You may also hide the capture window during the delay. You can change the delay from 0 to 9 seconds.'
Method mode:clientData:callData:
mode: aButton clientData: clientData callData: callData "Private - A capture mode has been selected." captureMode := clientData
Method pointerMotion:clientData:event:
pointerMotion: aWidget clientData: widgetManager event: event "Private - Erases the old rectangle and replaces it with the new rectangle." | point xE yE | point := widgetManager translateCoords: (event point). state = #initial ifFalse: [self eraseCurrentRectangle]. xE := (point x) - (self rectangle origin x). yE := (point y) - (self rectangle origin y). self rectangle extent: xE @ yE. CgWindow default drawRectangle: gc x: (self rectangle origin x) y: (self rectangle origin y) width: xE height: yE. state := #drawing.
Method adjustRectangle
adjustRectangle "Private - Makes sure that the rectangle has positive width and height." | xMin yMin | xMin := self rectangle origin x. yMin := self rectangle origin y. self rectangle width < 0 ifTrue: [ xMin := self rectangle origin x + self rectangle width]. self rectangle height < 0 ifTrue: [ yMin := self rectangle origin y + self rectangle height]. self rectangle: (xMin @ yMin extent: (self rectangle width abs) @ (self rectangle height abs)). self rectangle width < 1 ifTrue: [self rectangle width: 1]. self rectangle height < 1 ifTrue: [self rectangle height: 1].
Method delayAndGrab
delayAndGrab "Private - Captures the rectangle after seven seconds. Forks this process so the user can adjust the windows during the countdown." | delay | delay := countDown value first digitValue. delay = -1 ifTrue: [delay := 7]. [ delay to: 0 by: -1 do: [:count | (Delay forSeconds: 1) wait. countDown setString: count printString ]. self eraseCurrentRectangle. self saveGraphicImage. countDown setString: delay printString. ] forkAt: Processor timingPriority
Method eraseCurrentRectangle
eraseCurrentRectangle "Private - Erases the capture rectangle. Since the GCFunction was set to highlight, a re-draw will erase it." CgWindow default drawRectangle: gc x: self rectangle origin x y: self rectangle origin y width: self rectangle width height: self rectangle height
Method getPartialFrom:
getPartialFrom: widgetManager "Private - Sets up the event handlers for a partial screen grab. Also grabs the pointer." state := #initial. widgetManager addEventHandler: ButtonPressMask receiver: self selector: #buttonPress:clientData:event: clientData: widgetManager. widgetManager addEventHandler: ButtonReleaseMask receiver: self selector: #buttonRelease:clientData:event: clientData: widgetManager. widgetManager addEventHandler: Button1MotionMask receiver: self selector: #pointerMotion:clientData:event: clientData: widgetManager. widgetManager grabPointer: (widgetManager display createFontCursor: XCCrosshair).
Method promptForFileName
promptForFileName "Private - Prompts the user to name the target BMP file." ^CwFileSelectionPrompter new title: 'Graphic image filename: '; prompt
Method saveGraphicImage
saveGraphicImage "Private - Captures the image in the current rectangle and unloads the image into the file named by the user." | image file name fileFormat success | image := (CgScreen default) rootWindow getDeviceIndependentImage: self rectangle. (name := self promptForFileName) == nil ifTrue: [ ^self ].
"The following statement uses a class that defines a Windows-specific file format, CgWinBMPFileFormat. For an OS/2 file format, use in the following statement the class CgPMBMPFileFormat. The system offers TIFF, GIFF, IPEG, and ICO file formats as well. You can use whatever file format your graphics tools support, and capture screens in any format on any platform." fileFormat := CgWinBMPFileFormat new. (file := CfsFileDescriptor open: name oflag: OCREAT | OTRUNC | OWRONLY) isCfsError ifTrue: [ ^(CwMessagePrompter new iconType: XmICONERROR; buttonType: XmOK; messageString: file message; prompt)].
success := fileFormat unload: image intoFileHandle: file atOffset: 0. file close. success ifFalse: [ ^(CwMessagePrompter new iconType: XmICONERROR; buttonType: XmOK; messageString: 'Error saving graphic image'; prompt)] ifTrue: [ CwMessagePrompter new messageString: 'Graphic image saved'; buttonType: XmOK; prompt ]
Method setFullRectangle
setFullRectangle "Private - Sets rectangle for a full screen grab." self rectangle: ( 0@0 corner: (CgScreen default width) @ (CgScreen default height))