---------------------------------------------------------
Brosco's Liberty Basic Newsletter - Issue #6 - May 98
---------------------------------------------------------

In this issue 
        1) Writing a replacement for Notepad in LB

OK, I know that Notepad does a fine job, plus there are hundreds
of freeware and shareware versions of Notepad available.  I choose
this program for exactly this reason.  Everybody knows what 
Notepad does!  But we will put in a few extra features 
like wordwrap, spell checker and a graphic toolbar.

When I write a program like this, I first write the skeleton code of
how I would like the Window to look.  I make sure that I have this 
exactly the way I want it before coding any of the functions.

Here's the skeleton code:

    open "user" for dll as #user

    nomainwin
    WindowWidth = 640                   ' *** Note 1
    WindowHeight = 480
    UpperLeftX = 1                      ' *** Note 2
    UpperLeftY = 1

    filename$ = DefaultDir$ + "\untitled.txt"

    menu #w, "&File", _
        "&New", [new.file], _
        "&Open ...", [open.file], _     ' *** Note 3
        "&Save", [save.file], _
        "Save &As ...", [save.as], _
        |, _
        "E&xit", [close.w]
    menu #w, "&Edit"                    ' *** Note 4
    menu #w, "&Options", _
        "&WordWrap", [word.wrap], _
        "&Spell Check", [spell.check]

    menu #w, "&Help", _
        "&About", [about]

    graphicBox #w.tb, 0, 0, 632, 24      ' *** Note 5

    textEditor #w.txt, 0, 24, 632, 407   ' *** Note 6

    open "LB NotePad" for window as #w

    print #w, "trapclose [close.w]"
    print #w.txt, "!autoresize"         ' *** Note 7

    print #w.tb, "fill yellow;flush"

    gosub [TitleBar]

[loop]
    input var$
    goto [loop]
                                        ' *** Note 8
[new.file]
    notice "Not implemented yet"
    goto [loop]

[open.file]
    notice "Not implemented yet"
    goto [loop]

[save.file]
    notice "Not Implemented yet"
    goto [loop]

[save.as]
    notice "Not implemented yet"
    goto [loop]

[word.wrap]
    notice "Not implemented yet"
    goto [loop]

[spell.check]
    notice "Not implemented yet"
    goto [loop]

[about]
    notice "About LB Notepad" + _
        chr$(13) + "LB Notepad Version 1.00" + _
        chr$(13) + "Demonstration by Brosco" + _
        chr$(13) + "           May 98"
    goto [loop]

