Take a Hint!

First published in QL Today V10/I3/p21

Now that the "new" Easy Pointer keywords MCALLT and RPTR have been properly implemented and debugged, thanks to Marcel Kilgus, it is possible also for Easy Pointer programmers to create pop-up help or Hint windows.

You need the latest version of Easy Menu, ie at least V4.09, and the ptrmen_cde toolkit (of one sort or another) of at least V4.05.

The program below contains all you need to implement basic hinting in your own programs. A slightly more developed and generalised version of this program will be available on my web site, knoware, shortly. It is basically the same as the routine below but allows for long hint texts by semi-automatically splitting long lines.

The first part of the program is a harness to enable you to test the routines. However, to get this program to work you first need to create two menu definitions in Easy Menu.

The first one is a simple dialog window with two loose items (buttons) and a Menu Application Window. You may already have a menu in your library that you could use for this. If not, it is easy enough to make your own in a couple of minutes. It should look something like the one shown below.

hintdemo 1

It doesnt have to be pretty, just make sure all the elements are big enough to display the sub-elements, otherwise you will have problems later. Here Ive created a 128x148 window, which is more than ample.

Ive set the internal Move sprite as the object for the first 18x18 button and set its selection code to 5 (not the character '5' but the code). This latter means that Easy Pointer will treat a click automatically as a Window Move request.

Sadly there is no standard Escape sprite, so Ive entered the text ESC in the second, 24x18, button. Its selection code is 27. Just for decoration Ive added an Information Window containing an Information Object consisting of the text displayed. Finally, a large, menuless Application Window takes up the remaining space. Ive called this Menu Definition 'hintdemo' and saved it as 'hintdemo_men'.

The second Menu Definition is more useful as this can be re-used wherever you need hinting. Of course, you dont have to use a menu for this; you could just use a standard console instead. But using a menu is just simpler as it takes care of the pointer sprite, shadow, etc.

First consider the pointer sprite for this menu. We dont really want to see a pointer at all, although theres got to be one present. So the thing to do is to create a null sprite, ie the smallest possible, invisible, sprite.

Use Easy Sprite to create a single pixel, transparent sprite. (It may be necessary to make it 2x1 for use on non-SMSQ/E systems.) The new, second generation pointer driver can cope with a 0x0 sprite, but this cannot be created with Easy Pointer directly, so we'll leave that as an exercise for the more adventurous reader.

Now fire up Easy Menu and load the saved null sprite into the program. Set that sprite to be the pointer sprite for the present menu definition. (How? With Outline set as the item to work with, choose Object; select the null sprite, click Ok.)

Next choose the outline Attributes and set the window colour to Hint bg, and the border to Hint Border. No need to fiddle with any other attributes. Finally DO the Change menu to bring up the outline window metrics and enter the following data into the table:

No.     X       Y       X0      Y0    Object
--- - ----- - ----- - ----- - ----- -----------
 1  4    24 4    12 0   250 0    92 -> spr

The significant columns here are columns 2 to 5. The rest can be left alone. The '4' in columns 2 and 4 signify that the subsequent dimension can be varied freely, ie the window can be any size larger than 23 x 11 pixels. Finally call your menu 'hint' and save it.

For the sake of the demonstration, put the hintdemo_men and hint_men file in a folder with the program file and set the directory in line 1 of the program below accordingly. In the real world youd add the menus to an app-file or append them to your program file in some other way.

Type in the numbered lines below and youre ready to rock!

The Pop-up program

1 dir$ = 'win1_prg_hint_': rem Home directory
2 :
3 sp_hintbg% = 553: rem Hint background
4 sp_hintfg% = 554: rem Hint foreground
5 :

Its useful to have the above palette colour codes predefined as it saves you having to remember the numbers. On my website you can find the whole list; just copy the definitions and paste them into your program as required.

The next few lines are the harness, although you will need to add some of the definitions further down to the initialisation part of your own code to make the pop-up routines work.

