Custom Controls in a Box (- lbjoseph lbjoseph)

Making your own custom control with a graphicbox in Liberty BASIC.


Throughout the ages, mankind has sought after customization and personalization. Now, with the power of Liberty BASIC 4, you can create your very own custom control inside of a simple graphicbox. The following article expects you to be familiar with the Liberty BASIC language, as well as with Liberty BASIC's native drawing commands.

In this article, we will discuss the techniques that I (- lbjoseph lbjoseph) think are necessary to creating a good custom control.


Why a custom control?

Because you can. But there's more to it than that - by creating your own custom control, it's look and feel will stay consistent throughout all the various versions of windows. Secondly, you can make them much easier to use than the windows API controls. It is also possible to setup your custom control's functions/subs without global variables (depending on what kind of control you make). Another advantage of custom controls is that they do not require a huge wrapper of subs and functions to deal with the windows API calls, callbacks, messages, and so on.

The container

First of all, we need some sort of object that we can manipulate to turn into our own object. The Liberty BASIC graphicbox is just the thing. Not only does it let you draw on it with LB's native drawing commands, but it lets you set event handlers to branch labels or subs when it is clicked, etc. This allows you to make a click-able control that looks beautiful to the eyes (some sarcasm implied).

The foundation of what we want

In this article we'll walk through custom control creation by creating a "fake" hyperlink control. There's a couple of things we want specifically from this control:

  1. It needs to have a roll-over effect (becomes underlined upon mouse-over)
  2. We want to be able to create as many as we like
  3. And we want it to specify it's properties upon creation - like background color, text color, font, etc.

So, let's go ahead and create the basis of our program. We'll need a window with a graphicbox in place and a trapclose event setup so our program will actually close when someone hits the little red x.

If we wanted to have more than one hyperlink, we'd make a graphicbox for every link we want. More on that later.
'Make a custom control hyperlink with a Liberty BASIC graphicbox.
'-----------------------------------------------------------------'
 
    [SetupWindow]
        NoMainWin
        WindowWidth = 400
        WindowHeight = 200
        UpperLeftX = Int((DisplayWidth-WindowWidth)/2)
        UpperLeftY = Int((DisplayHeight-WindowHeight)/2)
 
        Link1.Width = 180
        Link1.Height = 28
 
        GraphicBox #Win.Link1, 4, 4, Link.Width+20, Link.Height+10
        Stylebits #Win.Link1, 0, _WS_BORDER, 0, 0
 
        Open "Hyperlink Custom Control" For Window As #Win
 
        #Win, "TrapClose [Quit.Win]"
 
    Wait
 
    [Quit.Win]
        Close #Win
    End
 
    [Link1.Click]
    Wait
 
If you run the code above, things don't look too promising. However, this is just the foundation of our program.

There's a couple of things you need to note about the above code:

First, notice in the "GraphicBox" command that we added 20 to the width, and added 10 to the height. This just gives us a little extra room to avoid client-size clipping issues.

Secondly, we issued a "Stylebits" Command - we used the flag _WS_BORDER in the removeBits section. This removes the border of the graphicbox. This command is necessary to remove clutter which could mess up the way our control looks (especially in a dialog window).

Now we have the foundation of a custom control - a graphicbox at the right size without a border.

Data management