[TitleBar]
    title$ = "LB Notepad: " + filename$ 
    h = hwnd(#w)
    calldll #user, "SetWindowText", _
        h as word, _
        title$ as ptr, _
        result as void
    return

[close.w]
    close #w
    close #user
    END

*** Note 1
    WindowWidth = 640                   ' *** Note 1
    WindowHeight = 480
I have set the Window Width and Height to the size of the smallest
display commonly supported by Windows - you can, of course change
this.

*** Note 2
    UpperLeftX = 1                      ' *** Note 2
    UpperLeftY = 1
If the user has a bigger screen than 640x480, the UpperLeftX,Y 
will force the window into the top left corner.  If I had used
values of 0,0 - the window would be 'free floating'

*** Note 3
        "&Open ...", [open.file], _     ' *** Note 3
For the MENU Item 'OPEN' I have also put '...' in the item title.
This is a Window's convention.  The '...' indicates to the user
that if he selects this option he will be presented with a Dialog
requesting further information.

*** Note 4
    menu #w, "&Edit"                    ' *** Note 4
The TextEditor control automatically generates an "Edit" menu
for us.  By placing this here, we are simply placing the "Edit"
menu item where we want it to appear on the MenuBar.

*** Note 5
    graphicBox #w.tb, 0, 0, 632, 24     ' *** Note 5
The GraphicBox is where we will be placing the Graphic toolbar.

*** Note 6
    textEditor #w.txt, 0, 24, 632, 407   ' *** Note 6
The TextEditor control is given dimensions to neatly take up all
the remaining visible window.

*** Note 7
    print #w.txt, "!autoresize"         ' *** Note 7
The 'autoresize' command will resize the TextEditor control in 
case the user resizes the Window.

*** Note 8
[new.file]
    notice "Not implemented yet"
    goto [loop]
I now code all of the functions with a 'Not implemented yet' 
message.  This allows me to test the way the program will look
to my user.


This is what we call a prototype - if I was developing this
program for someone else, I could demo it to them  
to ensure that I had understood their requirements.

Now we can start coding the functions. First the 'New File'
function:

[new.file]
    gosub [isModified]
    if modified.result = 2 then goto [loop]

    print #w.txt, "!cls";

    gosub [getLastDir]
    filename$ = lastPath$ + "untitled.txt"
    gosub [TitleBar]
    goto [loop]

First we use a subroutine to test if the contents of the TextEditor
box have been modified.  We will get to this in a moment, but just
accept the fact that if the user decides to CANCEL this option, 
'modified.result' will have a value of 2 - and so we stop any 
further processing.  We then 'clear' the screen.  
The [getLastDir] subroutine is used to split a filename into 
Path info and the 8.3 name.  The default filename$ for the new file 
is the Current Directory plus "untitled.txt".  This is written to 
the TitleBar with the [TitleBar] subroutine.

[isModified]
    modified.result = 0
    print #w.txt, "!modified?";
    input #w.txt, ans$
    if ans$ = "false" then return

    h=hwnd(#w)
    wtype = 4131            ' Yes, No, Cancel
    message$ = "The text in " + filename$ + " has changed." + _
                chr$(13) +"Do you wish to save these changes?"
    title$ = "LB NotePad"
    sound = _MB_ICONQUESTION
    calldll #user, "MessageBeep", _
        sound as word, _
        result as void
    calldll #user, "Messagebox", _
        h as word, _
        message$ as ptr, _
        title$ as ptr, _
        wtype as word, _
        modified.result as short

' Possible modified.result values are
' 2 = Cancel Button Pushed
' 6 = Yes Button Pushed
' 7 = No Button Pushed

    if modified.result = 6 then gosub [save.changes]
    return

The [isModified] routine checks to see if the contents of the 
TextEditor control has been modified.  If not - no further 
processing is performed by this subroutine.

If it has - the user is presented with a MessageBox to determine 
what action should be taken.  If the user requests the 
changes to be saved (modified.result=6) the subroutine:
[save.changes] is called.

[save.changes]
    print #w.txt, "!contents?";
    input #w.txt, txt$
    print #w.txt, "!origin?";
    input #w.txt, row, column

    open filename$ for output as #f
    print #f, txt$
    close #f
'                   Reset the Window's Modified flag
    print #w.txt, "!cls";
    print #w.txt, "!contents txt$";
'                   Restore scroll position
    print #w.txt, "!origin ";row;" ";column;
    return

[save.changes] retrieves the contents of the TextEditor and also the 
'scroll' position within the text.  The text contents are written to
a file, then the contents are 'rePrinted' to the control so that
the 'modified' flag is reset.  Finally, the scroll position is
restored.

[getLastDir]
    lastPath$ = DefaultDir$
    lastFile$ = filename$
    slash = instr(filename$, "\", 1)
    while slash <> 0
        lastSlash = slash
        slash = instr(filename$, "\", lastSlash + 1)
        wend
    if lastSlash = 0 then return
    lastPath$ = left$(filename$, lastSlash)
    lastFile$ = right$(filename$, len(filename$) - lastSlash)
    return

[getLastDir] simply splits the full filename into its components of
Path and File.

[open.file]
    gosub [isModified]
    if modified.result = 2 then goto [loop]

    gosub [getLastDir]
    fileDialog "Open File", lastPath$ + "*.txt", newFilename$
    if newFilename$ = "" then goto [loop]

    filename$ = newFilename$
    open filename$ for input as #f
    txt$ = input$(#f, lof(#f))
    close #f

    print #w.txt, "!cls";
    print #w.txt, "!contents txt$";
    gosub [TitleBar]
    goto [loop]

[open.file] first tests if the current contents of the control
have been modified.  This processing is the same as discussed
for [new.file].
Then we split the last filename into path and file.  This is done
so that the FileDialog will start at the last directory that was
used for saving or loading a file.
We then load the file, display it and finally, update the Titlebar
of the Window.

[save.file]
    gosub [save.changes]
    goto [loop]

[save.file] is very easy - we don't have to perform any checking -
we simply save the file.

[save.as]
    fileDialog "Open File", filename$, newFilename$
    if newFilename$ = "" then goto [loop]

    filename$ = newFilename$
    gosub [save.changes]
    gosub [TitleBar]
    goto [loop]

[save.as] presents the user with a fileDialog, but uses the
existing filename as the default.  If the user continues with 
this option - the file is saved with the new name and the 
TitleBar is updated.


In the next issue of the newsletter we will add the Graphics
Toolbar, WordWrap and the Spellchecker.  To test the program 
as it currently stands - you can cut and paste each of the 
functions discussed into the skeleton program, or you
can download the complete program from:

http://users.orac.net.au/~brosco/newsltr/lbnote.zip

This zip file also conatains a TKN file of the final program -
you will get the source next issue.


If you have any questions about the program, please post them on
my message board at:

http://users.orac.net.au/~brosco


--------------------------------------------------------------
 Newsletter written by: Brosco.
 Comments, requests or corrections mailto:brosco@orac.net.au

 Translated from Australian to English by an American:
 Alyce Watson -  Chief Editor.  Thanks Alyce.