Graphical User Interfaces - A Complete Study
Part 3 - ErgonOS Organization and Standards

Written by Stéphane Richard (Mystikshadows)

INTRODUCTION:

If you're reading this, I'm assuming you've read Part One and Part Two of my series already. If you didn't, please do before continuing here as the first two parts will greatly clarify what is going on in this third part of the series. In this document we'll begin to cover many aspects of what the programming will comprise. When starting to code a project this size, it's important to document yourself all the way. And this series will do just that.

Even though technically I will be working by myself on ErgonOS, one never knows what the future holds. I could be offered help in this project, I could let it go for a while and get back to it afterwards, I might even work for a good while on one part of the GUI and forget some parts that I created a while back when it's time to get back to those other modules. These are all situations where quality of code and effort in code documentation and "intelligent" organization of modules, a steady global naming convention and such type of tools can really come in handy. So before any coding begins, we'll defined these standards, and you'll see that the code I'll be writing will comply to that standard. So let's start this big wheel turning shall we?

ERGONOS CODING STANDARDS:

The standard I'll be using is broken down into three workable standard groups. These are the "Source File Documentation", "Indentation and Spacing" and "Naming Conventions". As I mentionned, coding standards are there because when the code gets big, it's clarity will have better chances at staying as clear as possible across the thousands of lines of codes there will be. Let's take the time to review these standards right here.

ERGONOS DEVELOPMENT STAGES:

And now that we have all the standards defined and out of the way, we can really begin to orient the project towards it's development. As you remember from the 2nd part of this series, I've enumerated 8 seperate engines that make up ErgonOS. If you had the User Interface part to the list (All the controls I enumerated and detailed) there's really 9 main engines. The main thing to remember is that all these 9 engines need to work together so they will need some means of communicating with each other and have access to each other's functionality. However. You might even think at this point (especially if you have a group of 9 people working on the project) that each could take an engine and just start coding. But that's not entirely the case. Some of these engines can be started independantly, others however will need one or more of the engines to be completed prior to their development. Let's Take these engines right here and determine their realization criteria. This way we'll know what should be done first (and even what parts of the engine, if any, could be created independantly of the the others).

There you have it. With these relationships established it will be easier to determine what's what and what should get done before whatever else. There's basically one thing left to determine and that is code module organization. That again is also mostly a question of personal taste. But just so you don't get lost in how I'll be doing things, I will explain to you now the way modules will be created and managed. Since these are all based on the engines themselves I will break them down by engine.

ERGONOS CODE MODULE ORGANIZATION:

When it comes to bigger projects, I believe that organization even at the module level, brings many benefits from the start of the development stage all the way down to the debugging phase. If you can create a system that can instantly tell you what code lies in what module instantly, it becomes much more trivial to locate where, in all the thousands of lines of code, something you're looking for is. As such, I try to organize my code in a way that really helps isolate every type of code into it's own module. Since ErgonOS has 9 engines it's easy to see how quickly code could get confusing if it was all in one module only. Code Module Organization along with intelligent error reporting can really make locating a bug a breeze. Of course Error management isn't the most passionate side of development so I like to get rid of it as soon as I can so I can get to the real fun part. So then, for each engine, each related module file will have a corresponding filename to clearly indicate, before we open the file, which engine the file belongs to and what I can expect to find in each of the engine's related modules. Here's the layout of the file naming conventions.

ErgonOS Module Naming Convention
Module Name Description
<EngineName>Constants.bi
<EngineName>Enumerations.bi
<EngineName>UserTypes.bi
<EngineName>EngineCore.bas
<EngineName>Helper.bas
<EngineName>Communicate.bi
<EngineName>UserInterface.bi
<EngineName>Events.bi
constants go here.
ENUM definitions go here
User Defined Types go here
Core Functionality goes here
Functions that help the engine go here
Information and code to transfer with other modules
User Interface related code goes here
Event Management related code goes here

