GUI Tutorial : Spinner Gadgets
What Is A Spinner?
If you don't know what a spinner is, then read this section. If you do know, then you can skip
this section. For those who don't know, lets continue. A spinner (or "up-down") control is a control with two arrow buttons on it that allow it to select a value. Pressing the up button of the control will increment this value (holding it will increment the value a bit faster). Pressing the down button of the control will decrement this value (holding it will decrement the value a bit faster). Usually, there is an additional control to the left of the spinner (An edit, AKA text-box control which allows values to be input). Spinners are useful for a variety of reasons - unfortunately I can't find one where a spinner is absolutely necessary (I'm doing this tutorial by request

).
How will our spinner be implemented?
Well, firstly our spinner will NOT use any child windows (buttons). Why? Because they're not necessary - we can squeeze more performance out of the spinner if we rely on just one control (in terms of GPU and CPU times, this would be more efficient). Think about it, if there are two controls attached to the spinner, then that means that for each spinner control, there are really 3 controls. So if you had, say, 9 spinners, there would be 27 controls to update! Quite unnecessary, IMO. Anyways, we'll implement spinners without buddy windows.
A buddy window is a window which has the same parent as another window, and communicates with that window, as that window does with it. We won't be using a buddy window because this adds unnecessary complication to our GUI (then again, so does our implementation to begin with ^_^).
The technical aspects of the implementation are this: We'll be using a single integer to hold 3 values through bitwise operations. These 3 values are; the value of the spinner [0-65535], the flags of the control [0-255], and a time-out value [0-255]. The flags let us know which button in the spinner is being highlighted or pressed. The time-out value lets us know how long the button has been held for.
I wrote the following section while working on the code for the tutorial. Please read it, and ignore the inconsistency with the general-tone of this tutorial.
Bitwise Notes
Guess which is slower!
A: x * 2
B: x << 1
They both equal the same answer. If x = 4, then x * 2 = 8 and x << 1 = 16).
Lets look for a second. When multiplying the processor has to do special
arithmetic to ensure an answer is correct. However, if the value in question
only has to be doubled (or multiplied by a power of two) then we can simply
shift the bits left by that power. So, if X = 4 (for a byte) then its bits
are %00000100. The bits for 8 as a byte are %00001000. Since the bits would
only be shifted left once, it's clearly quicker than performing a series of
complicated arithmetic and additional machine code instructions.
This technique can be applied for division by powers of two, but with the
right bit-shift operator, >>. For example, 128 / 2 = 64. 128 >> 1 = 64. It's
essentially the same operation in reverse, and much quicker than division.
NOTE: This technique does NOT work on floating point values, only integers,
dwords, words, bytes, and (probably) DBPro's booleans.
Look at the following operations - they will set a specific bit in an integer
to 0, set a specific bit in a integer to 1, and check what the value of a bit
in an integer is.
CLEAR_BIT(num,bit) { num = num && (0xFFFFFFFF - (1 << bit)) }
SET_BIT(num,bit) { num = num || (1 << bit) }
GET_BIT(num,bit) { is_bit_set = (num & (1 << bit)) }
In addition to all that interesting stuff, you can check if a value is
negative or not (avoiding the use of CMP and a JMP (Or if DBPro actually IS
optimized, a SETG/SETL/SETE/SETGE/SETLE instruction instead of JMP)) by
ANDing the value with 0x80000000. That's because by ANDing a value with
0x80000000 you're checking if the sign-bit has been set (this is why if you
display a number like 0xFFEEDDCC through the PRINT command you get a negative
number). So! Let's make our own ABS function!
function Absolute(num as integer)
if num && 0x80000000 then num = num && 0x7FFFFFFF
endfunction num
As you can tell, bitwise operations can be great performance optimizers if
used correctly in tight loops. Not to mention they're probably one of the
funnest aspects of programming! ^_^
On To Our Spinner Control!
Firstly, to implement this, we'll outline the same procedure as our previous tutorials. Add the class constant, and create two empty functions (One for updating, and one for rendering). But, in addition to that, we're also going to add some additional constants.
Flag constants to be exact. If you read the above bitwise notes section then you can see CLEAR_BIT, SET_BIT, and GET_BIT, and understand that every value in any data type is just a series of bits (0s, and 1s). Flags can be "magically OR'd" together through the || operator (You can also use the + operator, but I prefer the || operator). Anyways, we won't have to use CLEAR_BIT, SET_BIT, or GET_BIT to check our flags, we can implement these fairly easily. Do you know how numbers look in binary? Look at the following:
0000 = 0
0001 = 1
0010 = 2
0011 = 3
0100 = 4
0101 = 5
0110 = 6
0111 = 7
1000 = 8
1001 = 9
1010 = A hex, 10 dec
1011 = B hex, 11 dec
1100 = C hex, 12 dec
1101 = D hex, 13 dec
1110 = E hex, 14 dec
1111 = F hex, 15 dec
Lets say that 1 represents a flag A, 2 represents flag B, and 4 represents flag C. Notice anything in common? Well, 1 = 0001, 2 = 0010, and 4 = 0100. Can you guess what value flag D would have? Flag D would be 8 (1000). The reason for this is these values (They're powers of two) represent specific bits being set. So, the next value after 0x08 would be 0x10, then 0x20, then 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000 (and so on). Or in decimal; 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 (and so on).
Anyways, when flags get OR'd together, it "combines" them. Okay, take flag A, flag B, and flag C for instance, (%0001, %0010, %0100, respectively.) If you have a variable called flags (which should be initialized to zero before anything else), then you would be able to do the following:
flags = FLAG_A || FLAG_C Now, if you did that the value would be %0101. If you changed FLAG_C to FLAG_B it would be %0011. And so on. You can also add flags, for example, say the flags variable is 3 (FLAG_A || FLAG_B). You could add a flag like so:
flags = flags || OTHER_FLAG.
Now, checking a flag is REALLY easy. You just do a bitwise AND (The && operator in DBPro) on the flags variable with the flag in question to check. If, for some reason, you are confused about this, go ahead and ask me a question. (
DO NOT email me, I'm tired of all the spam about
"OMG! Wil u give m3 s0urce c0d3 plz?!" - Just post here).
Sorry for the long explanation of what a flag is, and how to use it, but it's necessary information as you're going to add constants for them. We have 4 flags. SPI_FLG_UP_HIGHLIGHT, SPI_FLG_UP_PRESSED, SPI_FLG_DN_HIGHLIGHT, SPI_FLG_DN_PRESSED. (
Spinner Flag - Up Highlight, Spinner Flag - Up Pressed, Spinner Flag - Down Highlight, Spinner Flag - Down Pressed).
Remember those update and render procedures you made a little while back? Well, lets edit those. FIRSTLY, our spinner only has on it two "buttons." Neither the spinner, or the button contains any text. So, with this information you should be able to construct the bodies for both the update and render functions for the spinner. Firstly, there's no horizontal/vertical spinners here - I don't see spinners necessary at all, why would I find horizontal spinners necessary? So we know that the top button takes up the top half of the spinner. The bottom button thus takes up the bottom half of the spinner. Now, whenever the user moves the mouse within range of one of these areas, we can set the highlight flag for the corresponding area on. And if the user is clicking the area, we can set the pressed flag on for that area. You should know how to do this from the example above, but if not you can go ahead and look at the source code (cheater

).
NOTE: -
We could use the text of the spinner as a way to represent the value of the spinner - and you can do this if you like to avoid certain aspects of bitwise operations. However, the bitwise operations are much more efficient than the text operations, so I'd recommend those. You're only limit is that you have to deal with a limited range of values for the spinner (0 .. 65535). In addition, you could allocate another structure with MAKE MEMORY and then set the windowData as a pointer to that structure, freeing the memory when the window closes, but this isn't something I plan on teaching in DBPro (I want to save you the frustration - If you want to use pointers and other advanced programming concepts, move on up to C++).
As for the render function, all you need to do is draw the buttons and draw arrows where the text should be. To do this I just drew 2 boxes, 5 lines, and 2 triangles. Again, if you're confused as to how to do this (I didn't tell you how to draw a triangle with Advanced2D, so I expect you would be) then you can just have a look at the source code. Keep in mind, that when drawing you'll want to check the flags of the spinner to see how things are done. Not doing this will yield an ugly looking spinner control (Then again, it's a sort of ugly GUI, might as well match the style

).
And that's it! Just create your spinner and let it draw. The source code to this tutorial is shown below, and a working executable is attached.

