OPL Challenge

Feel free to discuss any Organiser II related topic here
User avatar
MartinReid
Posts: 97
Joined: Wed Jan 27, 2021 3:44 pm

OPL Challenge

Post by MartinReid »

As the nights are drawing in and after reading Brian's introduction plus the statements by others about programming in OPL. I though I would put out a challenge to anyone wanting to practice their OPL.

The idea is to create a function that will return a string from a list of values, something like ListBox in an Excel spreadsheet.

The attached PDF outlines a specification for consideration.

To stop me waiting here like Billy no mates' can anyone taking up the 'challenge' please post below so everyone knows. If you are posting OPL's please REMark with Name and dates etc..

Always sincere
Martin
Attachments
FromListTips.pdf
Specification / Outline
(198.91 KiB) Downloaded 27 times
User avatar
Lostgallifreyan
Posts: 27
Joined: Fri Jun 11, 2021 2:52 pm

Re: OPL Challenge

Post by Lostgallifreyan »

Hi, I am working on a radio controller for the Icom PCR-1000 for now, so I can't go very deep into this, but I have some ideas that might help.

The main problem is the user modification. It rules out arrays because they waste a LOT of space when string lengths are very different, and they can't be stored easily for transfer to another machine or pack.

Data files can have large record counts and with just one field per record it's easy to save space, reference the string, and change the file. There are two vital points: ALWAYS use a RAM pack for each file (one per list), and you can only have up to four lists open. You may only need one at a time.

Prepare data files to go with the program, don't have the program create them because there would be a lot of duplicate data if you do that. A Windows text editor is ideal to make these files because you just put one string per line, and the CRLF line ending used when saving the file is the same thing the Organiser wants as record separator. Just make sure that the last line is also terminated, i.e CRLF at end of file. Rename as File.ODB then import it to the Organiser with anything that handles Organiser files.

Searching a large file is slow unless you keep track of where to start a search based on prior knowledge of something that lets you limit the scope, but I assume you only need to iterate through the list with the NEXT and BACK commands or use POSITION POS+N if you want to step through a large list in large steps.

Adding user entries will always put them at the end, so LAST then repeating BACK will scan for those if you know you need a recent entry to the list. Inserting new items at a current position in a list is VERY slow if the insertion is at the start of a long file, and the code to do it is larger than is justified except in logs that have records whose position must be preserved, like timestamps or ordered lists of radio frequencies. etc.. If you want alphanumeric sorting, it's best to do it as periodic maintenance, and several OPL programs can be found for sorting files.

Files are by far the best way to do this because the Organiser is dedicated to file handling as one of its most important abilities. There's a lot of support built in, and plenty added by others. You may find something that can act like a code library to solve a bulk problem like this.

Using VIEW() for records and EDIT for your user string lets you choose a new string, or return to what's still in the string if you press ON/Clear. EXE to select the string from the file by direct assignment of the string.

Once a file is OPEN, and USE has selected the right file if more than one is opened at once, this OPL procedure can navigate the records using the keys A~F without overshooting either end of the list:

Code: Select all

NAVREC:
REM One file open as A, one field per record as S$.
LOCAL K%,P%
WHILE KEY :ENDWH
WHILE 1
 IF EOF :CLS :PRINT"No Records Exist" :K%=GET
 ELSE K%=VIEW(1,A.S$)
 ENDIF
 P%=POS
 IF K%=1 :RETURN 0
 ELSEIF K%=65 :P%=1
 ELSEIF K%=66 :P%=COUNT
 ELSEIF K%=67 :P%=P%-10
 ELSEIF K%=68 :P%=P%+10
 ELSEIF K%=69 :P%=P%-1
 ELSEIF K%=70 :P%=P%+1
 ELSEIF K%=13 :RETURN P%
 ENDIF
 IF P%<1 :P%=1 :ENDIF
 IF P%>COUNT :P%=COUNT :ENDIF
 POSITION P%