Now some of these modules may not be needed for a given engine. For example, the low level libraries that do not interact with the user at all won't need the UserInterface and Events module Others might not need to communicate with other modules either, it all depends on the role of the engine in the ErgonOS hierarchy. As an example, let's illustrate this using the EVRIL engine so you can see how things will appear in the folder.

E.V.R.I.L. (ErgonOS Visual Representation and Intelligent Layout)
Module Name Description
EVRILConstants.bi
EVRILEnumerations.bi
EVRILUserTypes.bi
EVRILEngineCore.bas
EVRILHelper.bas
EVRILCommunicate.bi
EVRILUserInterface.bi
EVRILEvents.bi
constants go here.
ENUM definitions go here
User Defined Types go here
Core Functionality goes here
Functions that help the engine go here
Information and code to transfer with other modules
User Interface related code goes here
Event Management related code goes here

Aside the engine modules themselves there will be one set of module that will serve the purpose of containing elements that are shared among all other engines. For example, Keyboard Constants don't need to be defined at an engine level as any module that needs to access the keyboard can do so using the same constants. Such types of code will go in modules that are prefixed with "Shared". Here are the shared modules that we will need:

ErgonOS Shared Modules
Module Name Description
SharedConstants.bi
SharedEnumerations.bi
SharedUserTypes.bi
SharedHelper.bas
SharedCommunicate.bi
SharedUserInterface.bi
SharedEvents.bi
SharedErrorManagement.bi
Shared constants go here.
Shared ENUM definitions go here
Shared User Defined Types go here
Shared Helper functions and subs
Shared Module inter-communication facility
Shared User Interface related code goes here
Shared Event Management related code goes here
Shared Error Management and Logging facilities

Finally, as far as the user interface is concerned, each component that I have enumerated in the second part of this series will be implemented independantly in their respective module. Some modules will be bigger than others but by grouping these into control related functionality, it will help keep the whole user interface in perspective. Therefore, here are the control specific modules needed by the user interface:

ErgonOS Component Modules
Module Name Description
LabelComponent.bas
ButtonComponent.bas
CheckBoxComponent.bas
RadioButtonComponent.bas
TextBoxComponent.bas
MaskedBoxComponent.bas
SelectorBoxComponent.bas
PictureBoxComponent.bas
ListBoxComponent.bas
ListViewComponent.bas
TreeViewComponent.bas
ScrollBarComponent.bas
ComboBoxComponent.bas
CalendarDropComponent.bas
NumericDropComponent.bas
ToolbarComponent.bas
ToolboxComponent.bas
MenuBarComponent.bas
PulldownMenuComponent.bas
PopupMenuComponent.bas
StatusBarComponent.bas
IndicatorBarComponent.bas
TabbedDialogComponent.bas
TabStripComponent.bas
DocumentComponent.bas
UserDefinedComponent.bas
Static Label used to display text on the screen
Button that can be clicked, pressed or unpressed
Square component that can be checked and a label
Round component that only one can be checked
Standard text entry field type component
Text entry field that can block unwanted characters
Text entry that has 2 buttons to increment/decrement
Rectangular component to display an image
Rectangular list of selectable Item
Non Editable Grid viewing with images with multiple views
Control to represent data in a hierarchic fashion
A Slider Type control that has a min, max and current value
Combination TextBox, Button and ListBox components
Combination Maskedbox, Button and Calendar components
Combination textbox with 2 button components
Component that holds other components
Floating control that works like a toolbar component
Top of form rectangular area to hold menu options
Vertical selection appearing below a MenuBar component
Same as Pulldown Menu that appears where the mouse is
Bottom of screen rectangle that displays information
Bottom of screen rectangle to show indicators
Tabbed component that can have different page types
Tabbed component holding many of the same page type
Component to manage all supported document formats
Component to create original components from scratch

Note that this is my way of doing things, and in no means do I intend to "force" you to use this particular naming convention for your own projects. Since there are many modules involved I believe that by naming the modules accordingly and keep code organized in this manner it will greatly help the coding process by allowing me to see what is where even without opening the module. It also makes each module smaller and much more managable. For your projects you can create any standard your want because it's your project and the first person that needs to understand what's going on is you. You might work better with less modules and mode code in each module, you might even break your modules into even more modules than I've done. It all depends on what you're comfortable with and your way of doing things.