Please realize I was only able to put bits and pieces of this tutorial very little at a time due to some personal issues (Moving, packing, dealing with idiots, lack of motivation, etc). I apologize greatly for the inconvenience as, apparently some people seem to like the tutorials I've been writing. Now, please realize that my method for writing GUIs isn't the ONLY method out there. It's just the one I chose for this tutorial. It's relatively simple, and does rely on a renderer. There are much more complex GUIs, and I chose to write a simple one that can easily be expanded upon. It is a DBPro GUI system, so bare with me.
NOTE: -
These are the reasons this tutorial took so long to complete:
1. Lack of motivation
2. Installation of Ubuntu (3 times)
3. Minimization of hard drive space
4. Working on an OS - ran into some bugs with the file system (Everything else working great
).
5. Lack of time on the computer
6. Reading old planet zebeth comics - w00t! Go mature humor in retro games!
7. Packing, moving, destroying furniture
8. Some other C++ projects
9. I just felt like adding a ninth reason, that's it really
ALSO, I'm probably going to change the tutorial "style" from showing source code at the end, to showing it where-ever I reference it (Or, rather, a mix between that system and the current one).
SOURCE CODE 1-4
REM Project: GUI Tutorial
REM Created: 10/16/2008 9:47:45 PM
REM
REM ***** Main Source File *****
REM
REMSTART
Bitwise notes
Guess which is slower!
A: x * 2
B: x << 1
They both equal the same answer. If x = 4, then x * 2 = 8 and x << 1 = 16).
Lets look for a second. When multiplying the processor has to do special
arithmetic to ensure an answer is correct. However, if the value in question
only has to be doubled (or multiplied by a power of two) then we can simply
shift the bits left by that power. So, if X = 4 (for a byte) then its bits
are %00000100. The bits for 8 as a byte are %00001000. Since the bits would
only be shifted left once, it's clearly quicker than performing a series of
complicated arithmetic and additional machine code instructions.
This technique can be applied for division by powers of two, but with the
right bit-shift operator, >>. For example, 128 / 2 = 64. 128 >> 1 = 64. It's
essentially the same operation in reverse, and much quicker than division.
NOTE: This technique does NOT work on floating point values, only integers,
dwords, words, bytes, and (probably) DBPro's booleans.
Look at the following operations - they will set a specific bit in an integer
to 0, set a specific bit in a integer to 1, and check what the value of a bit
in an integer is.
CLEAR_BIT(num,bit) { num = num && (0xFFFFFFFF - (1 << bit)) }
SET_BIT(num,bit) { num = num || (1 << bit) }
GET_BIT(num,bit) { is_bit_set = (num & (1 << bit)) }
In addition to all that interesting stuff, you can check if a value is
negative or not (avoiding the use of CMP and a JMP (Or if DBPro actually IS
optimized, a SETG/SETL/SETE/SETGE/SETLE instruction instead of JMP)) by
ANDing the value with 0x80000000. That's because by ANDing a value with
0x80000000 you're checking if the sign-bit has been set (this is why if you
display a number like 0xFFEEDDCC through the PRINT command you get a negative
number). So! Let's make our own ABS function!
function Absolute(num as integer)
if num && 0x80000000 then num = num && 0x7FFFFFFF
endfunction num
As you can tell, bitwise operations can be great performance optimizers if
used correctly in tight loops. Not to mention they're probably one of the
funnest aspects of programming! ^_^
REMEND
REMSTART
CONSTANTS
REMEND
`Draw types
#constant DRAW_TYPE_BOX 0
#constant DRAW_TYPE_TRIANGLE 1
#constant DRAW_TYPE_LINE 2
#constant DRAW_TYPE_POINT 3
`Windows
#constant MAX_WINDOWS 512
`Window Classes
#constant CLASS_WINDOW 1
#constant CLASS_LABEL 2
#constant CLASS_BUTTON 3
#constant CLASS_CHECKBOX 4
#constant CLASS_RADIOBOX 5
#constant CLASS_SPINNER 6
#constant NUM_CLASSES 6
`Window Colors
#constant WND_CAP_COL_TOP_LEFT 0xFFA6CAF0
#constant WND_CAP_COL_TOP_RIGHT 0xFFA6CAF0
#constant WND_CAP_COL_BTM_LEFT 0xFF0A246A
#constant WND_CAP_COL_BTM_RIGHT 0xFF0A246A
#constant WND_CLI_COL_TOP_LEFT 0xEEE4E4E4
#constant WND_CLI_COL_TOP_RIGHT 0xEEE4E4E4
#constant WND_CLI_COL_BTM_LEFT 0xEEA4A4A4
#constant WND_CLI_COL_BTM_RIGHT 0xEEA4A4A4
#constant WND_BORDER_COL 0xFF404040
#constant WND_TEXT_COL 0xFFFFFFFF
#constant WND_TEXT_BG 0xFF000000
#constant IWN_CAP_COL_TOP_LEFT 0xFFC0C0C0
#constant IWN_CAP_COL_TOP_RIGHT 0xFFC0C0C0
#constant IWN_CAP_COL_BTM_LEFT 0xFF808080
#constant IWN_CAP_COL_BTM_RIGHT 0xFF808080
#constant IWN_CLI_COL_TOP_LEFT 0xDEE4E4E4
#constant IWN_CLI_COL_TOP_RIGHT 0xDEE4E4E4
#constant IWN_CLI_COL_BTM_LEFT 0xDEA4A4A4
#constant IWN_CLI_COL_BTM_RIGHT 0xDEA4A4A4
#constant IWN_BORDER_COL 0xFF404040
#constant IWN_TEXT_COL 0xFFD4D0C8
#constant IWN_TEXT_BG 0xFFFFFFFF
`Button Colors
#constant BTI_OUTLINE_COLOR 0xFF000000
#constant BTI_COL_TOP_LEFT 0xFFB0B0B0
#constant BTI_COL_TOP_RIGHT 0xFFB0B0B0
#constant BTI_COL_BTM_LEFT 0xFF909090
#constant BTI_COL_BTM_RIGHT 0xFF909090
#constant BTH_OUTLINE_COLOR 0xFF000000
#constant BTH_COL_TOP_LEFT 0xFFD0D0D0
#constant BTH_COL_TOP_RIGHT 0xFFD0D0D0
#constant BTH_COL_BTM_LEFT 0xFFB0B0B0
#constant BTH_COL_BTM_RIGHT 0xFFB0B0B0
#constant BTP_OUTLINE_COLOR 0xFF000000
#constant BTP_COL_TOP_LEFT 0xFF606060
#constant BTP_COL_TOP_RIGHT 0xFF606060
#constant BTP_COL_BTM_LEFT 0xFF808080
#constant BTP_COL_BTM_RIGHT 0xFF808080
`Spinner Flags
#constant SPI_FLG_UP_HIGHLIGHT 0x00000001
#constant SPI_FLG_UP_PRESSED 0x00000002
#constant SPI_FLG_DN_HIGHLIGHT 0x00000004
#constant SPI_FLG_DN_PRESSED 0x00000008
REMSTART
TYPES
REMEND
`A window
type tWindow
exist as boolean
class as dword
flags as dword
text$ as string
x as integer
y as integer
w as integer
h as integer
fgCol as dword
bgCol as dword
lcCount as integer
mcCount as integer
rcCount as integer
windowData as integer
userData as integer
parentWindow as integer
nextWindow as integer
prevWindow as integer
firstChild as integer
lastChild as integer
endtype
`A rectangle
type tRect
x1 as integer
y1 as integer
x2 as integer
y2 as integer
endtype
REMSTART
GLOBALS
REMEND
`Windows
global dim g_wndList(MAX_WINDOWS) as tWindow
`Input
global g_oldMouseClick as integer : g_oldMouseClick = 0
global g_mouseClick as integer : g_mouseClick = 0
global g_mouseX as integer : g_mouseX = 0
global g_mouseY as integer : g_mouseY = 0
global g_mouseOver as integer : g_mouseOver = 0
`Dragging
global g_dragWnd as integer : g_dragWnd = 0
global g_dragX as integer : g_dragX = 0
global g_dragY as integer : g_dragY = 0
`Timing
global g_prevTime as integer : g_prevTime = 0
global g_curTime as integer : g_curTime = 0
REMSTART
MAIN CODE
REMEND
`Setup sync
sync on
sync
`Initialize Advanced 2D
Init Advanced 2D
`Load a wallpaper
load image "Wallpaper.jpg", 1
`Change the font
set text font "Courier New"
set text size 16
`Create the windows
wnd1 = MakeWindow(CLASS_WINDOW, 0, "My Window", 30, 30, 320, 240, 0)
wnd2 = MakeWindow(CLASS_WINDOW, 0, "Other Window", 60, 60, 320, 240, 0)
lbl1 = MakeWindow(CLASS_LABEL, 0, "Hello World!", 0, 0, 100, 20, wnd1)
lbl2 = MakeWindow(CLASS_LABEL, 0, "Hello World!", 0, 0, 100, 20, wnd2)
btn1 = MakeWindow(CLASS_BUTTON, 0, "Button #1", 110, 10, 120, 20, wnd1)
btn2 = MakeWindow(CLASS_BUTTON, 0, "Button #2", 110, 10, 120, 20, wnd2)
cb1 = MakeWindow(CLASS_CHECKBOX, 0, "Checkbox #1", 0, 30, 120, 20, wnd1)
cb2 = MakeWindow(CLASS_CHECKBOX, 0, "Checkbox #2", 0, 50, 120, 20, wnd1)
rb1 = MakeWindow(CLASS_RADIOBOX, 0, "Radiobox #1", 0, 30, 120, 20, wnd2)
rb2 = MakeWindow(CLASS_RADIOBOX, 0, "Radiobox #2", 0, 50, 120, 20, wnd2)
sp1 = MakeWindow(CLASS_SPINNER, 0, "", 200, 80, 20, 20, wnd1)
sp2 = MakeWindow(CLASS_SPINNER, 0, "", 200, 80, 20, 20, wnd2)
spl1 = MakeWindow(CLASS_LABEL, 0, "", 150, 85, 50, 20, wnd1)
spl2 = MakeWindow(CLASS_LABEL, 0, "", 150, 85, 50, 20, wnd2)
SetSpinnerValue(sp1, 5)
SetSpinnerValue(sp2, 10)
`Main loop
do
`Preliminary
Set Texture 1
Stream Source To Texture Vertex Buffer
Prepare Image 0, 0, screen width(), screen height(), 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
Draw DRAW_TYPE_BOX
`Update the text of the labels
SetWindowText(spl1, str$(GetSpinnerValue(sp1)))
SetWindowText(spl2, str$(GetSpinnerValue(sp2)))
`Update
UpdateGUI()
sync
loop
`If we ever leave the loop we should end
end
REMSTART
UTILITY FUNCTIONS
REMEND
`Display an error and exit
function Error(msg$ as string)
exit prompt msg$, "Error"
end
endfunction
`Draw text with a shadow under it
function ShadowText(tx as integer, ty as integer, txt$ as string, fg as dword, bg as dword)
remstart
Set Font g_guiFont
Draw Text g_guiFont, tx + 1, ty + 1, txt$, bg
Draw Text g_guiFont, tx, ty, txt$, fg
remend
ink bg, 0
text tx + 1, ty + 1, txt$
ink fg, 0
text tx, ty, txt$
endfunction
`Draw an up arrow
function DrawUpArrow(x as integer, y as integer, w as integer, h as integer, c as dword)
Prepare Triangle x-1, y+h, x+w+1, y+h, x+(w/2), y-1, c, c, c
Draw DRAW_TYPE_TRIANGLE
endfunction
`Draw a down arrow
function DrawDownArrow(x as integer, y as integer, w as integer, h as integer, c as dword)
Prepare Triangle x, y, x+w, y, x+(w/2), y+h, c, c, c
Draw DRAW_TYPE_TRIANGLE
endfunction
REMSTART
GUI FUNCTIONS
REMEND
`Update the GUI
function UpdateGUI()
g_mouseX = mousex()
g_mouseY = mousey()
g_oldMouseClick = g_mouseClick
g_mouseClick = mouseclick()
g_mouseOver = InWhatWindow(0, g_mouseX, g_mouseY)
if g_mouseClick = 0
g_dragWnd = 0
g_dragX = 0
g_dragY = 0
endif
g_prevTime = g_curTime
g_curTime = timer()
__Call_Window_Procs__(0)
if g_dragWnd > 0
oldx = g_wndList(g_dragWnd).x
oldy = g_wndList(g_dragWnd).y
g_wndList(g_dragWnd).x = g_mouseX - g_dragX
g_wndList(g_dragWnd).y = g_mouseY - g_dragY
child = g_wndList(g_dragWnd).firstChild
while child <> 0
g_wndList(child).x = (g_wndList(child).x - oldx) + g_wndList(g_dragWnd).x
g_wndList(child).y = (g_wndList(child).y - oldy) + g_wndList(g_dragWnd).y
child = g_wndList(child).nextWindow
endwhile
endif
Alpha Blend On 0
Set Texture 0
__Redraw_Windows__(0)
Set Viewport 0, 0, screen width(), screen height()
endfunction
`Check to see if a window exists
function WindowExist(id as integer)
exist = 0
if id > 0 and id < MAX_WINDOWS + 1 then exist = g_wndList(id).exist
endfunction exist
`Check to see if a class exists
function ClassExist(class as dword)
exist = 0
if class > 0 and class < NUM_CLASSES + 1 then exist = 1
endfunction exist
`Find an unused window index
function FindFreeWindow()
id = 1
while g_wndList(id).exist = 1
id = id + 1
if id > MAX_WINDOWS then exitfunction 0
endwhile
endfunction id
`Create a window
function MakeWindow(class as dword, flags as dword, text$ as string, x as integer, y as integer, w as integer, h as integer, parent as integer)
id = FindFreeWindow()
if id = 0 then Error("Too many windows exist!")
if ClassExist(class) = 0 then Error("Class " + str$(class) + " Does Not Exist.")
if parent <> 0
if WindowExist(parent) = 0 then Error("Parent Window " + str$(parent) + " Does Not Exist")
endif
g_wndList(id).exist = 1
g_wndList(id).class = class
g_wndList(id).flags = flags
g_wndList(id).text$ = text$
g_wndList(id).x = x + g_wndList(parent).x + 1
g_wndList(id).y = y + g_wndList(parent).y + 21
g_wndList(id).w = w
g_wndList(id).h = h
g_wndList(id).fgCol = 0xffffffff
g_wndList(id).bgCol = 0xff000000
g_wndList(id).windowData = 0
g_wndList(id).userData = 0
g_wndList(id).parentWindow = parent
g_wndList(id).prevWindow = g_wndList(parent).lastChild
g_wndList(id).nextWindow = 0
g_wndList(id).firstChild = 0
g_wndList(id).lastChild = 0
if g_wndList(parent).lastChild > 0
g_wndList(g_wndList(parent).lastChild).nextWindow = id
endif
g_wndList(parent).lastChild = id
if g_wndList(parent).firstChild = 0 then g_wndList(parent).firstChild = id
WindowToFront(id)
endfunction id
`Destroy a window
function KillWindow(id as integer)
if id > 0 and WindowExist(id) = 1
child = g_wndList(id).firstChild
while child <> 0
KillWindow(child)
child = g_wndList(id).firstChild
endwhile
parent = g_wndList(id).parentWindow
nextWindow = g_wndList(id).nextWindow
prevWindow = g_wndList(id).prevWindow
if prevWindow > 0 then g_wndList(prevWindow).nextWindow = nextWindow
if nextWindow > 0 then g_wndList(nextWindow).prevWindow = prevWindow
if g_wndList(parent).firstChild = id
g_wndList(parent).firstChild = nextWindow
endif
if g_wndList(parent).lastChild = id
g_wndList(parent).lastChild = prevWindow
endif
g_wndList(id).exist = 0
else
Error("Window " + str$(id) + " Does Not Exist")
endif
endfunction
`Move a window to the front of the list
function WindowToFront(id as integer)
if id = 0 then exitfunction
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist.")
parent = g_wndList(id).parentWindow
nextWindow = g_wndList(id).nextWindow
prevWindow = g_wndList(id).prevWindow
if prevWindow > 0 then g_wndList(prevWindow).nextWindow = nextWindow
if nextWindow > 0 then g_wndList(nextWindow).prevWindow = prevWindow
if g_wndList(parent).firstChild = id
g_wndList(parent).firstChild = nextWindow
endif
if g_wndList(parent).lastChild = id
g_wndList(parent).lastChild = prevWindow
endif
g_wndList(id).prevWindow = g_wndList(parent).lastChild
g_wndList(id).nextWindow = 0
if g_wndList(parent).lastChild <> 0
g_wndList(g_wndList(parent).lastChild).nextWindow = id
endif
g_wndList(parent).lastChild = id
if g_wndList(parent).firstChild = 0
g_wndList(parent).firstChild = id
endif
endfunction
`Check what window a point is in
function InWhatWindow(parent as integer, x as integer, y as integer)
if parent <> 0
if WindowExist(parent) = 0 then Error("Parent Window " + str$(parent) + " Does Not Exist.")
endif
child = g_wndList(parent).lastChild
while child <> 0
hit = InWhatWindow(child, x, y)
if hit <> 0 then exitfunction hit
child = g_wndList(child).prevWindow
endwhile
if x - 1 > g_wndList(parent).x and y - 1 > g_wndList(parent).y
if x - 1 < g_wndList(parent).x + g_wndList(parent).w and y - 1 < g_wndList(parent).y + g_wndList(parent).h
exitfunction parent
endif
endif
endfunction 0
REMSTART
INTERNAL WINDOW FUNCTIONS
REMEND
`Call all the procedures belong to a window family
function __Call_Window_Procs__(id as integer)
wnd = g_wndList(id).firstChild
while wnd <> 0
__Call_Window_Procs__(wnd)
__Gadget_Proc__(wnd)
wnd = g_wndList(wnd).nextWindow
endwhile
endfunction
`Redraw all the windows
function __Redraw_Windows__(id as integer)
if id <> 0
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist.")
endif
__Draw_Gadget__(id)
wnd = g_wndList(id).firstChild
while wnd <> 0
__Redraw_Windows__(wnd)
wnd = g_wndList(wnd).nextWindow
endwhile
endfunction
`Handles a wnd
function __Gadget_Proc__(id as integer)
if g_mouseOver = id
if g_oldMouseClick = 0 and g_mouseClick > 0
`Move the window to the front
if g_wndList(id).class = CLASS_WINDOW
WindowToFront(id)
else
WindowToFront(g_wndList(id).parentWindow)
endif
endif
if g_oldMouseClick = 1 and g_mouseClick = 0 then g_wndList(id).lcCount = g_wndList(id).lcCount + 1
if g_oldMouseClick = 2 and g_mouseClick = 0 then g_wndList(id).rcCount = g_wndList(id).rcCount + 1
if g_oldMouseClick = 4 and g_mouseClick = 0 then g_wndList(id).mcCount = g_wndList(id).mcCount + 1
endif
if g_wndList(id).class = CLASS_WINDOW then __Window_Proc__(id) : exitfunction
if g_wndList(id).class = CLASS_LABEL then __Label_Proc__(id) : exitfunction
if g_wndList(id).class = CLASS_BUTTON then __Button_Proc__(id) : exitfunction
if g_wndList(id).class = CLASS_CHECKBOX then __CheckBox_Proc__(id) : exitfunction
if g_wndList(id).class = CLASS_RADIOBOX then __RadioBox_Proc__(id) : exitfunction
if g_wndList(id).class = CLASS_SPINNER then __Spinner_Proc__(id) : exitfunction
endfunction
`Draws a wnd
function __Draw_Gadget__(id as integer)
if id > 0
Stream Source To Primitive Vertex Buffer
Set Viewport g_wndList(id).x, g_wndList(id).y, g_wndList(id).w + 1, g_wndList(id).h + 1
if g_wndList(id).class = CLASS_WINDOW then __Draw_Window__(id) : exitfunction
if g_wndList(id).class = CLASS_LABEL then __Draw_Label__(id) : exitfunction
if g_wndList(id).class = CLASS_BUTTON then __Draw_Button__(id) : exitfunction
if g_wndList(id).class = CLASS_CHECKBOX then __Draw_CheckBox__(id) : exitfunction
if g_wndList(id).class = CLASS_RADIOBOX then __Draw_RadioBox__(id) : exitfunction
if g_wndList(id).class = CLASS_SPINNER then __Draw_Spinner__(id) : exitfunction
endif
endfunction
REMSTART
WINDOW CLASS FUNCTIONS
REMEND
`The window procedure
function __Window_Proc__(id as integer)
if g_mouseOver = id
if g_mouseClick = 1 and g_oldMouseClick = 0 and g_mouseY < g_wndList(id).y + 21
if g_dragWnd = 0
g_dragWnd = id
g_dragX = g_mouseX - g_wndList(id).x
g_dragY = g_mouseY - g_wndList(id).y
endif
endif
endif
endfunction
`How to render a window
function __Draw_Window__(id as integer)
x = g_wndList(id).x
y = g_wndList(id).y
w = g_wndList(id).w
h = g_wndList(id).h
fg = g_wndList(id).fgCol
bg = g_wndList(id).bgCol
txt$ = g_wndList(id).text$
if g_wndList(0).lastChild = id
Prepare Box x, y, x + w + 1, y + 20, WND_CAP_COL_TOP_LEFT, WND_CAP_COL_TOP_RIGHT, WND_CAP_COL_BTM_LEFT, WND_CAP_COL_BTM_RIGHT
Draw DRAW_TYPE_BOX
Prepare Box x, y + 20, x + w + 1, y + h + 1, WND_CLI_COL_TOP_LEFT, WND_CLI_COL_TOP_RIGHT, WND_CLI_COL_BTM_LEFT, WND_CLI_COL_BTM_RIGHT
Draw DRAW_TYPE_BOX
else
Prepare Box x, y, x + w + 1, y + 20, IWN_CAP_COL_TOP_LEFT, IWN_CAP_COL_TOP_RIGHT, IWN_CAP_COL_BTM_LEFT, IWN_CAP_COL_BTM_RIGHT
Draw DRAW_TYPE_BOX
Prepare Box x, y + 20, x + w + 1, y + h + 1, IWN_CLI_COL_TOP_LEFT, IWN_CLI_COL_TOP_RIGHT, IWN_CLI_COL_BTM_LEFT, IWN_CLI_COL_BTM_RIGHT
Draw DRAW_TYPE_BOX
endif
c = WND_BORDER_COL
if g_modalDialog = id then c = IWN_BORDER_COL
Prepare Line x, y, x + w + 1, y, c, c
Draw DRAW_TYPE_LINE
Prepare Line x, y, x, y + h + 1, c, c
Draw DRAW_TYPE_LINE
Prepare Line x + w, y, x + w, y + h + 1, c, c
Draw DRAW_TYPE_LINE
Prepare Line x, y + h, x + w + 1, y + h, c, c
Draw DRAW_TYPE_LINE
Prepare Line x, y + 20, x + w + 1, y + 20, c, c
Draw DRAW_TYPE_LINE
tx = x + ( (w/2) - (text width(txt$)/2) )
ty = y + ( 10 - (text height(txt$)/2) )
ShadowText(tx, ty, txt$, fg, bg)
endfunction
REMSTART
LABEL CLASS FUNCTIONS
REMEND
`Update the label
function __Label_Proc__(id as integer)
`TO DO: Label stuff
endfunction
`Draw the label
function __Draw_Label__(id as integer)
ShadowText(g_wndList(id).x, g_wndList(id).y, g_wndList(id).text$, g_wndList(id).fgCol, g_wndList(id).bgCol)
endfunction
REMSTART
BUTTON CLASS FUNCTIONS
REMEND
`Update the button
function __Button_Proc__(id as integer)
`Is there a left click?
if g_mouseClick = 1
`Did the left click just occur?
if g_oldMouseClick = 0
`When the left click occured, did it happen on the button?
if g_mouseOver = id
`If so the button is now in a pressed state (windowData = 2)
g_wndList(id).windowData = 2
endif
endif
`Is there no left click?
else
`Is the mouse currently over the button?
if g_mouseOver = id
`If so the button is now in a highlight state (windowData = 1)
g_wndList(id).windowData = 1
else
`Otherwise, the button's state is normal (windowData = 0)
g_wndList(id).windowData = 0
endif
endif
endfunction
`Draw the button
function __Draw_Button__(id as integer)
`Retrieve some 'lazy' variables
x = g_wndList(id).x
y = g_wndList(id).y
w = g_wndList(id).w
h = g_wndList(id).h
fg = g_wndList(id).fgCol
bg = g_wndList(id).bgCol
txt$ = g_wndList(id).text$
`Are we using the idle scheme?
if g_wndList(id).windowData = 0
`Idle scheme should be used
olc = BTI_OUTLINE_COLOR
tlc = BTI_COL_TOP_LEFT
trc = BTI_COL_TOP_RIGHT
blc = BTI_COL_BTM_LEFT
brc = BTI_COL_BTM_RIGHT
endif
`Are we using the highlighted scheme?
if g_wndList(id).windowData = 1
`Highlighted scheme should be used
olc = BTH_OUTLINE_COLOR
tlc = BTH_COL_TOP_LEFT
trc = BTH_COL_TOP_RIGHT
blc = BTH_COL_BTM_LEFT
brc = BTH_COL_BTM_RIGHT
endif
`Are we using the pressed scheme?
if g_wndList(id).windowData = 2
`Pressed scheme should be used
olc = BTP_OUTLINE_COLOR
tlc = BTP_COL_TOP_LEFT
trc = BTP_COL_TOP_RIGHT
blc = BTP_COL_BTM_LEFT
brc = BTP_COL_BTM_RIGHT
endif
`Draw the box
Prepare Box x, y, x+w+1, y+h+1, tlc, trc, blc, brc
Draw DRAW_TYPE_BOX
`Draw the outline
Prepare Line x, y, x+w+1, y, olc, olc
Draw DRAW_TYPE_LINE
Prepare Line x, y, x, y+h+1, olc, olc
Draw DRAW_TYPE_LINE
Prepare Line x+w, y, x+w, y+h+1, olc, olc
Draw DRAW_TYPE_LINE
Prepare Line x, y+h, x+w+1, y+h, olc, olc
Draw DRAW_TYPE_LINE
`Draw the text
ShadowText(x+((w/2)-(text width(txt$)/2)), y+((h/2)-(text height(txt$)/2)), txt$, fg, bg)
endfunction
REMSTART
CHECK BOX CLASS FUNCTIONS
REMEND
`Checkbox update procedure
function __CheckBox_Proc__(id as integer)
if g_mouseOver = id
if g_mouseClick = 1 and g_oldMouseClick = 0
if g_wndList(id).windowData = 1
g_wndList(id).windowData = 0
else
g_wndList(id).windowData = 1
endif
endif
endif
endfunction
`Draw the checkbox
function __Draw_CheckBox__(id as integer)
x = g_wndList(id).x
y = g_wndList(id).y
w = g_wndList(id).w
h = g_wndList(id).h
fg = g_wndList(id).fgCol
bg = g_wndList(id).bgCol
txt$ = g_wndList(id).text$
bx = x + 2
by = y + 2
bw = h - 4
bh = bw
Prepare Box bx, by, bx + bw, by + bh, bg, bg, bg + 0x00404040, bg + 0x00404040
Draw DRAW_TYPE_BOX
c = fg
if g_mouseOver = id then c = 0xff00ffff
Prepare Line bx, by, bx + bw + 1, by, c, c
Draw DRAW_TYPE_LINE
Prepare Line bx, by, bx, by + bh + 1, c, c
Draw DRAW_TYPE_LINE
Prepare Line bx + bw, by, bx + bw, by + bh + 1, c, c
Draw DRAW_TYPE_LINE
Prepare Line bx, by + bh, bx + bw + 1, by + bh, c, c
Draw DRAW_TYPE_LINE
if g_wndList(id).windowData = 1
Prepare Box bx + 6, by + 6, bx + bw - 5, by + bh - 5, fg, fg, fg - 0x00404040, fg - 0x00404040
Draw DRAW_TYPE_BOX
endif
tx = bx + bw + 2
ty = y + ( (h/2) - (text height(txt$)/2) )
ShadowText(tx, ty, txt$, fg, bg)
endfunction
REMSTART
RADIO BOX CLASS FUNCTIONS
REMEND
`Radiobox update procedure
function __RadioBox_Proc__(id as integer)
parent = g_wndList(id).parentWindow
if g_mouseOver = id
if g_mouseClick = 1 and g_oldMouseClick = 0
child = g_wndList(parent).firstChild
while child <> 0
if g_wndList(child).class = CLASS_RADIOBOX
g_wndList(child).windowData = 0
endif
child = g_wndList(child).nextWindow
endwhile
g_wndList(id).windowData = 1
endif
endif
endfunction
`Draw the radiobox
function __Draw_RadioBox__(id as integer)
x = g_wndList(id).x
y = g_wndList(id).y
w = g_wndList(id).w
h = g_wndList(id).h
fg = g_wndList(id).fgCol
bg = g_wndList(id).bgCol
txt$ = g_wndList(id).text$
bx = x + 2
by = y + 2
bw = h - 4
bh = bw
Prepare Box bx, by, bx + bw, by + bh, bg, bg, bg + 0x00404040, bg + 0x00404040
Draw DRAW_TYPE_BOX
c = fg
if g_mouseOver = id then c = 0xff00ffff
Prepare Line bx, by, bx + bw + 1, by, c, c
Draw DRAW_TYPE_LINE
Prepare Line bx, by, bx, by + bh + 1, c, c
Draw DRAW_TYPE_LINE
Prepare Line bx + bw, by, bx + bw, by + bh + 1, c, c
Draw DRAW_TYPE_LINE
Prepare Line bx, by + bh, bx + bw + 1, by + bh, c, c
Draw DRAW_TYPE_LINE
if g_wndList(id).windowData = 1
Prepare Box bx + 6, by + 6, bx + bw - 5, by + bh - 5, fg, fg, fg - 0x00404040, fg - 0x00404040
Draw DRAW_TYPE_BOX
endif
tx = bx + bw + 2
ty = y + ( (h/2) - (text height(txt$)/2) )
ShadowText(tx, ty, txt$, fg, bg)
endfunction
REMSTART
SPINNER CLASS FUNCTIONS
REMEND
`Update the spinner
function __Spinner_Proc__(id as integer)
`Preliminary
rctUp as tRect
rctDn as tRect
lowWord as word
highWord as word
lowByte as byte
highByte as byte
`Set the up region
rctUp.x1 = g_wndList(id).x
rctUp.y1 = g_wndList(id).y
rctUp.x2 = rctUp.x1 + g_wndList(id).w
rctUp.y2 = rctUp.y1 + (g_wndList(id).h >> 1) `Divide by two through a right bitshift
`Set the down region
rctDn.x1 = rctUp.x1
rctDn.y1 = rctUp.y2
rctDn.x2 = rctUp.x2
rctDn.y2 = rctUp.y1 + g_wndList(id).h
`Determine the low and high bits
lowWord = g_wndList(id).windowData && 0xFFFF
highWord = (g_wndList(id).windowData >> 16) && 0xFFFF
lowByte = lowWord && 0xFF
highByte = (lowWord >> 8) && 0xFF
`Is there a left click?
if g_mouseClick = 1
`Did the left click just occur?
if g_oldMouseClick = 0
`When the left click occured, did it happen on the button?
if g_mouseOver = id
`Check if the mouse is within the up region
if g_mouseY > rctUp.y1 and g_mouseY < rctUp.y2 then lowByte = SPI_FLG_UP_PRESSED : highByte = 0 : highWord = highWord + 1
`Check if the mouse is within the down region
if g_mouseY > rctDn.y1 and g_mouseY < rctDn.y2 then lowByte = SPI_FLG_DN_PRESSED : highByte = 0 : highWord = highWord - 1
endif
endif
`Is there no left click?
else
`Is the mouse currently over the button?
if g_mouseOver = id
`Check if the mouse is within the up region
if g_mouseY > rctUp.y1 and g_mouseY < rctUp.y2 then lowByte = SPI_FLG_UP_HIGHLIGHT : highByte = 0
`Check if the mouse is within the down region
if g_mouseY > rctDn.y1 and g_mouseY < rctDn.y2 then lowByte = SPI_FLG_DN_HIGHLIGHT : highByte = 0
else
`Otherwise, the button's state is normal (windowData = 0)
lowByte = 0
highByte = 0
endif
endif
`Check if one of the buttons is set
if lowByte && SPI_FLG_UP_PRESSED or lowByte && SPI_FLG_DN_PRESSED
est = g_curTime - g_prevTime
if highByte < 200 and est < 55 then highByte = highByte + est
if highByte > 200 then highByte = 200
if highByte = 200
if lowByte && SPI_FLG_UP_PRESSED then highWord = highWord + 1
if lowByte && SPI_FLG_DN_PRESSED then highWord = highWord - 1
endif
endif
`Assemble the lowByte, highByte, and highWord together (ignore lowWord since it's not altered)
lowWord = lowByte || (highByte << 8)
g_wndList(id).windowData = lowWord || (highWord << 16)
endfunction
`Draw the spinner
function __Draw_Spinner__(id as integer)
`Preliminary
rctUp as tRect
rctDn as tRect
lowWord as word
highWord as word
lowByte as byte
highByte as byte
`Set the up region
rctUp.x1 = g_wndList(id).x
rctUp.y1 = g_wndList(id).y
rctUp.x2 = rctUp.x1 + g_wndList(id).w
rctUp.y2 = rctUp.y1 + (g_wndList(id).h >> 1) `Divide by two through a right bitshift
`Set the down region
rctDn.x1 = rctUp.x1
rctDn.y1 = rctUp.y2
rctDn.x2 = rctUp.x2
rctDn.y2 = rctUp.y1 + g_wndList(id).h
`Determine the low and high bits
lowWord = g_wndList(id).windowData && 0xFFFF
```highWord = (g_wndList(id).windowData >> 16) && 0xFFFF
lowByte = lowWord && 0xFF
```highByte = (lowWord >> 8) && 0xFF
`Set the default color schemes
up_tlc = BTI_COL_TOP_LEFT
up_trc = BTI_COL_TOP_RIGHT
up_blc = BTI_COL_BTM_LEFT
up_brc = BTI_COL_BTM_RIGHT
dn_tlc = BTI_COL_TOP_LEFT
dn_trc = BTI_COL_TOP_RIGHT
dn_blc = BTI_COL_BTM_LEFT
dn_brc = BTI_COL_BTM_RIGHT
up_olc = BTI_OUTLINE_COLOR
dn_olc = BTI_OUTLINE_COLOR
`Is up highlighted?
if lowByte && SPI_FLG_UP_HIGHLIGHT
up_olc = BTH_OUTLINE_COLOR
up_tlc = BTH_COL_TOP_LEFT
up_trc = BTH_COL_TOP_RIGHT
up_blc = BTH_COL_BTM_LEFT
up_brc = BTH_COL_BTM_RIGHT
endif
`Is up pressed?
if lowByte && SPI_FLG_UP_PRESSED
up_olc = BTP_OUTLINE_COLOR
up_tlc = BTP_COL_TOP_LEFT
up_trc = BTP_COL_TOP_RIGHT
up_blc = BTP_COL_BTM_LEFT
up_brc = BTP_COL_BTM_RIGHT
endif
`Is down highlighted?
if lowByte && SPI_FLG_DN_HIGHLIGHT
dp_olc = BTH_OUTLINE_COLOR
dn_tlc = BTH_COL_TOP_LEFT
dn_trc = BTH_COL_TOP_RIGHT
dn_blc = BTH_COL_BTM_LEFT
dn_brc = BTH_COL_BTM_RIGHT
endif
`Is down pressed?
if lowByte && SPI_FLG_DN_PRESSED
dn_olc = BTP_OUTLINE_COLOR
dn_tlc = BTP_COL_TOP_LEFT
dn_trc = BTP_COL_TOP_RIGHT
dn_blc = BTP_COL_BTM_LEFT
dn_brc = BTP_COL_BTM_RIGHT
endif
`Set the outline color
olc = BTI_OUTLINE_COLOR
`Draw the box
Prepare Box rctUp.x1, rctUp.y1, rctUp.x2, rctUp.y2, up_tlc, up_trc, up_blc, up_brc
Draw DRAW_TYPE_BOX
Prepare Box rctDn.x1, rctDn.y1, rctDn.x2, rctDn.y2, dn_blc, dn_brc, dn_tlc, dn_trc
Draw DRAW_TYPE_BOX
`Draw the outline
Prepare Line rctUp.x1, rctUp.y1, rctUp.x2+1, rctUp.y1, olc, olc
Draw DRAW_TYPE_LINE
Prepare Line rctUp.x1, rctUp.y1, rctUp.x1, rctDn.y2+1, olc, olc
Draw DRAW_TYPE_LINE
Prepare Line rctUp.x2, rctUp.y1, rctUp.x2, rctDn.y2+1, olc, olc
Draw DRAW_TYPE_LINE
Prepare Line rctUp.x1, rctDn.y2, rctUp.x2+1, rctDn.y2, olc, olc
Draw DRAW_TYPE_LINE
Prepare Line rctUp.x1, rctUp.y2, rctUp.x2, rctUp.y2, olc, olc
Draw DRAW_TYPE_LINE
`Draw the arrows
DrawUpArrow(rctUp.x1 + 3, rctUp.y1 + 3, rctUp.x2 - rctUp.x1 - 6, rctUp.y2 - rctUp.y1 - 6, up_olc)
DrawDownArrow(rctDn.x1 + 3, rctDn.y1 + 3, rctDn.x2 - rctDn.x1 - 6, rctDn.y2 - rctDn.y1 - 6, dn_olc)
endfunction
REMSTART
USER INTERFACE INTERACTION FUNCTIONS
REMEND
`Get the class of a window
function GetWindowClass(id as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
v = g_wndList(id).class
endfunction v
`Get the flags of a window
function GetWindowFlags(id as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
v = g_wndList(id).flags
endfunction v
`Get the text of a window
function GetWindowText(id as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
v$ = g_wndList(id).text$
endfunction v$
`Get the X position of a window
function GetWindowPosX(id as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
v = g_wndList(id).x
endfunction v
`Get the Y position of a window
function GetWindowPosY(id as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
v = g_wndList(id).y
endfunction v
`Get the width of a window
function GetWindowWidth(id as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
v = g_wndList(id).w
endfunction v
`Get the height of a window
function GetWindowHeight(id as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
v = g_wndList(id).h
endfunction v
`Get the foreground color of a window
function GetWindowForegroundColor(id as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
v = g_wndList(id).fgCol
endfunction v
`Get the background color of a window
function GetWindowBackgroundColor(id as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
v = g_wndList(id).bgCol
endfunction v
`Get the number of left clicks on a window
function GetWindowLeftClickCount(id as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
v = g_wndList(id).lcCount
g_wndList(id).lcCount = 0
endfunction v
`Get the number of right clicks on a window
function GetWindowRightClickCount(id as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
v = g_wndList(id).rcCount
g_wndList(id).rcCount = 0
endfunction v
`Get the number of middle clicks on a window
function GetWindowMiddleClickCount(id as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
v = g_wndList(id).mcCount
g_wndList(id).mcCount = 0
endfunction v
`Get the user associated data on a window
function GetWindowUserData(id as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
v = g_wndList(id).userData
endfunction v
`Get the parent of a window
function GetWindowParent(id as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
v = g_wndList(id).parentWindow
endfunction v
`Position a window
function PositionWindow(id as integer, x as integer, y as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
oldx = g_wndList(id).x
oldy = g_wndList(id).y
g_wndList(id).x = x
g_wndList(id).y = y
child = g_wndList(id).firstChild
while child <> 0
g_wndList(child).x = (g_wndList(child).x - oldx) + g_wndList(id).x
g_wndList(child).y = (g_wndList(child).y - oldy) + g_wndList(id).y
child = g_wndList(child).nextWindow
endwhile
endfunction v
`Resize a window
function ResizeWindow(id as integer, w as integer, h as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
g_wndList(id).w = w
g_wndList(id).h = h
endfunction
`Set the text of a window
function SetWindowText(id as integer, txt$ as string)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
g_wndList(id).text$ = txt$
endfunction
`Set the color of a window (foreground and background)
function SetWindowColor(id as integer, fgCol as dword, bgCol as dword)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
g_wndList(id).fgCol = fgCol
g_wndList(id).bgCol = bgCol
endfunction
`Get the user data of a window
function SetWindowUserData(id as integer, userData as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
g_wndList(id).userData = userData
endfunction
`Set the parent of a window
function SetWindowParent(id as integer, parent as integer)
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
if parent <> 0
if WindowExist(parent) = 0 then Error("Parent Window " + str$(id) + " Does Not Exist")
endif
relX = g_wndList(id).x - g_wndList(g_wndList(id).parentWindow).x
relY = g_wndList(id).y - g_wndList(g_wndList(id).parentWindow).y
nextWindow = g_wndList(id).nextWindow
prevWindow = g_wndList(id).prevWindow
if prevWindow > 0 then g_wndList(prevWindow).nextWindow = nextWindow
if nextWindow > 0 then g_wndList(nextWindow).prevWindow = prevWindow
if g_wndList(parent).firstChild = id
g_wndList(parent).firstChild = nextWindow
endif
if g_wndList(parent).lastChild = id
g_wndList(parent).lastChild = prevWindow
endif
g_wndList(id).parentWindow = parent
g_wndList(id).prevWindow = g_wndList(parent).lastChild
g_wndList(id).nextWindow = 0
if g_wndList(parent).lastChild > 0
g_wndList(g_wndList(parent).lastChild).nextWindow = id
endif
g_wndList(parent).lastChild = id
if g_wndList(parent).firstChild = 0 then g_wndList(parent).firstChild = id
g_wndList(id).x = relX + g_wndList(parent).x
g_wndList(id).y = relY + g_wndList(parent).y
WindowToFront(id)
endfunction
`Get a spinner's value
function GetSpinnerValue(id as integer)
highWord as word
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
if g_wndList(id).class <> CLASS_SPINNER then Error("Window " + str$(id) + " Is NOT A Spinner")
`Get the value
highWord = (g_wndList(id).windowData >> 16) && 0xFFFF
endfunction highWord
`Set a spinner's value
function SetSpinnerValue(id as integer, value as word)
lowWord as word
if WindowExist(id) = 0 then Error("Window " + str$(id) + " Does Not Exist")
if g_wndList(id).class <> CLASS_SPINNER then Error("Window " + str$(id) + " Is NOT A Spinner")
`Determine the low and high bits
lowWord = g_wndList(id).windowData && 0xFFFF
`Assemble the words
g_wndList(id).windowData = lowWord || (value << 16)
endfunction
MAJOR NOTE!!! - R E A D M E ! ! !
I uninstalled DBPro to free up space... (I still have the disc though). Looks like a tutorial won't be out until I either a) get a new computer, b) get a larger hard drive, or c) reinstall DBPro (If I have enough space for it). Oops?
Cheers,
-naota
I'm not a dictator to those that do stuff for me by will. Only those who don't.