PHP WinBinder 4: Icons

 

UniServer 5-Nano
PHP WinBinder 4 - Tray Menu.

WinBinder Part 4 - Icons

Introduction

Icons

Unitray displays small icons to the left of a menu item. These icons are supposed to be intuitive as to their meaning and function! I have a host of remote controllers with similar icons; all different for the same function. Hence I hate this clutter and would not include them. However our menu is intended to be general purpose if not provided would be considered limited .

I do like the concept of a single image containing multi-images; well it’s in keeping with my concept of removing clutter.

In operation each sub-image is assigned a number this in turn is assigned to a menu item and displayed when the script is run. Main image containing each sub-image is a bit map hence there is no real indexing as such. However it is a good idea to consider the first image to have an index of zero.

This part of the tutorial looks at extracting a single image from a multi-image source. WinBinder has a small set of image functions however these are very powerful, as the following examples will demonstrate.

 

 

General

Most applications require an image to be extracted from a file on disk and assigned to a WinBinder object, once assigned that image resource is deleted. Our tray menu requires each image to be redrawn within the draw_on_window function. If the above was implemented in this function every mouse move will thrash the hard disk drive to death.

Once pointed out! It’s obvious that’s not the way to do it.

  • For each image retain a local copy (that resource)
  • On closing the application delete all image resources created.

Note: If you create an image or font resource delete them at the first opportunity or ensure to delete them on closing an application.

Hey! Less of this negative stuff let’s see how to extract an image resource.

Top

What is an image resource?

What is an image resource? A reasonable analogy is to consider it a bucket of memory with an identifying label slapped on it. When a bucket is created an amount of memory is reserved for it. The system places a bucket somewhere in its memory space and slaps a location label on it. System then provides us with this label information for safekeeping.

Top

Creating an image resource

To create an image resource WinBinder has the following function:

int wb_create_image (int width, int height)
  • Size of a bucket is defined by parameters width and height
  • System returns the label location information as an integer (int)
  • Its our responsibility to save this label information hence save it to a variale.

For example the following creates an image resource for a small icon

  • $img_1 = wb_create_image(16, 16);

Memory Leak

No it’s not a hole in our bucket!

The system has created reserved memory space and provided its location. It now has noting to do with that space other than to reserve it. Hence closing your application laves that allocated memory intact. The system assumes it is still required and maintains it hence no other application can use it this is referred to as memory leak.

To prevent memory leak prior to closing your application ensure all resources are destroyed. This frees allocated memory for other applications to use.

Destroy Image resources

Each image has an associated label (handle) that uniquely targets an image resource use the following WinBinder function to destroy a resource:

  • bool wb_destroy_image (int image)

For example

  • wb_destroy_image($img_1); -- Destroys the small icon image resource mentioned above.

Top

Empty buckets

You can create empty buckets (image resources) for later use. These can be filled with images from disk or drawn on using any of the image draw functions.

WinBinder is versatile allowing you to extract and draw part on an image into another image resource this is covered next.

Top

Image Strip - Multi-images

Example image strip (will be different in download) we are going to use consists of 15 small images each with dimensions 16x16 pixels as shown below:

File: menu_icons.bmp

 

There is nothing special about this image it is a 240x16 pixel bit map image.

I mentioned that there is an imaginary index (Id) assigned to each image starting at 0.

This allows us to use a simple formula to find the first pixel of an image.

  • Formula x = Id x 16
  • First image starts at 0
  • Second image starts at (1 x 16) = 16
  • Fifth image has index 4 hence (4 x 16) = 64 is its starting pixel

An image is referenced from it’s top left hand corner.

The x and y co-ordinates are 0,0

Top

Example 1

For this example I copied file rollover_5.phpw and renamed it icons_1.phpw likewise for its corresponding batch file.

Top

Create two image resources

Create two images resources, place them just under "Add image frame" as show below:

//== Add image frame
$frame = wb_create_control($mainwin, Frame, "", 0, 0, $win_width, $win_height2, 101, WBC_IMAGE);

//=== Create image resource (small icons)
$img_1 = wb_create_image(16, 16);  // Size of small icon
$img_2 = wb_create_image(16, 16);  // Size of small icon

These are empty and require filling with images from the image strip.

Top

Create image-strip resources

The following WinBinder function loads a image file "filename" from disk and returns a handle to it.

