10905 lines
321 KiB
Plaintext
Executable File
10905 lines
321 KiB
Plaintext
Executable File
PROGRAMMING IN HWIF
|
||
|
||
|
||
Version 2.10
|
||
|
||
|
||
February 3, 1995
|
||
|
||
|
||
(C) Copyright Psion PLC 1994-95
|
||
|
||
|
||
All rights reserved. This manual and the programs referred to herein are copyrighted works of Psion PLC,
|
||
London, England. Reproduction in whole or in part, including utilization in machines capable of
|
||
reproduction or retrieval, without express written permission of Psion PLC, is prohibited. Reverse
|
||
engineering is also prohibited.
|
||
|
||
|
||
The information in this document is subject to change without notice.
|
||
|
||
|
||
Psion and the Psion logo are registered trademarks, and Psion, Psion MC, Psion HC, Psion Series 3, Psion
|
||
Series 3a and Psion Workabout are trademarks of Psion PLC.
|
||
|
||
|
||
TopSpeed is a registered trademark of Clarion Software Corporation. Intel 8086 and 80286 are registered
|
||
trademarks of Intel Corporation. IBM, IBM XT and IBM AT are registered trademarks of International
|
||
Business Machines Corp. Microsoft and MS-DOS are registered trademarks of Microsoft Corporation.
|
||
Apple and Macintosh are registered trademarks of Apple Computer Inc. VAX and VMS are registered
|
||
trademarks of Digital Equipment Corporation. Brief is a registered trademark of Underware Inc. Psion PLC
|
||
acknowledges that some other names referred to are registered trademarks.
|
||
|
||
|
||
6102 0016 03
|
||
|
||
|
||
SSS SSS SS Se aa eee a)
|
||
|
||
|
||
Contents
|
||
TL Introduction: to! HWIf....ccscesscccccs-s0desciscocessveeseessedecsveusrececnacesoesshccoseivevewaheeegeag 1
|
||
OVErVIEW .......ececececeesenes misiadasaissseicseled Seve cocsosatsesuebecs sueuse sds Mase e cee oe vertex 1
|
||
Learning to program in HWif .............ccsccssccscnssccveccseusecetscesesonscssenseseess 1
|
||
Comparisons with OPL/w and with OOP ............cccsccscescesssonsesvescecscsees 2
|
||
Recognising Hwif function calls .............cccesscsseevesecssccsccscceccuscnscscaecesce 2
|
||
The connection to the Window Server ..........ccccsscsecscsevscsccecesceeeecscssees 3
|
||
The general shape of Hwif programs............sccsscsssccovecsccsccsessccesscecesseccecenss 3
|
||
PrOCESSING/ EVENTS: coc iads Severe este tIo eee sce tl ance see ston tte tie ode uvecteccancactacteuesbe 3
|
||
WVPES OT: OVENTS es otiaeerins eT nates Tiere se cee eke re ee re nace oo neecbacteeeeDhacsdecncdsedas 3
|
||
Programs with event sources other than keyS ..........csscscsscsccssosessescereces 4
|
||
Active and inactive event SOULCES ...........ccscccsccscoceececscecusasessscarsencncesecs 5
|
||
Active words and status words ContrasSted .............cccccescsccscescsecscscsceses 6
|
||
uGetKey and uGetKeyA compared............csssessescsscscsccsccscsccecssancucseeaces 6
|
||
Deferred ProCOSSING’. :.)-ci. casexsvescrei rece rveduvessscevesviscteSomey nective ee eee 6
|
||
Programs with more than one get-event lOO ............cccsecscsesescssccecscsees 7
|
||
Diamond keys ccc ste, Sores tata ean eG eee eee ect rocven cece sen Ste tewuunnen veer 8
|
||
Menu: bar interacthons...scs cscs usaseeesseveecedveessoestidoue dete tectes ohne Seth edei ces 10
|
||
Where _cmds must Point ..............cccscccsccsssosccosceusteccsceevserteccascescncseves 10
|
||
Where _mdata MUuSt Point .............ccscoecsececcsccsrcesesseccecscsccucusoesscesesnscs 11
|
||
How to use UPresentMenus...........csccscoscsscsccusesscvecsceccecsececsscetaenessesans 11
|
||
The ManageCommand routine .............s.cesccssccsescessucnecteceusresceeccecueaeees 12
|
||
Changing menu bar contents dynamically ..............ccccceccscesovccseeceseceecscs 12
|
||
Restrictions on valid accelerators .............cscossecescecscsccecccetscesscastescnsccns 12
|
||
Grey underlining:...:::¢.c88: 5. ventric forte ee ee ee re Oo oriadan 13
|
||
MERU POSITIONS e020 cecbo0nd bc CUTIVE STs. we tetean erate core sen ccvduceden tt ha lesaveaans 13
|
||
PFESENTING GidlOGS 03.2... <0 s.svecacevesesveacss ec ebesecexeed tome eens Shoe ove Bee ite or envadae 13
|
||
Checking for run-time €rrOrs .........:sccssccecessccesececesstsccesescceacsccrssaecerseces 13
|
||
Items that can be added to Hwif dialogs................cccsecsceecsccssosescacceeeces 13
|
||
Longer Choice lists ......c:.00sscceccasedevacevecustencess7ess A ore rs OOTTET EV weet ens 14
|
||
Typical dialog USAC «...ciccccscccseseneveovacusacteacecodecsdeeh chen teete Oe vinessavensas 15
|
||
Dialog, underlining .........::.cceccsccoessensscssceeconssoesces SMMMMNED clo vitlacsecescnrens 15
|
||
FIGIDICiFIOGS 6.205 cnsvessceseceseverecadectsceBtork Sev s50 00 645.7 eee nc ctae Srevndece 16
|
||
Help dialogs (an older alternative) .............ccccseceescceccvecceceseccuccecaucusceses 18
|
||
Line editors and multi-line Editors ..............ccscccecsscsccccesscsescesatsecscecscucecscass 18
|
||
Editing features SUPPOFted..............ccscssocsececcecescecvcessrcecssesssesoscecensacsecs 18
|
||
PFESENTING*AN1SditOl s....5 6c 2iceelivscocvesevesechisesasccciseescersectecdcdecuvancvewcncies 18
|
||
Applications with more than one @Gitor ..........ccssccescscosceeceseseccsceccesaveas 19
|
||
Edit boxes and saved file Versions ............csscecsssesseecevcsccccsccevascssasateenas 20
|
||
PRIME asars iovncsd senda caus cacevcdaidudete dustin es tos leaeddoccs SRN t Re FE, ORM ek oe oe 20
|
||
Printing features Supported 3 co.c5..5. caccccccev Picea sstessevecsdvcenveducecivesd Sdeecencs 20
|
||
The Print Setup dialogues. ss sssess ss cswess oc cise eros vee ok soe oe bat carer dete ast eeeledss 21
|
||
The basic mechanism of printing ............ccccecssssccccenscsccceeusesaucecutececececs 21
|
||
The PrintLine callback fUNCTION............ccccccceccesececescecucccesceeccsseeaecscnsaees 22
|
||
The location of the print DUffer .............cccccecsveessccececscecscatetevcscseecesscecs 22
|
||
The: Print: Details dialogs... ssccecisce.cvecec tetas sage aeveden boi deucesbuddvceettecessdees 23
|
||
Word wrapping during printing...........cccscscsscscostevcecncucssusoccccecueeensensenss 23
|
||
Printing the contents of multi-line Editors ..............cceececsessccscsenscsoenscnss 23
|
||
Time-text, utility FUNCTIONS ....i66..cssceccsajeacscassascscecsecvesvecsceseccedesesvadeustvevacves 24
|
||
Default textual representation .............cccscoccscsccsescccsceesscseuctecscscecenececes 24
|
||
Refreshing the format on returning to foreground ..........cccsceccsseesseeecsesos 24
|
||
Date/Time-text utility FUNCTIONS ...........ccescsecsccecestovsessuccecerscescouccesscosnsaccnss 25
|
||
Hwif, the Console, and screen Output ...........cccceccesscececaccvcccceccscascncetacavenss 25
|
||
Three options for graphics OUtPUt.............ccsccseecceccscceceeesecucesecuseeceecass 26
|
||
|
||
|
||
Practical acquisition of graphics techniques ............ccccccecceceseuecscececeseess 26
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
i
|
||
|
||
|
||
Hwif opens the console channel ..............ssccssesscssscecseececconccavecsnsceeeens 27
|
||
TGV AU WINKOW o.oo Seas deceuueccsuttcs os sates ues eoiBacetsansescoicoeeotue tek eras: 27
|
||
GLEY corracsrretrsceeremtadenece tee secscrccone sec teasecas fre nacts vagensore ove forest sare see cree 27
|
||
Dual mode applications.............cccseccccecsecsseccsssecccscassaccuscsntecesessuaceceusescess 27
|
||
SLONING Gata tote ic. ccaxescnustecsicslvaasece¥ianstasieusen<tigicthisasbicem takes ac ack 28
|
||
ThesDbf tile format tcc: secchsciesecs costes daa esvecg sats coesdsieescoeeeel esedea Aen 29
|
||
Dialling telephone MUMDETS .............secssessevecsssucecccscccescucesssecceseecusenecs 29
|
||
Communication with the System Screen ...........ccsscecsssosecoccsceccsssssssceceseeece 29
|
||
Reading the command lime...............csesscssseoccurceccessensccntsecacseesevsccssvece 30
|
||
Storing the name of the file currently Open...............cs-cosceceeccescecceuceescs 30
|
||
The protocol of messages from the System Screen ...........cscseccsscesssesces 30
|
||
SOME MOYES ON TUN-tIME EFTOFS..........ccccesccuccncscececsseecovccesccssceccscesccescevsnence 30
|
||
SOME EFOrs tO COMSIGET ..........cccecescascsssecccecscaccvcesecatcncsccteeseeteseuccacens 31
|
||
Strategies on handling eErrors..........ccccsccecsceecccssscescecucceececcescescestenceses 31
|
||
Reverting to the previous file..............:csssscsescssccsescresccossovecsarsceseoescones 31
|
||
Errors when formatting edit DOXES .........cccccescssceccesscovccecacceccescsescescnece 32
|
||
Future developments. .ccc.eA tiesto Batre tastiest tca tee crt ete oc eeesicsouses 32
|
||
|
||
|
||
2 Worked Examples in Hwit.............sccssscsrcsscesssscesscconcascersessconcostcacecaceusestaaceeece 33
|
||
How to use the supplied examples ...........ccccsscsceececascescoccescscsccetsecesesseececs 33
|
||
The embedded SUgGeStIONS............cscsecssecsccececsecsscessessecscescsstscessasenses 33
|
||
Preview of the example applications.............ccccececesscescsccssscescecesceesecens 33
|
||
Getting started: the Query application............cccccsscescsessseecevsscascescesseaneesces 35
|
||
Hello Worl der. reco ws vissccascsave onaprreneserse tees ea SSS eaey Oe TOTES Oar Eee 35
|
||
To build the program ..........ccceceee jaw nadea@ads vies Sel seislesicu.c hts soewecus sa deawaretons vee 35
|
||
Errors: Guring-linking wssvecscvessceccvavesavecscressereer cere Corte rte wrt 36
|
||
Running the application from the Series 3 System Screen ..........0ccescceeee 36
|
||
Further explanation Of Qu1.C ........ccccsssssscsscscsseecssenscsecseasascestetescucensens 36
|
||
Suggestions for MOGifying QU1 .............ccceeccosscesceesseceeccsccasccusseeesteases 36
|
||
IntrOdUCING’ AGG «os caveneerdeienccbvconcciacesssiadigaresvaredsteslevsegess Aa loecastavaa sic 37
|
||
Suggestions for Modifying Qu2 ...........ccccsescescsscesecsecssccucnsrcsteecececeusess 37
|
||
A status Window and a MENU ba? ............cccscccececsecsccntecstscsceccnceseveseucs 37
|
||
Defining: the: menu.Dar.:.....5. ea ae ee 8 es a 40
|
||
The contents of ManageCommand...........ccccsscscsscsssccnscescectecseccesceeseess 40
|
||
Suggestions for modifying QUS:..cicc224 wdsscee desoveve eeaes dette eoksesyh cs 41
|
||
SUDPIYING ANSICON : 6.55 tsevcccsues ccecdeesssevacaasadts dove ccs Sc toee eR Oe Mes ee oa, 41
|
||
First examples in presenting dialogs .............ccccecesecsesececcecestsscescesseasees 41
|
||
Suggestionsformoditying*FileSizevrrsrrsrrstrt 43
|
||
A date editor in a dialog ..............cscssccseessoscneceveuccccccessuecascnscancrescencess 43
|
||
Choice lists and the time-text fUNCTIONS ............ccccscosccscsseccscsscescecescasss 44
|
||
A note on the start-up heap ............:ssssccsssscascescessesccssccceseccarscesscastens 46
|
||
Further COMMENtS ON CAUMP..........cccssccsscesceeccecscsccscerscsteecescesscaatensees 46
|
||
Suggestions for Modifying QU ............ccccsssceccececccsscececercncossanscescescess 46
|
||
FROMPAMGItO SAPP iicct.ccctescadesecececesosecesevecescuccssdedsadvslevciecncterecceetesrets 46
|
||
The floating point emulator sys$8087.ldd .............ccccescscereecoceeccecssceceas 47
|
||
Debugging a .app application .............ccccscccsceecsccsccuscascceecstcecacesuusence 47
|
||
Some responsibilities of being @ .ADP...........cccccescvecsecsecscscssesceecesessuees 48
|
||
Menu command look up - by accelerator or by index?..........-ccccsscesceneees 48
|
||
Example of floating point Editor ...........cccccccecscescsccscsescecssassvcencetencecens 50
|
||
Example of Numeric Editor ............cceccsscnscescecactecsecceccecscasoscusenranceeenens 50
|
||
Examples of other dialog items .............c2sssecescsscssceusccsccucuscasseeccascnscess 51
|
||
Suggestions for Modifying QUETY.............:cscsecoeseccensceeseeccscessscceccuscees 51
|
||
Getting serious: the Tables application.............cccccsccsccsccercecocssasssconsascnceecs 51
|
||
The state of the application...............c:sesccsccesscsecesseccescucsensauseecesanceeuess 52
|
||
Using an environment variable.............ccsccsssscuccecsccessescecscnsescaececaesereas 53
|
||
Memory consumption by environment variables ..............cccecoscerescescecees 53
|
||
Complications on reading environment variables ............c.ccscececececseececes 54
|
||
Suggestions for enhancing Tal ............ccccscessconccceccecsccesvessstensceseecececs 54
|
||
Laying out information on the SCree@M..............cccscsecoucecseccucscecssaeusaeseses 54
|
||
Laying out an action button and its associated text ..........ccceesesecerceereres 56
|
||
Positioning an action button vertically ...............ccccceecscocseecscsececscsccsones 56
|
||
|
||
|
||
CONTENTS
|
||
— SSeS
|
||
|
||
|
||
Animating the action Dutton ............cccscssceescuseevscececsecsecscessenceaceevscenses 57
|
||
Suggestions for-modifyingala2s!.c:fcscees. veer het hice Mc oeeens 57
|
||
Presenting, ancedit boxtreseerts: OM oat. a da.ccssstleeevies coves sierdtaieceh i thocicads 57
|
||
Generating random nNUuMbETS..........ccccscsssccuscesecceccescnsccecacceccestessavcaseess 58
|
||
Eurther comments Ongliagve.08 fetvccecdetcccess Meh carecuas eee MN eS soc 58
|
||
Suggestions for Modifying Tad .............cccseccssecssesccsseecscescasctsesceeseseacs 59
|
||
AOOINQUINFAPEIMEL cnaeereeei ys ceavasscecsk, Alasessasses teen an caltt co teeaieovecee esate. yee 59
|
||
Drawing the: bargauges....tretc tous! sac ccinccsatccasenes scocicct ae daccdlursearceetcoues 60
|
||
Limitation on debugging Tables...............cssscccsesscsecesecceccnscacensceencencacs 61
|
||
Suggestions for enhancing Tables ..............ccssssseccsscccsccsscccesscureseascens 61
|
||
The remaining example applications ...............cesecescosscevccssseccstacecuseeceuceecess 61
|
||
Resource file access with REMIND ...............scsssssccsesecsscescsccecccovscceces 61
|
||
|
||
|
||
3 Advanced Use of Hwif ..........ccsccosssecssscocesousncccsscccecsconesacnsstsccascrececesacsecessenece 63
|
||
BuIGing the HWit DCAry cas sadcssusincx teste. a te tencSeTeeeel ws ce Ot Mb Sov ccs 63
|
||
EXtending Witte: circu teee eae t iret te tecert ., dacs nee ete este tet a ID Fea ca ace 63
|
||
Combining Hwif with object oriented code ............cccccccsccsececcecesccascesccceesecs 63
|
||
Wsingia Se pardre OVE orcs errant cen wid sasyurcosinaccnts vost otastswiues secucoomeaesesn 64
|
||
Debugging*an HWIMDY Wirores..c.-caccucsevesaneatesacisssiseddess gh naswswsre stun tics cis 65
|
||
Modifying the HWif category ..........ccccsccseccseecesccsscecsescucescessessesasescenus 66
|
||
Access to a growing scroll bar from Hwif ..........:cccccseccsssseccececcesseccesceseusease 67
|
||
The application's category TilG acest Me escancsuar sie ccecs te ansee ees bone tacn eee ti ascciie 67
|
||
C_DONEWN items in dialogs ............ccccseccssccccavsccesecscescsccsccosseeseuceensce 68
|
||
The SE_DONEWN struct and the WN |_SET method of DONEWN ............. 69
|
||
The/BAR AO ractiverobject cnt tecvcsccivelscsurssisdcccecsattcen cto 69
|
||
Termination of the grow bar dialog...........cccsssssscccesecsssesesecesscsssseneeesens 70
|
||
GOmeralMCOMMeMtS cer. cron stacc tarde stac tsa tercuieties mest ccatcomccss tyes tuce hc vhewel«, 71
|
||
|
||
|
||
4 Hwif Reference Documentation................scccscsssssscsssccsasccasccossccsncesccacecsscecsesees 73
|
||
Overview of the Hwittibrary esraicsyuiestexcasaves tt re tineaddaneyencvveeevecivaccisadeeiveeis 73
|
||
Two levels within the h-layer Calls..............csssccsessccscsnsccescesssevscaseasccecs 73
|
||
Two layers within the u-layer calls .............cccccccseccessccsecsecersccsseaeceeecacs 73
|
||
Groups of functions and naming CONVENTIONS...........c.ccsscssceseccsercnscescece 73
|
||
Return values and error notification ..............ccscseseccecsccecesccssccscecscascece 74
|
||
Binary CountedrStrings: tri. Scticr. core ecccecesncceonccdsdeeccs uecusievccsscscductes 74
|
||
Dialog and menu interactions as a special Mode ..............csccsesccsscenccecees 74
|
||
The central functions in the u-layer Of HWif..............ccccccccscoccscecescarescvececses 74
|
||
Initialisation common to Hwif applications (uCommonlnit).............c0ccses 74
|
||
Enable use of grey (UEmableGrey) .............cccccescssesccsscessceveecessseesceceneees 76
|
||
Read a key, waiting for its delivery (UGetKey) .............ccccsscssceecasteecescecs 77
|
||
Read a keypress asynchronously (uGetKeyA)............-.-cecesesscoscsseeseccace 77
|
||
Cancel outstanding asynch’ keypress request (uCancelGetKeyA) ............ 78
|
||
Test if a keypress is outstanding (ukeyPressOutstanding) ..............csee0006 79
|
||
Convert accelerator into command index (uLocateCommand) .............0068 79
|
||
Present a set of menus (uPresentMenus)...........ssccsesesecesesccescsscescnsrscacs 81
|
||
Open a dialog (UOpenDialog) ..............ccsccsssccesessceuceeccesescseccnccesneceucecs 82
|
||
Run a dialog (URUNDial0g) ...............:0ccceeccesccusenceeestaceevsceseccuscesceecuswass 83
|
||
Dialogs and flashing CUISOMS ............ssscesecssscssccosecassovecesseceseuscesceecuteees 83
|
||
Add an action list to a dialog (uAddButtonList) ...............scecccessesscecececees 83
|
||
Add a choice list to a dialog (UAddChoiceList) ..............ccccecsseesecssececscecs 84
|
||
Add a general item to a dialog (UAddDialogltem) ..............cccecscaccsesceeeess 84
|
||
Text items in dialogs (HEDIALOGYIEXT) ©. SM Neleawtietecdescunticvenconss 85
|
||
Numeric editors in dialogs (H_DIALOG_ NUMBER) .............scsssssssssseesseees 85
|
||
Floating point editors in dialogs (H_ DIALOG MELOAT) ie ttvecedssasteetedeeseswees 85
|
||
Time editors in dialogs (H_DIALOG TIME) .........cccccccecececeecesssssseseveeseees 86
|
||
Date editors in dialogs (H_| “DIALOG MDA WE et iipncc at tity eecen dM vanteveeetixc: 86
|
||
Useful date:constants.........ces0seccseoftees cs Mtevete anes cosas sgcedes esas ectvebecvewsne 86
|
||
Non-scrolling text editors in dialogs (H_DIALOG_EDIT) .............:.cseeceseees 86
|
||
Scrolling text editors in dialogs (HEDIAWOGFSEDIN? <0 cec terest escaieotieues 87
|
||
Secret data input items in dialogs {H_ DIALOG _XINPUT). ........0ssessseesveess 87
|
||
Filename selectors and filename editors (H_ DIALOG FSEL). ..............0066 87
|
||
|
||
|
||
iii
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
iv
|
||
|
||
|
||
Begin a dynamic choice list (UBeginDCL)...............sccecsesecsecesscecscsceeesees 88
|
||
Add a choice to a dynamic choice list (UGrowDCL)............c.ccscsceesececeoes 88
|
||
Add a dynamic choice list to a dialog (UAddDCL) ...............0ccccescecescscees 88
|
||
Underline menu items with a grey line (uAddGreyUline) ..............csceeeeees 88
|
||
Underline dialog components (uSetDialogUline) ..............cccssescerecccecceceee 91
|
||
The auxiliary functions in the u-layer Of HWif ..............:ccescecesccscescesccceccscees 92
|
||
Disable/enable Escape processing (UESCape)............scecococcscsorsccesceccceses 92
|
||
Find ID of main window (UFindMainWid)............ccccececscssresceseeveccscsceenes 93
|
||
Force the application into foreground (UForceTOFront) .........ccccsesesesceeeee 93
|
||
Fail-safe presentation of an error string (UErrorString) .........ccscessseceseseeee 93
|
||
Fail-safe presentation of an error message (UErrorValue) .........0sceseseevenee 93
|
||
Check that a handle is non-zero (uCheckHandle) ............ccccccsecenscsovececes 93
|
||
Convert a ZTS to a BCS (UZTStOBCS) .............cccccecececovesscvcecscecsseeeseess 94
|
||
Present a menu-like dialog (UDialogMenu) ...............ccscssesscvcvcvcvescscaceess 94
|
||
Present a dialog containing textual information (uDisplayText) ............... 94
|
||
Time-text utility FUNCTIONS ..............cecsceccescenscscaveccteceescecssesscecasscsaseceseceses 95
|
||
Open a time-text channel (HTTOpen) ...........sccsccscscsescscsccscssessvcverensceces 95
|
||
Set time-text abbreviation lengths (hTTSetAbbreviations) ............cseseseees 95
|
||
Set time-text format (HTTSetFormmat) ...........cccccsnscssecssccecseccssecsenseseseecs 95
|
||
Set time-text time and date (HTTSetTime) ............cesecsccsecscsvcssscecscecncens 96
|
||
Sense string from time-text channel (hTTSenseString) .........ccceceessceceeees 96
|
||
Close a time-text channel (HTTClose) .............cccesesescececsovsvcteccveesseseeecs 97
|
||
Stand alone date/time text editor FUNCTIONS..............cccecscesevensecesccesecncseceess 97
|
||
Create a date/time text editor (HDTOpPEN)..........:csecccesccsnscsvccsssceccsseceses 97
|
||
Close date/time text editor (HDTClose) .............cccecssuccecsveovcveccscecsceseres 97
|
||
Set value in date/time text editor (HDTSet).............ccscsecseccvsscccveececessees 97
|
||
Retrieve value from date/time text editor (hDTSemse)............ccscsescseseves 97
|
||
Date/time text editor self-check (hDTSelfCheck)............cccssssecceceecseececs 97
|
||
Pass key to date/time text editor (hOTHandleKey) ................ccecesceesceeees 98
|
||
Emphasise date/time text editor (hDTEmphasise) ............cccscseossceecssseece 98
|
||
HDT xxx structs:(H: DTEDEM) icc. ccctascsesnseucissechevdgeessacdeseveteceecevossecneceses 98
|
||
hDiExxx structs: (HESE. DGEDIM).w.cciveibsesccnsicuscducnecchccereuesstscaveavevarnsves 99
|
||
Edit: DOX:fUNCHORS sys ccudies: Ricees tree Suerte he ete ence cette tt otrcscet conaarmnne 99
|
||
Open an edit box (NEBOpen) ............cccceceessscsecerestscotsescaucescecaseusaveveees 99
|
||
Pass a key to an edit box (hHEBHandleKey).............cscscscsesscccescssececcessees 100
|
||
Formatting in: bBaACKQroUNG :......cscseassteeccunsasskewacet fo0Ms cc ta cade eS baceve cous ves 100
|
||
Complete edit box formatting (hEBCompleteFormat) .............csesscssereseees 100
|
||
Sense the text in an edit box (REBSenseText)............cscecesesecscscescecescees 101
|
||
Set the text in an edit box (HEBSetText) .............cccscessescsscesescuscnsesescess 101
|
||
Emphasise an edit box (HEBEmphasise)............csscccscsssesessccccecscucesenceces 101
|
||
When edit boxes lose their CUrSOF ............ccscescscecscecessstoceesccoussscssereeees 101
|
||
Set edit box select and cursor (HEBSetSelect) .............cscesceccssecscecececeses 102
|
||
Sense edit box select and cursor (hEBSenseSelect) ..............ccecseesscereees 102
|
||
Sense edit box clipboard contents (hEBSenseClipText)..........ccccscessccsrees 102
|
||
Set edit box clipboard contents (HEBSetClipText) ............csccecsccssecsesneens 102
|
||
Change width of edit box (hEBChangeWidth)................csccecscscscccovecesees 102
|
||
Set width of edit box cursor (HEBSetCWidth) .............scccceecccevseeeesseseees 103
|
||
Insert text buffer into edit box (HEBInSert)..............ccccscsceccsccecscncsseeeees 103
|
||
Replace selection in edit box (HEBReplace) ................ccsccecoseressecesscseeees 103
|
||
Evaluate edit box expression (HEBEvaluate) .............ccesescessescscscecsceeseees 103
|
||
Copy function for edit box (NEBCOpy)............csscscesscecscsscescetscecscsencesens 103
|
||
Paste function for edit box (HEBPaste) .............ssesssscveccssecsccteseseeseeeeees 104
|
||
Find text within edit box (HEBFind).............ccscssssccesccscecccsaceccueseescunses 104
|
||
Clear edit box changed flag (hEBClearChanged) ............:sssesesececeesceseacs 104
|
||
Sense if edit box contents have changed (hEBSenseChanged)................ 104
|
||
Hide or show edit box symbols (hEBShowSymbols) .............cecscscsseeeeees 104
|
||
Close an edit box (HEBCloSe)...............scccccssrecatasccestescecsesvseerecesresscncs 105
|
||
Return handle of edit box document component (hEBSenseDoc) ............ 105
|
||
Set capacity of document component (HEDCapacity) .............cssceceseaeeees 105
|
||
Insert text into document component (HEDInsert).............sesecssecesseeceenes 105
|
||
Notify edit box that document has changed (hEBDocChanged)............... 105
|
||
Set word-wrap margin (NEBSetMargin) ...............scscecerecseseceseseeecesesenes 106
|
||
Sense word-wrap margin (HREBSenseMargin)..........scccescesssereceescecncererees 106
|
||
Convert position to line number and pixel offset (hREBPosToXL).............. 106
|
||
|
||
|
||
CONTENTS
|
||
—_—_—_—_—_—_ eeSeSeeSeFeFeFFFssFFSSSSeSSeSeSeSsSseF
|
||
|
||
|
||
Printing and print Support FUNCTIONS ............cccccsecccsseseccesssecenessensscceceescoese 107
|
||
Invoke Print Setup dialog (hPrintSetupDialog)...............ccssseseccosecseesescees 107
|
||
Invoke Printer Configuration Setup dialog (hPrinterSetupDialog).............. 107
|
||
PHNE Gata AiRrinth:22-vveracancsencevonssterac duaete cen crept tvecctacssusssMeg ies lacadven. 107
|
||
Word wrapping during printing.............cccssssccssssseccsesesccesccseescseseeseceess 108
|
||
Page breaks uring: PrINthd Acscct-ct 275sssaceseuseDicdcobeesasdberscndecs cocorscowce tics 108
|
||
Limitations during the PrintLine callback .............cccccccosececcoseceecccecscnesece 108
|
||
Set subsequent indent for printing (hPrintSetSl) ...............ccccesecesscoesseeee 109
|
||
Sense page width for printing (hPrintSensePageWidth) ................secccceeee 109
|
||
Sense printed width of buffer (hPrintSenseBufWidth) ...........c.cs.ccceesecceee 109
|
||
Advanced possibilities when printing .............cccccccssccsseccsesccccescesececceece 109
|
||
|
||
MiSCellaneOUs FUNCTIONS 5.02055 stand de eels poadeadecaimatatewsade dived aesincdoscncliccwaeee: 109
|
||
Crack the command line (hCrackCommandLine) ..............cseccsesceseceesecoee 109
|
||
Notify a change in the name of the file (hSetUpStatusNames) ................ 110
|
||
Ensure that the path exists for a filename (hEnsurePath)...............0..c008.. 110
|
||
Position a dialog (NDIgPosition) ..............ssccscseccecsesscecseccecsescrescceseunaces 110
|
||
Emit DTMF tones (HDTMFString)...........0ssscsssecesssssscccsseccesessueseueesencecs 111
|
||
Check if database file is compressible (hisDbfCompressible)................0.. 111
|
||
Access help engine (hHelpSubSystem)...............cccsecssecessscececnsececesseeecs 111
|
||
Help: FESOUrCE STFUCTUPES .6...016icisiceestecocsnsdsaneserccnescsevsvasccnecsevecacicesccce 112
|
||
|
||
PRELPEARRAY sncssadagauveedca rioters eigeducasauia seastansd Gueei dslanade the Caiawsehce 112
|
||
|
||
STEIN Go ace sore cain atisios atacoseusedveasdaudts coras'etiehagttvientnes place. teen Ge ceae ices 112
|
||
|
||
TORIC ARRAY cxicsec.fssatswts vecaxcacastelesond las sux ceessas layne t(lesaceueeues caus 112
|
||
Pass handle of Appl.Res.Channel (hDeclareAppReb)................0seceseceeeses 112
|
||
Open channel to resource file (hIMitAppReb) ..............sscccesecocccesceseesecees 112
|
||
Request insertion of resource file pack (hRequestReplacePack) ............... 113
|
||
Set system resource file language (hSetSystemResourceLang)................ 113
|
||
Set choice list to use a variable array(hSetVarrayInChlist) ..............c0..e00 114
|
||
Load applications'’s DYL(hLoadOwnDyl) .............ccccsescossecaseseeccsscssee sees 114
|
||
Get last key press(hLastSystemKey) ...........ccccsssceccscccsccersscesccecssecerecees 115
|
||
Call an object oriented dialog(hOODialog) ..............ccessescsssscccssccosscuscees 115
|
||
|
||
The low level h-layer FUNCTIONS .............ccsescccsesccuccesseccccecensccesssencsececeseseees 116
|
||
Menu bar interactions - OVervieW .........c.csccscsscccsescsseccrsccaceceecsessceseucens 116
|
||
Dialog interactions - OVErViEW...........cssssesccessscccsseesenscesonssescusecensceusees 116
|
||
Low level initialisation (HIFIMit) .............cccseccsssccessccosscessccencsenscoecesceusens 117
|
||
Open a menu card (hCardOpen) ............cccccsescesececsceccsscusescescesceccenscece 117
|
||
Add an item to a menu card (hCardAdd) ............ccccsccseccsscecscceesceseeseuscs 117
|
||
Close a menu card (hCardClose)...........:sscscssccsesscccreccnsscnsscesccesccesucesens 117
|
||
Open a menu bar (hMenuOpen) ............scccccssccccsseeccenscccrersceeecsenceunecees 117
|
||
Add a menu card to a menu bar (HMenUAdG)...............-cceccesecasceccesseuccs 117
|
||
Run a menu bar (HMenuRun) ............cssececsscesesecsseccvscctscceueccesceeseescaseus 118
|
||
Close a menu bar (hMenuClose).............sscccssscssseccessctseccnsesesceaccessnecees 118
|
||
Opera dialog: (HDIGOPeN) sacks sesscscenasseqsacane5, o's oneeddeusucusdesuenatedeadycet bs 118
|
||
Rui a dialog ARDIGRUA): visnnsin--svcarcsecsusseues suena dohssian ghuevaawncccdaxhoatdicorses 118
|
||
Close down an incomplete dialog (hDigClose) .............cccsesecceseccseceecseese 118
|
||
Add an item to a dialog (HDIGAd)...............cscsssccccnssecessscecnssececccesceenes 118
|
||
Open a choice list (hChoiceOpen) ...............sceccssceccussceseccssecesceseceeceaceas 118
|
||
Add an item to a choice list (hChOic@Add) ..............cesscccseccescceccescecseuces 118
|
||
Close an incomplete choice list (hChoiceClose)..............cesccoscssseceesevenecs 119
|
||
Open a button action list (hButtonOpen)..............:cssscsssccssscceceesceceescees 119
|
||
Add a button to an action list (hButtonAdd).............ccccsseccsescseceeceeceeeses 119
|
||
Close an incomplete action list (hButtonClose) ...............ccssccsecescesccescaee 119
|
||
|
||
|
||
CHAPTER 1
|
||
|
||
|
||
INTRODUCTION TO HWIF
|
||
|
||
|
||
LEE a ee ee SR
|
||
Overview
|
||
|
||
|
||
Hwif, the Handheld Wimp InterFace, is a library of user-interface routines for C programmers writing
|
||
applications for the Psion Series 3, Series 3a and Workabout. At the time of writing, no comparable
|
||
library exists for the HC or MC ranges of SIBO computers.
|
||
|
||
|
||
In this manual, references to the Series 3 should generally be taken also to refer to the Series 3a and the
|
||
Workabout. Cases where there are differences in behaviour between the various models are mentioned
|
||
|
||
|
||
explicitly.
|
||
|
||
|
||
Hwif makes it easy for programmers to present menus, dialog boxes, and edit boxes. Hwif also allows
|
||
programmers to tap into the abundant printing functionality of the Series 3 - and much more, beside.
|
||
|
||
|
||
Hwif is an interface library because it provides access to code that is already present in the Series 3
|
||
ROM. Applications which include calls to Hwif will find that the size of their code only increases
|
||
slightly as a result. This is in marked contrast to the case if an alternative user interface system is
|
||
developed. At the same time, the ROM-based user interface is likely to be more comprehensive and
|
||
robust than any such alternative user interface. Finally, users will instantly feel at home with the user-
|
||
interface presented by Hwif applications - since it is the same as that possessed by the applications built
|
||
into the Series 3.
|
||
|
||
|
||
Going beyond the issues of dialogs, menus, and edit boxes, Hwif assists programmers in writing
|
||
applications that conform to the wider responsibilities of applications on the Series 3 - in terms of
|
||
communicating information to and from the System Screen and the status window. This adds to the effect
|
||
of applications which behave just like the built-in ones.
|
||
|
||
|
||
On a more practical issue, Hwif simplifies many of the initial programming choices facing would-be
|
||
Series 3 programmers. One particular method of interfacing to the Window Server is selected over all
|
||
others, and one particular method of structuring responses to external events is highly recommended.
|
||
These choices out of the way, programmers can concentrate, in the meantime, upon acquiring familiarity
|
||
with many of the other aspects of the Series 3 ROM software. In due course, programmers may wish to
|
||
re-evaluate the choices made for them by Hwif, and may choose to take alternative decisions (for
|
||
example, a different interface to the Window Server). In the meantime, Hwif helps programmers get off
|
||
to a flying start.
|
||
|
||
|
||
Learning to program in Hwif
|
||
The documentation for Hwif consists of three chapters: overview, worked examples, and reference.
|
||
|
||
|
||
= The current chapter gives an overview of the scope of Hwif, and of the basic programming ideas
|
||
it embodies; generally speaking, this is the chapter that should be read first
|
||
|
||
|
||
= The chapter Hwif reference guide presents a factual documentation of all the functions available
|
||
in the Hwif library; generally speaking, this is the chapter that should be read last
|
||
|
||
|
||
= The chapter entitled Worked examples in Hwif contains a more discursive account of how these
|
||
library functions can be used, in the context of a series of example programs.
|
||
|
||
|
||
The associated example applications are an integral part of learning to program in Hwif. As well as
|
||
illustrating access to the built-in menu and dialog system, they also contain many demonstrations of how
|
||
to use other, wider parts of the rich ROM software the Series 3 provides. To start with, the examples are
|
||
built up in stages, to make them easier to understand. The very first example is built up in stages right
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
from the very beginning (an Hwif version of the Hello World program), with ample discussion of such
|
||
topics as programming environment, and how to "build" ("make") an application. The later examples
|
||
embody considerable sophistication and an extensive use of the Series 3 ROM software - enough to keep
|
||
even the most avid of would-be Hwif programmers busy for quite some time.
|
||
|
||
Comparisons with OPL/w and with OOP
|
||
|
||
|
||
There are in fact three choices for programmers wishing to hook into the Series 3 built-in menu and
|
||
dialog system:
|
||
|
||
|
||
= Write in OPL/w, the Wimp extension of OPL
|
||
# Write in traditional C, using routines in the Hwif library
|
||
|
||
|
||
= Write in Psion's proprietary object-oriented extension of C, interacting much more directly with
|
||
the object classes in the ROM.
|
||
|
||
|
||
The advantages of OPL/w are:
|
||
|
||
|
||
= OPL programs can be written and debugged on the Series 3 itself, without any additional
|
||
hardware or software tools
|
||
|
||
|
||
= OPAL is a protected environment, automatically handling runtime errors so that they do not cause
|
||
an application crash (or even a system crash)
|
||
|
||
|
||
= Some programmers find the syntax of OPL less intimidating than that of C
|
||
|
||
= OPL provides a convenient layer over the raw database file functionality provided by the OS.
|
||
On the other hand, writing in C has the following gains:
|
||
|
||
= The code executes more swiftly
|
||
|
||
= Cis a richer programming environment, with abstract data structures, pointers, and typedefs
|
||
|
||
= It is generally much simpler to call routines in the OS from C than from OPL
|
||
|
||
= C allows access to a wider range of printing and editing support utilities
|
||
|
||
= Programmers with experience of C have no need to learn OPL
|
||
|
||
|
||
= Code written in C for other products on other hardware can obviously be converted more
|
||
quickly into C for the Series 3 than into OPL for the Series 3
|
||
|
||
|
||
= Conversely, code written in C for the Series 3 is more likely than OPL code to have parts that
|
||
are portable fo other projects; in this sense, programming in C is a better long-term investment.
|
||
|
||
|
||
As far as functional access to menus and dialogs goes, there is little of substance to choose between
|
||
OPL/w and Hwif. For greater control over menus and dialogs, programs have to be written in object-
|
||
oriented C. This is discussed in its own manual.
|
||
|
||
|
||
Compared to the full object-oriented approach, Hwif is a significantly simpler programming system;
|
||
nevertheless, it allows the creation of powerful and attractive applications. As evidence of this, a series
|
||
of realistic example applications accompany this manual, each written using Hwif. These applications
|
||
are all serviceable utilities that are likely to be found useful, either as they stand, or after an element of
|
||
customisation. But they by no means exhaust the scope of what can be achieved using Hwif. Indeed, each
|
||
example is deliberately constructed in such a way that an enterprising developer could enhance it
|
||
considerably. To this end, the discussions on each example contain numerous suggestions as to how the
|
||
application could be modified and extended.
|
||
|
||
|
||
Recognising Hwif function calls
|
||
|
||
|
||
Hwif library calls all have names starting either with lower case u or lower case h. For example,
|
||
uCommoninit, uGetKey, hPrintSetupDialog, and hDlgPosition.
|
||
|
||
|
||
In the code fragments below, routines supplied by the application have names starting with upper case
|
||
letters. For example, specificinit, MainLoop, and ManageCommand.
|
||
|
||
|
||
Routines with names starting with lower case w or lower case g are part of Wlib, the Window Server
|
||
library. Plib functions have names starting with p_ (or sometimes f_ or Dbj).
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
SSNS
|
||
|
||
|
||
The connection to the Window Server
|
||
|
||
|
||
The type of connection made by Hwif to the Window Server is actually via the console device (discussed
|
||
further in a later section). Although this will be of little concern to most Hwif programmers, several
|
||
points about the nature of this connection should be stated (particularly for the sake of those
|
||
programmers already familiar with the contents of the Window Server manual):
|
||
|
||
|
||
= The connection is made w_CONNECT_DISABLE_LEAVES - removing the need to enclose WIib calls in
|
||
p_enter harnesses. When an error occurs in a Wlib call (such as lack of system memory for the
|
||
request to be carried out), a simple error value is returned, rather than a call to p_leave being
|
||
made.
|
||
|
||
|
||
= The connection is made W_CONNECT_PRIORITY - so that the priority of the application is
|
||
automatically adjusted, as standard, whenever the application passes into foreground or
|
||
background.
|
||
|
||
|
||
= The connection creates a window the full size of the Series 3 or Series 3a screen, with its own
|
||
backed bitmap - so that Hwif programmers have no need to concern themselves with processing
|
||
redraw requests. Note that the Series 3a screen can emulate the Series 3 screen.
|
||
|
||
|
||
————E EEE ene SS eee
|
||
|
||
|
||
The general shape of Hwif programs
|
||
All Hwif programs can have the following for their main routine:
|
||
|
||
|
||
GLDEF_C VOID main(VOID)
|
||
€
|
||
uCommonI nit);
|
||
SpecificInit();
|
||
MainLoop();
|
||
>
|
||
|
||
|
||
The library routine uCommeninit performs initialisation that is common to all Hwif programs, such as
|
||
connecting to the Window Server, and creating control blocks for subsequent menu and dialog
|
||
interactions. A routine such as SpecificInit would be supplied by the program itself, to carry out
|
||
initialisation specific to the particular application, prior to getting down to the real business of the
|
||
program. Finally, a routine such as MainLoop (also supplied by the program) is where this real business is
|
||
handled.
|
||
|
||
|
||
Hwif programs can usefully be viewed as consisting, in their steady state, of a series of responses to
|
||
events. Accordingly, the routine MainLoop can always have the general shape
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VvoiD)
|
||
|
||
|
||
{
|
||
|
||
FOREVER
|
||
€
|
||
GetEvent();
|
||
ProcessEvent();
|
||
}
|
||
|
||
>
|
||
|
||
|
||
More flesh is placed on this skeleton in the sections immediately following.
|
||
The program terminates in response to suitable user-input, probably with a call
|
||
p_exit (0);
|
||
|
||
|
||
inside a routine such as ProcessEvent.
|
||
|
||
|
||
———SSS—_SS—S EE ee a a
|
||
Processing events
|
||
|
||
|
||
Types of events
|
||
Among the types of events that a program might process are:
|
||
|
||
|
||
= menu command hot keys, of the PSION+X variety
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
SS
|
||
|
||
|
||
= other keys with special meaning for the program, such as cursor keys or alphanumeric input
|
||
|
||
|
||
= system messages such as notification of passing into foreground or background, or the Series 3
|
||
being turned off and then on again
|
||
|
||
|
||
= messages from the System Screen for the application to close down, or to change the file
|
||
currently being used
|
||
|
||
|
||
= the expiry of timers or alarms
|
||
e the receipt of data via the serial channel.
|
||
These events can in fact be classified into just two types:
|
||
= those received as a result of reading a keypress
|
||
= others - of which only the last two in the earlier list count.
|
||
|
||
|
||
The point is that foreground and background messages, on the one hand, and messages from the System
|
||
Screen, on the other, are both received by Hwif applications as special sorts of keypresses (ones with
|
||
specially recognisable values of the keycode). (What is going on here is that the console device is
|
||
converting all Window Server events to otherwise unused keycodes).
|
||
|
||
|
||
This leads to a particularly simple form for the routine MainLoop:
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
|
||
|
||
€
|
||
WMSG_KEY key; /* to receive key press */
|
||
FOREVER
|
||
€
|
||
uGetKey(&key);
|
||
if Ckey.keycode&W_EVENT_KEY)
|
||
€
|
||
zee /* process system message */
|
||
else if (key.keycode&W_SPECIAL_KEY)
|
||
{
|
||
ane /* process menu command hot key */
|
||
else
|
||
{
|
||
iaia /* switch statement on other keys of interest */
|
||
>
|
||
3
|
||
|
||
|
||
The routine MainLoop can have this form for all applications in which there are no events to process, other
|
||
than those received as keypresses.
|
||
|
||
|
||
An application can of course omit the test
|
||
if (key. keycode&W_EVENT_KEY)
|
||
|
||
|
||
if it has no special action to take on passing into foreground or background, or on the Series 3 being
|
||
switched on, or on receipt of any messages from the System Screen.
|
||
|
||
|
||
An application can likewise omit the test
|
||
if (key. keycode&W_SPECIAL_KEY)
|
||
|
||
|
||
if it has no menu bar (for example, if it is only using Hwif in order to access its dialog functionality).
|
||
|
||
|
||
Programs with event sources other than keys
|
||
|
||
|
||
Consider a program in which there are events other than keypresses. For example, a Spy program giving
|
||
information about all applications currently running on a Series 3 might update its display regularly, on a
|
||
timer - to ensure that the display keeps up to date with what is happening in all the different applications.
|
||
|
||
|
||
In such a case, the program cannot know in advance, at any one time, which of the two events will occur
|
||
first: the receipt of a keypress, or the expiry of the timer.
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
oS eS
|
||
|
||
|
||
Accordingly, the synchronous call uGetkey must be replaced by the asynchronous call uGetKeyA. This
|
||
latter call takes an additional parameter - the address of a status word that is written to when a keypress is
|
||
in due course received. If on the other hand the timer expires without a keypress being received, it is the
|
||
status word of the timer that is written to.
|
||
|
||
|
||
The status word is set to E_FILE_PENDING when the call uGetKeya is made, and is set to zero when there is a
|
||
keypress ready to deliver. Maintoop in this case acquires the following form:
|
||
|
||
|
||
LOCAL_D WORD timstat;
|
||
LOCAL_D WORD keystat;
|
||
LOCAL_D WORD keyact ive=FALSE;
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
€
|
||
WMSG_KEY key;
|
||
|
||
|
||
FOREVER
|
||
€
|
||
if Ckeyactive)
|
||
wFlush(); /* flush any outstanding graphics calls */
|
||
else
|
||
€
|
||
uGetKeyA(&keystat ,&key);
|
||
keyact i ve=TRUE;
|
||
>
|
||
p_iowait(); /* wait for something to happen */
|
||
if Ckeystat==E_FILE_PENDING)
|
||
€
|
||
aon /* the timer must have expired */
|
||
else
|
||
€
|
||
keyactive=FALSE;
|
||
a /* proceed as above */
|
||
>
|
||
>
|
||
>
|
||
|
||
|
||
This is more complicated than the preceding version (in which there is only one event source) in each of
|
||
two ways:
|
||
|
||
|
||
= the single line of code with the call uGetkey has been replaced by a series of lines that calls either
|
||
uGetKeyA or the Window Server routine wr lush, and then in either case calls p_iowait
|
||
|
||
|
||
= — the code that determines the action appropriate to the keypress that has just been received now
|
||
has to stand alongside additional code that determines, by means of tests on status words,
|
||
whether a keypress has indeed been received, or whether it is another sort of event that needs to
|
||
be processed.
|
||
|
||
|
||
An application with more than two event sources will have a correspondingly enriched set of tests on
|
||
Status words, in order to find the event source which has delivered an event. On the other hand, there is
|
||
no further complication over the GerEvent part of the routine - this remains as in the above example.
|
||
Active and inactive event sources
|
||
|
||
|
||
Note that applications using the asynchronous call uGetkeyA need (on pain of being panicked) to keep
|
||
track of whether they already have a so-called outstanding read for a keypress. In the above example,
|
||
this is handled by the variable keyactive:
|
||
|
||
|
||
= every time round the main loop, the call uGetkeyA should be made only if keyactive is FALSE
|
||
= keyactive is initialised as being FALSE
|
||
|
||
= every time uGetKeya is called, keyactive is set TRUE
|
||
|
||
= every time a keypress is actually received, keyactive is set FALSE again.
|
||
|
||
|
||
Similar care must be taken for any other asynchronous event source. Thus the above program would
|
||
probably have a variable timactive too (the code that primes the timer is missing from the above listing).
|
||
In general, event sources do not take kindly to being asked more than once to deliver an event, without
|
||
|
||
|
||
ees
|
||
5
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
OO -- rr eee
|
||
|
||
|
||
an event being delivered in the meantime. This is regarded as evidence of faulty program logic,
|
||
deserving of a panic.
|
||
|
||
|
||
Of course, it would be possible to simplify the above code example, dispensing with the explicit
|
||
variables keyactive and timactive: the call uGetkeya could be made at once, when a keypress is received,
|
||
instead of setting the variable keyactive to FALSE. However, this is not recommended in general. In
|
||
practice, as a program grows to contain more event sources, it becomes ever easier to keep track of which
|
||
are active by using xxxactive variables, instead of by ad hoc program logic.
|
||
|
||
|
||
The need to flush the Window Server command buffer at least once each time round the main loop also
|
||
counsels in favour of locating the call uGetkeya as advised above. (Reading a key, whether synchronously
|
||
or asynchronously, automatically causes the command buffer to be flushed. It is only when a non-
|
||
keypress event has been received that an explicit call to flush the buffer is required.)
|
||
|
||
Active words and status words contrasted
|
||
|
||
|
||
Note carefully that the active word and the status word of an event source serve two different purposes:
|
||
|
||
|
||
= the active word records whether a request has been made to the event source to deliver an event
|
||
when one is available
|
||
|
||
|
||
= the status word records whether an event has in fact been delivered
|
||
= the active word is written to by the application itself, when it requests the delivery of an event
|
||
= — the status word is written to by code other than in the application - for example, by a timer wait
|
||
handler routine (when a timer expires), or by the Window Server process (when a key is to be
|
||
delivered).
|
||
uGetKey and uGetKeyA compared
|
||
As may be surmised, the call
|
||
uGetKey(&key);
|
||
is effectively equivalent, in programs with no other event sources, to
|
||
WORD keystat;
|
||
uGetKeyA(&keystat, &key);
|
||
P_iowait();
|
||
|
||
|
||
However, in programs with more than one event source, the call uGetKey will return only when a keypress
|
||
has been received (this includes quasi-keypresses such as coming info foreground), whereas the call
|
||
p_iowait will return when any event is ready to be serviced.
|
||
|
||
|
||
Accordingly, what uGetKey strictly corresponds to is
|
||
WORD keystat;
|
||
uGetKeyA(&keystat , &key);
|
||
p_waitstat(&keystat);
|
||
since p_waitstat returns only when the event associated with the passed status word has indeed expired -
|
||
regardless of whether other events expire in the meanwhile.
|
||
Deferred processing
|
||
|
||
|
||
An independent way in which the structure of a program's MainLoop can be developed is via a call which
|
||
simply checks if a keypress has been received, without actually delivering it. In case no keypress has
|
||
been received yet, the program might continue with some intensive processing, whereas if a keypress is
|
||
outstanding, that processing might be deferred until the keypress has been dealt with.
|
||
|
||
|
||
For example, suppose an icon is being re-positioned on the screen by cursor keystrokes, and that drawing
|
||
the icon in its new position is time-consuming. To increase performance, a programmer might decide to
|
||
draw the icon in its current position only if the user has ceased pounding on the cursor keys. Thus
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
——_— Se eee
|
||
|
||
|
||
UpdatePending=FALSE;
|
||
|
||
|
||
FOREVER
|
||
|
||
€
|
||
|
||
uGetKey(&key);
|
||
|
||
switch (key. keycode)
|
||
€
|
||
ek /* may set UpdatePending */
|
||
>
|
||
|
||
if (UpdatePending && !uKeyPressOutstanding())
|
||
€
|
||
Drawlcon(); /* time consuming */
|
||
UpdatePending=FALSE;
|
||
>
|
||
|
||
>
|
||
|
||
|
||
Programs with more than one get-event loop
|
||
|
||
|
||
Many programs possess more than one mode. In different modes, various keypresses can have different
|
||
meanings. Thus an icon designer program might have a special mode in which cursor keys Teposition a
|
||
selected portion of the screen, whereas ordinarily, cursor keys might simply reposition the current
|
||
drawing point. Again, a database program may have one mode in which records are being found, and
|
||
another in which records are being added or updated. As another example, an agenda program may have
|
||
one mode in which a month view is presented, and another in which a day view is presented.
|
||
|
||
|
||
There are in fact two different approaches to programming in more than one mode:
|
||
= have different get-event loops for each mode
|
||
|
||
|
||
= — just have one get-event loop, and keep state variables to decide the appropriate response to
|
||
various incoming events.
|
||
|
||
|
||
To illustrate the first approach, consider again the case of an icon designer application which enters a
|
||
special mode on receipt of a designated menu command. This could be programmed as follows:
|
||
|
||
|
||
LOCAL_C MainLoop(VOID)
|
||
|
||
|
||
{
|
||
FOREVER
|
||
€ /* outer get-event loop */
|
||
1FGeSS) /* designated menu command received */
|
||
€
|
||
SetUpSpecialMode();
|
||
FOREVER
|
||
€ /* an inner get-event loop */
|
||
> /* exit this loop on certain conditions */
|
||
TidySpecialMade():
|
||
>
|
||
}
|
||
|
||
|
||
In practice, the code responding to the designated menu command would probably be isolated in its own
|
||
separate subroutine.
|
||
|
||
|
||
Again, an agenda application with two different modes might in theory be structured as follows:
|
||
|
||
|
||
LOCAL_C VOID MonthViewMainLoop(VOID)
|
||
|
||
|
||
€
|
||
FOREVER
|
||
|
||
a
|
||
|
||
} /* exits loop only when user transitions out of month view */
|
||
>
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
SS
|
||
|
||
|
||
LOCAL_C VOID DayViewMainLoop( VOID)
|
||
|
||
|
||
€
|
||
FOREVER
|
||
€
|
||
> /* exits loop only when user transitions out of day view */
|
||
>
|
||
LOCAL_C VOID OverallMainLoop(VOID)
|
||
€
|
||
FOREVER /* start up in month view */
|
||
€
|
||
MonthViewMainLoopt);
|
||
DayViewMainLoop();
|
||
}
|
||
3
|
||
|
||
|
||
To compare the two approaches to programming in more than one mode:
|
||
|
||
|
||
= Programming with more than one get-event loop is generally easier: relevant state variables
|
||
(such as might be initialised in a routine like setupSpecialMode referenced above) can be kept on
|
||
the stack
|
||
|
||
|
||
= However, it is only possible to go so far with more than one get-event loop; as programs
|
||
become more complicated, just having one get-event loop becomes an ever better design
|
||
decision.
|
||
|
||
|
||
In particular, a program with more than one get-event loop may founder on account of the large overhead
|
||
of maintaining shared common processing between the different loops. Thus testing for special events
|
||
such as
|
||
|
||
|
||
= a message from the System Screen to terminate the application
|
||
= notification that the Series 3 has been switched on
|
||
® the expiry of timers or the receipt of data via the serial channel
|
||
|
||
|
||
could well be largely independent of which mode the application is in. As a result, logic would have to
|
||
be duplicated at the tops of the various possible get-event loops.
|
||
|
||
|
||
Incidentally, it is sometimes appropriate to disable some kinds of events when transiently entering a
|
||
certain mode. Thus messages from the System Screen to terminate the application or to change the
|
||
currently open file can be disabled by the simple line of code
|
||
|
||
|
||
DatLocked=TRUE;
|
||
in which case, in the System Screen, the user will be informed that the application is "busy" on any
|
||
attempt to close it down or to change the file being used.
|
||
Diamond key
|
||
The following discussion on the diamond key applies exclusively to the Series 3a.
|
||
In the previous section, the idea of programs possessing more than one mode was discussed.
|
||
The concept is used in the built-in applications such as agenda and data.
|
||
|
||
|
||
Commonly, applications switch to a particular mode when the corresponding key press event occurs. For
|
||
example, the agenda built-in application switches to Week View mode when the PSION+SHIFT-+W
|
||
keypress is received.
|
||
|
||
|
||
On the Series 3a, the diamond key is used in the built-in applications to cycle around the various modes.
|
||
Further, the built-in applications also allow the user to select which modes are to be included in the
|
||
cycle.
|
||
|
||
|
||
An Hwif program can also make use of the diamond key in this way simply by checking for the diamond
|
||
key in its main event loop (or the appropriate event loop if more than one is used) and taking suitable
|
||
action.
|
||
|
||
|
||
If a status window is displayed, the icon can be replaced by a list of modes. Optionally, a diamond
|
||
symbol can be used to highlight the mode which is currently active and can be a useful visual aid.
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
eS
|
||
|
||
|
||
This is achieved by using the window server functions wsSetList and wsSelectList (see the General
|
||
Window Server Functions chapter in the Window Server Reference manual).
|
||
|
||
|
||
The following simple example resizes the main console window and displays a permanent status window
|
||
alongside together with a list of three modes. Pressing the diamond key successively, causes the position
|
||
of the diamond symbol in the status window to be shifted to lie alongside “mode-B" and then "mode-C"
|
||
and then back to “mode-A” again.
|
||
|
||
|
||
Aside from the visual confirmation of a mode switch, the actual meaning and implementation of the
|
||
switch is application dependent.
|
||
|
||
|
||
#include <p_std.h>
|
||
#include <wlib.h>
|
||
#include <hwif.h>
|
||
|
||
|
||
GLREF_D UWORD _UseFullScreen;
|
||
|
||
|
||
LOCAL_D WORD keystat;
|
||
LOCAL_D INT gc;
|
||
|
||
|
||
LOCAL_D UINT modepos
|
||
|
||
LOCAL_D TEXT * modelist{}
|
||
€
|
||
"mode-A",
|
||
"mode-B",
|
||
“mode-C",
|
||
3;
|
||
|
||
|
||
et
|
||
2
|
||
|
||
|
||
LOCAL_C VOID ReduceMainWin(VOID)
|
||
{
|
||
P_EXTENT StatusExtent;
|
||
W_WINDATA wd;
|
||
|
||
|
||
wiInquireStatusWindow(W_STATUS_WINDOW_BIG,&StatusExtent);
|
||
|
||
|
||
wd.extent.tl.x = 0;
|
||
|
||
wd.extent.tl.y = 0;
|
||
|
||
wd.extent.width = 480 - StatusExtent.width:
|
||
wd.extent.height = 160;
|
||
|
||
|
||
wSetWindow(uF indMainWid¢),W_WIN_EXTENT, awd):
|
||
>
|
||
|
||
|
||
LOCAL_C VOID SpecificInit¢(VOID)
|
||
€
|
||
ReduceMainWin();
|
||
wStatusWindow(W_STATUS_WINDOW_BIG);
|
||
gc = gCreateGCO(uFindMainwid¢));
|
||
gBorder2(W_BORDER_TYPE_0,W_BORD_CORNER_4);
|
||
wsSetList(3,&model ist [0] ,modepos) ;
|
||
>
|
||
|
||
|
||
LOCAL_C VOID SwitchMode(VOID)
|
||
{
|
||
modepos++:
|
||
modepos %= 3;
|
||
wsSelectList(modepos);
|
||
/* ... application specific mode switch code ... */
|
||
>
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
——]——— KK eSSSSSSSsFSFSFSSSSSSSSSSSSSSSeeeSSSSSSSSSSSSSSSeF
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
€
|
||
WMSG_KEY key;
|
||
|
||
|
||
FOREVER
|
||
€
|
||
uGetKeyA(&keystat, &key);
|
||
P_iowait();
|
||
if (key. keycode & W_SPECIAL_KEY)
|
||
€
|
||
key. keycode &= (“W_SPECIAL_KEY);
|
||
if (key. keycode == 'x')
|
||
p_exit(0);
|
||
>
|
||
else if (key.keycode == W_KEY DIAMOND)
|
||
SwitchMode( );
|
||
>
|
||
>
|
||
|
||
|
||
GLDEF_C VOID main(VOID)
|
||
€
|
||
_UseFul Screen = TRUE;
|
||
uCommonInit();
|
||
SpecificInit();
|
||
MainLoop();
|
||
}
|
||
|
||
|
||
Note that setting _UseFul Screen to be TRUE indicates that this code is intended to be run on either the
|
||
Series 3 or the Series 3a. For a full explanation of the significance of the variable Useful screen, see the
|
||
description of the function uCommontnit in the Hwif Reference Documentation chapter.
|
||
|
||
|
||
SS EEE] _— SS eee]
|
||
Menu bar interactions
|
||
The way an Hwif application initiates a menu bar interaction is simply to make the call
|
||
uPresentMenus()
|
||
where there are no explicit parameters.
|
||
|
||
|
||
The actual contents of the menu bar are communicated implicitly via the static variables _cmds and _mdata
|
||
which various Hwif library calls expect to access. The application must ensure that these point to
|
||
appropriate tables.
|
||
|
||
|
||
In brief, _cmds is the address of a table of the text names and accelerators of all the current menu
|
||
commands of the application, and _mdata is the address of another table giving the names of the menu
|
||
tiles, and how many commands there are in each tile.
|
||
|
||
|
||
Where _cmds must point
|
||
For example:
|
||
|
||
|
||
LOCAL_D TEXT *cmds[]=
|
||
€
|
||
"nNew file",
|
||
"oOpen file",
|
||
"“aSave as",
|
||
"iInsert",
|
||
"eCopy",
|
||
"fFrame off",
|
||
"XExit",
|
||
NULL
|
||
3;
|
||
|
||
|
||
GLDEF_D TEXT ** _cmds=(&cmds [01 );
|
||
|
||
|
||
This defines a menu bar currently with 7 menu items.
|
||
|
||
|
||
10
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
|
||
|
||
eee
|
||
Note carefully:
|
||
= The text for each menu item starts with its accelerator
|
||
|
||
|
||
= The entire list is terminated by a NULL.
|
||
|
||
|
||
Where _mdata must point
|
||
|
||
|
||
For example, suppose that the above commands are split up into a "File" menu (the first three), an “Edit”
|
||
menu (the next two), and a "Special" menu (the last two). Then the following definitions would be
|
||
appropriate
|
||
|
||
|
||
LOCAL_D H_MENU_DATA mdata[]=
|
||
€
|
||
"File" 3,
|
||
"Edit",2,
|
||
"“Special",2,
|
||
NULL
|
||
3
|
||
|
||
|
||
GLDEF_D H_MENU_DATA * _mdata=(&mdata[0]);
|
||
Note that:
|
||
= Again, the data is terminated by a NULL
|
||
= The individual entries (one per menu tile) are given in the form of an H_MENU_DATA struct, which
|
||
simply contains a TEXxT* followed by a UWORD.
|
||
How to use uPresentMenus
|
||
|
||
|
||
If the user cancels, or if an error has occurred (eg out of memory), uPresentMenus returns 0. Otherwise, it
|
||
returns the accelerator of the item chosen.
|
||
|
||
|
||
Accordingly, uPresentMenus is normally called in the following context:
|
||
|
||
|
||
LOCAL_C VOID TryExecuteCommand(INT keycode)
|
||
C
|
||
keycode=uLocateCommand( keycode):
|
||
if (keycode>=0)
|
||
ManageCommand( keycode);
|
||
|
||
|
||
>
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
€
|
||
INT ret;
|
||
FOREVER
|
||
€
|
||
uGetKey(&key);
|
||
if (key. keycode&W_SPECIAL_KEY)
|
||
TryExecuteCommand( key. keycode&(“W_SPECIAL_KEY));
|
||
else if (key. keycode==W_KEY_MENU)
|
||
€
|
||
ret=uPresentMenus();
|
||
if (ret>0)
|
||
TryExecuteCommand(ret);
|
||
>
|
||
else ...
|
||
>
|
||
>
|
||
|
||
|
||
That is, a menu bar interaction is initiated in response to receipt of a MENU keypress. The result, if
|
||
positive, is dispatched to the Hwif library routine uLocateCommand, which converts the accelerator to an
|
||
index into the current table of menu commands (as pointed to by _cmds). Finally, inside the routine
|
||
ManageConmand, a switch statement (or equivalent) on the index is performed.
|
||
|
||
|
||
Note that there are two routes to the routine ManageCommand:
|
||
|
||
|
||
= the route via receipt of the MENU key and the presentation of the menu bar
|
||
|
||
|
||
11
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
= the route whereby the hot key is received directly, in the form PSION -+ ACCELERATOR.
|
||
|
||
|
||
In the latter case, the bit w_SPECIAL_KEY is set in key.keycode, so that the user's presumed intention of
|
||
invoking a menu command via its accelerator can be detected early inside any get-event loop. This bit has
|
||
to be masked out before the contents of the keypress is analysed by the routine uLocateCommand. In case
|
||
the user has typed PSION together with an accelerator that does not currently exist for the application, the
|
||
routine uLocateCommand returns -1. Otherwise, as stated above, it returns an appropriate index into the
|
||
table of menu commands.
|
||
|
||
|
||
The ManageCommand routine
|
||
|
||
|
||
The ManageCommand routine of an application is one of its most important ones, ranking alongside MainLoop
|
||
and (to a lesser extent) main itself as the locus of the controlling logic of the program.
|
||
|
||
|
||
For clarity, it seems best if the contents of ManageCommand just call other routines where the real work of
|
||
each of the different menu commands is executed. This leaves ManageConmand as, primarily, an extended
|
||
switch statement, branching on the command index number.
|
||
|
||
|
||
Changing menu bar contents dynamically
|
||
There are at least two methods of dynamically changing the contents of the menu bar.
|
||
|
||
|
||
In the first method, two different sets of tables could be declared, and the values of _cmds and _mdata be
|
||
changed when required. This might be appropriate for an application with two modes that differ
|
||
distinctly from each other.
|
||
|
||
|
||
Alternatively, for a more modest change, code such as the following suffices:
|
||
|
||
|
||
cmds [5]=(show_frame? "fFrame off": "fFrame on");
|
||
|
||
|
||
Restrictions on valid accelerators
|
||
|
||
|
||
On the Series 3, the allowed values for accelerators are the 26 lower case letters 'a' through 'z', together
|
||
with the four arithmetic operator keys, '+', '-', '*’, and '/' (though some of the last four values may
|
||
change to something else on a non-English keyboard version).
|
||
|
||
|
||
On the Series 3a and Workabout, however, the allowed values for accelerators are all those allowed for
|
||
the Series 3 plus the upper case letters 'A' through 'Z'.
|
||
|
||
|
||
It is not possible to specify a menu command without an accelerator. This means that at any one time, an
|
||
application is limited to 30 first level menu commands on the Series 3 and 56 first level menu commands
|
||
on the Series 3a and Workabout.
|
||
|
||
|
||
To handle upper case accelerators correctly, the MainLoop code fragment above could be changed as
|
||
follows:
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
€
|
||
INT ret;
|
||
INT code;
|
||
|
||
|
||
FOREVER
|
||
€
|
||
uGetKey(&key);
|
||
if (key. keycode & W_SPECIAL_KEY)
|
||
¢
|
||
code = key.keycode & (“W_SPECIAL_KEY);
|
||
if (key.modifiers & W_SHIFT_MODIFIER)
|
||
code = p_toupper(code);
|
||
TryExecuteCommand( code);
|
||
>
|
||
else if (key.keycode == W_KEY_MENU)
|
||
€
|
||
ret = uPresentMenus();
|
||
if (ret > 0)
|
||
TryExecuteCommand( ret);
|
||
>
|
||
else ...
|
||
|
||
|
||
12
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
SESS
|
||
|
||
|
||
Grey underlining
|
||
|
||
|
||
Built in applications have the ability to add grey lines undemeath menu items. This serves to group
|
||
related menu items and can be a useful visual aid if used sparingly.
|
||
|
||
|
||
Note that grey need not be enabled for the main console window in order for this to work.
|
||
|
||
This feature is available on the Series 3a and Workabout, but not on the Series 3. It is discussed more
|
||
fully in the Hwif Reference Documentation chapter.
|
||
|
||
Menu positions
|
||
|
||
|
||
The position of the menu item currently selected can be recorded by making use of the global variable
|
||
_MenuPositions.
|
||
|
||
|
||
This is particularly useful in an application where more than one menu bar is used. The position of the
|
||
menu item selected in each menu bar can be recorded so that the previously selected menu item can be
|
||
highlighted when a menu bar is re-displayed.
|
||
|
||
|
||
This feature is available on the Series 3a and Workabout, but not on the Series 3. It is discussed more
|
||
fully in the Hwif Reference Documentation chapter.
|
||
|
||
|
||
SSS a re a a
|
||
Presenting dialogs
|
||
Presenting a dialog consists of the following steps:
|
||
|
||
= one call to udpenDialog, to begin building up the dialog contents
|
||
|
||
|
||
= one or more calls to uAddDialog! tem, uAddButtonList, and/or uAddChoiceList, to add items to the
|
||
dialog
|
||
|
||
|
||
= possibly, a call to hOlgPosition, to position the dialog to one side or comer of the screen
|
||
|
||
|
||
= one call to uRunDialog, to await the user's response.
|
||
|
||
|
||
Checking for run-time errors
|
||
|
||
|
||
The programmer ought to bear in mind that an out-of-memory error can occur at any of the above stages,
|
||
in which case the flow of execution must be terminated at once. In practice, this is very simple to do,
|
||
since the Hwif uxxx calls all automatically inform the user if any error arises, and automatically clean up
|
||
any temporary dialog resources that are no longer required.
|
||
|
||
|
||
For example, to present a dialog with a title (Use) and a choice list (with prompt Clipboard):
|
||
|
||
|
||
LOCAL_C VOID ChangeCl ipboardUsed(VOID)
|
||
|
||
|
||
€
|
||
if (uOpenDialog("Use"))
|
||
return; /* out of memory */
|
||
if CuAddChoiceList("Clipboard",&using, "1", 02", "30 140 NULL)
|
||
return; /* out of memory */
|
||
if CuRunDialog¢)<=0)
|
||
return; /* out of memory, or user cancelled */
|
||
WriteClipboardText();
|
||
}
|
||
|
||
|
||
Items that can be added to Hwif dialogs
|
||
These are precisely the same as in OPL/w, namely:
|
||
= = choice lists
|
||
® action lists of buttons
|
||
= plain text items
|
||
=# numeric editors
|
||
® floating point editors
|
||
|
||
|
||
= time editors and date editors
|
||
|
||
|
||
13
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
= text editors (both scrolling and non-scrolling)
|
||
= secret data input boxes
|
||
= filename selectors and filename editors.
|
||
|
||
|
||
In most of these cases, the item is associated with a so-called live variable, which specifies the initial
|
||
value of the item (when the dialog is made visible), and which may be changed when the dialog is
|
||
successfully completed. The type of this live variable varies from item to item.
|
||
|
||
|
||
Thus in the above example, the (global) variable using is the live variable for the choice list.
|
||
|
||
|
||
Longer choice lists
|
||
|
||
|
||
In some cases, the list of choices presented in a particular choice list may be too long for a choice list to
|
||
be conveniently defined simply by one call to uAddchoiceList.
|
||
|
||
|
||
The three functions uBeginDCL, uGrowDCL, and uAddDCL exist to help out with these so-called dynamic
|
||
choice lists (the name reflects the fact that the contents of the choice list are built up over a few lines of
|
||
code, rather than just being defined statically; in some cases, the contents in the list may change between
|
||
different invocations of the dialog, to reflect changing run-time circumstances).
|
||
|
||
|
||
For example, the following routine builds up a choice list whose contents are the twelve month names:
|
||
|
||
|
||
LOCAL_C INT AddMonthChoiceList(UWORD *pmonno)
|
||
€
|
||
H_DI_CHOICE ch;
|
||
TEXT mon [32];
|
||
INT i;
|
||
|
||
|
||
if CuBeginDCL(&ch))
|
||
return(-1); /* report failure to caller */
|
||
for (i=0; i<12: i++)
|
||
€
|
||
p_nmmon(&mon [0] , i);
|
||
if CuGrowDCL(&ch,&mon[0] >)
|
||
return(-1); /* report failure to caller */
|
||
>
|
||
return(uAddDCL("Month", pmonno, &ch));
|
||
>
|
||
|
||
|
||
Alternatively, the function hSetVarrayInchlist can be used to build up a choice list, especially if the list
|
||
might contain more than 255 items.
|
||
|
||
|
||
For example, by modifying the above code, the same effect can be achieved as shown below:
|
||
|
||
|
||
#define C_VASTR 6
|
||
#define O_VA_APPEND 7
|
||
#define OLIB_CAT 1
|
||
|
||
|
||
LOCAL_C INT AddMonthChoiceList(INT item_no, INT *pmonno)
|
||
{
|
||
UWORD used = 0;
|
||
VOID *pvarray;
|
||
TEXT mon{32J;
|
||
INT i;
|
||
|
||
|
||
if (uAddChoiceList("month",&used,NULL))
|
||
return(-1); /* failure */
|
||
pvarray = p_new(OLIB_CAT,C_VASTR);
|
||
for (i = 0; i < 12; i++)
|
||
€
|
||
p_nmmon(&mon [0], 1);
|
||
p_send3(pvarray,0_VA_APPEND , &mon{[0] );
|
||
>
|
||
hSetVarrayInChlist( item_no, (*pmonno), pvarray):
|
||
>
|
||
|
||
|
||
Note that error handling in this code is incomplete.
|
||
|
||
|
||
14
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
- eS eee
|
||
|
||
|
||
Typical dialog usage
|
||
Applications will in many cases wish to call dialogs in a loop, as follows:
|
||
|
||
|
||
LOCAL_C VOID OpenFile(VvoID)
|
||
€
|
||
H_DI_FSEL open;
|
||
TEXT openbuf [P_FNAMESIZE+2] ;
|
||
VOID *newfcb;
|
||
|
||
|
||
SetupF i lename(&openbuf [0] );
|
||
open. flags=H_FILE_PICK_SELECTOR;
|
||
open. fname=(&openbuf (0) ); /* initialise filename selector */
|
||
do
|
||
{
|
||
if (uOpenDialog("Dump"'))
|
||
return;
|
||
if CuAddDialogI tem(H_DIALOG_FSEL,"File: " &open))
|
||
return;
|
||
if CuRunDialog()<=0)
|
||
return;
|
||
openbuf [1+openbuf [0] ] =0;
|
||
> while (TryOpenFile(&openbuf [1] ,&newfcb)); /* until open succeeds */
|
||
ChangeOverTo(&openbuf (1] ,newfcb);
|
||
}
|
||
|
||
|
||
Schematically:
|
||
|
||
|
||
InitialiseLiveVariables();
|
||
FOREVER
|
||
€
|
||
if (No memory for dialog)
|
||
break;
|
||
if (User cancels)
|
||
break;
|
||
if (Dialog choices validate okay)
|
||
£€
|
||
PerformAction();
|
||
break;
|
||
>
|
||
>
|
||
|
||
|
||
In such a case, relevant live variables need to be initialised before entering the loop. Then if the user
|
||
mistakenly selects (eg) the wrong file from a directory, this choice will remain in the dialog when it is
|
||
presented again (along with an appropriate error message), so that it is easy for the user to adjust the
|
||
choice to what was intended. At the same time, users will be able to see what they typed into the dialog
|
||
the first time.
|
||
|
||
|
||
It is possible to discover the last key press and key modifers handled by the system on the application's
|
||
behalf. This is particularly useful on exit from uRunDialog.
|
||
|
||
|
||
A number of key press combinations cause a dialog to terminate; amongst others, they include ESC and
|
||
HELP. Knowing which key press combination caused the dialog to terminate, enables the application to
|
||
take appropriate subsequent action.
|
||
|
||
|
||
For more information, see the description of the hLastSystemkey function in the Hwif Reference
|
||
Documentation chapter.
|
||
Dialog underlining
|
||
|
||
|
||
Built in applications have the ability to add or remove a solid underline to components in a dialog. This
|
||
serves to group related dialog components and can be a useful visual aid if used sparingly.
|
||
|
||
|
||
Hwif programs can also do this by calling the function usetDialogULine and specifying the position of the
|
||
dialog component within the dialog and indicating whether underlining is to be added or removed.
|
||
|
||
|
||
This feature is available on all machines, although there is a difference in behaviour on the Series 3 as
|
||
opposed to the Series 3a and Workabout.
|
||
|
||
|
||
Further detail on this can be found in the Hwif Reference Documentation chapter.
|
||
|
||
|
||
15
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
—. Ka
|
||
|
||
|
||
Help dialogs
|
||
|
||
|
||
Hwif contains support for accessing the same Help engine as used by the in-built applications on the
|
||
Series 3.
|
||
|
||
|
||
The function hHelpSubSystem can be called in response to suitable key-presses from the user (eg the HELP
|
||
keypress).
|
||
|
||
|
||
The Help engine is resource-based and any serious user of hHelpSubSystem must create a resource file
|
||
(using the tool RCOMP.EXE) containing resources defining the hierarchy of Help text.
|
||
|
||
|
||
Typically, a MainLoop routine might contain the following code fragment:
|
||
|
||
|
||
if (key. keycode == W_KEY_HELP)
|
||
hel pSubSystem(QUERY_HELP ,QUERY_HELP_INDEX);
|
||
|
||
|
||
where the two parameters are the resource IDs of the "top-level" Help resource and the "index" set of
|
||
Help resources respectively.
|
||
|
||
|
||
Like uPresentMenus and uRunDialog, hHelpSubSystem only returns when the entire Help operation has been
|
||
completed by the user. It does its own error handling internally, automatically presenting suitable error
|
||
messages where necessary.
|
||
|
||
|
||
Help Resources
|
||
|
||
|
||
As stated above, the function hHelpsubSystem requires two resource IDs as parameters. These reference
|
||
instances of the HELP_ARRAY resource (defined in the Hwif reference documentation). These, in turn, may
|
||
reference instances of STRING, TOPIC_ARRAY and yet other HELP_ARRAY resources, forming a potentially
|
||
complex hierarchy.
|
||
|
||
|
||
Note that in the definition of the resource struct HELP_ARRAY, the three fields must always appear in the
|
||
given order. When declaring an instance of the resource struct HELP_ARRAY, the fields can come in any
|
||
|
||
order (true for any resources declared in a resource file). The reason that it may be natural to rearrange
|
||
the fields is that the displayed form of a general Help screen is:
|
||
|
||
|
||
1. “topic” text in the title line (in bold).
|
||
2. Any STRINGs in "strlst" come next.
|
||
3. any associated topics defined by "topic_id" come last (bulleted and in bold).
|
||
|
||
|
||
The "topic_id” field of any HELP_ARRAY resource, if present, must always reference an instance of the
|
||
TOPIC_ARRAY struct (defined in the Hwif reference documentation). In turn the values in "id_tst” refer to
|
||
further HELP_ARRAYS as shown schematically below:
|
||
|
||
|
||
HELP_ARRAY (topic_id)--> TOPIC_ARRAY
|
||
|
||
|
||
(id_lst item)--> HELP_ARRAY ... etc
|
||
|
||
|
||
|
|
||
|
||
|
||
Cid_lst item)--> HELP_ARRAY ... etc
|
||
|
||
|
||
For example, the following definition has resource ID world_basics and contains all three possible types
|
||
of field - "topic", "strist” and "topic_id”.
|
||
|
||
|
||
RESOURCE HELP_ARRAY world_basics
|
||
|
||
|
||
€
|
||
|
||
topic = "World";
|
||
|
||
strist =
|
||
€
|
||
STRING {str = "To find a city, type first few letters";}
|
||
STRING {str = "25
|
||
STRING {str = "World button locks to cities in one country";>
|
||
>
|
||
|
||
topic_id = world_extra;
|
||
|
||
>
|
||
|
||
|
||
However, it is more common to omit at least one of these fields in any one HELP_ARRAY.
|
||
|
||
|
||
16
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
_ ee eeeeeeeSeSSSeSSSSSSSSSSSSSMMMSMMSSSSSSSSsssesesessseeee
|
||
|
||
|
||
In practice, Help hierarchies tend to be built from what can be described as "top-level" variations of
|
||
HELP_ARRAYS, where the "strtst” fields are omitted, and "bottom-level" variations, where the “topic_id"
|
||
fields are omitted
|
||
|
||
|
||
The “top-level” variations result in the presentation of bold, bulleted lists of further topics on which help
|
||
can be had. For example:
|
||
|
||
|
||
RESOURCE HELP_ARRAY query_help
|
||
€
|
||
topic = "Query";
|
||
topic_id = query_help data;
|
||
}
|
||
|
||
|
||
The "bottom-level" variations result in the presentation of UNbold, UNbulleted text Strings. For
|
||
example:
|
||
|
||
|
||
RESOURCE TOPIC_ARRAY query_help data
|
||
|
||
€
|
||
|
||
id_lst =
|
||
€
|
||
query_list,
|
||
query_func,
|
||
query_memories,
|
||
query_percent,
|
||
query_tips
|
||
7
|
||
|
||
>
|
||
|
||
|
||
In turn, query_memories, for example, is the ID of the resource:
|
||
|
||
|
||
RESOURCE HELP_ARRAY query_memories
|
||
|
||
|
||
{
|
||
|
||
topic = "Memories MO-M9";
|
||
|
||
strlst =
|
||
{
|
||
STRING {str = "Top line shows current memory";},
|
||
STRING {str = "'M In’, 'M+" ete work on it":},
|
||
STRING {str = ";},
|
||
STRING {str = "Change or set with 'Change memories'":}
|
||
3
|
||
|
||
>
|
||
|
||
|
||
Thus, calling hHelpsubsystem with first parameter query_HELP displays QUERY in the title line of the Help
|
||
display followed by a list of bold ,bulleted items of which MEMORIES MO-M9 is the third. Selecting
|
||
this item from the Help menu causes the above text to be displayed.
|
||
|
||
|
||
Note that neither the system code at run-time, nor the resource compiler offers any assistance in word-
|
||
wrapping strings of Help text. The developer must ensure that individual lines do not become so wide
|
||
that a run time "Too wide" error message is given.
|
||
|
||
|
||
The HELP_ARRAY identified by the index resource ID parameter to hHelpsubSystem (ie the second parameter)
|
||
is only referenced when the user requests an "Index" of all available Help topics, either by pressing
|
||
CONTROL +HELP inside the Help subsystem or by selecting the "Index" item and pressing ENTER. Either
|
||
way, the system code constructs a sorted alphabetical list of topics from two sources:
|
||
|
||
|
||
1. the help index at resource 112 in the "system" resource file (which the system code
|
||
automatically opens on behalf of all Hwif applications).
|
||
|
||
|
||
2. the HELP_ARRAY resource referenced by the caller's index resource ID parameter(if non-zero).
|
||
|
||
|
||
In constructing the list, the system code ignores any "strist” and "topic" fields in the top-level
|
||
resource.
|
||
|
||
|
||
A measure of context sensitive help can be achieved by allowing the values passed to hHelpsubSystem to
|
||
depend on the program state.
|
||
|
||
|
||
Finally, whenever a Help screen is constructed, the system code automatically appends a reference to
|
||
"Help on help" and "Index" provided that these are not already provided by the developer.
|
||
|
||
|
||
17
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
Help dialogs (an older alternative)
|
||
|
||
|
||
In previous versions of Hwif, it was not possible to access the built-in Help subsystem from an Hwif
|
||
application. However, two utility routines were available (and still are!) in the Hwif library that allowed
|
||
the presentation of a broadly comparable but possibly less satisfying Help dialog suite.
|
||
|
||
|
||
The routine uDiatogMenu allows the presentation of a menu-like dialog broadly equivalent to the top level
|
||
in a Help dialog suite. Typically, an application would launch this dialog when the HELP key is pressed.
|
||
The application supplies a range of topic titles, and the user cursors up and down in standard manner to
|
||
select a topic of further interest. The value returned from udiatogMenu informs the application which
|
||
topic was selected.
|
||
|
||
|
||
The application can then make use of the routine uDisplayText to present a dialog containing up to seven
|
||
lines of additional textual information (for the body of the help topic selected). When this is exited, the
|
||
application can, if desired, present the top-level dialog again.
|
||
|
||
|
||
Ee ee es ree a ee ee ee ee
|
||
Line editors and multi-line editors
|
||
|
||
|
||
In addition to the various editors that are available as items in dialogs, the Hwif library also allows access
|
||
to single- and multi-line editors, outside of the context of dialogs.
|
||
|
||
|
||
Such editors allow the user to alter data, without having to invoke a dialog box for this purpose.
|
||
Advantages include:
|
||
|
||
|
||
= compared to a corresponding (scrolling) editor in a dialog, a multi-line editor allows the user to
|
||
see more text at one time, and the text can contain embedded carriage returns
|
||
|
||
|
||
= any Find text (for example) can remain permanently visible on the screen, in its own edit box,
|
||
instead of being visible only when the user requests the presentation of a Find Dialog
|
||
|
||
|
||
= if the entries in for example a Diary are laid out on screen, the user can edit them in place,
|
||
rather than having to use a dialog and lose sight of the overall screen layout in the meantime.
|
||
|
||
|
||
Invoking these editors via Hwif library calls does not significantly add to the total size of the code of an
|
||
application, since the Hwif library calls merely provide access to editing functionality that is already
|
||
present in the Series 3 ROM.
|
||
|
||
Editing features supported
|
||
|
||
Hwif editors allow applications to make use of the following features:
|
||
|
||
|
||
= in multi-line editors, text is automatically word-wrapped at the visible right margin specified;
|
||
users can start new paragraphs by pressing the ENTER key
|
||
|
||
|
||
= in multi-line editors, the display automatically scrolls vertically when required
|
||
= the user can show or hide paragraph ends and spaces
|
||
|
||
|
||
= the text can be displayed bold, italicised, underlined, monospaced, and/or double height (though
|
||
the font style cannot vary from word to word inside any one editor)
|
||
|
||
|
||
= the width of an editor can be changed dynamically on request, for example if the user hides or
|
||
shows a permanent status window
|
||
|
||
|
||
"it is possible to display a side cursor in the left margin; the width of the main (flashing) cursor
|
||
can also be controlled (and can be set to zero)
|
||
|
||
|
||
= the functions cut, copy, paste, evaluate, find, and replace are all available.
|
||
|
||
|
||
Presenting an editor
|
||
The minimum steps required to include an editor in an application are the following:
|
||
|
||
|
||
= create the editor, using the cal! heBopen
|
||
= when appropriate, emphasise it, using the call hEBEmphasise, so that it displays a flashing cursor
|
||
= from time to time, pass it relevant incoming keypresses, using the call hEBHandleKey
|
||
|
||
|
||
= when the application needs to know the current contents of the editor, the call hEBSenseText can
|
||
be made.
|
||
|
||
|
||
18
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
|
||
|
||
The call heBopen passes a filled-in _ED1IT_Box struct, to customise the editor. This specifies (among other
|
||
things) the position of the top left of the editor on the screen, the maximum number of characters that the
|
||
editor is to accept, the width and height of the editor, the font style to use, and the spacing between lines.
|
||
|
||
|
||
For example, the following code fragment creates an editor four lines deep, of width 12 pixels less than
|
||
the current screen width, and which supports clipboard functionality and a left cursor:
|
||
|
||
|
||
H_EDIT_BOX heb;
|
||
|
||
|
||
heb. win=MainwWid; /* ID of main window */
|
||
|
||
heb.maxchars=255;
|
||
|
||
heb. vulen=ScreenWidth-12;
|
||
|
||
heb.visl ines=4;
|
||
|
||
heb.pos.x=5;
|
||
|
||
heb. pos. y=36;
|
||
ebH=hEBOpen(H_EDIT_BOX_VISLINES|H_EDIT_BOX_LEFT_CURSOR|H_EDIT_BOX_CLIPBOARD,&heb);
|
||
|
||
|
||
The return value ebi (the handle of the edit box) should be used to identify this particular editor (as
|
||
opposed to others) in subsequent hEBxxx calls. The call returns zero if there was insufficient memory to
|
||
create the editor.
|
||
|
||
|
||
In the above example, the variable screenwidth has previously been set up by the application to the
|
||
current width of the screen (this can vary depending on whether a permanent status window is visible).
|
||
The variable Mainwid is the ID of the main screen window, as discussed below in connection with the
|
||
Console.
|
||
|
||
|
||
The call hEB0pen creates an editor without any text in it. Text can be placed into the editor in a variety of
|
||
ways, chief amongst them the call
|
||
|
||
|
||
hEBSetText(VOID *ebH, TEXT *pb, INT blen)
|
||
|
||
|
||
In using the calls hEBSetText and hEBSenseText, it is important to understand that Hwif editors store text
|
||
internally in one contiguous buffer. The buffer itself is always terminated by a zero. Paragraph ends are
|
||
recorded using the character 13 (\n). Thus text set into an editor should not contain any zero (except,
|
||
possibly, after blen characters - in which case it is harmless). For example,
|
||
|
||
|
||
hEBSetText(ebi,"Hello world\nThis is Hwif",24);
|
||
|
||
|
||
The call heBSenseText simply returns a TEXT* pointer to the editor's own copy of the text being edited.
|
||
Clearly, this has to be treated with care. A copy of the text may have to be made (using, for example,
|
||
p_scpy) before closing down the editor or otherwise changing its contents.
|
||
|
||
|
||
As well as the textual content of an editor initially being zero, the cursor position also starts off at zero;
|
||
likewise there is, by default, no select region. These settings can be overridden by means of the call
|
||
hEBSetSelect. If required, there is also a corresponding call hEBSenseSelect.
|
||
|
||
|
||
Word wrapping can, effectively, be turned off by using the heBsetMargin function.
|
||
|
||
For more details of these and other editing calls, see the reference section, or the worked example
|
||
applications.
|
||
|
||
Applications with more than one editor
|
||
|
||
Applications with more than one editor can present an impressive appearance to users.
|
||
|
||
|
||
What the user sees is two or more regions of the screen - such as the Find Window and the Record
|
||
Window in a database application - each enclosed in its own border, and each housing an editor. The user
|
||
typically navigates between these windows using the TAB key to switch focus, and editing keys are
|
||
directed to whichever editor currently has the focus.
|
||
|
||
|
||
To implement such a set up, an Hwif programmer needs to take the following steps:
|
||
|
||
|
||
= the sizes and positions of the various screen components have to be carefully calculated (see the
|
||
example applications for some guidance on this)
|
||
|
||
|
||
= the requisite number of editors have to be created, and their handles stored
|
||
= a variable has to be dedicated to recording which of the editors currently has the focus
|
||
|
||
|
||
= for each editor, a graphics call such as gBorderRect has to be made, to produce an appropriately
|
||
shadowed boundary (with a heavier shadow for the editor possessing the focus).
|
||
|
||
|
||
19
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
On receipt of the TAB key, the application switches focus, by means of two calls to gBorderRect (one to
|
||
remove the shadow from the editor that is losing the focus, and one to apply a shadow to the editor that
|
||
is gaining it), and two calls to hEBEmphasise. The effect of these latter calls is to control whether a
|
||
flashing cursor is displayed, and whether a select region is highlighted.
|
||
|
||
|
||
Thus part of the code in the MainLoop of an application with three editors could be as follows:
|
||
|
||
|
||
switch (key. keycode)
|
||
€
|
||
|
||
|
||
case W_KEY_TAB:
|
||
RotateFocus(key.modifiers&W_SHIFT_MODIFIER); /* forwards or backwards */
|
||
break;
|
||
case W_KEY_RETURN:
|
||
if Cemph!=2)
|
||
break; /* else fall through */
|
||
default:
|
||
hEBHandleKey(edit [emph] , key. keycode, key.modi fiers);
|
||
}
|
||
|
||
|
||
In this application, the handles of the three edit boxes are stored in edit [0] through edit (2), the variable
|
||
emph records which currently has the emphasis, and of the three editors, only the third is multi-line (hence
|
||
the test in the W_KEY_RETURN branch). The effect of SHIFT+TAB is to rotate the focus in the opposite
|
||
direction to plain TAB.
|
||
|
||
|
||
Edit boxes and saved file versions
|
||
|
||
|
||
One important difference between restricting users to edit data via dialogs, and allowing them to edit the
|
||
data in place, in single- or multi-line editors, is that menu commands can arrive at any time in the middle
|
||
of editing in the second case (but not in the first). The point is that access to the menu bar is impossible
|
||
while a dialog is in place; not so when text in an edit box is being edited.
|
||
|
||
|
||
Applications which use edit boxes may therefore have to check, before carrying out any menu command,
|
||
that their own record of the contents of the edit boxes is up to date.
|
||
|
||
|
||
To this end, the routine hEBSenseChanged exists, which reports whether or not an edit box has had its
|
||
contents changed. There is also a routine hEBClearChanged, which clears the internal "changed" flag
|
||
maintained by the edit box.
|
||
|
||
|
||
When file-based data is being edited via a dialog, an application can often choose to write any changes to
|
||
file, immediately the dialog completes (especially in the case of a database application). But when data is
|
||
being edited via an edit box, the application obviously cannot write out any changes every time a keypress
|
||
is received. This leads to there being a potential difference between the file version of some data, and the
|
||
current in-memory version. It is up to applications to keep careful track of this difference, and to decide
|
||
when changes should be committed to file.
|
||
|
||
|
||
ESS en ee ee ee ne
|
||
Printing
|
||
Hwif library routines provide support for applications:
|
||
|
||
|
||
# invoking the standard Print Setup dialog suite (specifying page size, margins, headers and
|
||
footers, and so on)
|
||
|
||
|
||
= actually printing.
|
||
|
||
|
||
Printing features supported
|
||
|
||
|
||
Any printing from an Hwif application automatically conforms to the parameters specified by the user via
|
||
the Print Setup dialog, and is automatically directed to the file or device specified by the user in the
|
||
Printer Setup dialog in the System Screen. As the printing takes place, the standard Printing dialog is
|
||
presented, informing the user of the page currently being printed, and containing a Cancel button to
|
||
allow the printing to be abandoned.
|
||
|
||
|
||
Rom resident code performs the pagination and any word-wrap required, and ensures that any headers
|
||
and footers specified by the user are appropriately positioned. That is, including Hwif printing library
|
||
calls in an application does not significantly add to the total size of the code of an application, since these
|
||
library calls merely provide access to functionality that is present in the Series 3 ROM.
|
||
|
||
|
||
20
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
|
||
|
||
All that an application needs to provide is a callback function which provides the data for each new line
|
||
|
||
(or series of lines, if word-wrap is required) to be printed.
|
||
|
||
The Print Setup dialog
|
||
|
||
In order to enter the Print Setup dialog suite, an application only needs to include the single line of code
|
||
hPrintSetupDialog¢);
|
||
|
||
There is no requirement for the application to record the values chosen by the user in this dialog suite, as
|
||
|
||
ROM resident code does this automatically.
|
||
|
||
The basic mechanism of printing
|
||
|
||
|
||
As an example of how to print, consider an application which stores its data as a series of records
|
||
accessed via an index, table[]. These records in turn consist of a date and time, and a text string, all
|
||
defined by the struct
|
||
|
||
|
||
typedef struct
|
||
|
||
|
||
{
|
||
|
||
ULONG sdate; /* time and date */
|
||
|
||
UWORD tlen; /* length of text string */
|
||
TEXT “pb; /* address of text string */
|
||
> ENTRY;
|
||
|
||
|
||
The following two routines suffice to print the application's data:
|
||
|
||
|
||
LOCAL_D UWORD PrintRec; /* entry currently being printed */
|
||
LOCAL_D UWORD PrintState; /* which PART of the entry is currently being printed */
|
||
LOCAL_D TEXT PrintBuf{[H_TIME_LN_DATE_STRING] ;
|
||
|
||
|
||
LOCAL_C INT PrintLineCH_PRINT *pr)
|
||
{
|
||
ENTRY *pent;
|
||
|
||
|
||
pent=(&table[PrintRec] );
|
||
switch (PrintStatet+)
|
||
|
||
|
||
€
|
||
|
||
case 0:
|
||
pr->blen=SdateToBuf (&PrintBuf [0] ,&pent->sdate);
|
||
pr->buf=(&PrintBuf [0] );
|
||
pr->style|=H_PRINT_STY_BOLD;
|
||
break;
|
||
|
||
case 1:
|
||
pr->buf=pent->pb;
|
||
pr->blen=pent->tlen;
|
||
|
||
|
||
break;
|
||
|
||
case 2:
|
||
pr->blen=0;
|
||
PrintState=0;
|
||
PrintRec++;
|
||
return(PrintRec! =count);
|
||
>
|
||
|
||
pr->flags|=H_PRINT_KEEP;
|
||
|
||
return( TRUE);
|
||
|
||
>
|
||
|
||
LOCAL_C VOID PrintALL(VOID)
|
||
|
||
€
|
||
|
||
if (!count)
|
||
{
|
||
winfoMsg("Nothing to print");
|
||
return;
|
||
>
|
||
|
||
|
||
PrintRec=0;
|
||
PrintState=0;
|
||
hPrint(PrintLine);
|
||
d
|
||
|
||
|
||
21
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
Ss eS
|
||
|
||
|
||
Of these two routines, the latter (Printal) is the controlling one. The general form of this routine is
|
||
actually as follows:
|
||
|
||
|
||
CollectPrintDetails();
|
||
|
||
Check! fReal lyNeedToPrint();
|
||
InitialisePrintStateVariables();
|
||
hPrint(PrintLine);
|
||
PostPrintMessage();
|
||
|
||
|
||
In all cases, the centre-piece of a PrintAlt routine is the line
|
||
hPrint(PrintLine);
|
||
|
||
|
||
or equivalent. When the flow of program execution reaches this line, it remains inside the hprint routine
|
||
until printing has completed (either naturally, or on account of the user terminating, or on account of
|
||
some kind of error). Thus any following line of code, such as a call to PostPrintMessage, is executed only
|
||
after printing is complete. In this sense, hPrint is similar to the calls uRunDialog and uPresentMenus; a lot
|
||
can take place on the screen without the program progressing any further through application code.
|
||
However, in one crucial respect, hPrint differs from these other calls; the application-supplied callback
|
||
function PrintLine is repeatedly visited from inside the hprint call.
|
||
|
||
|
||
The PrintLine callback function
|
||
|
||
|
||
Each time system code calls the PrintLine function, the application has to supply the data for the next
|
||
line (or series of lines) to print.
|
||
|
||
|
||
It is the responsibility of the application to keep an independent record of how far the printing has
|
||
progressed - so that the appropriate data can be passed each time. This record - the so-called Print state
|
||
variables - has to be in some static data (or in an alloc cell whose handle is a static variable). In the
|
||
above example, the variables printstate and PrintRec play this role: printRec counts through the records
|
||
(from 0 through count-1), and PrintState records which part of each record is currently being printed:
|
||
|
||
|
||
® the text corresponding to the date and time”
|
||
= the main text of the record
|
||
= a possible blank line underneath the record, to separate it from the following one.
|
||
|
||
|
||
Each time PrintLine is called, the application has to fill in parts of a passed H_PRINT struct. The parts that
|
||
an application is most likely to want to write to are:
|
||
|
||
|
||
blen the length of the text for the line (or group of lines)
|
||
|
||
buf the address of a buffer containing the text to print
|
||
|
||
style possible further embellishment of the font style selected by the user in any
|
||
Print Setup dialog
|
||
|
||
flags the application may wish to or in the bit }_PRINT_KEEP, to request the system
|
||
|
||
|
||
software to keep this line (or group of lines) together on the same page with
|
||
the following line, if possible; another potentially useful flag is H_PRINT_PAGE,
|
||
to force the emission of a form feed before the line is printed.
|
||
|
||
|
||
Additionally, the return value from PrintLine has the following significance:
|
||
= the application should return FALSE when it has no more data to print
|
||
|
||
|
||
= otherwise, the application should return TRUE.
|
||
|
||
|
||
The location of the print buffer
|
||
|
||
|
||
Note that pr->buf must point to a buffer that will continue to exist after the routine printLine has
|
||
returned.
|
||
|
||
|
||
In the above example, the main body of text can be printed simply by setting pr->buf equal to the
|
||
application's own pointer to where this text is stored. However, the text corresponding to the time and
|
||
date is another matter, since the application evidently only stores this in the form of a ULONG. The
|
||
application routine SdateToBuf converts the time and date from a ULONG into text form (presumably using
|
||
the Hwif time-text utility functions, discussed later). However, it would be a severe error to declare a
|
||
buffer to hold this textual representation as an automatic on the stack inside printLine.
|
||
|
||
|
||
22
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
|
||
|
||
The Print Details dialog
|
||
|
||
|
||
Although the above example lacks such a dialog, it is possible for an application to present its own dialog
|
||
prior to proceeding with a print.
|
||
|
||
|
||
The purpose of this dialog - if not only to confirm that the user wishes printing to go ahead - could be to
|
||
collect additional parameters affecting the way the printing is done. For example, the user could be asked
|
||
to choose whether all records should be printed, or only a selected set (say only those records which are
|
||
|
||
somehow tagged). Again, the dialog could control whether each new record should begin on its own new
|
||
|
||
|
||
page.
|
||
|
||
|
||
Note that any such Print Details dialog differs in function from the Print Setup dialog available via
|
||
hPrintSetupDialog:
|
||
|
||
|
||
= the Print Setup dialog is common to all applications, whereas Print Details dialogs differ from
|
||
application to application
|
||
|
||
|
||
™ — system code takes care of recording and implementing the choices made from the Print Setup
|
||
dialog, but it is up to applications to record and implement choices made in any Print Details
|
||
dialog.
|
||
|
||
|
||
Word wrapping during printing
|
||
|
||
|
||
In most cases, applications have no need to be aware of any word-wrapping that may take place during
|
||
printing. Whether or not some text is printed on one line or over more than one line depends, after all,
|
||
on choices made by the user in the Print Setup dialog - such as the page size, the left and right margins,
|
||
and the default printing font. In all cases, the ROM printing code automatically ensures that the specified
|
||
margins are respected, with excess text being placed on the following line.
|
||
|
||
|
||
Occasionally, however, an application may wish to specially indent subsequent lines of a wrapped
|
||
paragraph. This can be achieved by using the Hwif library call hprintSetsi - which sets the Subsequent
|
||
Indent for any wrapped lines.
|
||
|
||
|
||
At the same time, amy line can be arbitrarily indented, by means of writing to the indent field of the
|
||
passed H_PRINT struct.
|
||
|
||
|
||
The units any such indents are expressed in vary considerably from printer to printer. To guide the
|
||
application as to suitable values, two additional calls are available:
|
||
|
||
|
||
hPrintSenseBufWidth returns the width, in printer units, of a specified buffer (when
|
||
printed in the selected default printer font)
|
||
|
||
|
||
hPrintSensePageWidth returns the width, in printer units, of the paper being printed on
|
||
(minus its margins).
|
||
|
||
|
||
Printing the contents of multi-line editors
|
||
Recall that Hwif multi-line editors use the character 13 (\n) to record paragraph ends.
|
||
|
||
|
||
Accordingly, if data produced in multi-line edit boxes is to be printed, it should first be scanned for
|
||
embedded \n's, along the following lines:
|
||
|
||
|
||
case 2:
|
||
PrintBuf=index (PrintRec] .note.buf;
|
||
PrintLen=index [PrintRec] .note. len;
|
||
default:
|
||
pr->buf=PrintBuf;
|
||
ind=p_bloc(PrintBuf ,PrintLen, '\n');
|
||
if Cind>=0)
|
||
€
|
||
pr->blen=ind;
|
||
PrintLen-=ind+1;
|
||
PrintBuf+=ind+1;
|
||
>
|
||
else
|
||
€
|
||
pr->blen=PrintLen;
|
||
PrintState=0;
|
||
PrintRec++;
|
||
>
|
||
|
||
|
||
23
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
SS SSS een Oe ee ee ee eee ee
|
||
Time-text utility functions
|
||
|
||
|
||
The Hwif time-text functions provide a convenient way of generating textual representations of times
|
||
and/or dates, that reflect the user's preferences as given in the Formats dialog in the Time application.
|
||
|
||
|
||
In general, a textual representation of time and/or date consists of a combination of some of the following
|
||
components:
|
||
|
||
|
||
= numerical representations of the day in the month, the month in the year, the year, and the
|
||
century
|
||
|
||
|
||
® numerical representations of the hour, the minute, and the second
|
||
|
||
|
||
= the name of the day in the week, and the name of the month in the year - each of which may be
|
||
abbreviated
|
||
|
||
|
||
= a suffix (such as ¢h or rd) after the day number in the month
|
||
® an am or pm indicator
|
||
= time and date separators (such as colons and slashes).
|
||
The htTxxx functions provide textual representations as combinations of the above, taking data from:
|
||
|
||
|
||
* atime and/or date that has previously been specified, using the htTSetTime call (which accepts
|
||
any of the P_DAYSEC, P_DATE, or system-time representations)
|
||
|
||
|
||
= formatting preferences previously indicated by the application, using the calls hTTsetformat and,
|
||
possibly, htTSetAbbreviations
|
||
|
||
|
||
= the user's current preference for whether time should be am/pm or 24 hour, for whether the
|
||
month should come before or after the day, and for what the date and time separators should be.
|
||
|
||
|
||
The resultant text itself is obtained by a call to hTTSenseText.
|
||
|
||
|
||
Each of the above calls has to pass a handle that has previously been obtained by a call to htTopen. This
|
||
allocates resources that the subsequent calls access. When these resources are no longer needed, they can
|
||
be freed by a call to htTClose.
|
||
|
||
Default textual representation
|
||
|
||
In the absence of a call from hTTSetFormat:
|
||
|
||
|
||
= any time string generated consists of hours, minutes, and seconds (all expressed numerically),
|
||
together with the current time separators
|
||
|
||
|
||
= any date string generated consists of the day in the month, the month in the year, the year, and
|
||
the century (again, all expressed numerically), together with the current date separators.
|
||
|
||
|
||
In the absence of a call from hTTSetAbbreviations, any day and month names generated are given in full,
|
||
without being abbreviated.
|
||
Refreshing the format on returning to foreground
|
||
|
||
|
||
Ideally, every time an application making long-term use of the time-text functions is brought into
|
||
foreground, it ought to reset the format of any time-text channels it currently has open. This ensures that
|
||
any changes made by the user in the meantime (when the application was in background) are picked up.
|
||
|
||
|
||
For example, part of the Maintoop of an application displaying time in textual form might be
|
||
|
||
|
||
if (key. keycode&W_EVENT_KEY)
|
||
|
||
|
||
€
|
||
|
||
if (key. keycode==CONS_EVENT_FOREGROUND)
|
||
€
|
||
UpdateT imeFormat();
|
||
Display();
|
||
>
|
||
|
||
>
|
||
|
||
else
|
||
|
||
|
||
24
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
—_— EEE
|
||
|
||
|
||
If the application displays time without any seconds, and displays the month name, the day name, and a
|
||
suffix after the day number, the contents of UpdateTimeFormat could be simply
|
||
|
||
|
||
LOCAL_C VOID UpdateTimeFormat(VOID)
|
||
€
|
||
hTTSetFormat(ttH,H_TIME_FORMAT_NO_SECONDS|H_TIME_FORMAT_SUFFIX |
|
||
H_TIME_FORMAT_DAY_NAME|H_TIME_FORMAT_MONTH_NAME);
|
||
>
|
||
|
||
|
||
This call re-asserts the application's requirements, but allows the user's latest preferences on matters of
|
||
time and date separator, 12 or 24 hour clock, and month coming before or after date, to be picked up
|
||
too.
|
||
|
||
|
||
Eee ne ee ee ee ee eee Sy
|
||
Date/Time-text utility functions
|
||
|
||
|
||
These are a small set of functions which construct and manipulate stand-alone date/time text editors. As
|
||
such, they need not exist within a dialog. In some respects they are similar to the time-text functions but
|
||
have fewer date/time formats.
|
||
|
||
|
||
The textual representation of date is limited to the ten characters DD/MM/YYYY. For example:
|
||
20/07/1993.
|
||
|
||
|
||
The textual representation of time can be in any of the following formats:
|
||
|
||
|
||
=" HH:MM:SS representing either a time duration or a time of day in hours, minutes and seconds.
|
||
If it represents a time of day then, depending on system settings, the hours can be in either the
|
||
24-hour or the 12-hour format. If the latter, the string will be followed by the characters am or
|
||
pm.
|
||
|
||
|
||
= HH:MM representing either a time duration or a time of day in hours and minutes. If it
|
||
represents a time of day then, depending on system settings, the hours can be in either the 24-
|
||
hour or the 12-hour format. If the latter, the string will be followed by the characters am or pm.
|
||
|
||
|
||
The formatting can be done either at creation time in a call to hDTOpen or when setting a value in a call to
|
||
hDTSet.
|
||
|
||
|
||
The value and formatting information can be retrieved by a call to hoTSense.
|
||
A call to hDTSel fCheck performs a validation on the value currently held.
|
||
|
||
|
||
A call to hDTHandleKey handles the current keypress, assuming that there is suitable code which can
|
||
capture keypress events.
|
||
|
||
|
||
A call to hDTEmphasise can switch the emphasis for the current date/time editor. In other words,
|
||
depending on whether the second parameter is set to TRUE or FALSE, text highlighting can be turned on or
|
||
off. The emphasis can also be set at creation, i.e. on a call to hOTOpen.
|
||
|
||
|
||
Each of the above calls must pass a handle that is obtained by the call to hnTopen. This allocates resources
|
||
that the subsequent calls access. When these resources are no longer needed, they can be freed by a call
|
||
to hDTClose.
|
||
|
||
|
||
It is worth a reminder that the position and width of the text editor on the screen can also be specified at
|
||
creation, i.e on a call to hoTOpen.
|
||
|
||
|
||
SSS SS ae ae)
|
||
Hwif, the Console, and screen output
|
||
The visual output of an Hwif application generally consists of:
|
||
|
||
= intermittently, menus and dialogs
|
||
|
||
= more permanently, single- or multi-line editors
|
||
|
||
= atemporary or permanent status window
|
||
|
||
= additional graphics and text effects.
|
||
|
||
|
||
These additional graphics and text effects are achieved by a mixture of Wlib calls such as winfoMsg,
|
||
gPrintBoxText, gBorder, ginvObloid, wsEnable, gClrRect, wScroltRect, and so on.
|
||
|
||
|
||
25
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
ee Ss eee
|
||
|
||
|
||
In comparing these graphics calls with simpler console routines such as p_puts, three possible difficulties
|
||
emerge:
|
||
|
||
|
||
= there is a significant learning curve of new functions and new function names
|
||
|
||
|
||
= console routines, being text-based, automatically take care of positioning the cursor, whereas
|
||
more painstaking calculation is, inevitably, required with graphics functions
|
||
|
||
|
||
= before making any of the graphics calls, a significant amount of initialisation has to be
|
||
undertaken, involving connecting to the Window Server as well as creating windows and
|
||
graphics contexts when required.
|
||
|
||
|
||
Three options for graphics output
|
||
In general, there are essentially three options for application screen output:
|
||
= — stick strictly to console services such as p_printf and p_puts
|
||
|
||
|
||
# use the routines in the Window Server library, but using windows with backed-up bitmaps, to
|
||
avoid the need to undertake the conceptually more taxing burden of do-it-yourself window
|
||
redrawing
|
||
|
||
|
||
= embrace the full philosophy of window redrawing.
|
||
|
||
|
||
Hwif applications fall decidedly into the second of these three options. Routines such as p_printf produce
|
||
an output that is clearly inferior, in graphics quality, to that of the menus, dialogs, and editors in the
|
||
Hwif arsenal.
|
||
|
||
|
||
The initialisation routine uCommontnit hides the complications of actually connecting to the Window
|
||
Server - thus alleviating one of the possible disadvantages mentioned earlier, as regards using Window
|
||
Server calls. Once the call ucommoninit is complete, the connection to the Window Server has already
|
||
been established (there is no need for any independent call such as wStartup), and a backed-up window
|
||
the size of the screen has been created. Similarly, the routines uGetkey and uGetKeyA hide the
|
||
complications of receiving and decoding events from the Window Server.
|
||
|
||
|
||
At the same time, it is just as simple to invoke graphics routines such as winfoMsg (which produces an
|
||
information message at the bottom right commer of the screen) and wSetBusyMsg (which produces a flashing
|
||
busy message) as it is to invoke p printf and p_puts - provided, that is, that you have learned of the
|
||
existence (and the names) of these graphics routines.
|
||
|
||
|
||
On the other hand, there is no requirement to go the full extent of adopting the window redraw
|
||
mechanism that ultimately gives the best performance from the window server. Just as console i/o is
|
||
inappropriately primitive, compared to the i/o of Hwif dialogs, edit boxes, and menus, the full redraw
|
||
mechanism is inappropriately advanced.
|
||
|
||
|
||
Indeed, the three stages of graphics output listed above correlate closely with the three general stages
|
||
through which programmers can develop, in acquiring fuller mastery of the Series 3 software:
|
||
|
||
|
||
= use only of console routines is appropriate to an initial encounter with the Series 3, and for
|
||
applications whose user interface is unimportant
|
||
|
||
|
||
= use of the graphics calls (but not of the intricacies of doing your own redraws) matches
|
||
applications at the Hwif level of sophistication
|
||
|
||
|
||
= application programmers for whom high performance is vital must adopt not only the concept of
|
||
redrawing windows but also the Psion proprietary object-oriented development system.
|
||
|
||
|
||
Practical acquisition of graphics techniques
|
||
|
||
|
||
As far as acquiring familiarity with the varied Window Server library calls is concerned, it is intended
|
||
that the accompanying Hwif example applications will prove useful in this regard (as well as in regard to
|
||
illustrating the Hwif library calls). These provide sufficient illustrations for would-be graphics
|
||
programmers to develop enough confidence to subsequently branch out, by themselves, into the wider
|
||
reaches of the Window Server reference manual.
|
||
|
||
|
||
Two of the main types of graphics displays on the Series 3 are amply treated within these examples: a
|
||
series of edit boxes (each with their own border), and a scrolling vertical list. Hiding and showing
|
||
permanent status windows is also covered more than once.
|
||
|
||
|
||
26
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
—_—_ Eee
|
||
|
||
|
||
Hwif opens the console channel
|
||
|
||
|
||
As a matter of implementation, the call ucommontnit which prepares the ground for all subsequent Hwif
|
||
calls itself involves opening the console device (if it is not already open). As is standard, the handle of
|
||
the console control block is written into the static winHandle.
|
||
|
||
|
||
Almost all of the time, Hwif programmers can be oblivious of this implementation decision, and need
|
||
make no reference to wintandle. The supplied routines uGetKey, uGetkeyA, and uKeyPressOutstanding hide
|
||
some of the details of the interaction with the console.
|
||
|
||
|
||
However, any console program can, by default, be terminated at any time by the user simply pressing
|
||
PSION + ESC. In case this is undesirable, an application should make the call
|
||
|
||
|
||
uEscape( FALSE);
|
||
during its SpecificInit routine.
|
||
|
||
|
||
An important point to note is that if the global variable Useful screen is zero on entry to the call to
|
||
uCommoninit, the console device is initialised in compatibility mode; in other words, the behaviour and
|
||
appearance of the console on the Series 3a or the Workabout emulates that of the console on the Series 3.
|
||
The main window
|
||
|
||
|
||
At the end of the call to uCommoninit, a graphics window exists, the size of the whole screen - 240 by 80
|
||
pixels on the Series 3, 480 by 160 pixels on the Series 3a and 240 by 100 pixels on the Workabout (in
|
||
full Series 3 compatibility mode on the Workabour there is a gap of 10 pixels both above and below the
|
||
window).
|
||
|
||
|
||
In practice, it is rarely necessary for Hwif programs explicitly to create any additional windows.
|
||
|
||
|
||
Many graphics calls need to know the window ID of the window they are to operate upon. The Hwif
|
||
routine uF indMainWid returns this ID.
|
||
|
||
|
||
Typically, Hwif applications include a line such as
|
||
MainWid=uF indMainWid¢);
|
||
|
||
|
||
early in their SpecificInit routines.
|
||
|
||
|
||
Grey
|
||
|
||
|
||
On the Series 3a and the Workabour, drawing can be done not only in black & white but also in grey. To
|
||
draw grey in the main console window, it must first be enabled.
|
||
|
||
|
||
This is done by calling the function uEnableGrey which is more fully described in the Hwif Reference
|
||
Documentation chapter.
|
||
|
||
|
||
Ideally, if grey is to be used, it should be enabled early in the life of the application, preferably during
|
||
the initialisation phase. On no account should grey be used before being enabled - the application is liable
|
||
to fail.
|
||
|
||
|
||
Note that utnableGrey changes the ID of the main console window. Therefore, ensure that uFindMainwid is
|
||
called to fetch the new ID.
|
||
|
||
|
||
SS ee a ee ee
|
||
Dual mode applications
|
||
|
||
|
||
In general, applications which are intended to run on the Series 3 as well as on the Series 3a and/or
|
||
Workabout often need to be able to distinguish the type of machine on which they are Tunning.
|
||
|
||
|
||
For example, grey is available on the Series 3a and Workabout but not on the Series 3. Applications that
|
||
are to run on more than one type of machine may wish to make use of such additional features if they are
|
||
available.
|
||
|
||
|
||
Global variables such as _UseFul \screen can be used to help an application differentiate between the
|
||
different situations. This is discussed in more detail in the description of the function ucommontnit in the
|
||
Hwif Reference Documentation chapter.
|
||
|
||
|
||
One point that needs to be discussed here though is the question of application icons, since the form of
|
||
icon required for the Series 3 is different from that needed for the Series 3a and Workabout. For
|
||
|
||
|
||
27
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
applications that are intended to run on the Series 3 and either or both of the other machines, a .pic file
|
||
can be created to hold two separate icons.
|
||
|
||
|
||
In this situation, the .pic file will first contain a bitmap, 24 pixels wide by 24 pixels deep, for the
|
||
Series 3 icon. This is immediately followed by two bitmaps, each 48 pixels wide by 48 pixels deep, for
|
||
the Series 3a/Workabout icon. This is discussed more fully in the Series 3 Programming Overview
|
||
chapter in the Series 3/3a Programming Guide.
|
||
|
||
|
||
In order to ensure that the appropriate icon is used, the function hcrackCommandl ine must be called before
|
||
the call to uCommoninit. This must be done even though the application might have no interest in the
|
||
contents of the command line.
|
||
|
||
|
||
Thus, the general shape of the main¢) of an application might look like this:
|
||
|
||
|
||
GLDEF_C VOID main(VOID)
|
||
€
|
||
_UseFullScreen = TRUE;
|
||
hCrackCommandL ine();
|
||
uCommonI nit);
|
||
SpecificInit();
|
||
MainLoop();
|
||
}
|
||
|
||
|
||
This ensures that all the relevant Epoc statics are correctly initialised by the time the application connects
|
||
to the window server (ie inside ucommontnit); this is when the window server decides which icon to use
|
||
for the application.
|
||
|
||
|
||
If an application is also interested in the value returned by hCrackCommandt ine, then it should save the
|
||
returned value at this point. It must NOT call hcrackCommandL ine a second time.
|
||
|
||
|
||
EE ee ee a ae]
|
||
Storing data to file
|
||
|
||
|
||
Applications which manipulate significant quantities of data will in general wish to allow users to save
|
||
this data to file. Such programs need to address the following points:
|
||
|
||
|
||
= the user interface allowing the user to specify which file(s) to open, save, merge, ...
|
||
= the format of the data, as saved on file
|
||
= the mechanism of reading/writing the data to and from file
|
||
|
||
|
||
= possible special requirements of writing files in a manner that makes best use of the Flash
|
||
storage medium
|
||
|
||
|
||
= keeping the System Screen and the status window informed as to which file is currently being
|
||
used.
|
||
|
||
|
||
The final topic is discussed in the section following this one. On the question of user interface, Hwif
|
||
dialogs allow the inclusion of either of two types of filename specifier:
|
||
|
||
|
||
= filename selectors constrain the user to select a file that already exists - as is appropriate for
|
||
commands such as Open and Merge
|
||
|
||
|
||
= filename editors allow the user to type in the name of a file that may or may not already exist -
|
||
as is appropriate for commands such as Save as and New.
|
||
|
||
|
||
In either case, users can bring up the full filelist, simply by pressing TAB. Or they can press
|
||
CONTROL+TAB for ease of swifter navigation to more distant files. Again, in either case, the dialog
|
||
supplies an associated disk selector, without the programmer having to explicitly arrange for this. If the
|
||
user has enabled Remote Link, drives on REM:: automatically become available for selection, alongside the
|
||
local ones. All this happens just by virtue of a filename selector or editor being added to a dialog, being
|
||
taken care of by ROM resident code on behalf of the Hwif programmer.
|
||
|
||
|
||
Given also that there is a wide range of flags allowing further customisation of the exact behaviour of
|
||
these dialog items, Hwif programmers should find all their needs amply catered for, as regards the user
|
||
interface of choosing files.
|
||
|
||
|
||
28
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
eS eee
|
||
|
||
|
||
The Dbf file format
|
||
|
||
|
||
The Plib file i/o functions can be used for any variety of data formats on file, and Hwif programmers can
|
||
choose whatever they feel most comfortable with. (There is some special treatment for text files.)
|
||
|
||
|
||
However, much can be said in favour of the Dbf file format that is used by, among other applications,
|
||
the built-in Database and Agenda:
|
||
|
||
|
||
® It is designed with Flash-friendliness as a high priority, with incremental file modification as
|
||
individual records are updated
|
||
|
||
|
||
= rom-resident code provides a rich set of services to simplify access to files of this format
|
||
= services such as random and sequential access are both highly optimised
|
||
= other services such as merging and compressing databases are easy to use.
|
||
|
||
|
||
The Hwif library itself has very little to add to these Dbf services (there is a utility function,
|
||
hIsDbfCompressible, to determine whether a given Dbf channel supports file compression). More
|
||
important is the fact that the Hwif example applications illustrate clearly the use of these Dbf functions.
|
||
Dialling telephone numbers
|
||
|
||
Typical contents of databases include telephone numbers.
|
||
|
||
The Hwif library includes a function, hoTMFstring, to emit DTMF tones corresponding to a passed string.
|
||
|
||
|
||
This function uses the tone lengths and pauses as specified by the user in the World application (or
|
||
otherwise), and reverts to system defaults in the absence of any such setting.
|
||
|
||
|
||
= SSS SS Se ee ee et ee ee eee Ee
|
||
Communication with the System Screen
|
||
|
||
|
||
An important aspect of the Series 3 is the way all the built-in applications communicate with the System
|
||
Screen:
|
||
|
||
|
||
« This name of any file currently open is displayed in bold in the file list in the System Screen
|
||
= This name is also displayed in any status window shown
|
||
|
||
|
||
= On a request from the System Screen, an application can close itself down tidily, saving any
|
||
changes to file as appropriate
|
||
|
||
|
||
" Alternatively, applications can be requested to switch files, to change which file they are
|
||
currently editing.
|
||
|
||
|
||
Applications use two mechanisms to communicate to the Series 3 OS their preferences concerning file
|
||
switching, as well as the name of the file they are currently editing:
|
||
|
||
|
||
= some data is written at compile time into a shell data (shd) file that is linked into the
|
||
application's .app file; this data includes the expected extension of any files to be edited, and the
|
||
default top-level directory, as well as the more basic point of whether the application is file-
|
||
based at all
|
||
|
||
|
||
= other data can be written at run time to various reserved Epoc statics; these include the full path
|
||
name of the file currently being edited.
|
||
|
||
|
||
There are routines in the Hwif library to take care of keeping the various Epoc statics up to date.
|
||
However, applications programmers may need to know about two of these statics directly:
|
||
|
||
|
||
UWORD DatLocked this should be set to TRUE whenever, over a potentially extended
|
||
period, the application is unable to respond to a Switchfile or
|
||
Shutdown message from the System Screen
|
||
|
||
|
||
TEXT *DatUsedPathNamePtr this points to a buffer giving the full path name of the file
|
||
currently being edited.
|
||
|
||
|
||
For full details on the interaction between Series 3 applications and the System Screen, see the chapter
|
||
Communicating with the System Screen in the Series 3/3a Programming Guide.
|
||
|
||
|
||
29
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
Reading the command line
|
||
|
||
|
||
In addition to being able to respond to requests of the Switchfile or Shutdown varieties, file-based
|
||
applications on the Series 3 should also be able to read the command line they are sent when they start.
|
||
This has a special form which can, however, be interpreted by means of the Hwif call hcrackCommandL ine.
|
||
|
||
|
||
File-based applications would ordinarily include a call to hcrackConmandL ine as part of their initialisation.
|
||
One of the consequences of this call is that the Epoc static patUsedPathNamePtr is initially pointed to an
|
||
appropriate zero-terminated string in the body of the command line.
|
||
|
||
|
||
Storing the name of the file currently open
|
||
|
||
|
||
Initially, the name of the open file is part of the command line. However, when this has to be changed -
|
||
either as a result of an Open or Save as command inside the application, or in response to a Switchfile
|
||
request from the System Screen - a new buffer has to be used for this purpose. (The command line buffer
|
||
is sized to precisely the right length needed for the initial file.)
|
||
|
||
|
||
Typically, file-based applications will maintain a permanent buffer, of length p_FNAMESIZE, to store any
|
||
change in the name of the file open. Once the new name has been copied into this buffer, the call
|
||
hSetUpStatusNames should be made, to adjust all Epoc statics as appropriate, including
|
||
DatUsedPathNamePtr.
|
||
|
||
The protocol of messages from the System Screen
|
||
|
||
|
||
A keycode with value equal to cONS_EVENT_COMMAND means that the System Screen wishes to communicate
|
||
with the application. In case there is any doubt as to what the message is, it can be determined by making
|
||
a Call to wGetCommand.
|
||
|
||
|
||
For more details, see Communicating with the System Screen in the Series 3/3a Programming Guide.
|
||
|
||
|
||
SSS ESS a Sa ee a eee
|
||
Some notes on run-time errors
|
||
Errors arising from Hwif calls include the following types:
|
||
|
||
|
||
=" programmer errors, such as making calls with unsuitable parameters (or disregarding earlier
|
||
errors) - these may well result in the application being panicked
|
||
|
||
|
||
= as a special case of programmer error, menus or dialogs may turn out too wide to display
|
||
properly on the screen; this is generally indicated by a return value E_GEN_TOOWIDE from a call
|
||
such as uRunDialog (there is also an associated error E_GEN_TOOMANY) and the user will see a Too
|
||
wide error alert
|
||
|
||
|
||
= shortage of memory in the application data space, generally indicated by a return value
|
||
E_GEN_NOMEMORY
|
||
|
||
|
||
# shortage of memory in the Window Server data space - also indicated by the same return value.
|
||
|
||
|
||
A well-written application needs to be able to recover from an out-of-memory (OOM) error, without
|
||
falling over in the process or corrupting or losing any data. In general, an application should always test
|
||
the return value of Hwif calls, to see whether they have succeeded, or whether they have failed with
|
||
OOM.
|
||
|
||
|
||
However, there are some cases when an application can legitimately assume that a call always succeeds:
|
||
= if the call is part of the initialisation of the application
|
||
|
||
|
||
= and if the application has specified its start-up heap appropriately (this is done as a line in the
|
||
.pr project file that orchestrates linking)
|
||
|
||
|
||
= and if the call only uses resources in the data space of the application (as opposed to resources in
|
||
the data space of the Window Server).
|
||
|
||
|
||
Note that in no case can an application legitimately assume the success of a call which requires Window
|
||
Server resources.
|
||
|
||
|
||
Application writers can make use of the Spy application to discover how much heap an application
|
||
requires in order to start.
|
||
|
||
|
||
30
|
||
|
||
|
||
1 INTRODUCTION TO HWIF
|
||
See
|
||
|
||
|
||
Some errors to consider
|
||
|
||
|
||
Other errors which application writers may need to consider include:
|
||
= running out of SSD space when writing to a file
|
||
" — not being able to find a specified file (because the relevant SSD has been removed)
|
||
# the SSD being removed part way through a file operation
|
||
|
||
|
||
" (perhaps the least obvious) the failure of a remote link connection to another filing system - say
|
||
because the user has shut the connection down since opening a file on that filing system.
|
||
|
||
|
||
Strategies on handling errors
|
||
|
||
|
||
Any error during application initialisation is generally fatal. The user should be informed of what has
|
||
happened and the application terminated.
|
||
|
||
|
||
For example:
|
||
|
||
|
||
LOCAL_C VOID SpecificInit(VOID)
|
||
{
|
||
INT command;
|
||
|
||
|
||
MainWid=uF indMainwWid¢();
|
||
|
||
CreateGC();
|
||
|
||
command=hCrackCommandL ine);
|
||
|
||
if (ObeySystemCommand( command, DatUsedPathNamePtr , &dH))
|
||
p_exit(0);
|
||
|
||
ReduceScreenSize();
|
||
|
||
gBorder(W_BORD_CORNER_4);
|
||
|
||
wsEnable();
|
||
|
||
DisplayStart(); =
|
||
|
||
>
|
||
|
||
|
||
In the above example, notifying the user of the error takes place inside the routine obeysystemConmand. In
|
||
other cases, an application may wish to take advantage of the fact that if it calls p_exit with a negative
|
||
parameter, the OS will automatically present a notifier on its behalf. The text in the notifier is the system
|
||
error message corresponding to the parameter to p exit.
|
||
|
||
|
||
Another straightforward case to handle is an error, such as OOM, while building up a dialog. In fact, all
|
||
that needs to be done in this case is to follow the procedure given in several of the earlier examples: test
|
||
the results of calls such as uOpenDialog and uAddDialogItem, and simply break out of the general stream of
|
||
program flow when an error is detected. The user will see the error (presented by Hwif library code), can
|
||
opt to free some memory by shutting other applications down, and then retry the command by invoking
|
||
the same menu choice as before.
|
||
|
||
|
||
A similar approach can often be taken for cases such as errors when writing to an SSD. Alternatively ,
|
||
applications may wish, in these cases, to provide their own retry loop, and may even wish to insist that
|
||
users successfully conclude the loop before allowing them to continue. This is appropriate for file-based
|
||
applications in which the file must always be kept up to date.
|
||
|
||
|
||
Sometimes, indeed, all that an application can do, on detecting an error, is to notify the user accordingly,
|
||
and then terminate the application. For example, if a user removes an SSD containing an open file, and
|
||
an application tries to read data from this file, the following sequence of events will occur:
|
||
|
||
|
||
= the OS will present its own notifier, requesting that the SSD be reinserted
|
||
= this notifier has two options: Retry and Fail
|
||
= if the user selects Fail, the OS returns the error E_FILE_ABORT to the application.
|
||
|
||
|
||
In such a case, there is little an application can do, apart from terminating gracefully.
|
||
|
||
|
||
Reverting to the previous file
|
||
|
||
|
||
Ideally, a file-based application should aim, where possible, at being able to recover from failing to
|
||
switch files (in response either to a menu command, or to a request from the System Screen) by means of
|
||
reverting to the previously open file.
|
||
|
||
|
||
Thus suppose an application currently has file name1 open, on file channel fcb1, and that the user requests
|
||
that file name2 be opened instead. Suppose further that, for one reason or another, name2 cannot be loaded
|
||
|
||
|
||
31
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
into the application (it may be the wrong type of file, it may currently be locked by another application,
|
||
or whatever). Then the user could see one of two things:
|
||
|
||
|
||
= an error notifier is presented, and then the application terminates
|
||
= an error notifier is presented, and then the application reverts to its previous state.
|
||
|
||
|
||
Evidently, the latter is preferable. It allows the user the opportunity to make due amends (for example,
|
||
closing down another application which has the file already open) and then retry.
|
||
|
||
|
||
A simple approach to this end is to keep the first file open until the second file is successfully loaded.
|
||
Only when this is complete are the resources associated with the first file freed.
|
||
|
||
|
||
For this reason, a file-based application will often possess a routine ChangeOverTo (with parameters such
|
||
as the new filename and its new control block) that has the role of finally closing down the previous file,
|
||
and then altering the application's records of the name of the current file. See the example given earlier,
|
||
in the section Typical dialog usage.
|
||
|
||
|
||
Errors when formatting edit boxes
|
||
|
||
Single- and multi-line edit boxes pose an additional type of problem, in handling OOM errors.
|
||
|
||
In making a change to an edit box, OOM can occur in either of two ways:
|
||
= there is insufficient memory to increase the contents of the edit box (eg to add another character)
|
||
® the contents can be grown but the Jayourt cannot be recalculated.
|
||
|
||
|
||
The point is that layout information (the location of all line breaks due to word-wrap, and so on) is
|
||
dynamically allocated; consequently, the calculation of layout can fail.
|
||
|
||
|
||
Paradoxically, it turns out that the best reaction an application can make to the second kind of error is
|
||
usually to ignore it. Hwif library code will ensure that the user is informed of the shortage of memory,
|
||
and the edit box will only be partially redrawn. Despite only being able to redraw itself partially, the edit
|
||
box will not crash, and will hold on to all its contents in the meanwhile. Once additional memory
|
||
becomes available, the edit box will recalculate its layout, and then redraw itself correctly.
|
||
|
||
|
||
Sa ae aa a a ae eg ee
|
||
Future developments
|
||
In summary of the foregoing, it can be said that Hwif fulfils two separate roles with regard to
|
||
applications programmers:
|
||
= in its own right, it supports the development of a large variety of significant and potent
|
||
applications, with an agreeable user interface
|
||
|
||
|
||
= ina broader context, it serves as a critical stepping stone towards a full mastery of the Series 3
|
||
API, including object orientation, low-ram window redraws, and the p_enter/ p_leave
|
||
mechanism that removes most of the clutter from error handling.
|
||
|
||
|
||
Whether programmers who learn Hwif will be content to stop there, and exploit the considerable avenues
|
||
this opens up in its own right, or whether they will wish to press on in due course to master the full
|
||
Series 3 API, will obviously vary from programmer to programmer. Both choices make good sense.
|
||
|
||
|
||
32
|
||
|
||
|
||
CHAPTER 2
|
||
|
||
|
||
WORKED EXAMPLES IN HWIF
|
||
|
||
|
||
SS a eee
|
||
How to use the supplied examples
|
||
The supplied example applications serve two purposes:
|
||
|
||
= tutorial, with embedded suggestions for further exploration
|
||
|
||
= reference pool, with varied illustrations of many parts of the Series 3 ROM software.
|
||
|
||
|
||
In neither case is there any need for would-be Hwif programmers to examine the code for all of the
|
||
example applications provided with this manual; nor is there any need to digest all the associated
|
||
discussion this chapter contains. Instead, the expectation is that prospective applications developers will
|
||
work through items in the tutorial that they find of interest, and will merely skim through the other parts.
|
||
|
||
|
||
In this way, prospective applications developers will familiarise themselves with at least the general
|
||
contents of the example applications. Then when they are planning their own application, they may well
|
||
recall that one of the example applications does something similar (with a dialog, say) to something
|
||
planned in their own application. In that case, the application developer can look up the relevant piece of
|
||
source code, and consult the associated documentation, to discover how to produce the desired effect.
|
||
|
||
|
||
Strangely enough, it is often going to be unhelpful for Hwif application writers to think that a certain
|
||
feature of the user interface of, for example, the built-in Agenda application ought to be duplicated in
|
||
their own application. For even were the relevant source code available for perusal, that code would
|
||
almost certainly be laden with proprietary object oriented techniques to the extent of being well out of the
|
||
grasp of the Hwif application writer. On the other hand, familiarity with the supplied Hwif example
|
||
applications is likely to provide a much more appropriate set of models to follow. Quite probably, there
|
||
will be something in one of these applications that does essentially the same job as in the desirable feature
|
||
of the built-in application (albeit possibly not so elegantly). In contrast to the code of the built-in
|
||
application, the code of the example Hwif application is suitable for being copied into the developer's
|
||
own application.
|
||
|
||
|
||
The embedded suggestions
|
||
|
||
|
||
In all forms of learning, practice makes perfect. This is as true for programming in a new system (such as
|
||
Hwif), as it is for learning in general.
|
||
|
||
|
||
Accordingly, this chapter is regularly punctuated with "Suggestions" sections. These have been provided
|
||
so that the would-be Hwif programmer who feels a bit unsure about some topic can have plenty scope for
|
||
practising in that area. Trying out a few of the suggestions should increase understanding and boost
|
||
confidence. Additionally, many of the suggestions provide a foretaste of topics to be discussed shortly
|
||
afterwards. Others give hints on ideas that Hwif programmers might like to develop independently.
|
||
|
||
|
||
Of course, readers are free to think up their own ideas for how to modify the various examples presented.
|
||
However, especially in the earlier stages, ideas that seem perfectly straightforward extensions of the
|
||
examples given might turn out to be significantly more involved than at first thought. Careful thought
|
||
has been applied to the lists of suggestions given in the text, to avoid precisely this problem.
|
||
|
||
|
||
Preview of the example applications
|
||
|
||
|
||
The first example application, Query, focuses almost exclusively on the basic menu and dialog
|
||
functionality of Hwif (use of the Hwif time-text utility functions is also illustrated). Examples are given
|
||
of each of the possible items that can be included in dialogs. There are only a few graphics calls, and
|
||
|
||
|
||
33
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
these are completely straightforward. There is no file-handling (likewise in fact for all of the first four
|
||
example applications). The application itself provides answers to questions that a user may wish to pose,
|
||
such as the conversion of centigrade values into Fahrenheit or miles into kilometres, the next occurrence
|
||
of a certain date combination (eg Friday the 13th), the size of a specified file, and the encryption and
|
||
decryption (using a supplied key) of given text messages.
|
||
|
||
|
||
The next example, Tables, introduces the important idea of reading a key asynchronously. This is
|
||
because it involves the user typing in the answer to a multiplication problem (such as "4 times 9") before
|
||
a timer that is ticking away on screen runs out completely. The application also introduces use of a
|
||
simple Hwif edit box (with double height characters), and includes examples of several useful graphics
|
||
techniques - with an animated action button and a growing gauge display outside of the context of a
|
||
dialog. On exit, the state of the application is recorded in an environment variable, which is used to re-
|
||
initialise the application the next time it is run.
|
||
|
||
|
||
The application Remind functions as a sort of half-way house between the built-in Agenda application and
|
||
the built-in Time application. It allows users to set alarms with text strings, which on expiry can, if
|
||
desired, be "snoozed" by specified time intervals (but still allowing access to the remainder of the
|
||
|
||
Series 3 in the meantime). Evidently, this application illustrates access to the alarm server device. As
|
||
such, it demonstrates more of the important concepts concerning asynchronous i/o. Remind also
|
||
introduces another large subject: printing and access to the Print Setup dialog. The main screen display is
|
||
a scrolling list of all reminders scheduled by the user, automatically sorted into chronological order. The
|
||
graphics calls employed demonstrate how to achieve smooth scrolling (without undue screen flicker).
|
||
Finally, on receipt of the keypress CONTROL+MENU, Remind hides or shows a permanent status window,
|
||
and adjusts the rest of its display accordingly.
|
||
|
||
|
||
Notes is another application that functions as a half-way house between the functionality of two of the
|
||
built-in applications: it straddles some of the characteristics of the built-in Database and Word
|
||
applications. The screen is divided up into three edit windows - Title, Notes, and Find - with the data for
|
||
a series of notes being directly edited in place (as opposed to being manipulated only through dialogs).
|
||
As well as providing a wide-ranging survey of the editing facilities available via Hwif, the Notes
|
||
application also gives a further example of printing.
|
||
|
||
|
||
The next example, Dump, produces a Hex dump of a nominated file. This is displayed on the screen in
|
||
the first instance, but a selected portion of the dump can be written out to a nominated file. The dump
|
||
can be scrolled in any direction, and it is possible to search it, either for strings of text, or for byte
|
||
streams. The application introduces file-handling, both of the file to be dumped (initially chosen from the
|
||
System Screen), and of the file to receive a written record of the dump. Finally, the use of a special mode
|
||
is illustrated, in which repeated cursor keypresses may cause the display to be drawn in its new position
|
||
only when there is a suitable delay in receiving keys.
|
||
|
||
|
||
Then comes a couple of applications illustrating different uses of the Dbf database subsystem. These
|
||
applications differ from both Notes and Remind in that they make permanent copies of their data on file
|
||
(whereas Notes and Remind just operate with in-memory data). Both of these applications deal with
|
||
Shutdown and Switchfile messages from the System Screen.
|
||
|
||
|
||
The first of these Dbf applications, Tele, is a simple example of a fixed field database, with fields for a
|
||
name, a department code, and a telephone extension number. Records can be added, deleted, updated,
|
||
searched for, and even sorted (using quicksort). A couple of other Dbf file options are also illustrated:
|
||
Merge and Copy. Telephone numbers, once found, can have corresponding DTMF tones emitted. The
|
||
main screen display is straightforward, involving double height characters.
|
||
|
||
|
||
The application Days illustrates a Dbf database that stores peoples’ birthdays (or other days of interest),
|
||
along with a notes field. The application maintains an in-memory index which sorts the entries by date to
|
||
facilitate a more meaningful presentation of the contents of the database. The main screen view is
|
||
somewhat elaborate: it can be toggled between a series of edit boxes (as in Notes) and a scrolling list (as
|
||
in Remind). Alteration of the data takes place by direct manipulation in the edit boxes.
|
||
|
||
|
||
Many secrets of the inner workings of the Series 3 are revealed by the application Spy, which presents a
|
||
list of all the processes running at any one time, together with specified information, such as the number
|
||
of cells in the allocator heap of that process, and the watermark on its stack. This list can be refreshed on
|
||
a timer, so the application also provides an additional example of asynchronous keyboard reads. For
|
||
more details on what can be done using Spy, see the chapter Using Spy.app in the Series 3/3a
|
||
Programming Guide.
|
||
|
||
|
||
Associated with Spy is a maverick application called Joker, whose main role is to instantiate all the
|
||
special cases tested for by Spy. For example, Joker can corrupt its allocator heap on demand, in a variety
|
||
of different ways.
|
||
|
||
|
||
Finally, the application Iconed is a full-blown icon editor, which can be used to design icons for new
|
||
applications (and to improve the icons shipped with the example applications). This illustrates a whole
|
||
variety of more advanced graphics calls, as well as another set of possibilities in file-based applications.
|
||
|
||
|
||
34
|
||
|
||
|
||
2 WORKED EXAMPLES IN HWIF
|
||
|
||
|
||
SS SSS SS re aE
|
||
Getting started: the Query application
|
||
|
||
|
||
Hello World
|
||
Consider the following program:
|
||
|
||
|
||
#include <p_std.h>
|
||
#include <wlib.h>
|
||
#include <hwif.h>
|
||
|
||
|
||
GLDEF_C VOID main(VOID)
|
||
€
|
||
WMSG_KEY key;
|
||
|
||
|
||
uCommoninit();
|
||
|
||
wSetBusyMsg("Hello world",W_CORNER_BOTTOM_LEFT);
|
||
uGetKey(&key);
|
||
|
||
uGetKey(&key) ;
|
||
|
||
p_exit¢Q);
|
||
|
||
3
|
||
|
||
|
||
This can be typed into your favourite programming editor (either inside or outside the TopSpeed
|
||
programming environment invoked by the ts command). Or, to save time, it can be loaded from disc: this
|
||
program is supplied in the directory \sibosdk\hwdemo\ as qui.c (with the name of this file indicating that
|
||
it is the first version of the Query application).
|
||
|
||
|
||
The meaning of various lines in this program is as follows:
|
||
|
||
|
||
#include <p_std.h> This is the standard Psion header file, containing the function prototypes for
|
||
all "simple" Plib routines (such as p_exit), as well as the typedefs for the likes
|
||
of GLDEF_c and voip
|
||
|
||
|
||
#include <wlib.h> This is the Wlib header file, containing the function prototypes for all Wlib
|
||
routines, such as wSetBusyMsg, as well as the definitions of constants like
|
||
W_CORNER_BOTTOM_LEFT and structs like WMSG_KEY
|
||
|
||
|
||
#include <hwif.h> This is the Hwif header file, containing the function prototypes for all Hwif
|
||
routines, such as uConmonInit, as well as the definitions of numerous constants
|
||
and structs
|
||
|
||
|
||
uCommonInit(); The first statement in all Hwif programs; miss this out and the above program
|
||
will panic when it reaches the next line
|
||
|
||
|
||
wSetBusyMsg(...); | Display the indicated text as a flashing message at the bottom left comer of the
|
||
screen
|
||
|
||
|
||
uGetKey(&key); Wait for a keypress event to be delivered (see below on why this line appears
|
||
twice in the above program)
|
||
|
||
|
||
p_exit(0); Exit the application cleanly.
|
||
|
||
|
||
To build the program
|
||
|
||
|
||
The next stage is to convert the above .c source file into a .img executable file. Any such conversion is
|
||
governed by a TopSpeed project file, with extension .pr. (The .pr file is involved whether or not
|
||
compilation takes place inside the ts system.)
|
||
|
||
|
||
In fact, all but two of the Hwif demo applications can use the project file unnamed.pr that can be found
|
||
in the same directory as the source modules. The exceptions are:
|
||
|
||
|
||
= Spy which has three different source modules and therefore its own .pr file (spy.pr)
|
||
« Remind which has its own remind.pr
|
||
|
||
|
||
For more details on .pr files, and on the associated housekeeping batch files such as make.bat, see the
|
||
chapter Building an Application in the General Programming Manual.
|
||
|
||
|
||
To create qul.img, simply type make qu’.
|
||
|
||
|
||
35
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
Note that the unnamed.pr in \sibosdk\hwdemo has one extra line than the copy in \sibosdk\demo:
|
||
#pragma linkChwif. lib)
|
||
to ensure that the Hwif library is pulled into the link.
|
||
|
||
|
||
Errors during linking
|
||
However the .img file is built, a spurious pair of warnings may, regrettably, be issued by the linker:
|
||
|
||
|
||
_ClassTable is duplicated, files involved are hwif and rlib
|
||
_ExtCatTable is duplicated, files involved are hwif and rlib
|
||
|
||
|
||
These warnings (which, at the time of writing, cannot be disabled) should be ignored. It is, however,
|
||
important that the HWIF and RLIB libraries are linked in the correct order. The RLIB library is
|
||
automatically included in the link and should not be explicitly included in any application's .pr file.
|
||
|
||
|
||
Needless to say, any other reported errors should be carefully attended to.
|
||
|
||
|
||
Running the application from the Series 3 System Screen
|
||
|
||
|
||
Once the file guJ.img has successfully been built, it can be copied (using Remote Link on the Series 3
|
||
and McLink on the PC) into a top-level \img\ directory on a Series 3. The name Qu/ will now appear
|
||
under the Runimg icon in the System Screen. (Update the System Screen display, if need be, by pressing
|
||
SYSTEM; you can press CONTROL -+SYSTEM to position to the Runimg icon; if perchance you have
|
||
removed this icon, re-install it with the Jnstall standard menu command.)
|
||
|
||
|
||
Cursor down onto the name Qu/ and press ENTER. The screen will clear completely, except for a
|
||
message Hello world flashing at the bottom left hand corner. On any keypress, the application terminates.
|
||
|
||
|
||
For an explanation of how to debug an application such as Qu1, see in the first instance the chapter
|
||
Building an Application in the General Programming Manual, and for more details, the SIBO Debugger
|
||
manual.
|
||
|
||
|
||
Further explanation of qu1.c
|
||
|
||
|
||
The reason why qguJ.c contains two calls to uGetkey can now be clarified. Whenever any application
|
||
comes into the foreground, it is sent notification of this fact. For Hwif programs, this notification takes
|
||
the form of a special keypress. The value of this keypress is CONS_EVENT_FOREGROUND, that is 0x401 (consult
|
||
the header file p_cons.h - which is automatically #included by Awif.h.) This (generalised) keypress is
|
||
sent to the application as soon as it starts, since when it starts, it comes into foreground. Hence the need
|
||
for a second call to uGetKey, to make the program wait until another keypress is received, before
|
||
terminating.
|
||
|
||
|
||
Incidentally, the code
|
||
|
||
|
||
GLDEF_C VOID main(VOID)
|
||
4
|
||
|
||
|
||
p_exit(value);
|
||
}
|
||
|
||
|
||
is of course equivalent to
|
||
|
||
|
||
GLDEF_C INT main(VOID)
|
||
€
|
||
|
||
|
||
return(value);
|
||
>
|
||
|
||
|
||
However, qul.c uses the former method since it is actually rare for Hwif applications to terminate at the
|
||
bottom of their main routines. Instead, they usually terminate, with a call to p exit, as soon as a suitable
|
||
menu command is received (but after first carrying out any necessary checks and/or saving data to file);
|
||
|
||
in-line calls to p_exit are also common when errors arise during application initialisation.
|
||
|
||
|
||
Suggestions for modifying Qu1
|
||
|
||
|
||
= Replace the two calls to uGetKey with a loop that repeatedly waits for keypresses, and which
|
||
terminates the program only on a designated keypress
|
||
|
||
|
||
® Inside this loop, test for other chosen keypresses, and make calls to wsetBusyMsg with parameters
|
||
that depend on what the keypress is
|
||
|
||
|
||
36
|
||
|
||
|
||
2 WORKED EXAMPLES IN HWIF
|
||
Ses SSeS
|
||
|
||
|
||
= Include, on various keypresses, calls to winfoMsg as well as to wSetBusyMsg; also try calls to
|
||
p_sound, wsAlertwW, and wClientPosition (to position the application to background)
|
||
|
||
|
||
= Instead of displaying Hello world, display the current time and/or date
|
||
|
||
|
||
= Deliberately call p_exit with a negative parameter, to see what the effect is.
|
||
|
||
|
||
introducing a GC
|
||
|
||
|
||
There are many graphics calls in the Wlib library that cannot be made unless a GC (graphics context)
|
||
exists. This includes the function gBorder that provides the standard Series 3 framing for regions of the
|
||
screen,
|
||
|
||
|
||
Accordingly, one step up from quI.c is for main to become (as in gu2.c)
|
||
|
||
|
||
GLDEF_C VOID main(VOID)
|
||
€
|
||
WMSG_KEY key;
|
||
|
||
|
||
uCommonI nit);
|
||
|
||
CreateGC();
|
||
|
||
gBorder(W_BORD_CORNER_4);
|
||
|
||
wSetBusyMsg("Hello world", W_CORNER_BOTTOM_LEFT);
|
||
|
||
|
||
FOREVER
|
||
€
|
||
uGetKey(&key);
|
||
if (key.keycode==(W_SPECIAL_KEY|'x'))
|
||
p_exit(0);
|
||
>
|
||
>
|
||
|
||
|
||
with the application-supplied routine createcc being
|
||
|
||
|
||
LOCAL_C VOID CreateGC(VOID)
|
||
€
|
||
INT hge;
|
||
|
||
|
||
hgc=gCreateGCO(uF indMainWid());
|
||
if Chgc<0)
|
||
|
||
P_exit(hge);
|
||
>
|
||
|
||
|
||
The GC created has default characteristics (hence the call gcreateGc0 as opposed to the more general
|
||
gCreateGC, which takes more parameters). The one parameter that has to be passed to gCreateGco is the ID
|
||
of the window the GC is attached to. The Hwif call uFindMainwid returns, as its name implies, the ID of
|
||
the window filling the screen, that was created by the call to uCommoninit.
|
||
|
||
|
||
Note that the call gcreateGco can fail. This is because it requires the Window Server to allocate additional
|
||
resources, and it may be the case, if there are many other applications running on the Series 3, some of
|
||
which have many windows, that the Window Server cannot satisfy this request.
|
||
|
||
Suggestions for modifying Qu2
|
||
|
||
|
||
= Now that a GC has been created, try out the effect of other Wlib calls, such as gDrawLine,
|
||
gDrawBox, gBorderRect, gClrRect, gPrintText, gPrintBoxText, and ginvObloid - all (possibly) in
|
||
response to the receipt of suitable incoming keypresses
|
||
|
||
|
||
= Use gCreateGc instead of gCreateGcO, and experiment with the other parameters (eg the font and
|
||
style fields of the G_cc struct required)
|
||
|
||
|
||
= Use gSetcc to change the nature of the GC dynamically on designated keypresses (there will
|
||
need to be a permanent record of the handle hgc of the GC created)
|
||
|
||
|
||
= Experiment with graphics calls that, being non GC-based, require to be passed the ID of the
|
||
relevant window: wScrollWin, wOrawTextCursor, wMakeInvisible, and wsCreateClock.
|
||
A status window and a menu bar
|
||
|
||
|
||
To look more like a genuine Series 3 application, the display should, where possible, sport a status
|
||
window. This requires two steps:
|
||
|
||
|
||
= calling the Wlib function wsEnable to display a permanent status window
|
||
|
||
|
||
37
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
= resizing the main graphics window, so that it no longer obscures the region where the status
|
||
window is displayed.
|
||
|
||
|
||
Provided the call to g8order is delayed until after the screen is resized smaller, the border will
|
||
automatically appear with an appropriately reduced width.
|
||
|
||
|
||
Note that the call wsEnabte has no visible effect unless the main window of the application has been
|
||
resized appropriately: permanent status windows always come at the back of the window order.
|
||
|
||
|
||
The routine to resize the main graphics window smaller is as follows:
|
||
|
||
|
||
LOCAL_C VOID ReduceScreenSize(VOID)
|
||
{
|
||
W_WINDATA wd;
|
||
|
||
|
||
wd.extent.tl.x=wd.extent.tl.y=0;
|
||
|
||
wd.extent .width=189;
|
||
|
||
wd.extent .height=80;
|
||
|
||
wSetWindow(MainWid,W_WIN_EXTENT,&wd);
|
||
|
||
if CuErrorValue(wCheckPoint()))
|
||
P_exit¢0):
|
||
|
||
>
|
||
|
||
|
||
Note the following points:
|
||
= the static variable Mainwid stores the result of a prior call to uF indMainwWid
|
||
|
||
|
||
= unexpectedly, it is possible for the resize to fail on account of lack of Window Server memory;
|
||
this is because the backed-up bitmap for the reduced window size is created before the one for
|
||
the old window size is finally discarded
|
||
|
||
|
||
= the call to wsetwindow is not flushed straightaway because it does not return a value; in other
|
||
words, the call may not be executed immediately. However, as the above point notes, it is
|
||
possible that the call could fail when it does eventually execute.
|
||
To make sure that the call is executed immediately, it is necessary to flush the Window Server
|
||
command buffer immediately after the call is made and to check that no error is reported as a
|
||
result; this is the point of the otherwise little-used call weheckPoint.
|
||
|
||
|
||
= The width and height values are suitable for the Series 3 screen, or for the Series 3a or
|
||
Workabout in Series 3 emulation mode. For a Series 3a in native mode, or a Workabout in full-
|
||
screen emulation mode, alternative values may be more appropriate.
|
||
|
||
|
||
The lines of code
|
||
|
||
|
||
if CuErrorValue(wCheckPoint()))
|
||
p_exit¢0);
|
||
|
||
|
||
are equivalent to
|
||
|
||
|
||
INT ret;
|
||
|
||
|
||
ret=wCheckPoint();
|
||
if (ret)
|
||
p_exit(ret);
|
||
|
||
|
||
Both methods result in the user being notified of any error (with an appropriate error string being
|
||
presented), and in the application being terminated in response to the error.
|
||
|
||
|
||
The routine ReduceScreenSize is added into the developing Query application in the file gu3.c. Qu3 also
|
||
adds in the presentation of a menu bar. There is now enough initialisation to create a separate
|
||
initialisation routine
|
||
|
||
|
||
LOCAL_C VOID SpecificInit(VOID)
|
||
|
||
|
||
€
|
||
|
||
MainWid=uF indMainWid();
|
||
ReduceScreenSize();
|
||
CreateGC();
|
||
gBorder(W_BORD_CORNER_4);
|
||
wsEnable();
|
||
winfoMsg("Hello world");
|
||
>
|
||
|
||
|
||
38
|
||
|
||
|
||
2 WORKED EXAMPLES IN HWIF
|
||
a eee
|
||
|
||
|
||
and main now simplifies to what is, in Hwif applications, its standard form:
|
||
|
||
|
||
GLDEF_C VOID main(VOID)
|
||
€
|
||
uCommonInit();
|
||
SpecificInit();
|
||
MainLoop();
|
||
>
|
||
|
||
|
||
This leaves the new routine MainLoop:
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
{
|
||
INT ret;
|
||
WMSG_KEY key;
|
||
|
||
|
||
FOREVER
|
||
€
|
||
uGetKey(&key);
|
||
if (key. keycode&W_SPECIAL_KEY)
|
||
ManageCommand( key. keycode&(“W_SPECIAL_KEY));
|
||
else if (key. keycode==W_KEY MENU && !(key.modifiers&W_CTRL_MODIFIER))
|
||
{
|
||
ret=uPresentMenus();
|
||
if (ret>0)
|
||
ManageCommand( ret);
|
||
>
|
||
|
||
|
||
}
|
||
which is an elaboration of the lines
|
||
|
||
|
||
FOREVER
|
||
{
|
||
uGetKey(&key);
|
||
if (key.keycode==(W_SPECIAL_KEY|'x!'))
|
||
p_exit(0);
|
||
>
|
||
|
||
|
||
from qu2.c.
|
||
Note the following points:
|
||
|
||
|
||
= the above code ignores the key combination CONTROL+MENU which often toggles the visibility
|
||
of any permanent status window; for this application, because the main display area (apart from
|
||
the status window) is so empty, there is no special merit in allowing the permanent status
|
||
window to be hidden
|
||
|
||
|
||
= only positive return values from uPresentMenus are of interest; other values correspond to the
|
||
user cancelling out of the menu bar by pressing ESCAPE (as well as to cases where the menu
|
||
presentation failed due to lack of memory)
|
||
|
||
|
||
= the program has to provide two passages to the routine ManageConmand: one following the
|
||
presentation of the menu bar, and the other following interception of a menu accelerator when
|
||
no menu is showing.
|
||
|
||
|
||
It is worth mentioning a potential problem with the MainLoop routine. On the Series 3 only the lower case
|
||
characters ‘a’ to 'z' plus the four characters '+','-’,'*' and '/' (in English language versions) are valid
|
||
accelerators and the above code will work unambiguously. The Series 3a and Workabout, however,
|
||
permit the uppercase alphabetic characters 'A' to 'Z'. To cater for this situation, MainLoop could be
|
||
changed as shown below:
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
€
|
||
INT code;
|
||
INT ret;
|
||
WMSG_KEY key;
|
||
|
||
|
||
39
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
—_——. SEE
|
||
|
||
|
||
FOREVER
|
||
€
|
||
uGetKey(&key);
|
||
if (key. keycode & W_SPECIAL_KEY)
|
||
€
|
||
code = key. keycode & ("W_SPECIAL_KEY);
|
||
if (key.modifiers & W_SHIFT_ MODIFIER)
|
||
code = p_toupper(code);
|
||
ManageCommand( code);
|
||
>
|
||
else if (key.keycode==W_KEY_MENU && !(key.modifiers&W_CTRL_MODIFIER))
|
||
.¢
|
||
ret=uPresentMenus();
|
||
if (ret>0)
|
||
ManageCommand( ret);
|
||
>
|
||
3
|
||
>
|
||
|
||
|
||
The function p_toupper is needed to ensure that the keycode is in uppercase before being passed to the
|
||
ManageCommand routine. Note, however, that no change is required to the code concerned with selecting a
|
||
command by highlighting its menu item and pressing ENTER (implemented by the call to uPresentMenus).
|
||
|
||
|
||
Defining the menu bar
|
||
|
||
|
||
The top of qu3.c is as follows:
|
||
|
||
|
||
LOCAL_D TEXT *cmds[}=
|
||
{
|
||
"ji Inches/Centimetres",
|
||
“mMi les/Kilometres",
|
||
"LPounds/Kilogrammes",
|
||
"pPints/Litres",
|
||
"fFahrenheit/Centigrade",
|
||
"dDay of week",
|
||
"cCombinations",
|
||
"tTime difference",
|
||
"hHoroscope",
|
||
"nNow",
|
||
"wPassword",
|
||
"eEncrypt",
|
||
"udecrypt",
|
||
"sSignificance",
|
||
"2File size",
|
||
|
||
|
||
"XExXit",
|
||
NULL
|
||
F
|
||
|
||
LOCAL_D H_MENU_DATA mdata [I=
|
||
€
|
||
"Conversions",5, /* first five of above commands form the Conversions menu */
|
||
"Calendar",5, /* next five form the Calendar menu */
|
||
"Secret" ,3, /* then three for the Secret menu */
|
||
"Special",3, /* then three for the Special menu */
|
||
NULL
|
||
i;
|
||
|
||
|
||
GLDEF_D TEXT ** _cmds=(&cmds{0});
|
||
GLDEF_D H_MENU_DATA * _mdata=(&mdata[0]);
|
||
|
||
|
||
with the statics _cmds and _mdata defining the contents of the menu bar and of each pulldown menu.
|
||
|
||
|
||
The contents of ManageCommand
|
||
|
||
|
||
Evidently, the real core of the application is to be found in ManageCommand, and in routines called therein.
|
||
|
||
|
||
40
|
||
|
||
|
||
2 WORKED EXAMPLES IN HWIF
|
||
SSS
|
||
|
||
|
||
As far as gu3.c is concerned, the contents of ManageCommand are just as follows:
|
||
|
||
|
||
LOCAL_C VOID ManageCommand(INT keycode)
|
||
€
|
||
INT index;
|
||
TEXT buf [£40];
|
||
|
||
|
||
switch (keycode)
|
||
€
|
||
case 'x!:
|
||
p_exit(0);
|
||
default:
|
||
index=uLocateCommand( keycode) ;
|
||
if Cindex>=0)
|
||
€
|
||
p_atos(&buf (0],"You chose '%s'", cmds [index] +1);
|
||
winfoMsg(&buf [0] );
|
||
>
|
||
|
||
|
||
>
|
||
|
||
|
||
As can be seen, only the Exit command functions properly. All other commands give rise to an
|
||
information message of the form
|
||
|
||
|
||
You chose 'Fahrenheit/Centigrade’.
|
||
|
||
|
||
Note the use of the Hwif library routine uLocateCommand to convert between the accelerator of a menu
|
||
command (which is what is returned by uPresentMenus) and the index of the menu command in the table
|
||
identified by _cmds. This provides a simple means of recovering the text for the chosen menu command.
|
||
Note also the need to test whether the passed keycode corresponds to any of the menu commands (ie the
|
||
test on whether the return value from uLocateCommand is non-negative).
|
||
|
||
|
||
Suggestions for modifying Qu3
|
||
|
||
|
||
= Provide code to display the current day name, in response to the Day of week menu command
|
||
(use eg winfoMsg)
|
||
|
||
|
||
= Display the current time, in response to the Now menu command
|
||
|
||
|
||
= In response to the File size menu command, display the size of qu3.img, determined by a run-
|
||
time call (the full path name of gu3.img will be stored, as a zero terminated string, at the Epoc
|
||
Static DatCommandPtr - as can be verified inside the Debugger)
|
||
|
||
|
||
= Provide code to toggle the permanent status window on receipt of CONTROL+MENU.
|
||
|
||
|
||
Supplying an icon
|
||
|
||
|
||
Qu3 suffers from having an empty hole, in its status window, where an icon should be. (The "empty
|
||
hole" is actually the default icon.) This shortcoming is in fact shared by Qu and Qu2, in that any
|
||
temporary status window displayed while they are in foreground also lacks a proper icon. The problem is
|
||
solved by Qu4. The critical difference is that Qu4 has its own .afl file.
|
||
|
||
|
||
The content of qu4.afl is just the single line
|
||
query.pic
|
||
|
||
|
||
When Qu4 is being linked, the fact that there is an .afl file is picked up by the TopSpeed make system (in
|
||
the part specially customised for the Epoc system), and any files listed in this file are joined together,
|
||
with the ordinary outcome of linking, to produce the final .img file. In this case, a copy of the icon file
|
||
query.pic is built into the final executable qu4.img.
|
||
|
||
|
||
First examples in presenting dialogs
|
||
|
||
|
||
Qu4 advances from Qu3, not only by having a proper icon, but also by having some proper dialogs - one
|
||
each for the commands File size, Day of week, and Now.
|
||
|
||
|
||
41
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
ManageCommand accordingly grows:
|
||
|
||
|
||
LOCAL_C VOID ManageCommand(INT keycode)
|
||
€
|
||
INT index;
|
||
TEXT buf [40];
|
||
|
||
|
||
switch (keycode)
|
||
€
|
||
case 'd!:
|
||
DayOfWeek();
|
||
break;
|
||
case 'n!:
|
||
TimeNow();
|
||
break;
|
||
case 'z':
|
||
FileSize¢);
|
||
break;
|
||
case 'x!:
|
||
p_exit¢0);
|
||
default:
|
||
index=uLocateCommand( keycode) ;
|
||
if Cindex>=0)
|
||
€
|
||
p_atos(&buf [0] ,"You chose ~%s'", cmds [index] +1);
|
||
winfoMsg(&buf [0] );
|
||
d
|
||
|
||
|
||
>
|
||
and the code for FileSize is
|
||
|
||
|
||
LOCAL_C VOID FileSize(VOID)
|
||
€
|
||
TEXT fname [P_FNAMESIZE+2] ;
|
||
H_DI_FSEL fsel;
|
||
P_INFO info;
|
||
TEXT buf [30];
|
||
|
||
|
||
fname [0] =0;
|
||
fsel. fname=(&fname [0] );
|
||
fsel.flags=H_FILE_PICK_SELECTOR;
|
||
FOREVER
|
||
€
|
||
if (udpenDialog("Find file size"))
|
||
return;
|
||
if CuAddDialogI tem(H_DIALOG_FSEL,"File:",&fsel))
|
||
return;
|
||
if CuRunDialog()<=0)
|
||
return;
|
||
fname (1+fname [0] ] =0;
|
||
if (!uErrorValue(p finfo(&fname[1] ,&info)))
|
||
€
|
||
p_atos(&buf (0],"File size is %lu bytes", info.size);
|
||
winfoMsg(&buf [0] );
|
||
>
|
||
|
||
|
||
>
|
||
The call that works out, amongst other things, the size of the specified file, is
|
||
p_finfoC&fname[1] ,&info);
|
||
|
||
|
||
with the size, in bytes, being written to the size member of the passed P_INFo struct. The code that
|
||
displays the file size is
|
||
|
||
|
||
p_atos(&buf[0],"File size is 4lu bytes", info.size);
|
||
winfoMsg(&buf [0] >;
|
||
|
||
|
||
42
|
||
|
||
|
||
2 WORKED EXAMPLES IN HWIF
|
||
SSS
|
||
|
||
|
||
After the user completes the dialog, the file size is displayed, and the dialog is presented again, for the
|
||
user to choose another file. The FOREVER loop in FileSize only terminates
|
||
|
||
|
||
= if the user presses ESCAPE to cancel the dialog - in which case uRunDialog returns zero
|
||
|
||
|
||
= — if there is insufficient memory for any of the calls defining or presenting the dialog - in which
|
||
case the corresponding call to udpenDialog, uAddDialogitem, Of uRunDialog returns a negative
|
||
number.
|
||
|
||
|
||
The filename chosen by the user is written to the buffer fsel. fname as a leading byte counted string
|
||
(BCS). However, the function p_finfo requires a zero terminated string (ZTS). Hence the conversion
|
||
|
||
|
||
fname (1+fname [0] } =0;
|
||
|
||
|
||
before the call to p_finfo. Since a filename as written by a filename selector can have, in general, up to
|
||
P_FNAMESIZE (128) bytes, and since the above code writes an extra byte beyond the end of this, the result
|
||
is that fname has to be declared to be at least P_FNAMESIZE+1 bytes long. In the interests of even byte
|
||
alignment, it has actually been declared as P_FNAMESIZE+2 bytes long.
|
||
|
||
|
||
It is necessary to add the line
|
||
#include <p_file.h>
|
||
|
||
|
||
to the top of qu4.c, since this is where the definitions of the constant P_FNAMESIZE and the struct P_INFO
|
||
are to be found. This header file also contains the function prototype for p_finfo.
|
||
|
||
|
||
The call u€rrorValue made around the result of p_finfo presents a suitable error message, if the size of the
|
||
file cannot be found. There is no need for corresponding calls around the results of udpenDialog,
|
||
uAddDialogItem, and uRunDialog, since these latter functions have error-notification built into them. Error
|
||
notification is standard for all but the most primitive of the Hwif library routines; however, because of
|
||
the generality of the Plib and Wlib functions, such error-notification code is not supplied in their case.
|
||
|
||
|
||
In fact, it would be a very rare case indeed for the above call to p finfo to fail. This is because the
|
||
filename selector item in the dialog automatically validates its contents, before allowing the dialog to
|
||
terminate. Nevertheless, it is theoretically possible for the file to be deleted in between the calls
|
||
uRunDialog and p_finfo (bear in mind the multi-tasking nature of the Series 3; more likely, an SSD might
|
||
be removed, or, for the case of a file selected on REM::, a remote link might become broken). Hence the
|
||
call to uErrorValue.
|
||
|
||
|
||
In the above code, the filename is initialised to have zero length, by the code
|
||
fname [0] =0;
|
||
|
||
|
||
This means that the filename selector will position itself initially to the default path of the application.
|
||
Since nothing has been done to set this up, the file shown in the dialog, when it first appears, will most
|
||
likely be something in the root directory of the default drive - perhaps the file sys$stub. img. If there are
|
||
no files in this directory, the filename selector will say so, and will not allow the user to terminate the
|
||
dialog (apart from cancelling it) until transitioning to a directory in which files do exist.
|
||
|
||
|
||
Suggestions for modifying FileSize
|
||
= Display the time the file was last modified, instead of its size
|
||
= To see the effect of the uErrorValue call, introduce a p_steep before the call to p_finfo and use
|
||
this delay to pull out an SSD on which a filename has been selected.
|
||
|
||
|
||
A date editor in a dialog
|
||
The routine DayOfwWeek contains an example of a date editor in a dialog:
|
||
|
||
|
||
LOCAL_C VOID DayOfWeek(VOID)
|
||
€
|
||
P_DAYSEC ds;
|
||
H_DI_DATE date;
|
||
TEXT buf [40];
|
||
H_DI_TEXT txt;
|
||
|
||
|
||
43
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
SetUpD iDate(&date, &ds): (
|
||
do
|
||
€
|
||
p_nmday(&buf [1] ,p_wkday(ds.day));
|
||
buf [0]=p_slen(&buf [1] );
|
||
txt.str=(&buf [0] );
|
||
txt. type=H_DTEXT_ALIGN_LEFT;
|
||
if CudpenDialog("Find day of week"))
|
||
return;
|
||
if CuAddDialog! tem( H_DIALOG_DATE, "Date", &date))
|
||
return;
|
||
if CuAddDialogItem(H_DIALOG_TEXT,"Day of week", &txt))
|
||
return;
|
||
> while CuRunDialog()>0);
|
||
>
|
||
|
||
|
||
In contrast to FileSize, which displays its result as an information message separate from the dialog,
|
||
(using the call winfoMsg), DayOfWeek displays its result inside the dialog, as a text item included in the
|
||
dialog:
|
||
|
||
buf [0]=p_slen(&buf [1] );
|
||
|
||
txt.str=(&buf [0] );
|
||
|
||
txt. type=H_DTEXT_ALIGN_LEFT;
|
||
|
||
if CuAddDialogItem(H_DIALOG_TEXT,"Day of week", &txt))
|
||
|
||
return;
|
||
|
||
|
||
The name of the day in the week is determined, as a ZTS, by the calls
|
||
p_nmday(&buf [1] ,p_wkday(ds.day));
|
||
|
||
and the string is converted into the BCS form required by the H_D1_TEXT struct by the code
|
||
buf (0]=p_slen(&buf [1] );
|
||
|
||
|
||
The day itself is stored, in the ULONG ds.day, as a day number since the beginning of 1900. This is the
|
||
form required by both the call p_wkday and the struct H_DI_DATE. It is initialised to today by the routine
|
||
SetUpD iDate:
|
||
|
||
|
||
LOCAL_C VOID SetUpDiDate(H_DI_DATE *pdate,P_DAYSEC *pds)
|
||
€
|
||
ULONG sdate;
|
||
|
||
|
||
sdate=p_date();
|
||
p_sttods(&sdate, pds);
|
||
pdate->value=(&pds->day);
|
||
pdate->low=0;
|
||
pdate->high=H_LAST_DAY;
|
||
>
|
||
|
||
|
||
It is necessary to add the line
|
||
#include <p_date.h>
|
||
|
||
|
||
to the top of qu4.c, since this is where the definitions of the struct p_DAYsEc and the function p_sttods are
|
||
to be found.
|
||
|
||
|
||
Choice lists and the time-text functions
|
||
|
||
|
||
The routine TimeNow contains examples of choice lists in a dialog - five choice lists in all, in fact all just
|
||
with the two choices "No" and "Yes" and added into the current dialog by the utility function
|
||
AddNoYesChoiceList:
|
||
|
||
|
||
LOCAL_C INT AddNoYesChoiceList(TEXT *pmt,UWORD *pval)
|
||
€
|
||
return(uAddChoiceList(pmt,pval, "No", "Yes", NULL)):
|
||
>
|
||
|
||
|
||
2 WORKED EXAMPLES IN HWIF
|
||
oo SSeS
|
||
|
||
|
||
LOCAL_C VOID TimeNow(VOID)
|
||
€
|
||
INT values;
|
||
H_DI_TEXT txt;
|
||
TEXT buf £48];
|
||
|
||
|
||
txt.str=(&buf [0] );
|
||
do
|
||
€
|
||
if CuOpenDialog(NULL))
|
||
return;
|
||
uZTStoBCS(&buf [0] ,"Time is now");
|
||
txt. type=H_DTEXT_ALIGN_CENTRE;
|
||
if (uAddD ialogI tem(H_DIALOG_TEXT,NULL,&txt))
|
||
return;
|
||
values=0;
|
||
if (ttMonth==2)
|
||
values=H_TIME_FORMAT_MONTH_NAME;
|
||
if (ttDay==2)
|
||
values |=H_TIME_FORMAT_DAY_NAME;
|
||
if (ttSuffix==2)
|
||
values |=H_TIME_FORMAT_SUFFIX;
|
||
if (ttCentury==1)
|
||
values |=H_TIME_FORMAT_NO_CENTURY;
|
||
if (ttSeconds==1)
|
||
values |=H_TIME_FORMAT_NO_SECONDS;
|
||
hTTSetFormat(ttH, values);
|
||
hTTSetTime(ttH,H_TIME_SET_NOW,NULL);
|
||
buf [0] =hTTSenseString(ttH,H_TIME_SENSE_BOTH, &buf [1]);
|
||
txt. type=H_DTEXT_ALIGN_CENTRE|H_DTEXT_UNDERLINE;
|
||
if (uAddD falogI tem(H_DIALOG_TEXT,NULL,&txt))
|
||
return;
|
||
if CAddNoYesChoiceList("Give month name",&ttMonth))
|
||
return;
|
||
if (AddNoYesChoiceList("Give day name",&ttDay))
|
||
return;
|
||
if (AddNoYesChoiceList("Use date suffix", &ttSuffix))
|
||
return;
|
||
if (AddNoYesChoiceList("Show century", &ttCentury))
|
||
return;
|
||
if CAddNoYesChoiceList("Show seconds", &ttSeconds) )
|
||
return;
|
||
> while CuRunDialog()>0);
|
||
>
|
||
|
||
|
||
The live variables for the five choice lists are five statics defined at the top of gu4.c, and all given initial
|
||
values reflecting the defaults built into the Hwif time-text utility functions:
|
||
|
||
|
||
LOCAL_D VOID *ttH;
|
||
|
||
LOCAL_D UWORD ttMonth=1;
|
||
LOCAL_D UWORD ttSuffix=1;
|
||
LOCAL_D UWORD ttDay=1;
|
||
LOCAL_D UWORD ttCentury=2;
|
||
LOCAL_D UWORD ttSeconds=2;
|
||
|
||
|
||
The textual form of the time is generated by the time-text channel tt opened by the following call at the
|
||
end of Specifictnit:
|
||
|
||
|
||
ttH=hTTOpen();
|
||
The text is actually generated by the calls
|
||
|
||
|
||
hTTSetFormat(ttH, values):
|
||
hTTSetT ime( ttH, H_TIME_SET_NOW,NULL);
|
||
buf [0] =hTTSenseString(ttH,H_TIME_SENSE_BOTH, &buf{1]);
|
||
|
||
|
||
where vatues has been built up as a combination of the present values of the ttxxx variables.
|
||
|
||
|
||
Whereas the results of FileSize and DayOfweek only persist until the user cancels the dialog, the result of
|
||
TimeNow persists throughout the lifetime of the application. This is because the ttxxx variables are statics.
|
||
|
||
|
||
45
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
— SSS
|
||
|
||
|
||
A note on the start-up heap
|
||
|
||
|
||
There is no special need to test for the result of the call httopen made in Specificinit. No Window
|
||
Server resources are required for a time-text channel; the only allocating that needs to be performed for it
|
||
is out of the application's own heap. Since the call is made during application initialisation, it can be
|
||
assumed that, if the application has been allowed by the OS to run at all, there will be sufficient memory
|
||
for the call to succeed.
|
||
|
||
|
||
This point is worthy of some further explanation. Using either the Debugger or the Spy application, it
|
||
can be seen that, when running, Qu4 has only around 0x300 bytes allocated from its heap. However, the
|
||
default value for the minimum heap of an application is 0x80 paragraphs, ie 0x800 bytes.
|
||
|
||
|
||
Further investigation will reveal that the minimum segment size for Qu4 is some 0x19c0 bytes, made up
|
||
as follows:
|
||
|
||
|
||
0x1000 stack
|
||
0x800 minimum heap
|
||
Oxic0 Static data
|
||
|
||
|
||
These figures may be confirmed by running the tool edump on qu4.img:
|
||
edump qu4
|
||
|
||
|
||
When the OS is instructed to try to run Qu4, it first has to allocate the data segment of 0x19c0 bytes. If it
|
||
fails to do so, the application is not allowed to run, and an out-of-memory notifier is presented. But if it
|
||
succeeds, the 0x19c0 bytes are guaranteed to remain available throughout the lifetime of the application.
|
||
Hence the guarantee that the call to hTTopen will never fail.
|
||
|
||
|
||
Clearly, Qu4 is an extremely anti-social application, hogging much more heap (not to mention much
|
||
more stack) than it needs. Such behaviour would be unacceptable in any commercial application. One
|
||
penalty the application incurs, upon itself, is that the OS will sometimes refuse to run it, even though
|
||
there is sufficient memory available for its actual requirements - the point being that there is insufficient
|
||
memory available for its stated requirements.
|
||
|
||
|
||
Incidentally, the start-up heap for an application can be customised by means of including a line such as
|
||
set heapsize=0x40
|
||
|
||
in the .pr project file governing how the application is built. The stack can be specified by means of a
|
||
|
||
different value of epocinit.
|
||
|
||
Further comments on edump
|
||
|
||
|
||
Another piece of information that edump gives is the size of any additional files built into the specified
|
||
image. Thus the result of running edump on qu4.img includes the line
|
||
|
||
|
||
Add 1 offset,len = 0040 (bytes), 0074 (bytes)
|
||
whereas no such line is given for qu3.img. This additional file, of size 0x74 bytes, is of course the copy
|
||
of the icon query.pic.
|
||
Suggestions for modifying Qu4
|
||
|
||
= Make the results of FileSize and DayOfweek persistent in the same way as the result of TimeNow is
|
||
|
||
|
||
= For some dates (eg Wednesday 26th September), the textual representation generated in TimeNow
|
||
can end up too wide to fit properly within the widest dialog that is allowed; look out for such
|
||
cases and abbreviate the text suitably (use abbreviated versions of the day and/or month names)
|
||
|
||
|
||
= Produce a customised project file gu4.pr including a line defining the start-up heap more
|
||
appropriately; confirm the result using edump.
|
||
From .img to .app
|
||
|
||
|
||
Although Qu4 has an icon built into it, it is not yet able to be installed in its own right as an application
|
||
in the System Screen. For this to be possible, an application also needs to have a shd (shell data) file
|
||
built into it.
|
||
|
||
|
||
For Query, the source of the shd file is query.ms, which consists solely of the line
|
||
|
||
|
||
Query
|
||
|
||
|
||
46
|
||
|
||
|
||
2 WORKED EXAMPLES IN HWIF
|
||
SSeS
|
||
|
||
|
||
This is actually an abbreviated form of a three-line file:
|
||
|
||
|
||
Query
|
||
|
||
|
||
0
|
||
|
||
|
||
in which the third line gives the type of the application. A type of zero means that the application is non
|
||
file-based, and consequently has no associated files.
|
||
|
||
|
||
The file query.shd can be produced from query.ms by the command
|
||
makeshd query
|
||
and then the file query. shd is joined into the final executable by being listed in query.afl.
|
||
|
||
|
||
Up to three files can be specified in an .afl file. Whereas the icon of an application can be placed into any
|
||
of the three slots, the shell data has to be placed into the third slot. Thus the contents of query.afl become
|
||
|
||
|
||
query.pic
|
||
query.rsc
|
||
query.shd
|
||
|
||
|
||
where query.rsc is any small file (preferably a zero-length file).
|
||
Running edump on query.img produces the following three lines of output (among others)
|
||
|
||
|
||
Add 1 offset, len
|
||
Add 2 offset, len
|
||
Add 3 offset, len
|
||
|
||
|
||
0040 (bytes), 0074 (bytes)
|
||
QOCO (bytes), 0000 (bytes)
|
||
00CO (bytes), 0024 (bytes)
|
||
|
||
|
||
Whereas an application without shell data is usually copied to an \img\ directory on the Series 3, one
|
||
with shell data is usually copied to an lapp\ directory, and renamed from .img to .app at the same time.
|
||
Thereafter, the application can be installed, using the Install application command in the System Screen.
|
||
|
||
|
||
Once installed, it can be run in the same way as any of the built-in applications is. Further, an application
|
||
button such as CONTROL+CALC can be assigned to it, if desired.
|
||
The floating point emulator sys$8087.Idd
|
||
|
||
|
||
Before Query can be run successfully, the Series 3 needs to be able to locate the floating point maths
|
||
emulator, sys$8087.ldd. This is because query.c contains lines such as
|
||
|
||
|
||
DOUBLE fahr;
|
||
|
||
|
||
fahr=32;
|
||
which, innocent as it may seem, requires the presence of sys$8087.ldd.
|
||
|
||
|
||
The simplest way to ensure the Series 3 can locate this emulator is to place a copy of it in the same
|
||
directory as the application itself. Thus if query.img is copied to m:\app\query.app on the Series 3, a
|
||
copy of sys$8087.ldd could be copied into this same directory, m:\app\. A copy may be found in
|
||
\sibosdk\lib\ on the PC.
|
||
|
||
|
||
In fact, of the example applications, Query is the only one which requires the presence of the emulator.
|
||
|
||
|
||
The built-in applications avoid requiring to use the emulator, since they replace the likes of the above
|
||
lines of code by the following
|
||
|
||
|
||
DOUBLE fahr;
|
||
|
||
WORD temp;
|
||
|
||
temp=32;
|
||
p_itof(&fahr,&temp);
|
||
|
||
|
||
which although it looks more cumbersome, actually produces leaner code overall.
|
||
|
||
|
||
Debugging a .app application
|
||
|
||
|
||
The mechanism for debugging a .app application is virtually the same as debugging a .img application.
|
||
In neither case is there any need to copy the application onto the Series 3 by hand.
|
||
|
||
|
||
The only complication concerns the need to pass a suitable command line to file-based applications. This
|
||
is considered later. However, non file-based applications, such as Query, can be run without any
|
||
command line being passed to them.
|
||
|
||
|
||
47
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
Some responsibilities of being a .app
|
||
|
||
|
||
In general, an application intended to be capable of being installed in the System Screen should always
|
||
make a call to hCrackCommandL ine in its SpecificInit routine (or equivalent). This is true whether or not
|
||
the application is file-based. If no call to hCrackConmandLine is made, the Epoc static DatstatusNamePtr
|
||
will be left at its default value of zero, and it will, accordingly, be fruitless for a user to assign an
|
||
application button (such as CONTROL+CALC) to this application.
|
||
|
||
|
||
However, any application that calls hcrackCommandL ine must explicitly test for system messages of (at
|
||
least) the Shutdown variety (assuming the application has not added in 4000 to its shell data type, to
|
||
prevent such messages ever being sent). This means that the top of MainLoop in query.c has to have the
|
||
form
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
¢
|
||
WMSG_KEY key;
|
||
|
||
|
||
FOREVER
|
||
€
|
||
uGetKey(&key);
|
||
if (key. keycode&W_EVENT_KEY)
|
||
€
|
||
if (key. keycode==CONS_EVENT_COMMAND)
|
||
p_exit(0);
|
||
>
|
||
else ...
|
||
|
||
|
||
Menu command look up - by accelerator or by index?
|
||
|
||
|
||
Query differs from Qu4 in the way the switch statement in ManageCommand is constructed: in place of
|
||
|
||
|
||
LOCAL_C VOID ManageCommand(INT keycode)
|
||
|
||
|
||
€
|
||
|
||
switch (keycode)
|
||
€
|
||
|
||
case 'd':
|
||
DayOfWeek();
|
||
break;
|
||
|
||
case 'n':
|
||
TimeNow();
|
||
break;
|
||
|
||
case 'z':
|
||
FileSize();
|
||
break;
|
||
|
||
case 'x!s:
|
||
p_exit¢0);
|
||
3
|
||
|
||
>
|
||
|
||
|
||
there is, effectively,
|
||
|
||
|
||
LOCAL_C VOID ManageCommand(INT index)
|
||
|
||
{
|
||
|
||
switch (index)
|
||
€
|
||
|
||
case 5:
|
||
DayOfWeek();
|
||
break;
|
||
|
||
case 9:
|
||
TimeNow();
|
||
break;
|
||
|
||
case 14:
|
||
FileSize();
|
||
break;
|
||
|
||
case 15:
|
||
p_exit¢0);
|
||
>
|
||
|
||
|
||
48
|
||
|
||
|
||
2 WORKED EXAMPLES IN HWIF
|
||
|
||
|
||
ar
|
||
|
||
|
||
and instead of ManageConmand being called in the simple context
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
€
|
||
INT ret;
|
||
WMSG_KEY key;
|
||
|
||
|
||
FOREVER
|
||
€
|
||
uGetKey(&key);
|
||
if (key. keycode&W_SPECIAL_KEY)
|
||
ManageCommand( key. keycode&(~W_SPECIAL_KEY));
|
||
else if (key. keycode==W_KEY_MENU && !(key.modifiers&W_CTRL_MODIFIER))
|
||
€
|
||
ret=uPresentMenus():
|
||
if Cret>0)
|
||
ManageCommand(ret);
|
||
}
|
||
|
||
|
||
>
|
||
there is now one extra layer to navigate between MainLoop and ManageCommand:
|
||
|
||
|
||
LOCAL_C VOID TryExecuteCommand(INT keycode)
|
||
cf
|
||
keycode=uLocateCommand( keycode);
|
||
if (keycode>=0)
|
||
ManageCommand( keycode);
|
||
>
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
€
|
||
INT ret;
|
||
WMSG_KEY key;
|
||
|
||
|
||
FOREVER
|
||
€
|
||
uGetKey(&key);
|
||
if (key. keycode&W_SPECIAL_KEY)
|
||
TryExecuteCommand( key. keycode&(“W_SPECIAL_KEY));
|
||
else if (key. keycode==W_KEY_MENU && !(key.modifiers&W_CTRL_MODIFIER))
|
||
€
|
||
ret=uPresentMenus();
|
||
if (ret>0)
|
||
TryExecuteCommand( ret);
|
||
>
|
||
|
||
|
||
>
|
||
|
||
|
||
The two mechanisms are obviously equivalent in general terms. However, the latter approach has been
|
||
adopted throughout all the example applications. The following points can be cited in its favour:
|
||
|
||
|
||
= quite often, several commands can be grouped together and executed more efficiently, passing as
|
||
a parameter to a common routine the command index (possibly less some base value)
|
||
|
||
|
||
= — the switch statement on index is completely dense, and hence compiles much more leanly than a
|
||
switch statement on accelerator
|
||
|
||
|
||
= the accelerator of a menu command is a less central aspect of it than its position in the menu bar;
|
||
it is better to switch on a variable of greater importance than on one which is virtually an
|
||
accident
|
||
|
||
|
||
= this method is language-independent: the accelerators can be changed for a foreign-language
|
||
version, without having to re-compile the ManageCommand routine.
|
||
|
||
|
||
In practice, the numerical values of the command indices do not appear explicitly in code; rather, they
|
||
are hidden through a sequence of #defines. See query.c for the details.
|
||
|
||
|
||
49
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
Example of floating point editor
|
||
|
||
|
||
The routine Temperatures called from ManageCommand to implement the conversion between Fahrenheit and
|
||
Centigrade demonstrates floating point editors in dialogs:
|
||
|
||
|
||
LOCAL_C VOID Temperatures(VOID)
|
||
€
|
||
DOUBLE fahr;
|
||
DOUBLE cent;
|
||
H_DI_FLOAT ffahr;
|
||
H_DI_FLOAT fcent;
|
||
INT index;
|
||
|
||
|
||
fahr=32;
|
||
cent=0;
|
||
ffahr.value=(&fahr);
|
||
ffahr. low=(-17968) ;
|
||
ffahr .high=18032;
|
||
fcent.value=(¢);
|
||
fcent. lLow=(- 10000);
|
||
fcent .high=10000;
|
||
FOREVER
|
||
€
|
||
if CuOpenDialog("Convert temperature"))
|
||
return;
|
||
if CuAddDialog] tem(H_DIALOG_FLOAT,"Fahrenheit",&ffahr))
|
||
return;
|
||
if CuAddDialogItemCH_DIALOG_FLOAT,"Centigrade",&fcent))
|
||
return;
|
||
index=uRunDialog();
|
||
if Cindex<=0)
|
||
break;
|
||
if Cindex==2)
|
||
€
|
||
cent=( fahr-32)*5/9;
|
||
Clip(¢);
|
||
}
|
||
else
|
||
€
|
||
fahr=32+cent*9/5;
|
||
Clipc&fahr);
|
||
>
|
||
|
||
|
||
>
|
||
|
||
|
||
As the variable names suggest, the current value in Fahrenheit is stored in fahr, and the current value in
|
||
Centigrade is stored in cent. There are two floating point editors, with fahr and cent being the live
|
||
variables. Appropriate maxima and minima are set up in each case.
|
||
|
||
|
||
The variables fahr and cent are initialised to 32 and 0 respectively. Each time the user presses ENTER, one
|
||
or other of these variables is sensed, and the other is recalculated. Which is which depends on where the
|
||
user has left the highlight in the dialog. Thus if the user has cursored the highlight down to the
|
||
Centigrade line and typed in a new value there, before pressing ENTER, the call uRunDialog returns 3 (the
|
||
counting starts at 1 for the title line in the dialog) and hence fahr is calculated anew, from the latest value
|
||
of cent.
|
||
|
||
|
||
Example of numeric editor
|
||
|
||
|
||
The routine clip alters the calculated value of eg fahr or cent so that it only features a specified number
|
||
of decimal points. (Currently, there is no Hwif mechanism for having floating point editors perform such
|
||
a clipping themselves.) The number of decimal points is governed by the static variable ndp, which is
|
||
initially 2. The Significance menu command allows the user to alter this:
|
||
|
||
|
||
50
|
||
|
||
|
||
2 WORKED EXAMPLES IN HWIF
|
||
|
||
|
||
OO eS
|
||
|
||
|
||
LOCAL_C VOID ChangeNdp(VOID)
|
||
€
|
||
LONG indp;
|
||
H_DI_NUMBER num;
|
||
|
||
|
||
if CuOpenDialog("Level of significance"))
|
||
return;
|
||
|
||
indp=ndp;
|
||
|
||
num. value=(&lndp);
|
||
|
||
num. low=0;
|
||
|
||
num. high=4;
|
||
|
||
if (uAddDialog! tem(H_DIALOG_NUMBER,"Decimal places", &num))
|
||
return;
|
||
|
||
if CuRunDialog()<=0)
|
||
return;
|
||
|
||
ndp=(WORD) Lndp;
|
||
|
||
CalcSmall¢);
|
||
|
||
>
|
||
|
||
|
||
Note the requirement to have a Lone variable for the live variable of the numeric editor. This explains
|
||
why a copy of ndp has to be made in the automatic variable tndp.
|
||
|
||
|
||
The routine calcSmal| recalculates some constants that are used in calls to ct ip.
|
||
|
||
|
||
Examples of other dialog items
|
||
|
||
See the following routines in query.c for examples of other types of items in dialogs:
|
||
time editors TimeDifference
|
||
action buttons Horoscope, Combinations
|
||
secret input boxes _EnterPassword
|
||
|
||
|
||
text editors EncryptMessage (non-scrolling), DecryptMessage (scrolling).
|
||
|
||
|
||
Suggestions for modifying Query
|
||
s Add at least one more conversion routine.
|
||
= Call hDtgPosition to position at least one dialog other than in the screen centre.
|
||
|
||
|
||
= Eliminate the need for the floating point emulator, by using routines such as p_fadd instead of
|
||
direct manipulation of floating point numbers. Compare the size of the executable produced with
|
||
that of the original query.app.
|
||
|
||
|
||
= Try to improve on the rather crude scheme in MakeReadable and MakeUnreadable, called
|
||
respectively by EncryptMessage and DecryptMessage, to convert between a short, totally
|
||
unreadable string of characters in the complete range of values 0 to 255 (as returned by
|
||
p_encrypt), and a longer string with values in the range 32 to 111.
|
||
|
||
|
||
SS EEE ee SS ae ee Eee
|
||
|
||
|
||
Getting serious: the Tables application
|
||
|
||
|
||
Whereas Query contains a collection of dialogs with little unifying principle, Tables contains a collection
|
||
of dialogs all working around a common aim. This aim is to produce a revision aid for someone trying to
|
||
learn some multiplication tables.
|
||
|
||
|
||
What the dialogs allow to be altered is the following aspects of the state of the application:
|
||
= how much time the user has in which to answer any multiplication question posed
|
||
= whether the tables end at 12 (as in 3 times 12, 7 times 12, and so on), or at 10, or wherever
|
||
|
||
|
||
= whether the questions posed all come from the same multiplication table, or from a variety, and
|
||
in the latter case, the range of tables covered
|
||
|
||
|
||
= the running total score of correct answers can be reset to zero.
|
||
As well as containing the code to present these dialogs, Tables contains code to:
|
||
|
||
|
||
i es eS
|
||
51
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
= record the state of the application in an environment variable on exit
|
||
|
||
® — initialise the application appropriately, on start up, from this environment variable
|
||
= calculate and pose random multiplication questions
|
||
|
||
= present an edit box to receive the user's response
|
||
|
||
= — simultaneously, count down a timer and progressively fill in a bar gauge display
|
||
|
||
= present feedback to the user on whether the answer proffered is correct.
|
||
|
||
|
||
Tal contains the dialogs and the environment variable code, but is otherwise devoid of any significant
|
||
screen display. Ta2 adds the display of the score so far and the range of values being tested; an animated
|
||
action button resides in the middle of the remainder of the screen. Ta3 actually poses random
|
||
multiplication problems, and provides an edit box to receive the user's response. Tables itself adds in the
|
||
timer, and presents the animated bar gauge display of the time elapsed.
|
||
|
||
|
||
The state of the application
|
||
|
||
|
||
This is recorded in a static instance, state, of the following struct:
|
||
|
||
|
||
typedef struct
|
||
{
|
||
UWORD TableEnd; /* where tables end */
|
||
UWORD MaxTable; /* maximum table to test */
|
||
|
||
|
||
UWORD Tested; /* number of questions since last reset */
|
||
|
||
UWORD Correct; /* number of correct answers since last reset */
|
||
UWORD Timing; /* number of seconds allowed for an answer */
|
||
UWORD Mode; /* which table is currently being tested */
|
||
|
||
3} TSTATE;
|
||
|
||
|
||
with values being initialised, the very first time, by the statement
|
||
LOCAL_D TSTATE state=(12,12,0,0,5,13;
|
||
|
||
|
||
The value 1 for the Mode field has the special meaning that all tables are to be tested (from 2 up to
|
||
MaxTable).
|
||
|
||
|
||
The Tested and Correct fields are reset to zero, provided the user responds affirmatively to a query
|
||
dialog, in the routine ResetScore.
|
||
|
||
|
||
The TableEnd and MaxTable fields are presented for editing, using numeric editors, in the routine
|
||
ChangeLimits.
|
||
|
||
|
||
Another numeric editor, in the routine changeTiming, allows the user to alter Timing.
|
||
|
||
|
||
The routine ChangeMode allows the Mode field to be changed. This uses a choice list whose contents are
|
||
dynamically defined - they vary from "2 times table” up to "n times table", where 7 is the current value
|
||
of MaxTable, but also always include "All tables":
|
||
|
||
|
||
LOCAL_C VOID ChangeMode(VOID)
|
||
€
|
||
H_DI_CHOICE ch;
|
||
INT jz
|
||
TEXT buf (201;
|
||
|
||
|
||
if (uQpenDialog("Mode"'))
|
||
return;
|
||
|
||
if (uBeginDCL(&ch))
|
||
return;
|
||
|
||
if CuGrowDCL(&ch, "ALL tables"))
|
||
return;
|
||
|
||
|
||
for (j=2; j<=state.MaxTable; j++)
|
||
€
|
||
p_atos(&buf (0) ,"%d times table", j);
|
||
if CuGrowDCL(&ch, &buf [0] ))
|
||
return;
|
||
>
|
||
|
||
|
||
52
|
||
|
||
|
||
2 WORKED EXAMPLES IN HWIF
|
||
_—_—_— eee
|
||
|
||
|
||
if (uAddDCL("Test which tables", &state.Mode,&ch))
|
||
return;
|
||
|
||
uRunDialog();
|
||
|
||
3
|
||
|
||
|
||
Using an environment variable
|
||
|
||
|
||
Instead of simply calling p_exit on receipt of the Exit menu command (in the manner of Query), the
|
||
following code is executed:
|
||
|
||
|
||
LOCAL_C VOID ExitApplication(VoID)
|
||
€
|
||
uErrorValue(p_setenviron(EnvName, ENV_NAME_LEN,&state,sizeof(TSTATE)));
|
||
p_exit(0);
|
||
>
|
||
|
||
|
||
The code in MainLoop that responds to Shutdown messages from the System Screen also has to change to
|
||
call ExitApplication:
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
€
|
||
WMSG_KEY key;
|
||
|
||
|
||
FOREVER
|
||
|
||
€
|
||
|
||
uGetKey(&key);
|
||
|
||
if (key. keycode&W_EVENT_KEY)
|
||
€
|
||
if (key. keycode==CONS_EVENT_COMMAND)
|
||
|
||
ExitApplication();
|
||
|
||
>
|
||
|
||
|
||
There are actually two sorts of environment variables on the Series 3:
|
||
= those whose names and values are each ZTSs
|
||
= those whose name or values are other than a ZTS.
|
||
|
||
|
||
Correspondingly, there are two sets of routines for reading, writing, searching, or deleting environment
|
||
variables. (In fact, the ZTS-related routines just layer above the more general ones.)
|
||
|
||
|
||
In this case, what is being stored in the environment variable is the content of the state struct - which is
|
||
bound to contain embedded zeros, and so the more general routine p_setenviron has to be used, as
|
||
opposed to the notionally simpler p_setenv. Accordingly, both the name and the value of the environment
|
||
variable have to be passed in the form buf, Len.
|
||
|
||
|
||
Since the name of the environment variable is obviously the same whether the variable is being set (on
|
||
application exit) or being read (on application start-up), this has been hidden away using the static
|
||
variable EnvName (statically initialised) and the #define ENV_NAME_LEN.
|
||
|
||
|
||
Memory consumption by environment variables
|
||
|
||
|
||
The only error that needs to be considered, on writing the environment variable, is lack of memory -
|
||
either because the limit of 4K allocated for environment variables has already been reached, or because
|
||
system memory is generally exhausted. The call ufrrorValue around p_setenviron above informs the user
|
||
should this transpire.
|
||
|
||
|
||
As a general principle, applications should only make sparing use of environment variables (otherwise
|
||
they may even detract from the performance of some of the built-in applications). In order to preserve
|
||
larger amounts of data between different invocations of an application, the data should be written to file -
|
||
either with or without the explicit knowledge of the user.
|
||
|
||
|
||
Note that the name of an environment variable should not, unless authorised by Psion, contain a '$'
|
||
character. See the Environment variables on the Series 3 section of the Series 3 Programming Overview
|
||
chapter of the Series 3/3a Programming Guide for further information on this important naming
|
||
convention for environment variables.
|
||
|
||
|
||
53
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
Complications on reading environment variables
|
||
|
||
|
||
Programs using environment variables should always bear in mind that it is theoretically possible for
|
||
another application to trash the variable - as a result of using another environment variable of the same
|
||
name. In particular, the length of the variable may turn out to be other than what is expected. For this
|
||
reason, the buffer to receive the environment variable should always be declared as having (at least)
|
||
P_ENVMAX (256) bytes. (In order to access the definition of p_ENVMAX, a program must #include the file
|
||
p_sys.h.) Hence
|
||
|
||
|
||
LOCAL_C VOID ReadState(VOID)
|
||
€
|
||
INT len;
|
||
UBYTE buf [P_ENVMAX] ;
|
||
|
||
|
||
len=p_getenviron(EnvName, ENV_NAME_LEN, &buf [0] );
|
||
if (ten<0 |{ lent=sizeof(TSTATE))
|
||
return; /* make do with the statically initialised values */
|
||
p_bcpy(&state, &buf [0] ,sizeof(TSTATE));
|
||
>
|
||
|
||
|
||
The case when ten is returned negative corresponds to the environment variable not existing - as will be
|
||
the case the first time the application is run.
|
||
|
||
|
||
Suggestions for enhancing Ta1
|
||
|
||
|
||
= When MaxTable is large, the amount of memory required by the dynamic choice list in the dialog
|
||
in ChangeMode can become considerable. Using either the Debugger or Spy, verify that this is the
|
||
case, and try to re-design the dialog to require less RAM.
|
||
|
||
|
||
= If the user presses PSION+ESCAPE, Tal is terminated without having any chance to save its state
|
||
to an environment variable. Prevent this from happening.
|
||
|
||
|
||
= Strictly speaking, the code in Readstate above can be caught out by a rogue program which
|
||
writes its own environment variable, with the same name and with the same length of data, but
|
||
with inappropriate values for the individual fields. Write such a rogue program to demonstrate
|
||
this fact, and consider amending Readstate to take better precautions.
|
||
|
||
|
||
Laying out information on the screen
|
||
|
||
|
||
Ta2 goes beyond Ta! in that it lays out its current state on the screen, for the user to see.
|
||
|
||
|
||
For example
|
||
|
||
|
||
Score! 4 correct out of 9 eee
|
||
Testing 7 times table 2x48
|
||
|
||
|
||
(up to 7 times 12) Tables
|
||
|
||
|
||
Press to test Zid
|
||
mM
|
||
Tha 23
|
||
|
||
|
||
There are no hard and fast rules for designing such a layout, but there certainly are easier and harder
|
||
ways of going about achieving a given layout (once one has been decided upon). The following
|
||
discussion may be read as an example of how to achieve a layout such as that shown in the above screen
|
||
dump.
|
||
|
||
|
||
The three lines of text at the top of the screen share the following features:
|
||
# they are centred in the main window (apart from the status window)
|
||
= they need to be smoothly updated when there is a change in any of the values shown.
|
||
|
||
|
||
Both these reasons argue in favour of using gPrintBoxText to draw the lines. Not only can this function
|
||
automatically centre text, it also takes care of the smooth screen update.
|
||
|
||
|
||
To explain the latter point more fully, consider what has to happen to the display of the second line down
|
||
when the user changes from testing the 12 times table to testing the 7 times table. Not only does new text
|
||
have to be drawn, some areas just outside the limits of the new text have to be cleared - since the new
|
||
text is slightly narrower than the old.
|
||
|
||
|
||
54
|
||
|
||
|
||
2 WORKED EXAMPLES IN HWIF
|
||
eS
|
||
|
||
|
||
Naively, the way to accomplish the above would be as follows:
|
||
= first, clear the area of screen where the old message was drawn
|
||
|
||
|
||
= second, draw the new text.
|
||
|
||
|
||
However, this can give rise to a noticeable and annoying screen flicker. This can be especially annoying
|
||
if, as often happens, the text is updated when there is actually no change in it.
|
||
|
||
|
||
The routine gPrintBoxText avoids these problems by simultaneously clearing pixels and drawing to them,
|
||
sweeping along in a horizontal pass. Pixels are written to if new text is to appear there, and are otherwise
|
||
cleared.
|
||
|
||
|
||
The three top lines are written by a common routine:
|
||
|
||
|
||
LOCAL_C VOID DrawLine(INT j,TEXT *pb)
|
||
{
|
||
P_RECT box;
|
||
|
||
|
||
box.tl.x=4-
|
||
|
||
box. br .x=189-4;
|
||
|
||
box. tl .y=4+9*j:
|
||
|
||
box.br.y=box.tl .y+9;
|
||
gPrintBoxText(&box,8,G_TEXT_ALIGN_CENTRE,C,pb,p slen(pb));
|
||
d
|
||
|
||
|
||
which is called as follows
|
||
|
||
|
||
LOCAL_C VOID DisplayScores(VOID)
|
||
r¢
|
||
TEXT buf [40];
|
||
|
||
|
||
p_atos(&buf(0],"Score: %u correct out of du" ,state.Correct, state. Tested);
|
||
DrawLine(0,&buf [0] );
|
||
>
|
||
|
||
|
||
and
|
||
|
||
|
||
LOCAL_C VOID DisplayMode(VOID)
|
||
€
|
||
TEXT *pb;
|
||
TEXT buf [40];
|
||
|
||
|
||
if (state.Mode==1)
|
||
pb="Testing all tables";
|
||
else
|
||
ca
|
||
p_atos(&buf [0] ,"Testing %d times table",state.Mode);
|
||
pb=(&buf [0] );
|
||
>
|
||
DrawLine(1,pb);
|
||
>
|
||
|
||
|
||
and
|
||
|
||
|
||
LOCAL_C VOID DisplayLimits(VvoID)
|
||
{
|
||
TEXT buf [40];
|
||
|
||
|
||
p_atos(&buf[0],"Cup to %d times %d)",
|
||
|
||
(state.Mode==1? state.MaxTable: state.Mode),state.TableEnd);
|
||
DrawLine(2,&buf [0] );
|
||
>
|
||
|
||
|
||
In all cases, the box drawn to has height nine pixels. This allows one pixel of leading between lines, in
|
||
addition to the font height of eight pixels. Since at least one pixel has to be reserved for descenders (such
|
||
as the bottom pixel in the p of up), the maximum allowed value for the ascent parameter to gPrintBoxText
|
||
is 8 - as in the above routine. This means in fact that the extra pixel of leading goes above the
|
||
corresponding line of text (not that it matters in this case).
|
||
|
||
|
||
55
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
Se
|
||
|
||
|
||
Collectively, the text respects a border of four pixels all around. The value of 189 is the full screen width
|
||
(240 pixels) of the Series 3 and Workabout, or of the Series 3a in Series 3 emulation mode, less the width
|
||
of the status window (51 pixels).
|
||
|
||
|
||
Since there is no need for a margin parameter in this case, it is left at zero.
|
||
|
||
|
||
To take advantage of the increased screen width of the Series 3a in "native" mode (480 pixels), the sizing
|
||
and positioning of the text would need to be changed and the above calculations reworked.
|
||
|
||
|
||
Laying out an action button and its associated text
|
||
The text Press Enter to test is rather harder to position, because of the embedded action button.
|
||
|
||
|
||
Start by considering the horizontal direction. 38 pixels is a good width for the action button (this is the
|
||
width of the action buttons in dialogs). There are five characters in Press, say six to include one trailing
|
||
space. This translates to around 36 pixels, allowing 6 characters per pixel. Likewise, there are seven
|
||
characters in to test, which ends up as around 48 pixels. Thus the width of the entire display is
|
||
36+38+48, ie 122 pixels. Centring this within 189 pixels gives an x-offset of around 34 for Press.
|
||
|
||
|
||
Vertically, there are some 80-(4 +3*9)-4 pixels to play with, ie 45 pixels. With 8 pixels for the height of
|
||
the text, this leaves 18 pixels clear above the top of the text, translating into a vertical offset of
|
||
4+3*9+18+7 pixels to the baseline of the text, ie 56 pixels.
|
||
|
||
|
||
This means that the code to display the middle line can be written as
|
||
|
||
|
||
LOCAL_C VOID DisplayPressButton(VOID)
|
||
¢
|
||
gPrintText(34,56,"Press",5);
|
||
DrawButton( FALSE);
|
||
gPrintText(34+36+38+6,56,"to test",7);
|
||
>
|
||
|
||
|
||
where Draw8utton (discussed below) draws the button itself, in either its normal or its depressed state
|
||
(depending on the parameter passed to it).
|
||
|
||
|
||
The above discussion again assumes a maximum screen width of 240 pixels which is valid for the Series 3
|
||
and Workabout, or the Series 3a in Series 3 emulation mode. The Series 3a in native mode has a
|
||
maximum screen width of 480 pixels. Therefore, to take advantage of the larger screen size of the
|
||
|
||
Series 3a, the above calculations would need to be reworked.
|
||
|
||
|
||
Positioning an action button vertically
|
||
|
||
|
||
As for the vertical positioning of the button, bear in mind that it requires at least 6 pixels for its "edge
|
||
effects" at top and bottom:
|
||
|
||
|
||
= one pixel for the top line
|
||
|
||
= one clear pixel underneath that
|
||
|
||
= one pixel each for the two bottom lines
|
||
|
||
= one clear pixel between the bottom lines, and one above the upper of these lines.
|
||
|
||
|
||
For text in the system font, which has height 8 pixels, this means that the total height of the button
|
||
should be at least 14 pixels. With a height of fourteen pixels, the baseline of the text comes 1+1+7
|
||
pixels below the top of the box.
|
||
|
||
|
||
Since this must match the baseline of the accompanying text Press and fo test, it follows that the top of
|
||
the box should be at 56-9 pixels.
|
||
|
||
|
||
This the code for DrawButton is
|
||
|
||
|
||
LOCAL_C VOID DrawButton(INT state)
|
||
€
|
||
P_RECT box;
|
||
|
||
|
||
box. tl.x=34+36;
|
||
|
||
box. br .x=34+36+38;
|
||
|
||
box.tl.y=47;
|
||
|
||
box. br. y=47+14;
|
||
wDrawButton(&box, "Enter", state);
|
||
>
|
||
|
||
|
||
56
|
||
|
||
|
||
2 WORKED EXAMPLES IN HWIF
|
||
OO SeSSSSSSSSSSSSSSSSSSSSSSeSeSSS
|
||
|
||
|
||
Animating the action button
|
||
|
||
|
||
When the user does indeed press ENTER, the button should visibly depress, before any multiplication
|
||
question is posed. The code to animate the button is as follows:
|
||
|
||
|
||
LOCAL_C VOID MakeButtonDance(VOID)
|
||
€
|
||
DrawButton( TRUE):
|
||
wFlush();
|
||
p_sleep(2);
|
||
DrawBut ton( FALSE);
|
||
wFlush();
|
||
p_steep(2);
|
||
>
|
||
|
||
|
||
Suggestions for modifying Ta2
|
||
= Display the top line in bold
|
||
|
||
|
||
= Improve the above calculation so that it takes into account the fact that not all characters have
|
||
widths of six pixels, and thereby position the test Press Enter to test yet more centrally
|
||
|
||
|
||
= Consider how to incorporate displaying the value of state.Timing too
|
||
= Experiment by removing the wrlush and/or the p_sleep from MakeButtonDance, to ensure that you
|
||
understand their role in this routine.
|
||
Presenting an edit box
|
||
|
||
|
||
In Ta2, when the user presses ENTER, all that happens is that the score is incremented. In Ta3, the screen
|
||
alters to the following form:
|
||
|
||
|
||
Score: 4 correct out of 9
|
||
Testing 7 times table
|
||
Cup to ? times 12)
|
||
|
||
|
||
Px12= 82]
|
||
|
||
|
||
The left hand part is just the result of one more call to gPrintBoxText, for the text (in this case) 7x 12 =.
|
||
The right hand part is an edit box for the user to enter the answer. There is a flashing cursor in the edit
|
||
box.
|
||
|
||
|
||
The logic of positioning the text display and the edit box is somewhat similar to that above for
|
||
positioning the action button and its surrounding text. The logic for presenting the edit box itself is new.
|
||
|
||
|
||
First, the edit box has to be created:
|
||
|
||
|
||
LOCAL_C VOID *CreateEditor(VOID)
|
||
{
|
||
H_EDIT_BOX heb;
|
||
|
||
|
||
heb.maxchars=4; /* allow up to four characters to be typed */
|
||
|
||
|
||
heb. vulen=30; /* the width is 30 pixels (enough for 4 characters plus the cursor) */
|
||
heb. pos .x=113;
|
||
|
||
heb.pos.y=45;
|
||
|
||
heb.win=MainwWid; /* use the main (screen) window */
|
||
|
||
heb. font=WS_FONT_BASE; /* use the standard font */
|
||
|
||
|
||
heb.style=G_STY_DOUBLE; /* but with double height */
|
||
returnChEBOpen(H_EDIT_BOX_FONT,&heb));
|
||
>
|
||
|
||
|
||
The meaning of the flag H_€01T_80x_FONT passed is that the font and style fields of the passed H_EDIT_BOX
|
||
struct are significant.
|
||
|
||
|
||
After creating the edit box, it has to be instructed to display its flashing cursor:
|
||
|
||
|
||
hEBEmphasise(ebH, TRUE);
|
||
|
||
|
||
57
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
Next, all suitable keypresses have to be diverted in its direction:
|
||
|
||
|
||
FOREVER
|
||
€
|
||
uGetKey(&key);
|
||
if (BadKey(key.keycode))
|
||
Beep();
|
||
else if (key. keycode! =W_KEY_RETURN)
|
||
hEBHandl eKey(ebH , key. keycode, key.modi fiers);
|
||
else
|
||
|
||
|
||
When the user again presses ENTER, the contents of the edit box have to be sensed:
|
||
|
||
|
||
LOCAL_C INT SenseNumberTyped(VOID *ebH)
|
||
{
|
||
TEXT *pb;
|
||
WORD num;
|
||
|
||
|
||
pb=hEBSenseText(ebH);
|
||
p_stoi(&pb, &num);
|
||
return(num);
|
||
|
||
a
|
||
|
||
|
||
If the answer is as expected, the score is incremented, and the user is returned to the base state of the
|
||
application. If the answer is incorrect, the user is given the opportunity either to retry, or to be told the
|
||
correct answer. This interaction takes place via a couple of dialogs. If the user opts to retry, the last
|
||
answer proffered is redisplayed, but completely highlighted so that any typing deletes it at once:
|
||
|
||
|
||
LOCAL_C VOID SelectALLC(VOID *ebH)
|
||
€
|
||
hEBSetSelect(ebH,0,p_slen(hEBSenseText(ebH)));
|
||
>
|
||
|
||
|
||
In all cases, when the application returns to its base state, the resources allocated for the edit box are
|
||
freed by making the call
|
||
|
||
|
||
hEBClose(ebH);
|
||
|
||
|
||
Generating random numbers
|
||
The multiplication questions are generated very easily:
|
||
|
||
|
||
LOCAL_C INT FindRandomC(INT low, INT high)
|
||
{
|
||
INT range;
|
||
|
||
|
||
range=high-low+1;
|
||
return( Low+(INT)(p_randl (&seed)%range) );
|
||
>
|
||
|
||
|
||
LOCAL_C VOID FindFactors(WORD *pa,WORD *pb)
|
||
€
|
||
*pa=(state.Mode==1? FindRandom(2,state.MaxTable): state.Mode);
|
||
*pb=F indRandom(2, state. TableEnd);
|
||
>
|
||
|
||
|
||
The seed for the random variable generator is initialised by making the following call from specificinit:
|
||
seed=p_date();
|
||
|
||
|
||
Further comments on Ta3
|
||
|
||
|
||
Note the following sequence of calls, to print the multiplication question in double height:
|
||
|
||
|
||
SwitchStyle(G_STY_DOUBLE);
|
||
gPrintBoxText(&box, 15,G_TEXT_ALIGN_RIGHT,0,&buf [0] ,p_slen(&buf (01 ));
|
||
SwitchStyle(G_STY_NORMAL);
|
||
|
||
|
||
Switching the style back to normal again is clearly important, since otherwise, the next time any other
|
||
call to gPrintBoxText is made, that text will end up in double height too.
|
||
|
||
|
||
58
|
||
|
||
|
||
2 WORKED EXAMPLES IN HWIF
|
||
—_— ee SeSSeeeSSSSSSSSSSSSSSSSSSSSSsheFsesese
|
||
|
||
|
||
When the editor is active, Ta3 enters a special inner mode, with another get-event loop. Access to the
|
||
menu bar is ruled out until the user has responded to the question in hand. Since no attention is paid to
|
||
Shutdown messages during this inner mode, the Epoc static patLocked is set TRUE before entering this
|
||
loop, and is cleared again on exiting it.
|
||
|
||
|
||
One difference between the edit box used in Ta3 and those used in dialogs is that the former has double
|
||
height display, for special emphasis purposes. This is of course not possible in dialogs. Another
|
||
important difference is that handling the interaction with the editor directly, as in Ta3, allows the whole
|
||
interaction to be terminated when a timer expires - as happens in the next step up from Ta3, namely
|
||
Tables itself.
|
||
|
||
|
||
Suggestions for modifying Ta3
|
||
|
||
|
||
= Improve the inner get-event loop to respond to Shutdown messages from the System Screen
|
||
|
||
|
||
= Add another action button, with the text Press Enter to confirm, while the editor is displayed; to
|
||
make room for this, change from using double height style to bold style
|
||
|
||
|
||
= Replace the code handling the edit box and its associated text with some invoking a suitable
|
||
dialog (albeit with single-height lines); note how simpler the code is in this case
|
||
|
||
|
||
= Keep track of which questions the user answers incorrectly, and modify the code generating the
|
||
questions so as to make these questions more likely to be asked again in the future.
|
||
Adding in a timer
|
||
When the user presses ENTER in the base state of Tables, the screen alters to the following:
|
||
|
||
|
||
Score? 4 correct out of 18 pected
|
||
Testing 7 times table 2x49
|
||
|
||
|
||
Cup to 7 times 12) Tables
|
||
|
||
|
||
?x12= 83] md
|
||
|
||
|
||
Thu 23
|
||
|
||
|
||
The edit box and its accompanying text have moved up, and a bar gauge has appeared. This is
|
||
incremented as time passes, and users have to complete their answer before the bar fills completely.
|
||
|
||
|
||
If the total time allowed is less than five seconds, the display updates once every half second; otherwise,
|
||
it updates itself once a second.
|
||
|
||
|
||
In Specificinit, a timer channel is opened, with the call
|
||
P_open(&timH,"TIM:",-1);
|
||
|
||
|
||
When an edit box is about to be displayed, the timer and some associated state variables are prepared for
|
||
action by the routine
|
||
|
||
|
||
LOCAL_C VOID InitialiseTimer(VOID)
|
||
|
||
|
||
{
|
||
|
||
if (state. Timing<=4)
|
||
{
|
||
timint=5;
|
||
timcount=2*state.Timing;
|
||
>
|
||
|
||
else
|
||
€
|
||
timint=10;
|
||
timcount=state.Timing;
|
||
}
|
||
|
||
timtotent=timcount;
|
||
|
||
QueueT imer();
|
||
|
||
}
|
||
|
||
|
||
The variables timcount and timtotent are used in drawing the bar gauge.
|
||
|
||
|
||
59
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
_—_—_——— — eeeFeFeSeSeSeSeSeeeeeeSSSSSSSSFFseseF
|
||
|
||
|
||
Evidently, part of this preparation stage is to prime the timer:
|
||
|
||
|
||
LOCAL_C VOID QueueTimer(VOID)
|
||
¢
|
||
CancelTimer();
|
||
p_ioa4(timH,P_FRELATIVE,&timstat,&timint);
|
||
timact ive=TRUE>
|
||
>
|
||
|
||
|
||
The reason why the routine queueTimer starts off with a call to cancetTimer is to cater for the case when
|
||
the user retries an answer.
|
||
|
||
|
||
CancelTimer protects itself against cancelling an event that does not exist, by means of checking the
|
||
variable timactive:
|
||
|
||
|
||
LOCAL_C VOID CancelTimer(VOID)
|
||
|
||
|
||
C
|
||
|
||
if (timactive)
|
||
{
|
||
P_iow2(timH,P_FCANCEL);
|
||
p_waitstat(&timstat);
|
||
>
|
||
|
||
timactive=FALSE;
|
||
|
||
>
|
||
|
||
|
||
As can be seen, timactive is set TRUE whenever any p_ioc call is made for the timer. It is set back to FALSE
|
||
again, either inside Cancel Timer, or in the get-event loop, whenever the expiry of the timer is detected:
|
||
|
||
|
||
p_iowait();
|
||
|
||
if (keystat==E€_FILE_PENDING)
|
||
€ /* the timer must have expired */
|
||
timactive=FALSE;
|
||
IncrementBarChart();
|
||
|
||
|
||
The routine CancelTimer is also called when exiting the inner get-event loop
|
||
|
||
|
||
DatLocked=FALSE;
|
||
hEBClose(ebH);
|
||
ClearBottomsrea();
|
||
DisplayPressButton();
|
||
Cancel Timer();
|
||
|
||
>
|
||
|
||
|
||
The call to p_waitstat inside CancelTimer is vital since, as for all the p_FCANCELS in Epoc, the timer
|
||
P_FCANCEL does not stop the timer from completing (and thereby signalling). Rather, it precipitates the
|
||
completion (if it has not already taken place).
|
||
|
||
|
||
Drawing the bar gauge
|
||
The outside of the gauge is drawn by a call to gBorderRect:
|
||
|
||
|
||
box.tl.x=8;
|
||
|
||
box. br .x=189-8;
|
||
|
||
box.tl.y=61;
|
||
|
||
box.br.y=61+8;
|
||
gBorderRect(&box,W_BORD_CORNER_1);
|
||
|
||
|
||
The grey pattern inside is drawn by calls to gFillPattern, using the built-in grey bitmap:
|
||
|
||
|
||
LOCAL_C VOID IncrementBarChart(VOID)
|
||
€
|
||
P_RECT box;
|
||
|
||
|
||
timcount--;
|
||
|
||
GetBarChartRect(&box);
|
||
|
||
box. br.x=9+171*(timtotent-timcount)/timtotent;
|
||
gFillPattern(&box,WS_BITMAP_GREY,G TRMODE_REPL);
|
||
}
|
||
|
||
|
||
60
|
||
|
||
|
||
2 WORKED EXAMPLES IN HWIF
|
||
—_— eee
|
||
|
||
|
||
The rectangle returned by GetBarChartRect is the same as that used to draw the outside of the gauge,
|
||
except that it is inset by one pixel all around.
|
||
|
||
|
||
Limitation on debugging Tables
|
||
|
||
|
||
Due to a limitation in some earlier versions of the Series 3 ROM, applications such as Tables, which use
|
||
asynchronous keyboard reads, may find they are unexpectedly panicked with panic 73, while debugging.
|
||
This can arise in the following situations:
|
||
|
||
|
||
= the program has stopped at a break point when it has a keyboard read outstanding (ie the
|
||
program has broken following a timer event), and a key is pressed on the Series 3
|
||
|
||
|
||
= or, the program has stopped at a break point when a timer has been queued, and the timer
|
||
expires when the program is broken.
|
||
|
||
|
||
In either case, the panic will not be immediate, but will occur later as the result of a signal being mis-
|
||
identified. (Another problem that can occur, for the same reason, is that the timer will never complete.)
|
||
Suggestions for enhancing Tables
|
||
|
||
|
||
® Allow access to the Timing menu command only when a suitable password is supplied; this
|
||
password could be set (via another menu command) only by a "supervisor", and the “student”,
|
||
without knowing the password, would be unable to alter the time allowed for each question
|
||
|
||
|
||
= Currently, the Tested and Correct fields can become arbitrarily high; impose some kind of limit
|
||
|
||
|
||
= Consider a mode in which questions are posed repeatedly, without the user needing to press
|
||
ENTER between every question; ask up to n questions repeatedly, where 7 has been set in
|
||
advance by the user
|
||
|
||
|
||
= Currently, the timer is reset for each question; allow users to answer as many questions as
|
||
possible during a total amount of time specified; give points for correct values and deduct points
|
||
for incorrect answers.
|
||
|
||
|
||
a a ee a Oe ah a a ee
|
||
The remaining example applications
|
||
|
||
|
||
Much could be said about the remaining example applications which cover a wide variety of different
|
||
function calls and programming ideas. However, any readers who have managed to follow the discussion
|
||
so far in this chapter will be well placed to unravel the contents of these other applications by themselves.
|
||
|
||
|
||
One possible exception is the use of a resource file in the Remind example application (This feature was
|
||
not present in earlier versions of this application).
|
||
Resource file access with REMIND
|
||
|
||
|
||
See the chapter on Resource Files in the Additional System Information manual for background
|
||
information about the value and use of resource files generally.
|
||
|
||
|
||
In Remind, all text has been removed from the source module remind.c and has been placed in suitable
|
||
structures in remind.rss. Code in remind.c sees that these resources are loaded when needed.
|
||
|
||
|
||
Several aspects of this should be noted:
|
||
|
||
|
||
« The custom project file remind.pr contains the instruction "runrs remind" which has the result of
|
||
creating the binary file remind.rsc from the input plain text file remind.rss using the batch file
|
||
rs.bat which in turn invokes the resource compiler rcomp.exe
|
||
|
||
|
||
= This project file runs the resource compiler UNCONDITIONALLY but a more sophisticated
|
||
project file, as discussed in the Object Oriented Programming Guide, could avoid recompiling
|
||
the resource file unnecessarily (assuming no changes have been made)
|
||
|
||
|
||
= The binary file remind.rsc is listed in the add-file-list file remind.afl to ensure that it is
|
||
automatically linked together with the object code as part of the application file remind.app
|
||
|
||
|
||
= The routine LoadMenus in remind.c loads the menu text out of the resource file into static data
|
||
structures AND THEN "walks" these data structures, converting them into the form required by
|
||
the Hwif menu subsystem
|
||
|
||
|
||
= Incontrast, string data is only loaded into memory when required using the function Loadstr
|
||
|
||
|
||
61
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
—_——— ee
|
||
|
||
|
||
The code in remind.c is copiously commented.
|
||
|
||
|
||
62
|
||
|
||
|
||
CHAPTER 3
|
||
|
||
|
||
ADVANCED USE OF HWIF
|
||
|
||
|
||
This chapter describes how to build your own version of the Hwif library and hence how to add your
|
||
own extensions to Hwif. It also explains, with examples, how to combine Hwif programming with the
|
||
use of Psion's object oriented programming techniques.
|
||
|
||
|
||
ESS ee ee ee ee
|
||
Building the Hwif library
|
||
|
||
|
||
Buildable source of the Hwif library is supplied as an HWIFSRC component on the Optional disk of the
|
||
SIBO C SDK software. If installed, this source is copied into a \sibosdk\hwifsrc directory.
|
||
|
||
|
||
This directory should contain all the source files necessary to build your own version of the Hwif library,
|
||
but you may need to insure that the ts.red file is suitable for your environment. Since the Hwif source
|
||
code contains some object oriented software, you will also need to install the OOP component from the
|
||
Optional disk before building the library.
|
||
|
||
|
||
Executing the make.bat batch file in the \sibosdk\hwifsrc directory will create an hwif.lib file that should
|
||
be identical, apart from four bytes of date-stamp information, to the hwif.lib that is copied into the
|
||
\sibosdk\lib directory by installing the HWIF component from the Optional disk. Note that making the
|
||
Hwif library will also create an hwifo.lib library, whose use is described later in this chapter.
|
||
Extending Hwif
|
||
|
||
|
||
Once you have successfully built an Awif.lib that reproduces the one supplied with the SDK software,
|
||
you may, if you wish, add your own extensions. These will typically be additional utility functions, but
|
||
could be anything that you wish to add to Hwif.
|
||
|
||
|
||
All you have to do is add further code, either to the existing Hwif source files, or to additional source
|
||
files and then rebuild the library. You may, if you wish, modify the make. bat file to remove the line:
|
||
|
||
|
||
tscx /m hwifo /v0
|
||
|
||
|
||
so that the Awifo. lib library is not rebuilt. If you have written source code in additional files you will, of
|
||
course, have to modify the Awif.pr project file to include them.
|
||
|
||
|
||
a a ek SY Re ee
|
||
Combining Hwif with object oriented code
|
||
|
||
|
||
It is possible for an Hwif program to be written to use parts of the built-in object oriented libraries OLIB,
|
||
FORM, HWIM and (on the Series 3a and Workabout) XADD. One of the most important advantages of
|
||
doing this is to use one or more object oriented (HWIM) dialogs, via the hoodialog utility function.
|
||
Because of its importance, the rest of this chapter concentrates on the techniques that allow the use of this
|
||
function.
|
||
|
||
|
||
HWIM dialogs support several features not available to Hwif dialogs. For example:
|
||
= Subdialogs can be launched when the user presses Tab.
|
||
|
||
|
||
= The value shown in one field can be made to change dynamically according to changes made by
|
||
users in other fields in the dialog.
|
||
|
||
|
||
= Features such as locking items or dimming items are also available.
|
||
|
||
|
||
63
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
See the Object Oriented Programming Guide and the HWIM Reference manual for a full discussion of
|
||
programming HWIM dialogs. The following description assumes some familiarity with the contents of
|
||
those manuals.
|
||
|
||
|
||
In the Psion programming system, the class definition of an object oriented class must appear in a
|
||
category file, and each code segment may only be associated with a single category file. Since the Hwif
|
||
library is associated with its own category file, this means that application-specific classes can not simply
|
||
be added directly to an Hwif program.
|
||
|
||
|
||
When combining application-specific classes with an Hwif program, the classes can be defined:
|
||
= ina separate category file, associated with a separate (DYL) code segment;
|
||
=# ina modified Hwif category file.
|
||
|
||
|
||
These two alternatives are described in the following two sections.
|
||
|
||
|
||
Using a separate DYL
|
||
|
||
|
||
This technique is illustrated by the OQuery example application that may be copied into a
|
||
\sibosdk\hwifood directory by installing the HWIFOOD component of the Optional disk. This example
|
||
will be recognised as a version of the standard Hwif Query example program.
|
||
|
||
|
||
In OQuery, only one dialog is converted into HWIM form; this is the dialog to scan forwards or
|
||
backwards in time to find the next occurrence of a particular date combination. On running the
|
||
application, the difference between this and the original Hwif dialog (in particular, its "flicker free"
|
||
updating) should be immediately noticeable.
|
||
|
||
|
||
In addition to the changes needed to run an HWIM dialog, all use of the floating point emulator has been
|
||
abolished by replacing explicit floating point manipulation with calls to the p_fxxx functions.
|
||
|
||
|
||
The resource file, oquery.rss, contains the following dialog resource:
|
||
|
||
|
||
RESOURCE DIALOG oqd_date_combins
|
||
€
|
||
title="Find date combinations";
|
||
controls=
|
||
€
|
||
CONTROL
|
||
€
|
||
class=C_CHLIST;
|
||
prompt="Day in week";
|
||
info=CHLIST { rid=oqm_daynames; };
|
||
>,
|
||
CONTROL
|
||
€
|
||
class=C_NCEDIT;
|
||
prompt="Day in month";
|
||
info=NCEDIT
|
||
€
|
||
low=1;
|
||
high=31;
|
||
);
|
||
},
|
||
CONTROL
|
||
€
|
||
class=C_DTEDIT;
|
||
prompt="Found date";
|
||
info=DTEDIT
|
||
€
|
||
flags=IN_DTEDIT_DDMMYYYY | IN_DTEDIT_INIT;
|
||
low=0;
|
||
high=93501L;
|
||
3
|
||
3,
|
||
|
||
|
||
3 ADVANCED USE OF HWIF
|
||
—_—_— SS eee
|
||
|
||
|
||
CONTROL
|
||
{
|
||
class=C_ACLIST;
|
||
info=ACLIST € rid=oqa_date_combins; };
|
||
>
|
||
3;
|
||
>
|
||
|
||
|
||
The code associated with the HWIM dialog itself is in the two files ogd.cat (the class definition of the
|
||
dialog) and oqdc.c (the source code for the dialog's method functions). These are the only two source
|
||
files that are used to build the application's DYL, ogd.dyl, using the techniques explained in the Object
|
||
Oriented Programming Guide.
|
||
|
||
|
||
The category file, ogd.cat contains the following definition of the oap_comBINs class that subclasses the
|
||
HWIM btesox class:
|
||
|
||
|
||
LIBRARY ogd
|
||
|
||
|
||
EXTERNAL olib
|
||
EXTERNAL hwim
|
||
|
||
|
||
INCLUDE dlgbox.g
|
||
|
||
|
||
CLASS oqd_combins dlgbox
|
||
€
|
||
REPLACE dl_dyn_init
|
||
REPLACE dl_key
|
||
}
|
||
|
||
|
||
which means that the class number of the dialog will be represented by the symbolic constant
|
||
C_OQD_COMBINS.
|
||
|
||
|
||
The name of the DYL is included in the DYL file list in oquery.dfl, which means that the DYL will be
|
||
built into the final image file, oquery.img. This is the preferred way of packaging a DYL with an
|
||
application.
|
||
|
||
|
||
The code associated with running this dialog is in oquery.c. In the function specificinit¢) the DYL is
|
||
loaded and its handle written to the static variable py|Handle by:
|
||
|
||
|
||
DylHandle=hLoadOwnDyl (0);
|
||
|
||
|
||
where the zero parameter indicates that ogd.dyl is the first (and, in this case, the only) DYL built into the
|
||
.img file.
|
||
|
||
|
||
The dialog is run, from the ManageCommand() function, by:
|
||
hOODjalog(Dyl Handle, C_OQD_COMBINS,OQD_DATE_COMBINS, NULL);
|
||
|
||
|
||
Note that static data is not allowed in a DYL,; all data transfer between an Hwif program and an HWIM
|
||
dialog has to be via:
|
||
|
||
|
||
= the rbuf result buffer;
|
||
|
||
|
||
= the EPOC magic statics DatApp1 through DatApp7, which are specifically designed for this kind of
|
||
use,
|
||
|
||
|
||
In this application, there is no transfer of data to or from the dialog, and so the rbuf parameter is set to
|
||
NULL.
|
||
|
||
|
||
Also note that, in this example application, the DYL is never unloaded by application code. In general, a
|
||
DYL should be unloaded (using the function p_unloadl ib) as soon as the code it contains is no longer
|
||
required.
|
||
|
||
|
||
Debugging an Hwif DYL
|
||
|
||
|
||
Note that, when using the SIBO Debugger, you can only apply breakpoints in a code segment (or see its
|
||
source code) when the code segment is loaded.
|
||
|
||
|
||
If you wish to apply a breakpoint in, or otherwise debug, a DYL used by an Hwif program you must
|
||
first run the program until the DYL is loaded. In the case of the OQuery program you could, for
|
||
example, set a breakpoint on the line:
|
||
|
||
|
||
DylHandle=hLoadOwnDyl (0);
|
||
|
||
|
||
65
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
_ — EeSeSSSSSSSSSSSSSSSSSSSMSSSSSee
|
||
|
||
|
||
On stepping through this line, the DYL is loaded and you can then debug it as normal.
|
||
|
||
|
||
You can, for example, view its code by using the Source module option of the Debugger's View menu
|
||
and selecting the appropriate code segment and source file in the resulting dialog.
|
||
|
||
|
||
You can set a breakpoint in the DYL without first viewing its code, provided you specify the code
|
||
segment name (which is the same as the name of the DYL). Suppose you wish to set a breakpoint in
|
||
oqd.dyl, on the dl_dyn_init method of the oap_come1ns dialog. While the DYL is loaded, you can, in the
|
||
Debugger's Set breakpoints dialog, add the breakpoint by typing in:
|
||
|
||
|
||
GQD:oqd_combins_dl_dyn_init
|
||
|
||
|
||
Modifying the Hwif category
|
||
|
||
|
||
The second way of introducing applicaton-specific object classes into an Hwif application is by
|
||
incorporating them into the Hwif category file. Effectively, this is the same idea as described earlier to
|
||
add extensions to Hwif.
|
||
|
||
|
||
In principle, the way to do this is to:
|
||
= add the application-specific class definitions to the end of the Hwif category file, hwif.cat,
|
||
= write the additional code in one or more additional source files,
|
||
= compile and link all the source files, including those of Hwif, into the application .img file.
|
||
|
||
|
||
In practice, it is more convenient to do this in a different, but totally equivalent, way. Instead of
|
||
modifying the Hwif category file, you create an application-specific category file. The initial lines of this
|
||
file must be an exact copy of the Hwif category file, hwif.cat, whose content is shown below.
|
||
|
||
|
||
IMAGE hwif
|
||
|
||
|
||
EXTERNAL olib
|
||
EXTERNAL hwim
|
||
|
||
|
||
INCLUDE Lprinter.g
|
||
INCLUDE help.g
|
||
|
||
|
||
CLASS hprinter lprinter
|
||
|
||
€
|
||
|
||
REPLACE lpr_read
|
||
|
||
REPLACE ipr_sense_text
|
||
|
||
PROPERTY
|
||
€
|
||
INT (*sense)(WDR_PRINT *);
|
||
>
|
||
|
||
>
|
||
|
||
|
||
CLASS hhelpdlg helpdlg
|
||
{
|
||
REPLACE destroy
|
||
}
|
||
|
||
|
||
You may change the file name and the name in the IMAGE statement to match the particular application.
|
||
Note that the two names must be the same, so that, for example, a category file called myapp.cat must
|
||
start with the statement
|
||
|
||
|
||
IMAGE myapp
|
||
|
||
|
||
You may also, if necessary for the application, add further exTERNAL and/or header file INCLUDE
|
||
statements.
|
||
|
||
|
||
Apart from these possible changes and additions, the first part of the file must match the contents of the
|
||
hwif.cat file exactly. This data should then be followed by the application-specific class definitions.
|
||
|
||
|
||
Further files contain the application source code exactly as for a normal Hwif application, except that
|
||
they also include the method function code for the application-specific classes.
|
||
|
||
|
||
After compiling these files, you should link them with the Awifo. lib library file, rather than the normal
|
||
hwif. lib.
|
||
|
||
|
||
66
|
||
|
||
|
||
3 ADVANCED USE OF HWIF
|
||
|
||
|
||
The file hwifo.lib is copied into the \sibosdk\lib directory when you install the HWIF component from
|
||
the Optional disk. It can also be built from the Hwif source code, as described earlier in this chapter. It
|
||
differs from hwif.lib only in that it does not contain the Hwif category data.
|
||
|
||
|
||
The technique of modifying the Hwif category file is illustrated by the gbar.img example code that is
|
||
described in the following section.
|
||
|
||
|
||
Sa SS a eS Se EES
|
||
|
||
|
||
Access to a growing scroll bar from Hwif
|
||
|
||
|
||
The source code for the gbar.img example application is copied into the \sibosdk\hwifood directory by
|
||
installing the HWIFOOD component from the Optional disk.
|
||
|
||
|
||
This example, in addition to illustrating the technique of including object oriented code by modifying the
|
||
Hwif category, also provides an example of how to use a growing scroll bar, or percentage done
|
||
indicator, in Hwif.
|
||
|
||
|
||
Note that including a growing scroll bar in a dialog is only possible when the dialog is fully object
|
||
oriented, that is, either in an HWIM application, or in a dialog called from Hwif via hooDiatog¢).
|
||
To make gbar.img, run the makegbar.bat batch file in \sibosdk\hwifood.
|
||
|
||
|
||
To run it, copy it to a top-level \IMG\ directory and run from under RunImg. When finished, press
|
||
Psion-Esc to exit it.
|
||
|
||
|
||
The first dialog in the loop lets you specify the parameters for how the second, growbar, dialog operates.
|
||
|
||
|
||
The application's category file
|
||
The category file, gbar.cat is as follows:
|
||
|
||
|
||
IMAGE gbar
|
||
|
||
|
||
EXTERNAL olib
|
||
EXTERNAL hwim
|
||
|
||
|
||
INCLUDE lprinter.g
|
||
INCLUDE help.g
|
||
INCLUDE dlgbox.g
|
||
|
||
|
||
CLASS hprinter (printer
|
||
4
|
||
REPLACE lpr_read
|
||
REPLACE lLpr_sense_text
|
||
|
||
|
||
PROPERTY
|
||
{
|
||
INT (*sense)(WDR_PRINT *):
|
||
>
|
||
|
||
>
|
||
|
||
|
||
CLASS hhelpdlg helpdlg
|
||
{
|
||
|
||
|
||
REPLACE destroy
|
||
>
|
||
|
||
|
||
67
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
—_ TS SSeS
|
||
|
||
|
||
CLASS data_dl dlgbox
|
||
{
|
||
REPLACE dl_dyn_init
|
||
REPLACE dl_key
|
||
TYPES
|
||
€
|
||
typedef struct
|
||
€
|
||
UWORD exit_code;
|
||
UWORD totloops;
|
||
UWORD update;
|
||
UWORD esc;
|
||
UWORD loopsleft;
|
||
UWORD toupdate;
|
||
} RB_GBAR;
|
||
|
||
|
||
>
|
||
|
||
|
||
CLASS gbar_dl dlgbox
|
||
€
|
||
REPLACE wn_sense_help
|
||
REPLACE dl_dyn_init
|
||
REPLACE dl_key
|
||
ADD gbar_update
|
||
>
|
||
|
||
|
||
CLASS bar_ao active
|
||
€
|
||
REPLACE ao_init
|
||
REPLACE ao_run
|
||
|
||
|
||
PROPERTY
|
||
{
|
||
RB_GBAR “prb;
|
||
>
|
||
|
||
>
|
||
|
||
|
||
Comparing this with Awif.cat shows that:
|
||
= the IMAGE name has changed,
|
||
= there is the additional inclusion of digbox.g
|
||
|
||
|
||
= there are application-specific class definitions for the two dialogs DATA_DL and GBAR_DL, and the
|
||
BAR_AO active onject.
|
||
|
||
|
||
This application uses a pointer to a result buffer (in this case, an RB_GBAR struct in the property of the
|
||
BAR_AO active object) to communicate with the dialogs. This is a design decision that is mentioned later.
|
||
|
||
|
||
C_DONEWN items in dialogs
|
||
|
||
|
||
As shown by the pt_sar dialog resource in gbar.rss, a growing scroll bar item in a dialog is defined in
|
||
the resource file simply as:
|
||
|
||
|
||
CONTROL
|
||
€
|
||
class=C_DONEWN;
|
||
>
|
||
|
||
|
||
Compare this with, for example, the definition of a numeric editor control:
|
||
|
||
|
||
CONTROL
|
||
€
|
||
class=C_NCEDIT;
|
||
prompt="Total number of loops";
|
||
jinfo=NCEDIT
|
||
€
|
||
high=100;
|
||
low=1;
|
||
5
|
||
|
||
|
||
68
|
||
|
||
|
||
3 ADVANCED USE OF HWIF
|
||
—_ TS SSeS
|
||
|
||
|
||
The differences are:
|
||
= there is no associated prompt
|
||
m there is no info data.
|
||
|
||
|
||
When a dialog contains a C_DoNewNn element, that element must be sent a WN_SET message, defining the
|
||
range of the element. This must be done during the initialisation of the dialog, before it becomes visible,
|
||
usually from the dl_dyn_init method of the dialog. For example, in the code of growbar.c:
|
||
|
||
|
||
METHOD VOID gbar_dl_dl_dyn_init(PR_DLGBOX “self)
|
||
€
|
||
RB_GBAR *prbuf;
|
||
SE_DONEWN set;
|
||
|
||
|
||
prbuf=sel f->dl gbox.rbuf;
|
||
set.flags=SE_DONEWN_RANGE;
|
||
set.range=prbuf->tot loops;
|
||
hDlgSet(1,&set);
|
||
|
||
}
|
||
|
||
|
||
Note that the wN_SET message to the c_DONEWN element (the element with index 1 in the dialog) is hidden in
|
||
the HWIM utility function hpigset¢).
|
||
|
||
|
||
The SE_DONEWN struct and the WN_SET method of DONEWN
|
||
|
||
|
||
The above code uses an SE_DONEWN struct to pass information in the wN_SET message. This struct is defined
|
||
as follows:
|
||
|
||
|
||
typedef struct
|
||
€
|
||
UWORD flags;
|
||
ULONG val;
|
||
ULONG range;
|
||
> SE_DONEWN;
|
||
|
||
|
||
The value of flags can be any one of the following:
|
||
|
||
|
||
SE_DONEWN_RANGE (0x01) set the control's range
|
||
SE_DONEWN_VALUE (0x02) set the current value to val
|
||
SE_DONEWN_INCREMENT (0x04) increase value by 1
|
||
SE_DONEWN_INC_VAL (0x08) increase value by val
|
||
|
||
|
||
For example, inside the gbar_update method of the eBar_pL dialog in growbar.c it is used to set a specific
|
||
current value:
|
||
|
||
|
||
METHOD VOID gbar_di_gbar_update(PR_DLGBOX *self)
|
||
€
|
||
RB_GBAR *prbuf;
|
||
SE_DONEWN set;
|
||
|
||
|
||
prbuf=sel f->dl gbox.rbuf;
|
||
|
||
set. flags=SE_DONEWN_VALUE;
|
||
set.val=prbuf->totloops-prbuf->Lloopsleft;
|
||
hDlgSet(1,&set);
|
||
|
||
>
|
||
|
||
|
||
Note that the above gbar_update method is not a REPLACEd method but one that has been oped by the
|
||
definition of GBAR_DL to the set defined by the superclass pLGBox.
|
||
The BAR_AO active object
|
||
|
||
|
||
A typical use of a grow bar dialog is to report on the progress of an extended activity. The "update"
|
||
method of the dialog has to be called every so often, during the course of the activity being described in
|
||
the dialog.
|
||
|
||
|
||
However, this activity has to take place in between the dialog starting and the dialog exiting and
|
||
therefore has to take place inside the ao_run method of an active object.
|
||
|
||
|
||
The example uses the BAR_AO active object which is created and initialised early in the Maintoop() function
|
||
in growbar.c by the code:
|
||
|
||
|
||
69
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
_ ee SSS
|
||
|
||
|
||
InitGbarData(&gb_ data);
|
||
|
||
|
||
ao=f_newsend(CAT_GBAR_GBAR,C_BAR_AO,O_AO_INIT,&gb data);
|
||
which calls the object's ao_init method:
|
||
|
||
|
||
METHOD VOID bar_ao_ao_init(PR_BAR_AO *self,RB_GBAR *prb)
|
||
{
|
||
p_send3(w_am,O_AM_ADD_TASK,self);
|
||
sel f->bar_ao.prb=prb;
|
||
>
|
||
|
||
|
||
In the example, the activity is simulated in the ao_run method by simply calling p_sleep(5) to pause the
|
||
application for half a second. The code for the method is:
|
||
|
||
|
||
METHOD INT bar_ao_ao_run(PR_BAR_AO *self)
|
||
¢€
|
||
RB_GBAR *prb;
|
||
|
||
|
||
p_sleep(5); /* the next stage of computation or drawing etc */
|
||
p_send2(sel f ,O_AO_QUEUE);
|
||
prb=sel f->bar_ao.prb;
|
||
if (!--(Cprb->loopsleft))
|
||
{
|
||
p_send2(DatDialogPtr,0_DESTROY);
|
||
prb->exit_code=0;
|
||
}
|
||
else if (!--(prb->toupdate))
|
||
{€
|
||
p_send2(DatDialogPtr,O_GBAR_UPDATE);
|
||
prb->toupdate=prb->update;
|
||
>
|
||
return(RUN_ACTIVE_USED);
|
||
3
|
||
|
||
|
||
Note the following points about the code of this method:
|
||
|
||
|
||
= The next stage of the "computation" is, for convenience, always queued in the ao_run method
|
||
(by sending an Ao_queUE message, which will cause the ao_run method to be called again at some
|
||
time in the future).
|
||
|
||
|
||
= Inconsequence, the grow bar dialog itself can be called by the code:
|
||
|
||
|
||
p_send2(ao,0_AO_QUEUE);
|
||
doDial(C_GBAR_DL,DL_GBAR,&gb data);
|
||
p_send2(a0,0_AO CANCEL);
|
||
|
||
|
||
which always cancels the activity of the active object when the dialog completes.
|
||
= The handle of the current dialog is always accessible from the “reserved static" patDialogpPtr.
|
||
|
||
|
||
= — If the computation is finished, the active object sends a DEsTRoY message to the dialog.
|
||
Otherwise, every so often, the active object sends an "update" message to the dialog.
|
||
|
||
|
||
® Don't forget to
|
||
return(RUN_ACTIVE_USED)
|
||
from your ao_run method (on pain of being panicked 143, most likely).
|
||
= Ip, at aoe there are no parameters to the “update” message, but in another example there
|
||
might be.
|
||
|
||
|
||
Termination of the grow bar dialog
|
||
|
||
|
||
In general, the grow bar dialog can terminate in either of two ways:
|
||
|
||
|
||
= the user presses Esc - in which case the call to hoopialog returns without the cooperation of any
|
||
of the code in the ao_run method
|
||
|
||
|
||
= the computation finishes - in which case the ao_run method sends the dialog a DESTROY message
|
||
and this precipitates the completion of the hooDialog call.
|
||
|
||
|
||
70
|
||
|
||
|
||
3 ADVANCED USE OF HWIF
|
||
eee
|
||
|
||
|
||
General comments
|
||
|
||
|
||
Help has to be disallowed while the grow bar dialog is running, to avoid accidents if the dialog is
|
||
terminated before the help system is shut down. (These complications only arise for hooDjalog, and not
|
||
for pure HWIM programs.) Hence the "magic" in the dialog's wn_sense_help method:
|
||
|
||
|
||
METHOD VOID gbar_dl_wn_sense_help(VOID *self)
|
||
{
|
||
p_leave(RUN_ACTIVE_USED);
|
||
>
|
||
|
||
|
||
For a similar reason, access to the freeform dialler has to be disallowed - hence the "magic" in the
|
||
routine DisallowDial ling:
|
||
|
||
|
||
LOCAL_C VOID DisallowDiall ing¢VOID)
|
||
€
|
||
W_ws->wserv. flags |=PR_WSERV_FREEFORM_DIALLING;
|
||
>
|
||
|
||
|
||
For simplicity, the code deliberately ignores various run-time errors that might arise - for example,
|
||
running out of memory when launching either dialog.
|
||
|
||
|
||
In growbar.c, the active object is created early in the application, and is used repeatedly each time the
|
||
grow bar dialog is invoked. Another design approach would be to have the active object exist only
|
||
throughout the lifetime of an individual grow bar dialog.
|
||
|
||
|
||
Another design decision in this example is not to access any specific static data from inside either the
|
||
dialog code or the active object code. Each of these object interacts with the rest of the world only via
|
||
the result buffer pointers, as noted earlier. An alternative design option would be to access more static
|
||
data from inside these objects.
|
||
|
||
|
||
71
|
||
|
||
|
||
CHAPTER 4
|
||
|
||
|
||
HwiF REFERENCE DOCUMENTATION
|
||
|
||
|
||
SS eS eee oe re ey
|
||
Overview of the Hwif library
|
||
Routines in the Hwif library fall into two categories:
|
||
|
||
= utility functions, which have names starting with lower-case u
|
||
|
||
= primitive functions, which have names starting with lower-case h.
|
||
|
||
|
||
The former category are routines which an experienced Hwif programmer could dispense with or re-
|
||
write. They layer over Window Server function calls, Console I/O requests, and some of the more
|
||
primitive Hwif routines. They turn out to be very useful in practice, but if the need arises, they can in
|
||
principle be replaced by alternative code.
|
||
|
||
|
||
On the other hand, the #-routines can be replaced only by someone familiar with Psion’s proprietary
|
||
object-oriented system.
|
||
|
||
Two levels within the h-layer calls
|
||
|
||
In turn, functions in the h-layer of Hwif can be further classified:
|
||
|
||
|
||
= Low level functions, which would normally be accessed directly only by programmers providing
|
||
their own versions of the u-level functions
|
||
|
||
|
||
« High level functions, which are more widely useful - such as hPrint, hEBSenseText, and
|
||
hDTMFString.
|
||
Two layers within the u-layer calls
|
||
The u-layer calls in the Hwif library can also be classified into two types:
|
||
|
||
|
||
= Central functions, which are likely to be called in every non-trivial Hwif application, and which
|
||
encapsulate detailed knowledge of the operation of the low level h-layer Hwif functions
|
||
|
||
|
||
= Auxiliary functions, whose contents are more straightforward, and which can more easily be
|
||
duplicated by applications programmers.
|
||
|
||
|
||
Many of the auxiliary functions in fact exist in the library only because they are called from within other
|
||
Hwif functions. It would be wasteful for applications to create their own versions of these functions,
|
||
since this would lead to two duplicate functions in the same application.
|
||
|
||
|
||
Groups of functions and naming conventions
|
||
|
||
|
||
The following groups of high-layer h-routines each have their own naming convention, to clarify their
|
||
roles:
|
||
|
||
|
||
hEBxxx edit box functions
|
||
|
||
HT TXxx time text functions
|
||
|
||
hDT xxx date/time text editor functions
|
||
hPrintxxx Printing and print support functions.
|
||
|
||
|
||
73
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
Return values and error notification
|
||
|
||
|
||
In most cases, Hwif functions that can fail return negative values to indicate the nature of the failure, and
|
||
zero or a positive value to indicate success. (The exceptions include a few constructive functions, which
|
||
return the handle of some allocated block if successful, and NuLL if not.)
|
||
|
||
|
||
For a function which can only have two outcomes, success or failure, the former is usually indicated by
|
||
the return value 0, and the latter by the return value -1. In practice, the outcome can be determined by
|
||
the caller making a simple test, such as
|
||
|
||
|
||
if (TryOpenDbf(...))
|
||
|
||
ae /* the call to TryOpenDbf failed */
|
||
else
|
||
|
||
sto. /* the call succeeded */
|
||
|
||
|
||
or
|
||
|
||
|
||
if (uOpenDialog(NULL))
|
||
return; /* no memory to open the dialog */
|
||
|
||
|
||
Most Hwif library routines automatically notify the user of any error that arises, before returning the
|
||
error value to the caller. It is only the low level h-layer routines that leave the notification to the caller.
|
||
|
||
|
||
Binary counted strings
|
||
|
||
|
||
Although most of the Series 3 ROM functions work with ZTSs (zero terminated strings) as opposed to
|
||
BCSs (leading byte-counted strings), some of the functions within Hwif instead work with BCSs.
|
||
|
||
|
||
Where conversion between the two types of representation of string is required, this is obviously
|
||
straightforward.
|
||
|
||
|
||
In all cases below, strings are assumed to be given in ZTS form, unless otherwise stated.
|
||
|
||
|
||
Dialog and menu interactions as a special mode
|
||
|
||
|
||
An Hwif application enters a special mode when it makes the calls uPresentMenus, uRunDialog, hPrint or
|
||
hPrintSetupDialog:
|
||
|
||
|
||
= messages from the System Screen are blocked during this time, with the user being told that the
|
||
application is "busy"
|
||
|
||
|
||
= if, during a menu or dialog interaction, the application is tasked into background or foreground,
|
||
or is switched off then on again, the application is not notified of this fact
|
||
|
||
|
||
= if a timer expires, or another non-keypress event occurs, the application only finds out about this
|
||
when the user in due course concludes the menu or dialog interaction.
|
||
|
||
|
||
In the above cases, the processing of events passes temporarily out of the hands of application, to a
|
||
central get-event loop in ROM code. This ROM get-event loop can only process events from event
|
||
sources it explicitly knows about - and this excludes any timers, alarms, or other non-keypress event
|
||
sources installed by the application. If the ROM get-event loop detects a signal without the status words
|
||
of any of the event sources it knows about being written to (as will occur if, for example, an application-
|
||
installed timer expires), it simply increments an internal counter. When program execution is about to
|
||
pass back out of the ROM get-event loop to the application, one signal is re-emitted for every time the
|
||
internal counter was incremented.
|
||
|
||
|
||
a a a a eS et RR OR a ee
|
||
The central functions in the u-layer of Hwif
|
||
|
||
|
||
i to Hwif applications
|
||
VOID uCommonInit(VOID);
|
||
|
||
|
||
Opens and sizes a console window appropriate for the Series 3, Series 3a or Workabout screen. Initialises
|
||
control blocks for subsequent menu and dialog interactions.
|
||
|
||
|
||
If unsuccessful (for example, because the Window Server has insufficient memory to open the console
|
||
window), the application is terminated with an in-line call to p_exit.
|
||
|
||
|
||
74
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
SSS
|
||
|
||
|
||
If successful, the address of the control block of the console is written to the globally referenced static
|
||
VOID *winHandle;
|
||
|
||
|
||
The routine copes with the case when wintandle is non-zero when the routine is called - usually because a
|
||
CLIB start-up module has been used. Rather than attempt to open the console again, the existing console
|
||
channel is used, with any flashing block cursor being turned off.
|
||
|
||
|
||
A basic example of the use of uCommontinit is:
|
||
|
||
|
||
GLDEF_C VOID main(VOID)
|
||
{
|
||
uCommonInit();
|
||
SpecificInit();
|
||
MainLoop();
|
||
>
|
||
|
||
|
||
The general behaviour and appearance of the console window that is created in a call to ucommoninit
|
||
depends on the value of the global variables _UseFul screen and _S3UseFul lScreen on entry to the call.
|
||
|
||
|
||
On all machines, if the values of _useFulltScreen and _S3UseFul Screen are zero (the default values) Hwif
|
||
is initialised in Series 3 compatibility mode. This means that the behaviour and appearance of the console
|
||
on the Series 3a or Workabour emulates the behaviour of the console on the Series 3.
|
||
|
||
|
||
If, however, the value of Useful Screen is non_zero, Hwif is initialised appropriately for the machine on
|
||
which the application is running. On the Series 3a and Workabout, the application can take full
|
||
advantage of the larger screen size, grey and other additional features.
|
||
|
||
|
||
The value of _s3UseFul screen is ignored by Series 3 and Series 3a machines. On the Workabout, if
|
||
_S3UseFul (Screen is non-zero (and regardless of the value of _UseFut tscreen) Hwif is initialised to use the
|
||
Window Server's w_ctTeY_s3_scr compatibility mode. This is a Series 3 (i.e. no grey) compatibilty mode,
|
||
but the full 240x100 area of the Workabout screen is used. For example:
|
||
|
||
|
||
GLREF_D UWORD _S3UseFul lScreen;
|
||
|
||
|
||
GLDEF_C VOID main(VOID)
|
||
€
|
||
_S3UseFul lScreen=TRUE; /* Set Workabout to $3 full-screen compatibility */
|
||
uCommonInit();
|
||
|
||
|
||
}
|
||
|
||
|
||
Note that on all machines (except the Workabout in true Series 3 compatibilty mode, where a 240x80
|
||
window is used) the console window is created to be occupy the full screen. Regardless of its size, it will
|
||
always display an exact number of lines of text.
|
||
|
||
|
||
In addition to its use to specify whether or not to use compatibility mode, the value of _UseFul LScreen can
|
||
be tested on return from uCommontinit to determine the type of the machine on which the code is running;
|
||
a non-zero value means that the application is running on a Series 3a or Workabout, while a zero value
|
||
means that the machine is running on the Series 3. This is demonstrated in the following code fragment:
|
||
|
||
|
||
GLREF_D UWORD _UseFullScreen;
|
||
|
||
|
||
GLDEF_C VOID main(VOID)
|
||
{
|
||
_UseFul LScreen=TRUE;
|
||
uCommonInit();
|
||
if (_UseFul l|Screen)
|
||
€
|
||
/* Running on a Series 3a or Workabout */
|
||
|
||
|
||
>
|
||
else
|
||
€
|
||
/* Running on a Series 3. */
|
||
|
||
|
||
}
|
||
|
||
|
||
A call to uCommontnit does not write anything to _s3UseFul Screen so there is no equivalent test that can
|
||
be made on its value.
|
||
|
||
|
||
75
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
VOID uEnableGrey(VOID);
|
||
|
||
|
||
This function enables the use of grey in the main console window. It must be called before any attempt is
|
||
made to draw grey on the Series 3a or Workabout.
|
||
|
||
|
||
Because of the overhead involved, grey should not be enabled as a matter of routine. If the application
|
||
never intends to draw grey then it should not be enabled!
|
||
|
||
|
||
Ideally, it should be called as soon as possible after the call to uCommoninit. In general, a call to this
|
||
function should be imbedded in the initialisation code specific to the application. Referring to the general
|
||
structure of an Hwif program as mentioned in the description of uCommoninit, the function specificinit¢)
|
||
is usually a good place to imbed a call to uEnableGrey.
|
||
|
||
|
||
The following program is a very simple example that draws a shadowed grey effect border using the
|
||
function gBorder2, if running on the Series 3a or the Workabour: if running on the Series 3, or on the
|
||
Series 3a or Workabout in compatibility mode, it draws a simple shadowed border without grey.
|
||
|
||
|
||
On the Series 3a and Workabout, grey must be enabled before the grey shadowed effect border can be
|
||
drawn.
|
||
|
||
|
||
#include <p_std.h>
|
||
#include <wlib.h>
|
||
#include <hwif.h>
|
||
|
||
|
||
GLREF_D UWORD _UseFullScreen;
|
||
|
||
|
||
LOCAL_D WORD keystat;
|
||
LOCAL_D INT gc;
|
||
|
||
|
||
LOCAL _C VOID SpecificInit¢(VOID)
|
||
{
|
||
gc = gCreateGCO(uF indMainWid());
|
||
if (_UseFul lScreen)
|
||
€
|
||
wFree(gc);
|
||
uEnabl eGrey();
|
||
gc = gCreateGCO(uF indMainWid());
|
||
gBorder2(W_BORDER_TYPE_1,W_BORD_CORNER_4|W_BORD_SHADOW_ON|W_BORD_SHADOW_D);
|
||
}
|
||
else
|
||
gBorder(W_BORD_CORNER_4|W_BORD_SHADOW_ON|W_BORD_SHADOW D);
|
||
>
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
€
|
||
WMSG_KEY key;
|
||
|
||
|
||
FOREVER
|
||
€
|
||
uGetKeyA(&keystat, &key);
|
||
p_iowait();
|
||
if (key.keycode & W_SPECIAL_KEY)
|
||
if (Ckey.keycode & (“W_SPECIAL_KEY)) == 'x')
|
||
p_exit (0);
|
||
|
||
|
||
>
|
||
|
||
|
||
GLDEF_C VOID main¢VOID)
|
||
€
|
||
_UseFullScreen = TRUE;
|
||
uCommonI nit();
|
||
Specificinit();
|
||
MainLoop();
|
||
>
|
||
|
||
|
||
It is important to note that uEnableGrey causes the ID of the main window to change. Thus, after calling
|
||
uEnableGrey and before calling any functions that need the main window ID as a parameter, call
|
||
uF indMainwWid.
|
||
|
||
|
||
76
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
|
||
|
||
VOID uGetKey(WMSG_KEY *pkey);
|
||
Reads a keypress into *pkey, waiting indefinitely if no keypress is received.
|
||
|
||
|
||
The routine also returns if any special event is received; in this case, the keycode has the bit W_EVENT_KEY
|
||
set. The various possible values in this case are given in the header file p_cons.h:
|
||
|
||
|
||
CONS_EVENT_FOREGROUND The application has passed into foreground
|
||
CONS_EVENT_BACKGROUND The application has passed into background
|
||
CONS_EVENT_ON_OFF The machine has been switched off and then on again
|
||
CONS_EVENT_COMMAND The application has received a message (probably from the
|
||
|
||
|
||
System Screen) and should call weetCommand to obtain a buffer
|
||
containing more details.
|
||
|
||
|
||
CONS_EVENT_DATE_CHANGED The system date has changed. Typically, the application will get
|
||
this message when the system date passes midnight.
|
||
|
||
|
||
Note that this is only available on Epoc V3.18 or later and
|
||
Window Server V4.32 or later
|
||
|
||
|
||
For example:
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
.¢
|
||
WMSG_KEY key;
|
||
|
||
|
||
FOREVER
|
||
<
|
||
uGetKey(&key);
|
||
if (key. keycode&W EVENT KEY)
|
||
{
|
||
if (key.keycode==CONS EVENT_COMMAND )
|
||
ProcessSystemCommand( );
|
||
|
||
|
||
VOID uGetKeyA(WORD *pstat,WMSG_KEY *pkey);
|
||
|
||
|
||
Reads a keypress into *pkey whenever the next keypress is received, without however waiting for this to
|
||
occur. The value of *pstat is changed to E_FILE_PENDING when the call is made. When a keypress is
|
||
received, the value of *pstat is changed from E_FILE_PENDING to 0.
|
||
|
||
|
||
An application that calls uGetkeyA when the previous such call is still outstanding is liable to be panicked
|
||
in due course with panic 73.
|
||
|
||
|
||
77
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
Ee
|
||
|
||
|
||
For example:
|
||
|
||
|
||
LOCAL_D WORD timstat;
|
||
LOCAL_D WORD keystat;
|
||
LOCAL_D WORD keyactive=FALSE;
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
€
|
||
WMSG_KEY key;
|
||
|
||
|
||
FOREVER
|
||
{
|
||
if (keyactive)
|
||
wFlush(); /* flush any outstanding graphics calls */
|
||
else
|
||
{
|
||
uGetKeyA(&keystat, &key);
|
||
keyact ive=TRUE;
|
||
|
||
|
||
>
|
||
p_iowait(); /* wait for something to happen */
|
||
if (keystat==E_FILE_ PENDING)
|
||
|
||
{
|
||
|
||
owe /* the timer must have expired */
|
||
else
|
||
|
||
{
|
||
|
||
keyact i ve=FALSE;
|
||
|
||
eine /* proceed as above */
|
||
|
||
>
|
||
|
||
|
||
VOID uCancelGetKeyACVOID);
|
||
|
||
|
||
This function cancels any outstanding asynchronous request for a keypress or any of the other event types
|
||
described in uGetKey.
|
||
|
||
|
||
Consider the code fragment given as an example in the description of uGetkeyA. This could be modified to
|
||
include a call to uCancelGetkeyA as soon as the timer has expired as shown below:
|
||
|
||
|
||
78
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
—_ ee eS
|
||
|
||
|
||
LOCAL_D WORD timstat;
|
||
LOCAL_D WORD keystat;
|
||
LOCAL_D WORD keyactive=FALSE;
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
£
|
||
WMSG_KEY key;
|
||
|
||
|
||
FOREVER
|
||
{
|
||
if (keyactive)
|
||
wWFlush(); /* flush any outstanding graphics calls */
|
||
else
|
||
{
|
||
uGetKeyA(&keystat ,&key);
|
||
keyact i ve=TRUE;
|
||
}
|
||
p_iowait(); /* wait for something to happen */
|
||
if (keystat==E_FILE_ PENDING)
|
||
{
|
||
ese /* the timer must have expired */
|
||
|
||
|
||
uCancelGetKeyA(); /* cancel outstanding keypress requests */
|
||
keyactive=FALSE; /* no key press requests outstanding */
|
||
|
||
|
||
>
|
||
else
|
||
{
|
||
keyactive=FALSE;
|
||
Ane /* proceed as above */
|
||
>
|
||
|
||
|
||
INT uKeyPressOutstanding(VOID);
|
||
|
||
|
||
Returns TRUE if a keypress is outstanding, else FALSE.
|
||
|
||
|
||
For example:
|
||
|
||
|
||
UpdatePending=FALSE;
|
||
FOREVER
|
||
{
|
||
uGetKey(&key) ;
|
||
switch (key. keycode)
|
||
{
|
||
ee /* may set UpdatePending */
|
||
>
|
||
if (UpdatePending && !uKeyPressOutstanding())
|
||
€
|
||
Drawlcon(); /* time consuming */
|
||
UpdatePending=FALSE;
|
||
>
|
||
>
|
||
|
||
|
||
Note that for the purposes of this routine, "keypress" does not include a general console event (such as
|
||
coming into foreground).
|
||
|
||
|
||
INT uLocateCommand(INT accel);
|
||
|
||
|
||
Looks through the table of commands implicitly identified by the static _cmds, searching for a command
|
||
with the accelerator accel.
|
||
|
||
|
||
Retums -1 if no match is found, or else the index of the matching command, starting with 0 for the first
|
||
command.
|
||
|
||
|
||
79
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
—_—————. $e
|
||
|
||
|
||
For the Series 3, the sets of valid accelerators are:
|
||
= the lower case letters ‘a’ to 'z' inclusive.
|
||
= four characters that vary from language to language - in English they are '+", '-', '*' and '/'.
|
||
|
||
|
||
For the Series 3a and Workabout, the sets of valid accelerators are those which are valid for the Series 3
|
||
plus:
|
||
|
||
|
||
= the upper case letters 'A’ to 'Z' inclusive.
|
||
|
||
|
||
The Series 3a and the Workabout distinguish between shifted and unshifted alphabetic accelerator keys.
|
||
For example, PSION+A and PSION+SHIFT+A may be used to invoke two different commands.
|
||
|
||
|
||
Shifted accelerators are not available on the Series 3 and should not be used in software intended to run
|
||
on any range of machine types that includes the Series 3.
|
||
|
||
|
||
A shifted accelerator is defined by an upper case accelerator in the command array, as for the Search
|
||
backwards command in the following example:
|
||
|
||
|
||
LOCAL_D TEXT *cmds[]=
|
||
€
|
||
"mNew File",
|
||
"aSaveas",
|
||
“sSearch forwards",
|
||
"SSearch backwards",
|
||
"XExit",
|
||
NULL
|
||
3;
|
||
|
||
|
||
Before calling uLocateCommand, a small change must be made to the accelerator key handling code; if the
|
||
Shift Modifier is set, the accelerator key must be converted to uppercase. This is illustrated in the
|
||
following code fragment:
|
||
|
||
|
||
LOCAL_C VOID TryExecuteCommand(INT keycode)
|
||
€
|
||
INT comid;
|
||
|
||
|
||
comid = uLocateCommand(keycode);
|
||
if (keycode >= 0)
|
||
{
|
||
/* execute command with command ID comid */
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID>
|
||
€
|
||
INT code;
|
||
INT ret;
|
||
WMSG_KEY key;
|
||
|
||
|
||
80
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
i er ee ee i ee
|
||
|
||
|
||
FOREVER
|
||
€
|
||
uGetKey(&key);
|
||
if (key. keycode & W_SPECIAL_KEY)
|
||
€
|
||
code = key.keycode & (“W_SPECIAL_KEY);
|
||
if (key.modifiers & W_SHIFT_MODIFIER)
|
||
code = p_toupper(code); /* code change needed to use shifted accelerators */
|
||
TryExecuteCommand(code);
|
||
3
|
||
else
|
||
{
|
||
switch (key.keycode)
|
||
€
|
||
case W_KEY_MENU :
|
||
if (key.modifier & W_CTRL_MODIFIER)
|
||
€
|
||
/* toggle status window */
|
||
else
|
||
€
|
||
ret = uPresentMenus(); /* no code change here */
|
||
if (ret > 0)
|
||
TryExecuteCommand(ret)
|
||
>
|
||
break;
|
||
case W_KEY_TAB :
|
||
break;
|
||
case W_KEY_RETURN :
|
||
break:
|
||
>
|
||
>
|
||
>
|
||
3
|
||
|
||
|
||
Note that no change is required to the code concerned with selecting a command by highlighting its menu
|
||
item and pressing Enter (implemented by a call to uPresentMenus).
|
||
|
||
|
||
INT uPresentMenus(VOID);
|
||
|
||
|
||
Commence a menu bar interaction, presenting the menus implicitly defined via the statics _cmds and
|
||
_mdata. Waits until the menu interaction has terminated before returning.
|
||
|
||
|
||
This function returns:
|
||
|
||
|
||
= 0 if the user cancels or if an error such as out of memory (OOM) occurs - in which case the user
|
||
will already have been notified of this
|
||
|
||
|
||
= the accelerator of the command chosen.
|
||
The Epoc static DatLocked is set TRUE for the duration of the call to uPresentMenus.
|
||
The call requires Window Server resources, and hence its success can never be guaranteed.
|
||
For example:
|
||
|
||
|
||
LOCAL_C VOID TryExecuteCommand(INT keycode)
|
||
€
|
||
keycode=uLocateCommand( keycode) ;
|
||
if (keycode>=0)
|
||
ManageCommand(keycode);
|
||
>
|
||
|
||
|
||
81
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
————_— SSSSSSSSSSSSSSSSSSFMMFee
|
||
|
||
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
|
||
|
||
€
|
||
INT ret;
|
||
FOREVER
|
||
€
|
||
uGetKey(&key);
|
||
if (key. keycode&W_SPECIAL_KEY)
|
||
TryExecuteCommand( key. keycode&(~W_SPECIAL_KEY));
|
||
else if (key. keycode==W_KEY_MENU)
|
||
{
|
||
ret=uPresentMenus();
|
||
if (ret>0)
|
||
TryExecuteCommand(ret);
|
||
>
|
||
else ...
|
||
>
|
||
}
|
||
|
||
|
||
A common situation in moderately complex applications is the need to display different menu bars as the
|
||
context of the application changes.
|
||
|
||
|
||
For example, the built in spreadsheet application on the Series 3a has a different menu bar when running
|
||
in graph mode compared to that when running in normal mode.
|
||
|
||
|
||
In switching between different menu bars in this way, the "position" of the menu item highlighted in one
|
||
menu bar is often lost after switching to a different menu bar. In other words, after switching back to the
|
||
original menu bar, the menu item highlighted is different to the one that was highlighted when this menu
|
||
bar was last displayed. This problem is often a cause of irritation to users.
|
||
|
||
|
||
This difficulty can be avoided by using the global variable MenuPositions available on the Series 3a
|
||
only. The following code fragment illustrates its use:
|
||
|
||
|
||
GLREF_D UWORD *_MenuPositions;
|
||
LOCAL_D UWORD mi;
|
||
LOCAL_D UWORD m2;
|
||
ee. /* build main menu bar */
|
||
_MenuPositions = &m1;
|
||
uPresentmenus( );
|
||
|
||
|
||
--- /* build alternative menu bar */
|
||
_MenuPositions = &m2;
|
||
uPresentmenus( );
|
||
|
||
ee. /* re -build main menu bar */
|
||
_MenuPositions = &mi;
|
||
uPresentmenus( );
|
||
|
||
|
||
In essence, Hwif uses m1 and m2 to store the “position” of the menu item highlighted. Before presenting a
|
||
particular menu bar, the address of the corresponding uworD variable (i.e. m1 or m2) should be loaded into
|
||
_MenuPositions.
|
||
|
||
|
||
INT uOpenDialog(TEXT *title);
|
||
|
||
|
||
Prepares to display a dialog. The dialog has a title line given by the zero terminated string pointed to by
|
||
title, unless title is NULL, in which case the title line is omitted.
|
||
|
||
|
||
Returns 0 for success, or else a negative error - in which case the user will already have been notified of
|
||
the error.
|
||
|
||
|
||
On the Workabout, the dialog will be displayed in a small font if the global variable smal lFontDialog is
|
||
set to a non-zero value before calling uOpenDialog. If this feature is used, it is recommended that the value
|
||
|
||
|
||
82
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
SEE
|
||
|
||
|
||
of _Smal\FontDialog should be set immediately prior to the call to udpenDialog, as in the following
|
||
example:
|
||
|
||
|
||
GLREF_D UWORD _SmallFontDialog;
|
||
|
||
|
||
LOCAL_C VOID RunSmal lDialog¢VOID)
|
||
{
|
||
|
||
|
||
_Smal | FontDialog=TRUE:
|
||
uOpenD ij alog(NULL);
|
||
|
||
|
||
>
|
||
A call to u0penDialog automatically clears _smallFontDialog.
|
||
|
||
|
||
Note that _smaltFontDiatog must not be set to a non-zero value for any dialog that is run on a Series 3 or
|
||
Series 3a. Attempting to run such a dialog on either of these machines will result in the application being
|
||
terminated with a panic 55.
|
||
|
||
|
||
See below for additional examples of the use of uOpenDialog.
|
||
|
||
|
||
9
|
||
|
||
|
||
INT uRunDialog(VOID);
|
||
|
||
|
||
Runs the current dialog, waiting until it is complete.
|
||
|
||
|
||
Returns 0 if the user cancelled, a negative value if an error such as OOM occurred (in which case the
|
||
user will already have been notified of the error), or else (as for Opl/W):
|
||
|
||
|
||
= in the case of a dialog with action buttons, the return value is the (lower-case) keycode of the
|
||
button pressed (unless that button was the Escape key, in which case the return value is zero)
|
||
|
||
|
||
= otherwise, the index of the item highlighted when the dialog is terminated, counting the first line
|
||
(which is the title line if that is present) as 1.
|
||
|
||
|
||
If the dialog is completed successfully, all live variables specified by the items included in the dialog are
|
||
written to, according to the values selected by the user.
|
||
|
||
|
||
The Epoc static DatLocked is set TRUE for the duration of the call to uRunDialog.
|
||
The call requires Window Server resources, and hence its success can never be guaranteed.
|
||
See below for examples.
|
||
|
||
|
||
Note that following a call to ukunDialog, any flashing cursor in the main display of the application may
|
||
stop flashing. This will happen if any field in the dialog displayed a flashing cursor.
|
||
|
||
|
||
Applications which display single- or multi-line edit boxes, or which otherwise incorporate a flashing
|
||
cursor, will need in general to provide a layer of the following sort around calls to uRunDialog:
|
||
|
||
|
||
LOCAL_C INT RunDialog(VOID)
|
||
€
|
||
INT ret;
|
||
|
||
|
||
ret=uRunDialog();
|
||
ReassertCursor();
|
||
return(ret);
|
||
|
||
}
|
||
|
||
|
||
(see also the later discussion on hEBEmphasise).
|
||
|
||
|
||
iAddButtonList Add an action ist te wadiatog
|
||
INT CDECL uAddButtonList(TEXT *but, INT code,...);
|
||
|
||
|
||
Adds an action list of buttons to the current dialog, with each button being specified by a pair of passed
|
||
parameters but, code. The text *but (ZTS) appears above the button and a representation of the keycode
|
||
code appears inside the button.
|
||
|
||
|
||
Buttons are added from the parameters passed until a NULL is encountered for the but of a pair.
|
||
|
||
|
||
83
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
For example,
|
||
uAddButtonL ist¢"Cancel",W_KEY_ESCAPE,"Grey", 'g', "Invert", '7!,NULL);
|
||
|
||
|
||
Returns 0 for success, or else a negative error - in which case the user will already have been notified of
|
||
the error.
|
||
|
||
|
||
Allowed values for code are any printable key (such as 'a' through 'z', or '+' or '*") as well as
|
||
W_KEY_RETURN, W_KEY ESCAPE, W_KEY_DELETE_LEFT, W_KEY_SPACE, W_KEY_UP, W_KEY_ DOWN, W_KEY_RIGHT,
|
||
W_KEY_LEFT, W_KEY_TAB, and W_KEY_MENU. Alphabetic values of code are always displayed in upper-case form
|
||
but are returned (when the corresponding key is pressed) in lower-case form.
|
||
|
||
|
||
If a keycode for a button is specified as negative, then if the user presses ESCAPE, that button will visibly
|
||
depress and the dialog will be terminated (with return value 0 and without the contents of any live
|
||
variables being overwritten).
|
||
|
||
|
||
INT CDECL uAddChoiceList(TEXT *prompt ,UWORD *nsel,TEXT *choice,...);
|
||
|
||
|
||
Adds a choice list to the current dialog, with prompt *prompt and live variable nsel, and choices given in
|
||
text form by additional parameters until a NULL is encountered.
|
||
|
||
|
||
For example,
|
||
uAddChoiceList("Font",&font,"Standard","Bold","Small digits",NULL);
|
||
|
||
|
||
The value of nset should initially be 1 to select the first choice in the list ("Standard” in the above
|
||
example), 2 to select the second choice, and so forth. This is also the form in which the choice of the
|
||
user is written back to nsel on successful completion of the dialog.
|
||
|
||
|
||
Returns 0 for success, or else a negative error - in which case the user will already have been notified of
|
||
the error. -
|
||
|
||
|
||
If prompt is passed as NULL, the choice list is displayed centred horizontally in the dialog, without any
|
||
prompt.
|
||
|
||
|
||
INT uAddDialogItemCINT type, TEXT *prompt,VOID *data);
|
||
|
||
|
||
Adds an item of specified type to the current dialog.
|
||
|
||
|
||
Returns 0 for success, or else a negative error - in which case the user will already have been notified of
|
||
the error.
|
||
|
||
|
||
The item has prompt as specified, unless prompt is passed as NULL, in which case the item has no prompt,
|
||
and is displayed centred horizontally in the dialog.
|
||
|
||
|
||
Possible values of type, and the corresponding structs for data, are:
|
||
|
||
|
||
H_DIALOG_TEXT for a text item, with struct H_DI_TEXT
|
||
|
||
H_DIALOG_NUMBER for a numeric editor, with struct H_DI_NUMBER
|
||
|
||
H_DIALOG_FLOAT for a floating point editor, with struct 1_DI_FLOAT
|
||
|
||
H_DIALOG_TIME for a time or duration editor, with struct H_D1_TIME
|
||
H_DIALOG_DATE for a date editor, with struct 4_DI_DATE
|
||
|
||
H_DIALOG_EDIT for a non-scrolling text editor, with struct H_DI_EDIT
|
||
H_DIALOG_SEDIT for a scrolling text editor, with struct H_DI_SEDIT
|
||
H_DIALOG_XINPUT for a secret data input item, with struct H_DI_XINPUT
|
||
H_DIALOG_FSEL for a filename editor or filename selector, with struct H_DI_FSEL.
|
||
|
||
|
||
(It is also possible to use this routine to add a choice list or an action list to a dialog but in practice, the
|
||
customised routines uAddChoiceList and uAddButonList given earlier are much to be preferred.)
|
||
|
||
|
||
More details of each of the above item types are given in the following sections.
|
||
|
||
|
||
84
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
eee
|
||
|
||
|
||
typedef struct
|
||
€
|
||
TEXT *str;
|
||
UWORD type;
|
||
} H_DI_TEXT;
|
||
|
||
|
||
Possible bit values of type are:
|
||
|
||
|
||
H_DTEXT_ALIGN_LEFT left align the text in its field (the default)
|
||
H_DTEXT_ALIGN_RIGHT right align the text in its field
|
||
|
||
H_DTEXT_ALIGN_CENTRE centre the text in its field
|
||
|
||
H_DTEXT_BOLD display in bold
|
||
|
||
H_DTEXT_UNDERLINE underline the item
|
||
|
||
H_DTEXT_SELECTABLE give the item a bullet and allow it to be highlighted.
|
||
|
||
|
||
The field str is a BCS giving the string to display. This is displayed in the right hand column of the
|
||
dialog, unless prompt is passed as NULL in the corresponding call to uAddDiatog! tem.
|
||
|
||
|
||
For example:
|
||
|
||
|
||
H_DI_TEXT txt;
|
||
TEXT buf[10];
|
||
|
||
|
||
if (uOpenDialog(NULL))
|
||
return;
|
||
txt. type=H_DTEXT_ALIGN_CENTRE|H_DTEXT_BOLD |H_DTEXT_UNDERLINE;
|
||
txt.str=(&buf [0] );
|
||
uZTStoBCS(txt.str,"Warning");
|
||
if (uAddDialogItem(H_DIALOG_TEXT,NULL,&txt))
|
||
return;
|
||
|
||
|
||
uRunDialog();
|
||
|
||
|
||
typedef struct
|
||
{
|
||
|
||
|
||
LONG *value;
|
||
LONG Low;
|
||
LONG high;
|
||
|
||
> H_DI_NUMBER;
|
||
|
||
|
||
The passed value of the live variable *value is what is initially displayed in the dialog. The user is
|
||
constrained from changing the value beyond the limits tow and high.
|
||
|
||
|
||
Setting value equal to the address of a 2-byte integer, instead of a 4-byte long integer, would be a severe
|
||
error.
|
||
|
||
|
||
typedef struct
|
||
{
|
||
DOUBLE *value;
|
||
DOUBLE low;
|
||
DOUBLE high;
|
||
> H_DI_FLOAT;
|
||
|
||
|
||
The meanings of the fields are as for H_DI_NUMBER.
|
||
|
||
|
||
85
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
typedef struct
|
||
{
|
||
ULONG *value;
|
||
ULONG Low;
|
||
ULONG high;
|
||
UWORD type;
|
||
} H_DI_TIME;
|
||
|
||
|
||
Possible bit values for type are:
|
||
|
||
|
||
H_DTIME_SHOW_SECONDS the time display is to include seconds (which are suppressed by
|
||
default)
|
||
H_DTIME_DURATION the time being edited is a duration, not an absolute time, and as
|
||
|
||
|
||
such it never makes sense to display (eg) an am or pm alongside
|
||
it.
|
||
|
||
|
||
The meanings of the other fields in the H_DI_TIME struct are as for H_DI_NUMBER. Note that all times are
|
||
expressed in seconds since midnight, regardless of the setting of the bit H_DTIME_SHOW_SECONDS.
|
||
|
||
|
||
typedef struct
|
||
€
|
||
|
||
|
||
ULONG *value;
|
||
ULONG Low;
|
||
ULONG high;
|
||
> H_DI_DATE;
|
||
|
||
|
||
The meanings of the fields are as for H_DI_NUMBER.
|
||
|
||
|
||
The dates are all expressed in days since 1900.
|
||
|
||
|
||
Useful date constants
|
||
The following constants, defined in hwif.h, may prove useful:
|
||
|
||
|
||
H_LAST_DAY the largest legal value for any of the three fields (when the p_DATE
|
||
representation of date expires)
|
||
|
||
|
||
H_FIRST_SYS_DAY the smallest value of day number that can be converted into the system-time
|
||
representation of date (ie Ist January 1970)
|
||
|
||
|
||
H_LAST_SYS_DAY the largest value of day number that can be converted into the system-time
|
||
representation of date.
|
||
|
||
|
||
(No value is defined for what would have been #_FIRST_DAY, since this is just zero.)
|
||
|
||
|
||
typedef struct
|
||
€
|
||
|
||
|
||
TEXT *str;
|
||
UWORD Len;
|
||
} H_DI_EDIT;
|
||
|
||
|
||
The field Len gives the maximum allowed length of the string. This also determines the width set aside
|
||
for the display of the item in the dialog.
|
||
|
||
|
||
The live variable str gives the initial contents of the string, in BCS form. The string, once edited, is also
|
||
written back in BCS form.
|
||
|
||
|
||
86
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
|
||
|
||
typedef struct
|
||
€
|
||
TEXT *str;
|
||
UWORD len;
|
||
UWORD width;
|
||
} H_DI_SEDIT;
|
||
|
||
|
||
The meaning of the fields is as for H_DI_EDIT, except that the width set aside for display purposes is given
|
||
by width full character widths.
|
||
|
||
|
||
typedef struct
|
||
{
|
||
TEXT *str;
|
||
> H_DI_XINPUT;
|
||
|
||
|
||
The field str must point to a buffer long enough to hold a BCS with eight characters.
|
||
|
||
|
||
typedef struct
|
||
{€
|
||
TEXT *fname;
|
||
UWORD flags;
|
||
> H_DI_FSEL;
|
||
|
||
|
||
The live variable fname must point to a buffer of at least 128 characters. This is used to seed the file
|
||
selector and also to receive the filename chosen.
|
||
|
||
|
||
If the bit H_FILE_NEW_EDITOR is set in flags, a filename editor is produced, with behaviour governed by the
|
||
following remaining bits in flags:
|
||
|
||
|
||
H_FILE_ALLOW_DIRS allow the user to choose a directory name
|
||
H_FILE_JUST_DIRS force the user to choose a directory name
|
||
H_FILE_FORCE_NXIST force the user to choose the name of a file that doesn't already exist
|
||
|
||
|
||
H_FILE_NO_AUTOQUERY disable the "Confirm overwrite?" dialog that appears, by default, when the
|
||
user types the name of a file that already exists
|
||
|
||
|
||
H_FILE_ACCEPT_NULL allow the user to leave the field blank
|
||
|
||
|
||
H_FILE_SET_DEFEXT set the default extension from the seed name passed (so that if the seed is
|
||
first.pic and the user types second, the filename returned to the program is
|
||
second. pic)
|
||
|
||
|
||
H_FILE_CAN_ WILDCARD allow the user to type in wildcards (such as *.pic)
|
||
|
||
|
||
If the bit H_FILE_NEW_EDITOR is nor set (there is a #define H_FILE_PICK_SELECTOR equal to zero), a filename
|
||
selector is produced, with behaviour governed by the following remaining bits in flags:
|
||
|
||
|
||
H_FILE_ALLOW_DIRS allow the user to choose a directory name
|
||
H_FILE_JUST_DIRS force the user to choose a directory name
|
||
|
||
|
||
H_FILE_RESTRICT_LIST restrict the set of files initially selectable (ie until the user presses TAB) to those
|
||
with extension matching that of the seed filename passed
|
||
|
||
|
||
H_FILE_ACCEPT_NULL allow the user to leave the field in a state in which no filename is selected -
|
||
displaying, for example, (no files).
|
||
|
||
|
||
H_FILE_SET_DEFEXT set the default extension from the seed name passed (so that if the seed is
|
||
first.pic and the user selects second, the filename returned to the program is
|
||
second. pic)
|
||
|
||
|
||
H_FILE_CAN WILDCARD allow the user to specify wildcards (such as *.pic) - by means of the
|
||
CONTROL+TAB, CONTROL+ENTER mechanism
|
||
|
||
|
||
87
|
||
|
||
|
||
INT uBeginDCL(H_DI_CHOICE *pch);
|
||
|
||
|
||
Prepares to add a dynamically-defined choice list to a dialog.
|
||
|
||
|
||
The routine writes into the passed H_p1_CHoIcE struct, which is declared and provided by the caller. The
|
||
address of this same struct should be passed to subsequent calls to uGrowDCL and uAddDCL.
|
||
|
||
|
||
Returns 0 for success, or else a negative error - in which case the user will already have been notified of
|
||
the error.
|
||
|
||
|
||
See below for an example.
|
||
|
||
|
||
INT uGrowDCL(H_DI_CHOICE *pch, TEXT *choice);
|
||
|
||
|
||
Adds an entry whose text is given by *pchoice to the end of the dynamically-defined choice list identified
|
||
by *pch.
|
||
|
||
|
||
Returns 0 for success, or else a negative error - in which case the user will already have been notified of
|
||
the error.
|
||
|
||
|
||
See below for an example.
|
||
|
||
|
||
INT uAGGDCL(TEXT *prompt,UWORD *nsel,H_DI_CHOICE *pch);
|
||
|
||
|
||
Adds a dynamically defined choice list to the current dialog, with prompt *prompt and live variable nsel,
|
||
and choices defined by *pch.
|
||
|
||
|
||
Returns 0 for success, or else a negative error - in which case the user will already have been notified of
|
||
the error.
|
||
|
||
|
||
For example, the following routine builds up a choice list whose contents are the twelve month names:
|
||
|
||
|
||
LOCAL_C INT AddMonthChoiceList(UWORD *pmonno)
|
||
€
|
||
H_DI_CHOICE ch;
|
||
TEXT mon [32];
|
||
INT i;
|
||
|
||
|
||
if (uBeginDCL(&ch))
|
||
|
||
|
||
return(-1); /* report failure to caller */
|
||
for (i=O; 1<12; i++)
|
||
|
||
{
|
||
|
||
)_nmmon{ &mon [0] , 1);
|
||
|
||
if CuGrowDCL(&ch,&mon[0] ))
|
||
|
||
return(-1); /* report failure to caller */
|
||
|
||
3
|
||
|
||
return(uAddDCL("Month", pmonno, &ch));
|
||
|
||
|
||
>
|
||
No access should be made to the contents of *pch after adding it into a dialog.
|
||
|
||
|
||
The calls uBeginDcL and uGrowDcL each allocate memory which is added into the central control block of
|
||
the current dialog only when a subsequent call uAddoct is made. If no such call is made, the memory will
|
||
remain permanently tied up. (However, if any call uGrowoct fails, this memory is automatically freed
|
||
before reporting back the error.)
|
||
|
||
|
||
VOID uAddGreyUlinme(UBYTE accel ,UWORD *plines);
|
||
|
||
|
||
Built in applications have the ability to add grey lines underneath menu items. This function allows Hwif
|
||
programs to do the same.
|
||
|
||
|
||
Grey underlining serves to group related menu items and can be a useful visual aid if used sparingly.
|
||
|
||
|
||
88
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
Ee re ae
|
||
|
||
|
||
To use this function, the parameter accel must contain the accelerator character corresponding to the
|
||
menu item under which a grey underline is to be placed. The accelerator character is the first character in
|
||
each entry of the table pointed to by _cmds (see the section on Menu bar interactions in the Introduction to
|
||
Awif chapter in this manual).
|
||
|
||
|
||
The parameter pl ines must point to a memory location containing 16 words (256 bits) provided by the
|
||
application; this area should be initialised to zero.
|
||
|
||
|
||
Further, the global variable _GreyLines should be declared in the application and should contain the
|
||
address of this area before the menu bar is displayed
|
||
|
||
|
||
The function is implemented as follows:
|
||
|
||
|
||
GLDEF_C VOID uAddGreyUline(UBYTE accel ,UWORD *plines)
|
||
€
|
||
*(plines+(accel/16)) [= (1<<¢accel%16));
|
||
}
|
||
|
||
|
||
It merely sets a bit corresponding to the value of the accelerator character in the 16 word area provided
|
||
by the application.
|
||
|
||
|
||
Some points should be noted:
|
||
|
||
|
||
= This function cannot be used if running on the Series 3 or in compatibility mode on the Series
|
||
3a.
|
||
|
||
|
||
= Menu items can be safely underlined in grey even if grey is not enabled for the main console
|
||
window.
|
||
|
||
|
||
The following code is an example of the use this function.
|
||
|
||
|
||
#include <p_std.h>
|
||
#include <wlib.h>
|
||
#include <hwif-h>
|
||
|
||
|
||
GLREF_D UWORD _UseFull Screen;
|
||
GLREF_D UWORD * GreyLines;
|
||
|
||
|
||
LOCAL_D WORD keystat;
|
||
LOCAL_D INT gc;
|
||
LOCAL_D UWORD lines{16];
|
||
|
||
|
||
LOCAL_D TEXT *cmds[] =
|
||
{
|
||
"nNew file",
|
||
"oOpen file",
|
||
"aSave as",
|
||
"sSave",
|
||
“iInsert",
|
||
"cCopy",
|
||
"delete",
|
||
"gChange group",
|
||
"tChange type",
|
||
"bChange subentry",
|
||
"pSet preferences",
|
||
"XExit",
|
||
NULL
|
||
5
|
||
|
||
|
||
GLDEF_D TEXT ** cmds = &cmds [0];
|
||
|
||
|
||
LOCAL_D H_MENU_DATA mdata{[] =
|
||
€
|
||
"Fi le",4,
|
||
"Edit",3,
|
||
"Changes",3,
|
||
"Special",2,
|
||
NULL
|
||
3
|
||
|
||
|
||
89
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
SSS
|
||
|
||
|
||
GLDEF_D H_MENU_DATA *_mdata = &mdata(0];
|
||
|
||
|
||
LOCAL_C VOID ManageCommand(INT index)
|
||
|
||
|
||
€
|
||
switch( index)
|
||
€
|
||
case 0:
|
||
break;
|
||
case 11 :
|
||
p_exit(0);
|
||
default:
|
||
break;
|
||
>
|
||
}
|
||
|
||
|
||
LOCAL_C VOID SpecificInit (VOID)
|
||
€
|
||
_GreyLines = &lines [0];
|
||
p_bfilc&lines [0] ,sizeof(lines),0);
|
||
uAddGreyUline('o',&lines [0] );
|
||
uAddGreyULine('g' ,&l ines [0];
|
||
uAddGreyULine('t' ,&l ines [0] );
|
||
|
||
|
||
if (_UseFul lScreen)
|
||
€
|
||
uEnableGrey();
|
||
gc = gCreateGCO(CuFindMainWid());
|
||
gBorder2(W_BORDER_TYPE_1,W_BORD_CORNER_4|
|
||
W_BORD_SHADOW_ON |WBORD_SHADOW_D);
|
||
>
|
||
else
|
||
€
|
||
gc = gCreateGCO(uF indMainwWid());
|
||
gBorder(W_BORD_CORNER_4|W_BORD_SHADOW_ON|
|
||
W_BORD_SHADOW_D);
|
||
}
|
||
>
|
||
|
||
|
||
LOCAL_C VOID TryExecuteCommand(INT keycode)
|
||
€
|
||
keycode = uLocateCommand(keycode);
|
||
if (keycode >= 0)
|
||
|
||
|
||
ManageCommand( keycode);
|
||
>
|
||
LOCAL_C VOID MainLoop(VOID)
|
||
€
|
||
WMSG_KEY key;
|
||
INT ret;
|
||
FOREVER
|
||
€
|
||
uGetKeyA(&keystat, &key);
|
||
p_iowait();
|
||
if (key.keycode & W_SPECIAL_KEY)
|
||
£€
|
||
key. keycode &= (“W_SPECIAL_KEY);
|
||
if (key.keycode == 'x')
|
||
p_exit (0);
|
||
TryExecuteCommand( key. keycode);
|
||
>
|
||
else if (key. keycode == W_KEY_MENU)
|
||
€
|
||
ret = uPresentMenus();
|
||
if (ret > 0)
|
||
TryExecuteCommand( ret);
|
||
}
|
||
>
|
||
>
|
||
|
||
|
||
90
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
—_—_ eee
|
||
|
||
|
||
GLDEF_C VOID main(VOID)
|
||
€
|
||
_UseFullScreen = TRUE;
|
||
uCommoninit();
|
||
SpecificInit¢);
|
||
MainLoop();
|
||
}
|
||
|
||
|
||
Note the use of _GreyLines and the implementation of grey underlining inserted at the beginning of
|
||
SpecificInit¢). The effect is as illustrated below:
|
||
|
||
|
||
{New file =N)
|
||
fOpen file 0)
|
||
iSaveas =A
|
||
A Save =}
|
||
|
||
|
||
VOID uSetDialogUlineCINT pos, INT on);
|
||
|
||
|
||
Built in applications have the ability to add or remove a solid underline to components in a dialog. This
|
||
function allows Hwif programs to do the same.
|
||
|
||
|
||
Underlining serves to group related dialog components and can be a useful visual aid if used sparingly.
|
||
|
||
|
||
The parameter pos specifies the number of the dialog component under which a line is to be inserted or
|
||
removed. A zero value refers to the title line while a value of one refers to the immediately following
|
||
dialog component, and so on. The value of pos must lie in the inclusive range from zero to one less than
|
||
the number of lines in the dialog (including the title line), otherwise the results are unpredictable.
|
||
|
||
|
||
The parameter on specifies either a zero or a non-zero value; a non-zero value means that an underline is
|
||
to be inserted while a zero value means that any underline is to be removed.
|
||
|
||
|
||
The function is usually called before calling uRunDialog.
|
||
|
||
|
||
By taking the example given in the description of uAddGreyul ine earlier and by adding the
|
||
RunSampleDialog function and modifying the ManageCommand function as shown below, the following dialog
|
||
display results.
|
||
|
||
|
||
Sample Diatog
|
||
|
||
|
||
(RRA <Itena>
|
||
# Choice List Itemx
|
||
j‘Numeric Editor 1
|
||
|
||
|
||
| Text Item aaaagh
|
||
|
||
|
||
#define ON 1
|
||
#define OFF 0
|
||
|
||
|
||
LOCAL_C VOID ManageCommand(INT index)
|
||
{
|
||
switch¢( index)
|
||
€
|
||
case 7:
|
||
RunSampleDialog();
|
||
break;
|
||
case 11 :
|
||
p_exit(0);
|
||
default:
|
||
break;
|
||
}
|
||
|
||
|
||
91
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
_—_—_— SSS
|
||
|
||
|
||
LOCAL_C VOID RunSampleDijalog(VOID)
|
||
€
|
||
UWORD chisel = 1;
|
||
UWORD ch2sel = 1;
|
||
LONG nEditorValue = 1L;
|
||
H_DI_NUMBER nEditor;
|
||
H_DI_TEXT titem;
|
||
|
||
|
||
nEditor.value = &nEditorValue;
|
||
|
||
|
||
nEditor.low = 0;
|
||
nEditor.high = 100;
|
||
titem.str "“aaaaagh";
|
||
|
||
|
||
tltem.type = H_DTEXT_ALIGN_CENTRE;
|
||
|
||
|
||
udpenDialog("Sample Dialog");
|
||
|
||
|
||
uAddChoiceList("Choice List 1",&chtsel,"Item a","Itemb", "Item c",NULL);
|
||
uAddChoiceList("Choice List 2",&ch2sel ,"Item x","Itemy",NULL);
|
||
|
||
|
||
uAddDialogI tem(H_DIALOG_NUMBER, "NumericEditor", &nEditor);
|
||
uAddDialogItem(H_DIALOG_TEXT,"Text Item", &tItem);
|
||
|
||
|
||
uSetDialogUL ine(2,0N);
|
||
uSetDialogULine(3,0N);
|
||
|
||
|
||
uRunDialog();
|
||
>
|
||
|
||
|
||
The above illustration was produced on a Series 3a in non-compatibility mode.
|
||
|
||
|
||
Underlining in dialogs
|
||
By default, the title of a dialog is always underlined on all machines.
|
||
There are, however, the following differences in behaviour between the different machine types:
|
||
|
||
|
||
= on the Series 3a and the Workabout, in both compatibility and non-compatibility mode, any
|
||
number of dialog components can be underlined.
|
||
|
||
|
||
= on the Series 3a and the Workabout, in both compatibility and non-compatibility mode, if the
|
||
title underline is to be removed then it must be done explicitly calling usetDialogUL ine(0,0).
|
||
|
||
|
||
= on the Series 3, only one underline is permitted in a dialog; therefore, inserting an underline
|
||
under a component other than the title causes the title underline itself to be removed.
|
||
|
||
|
||
SSE a a
|
||
The auxiliary functions in the u-layer of Hwif
|
||
|
||
|
||
process
|
||
VOID uEscape(UWORD flag);
|
||
|
||
|
||
If flag is FALSE, prevents the application from being automatically terminated if the user presses
|
||
PSION +ESCAPE. Otherwise, enables this behaviour (which is the default).
|
||
|
||
|
||
For example,
|
||
|
||
|
||
LOCAL_C VOID Specificinit¢VOID)
|
||
€
|
||
uEscape( FALSE);
|
||
MainWid=uF indMainWid();
|
||
CreateGC();
|
||
hCrackCommandL ine();
|
||
Smal lScreen();
|
||
OpenEditors();
|
||
DrawBorders();
|
||
wsEnable();
|
||
>
|
||
|
||
|
||
92
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
EEE
|
||
|
||
|
||
UINT UFindMainwWid(VOID);
|
||
|
||
|
||
Returns the ID of the graphics window opened by the Console. This is required as a parameter to many
|
||
WIlib calls, such as gCreateGc and wSetWindow.
|
||
|
||
|
||
See above for an example.
|
||
|
||
|
||
VOID uForceToFront(VOID);
|
||
|
||
|
||
Of use mainly when an error has arisen that must be notified to the user, when the application might be
|
||
in background (eg processing a Shutdown message from the System Screen).
|
||
|
||
|
||
VOID uErrorString(TEXT *message);
|
||
|
||
|
||
Presents an alert consisting of the message passed, in a manner guaranteed not to fail with OOM.
|
||
While the alert is on screen, the application appears as “Busy” in the System Screen.
|
||
The application is forced into foreground (if not already there).
|
||
|
||
|
||
INT uErrorValue(INT ret);
|
||
|
||
|
||
Presents a failsafe alert, similar to that presented by uErrorstring, except that:
|
||
=" nothing happens if ret is zero |
|
||
" otherwise, the message displayed is the system error text for the error number passed as ret
|
||
® in all cases, the value ret is returned from the call itself.
|
||
|
||
This routine is more useful than might at first be thought.
|
||
|
||
For example,
|
||
|
||
|
||
LOCAL_C INT DoMerge(TEXT “pb, INT flags, INT dir)
|
||
€
|
||
UINT state;
|
||
|
||
|
||
state=DbfStateDisabled;
|
||
return(uErrorValue(DbfCopyFile(&state,dH,pb, flags, 1,dir)));
|
||
Be
|
||
|
||
|
||
or
|
||
|
||
|
||
LOCAL_C VOID ReduceScreenSize(VOID)
|
||
€
|
||
W_WINDATA wd;
|
||
|
||
|
||
wd.extent.tl.x=wd.extent.tl.y=0;
|
||
|
||
wd. extent .width=189;
|
||
|
||
wd.extent .height=80;
|
||
|
||
wSetWindow(MainWid,W_WIN_EXTENT, awd):
|
||
|
||
if CuErrorValue(wCheckPoint()))
|
||
p_exit(0);
|
||
|
||
|
||
>
|
||
|
||
|
||
VOID *uCheckHandle{VOID *handle);
|
||
If handle is zero, presents an appropriate error message. Otherwise does nothing.
|
||
|
||
|
||
In either case, returns handle.
|
||
|
||
|
||
93
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
For example (to give the source code for uBeginDCL):
|
||
|
||
|
||
GLDEF_C INT uBeginDCL(H_DI_CHOICE “*pch)
|
||
€
|
||
pch->u.count=1;
|
||
pch->menu=uCheckHandle(hChoiceOpen());
|
||
return(! CINT)pch->menu);
|
||
|
||
|
||
VOID uZTStoBCS(TEXT *bes, TEXT *zts);
|
||
|
||
|
||
Writes the length of *zts (excluding the terminating zero) to *bes and copies *zts (again excluding the
|
||
Zero) to *(bes+1).
|
||
|
||
|
||
For example, to produce some text centred in the top line of a dialog, but without the usual underline:
|
||
|
||
|
||
H_DI_TEXT txt;
|
||
TEXT buf [20];
|
||
|
||
|
||
if (uOpenDialog(NULL))
|
||
return;
|
||
|
||
uZTStoBCS(&buf [0] ,"Time is now");
|
||
|
||
txt. type=H_DTEXT_ALIGN_CENTRE;
|
||
|
||
if (uAddDialog] tem(H_DIALOG_TEXT,NULL,&txt))
|
||
return;
|
||
|
||
|
||
INT CDECL uDialogMenu(TEXT *title, TEXT *pb,...);
|
||
|
||
|
||
Presents a dialog of text items that functions as a sort of menu, for example as the first level in a Help
|
||
dialog suite.
|
||
|
||
|
||
The dialog has *titte in its title line, and then subsequent choices, determined by following parameters
|
||
pb, ..., until a NULL is encountered. The choices are each selectable.
|
||
|
||
|
||
Following the standard rules for a dialog, returns 0 if the user cancelled or a negative value if an error
|
||
occurred (such as OOM) - in which case the user will already have been notified of this fact - or else the
|
||
index of the item chosen.
|
||
|
||
|
||
For example:
|
||
|
||
|
||
choice=uDialogMenu("Help on which topic",
|
||
"Cursor position",
|
||
"Select regions",
|
||
"Drawing lines",
|
||
"Brushes",
|
||
"Using clipboards",
|
||
"Borders and frames",NULL);
|
||
switch (choice)
|
||
|
||
|
||
VOID CDECL uDisplayText(TEXT *pb,...);
|
||
|
||
|
||
Presents a dialog with no title, every line of which is left-aligned text - for example, as a subsidiary
|
||
dialog in a Help dialog suite.
|
||
|
||
|
||
Lines are added to the dialog until a NULL is encountered in the argument list.
|
||
|
||
|
||
94
|
||
|
||
|
||
—
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
__ eee
|
||
|
||
|
||
For example:
|
||
|
||
|
||
uDisplayText("To move the cursor:",
|
||
“use the usual cursor keys",
|
||
“including Home, End, PgUp and PgDn",
|
||
“or use “Goto' in the “Edit' menu.",
|
||
"Use Enter or Space to toggle the pixel",
|
||
"at the cursor position.",NULL);
|
||
|
||
|
||
SSS ee er eS
|
||
Time-text utility functions
|
||
|
||
|
||
The Hwif time-text functions provide a convenient way of generating textual representations of times
|
||
and/or dates that reflect the user's preferences as given in the Formats dialog in the Time application.
|
||
|
||
|
||
VOID *hTTOpen(VOID);
|
||
|
||
|
||
Opens a channel for use by subsequent time-text utility functions. Returns NULL on error (OOM) - in
|
||
which case the user will already have been notified - or otherwise a handle to be used in subsequent
|
||
hTTxxx calls.
|
||
|
||
|
||
See below for an example.
|
||
|
||
|
||
It is possible to have more than one time-text channel open at any one time. Two channels might differ as
|
||
regards the formats specified for them, or times set into them.
|
||
|
||
|
||
VOID hTTSetAbbreviations(VOID *handle, INT dayabb, INT monabb);
|
||
|
||
|
||
Configures the specified time-text channel so that any day names rendered by it are abbreviated to dayabb
|
||
characters, and any month names rendered are abbreviated to monabb characters.
|
||
|
||
|
||
To abbreviate (eg) day names but not month names, give monabb a value larger than any expected month
|
||
name - 40, for example.
|
||
|
||
|
||
See below for an example.
|
||
|
||
|
||
VOID hTTSetFormat(VOID *handle, INT values);
|
||
|
||
|
||
Configures the specified time-text channel so that any text rendered by it subsequently conforms to the
|
||
bits present in values as follows (all the bits affect any date strings produced, except the last, which
|
||
affects any time strings produced):
|
||
|
||
|
||
H_TIME_FORMAT_NO_DAY Omit the number of the day in the month
|
||
H_TIME_FORMAT_NO_MONTH Omit the number of the month in the year
|
||
H_TIME_FORMAT_NO_YEAR Omit the year number
|
||
H_TIME_FORMAT_MONTH_NAME Include the name of the month
|
||
H_TIME_FORMAT_SUFFIX Include a suffix after any day number
|
||
H_TIME_FORMAT_DAY_NAME Include the name of the day
|
||
H_TIME_FORMAT_NO_CENTURY Include the century in any year
|
||
H_TIME_FORMAT_NO_SECONDS Include seconds
|
||
|
||
|
||
In all cases, the sense of the bit indicates what the default is. For example, the century is given unless the
|
||
bit H_TIME FORMAT_NO_CENTURY is set, whereas no month name is given unless the bit
|
||
H_TIME_FORMAT_MONTH_NAME is set.
|
||
|
||
|
||
95
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
eee
|
||
|
||
|
||
At the same time as a call to hTTSetFormat is made, the time-text channel records the user's preferences,
|
||
as indicated via the Formats dialog in the Time application, for the following components of any textual
|
||
representation of date and time:
|
||
|
||
|
||
= whether to use 12 or 24 hour clock
|
||
= whether the day name comes before or after the month name
|
||
= what time and date separators to use.
|
||
|
||
|
||
A second call to hTTsetFormat completely wipes out the effect of any previous such call on the same
|
||
channel. (However, it has no effect on the result of a previous call to hTTSetTime Or hTTSetAbbreviations.)
|
||
|
||
|
||
See below for an example.
|
||
|
||
|
||
INT hTTSetTime(VOID *handle, INT type, VOID *data);
|
||
|
||
|
||
Sets the time and date to be represented in the next string produced from the specified time-text channel.
|
||
The time and date can be given in any of four ways, depending on the value of type passed:
|
||
H_TIME_SET_SDATE data points to a ULONG giving the time and date in system format
|
||
H_TIME_SET_DATE data points to a P_DATE representation of time and date
|
||
H_TIME_SET_DAYSEC data points to a P_DAYSEC representation of time and date
|
||
|
||
|
||
H_TIME_SET_NOW the value of data is ignored and the time and date are set from the current
|
||
system time.
|
||
|
||
|
||
Returns zero unless an illegal value was passed (which is a programming error), causing underflow or
|
||
overflow. i
|
||
|
||
|
||
See below for an example.
|
||
|
||
|
||
INT hTTSenseString(VOID *handle, INT type, TEXT *buf);
|
||
|
||
|
||
Writes a string of the requested type from the specified time-text channel into the passed buffer.
|
||
The types of string that can be requested are:
|
||
|
||
H_TIME_SENSE_TIME just write the time
|
||
|
||
H_TIME_SENSE DATE just write the date
|
||
|
||
H_TIME_SENSE_BOTH — write both the time and the date.
|
||
The application must ensure that buf points to a sufficiently long buffer to receive the text written.
|
||
|
||
|
||
No terminating zero is written; instead, the length of the string produced is returned from the
|
||
hTTSenseString call.
|
||
|
||
|
||
For example, the following code
|
||
|
||
|
||
VOID *tth;
|
||
TEXT buf [48];
|
||
|
||
|
||
ttH=hTTOpenc);
|
||
|
||
hTTSetFormat(ttH, H_TIME_FORMAT_DAY_NAME|H_TIME_FORMAT_MONTH_NAME);
|
||
hTTSetAbbreviations(tthH,3,40);
|
||
|
||
hTTSetT ime(ttH, H_TIME_SET_NOW,NULL);
|
||
|
||
buf hTTSenseString(ttH,H_TIME_SENSE_DATE, &buf [0] )j=0;
|
||
hTTClose(ttH);
|
||
|
||
|
||
would result in today's date being written as a ZTS into buf{], in the form "Wed, 15 January 1992” on
|
||
an English language Series 3 with default settings.
|
||
|
||
|
||
Note that the above routine omits to check the value of ttu after the call to hTTOpen. This would be
|
||
permissible for a call to hTTOpen during the initialisation of an application (provided its start-up heap was
|
||
properly calibrated), but (possibly) not during its steady-state phase.
|
||
|
||
|
||
96
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
eee
|
||
|
||
|
||
VOID hTTClose(VOID *handle);
|
||
|
||
|
||
Frees the resources allocated for the specified time-text channel.
|
||
|
||
|
||
It is unnecessary to make this call if the time-text channel is used only for some of the lifetime of an
|
||
application. Any application which uses a time-text channel throughout its lifetime has no need to close
|
||
the channel down prior to exiting.
|
||
|
||
|
||
See above for an example.
|
||
|
||
|
||
SELES ee]
|
||
Stand alone date/time text editor functions
|
||
|
||
|
||
These are a set of functions which construct and manipulate stand-alone date/time editors. As such, they
|
||
need not exist within a dialog. In many respects they are similar to the time-text functions but have fewer
|
||
date/time formats.
|
||
|
||
|
||
VOID *hDTOpen(H_OTEDIT *dte);
|
||
|
||
|
||
Creates a stand alone date/time text editor for use by subsequent date/time editor functions. Returns NULL
|
||
on error (OOM) - in which case the user will already have been notified. On successful completion, it
|
||
returns a handle to be used in subsequent hDTxxx calls.
|
||
|
||
|
||
A pointer to a struct of type H_DTEDIT must be supplied. This enables initialisation information to be
|
||
supplied to the function. For example, the position of the date/time text editor within a window can be
|
||
specified.
|
||
|
||
|
||
The format of H_DTEDIT is shown below.
|
||
|
||
|
||
It is possible to have more than one date/time text editor open at any one time. Two editors might differ
|
||
in their formats or the date/time(s) set into them.
|
||
|
||
|
||
VOID hDTClose(VOID *dte);
|
||
|
||
|
||
Closes the stand alone date/time text editor and frees any resources used. The handle of the editor must
|
||
be passed to this function.
|
||
|
||
|
||
VOID hDTSet(VOID *dte, H_SE_DTEDIT *sdte);
|
||
|
||
|
||
Sets a value in the date/time text editor. dte contains the handle of the text editor and the source for the
|
||
value to be set is found in a struct of type H_SE_DTEDIT pointed to by sate.
|
||
|
||
|
||
The format of struct H_SE_DTEDIT is as shown below.
|
||
|
||
|
||
VOID hDTSense(VOID *dte, H_SE_DTEDIT *sdte)
|
||
|
||
|
||
Retrieves the current information held by the date/time text editor. dte contains the handle of the text
|
||
editor and the retrieved information is placed into a struct of type H_SE_DTEDIT pointed to by sdte.
|
||
|
||
|
||
The format of struct H_SE_DTEDIT is as shown below.
|
||
|
||
|
||
INT hDTSelfCheck(VOID *dte);
|
||
|
||
|
||
The date/time text editor performs a validation of the value it currently holds and will return a non-zero
|
||
value if the check fails. The handle of the text editor is contained in dte.
|
||
|
||
|
||
97
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
INT hDTHandleKey(VOID *dte, INT keycode, INT modifier)
|
||
|
||
|
||
Delivers the specified keypress to the date/time text editor whose handle is contained in dte.
|
||
|
||
|
||
The meaning of the return value has little significance for Hwif programming (date/time editors, once
|
||
initialised, can never subsequently fail with OOM).
|
||
|
||
|
||
VOID hDTEmphasis(VOID *dte, INT flag);
|
||
|
||
|
||
Changes the emphasis for the date/time text editor. If flag is TRUE, the text editor is highlighted (and
|
||
should gain the keyboard focus). If flag is FALSE, any highlighting is removed from the text editor.
|
||
|
||
|
||
The handle of the text editor is contained in dte.
|
||
|
||
|
||
typedef struct
|
||
{
|
||
UWORD flags;
|
||
LONG value;
|
||
LONG low;
|
||
LONG high;
|
||
P_POINT pos;
|
||
UWORD win;
|
||
UWORD width;
|
||
|
||
|
||
UWORD emph:
|
||
} H_DTEDIT
|
||
|
||
|
||
Possible values for flags are:
|
||
|
||
|
||
H_DTEDIT_DDMMYYYY date/time text editor has Date format in the shape:
|
||
DD/MM/YYYY; for example: 01/01/1993
|
||
H_DTEDIT_HHMMSS date/time text editor has Time format in the shape: HH:MM:SS.
|
||
|
||
|
||
Depending on the system settings, HH can be in 24 hour or 12
|
||
hour format. If in 12 hour format then the time is followed by am
|
||
Or pm as appropriate; for example:
|
||
|
||
02:20:30 pm or 14:20:30
|
||
|
||
|
||
H_DTEDIT_HHMM date/time text editor has Time format in the shape: HH:MM.
|
||
Depending on the system settings, HH can be in 24 hour or 12
|
||
hour format. If in 12 hour format then the time is followed by am
|
||
or pm as appropriate; for example: 02:20 pm or 14:20
|
||
|
||
|
||
H_DTEDIT_HHMMSS_D date/time text editor represents a time duration in the shape
|
||
HH:MM:SS
|
||
|
||
H_DTEDIT_HHMM_D date/time text editor represents a time duration in the shape
|
||
HH:MM
|
||
|
||
H_DTEDIT_SET_VALUE If this flag is set, then the current date/time in the editor is set to
|
||
|
||
|
||
value, otherwise it is set to the default (the current date or time)
|
||
|
||
|
||
H_DTEDIT_SET_LOW If this flag is set, then the minimum date/time in the editor is set
|
||
to low, otherwise it is set to the default
|
||
|
||
|
||
H_DTEDIT_SET_HIGH If this flag is set, then the maximum date/time in the editor is set
|
||
to high, otherwise it is set to the default
|
||
|
||
|
||
98
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
|
||
|
||
typedef struct
|
||
{
|
||
UWORD flags;
|
||
LONG value;
|
||
LONG Low;
|
||
LONG high;
|
||
> H_SE_DTEDIT
|
||
|
||
|
||
Possible values for flags are the H_DTEDIT_SET_ flags explained above.
|
||
|
||
|
||
SSS Ee a ee eS ee ee ey
|
||
Edit box functions
|
||
|
||
|
||
hEBO
|
||
|
||
|
||
VOID *hEBOpen(INT flags,H_EDIT_BOX *heb);
|
||
|
||
|
||
Opens an edit box, as specified by flags and by *heb.
|
||
|
||
|
||
Returns the handle of the edit box, if successful, or else NULL (in which case the user will already have
|
||
been informed of the failure). The handle should be used to identify this edit box, as opposed to others an
|
||
application may have, in subsequent hEBxxx calls.
|
||
|
||
|
||
The _ED1T_BOx struct is defined as follows:
|
||
|
||
|
||
typedef struct
|
||
¢
|
||
UWORD maxchars;
|
||
UWORD vulen;
|
||
UWORD vislines;
|
||
P_POINT pos;
|
||
UWORD win;
|
||
UWORD font;
|
||
UWORD style;
|
||
UWORD lead_tot;
|
||
UWORD lead_top;
|
||
> H_EDIT_BOX;
|
||
|
||
|
||
It is not necessary for all the fields in this struct to be filled in before a call to hEBOpen is made. Default
|
||
values are supplied for some of the fields. These defaults are overridden by the supplied values only if
|
||
corresponding bits are set in flags.
|
||
|
||
|
||
Possible bits set in flags are as follows:
|
||
|
||
|
||
H_EDIT_BOX_CLIPBOARD The edit box is to allocate extra resources so that it can perform
|
||
the clipboard functions Paste and Copy (with deleted text of size
|
||
more than one character automatically being cut into the
|
||
clipboard, as standard for Series 3 editors)
|
||
|
||
|
||
H_EDIT_BOX_LEFT_CURSOR A triangular pointing cursor is to be displayed down the left hand
|
||
side of the edit box, opposite the line with the flashing cursor
|
||
|
||
|
||
H_EDIT_BOX_FONT The font and font style for the edit box are to be as specified in
|
||
the fields font and style in “heb (the defaults are the system font
|
||
with normal style); possible values might be w_FoNT_BASE+1 for the
|
||
bold font, and 6_sTY_ITALIc for an italic style
|
||
|
||
|
||
H_EDIT_BOX_LEADING The leading for the edit box font is to be as specified in the fields
|
||
lead_tot and lead_top in *heb (the defaults being 2 and 1
|
||
respectively): the former being the total extra vertical spacing
|
||
between lines, in addition to the font height, and the latter being
|
||
how much of the total leading applies at the top of each line.
|
||
|
||
|
||
H_EDIT_BOX_VISLINES The edit box is to be heb->vislines lines high (the default is one
|
||
line) - although in all cases, it will scroll vertically if enough text
|
||
is added to form more lines than can be seen at once.
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
ee SSSeeeSeSSSSSSSSFSFSFSSSSSSSSSSFhheseFFFFFeFeeee
|
||
|
||
|
||
The meanings of the remaining fields in the H_EDIT_Box struct, which always have to be filled in by the
|
||
caller, are as follows:
|
||
|
||
|
||
maxchars The maximum number of characters in total that the edit box can contain
|
||
(before beeping at the user and displaying a Maximum number of characters
|
||
reached information message); paragraph ends count as one character each
|
||
|
||
|
||
vulen The total visible width of the edit box, in pixels, including any margin
|
||
required for a left cursor; this width also implicitly defines the wrapping
|
||
margin for multi-line edit boxes
|
||
|
||
|
||
win The ID of the enclosing window - which is usually the value Mainwid returned
|
||
by a call to uFindMainwid
|
||
|
||
|
||
pos The offset of the top left of the edit box, relative to the enclosing window.
|
||
|
||
|
||
The edit box may be further customised, before any keys are passed on to it, by means of many of the
|
||
calls discussed below.
|
||
|
||
|
||
INT hEBHandleKey(VOID *ebH, INT keycode, INT modifier);
|
||
|
||
|
||
Delivers the specified keypress to the edit box. This should be either a printable character or an editing
|
||
key. In practice, ENTER keys should only be allowed through to multi-line editors.
|
||
|
||
|
||
Returns zero for success, or a negative value for an error (in which case the user will already have been
|
||
notified).
|
||
|
||
|
||
Formatting in background
|
||
|
||
|
||
Keys which cause a change in the location of line breaks due to word-wrap are treated slightly differently
|
||
in Hwif editors than in editors used by the built-in applications:
|
||
|
||
|
||
# in the built-in applications, only the line containing the cursor is reformatted and redrawn at
|
||
once, before the edit box checks to see if another keypress is ready to be processed; lines further
|
||
from the cursor are reformatted and redrawn, if needed, as a background activity in pauses
|
||
between the receipt of incoming keys
|
||
|
||
|
||
= in Hwif editors, any subsequent key is processed only when the edit box has been completely
|
||
reformatted and redrawn.
|
||
|
||
|
||
The difference in performance only becomes apparent for larger editors with longer paragraphs. For
|
||
programmers wishing to increase the responsiveness of their editors to incoming keys, the following lines
|
||
of code may be tried:
|
||
|
||
|
||
GLREF_D UWORD _ebControl Format;
|
||
|
||
|
||
_ebControl Format=TRUE;
|
||
|
||
|
||
In this case, Hwif editors will, for any one call to hEBHandleKey, only reformat and redraw one line
|
||
(except on receipt of a cursor key). This means it is the responsibility of the programmer to make a later
|
||
call to hEBCompleteFormat (discussed below) at a suitable moment - for example, when a call to
|
||
uKeyPressOutstanding next returns FALSE.
|
||
|
||
|
||
hE
|
||
|
||
|
||
Somplete edi
|
||
INT hEBCompleteFormat(VOID *ebH);
|
||
|
||
|
||
Ensures that the specified edit box is completely formatted and completely drawn. Does nothing if the
|
||
formatting is already up to date.
|
||
|
||
|
||
Only needs to be called explicitly by an application if the static variable _ebcontrolFormat has been set
|
||
TRUE (see above).
|
||
|
||
|
||
Returns zero for success, or a negative value if there was insufficient memory to complete formatting.
|
||
|
||
|
||
100
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
|
||
|
||
TEXT *hEBSenseText(VOID *ebH);
|
||
|
||
Returns a pointer to the buffer where the edit box is currently keeping its own copy of its text.
|
||
This copy is always zero terminated, so its length can be obtained by a call to p_sten.
|
||
|
||
The buffer may contain embedded \n's, representing paragraph ends.
|
||
|
||
|
||
Note that the location of the buffer may change as more text is added into the edit box, so there is no
|
||
point in an application trying to keep a permanent copy of this address.
|
||
|
||
|
||
INT hEBSetText(VOID *ebH, TEXT *pb, INT blen);
|
||
|
||
|
||
Sets the blen characters at *pb as the text for the specified edit box.
|
||
|
||
|
||
Returns zero for success, or a negative value if an error occurred (in which case the user will already
|
||
have been notified).
|
||
|
||
|
||
VOID hEBEmphasise(VOID *ebH, INT flag);
|
||
|
||
|
||
Either emphasises or de-emphasises the specified edit box, depending on the value of flag (TRUE to
|
||
emphasise it, FALSE to de-emphasise it).
|
||
|
||
|
||
An emphasised edit box displays:
|
||
® a flashing text cursor (unless the width of the text cursor has been set to ZeTO)
|
||
= a triangular cursor in the left margin (if the flag #_EDIT_BOX_LEFT_CURSOR was set on initialisation)
|
||
= a highlight between the cursor and anchor points of any select region.
|
||
|
||
A de-emphasised edit box displays none of these features.
|
||
|
||
By default, an edit box is de-emphasised.
|
||
|
||
|
||
Applications may wish to surround edit boxes with curved borders, with varying degrees of shadowing to
|
||
help indicate whether or not each edit box is currently emphasised. In this case, the application has the
|
||
responsibility for drawing the borders (using the Wlib call gBorderkRect).
|
||
|
||
|
||
When edit boxes lose their cursor
|
||
|
||
|
||
Note that edit boxes maintain their own record of whether they are emphasised, and do nothing if they
|
||
|
||
|
||
receive an hEBEmphasise Call instructing them to change their emphasis state to what it already is. Thus in
|
||
the following sequence of code
|
||
|
||
|
||
hEBEmphasise(ebH, TRUE);
|
||
hEBEmphasi se(ebH, TRUE);
|
||
|
||
|
||
the later hEBEmphasise call is ignored, unless a call hEBEmphasise(ebH, FALSE) has been made in the
|
||
meantime.
|
||
|
||
|
||
The significance of this is as follows: suppose that, in the meantime, a flashing text cursor is drawn
|
||
elsewhere on the screen by the application. This may be as a result of an explicit call to worawTextCursor;
|
||
more likely, it will be as a side effect of a call to uRunDialog or hPrintSetupDialog. In this case, the text
|
||
cursor will be removed from the edit box - since there can only be one text cursor per application at any
|
||
one time. When the intervening text cursor is cancelled - say as the result of the termination of the dialog
|
||
- it is the responsibility of the application to re-activate the flashing cursor where it used to be (if that is
|
||
still appropriate). However, in the light of what has just been explained, a simple call to hEBEmphasise
|
||
will be insufficient to effect this.
|
||
|
||
|
||
Accordingly, applications which contain an edit box as part of their main display, and which invoke
|
||
dialogs with items which can also display a flashing cursor, need to use a layer of the following sort
|
||
around calls to uRunDialog:
|
||
|
||
|
||
101
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
LOCAL_C INT RunDialog(VOID)
|
||
£
|
||
INT ret;
|
||
|
||
|
||
hEBEmphasise( edit femph] , FALSE);
|
||
ret=uRunmDialog();
|
||
hEBEmphasise(edit [emph] , TRUE);
|
||
return(ret);
|
||
|
||
3
|
||
|
||
|
||
A similar protective layer is needed around any calls to hPrintSetupDialog.
|
||
|
||
|
||
INT hEBSetSelect(VOID *ebH, INT aoff,INT coff);
|
||
|
||
|
||
Sets the anchor point and cursor point of the specified edit box. Both positions are given as character
|
||
offsets into the content of the edit box, starting at 0 for the position in front of the first character.
|
||
|
||
|
||
Note that neither the anchor point nor the cursor point is permitted to come after the last character in the
|
||
edit box.
|
||
|
||
|
||
To set the cursor position without setting any highlighted select region, pass the value of aoff to be equal
|
||
to that of coff.
|
||
|
||
|
||
Returns zero for success or a negative error value (in which case the user will already have been
|
||
notified).
|
||
|
||
|
||
INT hEBSenseSelect(VOID *ebH,UWORD *top);
|
||
|
||
|
||
Returns the length of the select region of the specified edit box, and writes the character offset of the top
|
||
of the select region to *top.
|
||
|
||
|
||
If there is no select region, the value 0 is returned, and the character offset of the cursor point is written
|
||
to’ *top.
|
||
|
||
|
||
TEXT *hEBSenseClipText(VOID *ebH);
|
||
|
||
|
||
Returns a pointer to the buffer where the clipboard of the edit box is currently keeping its own copy of
|
||
its text.
|
||
|
||
|
||
The form of this buffer is exactly the same as the buffer used for the main text of the edit box (see the
|
||
discussion on hEBSenseText above).
|
||
|
||
|
||
INT hEBSetClipText(VOID *ebH, TEXT “pb, INT blen);
|
||
|
||
|
||
Sets the blen characters at *pb as the text for the clipboard of the specified edit box.
|
||
|
||
|
||
Returns zero for success, or a negative value if an error occurred (in which case the user will already
|
||
have been notified).
|
||
|
||
|
||
INT hEBChangeWidth(VOID *ebH, INT width);
|
||
|
||
|
||
Changes the width of the specified edit box to width. The new width is specified in pixels and includes an
|
||
allowance for any left margin required to display a left triangular cursor - exactly as for the vulen field of
|
||
the 4_EDIT_BOx struct used to initialise the edit box.
|
||
|
||
|
||
In the case of a multi-line editor, the text is automatically re-formatted, wrapping to the new width. In all
|
||
cases, the display is scrolled (vertically and/or horizontally) to expose the cursor position.
|
||
|
||
|
||
Returns zero for success, or a negative value if an error occurred (in which case the user will already
|
||
have been notified).
|
||
|
||
|
||
102
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
See
|
||
|
||
|
||
Even if the return value is negative (indicating a failure to re-format the edit box to its new width), the
|
||
record within the edit box of its width will be updated as requested.
|
||
|
||
|
||
VOID hEBSetCWidth(VOID *ebH, INT cwidth);
|
||
Changes the width of any flashing cursor displayed. The value of cwidth is in pixels.
|
||
By default, the flashing cursor is two pixels wide.
|
||
|
||
|
||
Passing cwidth as zero makes the flashing cursor invisible. This may be appropriate when, for example,
|
||
highlighting some found text by means of the call heBsetSelect.
|
||
|
||
|
||
INT hEBInsert(VOID *ebH, TEXT *pb, INT blen);
|
||
|
||
|
||
Inserts the blen characters at *pb into the edit box at the cursor position. Any select region is cancelled
|
||
first. The cursor is positioned afterwards to the end of the inserted text.
|
||
|
||
|
||
Returns zero for success, or a negative value if an error occurred (in which case the user will already
|
||
have been notified).
|
||
|
||
|
||
Deletes any highlighted selection, into the clipboard if the edit box has one, and then inserts the contents
|
||
of the ZTS *replace at the cursor position. The cursor is finally positioned at the end of the text inserted,
|
||
unless backwards is TRUE, in which case it is placed at the beginning of the selected text.
|
||
|
||
|
||
Returns zero for success, or a negative value if an error occurred (in which case the user will already
|
||
have been notified).
|
||
|
||
|
||
The routine was originally designed with the functionality of a Replace command in mind. See also the
|
||
section below on hEBFind.
|
||
|
||
|
||
INT hEBEvaluate(VOID *ebH);
|
||
Attempts to perform the standard Evaluate function on the specified edit box.
|
||
|
||
|
||
Retums zero for success, or a negative value if an error occurred (in which case the user will already
|
||
have been notified).
|
||
|
||
|
||
Typical contents of the Evaluate routine called from the ManageCommand routine of an application would
|
||
simply be as follows:
|
||
|
||
|
||
if (!CheckEditing()) /* check focus is positioned suitably */
|
||
hEBEvaluate(ebH); /* ignore any error */
|
||
|
||
|
||
INT hEBCopy(VOID *ebH);
|
||
|
||
|
||
Attempts to perform the standard Copy function on the specified edit box.
|
||
|
||
|
||
Retums zero for success, or a negative value if an error occurred (in which case the user will already
|
||
have been notified).
|
||
|
||
|
||
But if there is no select region (and hence nothing to copy into the clipboard), the special value 1 is
|
||
returned.
|
||
|
||
|
||
Typical contents of the Copy Text routine called from the ManageCommand routine of an application would
|
||
accordingly be as follows:
|
||
|
||
|
||
103
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
if (!CheckEditing())
|
||
{
|
||
if (hEBCopy(ebH)>0)
|
||
wWInfoMsg("No text to copy");
|
||
else
|
||
wInfoMsg("Text copied");
|
||
}
|
||
|
||
|
||
INT hEBPaste(VOID *ebH);
|
||
|
||
|
||
Attempts to perform the standard Paste function on the specified edit box.
|
||
|
||
|
||
Returns zero for success, or a negative value if an error occurred (in which case the user will already
|
||
have been notified).
|
||
|
||
|
||
But if the clipboard is empty (and hence there is nothing to paste), the special value 1 is returned.
|
||
|
||
|
||
Typical contents of the Paste routine called from the ManageCommand routine of an application would
|
||
accordingly be as follows:
|
||
|
||
|
||
if (!CheckEditing())
|
||
{
|
||
if (hEBPaste(ebH)>0)
|
||
wInfoMsg("No text to insert");
|
||
|
||
|
||
INT hEBFind(VOID *ebH, TEXT *str,INT flags);
|
||
|
||
|
||
Attempts to find a copy of the ZTS *str in the contents of the specified edit box. If successful, returns
|
||
TRUE and automatically creates a highlighted selection over the copy found. Otherwise returns FALSE
|
||
(except if an error occurred, in which case the return value is negative, and the user will already have
|
||
been notified).
|
||
|
||
|
||
The following bits in flags determine how the search is done:
|
||
|
||
|
||
HEB_FIND_BACKWARDS Search backwards from the cursor position (the default is to search forwards
|
||
from the cursor position)
|
||
|
||
|
||
HEB_FIND_CASESENS _ The search is case sensitive (the default is for a case insensitive search).
|
||
|
||
|
||
VOID hEBClearChanged(VOID *ebH);
|
||
|
||
|
||
Clears the internal "changed" flag of the specified edit box.
|
||
This flag is clear when the edit box is first initialised.
|
||
|
||
|
||
This flag is set whenever the contents of the edit box change as a result of any of the calls hEBHandlekey,
|
||
hEBInsert, hEBEvaluate, hEBPaste, Or hEBReplace.
|
||
|
||
|
||
Typically, an application might call hEBClearchanged following calls to hEBSetText or hEBSenseText.
|
||
|
||
|
||
INT hEBSenseChanged(VOID *ebH);
|
||
Returns the "changed" flag of the specified edit box. See above for some further discussion.
|
||
|
||
|
||
INT hEBShowSymbols(VOID *ebH, INT flag);
|
||
|
||
|
||
Shows or hides end of paragraph symbols and visible space markers, depending on the value of flag
|
||
(TRUE to show them, FALSE to hide them).
|
||
|
||
|
||
104
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
———— eee
|
||
|
||
|
||
These symbols are hidden by default.
|
||
|
||
|
||
Returns zero for success, or a negative value if an error occurred (in which case the user will already
|
||
have been notified).
|
||
|
||
|
||
Even if the return value is negative (indicating a failure to re-format the edit box), the record within the
|
||
edit box of whether to show these symbols will be updated as requested.
|
||
|
||
|
||
VOID hEBClose(VOID *ebH);
|
||
|
||
|
||
Frees the resources allocated for the specified edit box.
|
||
|
||
|
||
Any application which uses an edit box throughout its lifetime has no need to close the edit box prior to
|
||
exiting as any resources used will automatically be freed when the application terminates. However, it
|
||
may be sensible to close an edit box explicitly if it is only used for a short period during the lifetime of
|
||
the application. This avoids resources being tied up unnecessarily.
|
||
|
||
|
||
VOID *hEBSenseDoc(VOID *ebH);
|
||
|
||
|
||
This function returns the handle of the document component of an edit box allowing it to be manipulated
|
||
by other Hwif functions.
|
||
|
||
|
||
In some circumstances, the manipulation of the document component rather than the whole edit box can
|
||
significantly reduce overhead (see hEDCapacity, hEDInsert, hEBDocChanged).
|
||
|
||
|
||
The parameter ebh must contain the handle of the opened edit box whose document component is
|
||
required.
|
||
|
||
|
||
INT hEDCapacity(VOID *doc,UINT maxlen);
|
||
|
||
|
||
This function sets the capacity of the document component of an edit box. In other words, it specifies the
|
||
maximum size of the text that the edit box can hold.
|
||
|
||
|
||
The parameter doc must contain the handle of the document component of the edit box as returned from a
|
||
call to hEBSenseDoc. The maximum size of the text is specified in parameter maxlen.
|
||
|
||
|
||
The function returns zero if successful or a negative value otherwise. If an error occurs, the user will
|
||
already have been notified.
|
||
|
||
|
||
INT hEDInsert(VOID *doc,UINT pos, VOID *buf,UINT len);
|
||
|
||
|
||
This function inserts text into the document component of an edit box.
|
||
|
||
|
||
The parameter doc must contain the handle of the document component of the edit box as returned from a
|
||
call to hEBSenseDoc.
|
||
|
||
|
||
The text to be inserted is located at buf and is ten bytes long. The text is inserted at offset pos within the
|
||
document component.
|
||
|
||
|
||
The function returns zero if successful or a negative value otherwise. If an error occurs, the user will
|
||
already have been notified.
|
||
|
||
|
||
hEB
|
||
|
||
|
||
INT hEBDocChanged(VOID *ebh);
|
||
|
||
|
||
Notifies the edit box that the content of its document component has changed. This causes the text to be
|
||
re-formatted.
|
||
|
||
|
||
The parameter ebh must contain the handle of the edit box to be notified.
|
||
|
||
|
||
The function returns zero if successful or a negative value otherwise. If an error occurs, the user will
|
||
already have been notified.
|
||
|
||
|
||
105
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
Note that no attempt is made to validate the cursor position. It is the programmer's responsibility to set
|
||
this correctly.
|
||
|
||
|
||
INT hEBSetMargin(VOID *ebh,UINT right);
|
||
|
||
|
||
This function allows the right hand word-wrap margin of an edit box to be set. This value, in effect, sets
|
||
a limit on the amount of text that can be displayed on one line before being wrapped around onto the next
|
||
dine.
|
||
|
||
|
||
The parameter ebh must contain the handle of the edit box whose margin is to be set. The margin itself is
|
||
defined by the value in the parameter right; this value is measured in pixels.
|
||
|
||
|
||
Setting right to a large value such as 4096, effectively turns off word-wrap. In fact this is the only
|
||
sensible use of this function. If there were a need to set a margin smaller than the width of the edit box
|
||
then it would be easier to use a smaller edit box.
|
||
|
||
|
||
The following code fragment suggests how it might be used to turn off word-wrap:
|
||
|
||
|
||
H_EDIT_BOX heb;
|
||
VOID * ebh;
|
||
|
||
|
||
ebh = hEBOpen(H_EDIT_BOX_VISLINES|H_EDIT_BOX_LEFT_CURSOR, &heb);
|
||
hEBSetMargin(ebh, 4096);
|
||
|
||
|
||
The function returns zero if successful or a negative value otherwise. If an error occurs, the user will
|
||
already have been notified.
|
||
|
||
|
||
This function senses and returns the current value of the right hand word-wrap margin of an edit box
|
||
whose handle is passed in ebh.
|
||
|
||
|
||
UINT hEBPosToXL(VOID *ebh,H_SCRLAY_PLX *pLx);
|
||
|
||
|
||
This function converts a character position, within the text of the edit box whose handle is passed in ebh,
|
||
to a position on the screen.
|
||
|
||
|
||
The character position is passed in the pos member of the H_SCRLAY_PLX struct pointed to by plx. This
|
||
struct is defined in Awif.h as:
|
||
|
||
|
||
typedef struct
|
||
|
||
|
||
> H_SCRLAY_PLX;
|
||
|
||
|
||
If the character position is visible on the screen, the line number and horizontal pixel offset within the
|
||
line are written to plx->line and plx->x respectively and the function returns zero.
|
||
|
||
|
||
If the character position is above the screen, a value of -30000 is written to plx->line and the function
|
||
returns -1.
|
||
|
||
|
||
If the character position is below the screen or beyond the end of the text, a value of +30000 is written
|
||
to plx->line and the function returns +1.
|
||
|
||
|
||
106
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
|
||
|
||
in ee ee i er aes ee ee
|
||
Printing and print support functions
|
||
|
||
|
||
VOID hPrintSetupDialog(VOID);
|
||
This is NOT to be confused with the function hPrinterSetupDialog described later.
|
||
It presents the standard Print Setup dialog, waiting until it is complete.
|
||
|
||
|
||
The Epoc static DatLocked is set to TRUE for the duration of the call to hPrintsetupDialog.
|
||
|
||
|
||
As for the Print Setup dialogs in the built-in applications, the dialog sometimes allows the user to make
|
||
choices that the printer eventually chosen cannot deliver. For example, some style combinations (Bold
|
||
and italic) may not be supported in some fonts (in such a case, the text will probably come out either as
|
||
bold or as italic). Again, not all printers support landscape orientation.
|
||
|
||
|
||
VOID hPrinterSetupDialog(VOID);
|
||
|
||
|
||
This is NOT to be confused with the function hPrintSetupDialog described earlier.
|
||
|
||
|
||
It presents the standard Printer Configuration Setup dialog, waiting until it is complete.
|
||
The Epoc static DatLocked is set to TRUE for the duration of the call to hPrinterSetupDialog.
|
||
|
||
|
||
The Printer Configuration Setup dialog behaves in exactly the same way as for the built-in applications in
|
||
that it requests printer device information and provides an entry into the print preview settings dialog.
|
||
|
||
|
||
VOID hPrint(INT PrintLineCH_PRINT *));
|
||
|
||
|
||
Prints from the application, according to parameters specified by the user in any Print Setup dialog.
|
||
|
||
|
||
The callback function PrintLine is repeatedly called by system code, as printing progresses, until printing
|
||
terminates. Each time the function is called, the application has to return either TRUE or FALSE:
|
||
|
||
|
||
= areturn value of TRUE indicates that more data is being passed to print; this data is written into
|
||
the fields of the H_PRINT struct passed
|
||
|
||
|
||
= areturn value of FALSE indicates that the application has no more data to print.
|
||
The _PRINT struct is defined as follows:
|
||
|
||
|
||
typedef struct
|
||
|
||
|
||
WORD flags;
|
||
WORD typf;
|
||
WORD fheight;
|
||
WORD style;
|
||
WORD down;
|
||
WORD indent;
|
||
WORD height;
|
||
WORD right;
|
||
TEXT *buf;
|
||
UWORD blen;
|
||
} H_PRINT;
|
||
|
||
|
||
Most of the fields of this struct will have already been set to suitable values before printLine is called.
|
||
All but the most ambitious of Hwif application writers should be content to write to, at most, the
|
||
following fields:
|
||
|
||
|
||
blen This must be set if the bit H_PRINT_TEXT is set in flags (as it is by default). It
|
||
gives the number of characters to be printed.
|
||
|
||
|
||
107
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
— SSS
|
||
|
||
|
||
buf This must be set if blen is non-zero (and H_PRINT_TEXT is set in flags). It gives
|
||
the address of a contiguous buffer holding the blen characters to be printed.
|
||
Note that the buffer must be permanent (as opposed to being declared on the
|
||
stack of the routine PrintLine).
|
||
|
||
|
||
indent This (zero by default) specifies the additional amount to indent the print
|
||
position by, horizontally, prior to the specified text being printed. Any value
|
||
given must be in printer units (see below).
|
||
|
||
|
||
flags The bit H_PRINT_KEEP may be ORed in, to request that, if possible, this line of
|
||
text be kept together on the same page with the following line; the bit
|
||
H_PRINT_PAGE may be ORed in to force the emission of a form feed prior to the
|
||
line being printed.
|
||
|
||
|
||
style Any of the bits H_PRINT_STY_UNDERLINE, H_PRINT_STY_BOLD, H_PRINT_STY_ITALIC,
|
||
H_PRINT_STY_SUPER, and H_PRINT_STY_SUB may be ORed in, to further embellish
|
||
the font chosen by the user, in the Print Setup dialog, as the default font.
|
||
|
||
|
||
Note that in both the last two cases, it is crucial to or in the bits required, rather than simply setting them
|
||
with an assignment statement. Note also that in the case of styte, there is no guarantee that just because a
|
||
particular font style is set, the current printer will be able to fulfil the request made on it.
|
||
|
||
|
||
Word wrapping during printing
|
||
|
||
|
||
Before any text is printed, ROM resident printing code checks that it will fit in the width available to it.
|
||
If not, word wrap is performed, with any excess being printed on the subsequent line instead. This
|
||
subsequent line is printed without any additional call to the printLine function. That is, more than one
|
||
line may be printed as a consequence of any one call to PrintLine.
|
||
|
||
|
||
The word-wrap calculation performed makes the following assumptions:
|
||
|
||
|
||
= the text is to fit into the full width of the page, minus its left and right margins, and minus any
|
||
indent specified j
|
||
|
||
|
||
= — the text is to be printed in the font and style specified by the user in the Print Setup dialog.
|
||
|
||
|
||
Some fonts may change their width if (for example) they are bolded or italicised; if the application ors
|
||
any such bit into style, there is, accordingly, a risk that the word-wrap calculation will be incorrect.
|
||
(Similarly - but even more so - if the application writes into the right field of the H_PRINT struct, or if the
|
||
H_PRINT_LINE bit is removed from flags. See below for a discussion of these possibilities.)
|
||
|
||
|
||
If word-wrap is required, the H_PRINT_KEEP bit is set into flags provided the user has not set the Allow
|
||
widows/orphans choice list in the Print Setup dialog suite to "yes".
|
||
Page breaks during printing
|
||
|
||
|
||
Page breaks are automatically calculated by ROM resident layout software, and do not have to be
|
||
inserted by application code.
|
||
|
||
|
||
However, as noted above, it is possible for the application to force a given piece of text to appear at the
|
||
top of a new page.
|
||
|
||
Limitations during the PrintLine callback
|
||
|
||
The application is actually in a somewhat vulnerable state during a printLine callback:
|
||
|
||
|
||
# Only a limited amount of the Hwif system services are available to it in this state; in particular,
|
||
no call can be made to uRunDialog, uPresentMenus, hPrintSetupDialog, hPrinterSetupDialog or
|
||
(recursively) hPrint - on pain of indeterminate damage resulting
|
||
|
||
|
||
= Only a limited amount of time should be spent inside each call to printLine; if an application
|
||
remains in PrintLine indefinitely, and the application is tasked into background and then into
|
||
foreground again in the meantime, the Printing dialog in the foreground will not be redrawn
|
||
properly, and its Escape action button will not be effective.
|
||
|
||
|
||
The Epoc static DatLocked is set TRUE for the duration of the call to hprint.
|
||
|
||
|
||
108
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
eee
|
||
|
||
|
||
VOID hPrintSetSI(UINT subsqind);
|
||
|
||
|
||
Sets the indent to be used for the second and following lines of any wrapped block of text. The value
|
||
given must be in printer units (see below).
|
||
|
||
|
||
The subsequent indent defaults to zero. But once it is set, by one PrintLine call, it retains its value during
|
||
subsequent PrintLine calls (unless it is changed again).
|
||
|
||
|
||
INT hPrintSensePageWidth(VOID);
|
||
|
||
|
||
Returns the width of the page, minus its left and right margins, in current printer units.
|
||
|
||
|
||
INT hPrintSenseBufWidth(TEXT *buf, INT blen);
|
||
|
||
|
||
Returns the width of the passed buffer of text, in current printer units. The width is worked out in the
|
||
default font and style specified by the user in the Print Setup dialog.
|
||
|
||
|
||
The result may be of use in calculating indents for lines. For example, it allows the printing of centred
|
||
text.
|
||
|
||
|
||
Advanced possibilities when printing
|
||
By default, the 1_PRINT_LINE bit is always set in flags. This has the following effect:
|
||
|
||
|
||
= before printing any text, the print position is moved down by an amount equal to the sum of
|
||
height (equal by default to the height of the default font) and down (zero by default), except that
|
||
down is ignored for the first line on a page
|
||
|
||
|
||
= — the print position is moved back to the left margin, and then in by indent.
|
||
|
||
|
||
None of these things happen if the #_PRINT_LINE bit is missing. Printing just continues from where it left
|
||
off the previous time.
|
||
|
||
|
||
In order to print in columns, it is possible to proceed as follows:
|
||
= print the first column as per normal
|
||
|
||
|
||
= the next time PrintLine is called, clear the H_PRINT_LINE and 4_PRINT_TEXT flags that are set by
|
||
default; instead, set the H_PRINT_RIGHT flag and supply a suitable value of right
|
||
|
||
|
||
= following that, keep the H_PRINT_LINE bit clear, but pass the text corresponding to the second
|
||
column
|
||
|
||
|
||
= repeat for any additional columns.
|
||
|
||
|
||
The value specified for right has, again, to be in printer units. It can be calculated from the result of a
|
||
call to hPrintSenseBufWidth.
|
||
|
||
|
||
Inevitably, there are limitations with this approach. For greater control over printing, it is necessary to
|
||
interact more directly with the object classes in the Series 3 ROM.
|
||
|
||
|
||
ea ee ee ee ee ee ee
|
||
Miscellaneous functions
|
||
|
||
|
||
INT hCrackCommandL ine(VOID);
|
||
|
||
|
||
Reads the command line and sets up appropriate initial values of various reserved statics, including
|
||
DatUsedPathNamePtr (the full path name of any file to open or create).
|
||
|
||
|
||
The return value has significance for file-based applications:
|
||
‘O' the specified file already exists, and is to be opened
|
||
|
||
|
||
109
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
4or a file of the specified name is to be created and opened anew, with any existing file of that
|
||
name to be overwritten
|
||
|
||
|
||
0 the command line is not present (for example, the application may have been run from a
|
||
source other than the System Screen).
|
||
|
||
|
||
For example:
|
||
|
||
|
||
LOCAL_C VOID SpecificInit(VOID)
|
||
€
|
||
INT command;
|
||
INT bid;
|
||
VOID *fcb;
|
||
|
||
|
||
command=hCrackCommandL ine();
|
||
bid=ObeySystemCommand( command, DatUsedPathNamePtr ,&fcb);
|
||
|
||
|
||
VOID hSetUpStatusNames(TEXT *pb);
|
||
|
||
|
||
Changes the value of DatUsedPathNamePtr to pb and makes other required associated changes in reserved
|
||
Statics.
|
||
|
||
|
||
For example:
|
||
|
||
|
||
LOCAL_C VOID ChangeName(TEXT *newname)
|
||
€
|
||
p_scpy(&fi Lename[0] ,newname);
|
||
hSetUpStatusNames (&f i lename [0] );
|
||
wsUpdate(WS_UPDATE_NAME);
|
||
>
|
||
|
||
|
||
Note that *pb must be a fully parsed filename (such as is returned by a file selector item in a dialog).
|
||
Further, the buffer *pb must be a permanent one (as opposed to being defined on the stack of a routine
|
||
such as ChangeNames).
|
||
|
||
|
||
VOID hEnsurePath(TEXT *fname);
|
||
|
||
|
||
Ensures that the path of the specified filename exists.
|
||
Should generally be called following a New file or Save as menu command.
|
||
For example:
|
||
|
||
|
||
if (RunDialog())
|
||
|
||
|
||
€ /* Save As dialog successfully completed */
|
||
savebuf [1+savebuf [0]]=0; /* BCS to ZTS conversion */
|
||
hEnsurePath(&savebuf [1] };
|
||
|
||
DoSave(&savebuf [1] );
|
||
|
||
winfoMsg("Saved");
|
||
|
||
3
|
||
|
||
|
||
VOID hDlgPositionCINT x,INT y);
|
||
Affects the position in which the current dialog will appear.
|
||
|
||
|
||
If x is negative, the dialog will appear on the left edge of the screen; if positive, on the right edge; if
|
||
zero, centred horizontally.
|
||
|
||
|
||
If y is negative, the dialog will appear on the top edge of the screen; if positive, on the bottom edge; if
|
||
zero, centred vertically.
|
||
|
||
|
||
Thus in all there are 9 possible locations for the dialog.
|
||
|
||
|
||
110
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
__ SSSSSSSSSSSSSSSSSSSSSFsFeFeFeFeFeseseFeFesesesSse
|
||
|
||
|
||
In the absence of this call being made for a dialog, it is positioned in the centre of the screen, just as if
|
||
the call
|
||
|
||
|
||
hDigPosition(0,0);
|
||
had been made.
|
||
|
||
|
||
ring |
|
||
|
||
|
||
INT hDTMFString(TEXT *zts);
|
||
|
||
|
||
Emits DTMF tones for the passed string.
|
||
|
||
|
||
Uses the tone lengths and pauses as specified by the user in the World application (or otherwise),
|
||
reverting to system defaults in the absence of any such setting.
|
||
|
||
|
||
Returns zero for success or a negative error if the sound system was unavailable (on account of being
|
||
hogged by another application). The call embodies a double retry before failing.
|
||
|
||
|
||
The call waits for the tones to be emitted before returning.
|
||
For example:
|
||
|
||
|
||
if ChDTMFString("123"))
|
||
wInfoMsg("Sound system busy");
|
||
|
||
|
||
INT hIsDbfCompressible(VOID *dH);
|
||
|
||
|
||
Returns TRUE if the database file open on database channel di is compressible (ie if it is on any medium
|
||
other than Flash), and FALSE otherwise.
|
||
|
||
|
||
For example,
|
||
|
||
|
||
LOCAL_C VOID CompressFile(VOID)
|
||
{
|
||
UINT state;
|
||
|
||
|
||
if ¢(!hIsDbfCompressible(dH))
|
||
wInfoMsg("Cannot compress on Flash"):
|
||
else
|
||
€
|
||
state=DbfStateDisabled;
|
||
Check(DbfCompress(&state,dH));
|
||
winfoMsg("File compressed");
|
||
|
||
|
||
VOID hHelpSubSystemC(INT startid, INT indexid);
|
||
|
||
|
||
This function allows the developer to access the same Help engine as used by the inbuilt applications on
|
||
the Series 3.
|
||
|
||
|
||
Like uPresentMenus and uRunDialog, hHelpSubSystem only returns when the entire operation (in this case,
|
||
the Help operation) has been completed by the user. It does its own error handling internally,
|
||
automatically presenting suitable error messages where necessary.
|
||
|
||
|
||
It is worth noting that other events cannot be notified when inside this call; messages from the system
|
||
screen are ignored and the expiry of timers is effectively delayed until the call completes.
|
||
|
||
|
||
The two parameters are the IDs of suitable resources in an application resource file in which the
|
||
hierarchy of Help text is defined:
|
||
|
||
|
||
= The first is the resource ID of the "top-level" Help resource in the resource file.
|
||
= The second is the resource ID of the "index" set of Help resources.
|
||
|
||
|
||
For further general information on resource files, see the Additional System Information manual.
|
||
|
||
|
||
111
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
The following "structures" are used in building Help resources. For further information and examples on
|
||
the use of these structures in building a hierarchy of Help text, see the Introduction To HWIF chapter in
|
||
this manual.
|
||
|
||
|
||
STRUCT HELP_ARRAY
|
||
{
|
||
LINK topic_id;
|
||
TEXT topic;
|
||
LEN BYTE STRUCT strist{[];
|
||
>
|
||
|
||
|
||
where any instances of the strist fields must always be as STRING
|
||
|
||
|
||
STRUCT STRING
|
||
€
|
||
TEXT str;
|
||
>
|
||
|
||
|
||
STRUCT TOPIC_ARRAY
|
||
{
|
||
LEN BYTE LINK id lst]
|
||
}
|
||
|
||
|
||
VOID hDeclareAppRcb(VOID *rcb);
|
||
|
||
|
||
Before an application resource file can be used (e.g. to invoke Help), a channel to the file must be opened
|
||
and its handle passed to the system.
|
||
|
||
|
||
This function performs the action of passing the handle of an (already) opened application resource file
|
||
channel to the system via the rcb parameter.
|
||
|
||
|
||
It is called from the function hInitAppReb, described later, which opens an application's built in resource
|
||
file.
|
||
|
||
|
||
VOID *hInitAppReb(VOID);
|
||
|
||
|
||
This function opens a channel to an application's built in resource file and returns its handle. The handle
|
||
itself is passed to the system using the function hDeclareAppkeb, described earlier.
|
||
|
||
|
||
In general, this function allows the application's built in resource file to be accessed; the handle itself is
|
||
used explicitly by such functions as hRequestReplacePack described later.
|
||
|
||
|
||
In actual fact the function creates and initialises a resource file object. However, for those unfamiliar
|
||
with Object Oriented Programming, it is easier to think in terms of opening a channel.
|
||
|
||
|
||
The function is implemented as shown below. Note again that it uses hDeclareAppgcb described earlier.
|
||
|
||
|
||
GLDEF_C VOID *hInitAppRcb(VOID)
|
||
|
||
|
||
€ /* create and initialise resource file object */
|
||
INT ret;
|
||
VOID *rcb; /* resource file object handle wf
|
||
|
||
|
||
rcb = p_new(1,C_RSCFILE);
|
||
ret = p_entersend3(rcb,O_RS_INIT,DatCommandPtr); /* pass file name */
|
||
if (ret < 0) /* no resource file found */
|
||
|
||
p_exit(ret); /* fatal (programmer) error*/
|
||
hDeclareAppRcb(rcb);
|
||
>
|
||
|
||
|
||
112
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
SS SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSeSe
|
||
|
||
|
||
The implementation assumes that the application resource file is built into the .app file following
|
||
standard conventions.
|
||
|
||
|
||
If a resource file is to be used which is separate from the application, then the above code could be used
|
||
but the reference to DatCommandPtr would need to be changed. In general the third parameter to the
|
||
p_entersend3 function in the above code should contain a pointer to the resource file name.
|
||
|
||
|
||
VOID hRequestReplacePack(VOID *rcb, TEXT *fname)
|
||
|
||
|
||
This function is normally used when a channel to an application resource file (with handle reb) has
|
||
previously been opened but is now found to be unavailable. This is most commonly caused by the
|
||
removal of the pack on which the resource file is located.
|
||
|
||
|
||
The function issues a warning message to the user which PERSISTS until the appropriate resource file, as
|
||
specified by fname, has been loaded and found.
|
||
|
||
|
||
fname Must point to a buffer of at least p_FNAMESIZE characters.
|
||
|
||
|
||
The following code fragment illustrates the use of this function. It makes use of the rscfile class; this is
|
||
documented in the resource files chapter in the additional system information manual.
|
||
|
||
|
||
Also note that the function InitReb is, in essence, the same code that implements the utility function
|
||
hInitAppReb, described earlier.
|
||
|
||
|
||
It simply displays an information message where the text is taken from the resource file whose name is
|
||
contained in fname.
|
||
|
||
|
||
GLREF_D VOID *rcb:
|
||
GLREF_D TEXT fname [P_FNAMESIZE] ;
|
||
|
||
|
||
LOCAL_C VOID InitRcb(VOID)
|
||
{
|
||
INT ret;
|
||
|
||
|
||
reb = p_new(1,C_RSCFILE);
|
||
ret = p_entersend3(rcb,O RS_INIT,&fname([0]);
|
||
if (ret < 0)
|
||
p_exit(ret);
|
||
hDeclareAppRcb(rcb);
|
||
3
|
||
|
||
|
||
LOCAL_C VOID DoInfoMessage(INT index)
|
||
€
|
||
TEXT buf [60];
|
||
|
||
|
||
while(p_send4(rcb,O_RS READ _BUF,&buf [0], index) < 0)
|
||
hRequestRepl acePack(reb, &fname [0] ); a
|
||
|
||
winfoMsg(&buf [0] );
|
||
|
||
>
|
||
|
||
|
||
InitReb¢);
|
||
|
||
|
||
index = INFO_USEFUL_MESSAGE;
|
||
DoInfoMessage( index):
|
||
|
||
|
||
hSetS
|
||
|
||
|
||
VOID hSetSystemResourceLang(UINT Langnum);
|
||
|
||
|
||
Changes the language used by system resources to the that specified by Langnum. Language numbers are as
|
||
described for the PLIB function p_getlanguage.
|
||
|
||
|
||
This function is useful only for programs running on multi-lingual machines. It changes the system
|
||
resource for your single application and NOT for other applications running at the same time.
|
||
|
||
|
||
Note that hsetSystemResourceLang does nor alter messages from the .cfo config file.
|
||
|
||
|
||
113
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
An example of its use might be:
|
||
|
||
|
||
LOCAL_C VOID SpecificInit(VOID)
|
||
{
|
||
uEscape( FALSE);
|
||
hSetSystemResourceLang(6);
|
||
MainWid = uFindMainWid();
|
||
|
||
|
||
>
|
||
to try to set the system resource file for language number 6 (Swedish).
|
||
|
||
|
||
VOID hSetVarrayInChlistCINT index, INT nsel, VOID *varray);
|
||
|
||
|
||
This function permits a choice list to be added to a dialog item with index number index. The list of
|
||
items is found in the variable array object with handle varray. The default selected item is set to array
|
||
item nsel.
|
||
|
||
|
||
The assumption is made that the dialog item is already a choice list.
|
||
|
||
|
||
This function provides a means of setting a choice list containing more than 255 items. The
|
||
implementation is as shown below.
|
||
|
||
|
||
GLDEF_C VOID hSetVarrayInChlist(INT Index, INT nsel, VOID *varray)
|
||
€
|
||
SE_CHLIST set;
|
||
|
||
|
||
set.nsel = nsel;
|
||
|
||
set.data = varray;
|
||
|
||
set.set_flags = SE_CHLIST_DATA | SE_CHLIST_NSEL | SE_CHLIST_RETAIN;
|
||
p_send4(DatDialogPtr,O_WN_SET, index, &set);
|
||
|
||
>
|
||
|
||
|
||
An example of the use of hSetVarrayinchlist is as shown below. Note that createVariableArray() is a
|
||
smal] user written function which would create the variable array.
|
||
|
||
|
||
LOCAL_C VOID LongChoiceList(VOID)
|
||
{
|
||
UWORD junk;
|
||
UWORD used;
|
||
UWORD Longnsel;
|
||
PR_ROOT *vastr;
|
||
|
||
|
||
junk = 4;
|
||
used = 0;
|
||
longnsel = 1;
|
||
vastr = CreateVariableArray();
|
||
|
||
|
||
if (uOpenDialog("Example long list"))
|
||
return;
|
||
if CuAddChoiceList("Ignored",&junk,"Date","Time"™,NULL)
|
||
if (uAddChoiceList("Long choice", &used, NULL)
|
||
return;
|
||
hSetVarrayInChlist(2, longnsel ,vastr);
|
||
if (uRunDialog() > 0)
|
||
|
||
|
||
INT hLoadOwnDyl (INT index);
|
||
|
||
|
||
This is a utility function that loads a DYL from the multiple DYL file built into the application's .app
|
||
file and makes it ready for use.
|
||
|
||
|
||
114
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
SEES
|
||
|
||
|
||
If successful, the function returns the handle of the loaded DYL. It returns 0 if the file can not be
|
||
opened.
|
||
|
||
|
||
The parameter index specifies which DYL is to be loaded from the multiple DYL file. Zero refers to the
|
||
first DYL, one refers to the second and so on.
|
||
|
||
|
||
The function is implemented as shown below:
|
||
|
||
|
||
GLDEF_C INT hLoadOwnDyl (INT index)
|
||
€
|
||
INT DylHandle;
|
||
VOID *fcb;
|
||
INT ret;
|
||
|
||
|
||
DylHandle = 0;
|
||
|
||
ret = p_openlib(&fcb, DatCommandPtr);
|
||
|
||
if (tret)
|
||
€
|
||
p_loadfilelib¢fcb, index, byl Handle, TRUE);
|
||
p_close(feb);
|
||
>
|
||
|
||
return(DylHandle);
|
||
|
||
>
|
||
|
||
|
||
UINT hLastSystemKey(UINT *pmodi fiers);
|
||
|
||
|
||
This function allows the application to find out what keypress was last processed by the system on its
|
||
behalf.
|
||
|
||
|
||
The function returns the keypress value while the bit values representing any modifier keys pressed (e.g
|
||
SHIFT, CTRL etc) are placed in *pmodifiers.
|
||
|
||
|
||
More information on keys and key modifiers can be found in the Window Server Reference.
|
||
|
||
|
||
This function is particularly useful in determining what key press caused a dialog to terminate. For
|
||
example, a dialog can be terminated by pressing ESC or HELP (as well as other key combinations).
|
||
|
||
|
||
Knowing which key caused the dialog to terminate allows the application to take appropriate action. For
|
||
example, if a dialog were terminated by pressing the HELP key, the application could continue by
|
||
displaying help information.
|
||
|
||
|
||
For example, consider the following code fragment:
|
||
|
||
|
||
UINT key;
|
||
UINT modifiers;
|
||
|
||
|
||
/* build a dialog */
|
||
|
||
|
||
uRunDjalog();
|
||
key = hLastSystemKey(&modifiers)>
|
||
|
||
|
||
If the dialog were terminated by pressing SHIFT+CTRL+ENTER, then key would contain the value
|
||
W_KEY_RETURN (Ox0D) while modifiers would contain the value W_SHIFT_MODIFIER-+W_CTRL_MODIFIER (0x06).
|
||
|
||
|
||
Note that this function is only supported on the Series 3a.
|
||
|
||
|
||
VOID hOODialog(INT catHandle, INT class, INT resid, VOID *rbuf);
|
||
|
||
|
||
This function allows an HWIM (object oriented) dialog to be run from within an Hwif program. Use of
|
||
this function requires a knowledge of programming HWIM dialogs, as described in the Dialogs chapter
|
||
of the Object Oriented Programming Guide. See also the Combining Hwif with object oriented code
|
||
section of the Advanced Use of Hwif chapter of this manual.
|
||
|
||
|
||
The dialog object to be created and run is specified by its class number class and the category handle
|
||
catHandle of the category containing that class. The dialog contents are specified by the resource with
|
||
|
||
|
||
115
|
||
|
||
|
||
PROGRAMMING IN HWIF
|
||
|
||
|
||
resource ID resid. Data may be transferred to and from the dialog by means of a result buffer pointed to
|
||
by rbuf.
|
||
|
||
|
||
If the dialog's class is defined in an external DYL category, this category must be loaded before a call to
|
||
hOODialog. It is good practice to unload the category as soon as its code is no longer required.
|
||
|
||
|
||
aa a ae TE
|
||
The low level h-layer functions
|
||
This section may be omitted by almost all readers. Possible exceptions include readers wishing to
|
||
construct equivalents to the u-layer calls that, instead of returning errors on failure, call p_leave.
|
||
Menu bar interactions - overview
|
||
Any menu bar interaction consists of the following three stages:
|
||
|
||
® acall to hMenudpen
|
||
|
||
= one or more calls to hMenuAdd
|
||
|
||
Bacall to hMenuRun.
|
||
|
||
|
||
The calls to hMenudpen and hMenuAdd progressively build up a data structure in the form required by the
|
||
subsequent hMenuRun call. The menu bar is displayed only when the call to hMenukun is made.
|
||
|
||
|
||
A menu bar itself consists of a series of one or more menu cards. Each call to hMenuAdd adds another card
|
||
to the menu bar.
|
||
|
||
|
||
In turn, each card has a title and a series of items. The title is what appears on the menu bar, and the
|
||
items are the various choices presented to the user. Each item consists of some ext and an accelerator.
|
||
|
||
|
||
Like the menu bar as a whole, each menu card is built up in stages. Each menu card requires:
|
||
= acall to hCardopen
|
||
= one or more calls to hCardAdd
|
||
= acall to hMenuAdd (to add it into the current menu bar).
|
||
|
||
|
||
Each call hMenuOpen and hMenuadd allocates extra memory specifically for the menu bar. This memory is
|
||
freed following a successful call to hMenuRun. If however the process of building up the menu bar fails
|
||
before the call to hMenurun, the application should generally call hMenuClose to free this memory.
|
||
|
||
|
||
(However, any call to hMenudpen when there has been a previous call to hMenudpen not matched by a
|
||
following call to hMenuRun or hMenuClose also has the effect of performing an hMenuClose before
|
||
proceeding.)
|
||
|
||
|
||
Calls to hCardopen and hCardadd also allocate memory, associated with the particular menu card. This
|
||
memory is freed neither by the subsequent call hMenuAdd, nor by the call hMenukun, nor by a call
|
||
hMenuClose. Instead, the memory associated with a menu card remains allocated until specifically freed by
|
||
a call to hCardClose.
|
||
|
||
|
||
Dialog interactions - overview
|
||
|
||
|
||
In contrast to the case with menus - in which one u-layer Hwif call (uPresentMenus) encapsulates the
|
||
functionality of some seven h-layer calls - for dialogs, there is a reasonably close correspondence
|
||
between u-layer calls and h-layer calls.
|
||
|
||
|
||
The main differences between the two sets of dialog calls are:
|
||
|
||
|
||
= the h-layer calls require item prompts and dialog titles in BCS form, whereas the u-layer calls
|
||
require them in ZTS form
|
||
|
||
|
||
= the u-layer calls automatically present an appropriate error notification on detection of an error
|
||
|
||
|
||
= the u-layer contains convenience utilities for adding a choice list or an action button list to the
|
||
current dialog, in each case encapuslating the functionality of some four h-layer functions.
|
||
|
||
|
||
116
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
|
||
|
||
INT hIFInit(VOID *concb);
|
||
Initialises an application for subsequent menu bar or dialog interactions.
|
||
|
||
|
||
Returns zero for success or a negative error. However, an application that sets its start-up heap
|
||
appropriately can legitimately assume the function always succeeds.
|
||
|
||
|
||
The control block of the console (concb) must be passed. This is used internally by the ROM code just
|
||
before commencing any dialog or menu interaction (in response to an hDlgRun, hMenuRun,
|
||
hPrinterSetupDialog, or hPrint call), and again just after such an interaction. In both cases, an I/O
|
||
message
|
||
|
||
|
||
UINT func;
|
||
|
||
|
||
func=P_SCR_DISABLE_READS;
|
||
p_iow4(concb,P_FSET,&func, &state);
|
||
|
||
|
||
is sent to the console, with state set TRUE on commencing the interaction, and set FALSE on concluding it.
|
||
|
||
|
||
VOID *hCardOpen(VOID);
|
||
|
||
|
||
Prepares to build up a menu card.
|
||
|
||
|
||
Returns a handle to use in subsequent calls to hcardAdd, hMenuAdd, and hCardClose, or else 0 for OOM (no
|
||
Window Server resources are required by the call).
|
||
|
||
|
||
INT hCardAdd(VOID *card, INT index, INT accel , TEXT *str);
|
||
|
||
|
||
Adds an item to the menu card with handle card (as returned by a prior call to hCardopen).
|
||
|
||
|
||
The item is inserted as the item with position index in the menu card. (Thus ordinarily index would be 1
|
||
the first time hCardadd is called for a card, 2 the second time, and so on).
|
||
|
||
|
||
The item has accelerator accel, and text defined by the BCS str.
|
||
|
||
|
||
Returns 0 for success or a negative error. (No Window Server resources are required by the call).
|
||
|
||
|
||
VOID hCardClose(VOID *card);
|
||
|
||
|
||
Frees all the memory resources associated specifically with the menu card with handle card (as returned
|
||
by a prior call to hcardopen). Harmless if card is zero (may be useful in error-recovery code).
|
||
|
||
|
||
INT hMenuOpen(VOID);
|
||
|
||
|
||
Prepares for a menu bar interaction.
|
||
|
||
|
||
Returns 0 for success or a negative error. Applications should always test the return value, since this
|
||
routine involves opening another Window Server window.
|
||
|
||
|
||
INT hMenuAdd(TEXT *title,VOID *card);
|
||
|
||
|
||
Adds the menu card identified by card and with title given in BCS form by title into the current menu
|
||
bar.
|
||
|
||
|
||
The card is always added at the end of the current menu bar.
|
||
|
||
|
||
Retums 0 for success or a negative error. (No Window Server resources are required by the call).
|
||
|
||
|
||
117
|
||
|
||
|
||
, PROGRAMMING IN HWIF
|
||
|
||
|
||
INT hMenuRun(VOID);
|
||
|
||
|
||
Presents the menu bar prepared by earlier calls to hMenuOpen and hMenuAdd, and returns only when the user
|
||
has made a choice (or cancelled).
|
||
|
||
|
||
Returns 0 if the user cancelled, or a negative error value, or else the accelerator of the item selected by
|
||
the user. Applications must not assume that the function always succeeds, since additional Window
|
||
Server resources are involved in its execution.
|
||
|
||
|
||
VOID hMenuClose(VOID);
|
||
|
||
|
||
Frees all the memory resources associated specifically with the current menu bar. (Harmless if there is no
|
||
current menu bar.)
|
||
|
||
|
||
INT hD|gOpen(TEXT *title);
|
||
|
||
|
||
The low-layer version of uOpenDialog.
|
||
|
||
|
||
INT hDlgRun(VOID);
|
||
|
||
|
||
The low-layer version of uRunDialog.
|
||
|
||
|
||
VOID hBigClose(VOID);
|
||
|
||
|
||
Frees all resources known to the current dialog (if any).
|
||
|
||
|
||
Not called from within any of the u-layer functions under the rationale that a call to hDtgClose is
|
||
implicitly made every time a menu bar or dialog interaction is initiated.
|
||
|
||
|
||
The low-layer version of uAddDialog!item.
|
||
|
||
|
||
In addition to the values of type discussed in the documentation for uAddDialogItem, the following are
|
||
also available:
|
||
|
||
|
||
H_DIALOG_CHOICE for a choice list, with corresponding data struct H_DI_CHOICE
|
||
|
||
|
||
H_DIALOG_BUTTONS for an action list of buttons, with corresponding data struct H_DI_BUTTONS.
|
||
|
||
|
||
VOID *hChoiceOpen(VOID);
|
||
|
||
|
||
Prepares to build up a choice list.
|
||
|
||
|
||
Returns a handle to use in subsequent calls to hChoiceAdd, hDLgAdd, and hChoiceClose, or else 0 for OOM
|
||
(no Window Server resources are required by the call).
|
||
|
||
|
||
INT hChoiceAdd(VOID *hand,INT index,TEXT *str);
|
||
Adds an item to the choice list with handle hand (as returned by a prior call to hChoiceOpen).
|
||
|
||
|
||
The item is inserted as the item with position index in the choice list. (Thus ordinarily index would be 1
|
||
the first time hChoiceddd is called for a choice list, 2 the second time, and so on).
|
||
|
||
|
||
118
|
||
|
||
|
||
4 HWIF REFERENCE DOCUMENTATION
|
||
|
||
|
||
The item has text defined by the BCS str.
|
||
|
||
|
||
Returns O for success or a negative error. (No Window Server resources are required by the call).
|
||
|
||
|
||
INT hChoiceClose(VOID *hand);
|
||
|
||
|
||
Frees all the memory resources associated specifically with the choice list with handle hand (as returned
|
||
by a prior call to hChoiceOpen). Harmless if hand is zero (may be useful in error-recovery code).
|
||
|
||
|
||
This call only needs to be made if a failure occurs before the completion of the associated hb LgAdd call,
|
||
since from that time on, the resources of the choice list fall under the responsibility of the dialog as a
|
||
whole.
|
||
|
||
|
||
VOID *hButtonOpen( VOID);
|
||
|
||
|
||
Prepares to build up an action list of buttons.
|
||
|
||
|
||
Returms a handle to use in subsequent calls to hButtonAdd, hDIgAdd, and hButtonClose, or else 0 for OOM
|
||
(no Window Server resources are required by the call).
|
||
|
||
|
||
KRUBHAEE OS eo
|
||
|
||
|
||
INT hButtonAdd(VOID *hand, INT index, INT key, TEXT *str);
|
||
|
||
|
||
Adds a button to the action list with handle hand (as returned by a prior call to hButtonOpen).
|
||
|
||
|
||
The item is inserted as the button with position index in the action list. (Thus ordinarily index would be 1
|
||
the first time hButtonadd is called for an‘action list, 2 the second time, and so on).
|
||
|
||
|
||
The button has keycode defined by key and text defined by the BCS str.
|
||
|
||
|
||
Returns 0 for success or a negative error. (No Window Server resources are required by the call).
|
||
|
||
|
||
VOID hButtonClose(VOID *hand);
|
||
|
||
|
||
Frees all the memory resources associated specifically with the action list with handle hand (as returned
|
||
by a prior call to hButtondpen). Harmless if hand is zero (may be useful in error-recovery code).
|
||
|
||
|
||
This call only needs to be made if a failure occurs before the completion of the associated hp \gAdd call,
|
||
since from that time on, the resources of the action list fall under the responsibility of the dialog as a
|
||
whole.
|
||
|
||
|
||
119
|
||
|
||
|
||
ar?
|
||
|
||
|
||
INDEX
|
||
|
||
|
||
H_ DIALOG DATE 86
|
||
H_DIALOG EDIT 86
|
||
H_ DIALOG FLOAT 85
|
||
H_ DIALOG FSEL 87
|
||
H_ DIALOG NUMBER 85
|
||
H_DIALOG SEDIT 87
|
||
H_ DIALOG TEXT 85
|
||
H_ DIALOG TIME 86
|
||
H_ DIALOG XINPUT 87
|
||
H_DTEDIT 98
|
||
H_SE_DTEDIT 99
|
||
hButtonAdd 119
|
||
hButtonClose 119
|
||
hButtonOpen 119
|
||
hCardAdd 117
|
||
hCardClose 117
|
||
hCardOpen 117
|
||
hChoiceAdd 118
|
||
hChoiceClose 119
|
||
hChoiceOpen 118
|
||
hCrackCommandLine 109
|
||
hDeclareAppReb 112
|
||
hDigAdd 118
|
||
hDigClose 118
|
||
hDigOpen 118
|
||
hDigPosition 110
|
||
hDigRun 118
|
||
hDTClose 97
|
||
hDTEmphasise 98
|
||
hDTHandleKey 98
|
||
hDTMFString 111
|
||
hDTOpen 97
|
||
hDTSelfCheck 97
|
||
hDTSense 97
|
||
|
||
hDTSet 97
|
||
hEBChangeWidth 102
|
||
hEBClearChanged 104
|
||
hEBClose 105
|
||
hEBCompleteFormat 100
|
||
hEBCopy 103
|
||
hEBDocChanged 105
|
||
hEBEmphasise 101
|
||
hEBEvaluate 103
|
||
hEBFind 104
|
||
hEBHandleKey 100
|
||
hEBInsert 103
|
||
hEBOpen 99
|
||
hEBPaste 104
|
||
hEBPosToXL 106
|
||
hEBReplace 103
|
||
hEBSenseChanged 104
|
||
hEBSenseClipText 102
|
||
hEBSenseDoc 105
|
||
hEBSenseMargin 106
|
||
hEBSenseSelect 102
|
||
hEBSenseText 101
|
||
|
||
|
||
hEBSetClipText 102
|
||
hEBSetCWidth 103
|
||
hEBSetMargin 106
|
||
hEBSetSelect 102
|
||
hEBSetText 101
|
||
hEBShowSymbols 104
|
||
hEDCapacity 105
|
||
hEDInsert 105
|
||
HELP_ARRAY 112
|
||
hEnsurePath 110
|
||
hHelpSubSystem 111
|
||
hiFInit 117
|
||
hinitAppReb 112
|
||
hisDbfCompressible 111
|
||
hLastSystemKey 115
|
||
hLoadOwnDyl 114
|
||
hMenuAdd 117
|
||
hMenuClose 118
|
||
hMenuOpen 117
|
||
hMenuRun 118
|
||
hOODialog 115
|
||
|
||
hPrint 107
|
||
hPrinterSetupDialog 107
|
||
hPrintSenseBufWidth 109
|
||
hPrintSensePageWidth 109
|
||
hPrintSetS! 109
|
||
hPrintSetupDialog 107
|
||
hRequestReplacePack 113
|
||
hSetSystemResourceLang 113
|
||
hSetUpStatusNames 110
|
||
hSetVarrayInChlist 114
|
||
hTTClose 97
|
||
|
||
hTTOpen 95
|
||
hTTSenseString 96
|
||
hTTSetAbbreviations 95
|
||
hTTSetFormat 95
|
||
hTTSetTime 96
|
||
STRING 112
|
||
TOPIC_ARRAY 112
|
||
uAddButtonList 83
|
||
uAddChoiceList 84
|
||
uAddDCL 88
|
||
uAddDialogltem 84
|
||
uAddGreyUline 88
|
||
uBeginDCL 88
|
||
uCancelGetKeyA 78
|
||
uCheckHandle 93
|
||
uCommonlnit 74
|
||
uDialogMenu 94
|
||
uDisplayText 94
|
||
uEnableGrey 76
|
||
uErrorString 93
|
||
uErrorValue 93
|
||
uEscape 92
|
||
uFindMainWid 93
|
||
uForceToFront 93
|
||
uGetKey 77
|
||
|
||
uGetKeyA 77
|
||
uGrowDCL 88
|
||
uKeyPressOutstanding 79
|
||
uLocateCommand 79
|
||
uOpenDialog 82
|
||
uPresentMenus 81
|
||
uRunDialog 83
|
||
uSetDialogUline 91
|
||
uZTStoBCS 94
|
||
|
||
|
||
ar Vea ee,
|
||
OF) iterates
|
||
Tt ee et
|
||
|
||
|
||
yt » opel
|
||
|
||
|
||
Su9 pa) BEepale
|
||
|
||
|
||
A) A Wate ey ey &
|
||
a) oo as
|
||
ac ‘we Lady
|
||
|
||
|
||
" onealay espe
|
||
|
||
eee ee 1)
|
||
|
||
Sf) jee. 7° ele en
|
||
=
|
||
|
||
oy 5 oT LOTIUT 8 =
|
||
|
||
“i iter
|
||
|
||
Hy = nae : av’
|
||
|
||
oY apie Sarat) ©
|
||
|
||
> 2g Map Pry
|
||
|
||
—t Meret)
|
||
|
||
|
||
f¢ wets
|
||
art vi a ‘
|
||
eh ® GwiDe
|
||
aD we! Me
|
||
é CAs =
|
||
wy ad ¢ é
|
||
|
||
|
||
e Z hae |
|
||
We 7. —_-
|
||
i.
|
||
|
||
a ON '
|
||
in «aaa
|
||
|
||
t OG,
|
||
|
||
WwW & »~ ‘
|
||
|
||
a te 4.)
|
||
|
||
+f) «se
|
||
i? tre eae
|
||
Es y age” Ve
|
||
|
||
. we
|
||
|
||
|
||
et peopel LL «
|
||
4 payee 40
|
||
|
||
|
||
Mami
|
||
|
||
|
||
St (PAU GOR)
|
||
|
||
|
||
WH Ohne oe
|
||
oT? pte erate)
|
||
|
||
|
||
Cry @ 7 ;
|
||
Ait vegit ee
|
||
Siu ire jt +
|
||
|
||
vil oop
|
||
|
||
|
||
Ls Le
|
||
‘Vr ae
|
||
| ira ad “> \
|
||
|
||
|
||
‘* Gara wt
|
||
4 poeta hae
|
||
|
||
|
||
oe bir 8 ow ick
|
||
|
||
|
||
ba ae an La |
|
||
|
||
|
||
Ws) sa
|
||
a TD Se Med) ln ge
|
||
ml oye a i
|
||
My oath erie?
|
||
a |
|
||
AP ouerlhl
|
||
w bivmo 4h
|
||
a” eertalt “ve”
|
||
|
||
|
||
i
|
||
te Luana, Sate wendy
|
||
y wt Jaco
|
||
|
||
a) shee) A 5"
|
||
erect tp i
|
||
|
||
|
||
a
|
||
|
||
|