Remember that this series is to teach you everything you need to know about making a GUI. As such, and because different people read and understand things differently on different levels, I will be keeping the tutorial series and it's related code modules as clear and documented as possible so that everyone can read and understand the concepts I will be using. This is also one of the reason why the code will be organized the way it will be and why I will be following the standards I've established in this 3rd part of the document. For a project this size, not having some form of organization like this would defeat the purpose of writing this series. Let's continue with another important aspect of development (in GUI or any other programming project), I'm talking about Error Management.

ERGONOS ERROR MANAGEMENT:

Now some of you might be wondering why I'm talking about error management even before any line of code is written. The answer is simple. In big projects, if you don't implement error management right from the start, it will be a major headache to add it later in the project or at the end after you're done coding everything else. This project will easily have several thousand lines of code and atleast several hundred subs and functions, maybe thousands, imagine having to go through each and everyone of these subs and functions and having to add error management code to them all. By adding that code at the beginning it will not only rid you of he big burden of adding it later but also help you greatly in your testing and debugging phase. You'll thank yourself (and me, maybe) in the long run.

Throughout all the modules, when implementing the error management code, I'll want to be sure that it is as easy and quick to locate a bug or an error as possible. For that to successfully occur, I need a certain list of information to help me in my quest. Whether the bug is reported on screen or logged to a file this information will still help locating bugs quickly. Here's that information:

Error Information Description
Engine Name
Module Name
Sub/Function Name
Parameter List
Error Number
Error Description
The Engine name is displayed
The Name of the .bas or .bi file
The Sub or Function Name
The values of the parameters passed
The error number as returned by ERR
A human readable description of what the error means

This essentially means that whenever an error is returned by the system, it will give me back these specific pieces of information. By knowing right from the start, the Engine where the error occured, the module name, the sub or function name, the values of the parameters that were passed to that sub or function (if any) and the error that occured, imagine how fast the debugging process will suddenly become for me, or anyone else correcting the error. Here is an example of a typical function and how I will provide the needed information. Let's assume that this function will be in the EVRIL engine for the sake of the example:

' ============================================= ' NAME: MouseOverControl() ' PARAMETERS: XPos AS INTEGER ' YPos AS INTEGER ' Width AS INTEGER ' Height AS INTEGER ' MouseX AS INTEGER ' MouseY AS INTEGER ' ASSUMES: Parameters are positive values ' RETURNS: True if mouse is on top of the ' control, False if it is not. ' CALLED FROM: EVRIL's main logic loop. ' --------------------------------------------- ' DESCRIPTION: This function will take the ' position and dimensions of a ' control, do the math to get ' the range of coordinates that ' the mouse need to be in to be ' considered to be on top of the ' control and compare the mouse ' coordinates to see if it falls ' within the control's range. If ' it does, True will be returned ' to the calling sub. If it's ' not on top of it, False will ' be returned instead. ' ============================================= FUNCTION MouseOverControl(XPos AS INTEGER, YPos AS INTEGER, _ Height AS INTEGER, Width AS INTEGER, _ MouseX AS INTEGER, MouseY AS INTEGER) AS INTEGER ' ------------------------------------------------ ' We create a variable to hold the error message ' ------------------------------------------------ DIM ErrorMessage AS STRING DIM BottomRightX AS INTEGER DIM BottomRightY AS INTEGER DIM WorkResult AS INTEGER ' -------------------------- ' Turn in Error management ' -------------------------- ON LOCAL ERROR GOTO ErrorManager ' --------------------------------------- ' Evaluate the bottom right coordinates ' --------------------------------------- BottomRightX = XPos + Width - 1 BottomRightX = YPos + Height - 1 ' ------------------------------------------------------------ ' Compare Mouse coordinates to control's area and return the ' proper value of the function based on if the mouse is over ' the control or not. ' ------------------------------------------------------------ IF (MouseX >= XPos AND MouseX <= BottomRightX) AND (MouseY >= YPos AND MouseY <= BottomRightY) THEN WorkResult = True ELSE WorkResult = False END IF ' ------------------------------------------------------------- ' Return the value and exit the function right here before ' execution of the error management section can take place ' if no error occured. ' ------------------------------------------------------------- MouseOverControl = WorkResult EXIT FUNCTION ' ------------------------------------------------------------------- ' This is where the error management message is created and printed ' ------------------------------------------------------------------- ErrorManager: ErrorMessage = "Engine: E.V.R.I.L." + CHR$(13) + _ "Module: EVRILEngineCore.bas" + CHR$(13) + _ "Function: MouseOverControl" + CHR$(13) + _ "Parameters: (" + STR$(XPos) + ", " + _ STR$(YPos) + ", " + _ STR$(Height) + ", " + _ STR$(Width) + ")" + CHR$(13) + _ "Error: " + STR$(Err) + ":" + Err$ ' ----------------------------------------------------- ' The full error message is now created. ErgonOS will ' have an error logging facility that when turned on ' will add this error to a log file along with time ' and date. If not we'll just display the error in ' a standard message box. ' ----------------------------------------------------- IF ErrorLogging = True THEN LogError(ErrorMessage) ELSE DisplayError(ErrorMessage) END IF ' --------------------------------------------------------------- ' In this case, we resume execution loging or showing the error ' --------------------------------------------------------------- RESUME NEXT END FUNCTION