int wb_load_image (string filename [, int index])

Hence to load our image-strip use

  • $img = wb_load_image('menu_icons.bmp');

Top

Draw images to icon resources

This WinBinder funtion allows you to effectively copy a image or part of a image to another image by drawing.

bool wb_draw_image(target, source, t-xpos, t-ypos , t-width , t-height, transparentcolor, s-xpos,s-ypos)
  • target - target may be a WinBinder object, a window handle, a drawing surface or a bitmap
  • source - bitmap source a window handle
  • t-xpos - target x coordinate of upper-left corner, in pixels
  • t-ypos - target y coordinate of upper-left corner, in pixels
  • t-width - target width in pixels
  • t-height - target width in pixels
  • transparentcolor - set to NOCOLOR
  • s-xpos - source x coordinate start position in pixels
  • s-ypos - source y coordinate start position in pixels

For example:

 wb_draw_image($img_1, $img, 0, 0, 16, 16, NOCOLOR, 16, 0);  // Draw single images
 wb_draw_image($img_2, $img, 0, 0, 16, 16, NOCOLOR, 64, 0);  // Draw single images

Note: We are copying a larger image into a smaller one anything that does not fit is discarded.

Add the above two line to the previous code to give:

//=== Create image resource (small icons)
$img_1 = wb_create_image(16, 16);  // Size of small icon
$img_2 = wb_create_image(16, 16);  // Size of small icon

//=== Extract image from strip
$img = wb_load_image('menu_icons.bmp');                      // Load image strip
 wb_draw_image($img_1, $img, 0, 0, 16, 16, NOCOLOR,  16, 0); // Draw single images
 wb_draw_image($img_2, $img, 0, 0, 16, 16, NOCOLOR,  64, 0); // Draw single images
wb_destroy_image($img); 

 


Important:

Note the last line destroys the image resource $img. We have extracted required smaller images hence the resource is no longer required. At the first opportunity destroy any resources that are no longer required.

Top

Use images resource created

We want to draw the icons more importantly we want them to be redrawn when requied by the system hence we place them in the draw_on_window function.

Add the two appropriate variables in the global section and

 global  $frame;
 global  $img_1;
 global  $img_2;

Now we want to draw the images add the following two lines just above the image frame as show

 wb_draw_image($bmp, $img_1, 20, 100); // Draw left icon 1
 wb_draw_image($bmp, $img_2, 120, 100); // Draw left icon 2

 wb_set_image($frame, $bmp); // Swith image to label

Top

Remember to destroy resources

    case IDCLOSE:                          // Exit button clicked
      wb_destroy_window($window);          // Destry window 
      wb_destroy_font();                   // Destroy all fonts
      wb_destroy_image($img_1);            // Kill images created
      wb_destroy_image($img_2);            // Kill images created
    break;

 

When the application closes we want to destroy the images resources created add the last two lines to IDCLOSE section as shown

Top

Run Example 1

'Run icons_1.bat' Result shown on right.

I agree its not cosmetically pleasing that is intentional. It highlights a few issues the first you would think is colours are not transparent. Well the icons will be placed on a white background hence not an issue.

The real issue is one of positioning or lack off. Our final menu wants to be dynamically resized and components positioned accordingly.

This is covered on the next page.

 

Top

Complete Icon test script

icons_1.phpw

<?php
/*
###############################################################################
# Name: icons_1.phpw
# Developed By: The Uniform Server Development Team
# Modified Last By: Mike Gleaves (Ric)
# Web: http://www.uniformserver.com
# V1.0 2-5-2010
# Comment: WinBinder tutorial (Part 4)
###############################################################################
*/

include "winbinder.php";

//=== Constants

define("APPNAME", "WinBinder Borderless Window"); // Title displayed in taskbar

$win_width   = 300;
$win_height  = 200;
$win_height2 = 140; // This would be full window height
$win_x       = 200;
$win_y       = 200;

//== Font to use for drawing
$font_text_black = wb_create_font("Tahoma", 8, BLACK, 0);
$font_text_white = wb_create_font("Tahoma", 8, WHITE, 0);

//== Background colour
$back_black = BLACK;
$back_white = WHITE;