Here's where the fun begins. We know we need several parameters to create a hyperlink:

  1. We need the handle to the "parent" graphicbox container. We'll call this variable "gbHndl$". In our case, the programmer would pass the value "#Win.Link1" into the function.
  2. We need the text for the hyperlink - we'll call this "text$"
  3. We need to know what font to use - we'll call this "font$"
  4. We need to know the background color of the window the link is on (so it won't look ugly) - we'll call this "backcolor$"
  5. We need to know what color to make the hyperlink -we'll call this "linkcolor$"
  6. We need the name of the sub or branch label that contains the user's code to execute upon clicking the link. We'll call this "eventClick$". In our case, the programmer would pass the value "[Link1.Click]" into the function.
  7. We'll need the name of the sub or branch label that contains the user's code to execute when the mouse moves over the link. We'll call this eventMove$

We also know that each hyperlink needs to store the above parameters so it can be rendered. The hyperlink also needs to know what state it is in - whether or not is "active". We'll call this hlinkActive. We'll keep it set to 0 when the mouse isn't over the hyperlink, and we'll set it to 1 when the mouse is over the hyperlink. That way, we'll only need to re-render the hyperlink when the value of hlinkActive changes. This reduces flickering in the graphicbox. We'll also calculate the height of the specified font internally. We'll call this fontHeight.

The guts of our hyperlink program

Here's the updated program (heavily commented) with the sub and functions required for the hyperlink:
    [SetupWindow]
        NoMainWin
        WindowWidth = 400
        WindowHeight = 200
        UpperLeftX = Int((DisplayWidth-WindowWidth)/2)
        UpperLeftY = Int((DisplayHeight-WindowHeight)/2)
 
        Link1.Width = 180
        Link1.Height = 28
 
        GraphicBox #Win.Link1, 4, 4, Link1.Width+20, Link1.Height+10
        Stylebits #Win.Link1, 0, _WS_BORDER, 0, 0
 
        Open "Hyperlink Custom Control" For Window As #Win
 
        #Win, "TrapClose [Quit.Win]"
 
        Link1$ = cCc.Hyperlink$("#Win.Link1", "Link 1 Text", "Arial 10", "buttonface", "blue", "[Link1.Click]", "[Link1.Move]")
    Wait
 
    [Quit.Win]
        Close #Win
    End
 
    [Link1.Click]
        Notice "You clicked Link 1."
    Wait
 
    [Link1.Move]
        Call cC.RollHyperlink Link1$, MouseX, MouseY
    Wait
 
 
    Function cCc.Hyperlink$(gbHndl$, text$, font$, backcolor$, linkcolor$, eventClick$, eventMove$)
 
        #gbHndl$, "CLS; Down; Fill ";backcolor$ 'Clear the graphicbox and fill it with the specified backcolor.
 
        'We need the height of the current font in pixels. Here's an easy way:
            #gbHndl$, "Place -100 -100 " 'Place pen offscreen
            #gbHndl$, "| " 'Print a blank line.
            #gbHndl$, "PosXY penX penY" 'Get the coordinates of the pen. After drawing text, the pen moves down the proper
                'height to make room for another line. Just subtract the end position from the start position to get the height
                'of the font:
            fontHeight = penY-(-100) 'And it works, if you print the results out!
        '--------------------------------------------------------------------'
 
        #gbHndl$, "CLS; Down; Fill ";backcolor$;"; Flush" 'Redo the intial thing just in case and this time flush it
            'so the graphics will stick.
        #gbHndl$, "Font ";font$;" ; Color ";linkcolor$;" ; BackColor ";backcolor$ 'Set the font, foreground and background
            'color.
 
        #gbHndl$, "Place 4 ";fontHeight+2 'Set the pen at the proper location so the text will draw correctly in the
            'graphicbox.
            'Notice the text will start at the far left of the gbox, just like statictext would.
 
        #gbHndl$, "|"; text$ 'Draw the text!
 
        #gbHndl$, "Flush DefaultText" 'Make this drawing stick. And, give this drawing (segment) the name DefaultText .
 
        #gbHndl$, "when leftButtonUp "; eventClick$ 'Set the graphicbox to jump to the branch label/sub that the user
            'specified when the link/graphicbox is clicked.
        #gbHndl$, "when mouseMove "; eventMove$
 
        'Now, return the handle to a hyperlink so the user can pass it to the hyperlink functions:
 
        hlinkActive = 0 'The hyperlink isn't active just yet.
 
        'Return all the info as one big string of data seperated by spaces. We'll parse this using word$() in another
        'function. This allows the user to have more or less a "handle" to a link.
 
        font$ = Sys.ReplaceChar$(font$," ","ø") 'Replace any spaces in the font text with a weird symbol, so we can parse the
            'handle with word$() in another function.
 
        text$ = Sys.ReplaceChar$(text$," ","ø") 'Do the same with the text of the hyperlink. We'll reverse this in the other
            'function using Sys.ReplaceChar$(text$,"_"," ") which will replace the underscores with spaces - so we'll be back
            'to normal. Same with the font$.
 
        cCc.Hyperlink$=gbHndl$;" ";hlinkActive;" ";font$;" ";backcolor$;" ";linkcolor$;" ";eventClick$;" ";eventMove$;" ";_
        text$;" ";fontHeight
 
        'Word 1 = handle to the graphicbox.
        'Word 2 = 0/1 - whether or not the link is active (mouse over)
        'Word 3 = the font used
        'Word 4 = the backcolor
        'Word 5 = the link color
        'Word 6 = the event in which to trigger when the link is clicked.
        'Word 7 = the event in which to trigger when the mouse is moved over the gbox.
        'Word 8 = the text for the hyperlink
        'Word 9 = the height of the font
 
    End Function
 
    Sub cC.RollHyperlink byref Link$, X, Y
        'Extract information from the hyperlink's handle:
        gbHndl$ = Word$(Link$,1) : hlinkActive = Val(Word$(Link$,2)) : font$ = Word$(Link$,3) : backcolor$ = Word$(Link$,4)
        linkcolor$ = Word$(Link$,5) : eventClick$ = Word$(Link$,6) : eventMove$ = Word$(Link$,7) : text$ = Word$(Link$,8)
        fontHeight = Val(Word$(Link$,9))
 
        #gbHndl$, "Font ";font$;" ; Color ";linkcolor$;" ; BackColor ";backcolor$ 'Make sure the colors and fonts are set
            'right...
 
        'Now, replace the weird symbol in the font$ and text$ with spaces:
        font$ = Sys.ReplaceChar$(font$,"ø"," ")
        text$ = Sys.ReplaceChar$(text$,"ø"," ")
 
        'Check to see if the mouse coordinates (X, Y) are over the link's text - if so, we'll make sure the hyperlink
        'becomes underlined:
 
        'First, let's get the width of the hyperlink's text using the stringwidth? command:
        #gbHndl$, "StringWidth? text$ textWidth"
        textWidth = textWidth + 1
            'Now, we know both the width and height of the text. they are stored in textWidth and fontHeight . Perfect!
 
        'Now, check to see if the mouse is over the actual area the text is drawn in:
            If X<=(textWidth+4) And X>=4 And Y<=(fontHeight+2) And Y>=2 Then 'If the mouse is in the proper area:
                If Not(hlinkActive) Then
                    'If the link has not been drawn in it's mouseOver (active) state, then let's do so now.
                    'If hlinkActive was true (set to 1),
                    'it means we had already drawn it in it's active state, so we wouldn't need to redraw the same thing.
                    'That just causes flickering.
                    #gbHndl$, "DELSEGMENT DefaultText" 'Delete the inactive (normal) drawing of the text.
                    #gbHndl$, "REDRAW" 'Update the graphicbox to reflect our deletion.
                    #gbHndl$, "Place 4 ";fontHeight+2 'Position the pen to redraw the text.
                    #gbHndl$, "Font ";font$;" underscore" 'Set the font to be underlined! Of course,
                        'if the user already has an underlined font, this is a bummer. :(
                    #gbHndl$, "|";text$ 'Draw the new, underlined text!
                    #gbHndl$, "Flush ActiveText" 'Make this drawing stick, and call it ActiveText -
                              'we can remove this drawing and redraw the old one when the mouse isn't
                        'over the graphicbox text area. Cool, huh?
                    hlinkActive = 1 'The hyperlink is now in it's active state!
                End If
            Else 'If the mouse is NOT over the actual text area, then let's make sure that the hyperlink is drawn in it's
                 'inactive state.
                If hlinkActive Then 'If the hyperlink is being drawn in it's active state, then let's unactivate it!
                    #gbHndl$, "DELSEGMENT ActiveText" 'Remove the drawing of the active text.
                    'Draw the text in it's normal state:
                    #gbHndl$, "REDRAW"
                    #gbHndl$, "Font ";font$
                    #gbHndl$, "Place 4 ";fontHeight+2
                    #gbHndl$, "|";text$
                    #gbHndl$, "Flush DefaultText" 'Make it stick and call this drawing the DefaultText drawing.
                    hlinkActive = 0 'hlinkActive is now inactive.
                End If
            End If
        '----------------------------------------------------------------------------'
 
        'Replace spaces with underscores...
        font$ = Sys.ReplaceChar$(font$," ","ø")
        text$ = Sys.ReplaceChar$(text$," ","ø")
 
        'Change the properties of the hyperlink's handle to match the updated properties.
        'This will actually affect the user's handle, because we passed Link$ by reference. (byref in the help file)
        Link$=gbHndl$;" ";hlinkActive;" ";font$;" ";backcolor$;" ";linkcolor$;" ";eventClick$;" ";eventMove$;" ";text$;_
        " ";fontHeight
 
    End Sub
 
    'This is a helper function for the hyperlink functions.
    Function Sys.ReplaceChar$(String$, FindChar$, ReplaceChar$) 'Find the character FindChar$ and replace
        'it with ReplaceChar$
        For i = 1 To Len(String$)
            char$=Mid$(String$,i,1)
            If char$=FindChar$ Then char$=ReplaceChar$
            Sys.ReplaceChar$=Sys.ReplaceChar$;char$
        Next i
    End Function
 

What does it all mean?

To make the most out of this, you should probably look over the code and read the comments. It's designed to be easy to understand. You should be able to keep up quite well after doing so.

The function cCc.Hyperlink$ (the cCc stands for create custom control) is called after the window has been setup like this:
Link1$ = cCc.Hyperlink$("#Win.Link1", "Link 1 Text", "Arial 10", "buttonface", "blue", "[Link1.Click]", "[Link1.Move]")
The arguments passed into this function correspond with the paremeters (representational variables) received by the function cCc.Hyperlink$():
Link1$ = cCc.Hyperlink$("#Win.Link1", "Link 1 Text", "Arial 10", "buttonface", "blue",  "[Link1.Click]", "[Link1.Move]")
Function cCc.Hyperlink$(  gbHndl$,        text$,       font$,     backcolor$, linkcolor$, eventClick$,    eventMove$)
The function returns a string of values put together. Well, when we called this function, we assigned the variable Link1$ to be that string.

Earlier, we mentioned that we need an event for when the mouse moves over the link. If you compare the two above, you'll notice that we specified the branch label [Link1.Move] to be the block of code that Liberty jumps to when the mouse moves over the graphicbox #Win.Link1. Let's take a look at that block:
    [Link1.Move]
        Call cC.RollHyperlink Link1$, MouseX, MouseY
    Wait
 
Notice that we called the sub in our program. This sub, cC.RollHyperlink (cc stands for Custom Control), checks to see if the mouse is directly over the rendered text (using the graphics commands, and a little bit of math and conditional checking). The sub then draws the hyperlink either in it's active (underlined) form or inactive (not underlined) form depending on if the mouse is over it or not.

In the sub, we passed the value Link1$ as the handle to our link. It contains the string of information returned by the cCc.Hyperlink$() function. The sub breaks this information down, and uses it to see if it needs to redraw the hyperlink. If it does, it changes the value of the paremeter hlinkActive, which happens to be second word inside Link1$.

When the sub is done, it puts the link handle back together:
Link$=gbHndl$;" ";hlinkActive;" ";font$;" ";backcolor$;" ";linkcolor$;" ";eventClick$;" ";eventMove$;" ";text$;" ";fontHeight
Now, remember that in our case, we passed the value Link1$ in the sub. If you were to compare the values of the string variable Link1$ when the mouse is over, and when it is not, you would get this:

#Win.Link1 1 Arialø10 buttonface blue [Link1.Click] [Link1.Move] Linkø1øText 16
#Win.Link1 0 Arialø10 buttonface blue [Link1.Click] [Link1.Move] Linkø1øText 16

The first line is the value of Link1$ when the mouse is over the link. The second line is the value when the mouse is not over. There is only one difference between the two, and that is found in the second word. If you looked at the code, you'd realize that the second word in the "handle" of our link is the value of hlinkActive. But how are we able to change the actual value of a handle from the sub?

We take advantage of passing an argument by reference. Look at this:
Sub cC.RollHyperlink byref Link$, X, Y
Notice the little "byref" that is thrown in right before Link$ (the paremeter that represents the handle of the link passed in). Even though it doesn't turn blue in the Liberty BASIC 4.03 editor, it is still a recognized specification by Liberty BASIC's standards. Whenever you pass a variable into a sub or function by reference, the sub or function can actually modify the variable you gave it! Isn't that amazing? Ok, we'll maybe it doesn't blow you out of your seat, but it can be really useful - as we just saw.

For more info, check out BYREF in the help file.

Utilizing the hyperlink

Ok, so we have this great hyperlink custom control, but how do we use it? Well, it's really quite simple to use. All you have to do is look a little closer at the demo program.

You already know how to make a hyperlink. Just assign a value like we did in the demo to the result of cCc.Hyperlink$(), with your own arguments.
Link1$ = cCc.Hyperlink$("#Win.Link1", "Link 1 Text", "Arial 10", "buttonface", "blue", "[Link1.Click]", "[Link1.Move]")
As you know, the hyperlink function requires two events. The second event, what to do on mouse over, requires us to call the sub cC.RollHyperlink.

So, once you have your events setup, all you have to do is call the cC.RollHyperlink sub from your mouse over event:
    [Link1.Move]
        Call cC.RollHyperlink Link1$, MouseX, MouseY
    Wait
 
Then, all you have to do is pass the handle to the link - in this case, it's Link1$.

When you use a branch label event (like the example above) you must use the special variables MouseX and MouseY for the mouse coordinates. Liberty BASIC always assigns the x and y position of the mouse into these special global variables.

What if you chose to use a sub for an event handler? You would have to make the handle to your link global:

Global Link1$

You would also have to pass the name of the sub in for the mouse over event when you use the cCc.Hyperlink$() function, instead of the name of a branch label:

Link1$ = cCc.Hyperlink$("#Win.Link1", "Link 1 Text", "Arial 10", "buttonface", "blue", "[Link1.Click]", "Link1.Move")

And your sub might look something like this:
    Sub Link1.Move GraphicBox$, X, Y
            Call cC.RollHyperlink Link1$, X, Y
    End Sub
Notice the sub must accept three parameters. When Liberty BASIC calls a sub event for a graphicbox, it always passes the graphicbox handle, mouse x position, and mouse y position.

As for the mouse click event, you can just put your own code in a sub or branch label. If you use a sub, be sure to put a receiver for the graphicbox handle, mouse x, and mouse y coordinates!

Conclusion and a Progress bar control

Well, that's about it for the hyperlink. With the power of Liberty BASIC graphicboxes, you can create all kinds of custom controls.

An example of a progressbar custom control can be found below. It's really quite simple, if you understand the principles discussed in this article.
    NoMainWin
    WindowWidth = 600
    WindowHeight = 400
    Button #Win.b, "Unstep progress bar",[UnStepIt],UL,4,38,130,30
    Button #Win.b2, "Step progress bar",[StepIt],UL,138, 38, 130, 30
    Button #Win.b3, "Set Percentage",[Percent],UL,4,72,130,30
    GraphicBox #Win.g, 4, 4, 436, 30
    Stylebits #Win.g, 0,_WS_BORDER,0,0
    Open "Temp" For Window_NF As #Win
    #Win, "TrapClose [Quit]"
    #Win, "Font Arial 10"
    Prog1$ = cCc.ProgressBar$("#Win.g", 436, 30)
    Wait
 
    [UnStepIt]
        Call cC.UnStepProgressBar Prog1$
    Wait
 
    [StepIt]
        Call cC.StepProgressBar Prog1$
    Wait
 
    [Percent]
        Prompt "Choose percentage (0-100):"; Percent
        Call cC.SetProgressBarPercent Prog1$, Percent
    Wait
 
    [Quit]
    Close #Win
    End
 
 
'*****************************************************************************************************************'
'BEGIN PROGRESS BAR FUNCTIONS ************************************************************************************'
'*****************************************************************************************************************'
    Function cCc.ProgressBar$(gbHndlb$, width, height) 'Create Custom Control Progress Bar
        gbHndl$ = Word$(gbHndlb$,1)
        'Border drawing...sad this takes up a ton of code :( - but looks beautiful!
        dkGray$ = "102 102 102" : mdGray$ = "185 185 185" : ltGray$ = "234 234 234"
        #gbHndl$, "CLS;Down;Fill White ; Size 1 ; Color ";ltGray$;"; Set 0 0 ; Color ";dkGray$;"; Line 1 0 ";(width-3);_
        " 0 ; Color 124 124 124 ; set ";(width-3);" 0"
        #gbHndl$, "Color 167 167 170 ; Set ";(width-2);" 0 ; Color 178 178 178 ; Set 0 1 ; Color 127 127 127 ; Set 0 2"
        #gbHndl$, "Color ";mdGray$;" ; Line 1 1 ";(width-2);" 1 ; Color 117 117 117 ; Set ";(width-2);" 1"
        #gbHndl$, "Color 167 167 170 ; Set ";(width-1);" 1 ; Color 124 124 124 ; Set ";(width-1);" 2"
        #gbHndl$, "Color ";ltGray$;" ; Line 1 2 ";(width-2);" 2 ; Color ";mdGray$;";Set ";(width-3);" 1 ; Set ";(width-2);" 2"
        #gbHndl$, "Set ";(width-3);" 2 ; Color ";dkGray$;" ; Line 0 3 0 ";(height-3)
        #gbHndl$, "Color 124 124 124 ; Set 0 ";(height-3);" ; Color 167 167 167 ; Set 0 ";(height-2)
        #gbHndl$, "Color ";dkGray$;" ; Line 1 ";(height-1);" ";(width-3);" ";(height-1);";Line ";(width-1);" 3 ";(width-1);" ";(height-3)
        #gbHndl$, "Color 124 124 124 ; Set ";(width-1);" ";(height-3);"; Set ";(width-2); " ";(height-2);";Set ";(width-3);" ";(height-1)
        #gbHndl$, "Color 167 167 167 ; Set ";(width-1);" ";(height-2);"; Set ";(width-2); " ";(height-1);";Color ";ltGray$;_
        "; Line 1 ";(height-2);" ";(width-2);" ";(height-2)
        #gbHndl$, "Color ";mdGray$;"; Line ";(width-2);" 2 ";(width-2);" ";(height-2);";Color ";ltGray$;"; Line ";(width-3);" 3 ";_
        (width-3);" ";(height-2)
        barWidth = Int(width/50)
        padWidth = Int(width/218)
        maxBars = Int(width/(barWidth+padWidth)) 'holds how many bars this progressbar holds...
        cCc.ProgressBar$ = gbHndl$;" ";width;" ";height;" ";barWidth;" ";padWidth;" ";barCount;" ";maxBars
        #gbHndl$, "backcolor 255 255 255"
        #gbHndl$, "Flush"
    End Function
    Sub cC.SetProgressBarPercent byref progHndl$, percent
        gbHndl$=Word$(progHndl$,1):width=Val(Word$(progHndl$,2)):height=Val(Word$(progHndl$,3)):barWidth=Val(Word$(progHndl$,4))
        padWidth=Val(Word$(progHndl$,5)):barCount=Val(Word$(progHndl$,6)):maxBars=Val(Word$(progHndl$,7))
        p = Int((maxBars/100)*percent)
        If p = 0 Then
            progHndl$=cCc.ProgressBar$(gbHndl$;" .", width, height)
            Exit Sub
        End If
        If p>barCount Then
            dif = p-barCount
            For i = 1 To dif
                Call cC.StepProgressBar progHndl$
            Next i
        End If
        If p<barCount Then
            dif = barCount - p
            For i = 1 to dif
                Call cC.UnStepProgressBar progHndl$
            Next i
        End If
        progHndl$ = progHndl$
    End Sub
    Sub cC.StepProgressBar byref progHndl$
        gbHndl$=Word$(progHndl$,1):width=Val(Word$(progHndl$,2)):height=Val(Word$(progHndl$,3)):barWidth=Val(Word$(progHndl$,4))
        padWidth=Val(Word$(progHndl$,5)):barCount=Val(Word$(progHndl$,6)):maxBars=Val(Word$(progHndl$,7))
        barCount=barCount+1
        If barCount>maxBars Then Exit Sub
        If barCount>1 Then Lx=((barWidth+padWidth)*(barCount-1))+1 Else Lx=1
        LxF = Lx+barWidth
        #gbHndl$, "Color 181 200 226;Line ";Lx;" 1 ";LxF;" 1;Color 164 191 221;Line ";Lx;" 2 ";LxF;" 2;Color 146 180 219;Line ";_
        Lx;" 3 ";LxF;" 3"
        #gbHndl$, "Color 130 166 214;Line ";Lx;" 4 ";LxF;" 4;Color 114 156 211;Line ";Lx;" 5 ";LxF;" 5;Color 95 145 206;Line ";_
        Lx;" 6 ";LxF;" 6"
        #gbHndl$, "BackColor 87 138 204; Color 87 138 204; Size 1; Place ";Lx;" 7; BoxFilled ";LxF;" ";(height-6)
        #gbHndl$, "Color 90 142 206;Line ";Lx;" ";(height-6);" ";LxF;" ";(height-6);"; Color 104 151 209;Line ";Lx;" ";(height-5);" ";_
        LxF;" ";(height-5)
        #gbHndl$, "Color 124 163 214;Line ";Lx;" ";(height-4);" ";LxF;" ";(height-4);";Color 140 173 216;Line ";Lx;" ";(height-3);" ";_
        LxF;" ";(height-3)
        #gbHndl$, "Color 159 187 221;Line ";Lx;" ";(height-2);" ";LxF;" ";(height-2)
        progHndl$ = gbHndl$;" ";width;" ";height;" ";barWidth;" ";padWidth;" ";barCount;" ";maxBars
        #gbHndl$, "Backcolor 255 255 255"
        #gbHndl$, "Flush bar";barCount
    End Sub
    Sub cC.UnStepProgressBar byref progHndl$
        gbHndl$=Word$(progHndl$,1):width=Val(Word$(progHndl$,2)):height=Val(Word$(progHndl$,3)):barWidth=Val(Word$(progHndl$,4))
        padWidth=Val(Word$(progHndl$,5)):barCount=Val(Word$(progHndl$,6)):maxBars=Val(Word$(progHndl$,7))
        If barCount=0 Then Exit Sub
        barSeg = barCount' + 1
        #gbHndl$, "delsegment bar";barSeg
        #gbHndl$, "redraw"
        if barCount>0 Then barCount=barCount-1
        progHndl$ = gbHndl$;" ";width;" ";height;" ";barWidth;" ";padWidth;" ";barCount;" ";maxBars
    End Sub
'*****************************************************************************************************************'
'END PROGRESS BAR FUNCTIONS **************************************************************************************'
'*****************************************************************************************************************'