-> strhooks.e - string gadget hooks demo -> E-Note: this uses several of the 'tools' modules, notably 'installhook' MODULE 'utility', 'graphics/rastport', 'intuition/intuition', 'intuition/screens', 'intuition/sghooks', 'utility/hooks', 'tools/ctype', 'tools/installhook' ENUM ERR_NONE, ERR_DRAW, ERR_KICK, ERR_LIB, ERR_PUB, ERR_WIN RAISE ERR_DRAW IF GetScreenDrawInfo()=NIL, ERR_LIB IF OpenLibrary()=NIL, ERR_PUB IF LockPubScreen()=NIL, ERR_WIN IF OpenWindowTagList()=NIL CONST SG_STRLEN=44, MYSTRGADWIDTH=200 -> We'll dynamically allocate/clear most structures, buffers OBJECT vars sgg_Window:PTR TO window sgg_Gadget:gadget sgg_StrInfo:stringinfo sgg_Extend:stringextend sgg_Hook:hook sgg_Buff[SG_STRLEN]:ARRAY sgg_WBuff[SG_STRLEN]:ARRAY sgg_UBuff[SG_STRLEN]:ARRAY ENDOBJECT -> Open all required libraries, set-up the string gadget. -> Prepare the hook, open the sgg_Window and go... PROC main() HANDLE -> E-Note: subtle name changes needed... DEF vars=NIL:PTR TO vars, screen=NIL:PTR TO screen, drawinfo=NIL:PTR TO drawinfo IF KickVersion(37)=FALSE THEN Raise(ERR_KICK) utilitybase:=OpenLibrary('utility.library', 37) -> Get the correct pens for the screen screen:=LockPubScreen(NIL) drawinfo:=GetScreenDrawInfo(screen) NEW vars -> E-Note: raises an exception if it fails vars.sgg_Extend.pens[0]:=drawinfo.pens[FILLTEXTPEN] vars.sgg_Extend.pens[1]:=drawinfo.pens[FILLPEN] vars.sgg_Extend.activepens[0]:=drawinfo.pens[FILLTEXTPEN] vars.sgg_Extend.activepens[1]:=drawinfo.pens[FILLPEN] vars.sgg_Extend.edithook:=vars.sgg_Hook vars.sgg_Extend.workbuffer:=vars.sgg_WBuff vars.sgg_StrInfo.buffer:=vars.sgg_Buff vars.sgg_StrInfo.undobuffer:=vars.sgg_UBuff vars.sgg_StrInfo.maxchars:=SG_STRLEN vars.sgg_StrInfo.extension:=vars.sgg_Extend -> There should probably be a border around the string gadget. -> As is, it is hard to locate when disabled. vars.sgg_Gadget.leftedge:=20 vars.sgg_Gadget.topedge:=30 vars.sgg_Gadget.width:=MYSTRGADWIDTH vars.sgg_Gadget.height:=screen.rastport.txheight vars.sgg_Gadget.flags:=GFLG_GADGHCOMP OR GFLG_STRINGEXTEND vars.sgg_Gadget.activation:=GACT_RELVERIFY vars.sgg_Gadget.gadgettype:=GTYP_STRGADGET vars.sgg_Gadget.specialinfo:=vars.sgg_StrInfo -> E-Note: use typed lists for border and its data -> E-Note: because we're using E we don't need stupid INIT_LATER vars.sgg_Gadget.gadgetrender:=[-2,-2,1,0,RP_JAM1,5, [0, 0, MYSTRGADWIDTH+3, 0, MYSTRGADWIDTH+3, screen.rastport.txheight+3, 0, screen.rastport.txheight+3, 0, 0]:INT, NIL]:border -> E-Note: use Wouter's installhook installhook(vars.sgg_Hook, {str_hookRoutine}) vars.sgg_Window:=OpenWindowTagList(NIL, [WA_PUBSCREEN, screen, WA_LEFT, 21, WA_TOP, 20, WA_WIDTH, 500, WA_HEIGHT, 150, WA_MINWIDTH, 50, WA_MAXWIDTH, -1, WA_MINHEIGHT, 30, WA_MAXHEIGHT, -1, WA_SIMPLEREFRESH, TRUE, WA_NOCAREREFRESH, TRUE, WA_RMBTRAP, TRUE, WA_IDCMP, IDCMP_GADGETUP OR IDCMP_CLOSEWINDOW, WA_FLAGS, WFLG_CLOSEGADGET OR WFLG_NOCAREREFRESH OR WFLG_DRAGBAR OR WFLG_DEPTHGADGET OR WFLG_SIMPLE_REFRESH, WA_TITLE, 'String Hook Accepts HEX Digits Only', WA_GADGETS, vars.sgg_Gadget, NIL]) handleWindow(vars) -> E-Note: exit and clean up via handler EXCEPT DO IF (vars<>NIL) AND vars.sgg_Window THEN CloseWindow(vars.sgg_Window) -> E-Note: vars automatically freed IF drawinfo THEN FreeScreenDrawInfo(screen, drawinfo) IF screen THEN UnlockPubScreen(NIL, screen) IF utilitybase THEN CloseLibrary(utilitybase) -> E-Note: we can print a minimal error message SELECT exception CASE ERR_DRAW; WriteF('Error: Failed to get drawinfo from screen\n') CASE ERR_KICK; WriteF('Error: Needs Kickstart V37+\n') CASE ERR_LIB; WriteF('Error: Failed to open utility.library\n') CASE ERR_PUB; WriteF('Error: Failed to lock public screen\n') CASE ERR_WIN; WriteF('Error: Failed to open window\n') CASE "MEM"; WriteF('Error: Ran out of memory\n') ENDSELECT ENDPROC -> This is an example string editing hook, which shows the basics of creating -> a string editing function. This hook restricts entry to hexadecimal digits -> (0-9, A-F, a-f) and converts them to upper case. To demonstrate processing -> of mouse-clicks, this hook also detects clicking on a character, and -> converts it to a zero. -> -> NOTE String editing hooks are called on Intuition's task context, so the -> hook may not use DOS and may not cause Wait() to be called. PROC str_hookRoutine(hook, sgw:PTR TO sgwork, msg:PTR TO LONG) DEF work_ptr, return_code -> Hook must return non-zero if command is supported. -> This will be changed to zero if the command is unsupported. return_code:=-1 IF msg[]=SGH_KEY -> Key hit -- could be any key (Shift, repeat, character, etc.) -> Allow only upper case characters to be entered. -> Act only on modes that add or update characters in the buffer. IF (sgw.editop=EO_REPLACECHAR) OR (sgw.editop=EO_INSERTCHAR) -> Code contains the ASCII representation of the character entered, if -> it maps to a single byte. We could also look into the work buffer to -> find the new character. -> -> sgw.code = sgw.workbuffer[sgw.bufferpos-1] -> -> If the character is not a legal hex digit, don't use the work buffer -> and beep the screen. -> E-Note: use isxdigit from 'tools/ctype' IF isxdigit(sgw.code)=FALSE sgw.actions:=sgw.actions OR SGA_BEEP sgw.actions:=sgw.actions AND Not(SGA_USE) ELSE -> And make it upper-case, for nicety work_ptr:=sgw.workbuffer work_ptr[sgw.bufferpos-1]:=toupper(sgw.code) ENDIF ENDIF ELSEIF msg[]=SGH_CLICK -> Mouse click -> Zero the digit clicked on IF sgw.bufferpos < sgw.numchars work_ptr:=sgw.workbuffer+sgw.bufferpos work_ptr[]:="0" ENDIF ELSE -> UNKNOWN COMMAND -> Hook should return zero if the command is not supported return_code:=0 ENDIF ENDPROC return_code -> E-Note: we don't need the hookEntry stuff, installhook does it all -> Process messages received by the sgg_Window. Quit when the close gadget -> is selected. -> E-Note: E version is simpler, since we use WaitIMessage PROC handleWindow(vars:PTR TO vars) DEF class REPEAT class:=WaitIMessage(vars.sgg_Window) -> If a code is set in the hook after an SGH_KEY command, where SGA_END is -> set on return from the hook, the code will be returned in the Code field -> of the IDCMP_GADGETUP message. -> E-Note: ...so use MsgCode() to get at it UNTIL class=IDCMP_CLOSEWINDOW ENDPROC