ENDWH
If the ON key is pressed, 0 is returned, indicating that no selection was used.
If the EXE key is pressed, a nonzero return points to the selected record, and you can copy it to a string for editing. If the committed entry compares equal to the record, the string is accepted. If it is not, it is also accepted but you can prompt first to ask if the edited version is to be added to the list with APPEND. Deleting a record is also possible but I left out code for that to keep the template clear and easy to read.

A useful editor is this:

Code: Select all

TRAP EDIT E$ IF ERR=206 :RETURN :ENDIF
That lets you use ON twice, the first clears the string for new input, the second exits the editor and leaves the original string intact if you decide not to edit it.
User avatar
MartinReid
Posts: 97
Joined: Wed Jan 27, 2021 3:44 pm

OPL Challenge

Post by MartinReid »

I've learnt something already.. I've never tried 'TRAP' with 'EDIT'.. I see you've also used it in NavRec:(w%,h%) and LogEntry:(f%)

Jaap has some thoughts on using EDIT (here) and some code to place the cursor at the end of the item to be edited..

I am with you on storing the 'list' in a file and I'm coming round to each list having it's own file so the 'category' can be the file name.

I was considering putting all the lists in a single file with one list per record and using the first field to hold the category and the number of 'items' on the list. This would put all the lists in one place and allow them to be accessible at one time, but would limit the number of items to less than 16 - the maximum number of fields allowed. On reflection the function only needs one 'list' open at a time.

Original file storage idea... FromList.ODB

Code: Select all

"04-Weather","Sunny","Rain","Cloud","Fog"
"15-Coarse fish","Bream","Barbel","Carp",etc...
"08-Colour","Red","Yellow","Blue","Orange","Green","Violet","Cyan","Magenta"

Code: Select all

IF EXIST "A:FromList"
 OPEN "A:FromList",D,Cat$,fld1$,fld2$,...fld15
ELSEIF EXIST "B:FromList"
 OPEN etc...
ELSEIF EXIST "C:FromList"
 OPEN etc...
ELSE
 Manual Input 
ENDIF
For me the modifying any given 'list' will de done outside the 'utility' in Xfiles or Windows NotePad. In order to keep the sequence then another field can be added to hold a sequential number (in text) "01","02","03"..."10","11","12" that can be sorted in xFiles.

Code: Select all

OPEN "B:WhthrLST",C.No$,Df$
I also want the other items on the list to be 'set up' too, so the user can see what is coming up. At first I thought was this would be up and down...

Code: Select all

   Bream
>>>Barble
   Carp
etc..

But looking at the XP display on the PDF I quite like the left right idea..

Code: Select all

1234567890123456      12345678901234567890
eam >Barble< Car      Bream >Barble< Carp
This will need some clever string manipulation... something interesting to be getting on with..

I though of putting all the 'RETURNS' in a separate section at the end of the routine where I could put the 'CLOSE' statement. I don't want to have multiple 'CLOSE' statements scattered around which could cause 'mishaps'.

Anyway thanks for your contribution..
Always sincere
Martin
User avatar
Lostgallifreyan
Posts: 27
Joined: Fri Jun 11, 2021 2:52 pm

Re: OPL Challenge

Post by Lostgallifreyan »

Jaap's idea for putting the cursor at the end is nice. I used a system service call for editing in my EVENT logger system, and I can't remember if some argument to that places the cursor at the end. It might... I know I came across the idea somewhere before, but it might have been Jaap's thing...

About all lists in a single file, that might even work, if you only had 16 lists max. Consider your idea, then swap the axes. :) The FIRST record could have the categories, selected by iterating fields. Once a category is selected, then large numbers of entries may exist if you then iterate through records accessing only that field name. It could still be efficient because of the way records and fields are stored. THsi could be problematic for editing though, the latest edit goes on the end, so if it was category 16 (last field), and some other category had a greater number of entries, the current category would have gaps in it! You'd have to build an auto-scan to run through the entire file looking for whatever came after a gap. That's doable but the performance might be horrible. With a fixed system that did not allow editing it would be ok because when it hit a gap, it could know it was at the end of that list.