As you can see, it takes a little bit extra coding to implemented error management properly. I'd rather have to add 10 lines everytime I create a sub than to have to find and add a couple 100 or 1000 lines of code by doing this part in the end, after the whole coding process is done. Error management is really there for two purposes. The first is of course to document the error when it occurs in an intelligent way that will help you know where to look and what type of error you'll be fixing. But it's also there so that the program doesn't quit in an uncivilized way. For example, say the user has a document currently opened. When there's no error management and the program just exists, there's a risk that the document might be either lost or corrupted (especially if the error occured as you were saving the file). Proper error management can prevent alot of these situations that make your system that much more stable and reliable to the users.

PART THREE NOW CONCLUDED:

This is it for the third part of the GUI Development Tutorial. The main thing to remember from this series and especially this third part is that you are free to create your own names, standards (if you want), your own component names, your own graphics, your own style. What you are reading here is based on my own project and as such I have the freedom to name things the way I want to. In the same frame of mind, because this is a tutorial series designed to make you, the reader, understands everything there is to know about GUI development from the very start to the end, I am making special efforts to name things very clearly and use a standard that can help you learn the type of coding I will do as well as how you can implement similar routines and structures in your own projects. The name of the game here is that GUI development should most of all be fun to make and to use after you made it. This means if you don't want to implement Error Management right away, you don't have to, but my own personal and professional experience has thought me that if you are planning to implement error management (which I highly recommend on any project that might be used by other people) then right now is the best time to do it because you can then integrate error management in your regular coding routine. As well, when you're done coding, you won't have to go through all your code to insert the error management code later.

I think we've now had enough of the theories, standards and conventions, the next part of this series will now concentrate on the ErgonOS development itself. We'll begin to define the information we'll need when creating components, or whole system of components, we'll start to create coding structures for this information, and we'll begin to put some code in all these modules we defined in this third part of the series. I hope you're enjoying the series so far, I sure am enjoying writing it for you (of course) but for me as well, since it's my GUI project, needless to say that this series will serve as an excellent document for the development of this project. So then, let all this knowledge sink in good. Maybe you've already started to document your own project as you're reading this and you'll want to do some documentary work on your project, go right ahead. For a project like this, you'll only thank yourself in the end. As always, if you have questions, if something in this document (or the other documents in the series) that isn't quite clear or that you'd like me to elaborate on in even more details, send me an email and let me know all about it. Untill Next time, happy reading, and learning.


MystikShadows
Stéphane Richard
srichard@adaworld.com