PHP WinBinder 4: Size and position

From The Uniform Server Wiki
Jump to navigation Jump to search


UniServer 5-Nano
PHP WinBinder 4 - Tray Menu.

WinBinder Part 4 - String length and dynamic resizing


Before we can start wring real code for our tray menu we requires pre-knowledge of its finished sized.

The tray menu is to be dynamically generated self-sizing and self-positioning. This part of the tutorial looks at potential issues and how to resolve them.

WinBinder has a number of powerful functions one in particular addresses a font size issue especially when using UniCode (UTF-8).

Again a test script is included to provide a working example.

Basic structure

Both main-menu and sub-menus follow an identical structure as shown on the right.

Pixels sizes shown are not written in stone and should not be hard coded into our script.

Either define pixel sizes as constants or preferably use variables (menu is dynamic and changes values on the fly; which values to be decided later)

Important: Are all dimensions resolvable?


If we assume menu item text height will not exceed an icon’s height

  • Each menu item occupies 16+4 pixels
  • Unless it is a spacer which is 13 pixels
  • Top and bottom border are 5 pixels each


  • Left and right border are defined 5+2
  • Left and right icons are 16 pixels
  • Spacing between left icon and text is 4 pixels
  • Text width is an unknown?

Text width unknown or is it?

We can seach the configuration file for widest text.

We know the font size we are using however it is defined in points!

WinBinder has a neat function that will convert it into pixels.

Hence we can calculate the maximum width of our menu and sub-menus.

String length 1.gif


Position tray menu

Unfortunately the tray menu does not automatically pop-up in the correct position. After all it is a standard bare window and requires positioning dynamically.

Work area: To position our menu we need something to position it in.

Windows defines a work area this is the whole screen minus all borders banners and tray menu strip.

WinBinder has a function wb_get_system_info() that provides the dimensions of this area.

$dim = explode(" ", wb_get_system_info("workarea")); // Working screen area
$screen_width  =  $dim [2];                          // Extract width
$screen_height =  $dim [3];                          // Extract height

Menu height and position:

Menu height is definable from number of menu items and spacers configured in the configuration file.

Subtract this height from the work area height places the menu just above the tray menu bar

Menu width and position:

Menu and sub-menu widths are obtained from maximum text widths of menu items and including all spacing.

To position our tray menu we need to find a sub-menu with the greatest width. We add this to the width of the main menu and add an offset Xn Findlay subtract this from the working area width.

String length 2.gif


Property and dimension tracking

From the above you will notice each menu item and spacer require a large number of dimensions to be tracked. Added to this is tracking of properties for each menu item configured i.e. command to execute.

If all that weren’t enough we have the added complication of which menu are these items assign to. Is it a main menu item or a particular sub-menu item.


Master array

Now is a good time to introduce the master array it will hold information for each item. This array is built once with information from the configuration file, any additional data being added at the same time.

The array is constructed sequentially some information is transient. A consequence of this is a small amount of duplicated information is stored.

Yep! That all sounds complicated?

All it means is any line in the master array will contain enough data to position that item (icon, text and rollover) and what command to perform when clicked.


Define master array parameters

So far its all a bit nebulous, its time to define a few items such as the master array name, let name it $main. What elements do we wish to store in order to position a menu item?

Array parameters

First part of our array is reserved; this will contain data from the configuration file. We are currently interested in only data to position a menu item and its elements.

We want to draw a menu item and spacer using a for-loop. The following elements are required in our master array.

 $main[$i][7]  // Configuration menu icon 0 = no icon

 $main[$i][8]  // y-top where an item or rollover starts
 $main[$i][9]  // y-rollover-end where a rollover ends
$main[$i][10]  // y-bottom where an item ends and the next one startsy

$main[$i][11]  // x-icon1 where left icon starts
$main[$i][12]  // x-rollover-start where a rollover starts
$main[$i][13]  // x-text where text starts
$main[$i][14]  // x-rollover-end where rollover ends
$main[$i][15]  // x-icon2 where right icon starts

From the above data can we draw each item.

This code snippet is taken from the redraw function.

// Create rollover for text 1
 if( ($x >= $main[$i][12]) && ($x <= $main[$i][14])  && ($y >= $main[$i][8]) && ($y <= $main[$i][9]) ){

  wb_draw_rect($bmp, $main[$i][12], $main[$i][8], $main[$i][14] - $main[$i][12] ,
  $main[$i][9] - $main[$i][8], $back_black);          // Text Background

  wb_draw_text($bmp, "Basic building block  基本构建块 and Unicode.", $main[$i][13],
  $main[$i][8], 0, 0, $font_text_white);

  wb_draw_image($bmp, $img,  $main[$i][11], $main[$i][8], 16, 16, NOCOLOR,
  $main[$i][7]*16, 0);  // Draw single image onto main drawing area

  wb_draw_image($bmp, $img,  $main[$i][15], $main[$i][8], 16, 16, NOCOLOR, 
               0, 0);  // Draw single image onto main drawing area

Note code that draws a text background requires width and height to be calculated. This places additional strain on our redraw function having width and height pre-calculated in the master array will reduce calculation time. It’s a balance between speed and redundancy.


Text string witdh and height

In order to populate our master array we need to find a menu item with the widest width in pixels.

Lets assume the following string is the widest:

$text_str  = "Basic building block  基本构建块 and Unicode";  // Assume maximum width string

Function wb_get_size() returns an array containing string width and height in pixels

$max_width_array = wb_get_size($text_str); // Get string dimensions in pix
$max_width = $max_width_array[0] +3;

Note: The fiddle factor 3 is required width is always short by two to three pixels.


Run Example 1

At this stage its worth looking at example 1

Run the example by double clicking on:


If you wish view the code in file size_and_position_1.phpw

As a test piece it is lacking a spacer and auto window width.

Background colour and border are not representative.


Size and position 1.gif


Run Example 2

For comparison example 2 has been modified

Run the example by double clicking on:


If you wish view the code in file size_and_position_2.phpw

This final test piece implements a spacer and auto window width.

Background colour and border are now representative.


Size and position 2.gif


Example 2 - Notes

I mentioned the transient nature of certain data. A user can configure menu items and spacers in any mix because of this you cannot use a simple formula to place elements vertically.

Solution is to store both start and end y-positions for each menu element. Hence when constructing a new array line it relies on data from the previous one constructed. The following lines show this:

 $main[0][8]  = $top_offset;                   // y-top where an item or rollover starts
 $main[0][10] = $main[0][9] +  $item_space;    // y-bottom where an item ends and the next one startsy

 $main[1][8]  = $main[0][10];                   // y-top where an item or rollover starts
 $main[1][10] = $main[1][8] +  $spacer_height;  // y-bottom where an item ends and the next one startsy

 $main[2][8]  = $main[1][10];                  // y-top where an item or rollover starts
 $main[2][10] = $main[2][9] +  $item_space;    // y-bottom where an item ends and the next one startsy


Although there is redundancy associated with this method it has one redeeming feature.

After building master array, main menu and sub-menu heights are easily determined by adding bottom offset to $main[X][10].

Main menu and sub-menus will each have an associated $main[X][10] entry (last menu item)



The above shows how to dynamically create a very simple rollover menu effect. Menu width and height are easily determined allowing the menu to be positioned.

It’s a proof of concept next page covers the configuration file.