// Create main window
$mainwin = wb_create_window(NULL, NakedWindow, APPNAME,
  $win_x, $win_y, $win_width, $win_height, WBC_NOTIFY | WBC_TOP  | WBC_TASKBAR ,
  WBC_DBLCLICK | WBC_MOUSEDOWN | WBC_MOUSEUP | WBC_MOUSEMOVE | WBC_REDRAW);

// Add controls
 wb_create_control($mainwin, PushButton, "Exit",  	  10,160, 90, 25, IDCLOSE);
 wb_create_control($mainwin, PushButton, "Minimize",  	 200,160, 90, 25, WBC_MINIMIZED);

//== Add image frame
$frame = wb_create_control($mainwin, Frame, "", 0, 0, $win_width, $win_height2, 101, WBC_IMAGE);

//=== Create image resource (small icons)
$img_1 = wb_create_image(16, 16);  // Size of small icon
$img_2 = wb_create_image(16, 16);  // Size of small icon

//=== Extract image from strip
$img = wb_load_image('menu_icons.bmp');                       // Load image strip
 wb_draw_image($img_1, $img, 0, 0, 16, 16, NOCOLOR,  16-1, 0);  // Draw single images
 wb_draw_image($img_2, $img, 0, 0, 16, 16, NOCOLOR,  64-1, 0);  // Draw single images
wb_destroy_image($img);                                       // Kill image noonger required

// Main draw
 draw_on_window($mainwin); // Draw additional features 

// Assign handler 
wb_set_handler($mainwin, "process_main");

// Start main loop
wb_main_loop();

//=== Handler function ========================================================

/* Process main window commands */

function process_main($window, $id, $ctrl, $lparam1=0, $lparam2=0){
  switch($id) {

    case IDDEFAULT:

      if($lparam1 & WBC_REDRAW) {  // A redraw required.(e.g. minimize to max)   
        draw_on_window($window);   // Yes: Call redraw function
      }

    $x = $lparam2 & 0xFFFF;              // Get mouse co-ords
    $y = ($lparam2 & 0xFFFF0000) >> 16;  // Get mouse co-ords
    draw_on_window($window,$x,$y);       // Run mouse over

    break;

    case WBC_MINIMIZED:                    // Minimise button clicked
      wb_set_size($window, WBC_MINIMIZED); // Minimize window
    break;

    case IDCLOSE:                          // Exit button clicked
      wb_destroy_window($window);          // Destry window 
      wb_destroy_font();                   // Destroy all fonts
      wb_destroy_image($img_1);            // Kill images created
      wb_destroy_image($img_2);            // Kill images created
    break;
  }
}
//=== END Handler function ====================================================

//=== Draw on window ==========================================================

function draw_on_window($win,$x=0,$y=0){

 global  $win_width;
 global  $win_height2;
 global  $font_text_black;
 global  $font_text_white;
 global  $back_black;
 global  $back_white;
 global  $frame;
 global  $img_1;
 global  $img_2;

print "\nMouse $x $y\n"; // For test only

//== Create an image
$bmp = wb_create_image($win_width, $win_height2);

 // Draw rectangles
 wb_draw_rect($bmp, 0, 0, $win_width, $win_height2, GREEN);          // Green canvas
 wb_draw_rect($bmp, 0, 0, $win_width, $win_height2, BLACK,FALSE,5 ); // Border around window

// Create rollover for text 1
 if( ($x >= 5) && ($x <= 280)  && ($y >= 15) && ($y <= 40) ){
  wb_draw_rect($bmp, 10, 15, 280, 30, $back_black);          // Text Background
  wb_draw_text($bmp, "Basic building block  基本构建块 and Unicode.", 25, 20, 0, 0, $font_text_white);
 }
 else{
  wb_draw_rect($bmp, 10, 15, 280, 30, $back_white);          // Text Background
  wb_draw_text($bmp, "Basic building block  基本构建块 and Unicode.", 25, 20, 0, 0, $font_text_black);
 }

// Create rollover for text2
 if( ($x >= 5) && ($x <= 280)  && ($y >= 50) && ($y <= 80) ){
  wb_draw_rect($bmp, 10, 50, 280, 30, $back_black);          // Text Background
  wb_draw_text($bmp, "Basic building block  基本构建块 and Unicode.", 25, 55, 0, 0, $font_text_white);
 }
 else{
  wb_draw_rect($bmp, 10, 50, 280, 30, $back_white);          // Text Background
  wb_draw_text($bmp, "Basic building block  基本构建块 and Unicode.", 25, 55, 0, 0, $font_text_black);
 }

 wb_draw_image($bmp, $img_1, 20, 100); // Draw left icon 1
 wb_draw_image($bmp, $img_2, 120, 100); // Draw left icon 2

 wb_set_image($frame, $bmp); // Swith image to label
 wb_destroy_image($bmp);     // Delete image 

}
//=== END Draw on window ======================================================
?>

