Previous page Select page Next page

Building the "peg" handler

OK, we now have our "raw materials" - let's do something with them. Consider the steps we would need to follow to get the behaviour we want:

  1. Get a handle on the button (remember, we only have its "ID"), since we are going to want to change its position.
  2. Get the new size of the window's client area (we know how to do this already).
  3. Get the width of the button and subtract it from the width of the client area (together with any border we want to add).
  4. Set the "left" position of the button to the above value.
  5. Get the height of the button and subtract it from the height of the client area (together with any border we want to add).
  6. Set the "top" position of the button to the above value.
  7. Return back to the main event loop

In concept, fairly straightforward but we don't yet know how to get the width and height of a button nor do we know how to subtract. What we do know is that if we are going to use the Win32 getClientRect function, we will have to declare a label to hold a RECT structure - call it pBox ("pointer to Box"). Also, we need something to hold our handle for the button - what type should it be? Bring up the Win32 help again and go to the entry for getClientRect. You can see from the definition of the function that window handles are of type HWND. You'll discover later in subsequent chapters that buttons and labels, etc, are all types of the same thing - windows. They're just specialised forms of windows and we use exactly the same command to create each of them. We just use different parameters in the function call. You would know this if you were writing your assembler using the "Win32 Classic" option in EasyCode because you would have to write the code to create them. Using the "Visual Project" approach, EasyCode does it all for you in the background and so you don't see it. Anyway, let's make a label called hButton of that type to hold the handle. Including our definition of the event and the handler, the .Data section should look like this:

	MESSAGES	DD WM_CREATE, OnCreate
			DD WM_CLOSE, OnClose
			DD WM_SIZE, OnResize
	hButton		DD ?
	pBox		RECT

Well, there's nothing really new there apart from the HWND, so let's move on to the handler itself. As you would expect from our example in the last chapter, we need to type in the label for the handler, a request to use the event loop variables and a corresponding "end" to their use, giving us:

	OnResize:
		UseData winMainProcedure
	EndU
	; End OnResize

Now to add some real code to the handler! Looking at the breakdown of the steps in the list at the top of this page, we see that the first thing we need to do is to get a handle for the button. Why do we need to do this? It's because the functions we need to use in order to move the button need to know its handle and not its ID. That means we have to go get it. The command to acquire the handle is an EasyCode one - getWindowItem. Look it up in the EasyCode manual - it needs to be given the handle of the window where the button is located and the ID. If all goes well, the handle comes back to us in the EAX register (or NULL if it fails). Since we'll need to use that register for other function calls later in the code, we will have to save its contents immediately into our variable hButton. Here's the code. Note the use of the square brackets to enable goAsm to get or set the contents of the box being referred to and not the reference itself.

	OnResize:
		UseData winMainProcedure

		; 1. Get a handle on the button
		Invoke GetWindowItem, [hWnd], IDC_WINMAIN_BTNEXIT
		Mov [hButton], Eax
	EndU
	; End OnResize

Now we need to geth the dimensions of the client area - just like we did in the last chapter. Of course, we could have done steps 1 and 2 in the reverse order. It doesn't really matter that I got the handle to the button and then got the size of the client area. I could have done it the other way around. So no surpises that we would write:

		; 2. Get the new size of the window's client area
		Invoke GetClientRect, [hWnd], Addr pBox

This is where it gets a little trickier. In step 3, we need to get the width of the button and and subtract it from the width of the client area. We also need to subtract any border that we might want to use so that, instead of the button being hard up against the edge of the client area, there would be a few pixels separating the two. Win32 has functionality to enable us to discover the width of an item but EasyCode (as you would expect) has an easier way of doing it - the GetWidth method. Look it up in the EasyCode help manual. You'll see that all it needs is handle to the control whose width we want to find. That's why we needed to get the handle of the button. The result is placed in the EAX register (or NULL for a failure) and represents the width of the control in either twips or pixels, depending on the ScaleMode setting for the window. That's why we set this value to "pixels" in the winMain properites.

Fine, we have the number of pixels sitting in the EAX register. What now? Let's say that we want our button to be separated by a border of 4 from the vertical edge of the client area. What we should do, then, is to add 4 to the width of the button. Since the width is in EAX, all we have to do is to add 4 to that value - ADD Eax, 4.

That makes us ready to subtract the button width from the client width, so we now need to get the latter into a register so that we can do the arithmetic. Let's choose EBX to hold the client width. If you remember from last chapter, the width in a RECT is held in the sub-compartment called "right" and we use the dot-symbology to tell the assembler which rectangle structure this "right" belongs to. In fact, you can imagine the dot as being a bit like the "'s" in English ("pBox's right"). So, we would say Mov Ebx, [pBox.right]. Again, remember the square brackets!

The SUB mnemonic

At last comes the subtraction. It works just like the addition equivalent - we specify the register being affected by the subtraction first and then the value we are subtracting from it. In our case, the first value has to be whatever is in Ebx (it's holding the width of the client area) and the second is Eax (the width of the button plus its border). All in all, then, the code to do step 3 looks like this:

		; 3. Get the width of the button and subtract it from the width of the
		;    client area, together with any border
		Invoke GetWidth, [hButton]	; Get the button's current width
		Add Eax, 4			; A border of 4
		Mov Ebx, [pBox.right]		; Retrieve the parent's width
		Sub Ebx, Eax			; Subtract the button's (plus border) width
						  from it.

We now have the new "left" postion for our button sitting in Ebx! So, let's get on a set the button to this new position. Once again, EasyCode has a simple function to enable us to set the "left" position of an object - SetLeft. Check it out in the manual (this should be automatic for you every time I introduce a new command). As you would imagine, it needs to knwo which button and which position:

		; 4. Set the "left" position of the button to the above value
		Invoke SetLeft, [hButton], Ebx	; Set the button's left position to the new
						  value

As you can imagine, the rest of the handler is a repeat of the above, except that it relates now to the "top" position of the button. So, if you have understood everything I have covered so far in this and the last chapter, the rest of the code should be easy. Here's the complete handler:

OnResize:
    UseData winMainProcedure

	; 1. Get a handle on the button
	Invoke GetWindowItem, [hWnd], IDC_WINMAIN_BTNEXIT
	Mov [hButton], Eax

	; 2. Get the new size of the window's client area
	Invoke GetClientRect, [hWnd], Addr pBox

	; 3. Get the width of the button and subtract it from the width of the
	;    client area, together with any border
	Invoke GetWidth, [hButton]	; Get the button's current width
	Add Eax, 4			; A border of 4
	Mov Ebx, [pBox.right]		; Retrieve the parent's width
	Sub Ebx, Eax			; Subtract the button's (plus border) width from it.

	; 4. Set the "left" position of the button to the above value
	Invoke SetLeft, [hButton], Ebx	; Set the button's left position to the new value

	; 5. Get the height of the button and subtract it from the height of the
	;    client area, together with any border
	Invoke GetHeight, [hButton]	; Get the button's current height
	Add Eax, 4			; A border of 4
	Mov Ebx, [pBox.bottom]		; Retrieve the parent's height
	Sub Ebx, Eax			; Subtract the button's (plus border) height from it.

	; 6. Set the "top" position of the button to the above value
	Invoke SetTop, [hButton], Ebx	; Set the button's top position to the new value

	; 7. Return back to the main event loop
	Return (TRUE)
; End OnResize
EndU

Previous page Select page Next page