Dialog Style Program

Dialog Style Program (contd.)

This second part of the tutorial will focus on first making the program run and then adding functionality to it.

Adding the form source to the project

We can now start getting the program to run. The first thing we need to do is include the form source code:

include “colorlab_form.sma”

After adding this line, save the file. At this point, two dependent entries will appear in the Project View tree. One is colorlab_form.sma the other uisyshelphdr.sma is included by the form source code but is not visible to the project. To resolve this, we need to add the include directory to the project as well as the library uisyshelp.sml. After this has been done the Project Settings Includes and libraries tab should look like this:

The Project Settings dialog after adding the relevant items

Setting up the program

The first step with getting the program running is to write the code that initializes the program, creates the form, creates the dialogue window, and then waits for events. As it turns out, this does not require an excessive amount of program code.

The main() Function of the colorlab Program

include "colorlab_form.sma"

constant iSTARTCOLOR 0xffffff

function main()
  wxform f
  wxdialog d
  integer e
  e = 0
  f =@ colorlab(error=e)
  if f =@= .nul
        errormsg(e)
  else
        d =@ wxdialog.new(1, 1, innerwidth=f.width, innerheight=f.height, visible=.false, \
                         captiontext="SIMPOL Color Lab", error=e)
        if d =@= .nul
              errormsg(e)
        else
              adjustformcolorvals(f, iSTARTCOLOR)
              f.setcontainer(d)
              centerdialogonparent(d)
              d.processmodal(.inf)
        end if
  end if
end function

The code above is fairly straightforward. It calls the generated colorlab() function to create the form. If anything goes wrong, it calls the errormsg() function. Assuming the form was successfully created it creates the dialogue window, sizing is based on the size of the form. Here we again check for success and assuming everything worked call a function to initialise the form for a specific colour value (this is stored in the constant iSTARTCOLOR) Finally, the form is centred on the display, and then set to wait forever (or until the dialogue is either made invisible or by the user clicking Close)

The program as-is will not compile successfully as the source code for the form contains assignments of function names for handling events, but those functions have not yet been created

Getting the basic form running

We are going to now add all the minimum bits remaining to get our program to run and show the form. It will not do anything, but we will be able to see the form come up in the dialogue window, as well as close the window and have the program exit correctly.

In order to do this, we need to add the functions, even if they don’t yet do anything. That code is below

The remaining Empty Functions of the colorlab Program

function adjustformcolorvals(wxform f, integer rgbval, string ignorescrollbar="")
end function
function hexval_olf(wxformedittext me)
end function
function decval_olf(wxformedittext me) 
end function
function redval_olf(wxformedittext me)
end function
function greenval_olf(wxformedittext me)
end function
function blueval_olf(wxformedittext me)
end function 
function redscroll_os(wxformscrollbar me, string scrolltype)
end function
function greenscroll_os(wxformscrollbar me, string scrolltype)
end function 
function bluescroll_os(wxformscrollbar me, string scrolltype) 
end function
function okbtn_oc(wxformbutton me)
   wxdialog d
   d =@ me.form.container
   d.setvisible(.false) 
end function 
function errormsg(string s)
   wxmessagedialog(message=s, captiontext="SIMPOL Color Lab Error", style="ok", icon="error") 
end function 

The only function which does anything so far is okbtn_oc, which sets the dialogue visibility to .false resulting in the code exiting the processmodal() method and the program exiting.

Note:
Another useful naming convention can be seen in the names of the functions. The beginning portion of the name indicates the control with which it is associated, followed by an underscore, and then a set of letters describing the event. Below is a table of potentially useful names for the portion following the underscore.

SuffixExplanation
oconchange
oconclick
occoncellchange
ocsoncellselect
ocwconcolwidthchange
odcondoubleclick
ogfongotfocus
olfonlostfocus
omonmouse
omonmove
orhconrowheightchange
osonscroll
osonselect
osonsize
osconselectionchange
osconstatechange
ovconvisibilitychange

At this point, it should be possible to build and run the program. It’s not very functional yet, but it is a nice place to be since now all that is left is manipulating the form in response to user-generated events (or in other words, filling in those empty functions).

Finishing the color lab program

Now that we have the basic programming running and displaying the form, all that remains is to fill in the functions that are currently empty. One thing that we can do to minimize the amount of coding is to use a common piece of code for some of the functions and call it from each of them. In this case, the scrollbar event handling functions will all be similar as will the functions that handle the edit control events for the three colour values. Everything will eventually call the adjustformcolorvals() function. Since that is the function that everything has in common

The Full Implementation of the adjustformcolorvals() Function

function adjustformcolorvals(wxform f, integer rgbval, string ignorescrollbar="")
   integer red, green, blue
   blue = rgbval / 0x10000
   green = (rgbval mod 0x10000) / 0x100
   red = ((rgbval mod 0x10000) mod 0x100)

   f!tbHexColorValue.settext(.tostr(rgbval, 16))
   f!tbDecColorValue.settext(.tostr(rgbval, 10))
   f!tbRed.settext(.tostr(red, 10))
   f!tbGreen.settext(.tostr(green, 10))
   f!tbBlue.settext(.tostr(blue, 10))
   f!sbRed.setbackgroundrgb(red)
   f!sbGreen.setbackgroundrgb(green * 0x100)
   f!sbBlue.setbackgroundrgb(blue * 0x10000)
   if ignorescrollbar != "red"
     f!sbRed.setscroll(position=red)
   end if
   if ignorescrollbar != "green"
     f!sbGreen.setscroll(position=green)
   end if
   if ignorescrollbar != "blue"
     f!sbBlue.setscroll(position=blue)
   end if
 f!rBorder.setrgb(rgb=rgbval)
 end function