6 dim dat$(6, 12)
7 for i% = 0 to dimn(dat$): dat$(i%) = 'Data ' & i%
8 :
9 ch% = fopen(#0; 'con_')
10 mdraw#ch%; dir$ & 'hintdemo_men'
11 mawdraw#ch%; 1, dat$
12 :

The following must be initialised before using these routines, ie put them in the initialisation part of your program.

13 timep% = 100: rem Timeout before pop-up
14 timed% = 300: rem Pop-up display time
15 ev% = 0: rem Events
16 it% = 1000: lit% = it%: rem Current and last items
17 dim pv%(15): rem Init pointer record
18 :
19 wsa = mwdef(#ch%): cia = peek_l(wsa)+ 48: rem Ptr to current item
20 :

Example of use:

21 rep main
22 item = mcallt(#ch%, ev%, timep%)

'item' contains the result of any clicked object - unless nothing was clicked and the routine simply timed out after timep% frames. In that case item contains the code -1280 (see below)

23 pval#ch%; pv%: rem Read the pointer record into array
24 if item = -1280 then
25 rem timed out
26 lit% = it%
27 if pv%(2) = 0 then
28 it% = 10

The Application Window number is returned in pv%(2) (counting starts at 0, with -1 being none). Here we could calculate the element number and show a different hint for each menu item. Ive just given a general ID for the whole Application Window.

29 else
30 it% = peek_w(cia) * pv%(2)

it% is the current (highlighted) item - peeked from the Working Definition.

31 endif
32 if it% = lit%: next main
33 :

Line 32 above implies: Dont display the same item twice in succession.

34 sel on it%
35 = 0: Pop 'Move Window'
36 = -1: Pop 'Quit Program'
37 = 10: Pop 'Appwin'
38 = remainder: Pop 'Hint demo'
39 endsel
40 next main

The above is what happens when MCALLT times out. Depending on the current item or other return code, a pop-up window is generated with the text provided.

41 else
42 if item < 0 then
43 select on item
44 = -1: rem Wmove (but program never gets here)
45 = -2: quit
46 endsel
47 endif
48 endif
49 endrep main
50 :

The above are the normal action routines. The program only arrives there if an object was actually hit. The next bit is the main pop-up routine. It was written to act as a general utility that could be used without too much fuss, so the only parameter you need to supply to the routine is the text you want to display. It takes care of the position and size of the window by itself.

51 defproc Pop(txt$)
52 loc cp%, l%, x%, y%, xs%
53 rem V0.01 March 1st 2005
54 :
55 x% = pv%(14): y% = pv%(15)

Get current pointer x and y coordinates

56 l% = len(txt$) * 6 + 4: rem csize 0, 0
57 xs% = x% - (l% div 2): if xs% < 1: xs% = 1

Calculate window x size in pixels

58 :
59 cp% = fopen('con_')
60 mdraw#cp%; dir$ & 'hint_men', xs%, y% + 2, l%, 12

Display window. Stretch x dimension to fit text

61 wm_ink#cp%; sp_hintfg%: wm_paper#cp%; sp_hintbg%
62 cursor#cp%; 2, 1: print#cp%; txt$;

Display hint text, using designated palette colours

63 rdpt#cp%, 11, x%, y% + 2, timed%

Wait for pointer move, a click or timeout, and then..

64 mclear#cp%: close#cp%


65 enddef Pop
66 :
hintdemo 2

To test, let the pointer rest on one of the objects, ie one of the buttons, the Application Window, or the main window itself. After timep% frames the hint should display for timed% frames or until the pointer is moved. Note that you wont get a hint twice in a row; you have to visit another object first before you can coax a second hint from the first object. Enjoy! (And please write lots of lovely pointer programs for us all to enjoy).

The program and associated menus can be downloaded here. A slightly more advanced version of the program can be found here (Pox).

©pjwitte November 6th 2005