Top

Example 2

If you are using only a few images from an image strip depending on your application the above method is suitable. However for our tray menu a user can select any image from a image strip to use.

If the above technique is used it requires a separate image for each image on the strip. This clearly is not the right way to proceed if a new image is added we need to chage code accordingly.

Take another look at this function:

bool wb_draw_image(target, source, t-xpos, t-ypos , t-width , t-height, transparentcolor, s-xpos,s-ypos)

It allows use to draw on any target image resource. Since we are using $bmp why not directly draw on that and cut out the intermediary image resources.

This example does just that, to target an image all that is required is its index number.

Top

Modifications

Modification to example 1

Replae the following:

//=== Create image resource (small icons)
$img_1 = wb_create_image(16, 16);  // Size of small icon
$img_2 = wb_create_image(16, 16);  // Size of small icon

//=== Extract image from strip
$img = wb_load_image('menu_icons.bmp');                       // Load image strip
 wb_draw_image($img_1, $img, 0, 0, 16, 16, NOCOLOR,  16, 0);  // Draw single images
 wb_draw_image($img_2, $img, 0, 0, 16, 16, NOCOLOR,  64, 0);  // Draw single images
wb_destroy_image($img); 

With

//=== Create image resource
 $img = wb_load_image('menu_icons.bmp');                       // Load image strip

Remember we need to destroy this image resource on exit hence replace this:

 wb_destroy_image($img_1);            // Kill images created
 wb_destroy_image($img_2);            // Kill images created

with:

 wb_destroy_image($img);              // Kill image no longer required

Our draw_on_window function requires a few tweaks

Add this line to the globals section: global $img;

Replace

 wb_draw_image($bmp, $img_1, 20, 100); // Draw left icon 1
 wb_draw_image($bmp, $img_2, 120, 100); // Draw left icon 2

With

 $id=3;
 wb_draw_image($bmp, $img,  20, 100, 16, 16, NOCOLOR,  $id*16, 0);  // Draw single image onto main drawing area
 $id=4;
 wb_draw_image($bmp, $img, 120, 100, 16, 16, NOCOLOR,  $id*16, 0);  // Draw single image onto main drawing area

I have separated out the index $id to emphasize it will not be hard coded but picked up from a configuration file.

Top

Run example

Run example 2 by double clicking on icons_2.bat

Change index values and see what image is displayed, try an index of 40!

Top

Complete Icon test 2 script

icons_2.phpw

<?php
/*
###############################################################################
# Name: icons_2.phpw
# Developed By: The Uniform Server Development Team
# Modified Last By: Mike Gleaves (Ric)
# Web: http://www.uniformserver.com
# V1.0 4-5-2010
# Comment: WinBinder tutorial (Part 4)
###############################################################################
*/

include "winbinder.php";

//=== Constants

define("APPNAME", "WinBinder Borderless Window"); // Title displayed in taskbar

$win_width   = 300;
$win_height  = 200;
$win_height2 = 140; // This would be full window height
$win_x       = 200;
$win_y       = 200;

//== Font to use for drawing
$font_text_black = wb_create_font("Tahoma", 8, BLACK, 0);
$font_text_white = wb_create_font("Tahoma", 8, WHITE, 0);

//== Background colour
$back_black = BLACK;
$back_white = WHITE;


// Create main window
$mainwin = wb_create_window(NULL, NakedWindow, APPNAME,
  $win_x, $win_y, $win_width, $win_height, WBC_NOTIFY | WBC_TOP  | WBC_TASKBAR ,
  WBC_DBLCLICK | WBC_MOUSEDOWN | WBC_MOUSEUP | WBC_MOUSEMOVE | WBC_REDRAW);

// Add controls
 wb_create_control($mainwin, PushButton, "Exit",  	  10,160, 90, 25, IDCLOSE);
 wb_create_control($mainwin, PushButton, "Minimize",  	 200,160, 90, 25, WBC_MINIMIZED);

