Implementing the private instance methods
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.
Private methods for category Getters & Setters
Method rectangle
rectangle
"Private - Answers the current rectangle"
^rectangle
Method rectangle:
rectangle: aRectangle
"Private - Sets the current rectangle"
rectangle := aRectangle
Private methods for category Initialization
Method initialize
initialize
"Private - Sets intial values for some of the variable."
gc := CgWindow default
createGC: None
values: nil.
gc setFunction: GXhighlight.
captureMode := #none.
Private methods for category Window Creation
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.
Private methods for category Event Handlers
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.
Private methods for category Image Operations
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))
Last modified date: 03/13/2019