This function takes the final colour value, and then use it to set the value of all other controls. It is a very basic function, it takes the colour value that comes as an RGB value and splits it into the red, green, and blue. It then assigns the value to each of the edit controls and uses the individual colour values to set the background for each of the scrollbars. Furthermore, it sets the position of the thumb in the scrollbars. Finally, it sets the colour of the rectangle to that of the colour passed.

While playing around with this, it was noticed that setting the position of a scrollbar that had caused the event resulted in a strange flicker, so an extra parameter was created that is ignored by the other functions, but which is passed by the code that handles the scrollbar events. This lets the function choose not to set the scroll position for the scrollbar that is passed.

The next two functions are quite similar but different enough to deserve different function implementations. In each case, the functions retrieve the current value of the control, convert it to a value, force the value to be within a valid range, and then they each call the adjustformcolorvals() function.

The Code for the hexval_olf() and decval_olf() Functions

function hexval_olf(wxformedittext me)
     integer rgbval
     string hexcolor

     hexcolor = me.gettext()
     hexcolor = .if(hexcolor <= "", "0", hexcolor)

     rgbval = .toval(hexcolor, nohexdigits(hexcolor), 16)
     rgbval = .max(.min(0xffffff, rgbval), 0)
     adjustformcolorvals(me.form, rgbval)
end function

function decval_olf(wxformedittext me)
     integer rgbval
     string deccolor
     deccolor = me.gettext(   deccolor = .if(deccolor <= "", "0", deccolor)
     rgbval = .toval(deccolor, nodigits(deccolor), 10)
     rgbval = .max(.min(0xffffff, rgbval), 0)
     adjustformcolorvals(me.form, rgbval) 
end function

There are two special function calls in the previous code, nohexdigits() and nodigits(). Each is designed to extract all of the characters of a specific type, either normal digits or the normal plus hexadecimal digits. The result is passed to the .toval() function as the characters to ignore when converting the value.

The next task is to handle the events for the individual colour values. As mentioned earlier, these will, in fact, be exactly the same code in each case, since the change to any single colour value still requires all the colour values to be read. All the event handlers will call the exact same function, which we will call handleonecolorchange().

Handling the Events for the Colour Edit Controls

function handleonecolorchange(wxform f) 
     integer red, green, blue, rgbval 
     string color
     color = f!tbRed.gettext() 
     red = .toval(color, nodigits(color), 10) 
     red = .max(0, .min(255, red)) 
     color = f!tbGreen.gettext() 
     green = .toval(color, nodigits(color), 10)
     green = .max(0, .min(255, green)) 
     color = f!tbBlue.gettext()
     blue = .toval(color, nodigits(color), 10)
     blue = .max(0, .min(255, blue)) 
     rgbval = calcrgbval(red, green, blue)
     adjustformcolorvals(f, rgbval) 
end function

function redval_olf(wxformedittext me)
   handleonecolorchange(me.form) 
end function
 
function greenval_olf(wxformedittext me)
   handleonecolorchange(me.form) 
end function
 
function blueval_olf(wxformedittext me)
   handleonecolorchange(me.form) 
end function
 
function calcrgbval(integer red, integer green, integer blue)
    integer rgbval

    rgbval = blue * 0x10000 + green * 0x100 + red 
end function rgbval

The final piece of the puzzle is to handle the events for the scrollbars, and this next piece of code does that. Again, all three have much in common, so they all call one common routine called doscrollbars().

Handling the Scroll Bar Events

function getcurrentcolorvals(wxform f, integer red, integer green, integer blue)
     red = f!sbRed.position
     green = f!sbGreen.position 
     blue = f!sbBlue.position
end function

function doscrollbars(wxform f, string ignorescrollbar) 
     integer red, green, blue, rgbval
     red = 0; green = 0; blue = 0 
     getcurrentcolorvals(f, red, green, blue) 
     rgbval = calcrgbval(red, green, blue)
  adjustformcolorvals(f, rgbval, ignorescrollbar)
end function

function redscroll_os(wxformscrollbar me, string scrolltype) 
  doscrollbars(me.form, "red") end function

function greenscroll_os(wxformscrollbar me, string scrolltype)
  doscrollbars(me.form, "green")
end function

function bluescroll_os(wxformscrollbar me, string scrolltype) 
  doscrollbars(me.form, "blue") 
end function

The first function in the previous chunk of code is called by the doscrollbars() function to retrieve the component colour values from the position property of each of the scrollbars. Since we set the range of the scrollbars to 256 and the thumb size to 1, that means that the range of valid positions is from 0 through 255. Once the component values have been retrieved, it calls the calcrgbval() function that is also called by the handleonecolorchange() function.

Finally, here is the code for the two functions mentioned earlier for extracting the valid digits from the string passed.

Extracting the Digits from String Values

function nodigits(string s)
end function s-"0"-"1"-"2"-"3"-"4"-"5"-"6"-"7"-"8"-"9" 

function nohexdigits(string s)
end function s-"0"-"1"-"2"-"3"-"4"-"5"-"6"-\
               "7"-"8"-"9"-"a"-"b"-"c"-"d"-\
               "e"-"f"-"A"-"B"-"C"-"D"-"E"-"F"

Summary

In the preceding section, we have learned to design a basic form using the Form Designer, including setting default values, using system theme colours, and working with the sizing and alignment tools. We have also saved that form in the new XML-based form format and also as SIMPOL source code. We have worked with included source files and SIMPOL language libraries. Finally, the resulting form was incorporated in a project that used dialogue to host the form and then waited on events, which were then handled by the program code. We also validated the input that was entered.

This sort of program component is a common requirement for more complex applications, where any number of similar dialogue-style user-interface components will be needed to ensure a user-friendly experience.

Pages: 1 2