home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 1994-08-16 | 121.6 KB | 2,863 lines
NPLibrary version 1.11 written by Chris Coe (c) Norsoft Productions 1994 ========================================================================= The Norsoft Productions library is the wimp procedure library that has been employed by ALL multi-tasking programs from Norsoft Productions. Having looked at many wimp libraries in the Public Domain, I decided to write my own. The problem with these libraries is that often they don't suit the style of programming of anybody but the author. Obviously I can't say that NPLibrary is any different, but I hope that it will be found useful to WIMP programmers everywhere. NPLibrary is written in BASIC, so it will be of most use to BASIC programmers. You can find the version number in the fourth line of the program (a REM statement). As the library is only in the 'expanding' stage at the moment, it is inevitable that people will want to add their own routines to the library. I would like programmers to write to me with any improvements they think might be useful rather than doing this, as it will lead to many strange, incompatible and inconsistent versions springing up everywhere. Note that NPLibrary is NOT for people with "little or no knowledge" of Wimp programming, because it's quite complicated, and expects you to know what you are doing. I have given help where I think it's necessary, and at the end there is an example program showing where all these procedures are meant to go in the program, but once again I must stress that it's not for newcomers to Wimp programming, and a copy of the new PRMs is strongly recommended. Usage of NPLibrary: technical & official ---------------------------------------- ***** TECHNICAL ***** GENERAL 1) All procedures and variables used in NPLibrary begin with 'lib_', and all variables are localised except for a special few (see later), so it is almost impossible to have procedures and variables in your program and NPLibrary clashing with each other. 2) In an ordinary Wimp task, the task would have to keep track of things like the last menu that was open, the template buffer and so on. When you use NPLibrary, the library takes care of all this. In fact, the task doesn't even need to know anything about it. INSTALLING As with any other files used by your applications, NPLibrary should be placed inside the application it is to be used in. One of the first lines of your program should be: LIBRARY "<Obey$Dir>.NPLibrary" You can of course replace "<Obey$Dir>" with the program's system variable if it has one, like "<App$Dir>". MEMORY CONSUMPTION Because of the overheads incurred by tacking large amounts of code to your program, you should add about 64k onto the expected wimpslot value of the program, so a program with a 32k wimpslot becomes a program with a 96k one. WimpSlot -min 96k -max 96k Run <Obey$Dir>.!RunImage INITIALISING Before any NPLibrary procedures are called or variables are used, the procedure PROClib_initialise must be called. For details of this, see the definitions of each function/procedure below. POLLING LOOP The main Wimp polling loop is also dealt with by NPLibrary. In version 1.00 (which has been released inside earlier programs of mine but this is its first release as a stand-alone program) was handled by the task. The new method takes even more programming strain away from the task to let the programmer concentrate on what it was designed for. It also means that little things like reopening the menu if adjust was used and sending superfluous keypresses to the next task are dealt with automatically, whereas before they had to be in the task. The task's main program loop should look something like this: DEF PROCpoll finish%=FALSE REPEAT PROClib_poll(work%) UNTIL finish% ENDPROC Where finish% is a flag that should be set when the user quits the task, or the task is forced by the Wimp to close down. PROClib_poll will call the task when it needs help, but many things can be carried out entirely in the background without the programmer even realizing that they have to be done. COMPULSORY PROCEDURES The task you are writing is expected to have certain special procedures that can be called. To avoid confusion, these all start with 'task_' and should be located within the main code somewhere, and NOT in NPLibrary. There are also several procedures to do with polling, and these all start with 'poll_'. These too should be placed in the main code. ERROR TRAPPING To trap internal errors with the ON ERROR statement, you should have a line near the start of the program looking similar to: ON ERROR PROClib_fatalerror:PROCtask_quit:END Obviously, you should only put this AFTER you have installed NPLibrary with the LIBRARY command. TEMPLATES Two template files are included with NPLibrary, Template2D and Template3D. In this version, they contain just two window definitions - "info" and "savebox" - with exactly the same icon numbers etc. The only difference is that one is for RISC OS 2, the other is for RISC OS 3 with the 3D bit in the CMOS RAM set. You should use these as the basis of your template files, as they are standard windows that I have already set up for you. PINBOARD ICONS The two files IcSprite and IcSprite22 contain two blank sprites on which you should base your designs for iconized window sprites. IcSprite is the lo-res version and IcSprite22 is for those with hi-res monitors. See the section on iconizing windows for more information. ***** OFFICIAL ***** If you wish to use NPLibrary in programs for general release, be it Public Domain, shareware, commercial or whatever, you should contact me with a copy of the program to obtain my permission to use it. I won't refuse you unless the program is obscene or utter crap, so there aren't really any strings attached. The only other condition is that I am credited somewhere in the program that is visible to the user during use (that means not in a REM line somewhere that nobody will ever look at!). If you have any suggestions for improvement to the library, please let me know so I can implement them and send you a copy of the new version. I am aware that NPLibrary is not a full library of Wimp routines at present, mainly because I have been adding bits to it as I need them rather than programming it as a project in its own right. To contact me, please write to: Norsoft Productions, 19, Seton Road, Taverham, Norwich, Norfolk, NR8 6QE. Enclose a SAE for the return of your disk(s). Accessible NPLibrary variables ------------------------------ VARIABLE NAME CONTENTS *lib_templatesize% The size in bytes of NPLibrary's template area. *lib_indirectsize% The size in bytes of NPLibrary's indirected icon data block. *lib_menusize% The size in bytes of NPLibrary's menu data block. *lib_blocksize% The size in bytes of NPLibrary's miscellaneous data block. *lib_block% The start address of NPLibrary's miscellaneous data block. *lib_templatebuffer% The start address of NPLibrary's template area. *lib_indirect% The start address of NPLibrary's indirected icon data block. *lib_menu% The start address of NPLibrary's menu data block. lib_left% Used to refer to the left-hand side of the icon bar. It is a constant holding the value -2. lib_right% Used to refer to the right-hand side of the icon bar. It is a constant holding the value -1. *lib_menuptr% NPLibrary's current position down the menu data block. lib_lastopen% The handle of the last menu that was open. When undefined, it holds the value -1. *lib_lastopenitems% The number of items in the last menu that was open. When undefined or unrequired, it holds the value -1. lib_front% Used to refer to the setting of the positions of windows to the front. It is a constant holding the value -1. *lib_lastopenx% Used to refer to the x position of the last menu open. When undefined, it holds the value -1. *lib_lastopeny% Used to refer to the y position of the last menu open. When undefined, it holds the value -1. lib_saved% A flag showing whether the current document has been saved (-1/TRUE if so, 0/FALSE if not). When undefined, it holds the value -2. lib_taskname$ The name of the task to be used in the task manager display. When undefined, it holds the string "<Untitled>". *lib_sprites% Contains the pointer to NPLibrary's private sprite area. When undefined, it contains the value 1 (this will cause the Wimp to look in its own sprite pool when the task is looking for a sprite). * should not need to be referred to by the task. Compulsory task procedures -------------------------- These must be found in !RunImage somewhere. They can be called by the task if it so desires, but NPLibrary expects all of them to be there, even if it just passes control straight back to the library and does nothing. The complete list of procedures and functions is: WINDOWS PROCtask_redrawwindow Initiate redraw of window FNtask_closewindow Check if it is ok for NPLibrary to close a window FILE FNtask_oktosave Check if it is ok for NPLibrary to HANDLING initiate a save PROCtask_save Saves a file/document FNtask_oktoload Check if it is ok for NPLibrary to initiate a load PROCtask_load Loads a file/document PROCtask_updatefilestatus Perform any tidying up necessary concerning file status TASK PROCtask_quit Close down the task HANDLING ..................................................................WINDOWS.... PROCEDURE/FUNCTION NAME: PROCtask_redrawwindow PURPOSE: Initiate redraw of window PARAMETERS: On entry: 1. window handle 2. visible top-left x origin of window 3. visible top-left y origin of window 4. redraw minimum x coordinate 5. redraw minimum y coordinate 6. redraw maximum x coordinate 7. redraw maximum y coordinate USAGE: When NPLibrary needs the task's help to redraw a window, it will call PROCtask_redrawwindow with the graphics window set to the redraw rectangle. Because of this, it doesn't matter if you just redraw the whole window at P2,P3 because the only part that will actually be redrawn is the graphics window. EXAMPLE: DEF PROCtask_redrawwindow(window%,xorigin%,yorigin%,x1%,y1%,x2%,y2%) CASE window% OF WHEN window handle 1:PROCredraw_preferenceswindow WHEN window handle 2:PROCredraw_palettewindow WHEN window handle 3:PROCredraw_picturewindow ENDCASE ENDPROC ............................................................................. PROCEDURE/FUNCTION NAME: FNtask_closewindow PURPOSE: Check if it is ok for NPLibrary to close a window PARAMETERS: On entry: 1. window handle On exit: 1. TRUE = ok to close window FALSE = not ok to close window USAGE: This should return TRUE or FALSE depending on whether or not it is ok to close the window of that particular handle. You can also use it to perform actions like opening filer windows if the user is holding down SHIFT etc. EXAMPLE: DEF FNtask_closewindow(window%) LOCAL ok%:ok%=TRUE CASE window% OF WHEN mainwindow%: IF lib_saved%=0 PROClib_openwindowincentre(warning%,FALSE):ok%=FALSE ENDCASE =ok% The third from last line means: if the document has not been saved, then bring up a warning window and set the ok% flag to NOT ok to close the window. ...........................................................FILE HANDLING..... PROCEDURE/FUNCTION NAME: FNtask_oktosave PURPOSE: Check if it is ok for NPLibrary to initiate a save PARAMETERS: On entry: 1. filename On exit: 1. TRUE = ok to save FALSE = not ok to save USAGE: This procedure gives the task a chance to object if for some reason there is a problem with saving the file. For example, it could be used to make sure that a file of the same name doesn't exist, and this is the subject of the example below. EXAMPLE: DEF FNtask_oktosave(file$) LOCAL h%,ok%:ok%=TRUE h%=OPENIN(file$):CLOSE#h% IF h%>0 THEN PROClib_openwholewindowincentre(overwritewarning%,FALSE ):ok%=FALSE =ok% If the handle (h%) of the file opened is 0, then it doesn't exist and returns OK, but if it has a handle >0, then it does exist and a warning window is opened, and the ok% flag is set to FALSE. ............................................................................. PROCEDURE/FUNCTION NAME: PROCtask_save PURPOSE: Saves a file/document PARAMETERS: On entry: 1. filename USAGE: Although NPLibrary handles the majority of the data transfer protocol, there comes a point when the actual data must be written, and at this point PROCtask_save is called. The task must save the file, update any filename icons to reflect the new filename, set the saved flag if necessary, carry out any other actions like closing windows etc., and pass control back to the library. EXAMPLE: DEF PROCtask_save(file$) LOCAL handle% handle%=OPENOUT(file$) BPUT#handle%,"Hello World" CLOSE#handle% PROClib_saved(TRUE) <- This sets the lib_saved% flag $file%=file$ <- Assuming file% holds the indirected icon address of the save box file icon, this updates its contents. PROClib_closewindow(documentwindow%) ENDPROC ............................................................................. PROCEDURE/FUNCTION NAME: FNtask_oktoload PURPOSE: Check if it is ok for NPLibrary to initiate a load PARAMETERS: On entry: 1. filename On exit: 1. TRUE = ok to load FALSE = not ok to load USAGE: This procedure gives the task a chance to object if for some reason there is a problem with loading the file. For example, an unsaved file could already be in memory, and the loading action would overwrite it, and this is the subject of the example below. EXAMPLE: DEF FNtask_oktoload(file$) LOCAL ok%:ok%=TRUE IF lib_saved%=0 THEN PROClib_openwholewindowincentre(savewarning%,FA LSE):ok%=FALSE =ok% ............................................................................. PROCEDURE/FUNCTION NAME: PROCtask_load PURPOSE: Load a file/document PARAMETERS: On entry: 1. filename USAGE: This may be called by the task or by NPLibrary to load something into the task. The procedure must reset everything necessary, load the file, and open a window displaying its contents. As in PROCtask_save, you must also update any filename icons necessary and set the lib_saved% flag (as the file won't have been altered yet if it has just been loaded). Finally, control must be passed back to NPLibrary. EXAMPLE: DEF PROCtask_load(file$) PROCclearmemory OSCLI"Load "+file$+" "+STR$~memory% <- memory% has been previously allocated with a DIM PROCputfileinwindow PROClib_openwholewindowincentre(mainwindow%,FALSE) <- opens the main window PROClib_saved(TRUE) $file%=file$ <- assuming file% points to the indirected icon for the save box ENDPROC ............................................................................. PROCEDURE/FUNCTION NAME: PROCtask_updatefilestatus PURPOSE: Perform any tidying up necessary concerning file status PARAMETERS: None USAGE: This procedure is used in various places by NPLibrary to keep the user of the task informed about file information. The procedure should add or remove "*"s from window titles showing whether or not a file has been changed since it was last saved, update info windows, title bars and so on to reflect any change in document filenames etc. EXAMPLE: DEF PROCtask_updatefilestatus IF lib_saved% PROClib_changeindtexticon(windinfo%,1,"NO") ELSE PROCl ib_changeindtexticon(windinfo%,1,"YES") ENDPROC The middle line examines the lib_saved% flag and changes the text in an indirected icon to NO if it has been saved, and YES if it hasn't. Suppose there were two icons in a window: Modified? ---- ^^^ ^^ Icon 0 Icon 1 Icon 1 is changed to YES if the file hasn't been saved, so it appears as: Modified? YES. ............................................................TASK HANDLING.... PROCEDURE/FUNCTION NAME: PROCtask_quit PURPOSE: Close down the task PARAMETERS: None USAGE: The task must close any files open, tidy up and finally close itself down as a Wimp task. By this stage any warning windows will have already 'been and gone' - all this procedure must do is quit. Note though that control is still passed back to the library/program at the end for it to issue a final END statement. EXAMPLE: DEF PROCtask_quit CLOSE#handle% OSCLI"Wipe <Wimp$ScrapDir>.MyApp ~C~V FR" <- deletes its part of the !Scrap directory PROClib_closedown(taskhandle%) ENDPROC ............................................................................. Polling procedures and functions -------------------------------- These must all be located in the main !RunImage file, and are called by PROClib_poll when the need arises. Events marked "---" are handled by NPLibrary itself. You will not need to use many of these, but they should still be present in your program in case they are ever called, so DEF PROCpoll_pointerenteringwindow:ENDPROC is fine. Procedure/function called Event code Event number ------------------------- ---------- ------------ PROCpoll_null Null_Reason_Code 0 --- Redraw_Window_Request 1 PROCpoll_openwindow Open_Window_Request 2 --- Close_Window_Request 3 PROCpoll_pointerleavingwindow Pointer_Leaving_Window 4 PROCpoll_pointerenteringwindow Pointer_Entering_Window 5 PROCpoll_checkmouse Mouse_Click 6 PROCpoll_drag User_Drag_Box 7 FNpoll_keypressed Key_Pressed 8 PROCpoll_menuselection Menu_Selection 9 PROCpoll_scrollrequest Scroll_Request 10 PROCpoll_losecaret Lose_Caret 11 PROCpoll_gaincaret Gain_Caret 12 PROCpoll_receivemessage User_Message(_Recorded) 17(18) ............................................................................. PROCEDURE/FUNCTION NAME: PROCpoll_null CALL EVENT: Null_Reason_Code PARAMETERS: None USAGE: This is the time to be doing any calculations or other work that the task may want to do, for Null_Reason_Code means that the computer has some time on its hands and is offering it to your task. ............................................................................. PROCEDURE/FUNCTION NAME: PROCpoll_openwindow CALL EVENT: Open_Window_Request PARAMETERS: Received: 1. window handle 2. visible area minimum x coordinate 3. visible area minimum y coordinate USAGE: By the time the task is called, NPLibrary will have already opened the window specified by the Wimp. It is now up to the task to correctly open/reposition any toolboxes necessary. The handle of the window opened is supplied so that the task can work out if any other windows attached to that one need to be moved, and if so, you can simply offset them from the coordinates supplied. ............................................................................. PROCEDURE/FUNCTION NAME: PROCpoll_pointerleavingwindow CALL EVENT: Pointer_Leaving_Window PARAMETERS: Received: 1. window handle USAGE: This is the task's opportunity to change the shape of the pointer, remove the input focus from the window etc. The window the pointer has left is specified in P1. ............................................................................. PROCEDURE/FUNCTION NAME: PROCpoll_pointerenteringwindow CALL EVENT: Pointer_Entering_Window PARAMETERS: Received: 1. window handle USAGE: The pointer has just entered window P1, so if you are writing an art package for instance you can use this procedure to change the pointer shape to that of the currently used tool. The window the pointer has entered is specified in P1. ............................................................................. PROCEDURE/FUNCTION NAME: PROCpoll_checkmouse CALL EVENT: Mouse_Click PARAMETERS: Received: 1. mouse absolute x coordinate 2. mouse absolute y coordinate 3. button state: bit 0 set = select depressed bit 1 set = menu depressed bit 2 set = adjust depressed 4. window handle 5. icon handle USAGE: The user has just depressed a button on the mouse. Note if more than one button is depressed, then two or more bits can be set, so the way to check that select is pressed is not: IF buttons%=1<<2 but IF (buttons% AND 1<<2) The first will only work if select is the only button depressed, but the second will work whatever combination is depressed (as long as select is one of them). P4 and P5 specify the icon clicked on and what window it is in. The task is more likely to want to use these values than P1 and P2. ............................................................................. PROCEDURE/FUNCTION NAME: PROCpoll_drag CALL EVENT: User_Drag_Box PARAMETERS: Received: 1. drag box absolute x minimum coordinate 2. drag box absolute y minimum coordinate 3. drag box absolute x maximum coordinate 4. drag box absolute y maximum coordinate USAGE: The user has just released all the mouse buttons, terminating a user drag event. The size of the box made is returned, but remember that a drag also occurs when the user drags files to filer windows, so the most common use of this procedure will be to initiate a save (in which case the coordinates supplied are not used). ............................................................................. PROCEDURE/FUNCTION NAME: FNpoll_keypressed CALL EVENT: Key_Pressed PARAMETERS: Received: 1. window handle 2. icon handle 3. ASCII code of key pressed Sent: 1. key process status: TRUE = keypress was for us, do not send to other tasks FALSE = keypress was not for us, send to other tasks USAGE: The Wimp can deal with most keypresses itself, but keypresses invoking action such as RETURN must be dealt with by the task. P1 and P2 are the window and icon handles that the caret is in. P3 can be converted to a character with BASIC's CHR$(a) function, where 'a' is an ASCII code. RETURN has the ASCII code 13. The task must decide and return whether the keypress was intended for it, TRUE if it was (and this will terminate it), FALSE if it wasn't (NPLibrary will pass it on to the next task). It is crucial that you program this correctly as programs that employ hot-key functions won't work if you terminate every keypress that reaches your task. ............................................................................. PROCEDURE/FUNCTION NAME: PROCpoll_menuselection CALL EVENT: Menu_Selection PARAMETERS: Received: 1. textual selection (submenus separated by periods) 2. last menu open USAGE: This returns the actual text that was clicked on in the menu structure, so clicking on "Quit" will return "Quit". P2 is supplied just in case you have the same option in more than one menu, and of course you need to check that it was actually one of your task's menus that an option was chosen from. ............................................................................. PROCEDURE/FUNCTION NAME: PROCpoll_scrollrequest CALL EVENT: Scroll_Request PARAMETERS: None USAGE: This procedure is not yet supported. While no parameters are supplied, you can still find out anything you want from the block returned by Wimp_Poll. ............................................................................. PROCEDURE/FUNCTION NAME: PROCpoll_losecaret CALL EVENT: Lose_Caret PARAMETERS: Received: 1. window handle 2. icon handle USAGE: The Lose_Caret event occurs when the window with the input focus window changes. It does not occur if a different icon in the same window gets the input focus. Bear in mind that if your task has more than one window capable of holding the input focus, then the caret may still be with it. A Gain_Caret message is broadcast immediately after the Lose_Caret to notify the task in question, so you will find out if your task still has the input focus. P1 and P2 specify from where the task has lost the caret. ............................................................................. PROCEDURE/FUNCTION NAME: PROCpoll_gaincaret CALL EVENT: Gain_Caret PARAMETERS: Received: 1. window handle 2. icon handle USAGE: The task has just gained the caret. P1 and P2 specifies the window and icon the caret has been placed in. Window P1 will also gain the input focus. ............................................................................. PROCEDURE/FUNCTION NAME: PROCpoll_receivemessage CALL EVENT: User_Message / User_Message_Recorded PARAMETERS: Received: 1. message action code USAGE: All wimp, filer, pinboard messages and so on will be routed here. The use of these messages varies enormously, so it is left to the task programmer to examine the parts of the message block that he or she wants to use. You really need the PRMs to take advantage of such messages, which include saving files, iconizing windows, setting task alarms and so on. Owners of the RISC OS 3 PRMs can find detailed information about every message available in RISC OS 3 starting on page 3-230. This information is extremely useful. PROCpoll_receivemessage should take the form: DEF PROCpoll_receivemessage(message%) CASE message% OF WHEN 0:PROCtask_quit:END <-- always include this line WHEN 2:PROClib_dosave(savewind_handle,saveicon_handle,wimp_poll_block) WHEN 3,5:PROClib_doload(wimp_poll_block,file_type) ... ENDCASE ENDPROC where wimp_poll_block is the block returned by PROClib_poll - you specify it as the first parameter to PROClib_poll. A couple of messages have been included here: 0 = Message_Quit - instant shutdown, no choices; 2 = Message_DataSaveAck - filer acknowledges save start; 3 = Message_DataLoad - filer wants task to load file; 5 = Message_ - DataOpen - the user has double-clicked on a file/directory. The list should continue in this manner for every message you want to intercept. ............................................................................. NPLibrary procedures and functions ---------------------------------- These form the skeleton of Wimp programs, which you can use in your own programs. You do need some knowledge of Wimp programming, but the task in hand should be greatly simplified by NPLibrary, especially operations where messages are being broadcast all over the place, like saving operations, which are reduced to three or four PROCs in the right place. In the descriptions below, as well as full details on all the procedures implemented so far, their context in the whole overall program are discussed so you know exactly where they go. There are also some routines which have nothing to do with the Wimp itself, but will be useful to Wimp programmers, such as a routine to check if a filename is valid. The complete list of procedures and functions is: TASK PROClib_initialise Initialise NPLibrary HANDLING FNlib_startuptask Register a task on the active list PROClib_closedown Remove a task from the active list ERROR PROClib_reporterror Report an error HANDLING PROClib_fatalerror Deal with and report a fatal error FNlib_reportwarning Report a warning error ICONS FNlib_iconbar Put an icon on the icon bar FNlib_indirecticon Return the address of an indirect icon PROClib_changeindtexticon Change the contents of an indirected text only icon PROClib_changeiconbartext Changes the text in an icon bar icon (does not work properly yet) PROClib_redrawicon Redraw an icon PROClib_deleteicon Delete an icon PROClib_iconselectable Select whether an icon is selectable or greyed out PROClib_iconselectstatus Select whether an icon is selected or unselected FNlib_selected Return whether an icon is selected or unselected FNlib_putspriteinicon Puts a sprite into an indirected, sprite-only icon. WINDOWS PROClib_opentemplate Open a window template FNlib_loadtemplate Load a window template PROClib_closetemplate Close a window template PROClib_openwindow Open a window PROClib_openwholewindow Open a whole window PROClib_openwindowincentre Open a whole window in the centre of the screen, regardless of mode FNlib_windowopen Check if a window is open PROClib_closewindow Close a window PROClib_redrawwindow Initiate a window redraw PROClib_forceredraw Redraw a whole window PROClib_changewindowtitle Change the title of a window FNlib_windowtitle Return the contents of an indirect window title PROClib_bringtofront Bring a window to the front PROClib_openfilerwindowifadjust Check the mouse button status, and open a filer window if adjust is being held down FNlib_centrex Get the x position a window would need to be plotted at to make it central to the screen edges on the x axis FNlib_centrey Get the y position a window would need to be plotted at to make it central to the screen edges on the y axis PROClib_setwindowheight Sets the height of a window PROClib_setwindowwidth Sets the width of a window FNlib_getwindowheight Gets the height of a window FNlib_getwindowwidth Gets the width of a window PROClib_iconizewindow Iconizes a window (RISC OS 3 only) MENUS FNlib_createmenu Set up a menu structure PROClib_openmenu Display a menu on the screen FNlib_getmenuselection Return the user's menu choice in a textual representation PROClib_reopenmenuifadjust Check the mouse button status, and reopen the last open menu if adjust is being held down. PROClib_menuselectable Set whether a menu option is greyed out or selectable PROClib_menutick Select whether a menu option is ticked or not FILE PROClib_savedragstart Initiate a save drag from the save HANDLING box to a filer window PROClib_quicksave Initiate a save from an OK click in the save box PROClib_tellfileraboutsave Send save message to the filer PROClib_dosave Perform final checking before a save, then save PROClib_saved Set the lib_saved% flag status PROClib_doload Perform final checking before a load, then load MISC PROClib_setcaretposition Position the caret WIMP PROClib_pointerinfo Returns the window and icon the mouse pointer is currently in PROClib_loadsprites Initializes and loads sprites into NPLibrary's private sprite area MISC FNlib_getstring Extract string from memory NON-WIMP FNlib_validfilename Check if the passed filename is valid FNlib_getleafname Gets the leafname of a whole pathname FNlib_getfiletype Gets the filetype of a file FNlib_gettimestamp Get the datestamp from a file FNlib_putbit Change the value of a bit in a number FNlib_bit Get the value of a bit in a number FNlib_roundup Rounds up a whole number to the nearest multiple of another whole number ............................................................TASK HANDLING.... PROCEDURE/FUNCTION NAME: PROClib_initialise PURPOSE: Initialise NPLibrary PARAMETERS: On entry: 1. template size (kilobytes) 2. indirected icon data size (kilobytes) 3. menu block size (kilobytes) USAGE: This call should be issued before any other NPLibrary procedures or functions are used. The procedure sets up various data blocks and variables, and also initialises the library. To work out the template size, use the Count option in the filer menu on the template file, divide the number you get by 1024 (to find its value in kilobytes) then round up to the nearest multiple of 4. So if the number you got was 5346, that's 5346/1024=5.22k, rounded up gives 8k. That solves the problem of the template buffer size. Try a low value like 2k for the indirected icon data size first, and if you find that windows have the wrong contents, or their flags have been corrupted, or the window is the wrong size, increase it in steps of 2k until it works ok. Menu blocks are also small, 28 bytes for the header and 24 bytes for each menu option, so 2 or 4k should suffice for most programs. If it doesn't, try increasing it in 1k steps. Not counting headers, you can work out the number of menu options you can get per kilobyte with the formula: (m*1024)/o where m is the number of kilobytes allocated and o is the number of bytes used per menu option (always 24). EXAMPLE: PROClib_initialise(16,4,2) Initialises NPLibrary, and allocates 16k for template data, 4k for indirected icon data and 2k for menu structures. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_startuptask PURPOSE: Register a task on the active list PARAMETERS: On entry: 1. proposed task name 2. highest version of RISC OS that task recognizes On exit: 1. task handle USAGE: This will register a task with the Wimp its list of active tasks. The task name that is specified in P1 is what will appear in the task display. If P2 is 2 (ie. RISC OS 2), then messages and events new to RISC OS 3.1 will never be returned by Wimp_Poll. This allows backwards- compatibility between programs that may object to unfamiliar events. When writing Wimp programs, you should NEVER do this. Unrecognized events should be ignored. If P2 is 3.1, a table of messages to be masked in should be passed to Wimp_Initialise, but the current version of NPLibrary specifies 0 - which means that all messages are important to this task. This is the easiest way of doing it. This procedure also sets up the variable lib_taskname$ (see above). EXAMPLE: taskhandle%=FNlib_startuptask("MyApp",2) This registers a task called MyApp with the Wimp, requesting it to return all messages and events that were present in the old RISC OS 2, and none since then. The task handle is returned in a variable called taskhandle%. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_closedown PURPOSE: Remove a task from the active list PARAMETERS: On entry: 1. task handle of quitting task USAGE: This removes any task from the Wimp's list of active tasks, not just the one it is running from. This means that as well as quitting your own task, which would be the normal use for it, you can also force other tasks to close down if you know their task handles. This is rather unorthodox and I can't think of any non-malicious uses for it. Nevertheless, the feature is there. Even though you may have closed down your own task, the procedure will still return control back to the main program for it to issue a final END statement etc. EXAMPLE: PROClib_closedown(taskhandle%) Assuming that earlier on you called: taskhandle%=FNlib_startuptask... then this command will deregister your task from the active list. PROClib_closedown(&12345678) This deregisters task &12345678 from the active list. ...........................................................ERROR HANDLING.... PROCEDURE/FUNCTION NAME: PROClib_reporterror PURPOSE: Report an error PARAMETERS: On entry: 1. error message 2. flags USAGE: This will pop up a standard error box with P1 written in it, and the taskname as used in FNlib_startuptask in the title bar. The flags have the following functions: Bit Meaning when set 0 Provide an OK box 1 Provide a Cancel box 2 Highlight Cancel (or OK if bit is cleared) 3 If the error is generated while a text-style window is open (eg. within a call to Wimp_CommandWindow), then don't produce the prompt "Press SPACE or click mouse to continue", but return immediately 4 Don't prefix the application name with "Error from" in the error window's title bar 5 If neither box is clicked, return immediately (with R1=0) and leave the error window open 6 Select one of the boxes according to bits 0 and 1, close the window and return 7 Don't produce a beep even if WimpFlags bit 4 is clear (this bit is reserved in RISC OS 2) 8-31 Reserved; must be 0 Currently, you are unable to tell which button has been pressed in the error window; to do this, use FNlib_reportwarning. EXAMPLE: PROClib_reporterror("You've put the disk in upside-down",%10010110) Report the error in a box, don't beep and don't prefix the task name with "Error from", highlight Cancel and provide a Cancel box but no OK box. PROClib_reporterror("I wouldn't press that if I were you",%011) Report the error in a box, highlight OK and provide an OK box and a Cancel box. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_fatalerror PURPOSE: Deal with and report a fatal error PARAMETERS: None USAGE: This procedure turns off the hourglass, closes all open files and calls PROClib_reporterror with BASIC's REPORT$ variable plus the text: (internal error code [line number]) - must exit immediately The flags are set to 1, ie provide a cancel box only. This call can also be used with an ON ERROR statement, see below. EXAMPLE: ON ERROR PROClib_fatalerror:PROCtask_quit:END If something untoward should happen in the program code, this device will make sure that the program exits neatly and reports the nature and location of the error. The additional call to PROCtask_quit is essential in case the task wants to tidy up anything not dealt with by PROClib_fatalerror, and if you have written your program properly this will also call PROClib_closedown (see the definition of PROCtask_quit above for more information). ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_reportwarning PURPOSE: Report a warning error PARAMETERS: On entry: 1. error message On exit: 1. icon selection: 1 = OK selected 2 = Cancel selected USAGE: This calls Wimp_ReportError (as in PROClib_reporterror) with bits 4, 1 and 0 set, ie. don't prefix the task name with "Error from", and provide an ok and a cancel box (highlight the ok box, as bit 2 is clear). The main difference between this call and PROClib_reporterror is that this call will return whether the user selects OK or Cancel. EXAMPLE: ok%=FNlib_reportwarning("Clicking on OK will initiate a nuclear meltdown. Are you sure you wish to proceed?") IF ok%=2 THEN he's no fool This will print the warning in the standard error box and wait for the user to select ok or cancel. The result is put into the variable ok% and action is then taken according to the user's choice. ....................................................................ICONS.... PROCEDURE/FUNCTION NAME: FNlib_iconbar PURPOSE: Put an icon on the icon bar PARAMETERS: On entry: 1. name of sprite to use as icon 2. side of icon bar to put sprite on: -1 = right-hand side -2 = left-hand side 3. buffer to text to put underneath icon, or -1 for no text On exit: 1. icon handle USAGE: Most programs will want an icon to go on the icon bar, and this call makes the process very simple. For the second parameter, to save you remembering the two numbers, you may use the NPLibrary variables lib_left% and lib_right% (documented above) which hold the corresponding values. EXAMPLE: icon%=FNlib_iconbar("!myapp",lib_right%,-1) This is what most calls to this function will look like. This will place the icon !myapp on the right-hand side of the icon bar with no text. DIM icontext% 12 $icontext%="An Icon" icon%=FNlib_iconbar("!myapp",-1,icontext%) This will place the icon !myapp on the right-hand side of the icon bar with the text "An Icon" written underneath. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_indirecticon PURPOSE: Return the address of an indirect icon PARAMETERS: On entry: 1. window handle 2. icon handle On exit: 1. address of indirect data buffer USAGE: In pre-release versions of NPLibrary, this was an essential function, and while it is not so important now that more friendly procedures are available to you, it is still useful and still used internally. Some icons have text in them, and any icon that needs to have over twelve characters has to be indirected. This will apply particularly to writable icons. So that the task can read the contents of the icon, or so that it can change its contents, it needs to know its address in memory, and that is what this function does. Simply supply the window handle of the window that the icon is in, and the icon handle itself, and the indirect text address will be returned. Note that this will ONLY work on indirected, text, no sprite icons. This procedure has now been superseded in many ways by PROClib_changeindtexticon (see below). EXAMPLE: savefilename%=FNlib_indirecticon(savewindow%,2) Supposing that savewindow% is the window handle of a standard save box, and 2 is the icon handle of the writable filename icon in it, then this will return the address in memory at which that filename is stored. In future, the task can now find out the default filename in the save box with the reference: $savefilename%. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_changeindtexticon PURPOSE: Change the contents of an indirected text only icon PARAMETERS: On entry: 1. window handle 2. icon handle 3. new textual content of icon USAGE: Icons that need to hold text in excess of twelve characters long must be indirected, and this procedure provides a way of changing that data. You supply the window handle of the window contain the icon, and the icon handle itself, and the procedure will issue a call to FNlib_indirecticon(P1,P2) to find the indirected icon's address. The address will then be poked with P3, terminated by a carriage return (ASC 13). EXAMPLE: PROClib_changeindtexticon(progress%,status%,"Ready") Assuming that progress% is the window handle of a window containing some kind of progress report, and status% is the icon handle of an indirected text only icon containing information on what the task is doing, then this will change that icon to read "Ready". ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_changeiconbartext PURPOSE: Changes the text in an icon bar icon (does not work properly yet) PARAMETERS: On entry: 1. icon handle of icon bar icon 2. pointer to icon bar text buffer 3. new textual content of icon USAGE: THIS PROCEDURE HAS NOT BEEN FULLY WRITTEN YET. YOU SHOULD NOT USE IT IN YOUR OWN PROGRAMS. EXAMPLE: PROClib_changeiconbartext(taskicon%,textbuf%,"Waiting") Assuming that taskicon% is the icon handle of the task's icon bar icon and textbuf% is the text buffer of that icon, then this will change the text underneath the icon to read "Waiting". ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_redrawicon PURPOSE: Redraw an icon PARAMETERS: On entry: 1. window handle 2. icon handle USAGE: This procedure calls SWI Wimp_SetIconState with both the AND and EOR words set to zero, which has the effect of redrawing the icon with no changes. The window handle is that which the icon is contained in. EXAMPLE: PROClib_redrawicon(window%,icon%) This redraws the icon with the handle icon% in window window%. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_deleteicon PURPOSE: Delete an icon PARAMETERS: On entry: 1. window handle 2. icon handle USAGE: This procedure deletes the icon with the specified icon handle from the specified window. It will then call PROClib_forceredraw(P1), causing the whole window to be updated. EXAMPLE: PROClib_deleteicon(window%,icon%) This deletes icon icon% from window window% and redraws the window. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_iconselectable PURPOSE: Select whether an icon is selectable or greyed out PARAMETERS: On entry: 1. window handle 2. icon handle 3. icon status: TRUE = icon is selectable FALSE = icon is unselectable and greyed out USAGE: In some situations you may only want the user to be able to access a particular icon if certain other conditions have been met. For example, you would only allow the user to type in the screen blanking delay if he had previously chosen to have the screen blanker on. If he or she has chosen to switch it off, then there is no point in entering a delay, and so it is the RISC OS standard to grey out such icons. EXAMPLE: PROClib_iconselectable(window%,2,FNlib_selected(window%,4)) (FNlib_selected is described below, and is used to determine whether an icon is selected or unselected) This will make icon 2 in window window% selectable or unselectable depending on whether or not icon 4 in window window% is selected. If icon 4 is selected, icon 2 will be selectable. If icon 4 is unselected, icon 2 will be greyed out. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_iconselectstatus PURPOSE: Select whether an icon is selected or unselected PARAMATERS: On entry: 1. window handle 2. icon handle 3. icon status: TRUE = icon is selected FALSE = icon is unselected USAGE: Usually the user can determine the state of icons (particularly radio icons) by clicking on them with the appropriate mouse button. However, there may be some cases where the task needs to set the state of the icons itself. For instance, if the task has just loaded up a preferences file, then all the options on the preference screen will need to be set accordingly. This procedure performs that function. EXAMPLE: PROClib_iconselectstatus(pref%,6,confirm%) Supposing confirm% was a boolean variable (a variable holding either TRUE or FALSE) and pref% was the window handle of a preferences window, then icon 6 in the preferences window would reflect the value of confirm%. If confirm% is TRUE, then icon 6 will be selected. If confirm% is FALSE, then icon 6 will be deselected. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_selected PURPOSE: Return whether an icon is selected or unselected PARAMETERS: On entry: 1. window handle 2. icon handle On exit: 1. icon status: TRUE = the icon is selected FALSE = the icon is unselected USAGE: This performs the opposite of PROClib_iconselectstatus. Rather than setting the selected status of an icon, FNlib_selected will return it. This is essential for setting variables according to the status of icons. EXAMPLE: confirm%=FNicon_selected(pref%,6) Assuming pref% is the window handle of a preferences window, then confirm% will be set according to the status of icon 6 in that window. If icon 6 is selected, confirm% will be TRUE. If icon 6 is unselected, confirm% will be FALSE. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_putspriteinicon PURPOSE: Puts a sprite into an indirected, sprite-only icon PARAMETERS: On entry: 1. sprite name 2. window handle 3. icon handle On exit: 1. icon handle USAGE: This function is used to make a non-indirected sprite-only icon point to a sprite. All calls to this command ought to be made towards the end of the task's initialization procedure. Since FNlib_putsprite- inicon causes the handle of the icon being changed to be renumbered, its new icon handle is returned at the end. Note this call will ONLY work on indirected, sprite-only icons. The area where the sprite is looked for is determined by the variable lib_sprites%. If lib_sprites% holds the value 1 (which it does after PROClib_initialize is called), then the sprite will be found in the Wimp sprite pool. If lib_sprites% holds any other value (calling PROClib_loadsprites will cause this to happen), then the sprite will be found in NPLibrary's private sprite area. ..................................................................WINDOWS.... Window coordinate information ----------------------------- There are several terms and definitions that you need to understand concerned with the plotting of windows. These represent what part of the window is displayed, how much of it is displayed, and where it is displayed. WORK AREA: A window is only a partial view. Imagine a document twice the size of the screen - you can only see part of it at any one time. The area of the whole document is called the work area. The bottom-left corner represents the minimum x and y, and x and y increase as the work area extends right and up respectively. However, the top-left corner of the work area is always (0,0), so this means that the bottom-left corner of a work area 200 pixels high is (0,-200). VISIBLE AREA: The visible area is the area of the screen that is taken up by the window. The bottom-left corner represents the minimum x and y, and x and y increase as the visible area extends right and up respectively. The visible area x and y coordinates are relative to the screen, whose bottom-left corner is always (0,0), so the minimum x and y of a window 300 pixels across and 100 up is (300,100). SCROLL OFFSET: The scroll offset determines which part of the window is displayed. The scroll offset x and y coordinates specify the top-left corner of the work area to be displayed, so a scroll offset of (200,-250) is 200 pixels from the left and 250 from the top. VISIBLE WORK AREA: The visible work area takes the concept of the scroll offset one step further. Suppose we want to display part of a work area in a window with a visible area of (400,300)-(800,500). If the scroll offset is (100,-100) then the visible work area can be worked out thus: width = 800 - 400 = 400 height = 800 - 500 = 300 visible work area minimum x = scroll offset x = 100 visible work area maximum y = scroll offset y = -100 visible work area maximum x = scroll offset + width = 100 + 400 = 500 visible work area minimum y = scroll offset - height = -100 - 300 = -400 So the visible work area is (100,-100)-(500,-400) and it is to be plotted at (400,300)-(800,500). SCROLL OFFSET 0,0 : ------:----------------------------------------- | 100,-100 | | ----------------------- | | | | | | | VISIBLE | WORK | | | WORK | AREA | | | AREA | | | | | | | | | | | ----------------------- | | 500,-400 | | | | | ------------------------------------------------ 800,-600 ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_opentemplate PURPOSE: Open a window template PARAMETERS: On entry: 1. template filename (full pathname) 2. 3D option: TRUE = use two template files FALSE = use one template file USAGE: Template files are used to describe window shapes and contents. Before a program can display any windows in template files, area has to be set aside in memory for them, they must be loaded and their indirect data fields must be set up. This procedure will open a template file ready for use. The actual file opened depends upon two factors: If P2=FALSE then the file specified will be opened as normal and control will return to the task. If P2=TRUE then the current version of RISC OS will be checked. If the version is less than 3.1 then the filename + "2D" will be opened. If the version is 3.1 or over, then the 3D bit in CMOS RAM will be checked. If the 3D bit is clear, then the filename + "2D" will be opened. If the 3D bit is set, then the filename + "3D" will be opened. In RISC OS 3.1, there is a previously unused bit in the CMOS RAM which determines whether old RISC OS 2-style 2D window icons will be used, or whether new RISC OS 3 upwards 3D window icons will be used. What this amounts to is that you need to define two sets of windows, one with the suffix 2D and one with the suffix 3D (make sure all the icon numbers match otherwise the program will not work as expected). If the user is using a RISC OS 3.1+ machine and the 3D bit is set, then the 3D template will be loaded, otherwise the 2D templates will be loaded. Of course, you can just specify FALSE for P2 and the same templates will be used whatever the operating system. All template data handling is done by NPLibrary - the task needn't get involved. EXAMPLE: PROClib_opentemplate("<Obey$Dir>.Templates",FALSE) Template file "<Obey$Dir>.Templates" will be opened. PROClib_opentemplate("<Obey$Dir>.Temp",TRUE) Template file "<Obey$Dir>.Temp2D" will be opened, unless the user is using a RISC OS 3.1+ machine with the 3D bit set, in which case "<Obey$Dir>.Temp3D" will be opened instead. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_loadtemplate PURPOSE: Load a window template PARAMETERS: On entry: 1. window name On exit: 1. window handle USAGE: This function will search the currently open template file from the beginning for any window whose name matches that given in P1. If it does, then it will be loaded, a window created and any indirected data fields set up. The function will then exit with the new handle of the window loaded, with which it will always be referred to by from now on. Every window will have the current sprite block pointer inserted into it so that it knows where to find sprites, so if you have any sprite files to load, do so BEFORE loading any templates. EXAMPLE: main%=FNlib_loadtemplate("editwindow") This will scan through the template file looking for a window called "editwindow". The window handle allocated to it will be stored in main%. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_closetemplate PURPOSE: Close a window template PARAMETERS: None USAGE: This quite simply closes a window template with SWI Wimp_CloseTemplate and returns control to the task. EXAMPLE: PROClib_opentemplate("<Obey$Dir>.Template",TRUE) infowind%=FNlib_loadtemplate("info") savewind%=FNlib_loadtemplate("xfer_send") mainwind%=FNlib_loadtemplate("main") PROClib_closetemplate Open the template file, load in three windows and close it again. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_openwindow PURPOSE: Open a window PARAMETERS: On entry: 1. window handle 2. visible area minimum x coordinate 3. visible area minimum y coordinate 4. visible area maximum x coordinate 5. visible area maximum y coordinate 6. scroll x offset relative to work area origin 7. scroll y offset relative to work area origin 8. layer position of window: -1 = at front -2 = at back -3 = behind Wimp's backwindow, hiding it from sight 9. transiency of window: TRUE = window is transient FALSE = window is persistent USAGE: This procedure will open any part of a window on any part of the screen. P8 determines where in the window stack the window shall be opened. The variable lib_front% (which is a constant holding the value -1) can be substituted to make your program easier to read. The value -3 causes the input focus to be taken away before the window is opened, and is not available on RISC OS 2. P9 specifies the transiency of the window. A transient window is one that disappears when you click outside of it, like save boxes and menus. A persistent window is one that stays on the screen until the user closes it in some way, like filer windows. The coordinates for this procedure are rather complex, and two other window opening procedures (PROClib_openwhole- window and PROClib_openwindowincentre) are provided to simplify things a little. There are also functions for working out centre positions on screen (FNlib_centrex and FNlib_centrey). See the section on window coordinates for information on work areas, visible work areas and scroll offsets. EXAMPLE: PROClib_openwindow(main%,300,200,900,400,200,200,lib_front%,FALSE) This opens a persistent window at the front of the stack. The bottom-left coordinate on screen is 300,200 and the top-right is 900,400. The top-left of the window is 200,200 across and down from the start of the work area, so the bottom-right pixel is 800,700 across and down. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_openwholewindow PURPOSE: Open a whole window PARAMETERS: On entry: 1. window handle 2. visible area minimum x coordinate 3. visible area minimum y coordinate 4. transiency of window: TRUE = window is transient FALSE = window is persistent USAGE: This procedure will work out the width and height of a window and then display it wholly on the screen using P2 and P3 as the bottom-left hand corner of the window. PROClib_openwindow is called thus: PROClib_openwholewindow(P1,P2,P3,P2+width,P3+height,0,0,-1,P4) Note that the window will always be opened at the front of the stack. See PROClib_openwholewindow for a more detailed description, and information on window transiency. EXAMPLE: PROClib_openwholewindow(savebox%,500,500,TRUE) This will open the whole window savebox% at 500,500 on the screen. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_openwindowincentre PURPOSE: Open a whole window in the centre of the screen, regardless of mode PARAMETERS: On entry: 1. window handle 2. transiency of window: TRUE = window is transient FALSE = window is persistent USAGE: This command will open a whole window in the centre of the screen. To be more precise, the bottom-left position to plot the window at for it to appear in the centre of the screen is calculated with a call to each of FNlib_centrex and FNlib_centrey (see below), and PROClib_openwholewindow is called thus: PROClib_openwholewindow(P1,FNlib_centrex(P1),FNlib_centrey(P1),P2) PROClib_openwholewindow will in turn calculate any other coordinates necessary and call PROClib_openwindow. See PROClib_openwindow above for more details and information on window transiency. Note that as the call is routed through PROClib_openwholewindow, the window will always be opened at the front of the stack. EXAMPLE: PROClib_openwindowincentre(warning%,FALSE) This will open the entire window warning% in the centre of the screen (the window will be persistent). ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_windowopen PURPOSE: Check if a window is open PARAMETERS: On entry: 1. window handle On exit: 1. window status: TRUE = window is open FALSE = window is not open USAGE: This function can be used in all sorts of situations to check if a given window is open or not. For instance, suppose you are writing a music package, and every time a new track is loaded the control panel is opened. If you just call PROClib_openwindow then the window's position on the stack is corrupted. However, you can use: IF NOT FNlib_windowopen(panel%) THEN PROClib_openwindow(panel%,...) and the panel will only be opened if it isn't already on the screen. EXAMPLE: IF NOT FNlib_windowopen(main%) PROClib_closewindow(pane%) Supposing pane% is a pane on top of window main%, then if window main% mysteriously disappears from the screen, this makes sure that the pane is not left behind. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_closewindow PURPOSE: Close a window PARAMETERS: On entry: 1. window handle USAGE: This function closes the window given in P1, providing that the task approves - before closing a call is made to FNtask_closewindow, and the window will be closed only if this function returns TRUE. This is so that if the user clicks the close icon of a window containing edited data, the task has a chance to object by opening a warning window and returning FALSE. EXAMPLE: PROClib_closewindow(warning%) Closes the window whose handle is warning%. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_redrawwindow PURPOSE: Initiate a window redraw PARAMETERS: On entry: 1. pointer to block USAGE: PROClib_redrawwindow takes care of the Wimp's side of things when a window needs to be redrawn. The Wimp will split the window down into rectangular sections that need to be updated, and PROClib_redrawwindow will call PROCtask_redrawwindow with these coordinates after setting the graphics window appropriately. This is so that it doesn't matter if the task overlaps the redraw area, as it will never be displayed. PROCtask_redrawwindow will be called repeatedly until the window has been updated completely. A task can either just redraw the whole window, which removes all the calculations necessary but is rather sloppy and inefficient, or just the section that needs to be redrawn, which is faster but more complex. Normally, redrawing the whole window is acceptable, except for speed critical applications and programs such as art packages, which would become painfully slow to work with should they be programmed in this manner. On entry, the first word of the block should contain the window handle. All the coordinate information is filled in when NPLibrary calls SWI Wimp_RedrawWindow. PROClib_redrawwindow used to have to be called by the task when the Wimp returned a Redraw_Window_Request, but now polling is handled by NPLibrary, the task should not need to call this procedure. Use PROClib_forceredraw to update a window's contents. EXAMPLE: DIM temp% 44 !temp%=mainwindow% PROClib_redrawwindow(temp%) This allocates a block for NPLibrary to store all the window's coordinate information in (this uses 44 bytes of space). The first word is filled in with the window handle and the block pointer is then sent to PROClib_redrawwindow which then initiates the redraw. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_forceredraw PURPOSE: Redraw a whole window PARAMETERS: On entry: 1. window handle USAGE: This procedure is used to force an entire window to be redrawn. This is done by generating Window_Redraw_Request events to be sent to itself. When this happens, PROClib_poll will intercept the events and call PROClib_redrawwindow (described above) which in turn will call PROCtask_redrawwindow, where the window will actually be redrawn. As far as the task is concerned, this sort of window redraw is no different from any other - it is completely unaware that the event was generated by itself. PROClib_forceredraw will calculate the visible work area of the window whose handle is given in P1 and mark that area as invalid, thus forcing the whole window to be updated. This is the preferred way of redrawing a window. NPLibrary itself calls PROClib_forceredraw after deleting an icon from a window, so there is no need for the task to call it a second time. EXAMPLE: a$="Hello" PROClib_forceredraw(wind%) ... DEF PROCtask_redrawwindow(window%,xo%,yo%,x1%,y1%,x2%,y2%) CASE window% OF WHEN wind%:VDU 5:MOVE xo%+100,yo%+300:PRINT a$:VDU 4 ... ENDCASE ENDPROC This set up means that when window wind% is updated, the contents of variable a$ are printed at a scroll offset of (100,300). So when the task changes the contents of a$, the window needs to be updated to reflect this, which is what PROClib_forceredraw does here. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_changewindowtitle PURPOSE: Change the title of a window PARAMETERS: On entry: 1. window handle 2. new title USAGE: The title bar on a window is an indirected icon, but needs some extra help to be redrawn when its contents are changed, so this procedure will let you do so with ease. Simply supply the window handle in P1 and a string showing the new title bar contents in P2 and the icon will be changed and a Redraw_Window_Request will be generated for the title bar only (that is the top 36 pixels of the window). EXAMPLE: PROClib_changewindowtitle(main%,filename$) Assuming filename$ stores the filename of the currently edited document, then this will change and redraw the title bar of window main% to display that filename. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_windowtitle PURPOSE: Return the contents of an indirect window title PARAMETERS: On entry: 1. window handle On exit: 1. contents of title bar USAGE: This procedure is provided to let you check the contents of a window's indirected text only title bar icon. The actual textual content of the title bar icon of window P1 is what is returned. EXAMPLE: PROClib_changewindowtitle(main%,FNlib_windowtitle(main%)+" *") In RISC OS programs it is custom to add a '*' to the end of the contents of the title bar if the document being editing has been modified in anyway, and this command does just that - looks up the title of window main%, adds a space and an asterisk, and writes it back to window main%. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_bringtofront PURPOSE: Bring a window to the front PARAMETERS: On entry: 1. window handle USAGE: This procedure is slightly more subtle than you may think. It does two things: It sets a flag in the window data specifying that the window is now at the front of the stack If the window is closed, no further action is taken If the window is open, it is opened again at the front This effectively means that even if the window is closed, you can still move it to the front ready for the next time it is opened. FNlib_windowopen is called to check if a window is open or not. EXAMPLE: PROClib_bringtofront(warning%) Brings the window warning% to the front of the window stack. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_openfilerwindowifadjust PURPOSE: Check the mouse button status, and open a filer window if adjust is being held down PARAMETERS: On entry: 1. full pathname USAGE: In RISC OS 3 there is a new 'standard' feature of opening the parent window of a document when the document window is closed with adjust rather than select. To make your application support this, you need to add an extra command when NPLibrary notifies your task that it wants to close the document window. You should use the filename stored in the save box, check to see if it is valid, and if so call PROClib_openfilerwindowifadjust. If adjust is not depressed then control will return to the task and no action will be taken. If adjust is being depressed however, then NPLibrary will remove the leafname leafname from the end (the name of the actual file), leaving the pathname (the directory that the file is in) and attempt to open a filer window of that pathname. EXAMPLE: DEF FNtask_closewindow(window%) LOCAL ok%:ok%=TRUE CASE window% OF WHEN editwindow%: IF NOT lib_saved% THEN REM object if file not saved ok%=FALSE ELSE lib_saved%=-2 IF FNlib_validfilename($savename%) PROClib_openfilerwindowifadjust(s avename%) ENDIF ENDCASE =ok% Before PROClib_closewindow closes any windows, it calls FNtask_- closewindow first to make sure it is ok. This setup means that if NPLibrary wants to close window editwindow% (supposing that this is the main document window) then one of two things may occur: If the document has not been saved then FNtask_closewindow will return FALSE, terminating any action (and probably popping a warning window up), If the document has been saved, then FNtask_closewindow will return TRUE, allowing the window to be closed, but will first call PROClib_openfilerwindowifadjust to open the document's parent filer window if the user clicked adjust on the close icon. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_centrex PURPOSE: Get the x position a window would need to be plotted at to make it central to the screen edges on the x axis PARAMETERS: On entry: 1. window handle On exit: 1. x position USAGE: This function will find the width of the window and calculate what x position you would need to plot it at to make it central on the left and right screen edges. This function is mode independent since it reads the width of the mode and its x pixel ratio, so in large modes the window will not appear off to the left. If the window has a vertical scroll bar then this too is taken into account. The formula to work out the x position required is: width = ( visible area maximum x - visible area minimum x ) pixels = ( ( x pixels on screen - 1 ) * 2 ^ x eig shift factor ) window x position = ( pixels - width ) / 2 window x position = window x position + 40 if vertical scroll bar EXAMPLE: PROClib_openwholewindow(progress%,FNlib_centrex(progress%),0,FALSE) This will open the whole window progress% at the bottom of the screen centralized on the x axis. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_centrey PURPOSE: Get the y position a window would need to be plotted at to make it central to the screen edges on the y axis PARAMETERS: On entry: 1. window handle On exit: 1. y position USAGE: This function will find the height of the window and calculate what y position you would need to plot it at to make it central on the top and bottom screen edges. This function is mode independent since it reads the height of the mode and its y pixel ratio, so in large modes the window will not appear off to the bottom. The fact that a window may have a horizontal scroll bar is NOT taken into account. The formula to work out the y position required is: height = ( visible area maximum y - visible area minimum y ) pixels = ( ( y pixels on screen - 1 ) * 2 ^ y eig shift factor ) window y position = ( pixels - width ) / 2 EXAMPLE: PROClib_openwholewindow(progress%,0,FNlib_centrey(progress%),FALSE) This will open the whole window progress% on the left of the screen centralized on the y axis. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_setwindowheight PURPOSE: Sets the height of a window PARAMETERS: On entry: 1. window handle 2. new work area height USAGE: This procedure changes the height of the total work area. It does not change the size of the actual window on screen (visible work area), but will cause the scroll bars to be redrawn if the window is open. This sort of thing is normally done in applications like word processors when the text fills the available space. EXAMPLE: PROClib_setwindowheight(document%,FNlib_getwindowheight(document%)+5 00) This adds another 500 pixels onto the the bottom of the work area height of window document%. Note the call to FNlib_getwindowheight to find out how high the work area is already. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_setwindowwidth PURPOSE: Sets the width of a window PARAMETERS: On entry: 1. window handle 2. new work area width USAGE: This procedure changes the width of the total work area. It does not change the size of the actual window on screen (visible work area), but will cause the scroll bars to be redrawn if the window is open. This sort of thing is normally done in applications like word processors when the text fills the available space. EXAMPLE: PROClib_setwindowwidth(document%,950) Sets the width of the work area of window document% to be 950 pixels. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_getwindowheight PURPOSE: Gets the height of a window PARAMETERS: On entry: 1. window handle On exit: 1. height of window work area USAGE: This procedure can be used to find out the total height of a window's work area. It is used internally by PROClib_setwindowwidth (as the SWI Wimp_SetExtent which is used to alter work area size requires both the new width and new height). EXAMPLE: IF FNlib_getwindowheight(main%)>2000 THEN REM maximum size of document reached You can set a maximum height for a document and then object if the user tries to exceed it. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_getwindowwidth PURPOSE: Gets the width of a window PARAMETERS: On entry: 1. window handle On exit: 1. width of window work area USAGE: This procedure can be used to find out the total width of a window's work area. It is used internally by PROClib_setwindowheight (as the SWI Wimp_SetExtent which is used to alter work area size requires both the new width and the new height). EXAMPLE: IF FNlib_getwindowwidth(main%)>500 THEN REM maximum size of document reached You can set a maximum width for a document and then object if the user tries to exceed it. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_iconizewindow PURPOSE: Iconizes a window (RISC OS 3 only) PARAMETERS: On entry: 1. window handle 2. sprite name 3. icon text 4. block returned by PROClib_poll USAGE: This is one of the more luxurious offerings from NPLibrary. If you fail to include this in your program, then the window will be iconized anyway but a blank sprite will be used. However, putting this in at the appropriate place will allow you to use your own sprite plus a small description of the program underneath. In PROCpoll_receivemessage, you need to trap message number &400CC (it doesn't matter if the program is running on a RISC OS 2 machine, for this message will never be broadcast). Check the word at block+20, for this will contain the window handle of the window that the user wants to iconize on the pinboard. If it is a suitable window (NOT the preferences window etc.!), then call PROClib_iconizewindow with the same window handle, the name of the sprite you want to use (which should be present in your !Sprites/!Sprites22/!Sprites23 files), upto twelve characters to be written underneath the icon, and the pointer to the block you passed to PROClib_poll. The window will then be iconized. In the NPLibrary directory there are lo-res and hi-res versions of the blank iconized window icon. You should always use these as the basis of your own - they are the standard icons. EXAMPLE: DEF PROCpoll_receivemessage(message%) CASE message% OF WHEN 0:PROCtask_quit:END WHEN &400CC:IF work%!20=windmain% PROClib_iconizewindow(windmain%,"i c_main","My Program",work%) ENDCASE ENDPROC Assuming that PROClib_poll(work%) was called earlier, then this is how to iconize windows in your own programs. Don't call the procedure from anywhere else. ....................................................................MENUS.... PROCEDURE/FUNCTION NAME: FNlib_createmenu PURPOSE: Set up a menu structure PARAMETERS: On entry: 1. menu structure string 2. RETURNed variable (see P2 on exit) On exit: 1. menu handle 2. number of items in menu USAGE: This complex procedure will set up and link together a menu structure. The format of the menu structure string P1 is as follows: <title of menu>{|[vars]#<menu item>/<link>}| The section in curly brackets { } is repeated for every menu option. The first part is simple enough, and is just what is displayed in the title bar of the menu. If it is longer than twelve characters long, it will be truncated. Then, for each menu option: start with a '|' if you would like any options, specify them here. They are: D = Dotted line - draw a dotted line after this menu option U = Unselectable - this menu option is greyed out now add a '#' type in the name of the next menu item add a '/' the link parameter is next. This can be one of three things: for no link, type in an 'N' to link to another window, type in its handle variable (this means that all windows must be created before the menus) to link to another menu, type in its handle variable (this means that the deepest menu must be created first) Add a final '|' at the end to signify the end of the menu. Note that in order to uphold the RISC OS standards, I have not allowed you to change the colour or size of menus. Some examples will help to simplify matters a little. EXAMPLE: iconbarmenu%=FNlib_createmenu(task$+"|#Info/windinfo%|#Quit/N|",it%) Assuming task$ is the name of the task and windinfo% is the window handle of a standard info box, then this creates a standard icon bar menu of two options, "Info" leading off to an info box, and "Quit", linked to no other windows or menus. Somewhere further on in the program, there will be a check to see if the user clicked on "Quit" and if so, set a finish flag. The menu handle (which is actually its address in memory, but unique nevertheless) is returned in iconbarmenu% and the number of items in it%. submenu1%=FNlib_createmenu("Sub1|D#Option1/N|U#No way!/N|",subit%) mainmenu%=FNlib_createmenu("Main|#Hello/N|#Sub menu/submenu1%|",i2%) This first of all creates a menu with the title "Sub1" containing two options, "Option1" which has a dotted line after it, and then the option "No way!" which is greyed out. Then in the definition for mainmenu%, titled "Main", one option is "Hello" and the second is called "Sub menu", which is linked to the menu submenu1% (so it will have an arrow leading across into it). ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_openmenu PURPOSE: Display a menu on the screen PARAMETERS: On entry: 1. menu handle 2. display flag: -1 = display menu at pointer position items = this is icon bar menu - display at icon bar level USAGE: This will simply open up the menu whose handle is specified in P1 and set some flags in NPLibrary regarding which menu was last open. Normally menus are opened slightly left of the pointer, but on the icon bar, the bottom of all menus should be at the same level, and to work it out you need to specify the number of items in it. So, if -1 is specified in P2 it is assumed to be an ordinary menu, but if the number of items is specified, it is assumed to be the icon bar menu. EXAMPLE: IF (buttons% AND 2) AND window%=windmain% PROClib_openmenu(mainmenu% ,-1) If the user has pressed menu over the main window (assumed to be windmain%), then open up menu mainmenu%. IF (buttons% AND 2) AND window%=-2 PROClib_openmenu(iconbarmenu%,ico nbarmenuitems%) If the user has pressed menu over the icon bar (window handle -2), then open up menu iconbarmenu% at offset 96+(iconbarmenuitems%*44) from the bottom of the screen. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_getmenuselection PURPOSE: Return the user's menu choice in a textual representation PARAMETERS: On entry: 1. pointer to block returned by PROClib_poll On exit: 1. textual menu choice USAGE: This turns a list of menu structure choices returned by Wimp_Poll into text with periods in between submenus. PROClib_poll will call this for you automatically if there is a Menu_Selection event, so the task should not need to use this procedure. EXAMPLE: SYS "Wimp_Poll",0,work% TO reason% CASE reason% OF ... WHEN 9:PROCpoll_menuselection(FNlib_getmenuselection(work%),lib_last open%):PROClib_reopenmenuifadjust ... ENDCASE This is how PROClib_poll handles menu selection. As you can see, by the time it reaches the task, NPLibrary has already converted it into textual format. The returned text could be something of the form: Style.Font.Size.14pt (if using a DTP package) ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_reopenmenuifadjust PURPOSE: Check the mouse button status, and reopen the last menu if adjust is being held down PARAMETERS: None USAGE: There are two ways of choosing menu options. The user can press select in which case the menu will disappear, or he or she can press adjust, where the menu should stay on the screen. It is however up to the task to make sure that this happens. A call to this at the end of any menu selection procedure will ensure that if the user has pressed adjust then the menu will stay on the screen. This is now taken care of by PROClib_poll, so you should not need to use this procedure. EXAMPLE: PROCpoll_menuselection(FNlib_getmenuselection(work%),lib_lastopen%): PROClib_reopenmenuifadjust After the user has chosen something from a menu, this checks to see if he has used adjust rather than select, and if so the menu will remain on screen. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_menuselectable PURPOSE: Set whether a menu option is greyed out or selectable PARAMETERS: On entry: 1. menu handle 2. item number 3. selectability: TRUE = item is selectable FALSE = item is unselectable and greyed out USAGE: Sometimes you only want the user to perform certain actions when certain conditions have been met. You can prevent the user from choosing these options by greying out that part of the menu, or conversely, you can allow him to choose the options by making them selectable again, and that is the purpose of this procedure. The item number, P2, starts at zero for the first item on the menu, and increases by one for each item, so for a menu with six options on the last option would be number five. EXAMPLE: PROClib_menuselectable(edit%,3,undo%) Suppose that the fourth item on menu edit% is "Undo". This command will grey out or make selectable the "Undo" option depending on the contents of variable undo%. If undo% is TRUE, the item will be made selectable If undo% is FALSE, the item will be greyed out and unselectable ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_menutick PURPOSE: Select whether a menu option is ticked or not PARAMETERS: On entry: 1. menu handle 2. item number 3. tick status: TRUE = item is ticked FALSE = item is not ticked USAGE: You can tick or untick menu items to show whether certain options are selected or not. The user is able to toggle the state of the option by clicking on it, but sometimes the task may want to set it itself, and that is the purpose of this procedure. The item number, P2, starts at zero for the first item on the menu, and increases by one for each item, so for a menu with six options on the last option would be number five. EXAMPLE: PROClib_menutick(status%,2,autosave%) This ticks or unticks the third option on menu status% depending on the contents of variable autosave%. If autosave% is TRUE, the item will be ticked. If autosave% is FALSE, the item will be unticked. ............................................................FILE HANDLING.... File handling messages ---------------------- File handling is a very important and rather complex subject when it comes to writing desktop applications. NPLibrary simplifies matters enormously, reducing many many lines of code to just a few calls to procedures here and there. This section is not about NPLibrary as such, but about exactly how to get files into and out of your programs. MESSAGES The Wimp uses messages to communicate between itself and other tasks, and tasks between each other. Any task can create a message; some acknowledge things, others notify tasks of things the user has done, and others ask the task to do certain functions. The set of messages we are concerned with here are messages from the filer, which handles file transfer. THE DATA TRANSFER PROTOCOL The data transfer protocol is a set of messages that allow tasks to communicate with the filer and to get files to and from media. These messages all have names and numbers, and they are: 1 Message_DataSave 2 Message_DataSaveAck 3 Message_DataLoad 4 Message_DataLoadAck 13 Message_DataSaved 6 Message_RAMFetch 7 Message_RAMTransmit There is also a special message: 5 Message_DataOpen We are only concerned with messages 1-5. SAVING Between the user bringing up the save box and the file reaching the disk, many things occur: 1) After the user drags the file icon and releases the mouse button, the task will receive a User_Drag_Box event. 2) The task works out which window the pointer was over when the mouse button was released and sends a DataSave message to the filer containing information about the file. 3) The filer returns a DataSaveAck message, telling the task the full pathname of the file. 4) The task saves the file. LOADING Loading should be more straightforward, but is complicated by certain factors a little. Keeping it simple first, this is what happens when the user drags a file to the task's icon on the icon bar: 1) The filer sends a DataLoad message to the task. 2) The task loads the file. 3) The task sends back a DataLoadAck message, confirming a successful load. Things turn a little 'nasty' when the user double-clicks on a file: 1) The filer sends a DataOpen message to every task. 2) Any task that recognizes this type of file should proceed with steps 2 and 3 of the ordinary load. 3) If nobody claims the file (by replying with a DataLoadAck), then the filer *Runs the file. 4) If there is a system variable Alias$@RunType_xxx (where xxx is the hex filetype number), then the command in that variable will be executed. 5) If there is no such variable, the error "No run action specified for this filetype" will pop up on the screen. IMPLEMENTATION What this all boils down to is that to successfully load and save files in every way described, you need to put the following lines in your program: DEF PROCpoll_receivemessage(message%) CASE message% OF WHEN 0:PROCtask_quit:END Always include this line WHEN 2:PROClib_dosave(windsave%,2,work%) If DataSaveAck received call PROClib_dosave: windsave%=save box window handle; 2=writable icon handle; work%=PROClib_poll block pointer WHEN 3,5:PROClib_doload(work%,&123) If DataLoad/DataOpen received call PROClib_doload; work%=PROClib_poll block pointer; &123=filetype wanted ENDCASE ENDPROC DEF PROCpoll_checkmouse(mx%,my%,b%,window%,icon%) CASE window% OF WHEN save%:CASE icon% OF WHEN 0: 0=OK button icon handle IF (b% AND 4) PROClib_quicksave(save%,2) If select pressed, call PROClib_quicksave; save%=save box window handle; 2=writable icon WHEN 3: 3=file icon handle IF (b% AND 4) PROClib_savedragstart(save%,3) If select pressed, call PROClib_savedragstart; save%=save box window handle; 3=file icon handle ENDPROC DEF PROCpoll_drag(x1%,y1%,x2%,y2%) PROClib_tellfileraboutsave(size,&123,leaf$) When drag ends, call PROClib_tellfileraboutsave; size= estimated file size; &123=filetype; leaf$=leaf name of file ENDPROC DEF PROCtask_save(file$) ... PROClib_saved(TRUE) ENDPROC DEF PROCtask_load(file$) ... PROClib_saved(TRUE) ENDPROC That sorts out the message side of things. Now to make your program launch when the user double-clicks on a file of a type you want to recognize, add the following to your !Boot file: Set Alias$@RunType_xxx /<Obey$Dir>.!Run %%*0 (xxx=filetype number) If you didn't have a !Boot file, add: IconSprites <Obey$Dir>.!Sprites at the start to make the Wimp load the sprite file into the sprite pool. If you want to give the filetype a name, add: Set File$Type_xxx name (xxx=filetype number, name=name) The name will be truncated to eight characters. Now, the line in your !Run file that reads: Run <Obey$Dir>.!RunImage (or similar) change to read Run <Obey$Dir>.!RunImage %*0 (add the %*0 to the end) That lot will make your program launch, but to load the file the user has clicked on, add after your initialization routine: f$=FNgetparams IF FNlib_validfilename(f$) PROClib_saved(TRUE):IF FNtask_oktoload(f$) THEN PROCtask_load(f$) Now at the end of your program, add the routine: DEF FNgetparams LOCAL i%,space%,com% SYS "OS_GetEnv" TO com% i%=0 WHILE com%?i%<>0 i%+=1 ENDWHILE com%?i%=13 =MID$($com%,INSTR($com%,"!RunImage")+11) If your main file is not called !RunImage, change the leafname shown and make the number after it "LEN(leafname$)+2", so if your program is called Blob, the number becomes 6. This will get the program to load the file that the user clicked on. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_savedragstart PURPOSE: Initiate a save drag from the save box to a filer window PARAMETERS: On entry: 1. window handle 2. icon handle USAGE: This procedure is used when the user drags a file icon from a save box to a filer window, and is called when the user first depresses a button over the icon. P1 specifies the save window handle, and P2 the file icon handle (that is the one to be dragged). When dragging boxes, the Wimp must be told what the limits of movement are. Known as the parent box, no drag will be allowed to move outside of this box. PROClib_savedragstart assumes that you want to allow movement around the whole screen, so reads information for the current mode and uses that. This makes the procedure mode independent. EXAMPLE: DEF PROCpoll_mouse(mx%,my%,but%,wind%,icon%) CASE wind% OF WHEN savewind%:CASE icon% OF WHEN 3: IF (but% AND 4) PROClib_savedragstart(savewind%,3) ENDCASE ENDCASE ENDPROC This is the context that the procedure should be used in. Assuming that the file icon is icon number 3 in window savewind% (in my supplied Template2D and Template3D files, it is), then when the user depresses select over the file icon, a drag will commence. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_quicksave PURPOSE: Initiate a save from an OK click in the save box PARAMETERS: On entry: 1. window handle 2. icon handle USAGE: Usually to save a file, the user must drag the file icon in the save box to a destination filer window. However, if there is already a filename in the writable icon then a click on the OK button is all that is required. It is the job of this procedure to handle the saving of files when the user clicks on the OK button. The handles passed are the save box window handle in P1 and the writable icon handle in P2 (the one that contains the save filename). PROClib_quicksave will carry out the following actions: Check to see if the filename is a valid full pathname, and if not, issue the error "To save, drag the save icon to a directory display" and pass control back to the program. If the filename is valid, a call will be made to FNtask_oktosave to give the task a chance to object if it wants to. If it does, control is returned to the task. If the task does not object, a call will be made to PROCtask_save, where the file will be written. The save window will be closed. The menu structure (if open) will be closed. Control will pass back to the task. EXAMPLE: DEF PROCmouse(mx%,my%,but%,wind%,icon%) CASE wind% OF WHEN savewind%:CASE icon% OF WHEN 0: IF (but% AND 4) PROClib_quicksave(savewind%,2) ENDCASE ENDCASE ENDPROC This is the context that PROClib_quicksave should be used in. Supposing that icon 0 in the save box is the OK button and icon 2 is the writable icon containing the filename (both are in my supplied template files), then if the user depresses select over the OK button, PROClib_quicksave will be called with the window and icon handles of the filename icon and an attempt will be made to save the file there and then. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_tellfileraboutsave PURPOSE: Send save message to the filer PARAMETERS: On entry: 1. estimated size of file in bytes 2. filetype of file 3. filename of file USAGE: This procedure should be called when the user releases the mouse button after dragging the file icon to his or her chosen destination. When the user releases the mouse button, PROClib_poll will receive a User_Drag_Box event which it will route through PROCpoll_drag, so it is here where you should make the call. P1 is the estimated file size in bytes - do not worry if you don't have a clue how big the file is going to be, just use a number greater than zero and the filer will allocate more space if need be. Note that however small a file is, it will use up at least 2k of disk space, because programs always start at the beginning of a sector, and since there are 1024 bytes in a kilobyte, a minimum value of 2*1024=2048 bytes is recommended. P3 ought to be just the leafname of the file, but if you specify a full pathname, NPLibrary will chop any unnecessary bits off. EXAMPLE: DEF PROCpoll_drag(x1%,y1%,x2%,y2%) PROClib_tellfileraboutsave(2048,&FFF,$savefile%) ENDPROC Assuming that savefile% is the pointer to the save box's writable icon indirected text data, then when the user releases the mouse and terminates a drag, this will tell the filer that the task wants to save a 2k text file (filetype &FFF) called $savefile%. If $savefile% is a full pathname, then the leafname only will be extracted and used. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_dosave PURPOSE: Perform final checking before a save, then save PARAMETERS: On entry: 1. window handle 2. icon handle 3. pointer to block returned by PROClib_poll USAGE: After the filer has been notified about the task's need to save a file by PROClib_tellfileraboutsave, the filer will eventually get back to the task and acknowledge receipt of the message. Now is the time to actually call PROClib_dosave and save the file. The actual actions performed are as follows: Get the filename from the save box (the writable icon handle is P2 and the save box window handle is P1) and check that is valid. If it is not valid, report the error "Invalid filename" and abort the save. If it is valid, a call to FNtask_oktosave is made to give the task a chance to object to the save. If the task objects, control returns to the task. If the task does not object, the writable icon in the savebox is changed to reflect the new pathname of the file. The file is saved. The save window is closed. The menu structure (if open) is closed. Control returns to the task. EXAMPLE: DEF PROCpoll_receivemessage(message%) CASE message% OF WHEN 0:PROCtask_quit:END WHEN 2:PROClib_dosave(savewind%,2,work%) ENDCASE ENDPROC Assuming that work% is the pointer to the block returned by PROClib_poll, and that icon 2 in the save box is the writable icon containing the filename (which it is with my supplied template files), then when PROClib_poll receives the message Message_DataSaveAck, this will attempt to save the file. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_saved PURPOSE: Set the lib_saved% flag status PARAMETERS: On entry: 1. new status of save flag: TRUE = file has been saved FALSE = file has not been saved -2 = undefined USAGE: This flag is used by NPLibrary and can and should be used by the task to determine whether or not a file in memory has been saved. The saved flag should be set to undefined when there is no file in memory or when the user has tried to close a window containing edited and unsaved data, the task has objected and popped up an error window but the user has clicked on "Discard". You can quite easily just use the command: lib_saved%=<new status> but PROClib_saved performs the extra action of making a call to PROCtask_updatefilestatus, which should reflect the status of this flag in any "Modified?" icons or window titles (by adding an asterisk if the file has been edited) that need adjusting. If you call PROClib_saved but P1 is the same as lib_saved% was in the first place, PROCtask_updatefilestatus is not called. PROClib_saved should be found somewhere in PROCtask_save and PROCtask_load (you set the save flag to TRUE since the file has not been altered). EXAMPLE: DEF PROCtask_load(file$) SYS "OS_File",255,file$,filestore% PROClib_saved(TRUE) ... When you load a file, it has not been modified, so the saved flag needs to be set to TRUE. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_doload PURPOSE: Perform final checking before a load, then load PARAMETERS: On entry: 1. pointer to block returned by PROClib_poll 2. filetype: filetype = file loaded must be of this filetype -1 = file loaded can be of any filetype USAGE: This procedure should be called when loading a new file. The exact actions performed are as followed: If the filetype of the file requested is not the same as that in P2, control returns to the task and the load is aborted, unless P2 is -1. A call is made to FNtask_oktoload to give the task a chance to object to the load. If the task objects, no further action is taken. If the task does not object, a call is made to PROCtask_load, where the file is actually loaded. A message is sent to the filer informing it that the file has been loaded successfully. This last action is very important. While it is not important when the user drags the file onto your task's icon, if the user simply double- clicks on a file, the filer passes it round every task to see if anyone will claim it. If you load the file but then don't tell the filer, it will eventually *Run the file, which could cause another application to be launched if any Alias$@RunType_xxx variables are set. EXAMPLE: DEF PROCpoll_receivemessage(message%) CASE message% OF WHEN 0:PROCtask_quit:END WHEN 3,5:PROClib_doload(work%,&123) ENDCASE ENDPROC This is the context that PROClib_doload should be used in. Assuming that work% is the pointer to the block returned by PROClib_poll, then any double-click on or drag to the task's icon of files of type &123 will cause PROClib_doload to be called. Note there are two messages being trapped here, Message_DataLoad and Message_DataOpen. See the section on file handling messages for more information. ................................................................MISC WIMP.... PROCEDURE/FUNCTION NAME: PROClib_setcaretposition PURPOSE: Position the caret PARAMETERS: On entry: 1. window handle 2. icon handle 3. index into string USAGE: This will place the caret in writable icon P2 in window P1. No checks are actually made to ensure that the icon is writable, so the task must make sure that it is correct before calling the procedure. P3 specifies how many characters into the string written in the icon the caret should be placed, with 0 the beginning. EXAMPLE: PROClib_setcaretposition(pref%,9,4) This places the caret in icon 9 of window pref%, 4 characters into the string, so if the string read "HELLO", the caret would be between the "L" and the "O". ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_pointerinfo PURPOSE: Returns the window and icon the mouse pointer is currently in PARAMETERS: On entry: 1. RETURNed variable (see P1 on exit) 2. RETURNed variable (see P2 on exit) On exit: 1. window handle 2. icon handle USAGE: This procedure allows the task to find out exactly at the moment in time the procedure is called which window and icon the mouse pointer is over. This can be used if you want the pointer to change shape over writable icons etc. EXAMPLE: PROClib_pointerinfo(window%,icon%) This will make window% contain the window handle and icon% contain the icon handle that the mouse pointer is currently over. ............................................................................. PROCEDURE/FUNCTION NAME: PROClib_loadsprites PURPOSE: Initializes and loads sprites into NPLibrary's private sprite area PARAMETERS: On entry: 1. filename USAGE: When NPLibrary is first initialized with PROClib_initialize, the sprite pointer variable lib_sprites% is set to 1. This means that any sprites wanted will be looked for in the Wimp sprite pool. You may want to load up your own sprites that don't reside in this pool. If this is the case, one of the first procedures you should call after PROClib_initialize is PROClib_loadsprites. This will allocate a block of memory and load the sprite file specified into it. The variable lib_sprites% will be changed to contain the pointer to this new sprite block, which is where sprites will be looked for from now on. Note that you must call this only once, and before you attempt to load in any templates containing non-indirected sprite-only icons, otherwise it won't work. ............................................................MISC NON-WIMP.... PROCEDURE/FUNCTION NAME: FNlib_getstring PURPOSE: Extract string from memory PARAMETERS: On entry: 1. pointer to string On exit: 1. string found USAGE: This function will extract any string from memory, terminating at the point where the next byte is outside the range 33-126 inclusive, with the exception of byte 160 (hard space), which is sometimes used in filenames. This means that zero/CR-terminated strings will be correctly found, and no ordinary spaces are allowed (since a space has a code of 32). This function is often used to get filenames that are zero-terminated from their fields. EXAMPLE: str$=FNlib_getstring(pointer%) Puts the string at pointer% into variable str$. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_validfilename PURPOSE: Check if the passed filename is valid PARAMETERS: On entry: 1. filename On exit: 1. validity of filename TRUE = filename is valid FALSE = filename is invalid USAGE: This can be used on whole pathnames to check their validity. If there are no colons in the filename, FALSE is returned. If there are no periods in the filename, FALSE is returned. If the last character is a filename is a colon or a period, FALSE is returned. Otherwise, TRUE is returned. EXAMPLE: valid%=FNvalidfilename(file$) If filename file$ is valid according to the rules above, then valid% will hold the value TRUE. If not, it will hold FALSE. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_getleafname PURPOSE: Gets the leafname of a whole pathname PARAMETERS: On entry: 1. pathname On exit: 1. leafname USAGE: This will remove all filing system, drive and directory prefixes from a whole pathname, leaving just the actual filename of a file. EXAMPLE: leaf$=FNlib_getleafname("adfs::4.$.Music.Tracks.GoodSong") leaf$ will contain "GoodSong" on exit. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_getfiletype PURPOSE: Gets the filetype of a file PARAMETERS: On entry: 1. pathname On exit: 1. filetype USAGE: This function will return the filetype of any given file (the full pathname is required). Note that the filetype returned is a hexadecimal number and not a textual representation. EXAMPLE: type%=FNlib_getfiletype("scsifs::4.$.!System.Modules.Colours") (Colours is a module, an update to ColourTrans) type% would contain &FFA on exit (the filetype for "Module"). ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_gettimestamp PURPOSE: Get the datestamp from a file PARAMETERS: On entry: 1. pathname On exit: 1. date USAGE: This function will return the datestamp of any given file (the full pathname is required). The datestamp returned is in the format: DD-MM-YYYY EXAMPLE: date$=FNlib_gettimestamp("idefs::5.$.program") If idefs::5.$.program was created on 21 of May 1994, then date$ would contain: "21-May-1994" on exit. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_putbit PURPOSE: Change the value of a bit in a number PARAMETERS: On entry: 1. number 2. bit number 3. new value of bit On exit: 1. new number USAGE: This function is used mainly by NPLibrary when it is changing window, icon and menu flags, but can be used by the task if it wishes. It allows you to poke individual bits of a number with their new contents, so is most useful for changing flag contents. P2 is the number of the bit to change (the right-most or Least Significant Bit is bit 0, the next from the right is bit 1 and so on), and 3 is its new value, 0 or 1. EXAMPLE: newnum%=FNlib_putbit(57,3,0) This takes the number 57: %111001 (% is used to prefix binary numbers) clears bit 3: 543210 %111001 %110001 = 49 and puts the result into newnum%, so newnum% is equal to 49 on exit. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_bit PURPOSE: Get the value of a bit in a number PARAMETERS: On entry: 1. number 2. bit number On exit: 1. bit value USAGE: This function can be used to find out the value of individual bits in numbers. You supply the number in P1 and the number of the bit you want to peek in P2, and 0 or 1 is returned depending on the bit's value. EXAMPLE: bitvalue%=FNlib_bit(185,6) This takes the number 185: %10111001 examines bit 6: 76543210 %10111001 and puts the result into bitvalue%, so bitvalue% is equal to 0 on exit. ............................................................................. PROCEDURE/FUNCTION NAME: FNlib_roundup PURPOSE: Rounds up a whole number to the nearest multiple of another whole number PARAMETERS: On entry: 1. number 2. multiple to round up to On exit: 1. new number USAGE: Most command used to round up to the nearest word-aligned address when filling data blocks, this will round up any number to the nearest multiple of another. Note this function will always round up. EXAMPLE: round%=FNlib_roundup(8,3) round% will equal 9 round%=FNlib_roundup(85,4) round% will equal 88 ............................................................................. Skeleton program ---------------- Supplied with NPLibrary is a skeleton program which already contains many of the set ups mentioned in the above descriptions. Although the program doesn't actually do anything useful apart from provide an icon with the standard icon bar menu, all the hooks have been left in for file handling, window iconization etc. etc. All you need to do is copy it, change the sprite, add some window templates and you're off! Example program --------------- A quick example program is supplied demonstrating windows, icons, iconization, save boxes and sprites. Again it doesn't do anything useful, but could give a few clues if you come unstuck while trying to work something out. Credits ------- NPLibrary was written by Chris Coe of Norsoft Productions. You are allowed to use NPLibrary in your own programs, subject to the conditions outlined in the "Official Use" section at the start. I have just noticed that this file is 120k long - that's six times the length of the code! However, the code took longer to write so I'll personally castrate anyone who doesn't credit me or decides to change the author's name. Spleen vented, thank you. History ------- 1.00 - Pre-release version used in certain Norsoft Productions programs before official release 1.10 - Wimp_Poll loop taken over by NPLibrary - originally left to task to handle 1.11 - Sprite routines FNlib_putspriteinicon and PROClib_loadsprites added, and FNlib_loadtemplate and PROClib_initialize altered slightly to cater for the private sprite area.