Text with Style
Volume Number: | | 4
|
Issue Number: | | 5
|
Column Tag: | | Forth Forum
|
Formatted Text with Style
By Jörg Langowski, MacTutor Editorial Board
TextEdit with Style(s)
TextEdit has always been one of the major conveniences of the Macintosh. Life (as far as programming is concerned) is so much simpler with a standard editing package that takes care of line break, word wrap, text insertion, justification etc. for you, instead of having to write it yourself.
One major reason why TextEdit was inadequate for e.g. word processing had always been that the text style was fixed for one text edit record, i.e. for one piece of edited text. Changing fonts, boldfacing, or changing the size of only one word or one phrase in the text was not possible.
The new implementation of TextEdit that is described in IM Vol.V finally introduces this possibility. TextEdit now recognizes two types of TE records: the old one, having the same text style all over the text, and a new format where style information is associated and displayed with the text. Although contained in IM V, the new TextEdit traps are available (System 4.2 and later) on the Mac Plus as well as on the SE and MacII.
A second inconvenience has been resolved: When working on new type TE records, TECopy and TEPaste now uses the desk scrap (i.e. the general clipboard) for cutting/pasting directly. It is no more necessary to convert between the internal TE scrap and the desk scrap on activate/deactivate events. For old TE records, TECopy and TEPaste still only use the internal scrap (for compatibility).
The new text edit is not yet used very widely, but it is worth it. Therefore I thought it might be a good idea to show its function on a practical example in Mach2 Forth. It is based on the skeleton editor on the Mach2 demo disk, but contains a lot of enhancements, such as horizontal scrolling and scroll thumbs that work, and of course the text style support.
The new TE record
How does the system distinguish between the new and the old type TE record?
Mostly, the structure of the new record is the same as the old one, with a couple of exceptions: The txSize field of a new TE record contains -1 (word, offset $50 from beginning of record). In that case, the fields txFont and txFace (offset $4A and $4C) are combined to hold the handle of what is called a style record, a structure that contains the style information associated with the text. Of course, the information previously contained in the txFont, txFace and txSize fields - font, text face, and font size - is not meaningful anymore, since it may change over the length of the text.
Furthermore, the fields lineHeight and fontAscent (offset $18 and $1A) may now also contain -1, in which case the line height and ascent will be calculated individually for each line; if they contain positive numbers, the TErecord has fixed line height and ascent as before.
The style record
This structure contains the style information that belongs to the TErecord. Its layout is give in IM V-261 and Ill repeat it here (Pascal style):
TYPE
TEStyleHandle = ^TEStylePtr;
TEStylePtr = ^TEStyleRec;
TEStyleRec = RECORD
nRuns: INTEGER;
nStyles: INTEGER;
styleTab:STHandle;
lhTab: LHHandle;
teRefCon:LONGINT;
nullStyle: nullSTHandle;
runs: ARRAY [0..0] OF StyleRun
END;
StyleRun = RECORD
startChar: INTEGER;
styleIndex:INTEGER
END;
The text is characterized by a succession of style runs, characters of the same style in the TE record. The system knows where they start (startChar) and the index styleIndex of the corresponding style in a style table. Each style record contains information about how many style runs and how many different styles there are in the text (nruns, nStyles), and handles to the style and line height tables (styleTab, lhTab). teRefCon can be used freely by the application, and nullStyle contains a handle to the style table that is used when the selection is empty.
The style table contains an entry for each different style encountered in the text:
TYPE
STHandle = ^STPtr;
StPtr = ^TEStyleTable;
TEStyleTable = ARRAY [0..0] OF STElement;
STElement = RECORD
stCount: INTEGER;
stHeight:INTEGER;
stAscent:INTEGER;
stFont:INTEGER;
stFace:Style;
stSize:INTEGER;
stColor: RGBColor;
END;
stCount indicates how often this style occurs in the text; the remaining fields indicate the text style.
Since the line height now may differ from line to line, there is another table, the line-height table, which contains an entry for each line in the lineStarts array of the TE record.
TYPE
LHHandle = ^LHPtr;
LHPtr = ^LHTable;
LHTable = ARRAY [0..0] OF LHElement;
LHElement = RECORD
lhHeight:INTEGER;
lhAscent:INTEGER;
END;
For each line, lhHeight and lhAscent contain the maximum height and ascent present in that line.
Fortunately, you dont have to remember any of this information when using the new Text Edit. For straightforward text editing, all we need to know is that the TECopy, TECut, TEKey and TEDelete routines work as before, but Copy and Cut store a second type of scrap, styl, in the desk scrap. When you do a TEPaste, this information is not used and only the text is pasted into the edit record using the style that was present at the insertion point. For pasting with style, a new routine exists, TEStylPaste. This is one of 10 routines that are called through the new trap TEDispatch. This trap will look at a selector (integer) on top of stack and call the new text edit routines accordingly.
Mach2 implements the new TE routines using their names and compiling the glue code for the dispatch routine automatically. One routine, TEStylInsert, has been left out accidentally, and is redefined in the example listing. Two more new traps exist: TEStylNew and TEGetOffset. Mach2 spells the former TEStyleNew, so watch out for that.
For simple use as in the example, the most important new routines that you have to remember are TEStylNew, TEStylPaste, TEGetOffset, TEGetStyle, and TESetStyle.
TEStylNew is just like TENew, except that it creates a new type TE record. TEStylPaste will use the styl information in the scrap, if present, for the text to be pasted.
TEGetOffset works with both old and new type TE records and finds the character offset in the text corresponding to a certain point in the window (local coordinates). This is necessary for updating the font, size and style menu information after a change of the insertion point by a mouse click.
TEGetStyle and TESetStyleare used to get and set style information at the selection of insertion point in the text. They work with another data structure, the TextStyle:
TYPE TextStyle = RECORD
tsFont:INTEGER;
tsFace:Style;
tsSize:INTEGER;
tsColor: RGBColor
END;
This record contains the text style information that is passed to/from the TE record.
All these routines are, of course, documented in IM Vol. V. Examples on how to call them can be found in the program listing. Feel free to experiment with the other new TE routines.
The example will create an editor window with vertical and horizontal scroll bars and read the first 1024 characters from a text file. You can use this text for playing around with different style settings (using the menus I provided). Doing this, you will notice that the Style menu doesnt seem to have any effect on the text. Fonts and font sizes may be changed, but underlining, boldfacing etc. seems to be impossible. However, when you set those text attributes for a certain selection and then click at different positions in the text, you will see that the Style menu changes appropriately, checkmarks appear and disappear in the right positions. Therefore I believe that the style changes are well recorded in the style record/style table; only the text display doesnt seem to function. Is this a bug still present in the new TextEdit, or have I overlooked something obvious (question to you, the readers)?
You see that editing multi-style text is not too difficult with the new TE routines, since they take care of almost everything. For saving and loading files, you would have to provide code that reads/writes the style record information together with the text, this also seems pretty straightforward. Printing a new style text edit record is a completely different ballgame, since no printing support exists (yet?) that is quite as extensive as the new TextEdit. You would have to extract the style information for each line, using the style record, style and line height tables, and write the printing code from scratch. More difficult, but probably a good exercise for the reader.
Bugs in the SCSI driver?
Some remarks have been received that the SCSI code published in V4#1/2 was buggy, and someone seems to have crashed his hard disk using it. I feel sorry if application of that example (which was however marked experimental) should have caused trouble to anyone. The only excuse I have is that it was said that the code had been shown to work only for two types of disk, the Q280 and the ST225N, the only ones available to me for testing at that time.
Let me point out here that we can only do our best to give examples of Macintosh programming, but never guarantee that everything works 100% and bug-free. Feel free to publish your comments, preferably with corrections, in MacTutor, thats what were here for. But for any example that is printed here or published on the source code disks, be prepared that something might go wrong, and especially DONT run it from the disk that has your only copy of that 40-page report on it that is due in two days! Play it safe and use floppies that have nothing valuable on them. I learned my lesson when I crashed my own hard disk while writing the Forth example for the February article.
I wish you good luck with this months example. The source code disk contains two compiled versions, one for Mac Plus/SE/II, and one for Mac II only (contains 68020 code). As far as I have checked them, they dont crash and work under MultiFinder. But you never know...
Till next month, happy threading.
Listing 1: Text Edit Example with Style
\ New Text Edit example
\ J. Langowski for Mac Tutor March 1988
\ derived from
\ Editor Shell Example Program on Mach 2 demo disk
\ found two features of the new text edit while
\ experimenting:
\ a. when the insertion point is at a boundary between
\ two different styles, the text typed will be TEKeyed
\ according to the style BEFORE the insertion point,
\ while TEGetStyle will return style information from
\ AFTER the insertion point.
\ b. Although the text face seems to be set inside the style \ record
and properly associated with the text
\ (TEGetStyle returns the correct information after the
\ text face has been changed), the text is always drawn
\ plain text style. The font and size changes work OK.
\
only forth definitions
also assembler also mac
\ ***** constants
300 CONSTANT APPLEID
310 CONSTANT FILEID
320 CONSTANT EDITID
330 CONSTANT SIZEID
340 CONSTANT FontID
350 CONSTANT StyleID
20 CONSTANT InUpArrow
21 CONSTANT InDownArrow
22 CONSTANT InPageUp
23 CONSTANT InPageDown
129 CONSTANT InThumb
$44525652 Constant drvr
$464F4E54 Constant font
%000001000000000 CONSTANT ShiftMask
$10 CONSTANTportRect \ Grafport rectangle
$6E CONSTANTwVisible \ visible flag [byte]
\ text edit equates
0 CONSTANT teDestRect
8 CONSTANT teViewRect
$C CONSTANTselRect
$18 CONSTANT teLineHite
$1A CONSTANTteFontAscent
$1C CONSTANTteSelPoint
$20 CONSTANT teSelStart
$22 CONSTANT teSelEnd
$38 CONSTANT teCarOn
$39 CONSTANT teCarAct
$3C CONSTANTteLength
$3E CONSTANTteTextH
$48 CONSTANTteCROnly
$4A CONSTANTteFont
$4C CONSTANTteFace
$4A CONSTANTteStylHandle
\ handle to style record for new
\ text edit. Never accessed directly
$4E CONSTANTteMode \ text mode [word]
$50 CONSTANT teSize\ font size [word]
\ teFont, teFace, teMode, teSize are only
\ meaningful for old style TE records.
\ for a new style record, teSize contains -1.
\ in that case, teFont and teFace together contain
\ the handle to the style record.
$5E CONSTANTteNLines
$60 CONSTANTteLines
$AB0 CONSTANT TEScrpLength
$AB4 CONSTANT TEScrpHandle
\ Event Record Equates
$0 CONSTANT What ( event code [word] )
$2 CONSTANT Message( event message [long] )
$6 CONSTANT When ( ticks since start-up [long] )
$A CONSTANT Where( mouse loc. pt. global [long] )
$E CONSTANT Modifiers( modifier flags [word] )
$0A CONSTANT LF ( ascii linefeed )
$20 CONSTANT SP ( ascii space )
create applestring 01 C, $14 C, \ Apple symbol
\ ***** variables
VARIABLE TEHandle( handle for text edit record )
VARIABLE TERect 4 VALLOT
( Text Edit view rectangle )
VARIABLE SIZE ( item# of current textsize )
VARIABLE DESKNAME 252 VALLOT\ holds name of desk accessory
VARIABLE FONTNAME 252 VALLOT\ holds font name selected
VARIABLE ITEMNAME 60 VALLOT
\ receives menu item name
VARIABLE MyStyle 8 VALLOT
\ text style record for our private use
\ fields of MyStyle:
0 CONSTANT tsFont
2 CONSTANT tsFace
4 CONSTANT tsSize
6 CONSTANT RGBColor
VARIABLE currentFont \ menu ID of font in use
VARIABLE #fonts \ # of currently installed fonts
VARIABLE currentSize \ menu ID of size in use
76 USER AbortHook
152 USER ContentHook
160 USER GrowHook
164 USER CloseBoxHook
168 USER UpdateHook
172 USER ActivateHook
202 USER CAction \ control action routine vector
\ ***** glue routines for new text edit
\
\ TEStylNew ( destRect viewRect -- TEHandle )
\ is misspelled TEStyleNew in the Mach2 trap definitions,
\ but implemented. So are TEGetOffset and most of the
\ other new text edit routines that are called through
\ TEDispatch.
\ One exception is TEStylInsert, which we are defining
\ here:
CODE TEStylInsert ( text length hST hTE -- )
EXG D4,A7
MOVE.L $C(A6),-(A7) \ pointer to text
MOVE.L $8(A6),-(A7) \ length of text
MOVE.L $4(A6),-(A7) \ style record handle
MOVE.L (A6),-(A7) \ TE record handle
ADDA.W #$10,A6
MOVE.W #$7,-(A7)
_TEDispatch
EXG D4,A7
RTS
END-CODE
\ ***** windows, menus, controls, tasks etc. *****
NEW.WINDOW Editor
Editor Editor TITLE
42 4 330 507 Editor BOUNDS
DOCUMENT INVISIBLE CLOSEBOX GROWBOX
Editor ITEMS
200 1000 TERMINAL EditTask
NEW.MBAR EditBar
NEW.MENU AppleMenu
APPLESTRING AppleMenu TITLE
0 APPLEID AppleMenu BOUNDS
About Editor ...;(- AppleMenu ITEMS
NEW.MENU FileMenu
File FileMenu TITLE
0 FileID FileMenu BOUNDS
New/N;Open.../O;Close;Save;Save as...;Revert to Original;(Print
FileMenu ITEMS
NEW.MENU EditMenu
Edit EditMenu TITLE
0 EDITID EditMenu BOUNDS
(Undo/Z;(-;Cut/K;Copy/C;Paste/V;Clear
EditMenu ITEMS
NEW.MENU FontMenu
Font FontMenu TITLE
0 FontID FontMenu BOUNDS
(Fonts<I;(- FontMenu ITEMS
NEW.MENU SizeMenu
Size SizeMenu TITLE
0 SizeID SizeMenu BOUNDS
9 Point; 10 Point; 12 Point; 14 Point; 18 Point; 20 Point; 24 Point
SizeMenu ITEMS
CREATE SizeIDTable
0 , 0 , 0 c, \ no menu IDs for sizes 0 thru 8
1 c, 2 c, 0 c, 3 c, \ 9,10,--,12
0 c, 4 c, 0 c, 0 c, \ --,14,--,--
0 c, 5 c, 0 c, 6 c, \ --,18,--,20
0 c, 0 c, 0 c, 7 c, \ --,--,--,24
CREATE SizeTable
0 c, 9 c, 10 c, 12 c, 14 c, 18 c, 20 c, 24 c,
NEW.MENU StyleMenu
Style StyleMenu TITLE
0 StyleID StyleMenu BOUNDS
Plain/P; Bold/B<B; Italic/I<I; Underline/U<U; Outline<O; Shadow<S;
Condense; Extend
StyleMenu ITEMS
NEW.CONTROL Scroll
VSCROLLBAR VISIBLE 100 0 Scroll ITEMS
VARIABLE lastVs
400 CONSTANT maxVs
NEW.CONTROL hScroll
HSCROLLBAR VISIBLE 100 0 hScroll ITEMS
VARIABLE lastHs
100 CONSTANT maxHs
: CHECK ( menuhandle item# flag -- )( checking a menu item )
CALL CheckItem ;
: =string { aStr bStr | -- flag }
aStr count 65536 * bStr count rot + swap
call CmpString 0=
;
CODE @TEHandle
MOVE.L TEHandle,-(A6) RTS
END-CODE
: Shift? ( - f ) \ checks the event record to see if the
\ shift key was pressed.
EVENT-RECORD Modifiers + W@ ShiftMask AND
IF -1 ELSE 0 THEN
;
: adjustFontMenu
\ adjust font menu and currentFont variable
myStyle w@ ( font ID ) fontName call getFname
#fonts @ 0 DO
fontMenu @ i itemName call GetItem
itemName fontName =string
IF FontMenu @ currentFont @ 0 check
\ uncheck previous font selection
FontMenu @ i -1 check
i currentFont !
leave
THEN
LOOP
;
: adjustStyleMenu { | face - }
myStyle tsFace + w@ -> face
8 0 DO
1 i scale face and ( get style bit )
if -1 else 0 then
styleMenu @ i 2+ rot check
LOOP
;
: adjustSizeMenu
SizeMenu @ currentSize @ 0 check
myStyle tsSize + w@ ( size )
SizeIDTable + c@ ( sizeID )
dup currentSize !
SizeMenu @ swap -1 check
;
: getCurrentStyle { | LHite FAsc -- }
( updates variable currentFont )
( size and Face kept in myStyle )
( LHite and FAsc are currently not used )
@TEHandle @ teselStart + w@
\ get start of selection (or insertion point)
( offset ) myStyle ^ LHite ^ FAsc @TEHandle
call TEGetStyle
adjustFontMenu
adjustStyleMenu
adjustSizeMenu
;
: AdjustTERect
\ adjust terect size for the presence of scrollbars
portRect Editor + 4 + W@ ( get bottom coord )
16 - ( subtract 16 for height of scrollbar )
teViewRect @TEHandle @ + 4 + W! \ store new coord back in text edit
record
portRect Editor + 6 + W@ ( get right coord )
16 - ( subtract 16 for width of scrollbar )
teViewRect @TEHandle @ + 6 + W!
;
: Visible? ( - f ) \ checks visible flag in window record
Editor wVisible + C@
;
\ ***** event handlers *****
: ACTIVATE-HANDLER
RUN-ACTIVATE
EVENT-RECORD Modifiers + W@( get modifiers word )
1 AND IF
@TEHandle CALL TEActivate
getCurrentStyle
ELSE
@TEHandle CALL TEDeactivate
THEN
;
: UPDATE-HANDLER
Editor CALL SetPort
AdjustTERect
Editor CALL BeginUpdate
Editor CALL DrawControls
Editor CALL DrawGrowIcon
Editor portRect + @TEHandle CALL TEUpdate
Editor CALL EndUpdate
;
: CONTENT-HANDLER { | theMouse -- }
RUN-CONTENT
Editor CALL SetPort
^ theMouse CALL GetMouse
theMouse @TEHandle @ TEViewRect +
call PtInRect
IF
theMouse Shift? @TEHandle CALL TEClick
getCurrentStyle
THEN
;
: CLOSEBOX-HANDLER
Editor \ windowpointer
EVENT-RECORD Where + @ call TrackGoAway IF Editor CALL HideWindow
THEN
;
\ **** main editor example code *****
: POP-UP
Editor CALL ShowWindow
Editor CALL SelectWindow
EditBar @ CALL SetMenuBar
CALL DrawMenuBar
;
: ShutDown
Editor CALL HideWindow
PAUSE ( PAUSE so that the i/o task can
have a turn and handle the
deactivate event generated by
the closing of the window )
MACH.MBAR( MACH menubar back on screen )
@TEHandle CALL TEDispose
;
: SetScrollLimits
Scroll @ 0 CALL SetMinCtl
Scroll @ maxVs CALL SetMaxCtl
Scroll @ 0 CALL SetCtlValue
0 lastVs !
hScroll @ 0 CALL SetMinCtl
hScroll @ maxHs CALL SetMaxCtl
hScroll @ 0 CALL SetCtlValue
0 lastHs !
;
: EditFile { | char exitflag -- }
BEGIN
Visible?
IF
?TERMINAL IF
KEY -> char( get the character )
char 14 = IF
0 -> exitflag ( if cmd . exit )
ELSE
char @TEHandle CALL TEKey
( else insert )
1 -> exitflag ( char )
THEN
ELSE
1 -> exitflag
( if no key pressed, keep looping )
THEN
ELSE
0 -> exitflag
( if windows been closed, exit )
THEN
exitflag ( check exit condition )
WHILE
@TEHandle CALL TEIdle
REPEAT
;
: Open
Pop-Up
Editor CALL SetPort
TERect TERect CALL TEStyleNew TEHandle !
\ get new style TE record
-1 teCROnly @TEHANDLE @ + W! ( no word wrap )
-1 teCarAct @TEHandle @ + C! ( activate caret )
-1 @TEHandle call TEAutoView
\ enable auto scroll
( get the first 1K of text )
0 VIRTUAL 1024 0 @TEHandle TEStylinsert
0 0 @TEHandle CALL TESetSelect
15 ( doAll ) myStyle -1 ( redraw) @TEHandle
call TESetStyle
adjustFontMenu
adjustStyleMenu
adjustSizeMenu
AdjustTERect ( initialize the text )
PortRect Editor + @TEHandle CALL TEUpdate
@TEHandle CALL TEDeactivate
@TEHandle CALL TEActivate
SetScrollLimits
Editor CALL DrawControls Editor CALL DrawGrowIcon
[] UPDATE-HANDLER UpdateHook !
[] CONTENT-HANDLER ContentHook !
[] ACTIVATE-HANDLER ActivateHook !
[] CLOSEBOX-HANDLER CloseBoxHook !
;
\ ***** menu handlers *****
: HandleDeskAcc ( item# - )
APPLEMENU @ SWAP DESKNAME CALL GETITEM
DESKNAME CALL OPENDESKACC
DROP
;
: DO-APPLE ( item# - )
dup 1 = IF
( AboutEdit ) ( About Editor ... )
drop
ELSE HandleDeskAcc
THEN
;
: NewFile ;
: OpenFile ;
: CloseFile ;
: SaveFile ;
: SaveAs ;
: Revert ;
: DO-FILE ( item# - )
CASE
1 OF NewFile ENDOF
2 OF OpenFile ENDOF
3 OF CloseFileENDOF
4 OF SaveFile ENDOF
5 OF SaveAsENDOF
6 OF RevertENDOF
ENDCASE
;
: DO-EDIT ( item# - )
CASE
1 OF ( TEUndo ) ENDOF
3 OF @TEHandle CALL TECut ENDOF
4 OF @TEHandle CALL TECopy ENDOF
5 OF @TEHandle CALL TEStylPaste ENDOF
6 OF @TEHandle CALL TEDelete ENDOF
ENDCASE
;
: DO-Font { item# | fontID - }
FontMenu @ item# Fontname call getitem
Fontname ^ fontID call getFNum
^ fontID w@ myStyle w!
\ put into tsFont field of style record
1 ( doFont) myStyle -1 ( redraw) @TEHandle
call TESetStyle
FontMenu @ currentFont @ 0 check
FontMenu @ item# -1 check
item# currentFont !
;
: Do-Style { item# | facefield -- }
myStyle tsFace + -> facefield
item# CASE
1 OF ( plain text )
0 facefield w!
ENDOF
facefield w@
1 item# 2- scale xor
facefield w! \ flip bit
ENDCASE
2 ( doFace) myStyle -1 ( redraw) @TEHandle
call TESetStyle
adjustStyleMenu
;
: Do-Size ( item# - )
SizeTable + c@
myStyle tsSize + w!
4 ( doSize) myStyle -1 ( redraw) @TEHandle
call TESetStyle
adjustSizeMenu
;
: MBAR-HANDLER ( item# menuID - )
CASE
APPLEID OF DO-APPLE ENDOF
FILEID OF DO-FILE ENDOF
EDITID OF DO-EDIT ENDOF
FontID OF DO-Font ENDOF
SIZEID OF DO-Size ENDOF
STYLEIDOF DO-StyleENDOF
ENDCASE
0 CALL HILITEMENU
;
\ ***** control action routines *****
\ A control action routine specifies what action should take
\ place WHILE a control is being held down.
: ScrollText { dv dh -- }
dh dv @TEHandle CALL TEScroll
;
: DO-Scroll { part-code | ctlvalue - }
part-code
CASE
inuparrow OF Scroll @ CALL GetCtlValue -> ctlvalue
ctlvalue 0= NOT
IF
Scroll @ ctlvalue 1- call SetCtlValue
5 0 ScrollText
THEN
ENDOF
indownarrow OF Scroll @ call GetCtlValue -> ctlvalue
ctlvalue maxVs = NOT
IF
Scroll @ ctlvalue 1+ call SetCtlValue
-5 0 ScrollText
THEN
ENDOF
inpageup OF Scroll @ call GetCtlValue -> ctlvalue
ctlvalue 0= NOT
IF
Scroll @ ctlvalue 5 - call SetCtlValue
25 0 ScrollText
THEN
ENDOF
inpagedown OF Scroll @ call GetCtlValue -> ctlvalue
ctlvalue maxVs = NOT
IF
Scroll @ ctlvalue 5 + call SetCtlValue
-25 0 ScrollText
THEN
ENDOF
ENDCASE
Scroll @ call GetCtlValue lastVs !
;
: DO-hScroll { part-code | ctlvalue - }
part-code
CASE
inuparrow OF hScroll @ call GetCtlValue -> ctlvalue
ctlvalue 0= NOT
IF
hScroll @ ctlvalue 1- call SetCtlValue
0 5 ScrollText
THEN
ENDOF
indownarrow OF hScroll @ call GetCtlValue -> ctlvalue
ctlvalue maxHs = NOT
IF
hScroll @ ctlvalue 1+ call SetCtlValue
0 -5 ScrollText
THEN
ENDOF
inpageup OF hScroll @ call GetCtlValue -> ctlvalue
ctlvalue 0= NOT
IF
hScroll @ ctlvalue 5 - call SetCtlValue
0 25 ScrollText
THEN
ENDOF
inpagedown OF hScroll @ call GetCtlValue -> ctlvalue
ctlvalue maxHs = NOT
IF
hScroll @ ctlvalue 5 + call SetCtlValue
0 -25 ScrollText
THEN
ENDOF
ENDCASE
hScroll @ call GetCtlValue lastHs !
;
: ControlAction ( part-code control-handle - )
CASE
Scroll @ OF DO-Scroll ENDOF
hScroll @ OF DO-hScroll ENDOF
swap drop
ENDCASE
;
\ ***** scrollbar thumb control handler *****
: DO-vThumb { | ctlV }
inThumb = IF
scroll @ call getCtlValue -> ctlV
lastVs @ ctlV - 5 * 0 scrollText
ctlV lastVs !
THEN
;
: DO-hThumb { | ctlV }
inThumb = IF
hscroll @ call getCtlValue -> ctlV
0 lastHs @ ctlV - 5 * scrollText
ctlV lastHs !
THEN
;
: ControlHandler ( part-code control-handle - )
CASE
Scroll @ OF DO-vThumb ENDOF
hScroll @ OF DO-hThumb ENDOF
swap drop
ENDCASE
;
\ ***** initialization *****
: INIT-MBAR
EditBar ADD
EditBar APPLEMENU ADD
APPLEMENU @ drvr call addresmenu
EditBar FileMenu ADD
EditBar EditMenu ADD
EditBar FontMenu ADD
Fontmenu @ font call addresmenu
Fontmenu @ call countMItems #fonts !
EditBar SizeMenu ADD
EditBar StyleMenu ADD
;
: INIT-TASK
Editor ADD ( make the Editor window )
Editor Scroll ADD ( add vertical scroll bar )
Editor hScroll ADD( add horizontal scroll bar )
Editor EditTask BUILD
;
: START-TASK
ACTIVATE
[] ControlAction CAction !
[] ControlHandler Control-Vector !
[] MBAR-HANDLER MENU-VECTOR !
BEGIN
STANDARD-GETFILE
IF
Open
EditFile
ShutDown
THEN
[] RUN-UPDATE UpdateHook !
[] RUN-CONTENT ContentHook !
[] RUN-ACTIVATE ActivateHook !
[] RUN-CLOSEBOX CloseBoxHook !
SLEEP STATUS W! ( put Editor task to sleep )
PAUSE( exit this task )
AGAIN
;
: INIT-EDIT
INIT-TASK
INIT-MBAR
EditBar EditTask MBAR>TASK 4 myStyle w! \ default font, Monaco
0 myStyle 2+ w! \ default face, plain text
9 myStyle 4 + w! \ default size, 9 point
0 myStyle 6 + ! \ RGBcolor = ...
0 myStyle 10 + w! \ ...black
4 TERect W! ( define the text edit rectangle )
4 TERect 2+ W!
288 TERect 4 + W!
503 TERect 6 + W!
EditTask START-TASK
;
: EDIT ( wakes up Editor task )
EDITTASK @
IFWAKE STATUS TASK-> EditTask W!
ELSE INIT-EDIT
THEN
;