//== Add image frame
$frame = wb_create_control($mainwin, Frame, "", 0, 0, $win_width, $win_height2, 101, WBC_IMAGE);


//=== Create image resource
 $img = wb_load_image('menu_icons.bmp');                       // Load image strip

// Main draw
 draw_on_window($mainwin); // Draw additional features 

// Assign handler 
wb_set_handler($mainwin, "process_main");

// Start main loop
wb_main_loop();

//=== Handler function ========================================================

/* Process main window commands */

function process_main($window, $id, $ctrl, $lparam1=0, $lparam2=0){
  switch($id) {

    case IDDEFAULT:

      if($lparam1 & WBC_REDRAW) {  // A redraw required.(e.g. minimize to max)   
        draw_on_window($window);   // Yes: Call redraw function
      }

    $x = $lparam2 & 0xFFFF;              // Get mouse co-ords
    $y = ($lparam2 & 0xFFFF0000) >> 16;  // Get mouse co-ords
    draw_on_window($window,$x,$y);       // Run mouse over

    break;

    case WBC_MINIMIZED:                    // Minimise button clicked
      wb_set_size($window, WBC_MINIMIZED); // Minimize window
    break;

    case IDCLOSE:                          // Exit button clicked
      wb_destroy_window($window);          // Destry window 
      wb_destroy_font();                   // Destroy all fonts
      wb_destroy_image($img);              // Kill image no longer required
    break;
  }
}
//=== END Handler function ====================================================

//=== Draw on window ==========================================================

function draw_on_window($win,$x=0,$y=0){

 global  $win_width;
 global  $win_height2;
 global  $font_text_black;
 global  $font_text_white;
 global  $back_black;
 global  $back_white;
 global  $frame;
 global  $img;

print "\nMouse $x $y\n"; // For test only

//== Create an image
$bmp = wb_create_image($win_width, $win_height2);

 // Draw rectangles
 wb_draw_rect($bmp, 0, 0, $win_width, $win_height2, GREEN);          // Green canvas
 wb_draw_rect($bmp, 0, 0, $win_width, $win_height2, BLACK,FALSE,5 ); // Border around window

// Create rollover for text 1
 if( ($x >= 5) && ($x <= 280)  && ($y >= 15) && ($y <= 40) ){
  wb_draw_rect($bmp, 10, 15, 280, 30, $back_black);          // Text Background
  wb_draw_text($bmp, "Basic building block  基本构建块 and Unicode.", 25, 20, 0, 0, $font_text_white);
 }
 else{
  wb_draw_rect($bmp, 10, 15, 280, 30, $back_white);          // Text Background
  wb_draw_text($bmp, "Basic building block  基本构建块 and Unicode.", 25, 20, 0, 0, $font_text_black);
 }

// Create rollover for text2
 if( ($x >= 5) && ($x <= 280)  && ($y >= 50) && ($y <= 80) ){
  wb_draw_rect($bmp, 10, 50, 280, 30, $back_black);          // Text Background
  wb_draw_text($bmp, "Basic building block  基本构建块 and Unicode.", 25, 55, 0, 0, $font_text_white);
 }
 else{
  wb_draw_rect($bmp, 10, 50, 280, 30, $back_white);          // Text Background
  wb_draw_text($bmp, "Basic building block  基本构建块 and Unicode.", 25, 55, 0, 0, $font_text_black);
 }

 //Drawn icons. Draw inages index 3 and 4 
 $id=3;
 wb_draw_image($bmp, $img,  20, 100, 16, 16, NOCOLOR,  $id*16, 0);  // Draw single image onto main drawing area
 $id=4;
 wb_draw_image($bmp, $img, 120, 100, 16, 16, NOCOLOR,  $id*16, 0);  // Draw single image onto main drawing area


 wb_set_image($frame, $bmp); // Swith image to label
 wb_destroy_image($bmp);     // Delete image 

}
//=== END Draw on window ======================================================
?>

Top

Summary

I have shown creating and destroying image resources is easy.

Image extraction uses function wb_draw_image() with all its parameters, this is about as complex as it gets. Depending on application most draw_image() parameters are optional.

To prevent memory leak remember to destroy any resources you create.

If we are going to implement an icon to the left of each menu item it requires an additional setting in the configuration file and an entry in the master array.

For our tray menu we have most of the code snippets in place next page covers dynamic resizing.


Top