PHP WinBinder 4: Icons
PHP WinBinder 4 : Introduction | Rollover | Icons | Size and position | Configuration file | Command Processing | Coding | Final Tray Menu
|
|
UniServer 5-Nano PHP WinBinder 4 - Tray Menu. |
WinBinder Part 4 - Icons
Introduction
IconsUnitray 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.
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.
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.
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.
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
Example 1
For this example I copied file rollover_5.phpw and renamed it icons_1.phpw likewise for its corresponding batch file.
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.
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');
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); |
|
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. |
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
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 |
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. |
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 ====================================================== ?> |
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.
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.
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!
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 ====================================================== ?>
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.