You mention editing outside the program, in advance of running it, so the method above might work well. Just make sure an empty field cannot be found until the end of the list when scanning with POSITION and reading fields.

If you need editing of lists inside the program, then separate files will have lower costs to operate even though it looks messy with lots of files. Sometimes we just have to play to the Organiser's strengths. If you use TextPad you can use TAB to separate the categories with their names on the top line, then each line below would have the list entries in columns. As TAB is the actual separator for fields in an ODB file when saved on a computer, this method is ideal, not least because the Block Select ability in TextPad can make it very easy to copy a column, sort it in a new window, then block-select the result to put it back in the ODB file.

That left/right idea might look good but I bet coding it would be hard, and it would not run fast. There are system services that could do the display efficiently but only as a string from which picking the substring would be tough. Up/down is the only practical way, so the fix is to scan back as easily as forward so a person can see what they missed. An LZ can make this similar to the original intent, and already does so with dir listings (but it's slower going backward for those).

For CLOSE and RETURN, it might be better to avoid the risk by strictly pairing OPEN and CLOSE, and using RETURN as a thing in its own right when it's needed (and not always just once at the end, as some coders insist on). It's less confusing to do open/close the way we do if/endif in a big program, and probably faster for the machine if it can free anything the moment it's done with it.
User avatar
MartinReid
Posts: 97
Joined: Wed Jan 27, 2021 3:44 pm

Re: OPL Challenge

Post by MartinReid »

I was pleased with the neatness of putting all the 'lists' in one file, but on reflection; once the datapak is 'MADE' no one is ever going to see it and indiviual 'list' files will be easier for the end user to copy to A: for modifying if the one supplied doesn't exactly match their needs. There will have to be a naming protocol to identify the lists when used with the Xfiles or Utils DIR function; I'm going to use NAMESlst.odb so that gives 5 characters for a meaningful 'list' name and lst to identify it as a FromLst$ file.

As for direction of scrolling the list.. Up and down is quite easy to produce and works well... But I have not given up on the Left - Right scrolling, but you are right is is complicated especially if you want to keep the 'selection' in the centre of the display..

Code: Select all

12345678901234567890		12345678901234567890
w,Blue>Orange<Green,		ike>Stickleback<Gudg
But it will make best use of the XP display.

Code: Select all

1234567890123456		1234567890123456
Blue>Orange<Gree		e>Stickleback<Gu
If I manage to get the left - right scrolling to work 'economically' then that will force me to make the FromLst$ function self identify which machine it is working on and adjust the screen output to suit. Another intetesting complication.

Gary.. if you are reading this then I'm going to implement this 'FromLst$' function in HamLog. So the user can select their values from a given list. With this in mind I will be looking a heads up on which of the 'log' entries can be 'predicted' and what 'values' should be offered as a selection...

Csign: No.. individual entry
Htz: ?
Mode: ?
Power: ?
Signal: ?

Again thanks for your thoughts.
Always sincere
Martin
User avatar
Lostgallifreyan
Posts: 27
Joined: Fri Jun 11, 2021 2:52 pm

Re: OPL Challenge

Post by Lostgallifreyan »

I think the horizontal scroll could be done but not easily. It would have to take a list file, count characters to build indexes, access the file directly as a large buffer, replace the tab and record separators with a single printable character, iterate though the buffer according to indexes gathered, then print directly to the screen buffer. It would then have to replace the original tab and record separators to preserve the file when it closed. If it copied the whole file it might avoid risk of corrupting an original but then time and space get used recklessly instead. Even in machine code this method of scrolling might be slow and take a very long time to code and test. I don't think the results would be worth the effort, on a machine with a CPU with a clock rate less than several tens of MHz. I think even the 16 bit Organisers didn't get something like this, and plenty of innovations happened there including scalable proportional width fonts (I made a multi-line text editor for a version of my EVENT logger on the WorkAbout), and even there the only scrolled-list menu type selection tool I can remember was the top line menu in the main built-in programs, where it was viable because there were very few choices, and they were permanently fixed. This method just doesn't scale up well, let alone easily accept customisation, because it rapidly becomes more complex than the rest of the program it's meant to support.

If an entire list has less than 255 characters it might work with the system service version of the VIEW function to do the scrolling, but only if you copied the list to a string, replaced record separators (0x90) with spaces, and if when pressing EXE the cursor position was noted so you can tell which substring it's in, then extract that from the whole string either by known index of start offsets or by searching for the spaces in both directions. Even this grossly reduced form would be painfully awkward in OPL, it would need to be entirely written in machine code to make it small and fast enough to use.
User avatar
MartinReid
Posts: 97
Joined: Wed Jan 27, 2021 3:44 pm

Completion..

Post by MartinReid »

OK...

I think I've got a working version... I'd be happy if members would test it and comment..

The Function is called FromLst$. The attached PDF outlines the considerations and instructions along with a fully documented listing.

The attached ZIP contains...
FromLst$.opl - a working version of the function without any REMarks 'use this'
FREMLst$.opl - another copy of the function documented with REMarks 'print this'
AP.OPL - an AT PRINT function needed to manage the screen output
TestLst.opl - a program that will test the FromLst$ function

FishLst.odb - three example 'Lst' database files used by the TestLst.opl programme
NumLst.odb
ToolsLst.odb

TestLst.opk - a Datapak image containing the above files that can be tested in Jaaps Jape Emulator - this is the easiest way to test it.

Always sincere
Martin
-
FromListTips.pdf
Documentation and listing
(352.74 KiB) Downloaded 17 times
FromLst.zip
Program and database files ZIP
(310.26 KiB) Downloaded 17 times
MartinP
Posts: 6
Joined: Tue Oct 05, 2021 7:01 pm

Re: OPL Challenge

Post by MartinP »

I tried this out, it works well. I think an improvement might be to move the selection line to the lower line when browsing back up the list. I think we can rely on human memory for the previous selection, but it's nice to see the next selection ahead.

I wonder if the MENUN command could be used with a one line menu for this? The menu list could still be filled from data files, the default selection could be put 1st and the add option could be last. I suppose it would limit us to 255 characters, but is this that bad?
User avatar
MartinReid
Posts: 97
Joined: Wed Jan 27, 2021 3:44 pm

FromLst$:() use in PFotoPAK

Post by MartinReid »

Thank you for reviewing that Martin, it is reasuring to get someone else's views. I'm committed now as I've integrated it in to the PFotoPAK where it has simplified its use.

Those interested who would like to have a look can upload the attached PFotoPAK.OPK into Jaaps' Jape Emulator (here) - select an LZ model and don't forget to set the clock, there's a manual (here) .

Your thoughts on using MENUN are interesting. You may know I was interested in a 'horizontal' scrolling selection list, to help make it suitable for use on a two line XP machine. As we know MENUN is not implemented in XP OPL but there might be some mileage in testing MENU(). If the number of characters in the 'menu' list come anywhere close to 255 then it is too large to be helpful/usable. Of course the MENU command has the added benefit of allowing 'first character selection' of items on the list.

Anyway again thank you for your thoughts.
Always sincere
Martin
-
PFotoPAK.OPK
Programme Pack Image for use in Jape
(13.28 KiB) Downloaded 12 times
hawsey
Posts: 42
Joined: Fri Jul 02, 2021 12:34 am

Re: OPL Challenge

Post by hawsey »

MartinReid wrote: Tue Oct 05, 2021 12:48 pm

Gary.. if you are reading this then I'm going to implement this 'FromLst$' function in HamLog. So the user can select their values from a given list. With this in mind I will be looking a heads up on which of the 'log' entries can be 'predicted' and what 'values' should be offered as a selection...

Csign: No.. individual entry
Htz: ?
Mode: ?
Power: ?
Signal: ?

Again thanks for your thoughts.
Always sincere
Martin
Hi Martin,
Yes I'm still here
, that is a great idea, I had thought to ask you something similar but didn't like to ask as you had done so much work already, thank you again.
You will be needing another PAK so I can test :D
Post Reply