PHP WinBinder 4: Coding

From The Uniform Server Wiki
Jump to navigation Jump to search

 

UniServer 5-Nano
PHP WinBinder 4 - Tray Menu.

WinBinder Part 4 - Coding

Introduction

Our tray-menu contains unresolved details such as what elements to include in the master array and configuration file.

In order to start coding now is a good time to be specific, like remove the ability to have a sub-men title a future feature that probably will never be used.

Retain configuration file and parameter items strictly not required a single line would suffice. However two lines makes it easier for a user to understand.

In a similar vein all those redundant lines for a spacer can be removed. Also delete the item number server's no real purpose.

This page provides final details required to implement our tray-menu.

Top

Tray menu configuration file

Basic format

Main menu and sub-menus have this structure:

  • [block name]
  • Line 1[]
  • Line 2[]
  • Line 3[]
  • Line 4[]
  • Line 5[]

 

The configuration file consists of defined blocks each block has a unique name contained in square brackets.

Main menus block must start with [main_menu] sub-menu blocks must have a unique name enclosed in square brackets.

Note: Names must be alphanumeric lowercase and contain no spaces for example sub_menu_1

All menu entries with the exception of a spacer (single line) consist of five lines Line 1[]-Line 2[] these are arrays and must have a value or set to a empty string.

A menu entry can be one of three types a click-able link, a separator or a sub-menu.

Top

A menu entry block

Each menu entry block consists of five arrays (lines) with the following names and function:

item[]   Text displayed in menu (menu item)
action[]   Action functions are: Command (run or runh). Or a sub-menu (sub). Or a menu spacer (separator)
file[]   File name if above is a command. Sub-menu name if above is a sub
parameter[]   Optional parameters to pass if command is the action.
icon[]   Left icon to display index=0 no icon displayed

Note 1 : Every menu item must have a complete block of five lines.

Note 2 : Exception to the above is a spacer which requires only a single line (action) .

Top

Configuration file example

; File tray_menu.ini
; This is a sample configuration file
; Comments start with ';', as in php.ini

title = "US Menu"                     ; Main application name

[main_menu]

item[]      = "Start Apache Service"  ; display menu item
action[]    = "run"                   ; run, runh, sub, separator 
file[]      = "net"                   ; file name or sub-name
parameter[] = "start  ApacheS1"       ; parameters to pass
icon[]      = "7"                     ; icon id number

item[]      = "Stop Apache service"   ; display menu item
action[]    = "run "                  ; run, runh , sub, separator 
file[]      = "net"                   ; file name or sub-name
parameter[] = "stop ApacheS1"         ; parameters to pass
icon[]      = "6"                     ; icon id number

item[]      = "Service 服务"          ; display menu item
action[]    = "sub"                   ; create sub-menu 
file[]      = "sub_1"                 ; name see section below 
parameter[] = ""                      ; no parameter
icon[]      = "0"                     ; no icon

;-------------------------
action[]    = "separator"             ; only a action name required
;------------------------- 

item[]      = "Exit 出口 "             ; Display menu item text
action[]    = "Exit"                  ; Do not change
file[]      = ""                      ; no file
parameter[] = ""                      ; and no parameter
icon[]      = "4"                     ; Icon cross  

item[]      = "Minimize  最小化"       ; Display menu item text
action[]    = "Minimize"              ; Do not change
file[]      = ""                      ; no file
parameter[] = ""                      ; and no parameter
icon[]      = "3"                     ; Icon down arrow 

;=== Sub-Menus =====================================================
[sub_1]

item[]      = "启动 Apache服务"        ; display menu item
action[]    = "run"                   ; run, runh, sub, separator 
file[]      = "net"                   ; file name or sub-name
parameter[] = "start  ApacheS1"       ; parameters to pass
icon[]      = "9"                     ; icon id number

item[]      = "停止 Apache服务"         ; display menu item
action[]    = "run "                  ; run, runh, sub, separator 
file[]      = "net"                   ; file name or sub-name
parameter[] = "stop ApacheS1"         ; parameters to pass
icon[]      = "8"                     ; icon id number

 


Example pop-up tray menu:

The example configuration file will produce the following tray menu:

All menu elements are shown:

Main Menu:

  • Two click-able menu items
  • A sub-menu hover link
  • A seperator
  • Exit link
  • Minimize link

Sub-menu:

  • Two click-able menu items

Top

Master array elements

  $main[$i][0]  // Configuration section name
  $main[$i][1]  // Configuration menu item text
  $main[$i][2]  // Configuration menu item action
  $main[$i][3]  // Configuration menu file path
  $main[$i][4]  // Configuration menu parameter to pass
  $main[$i][5]  // Configuration menu icon 0 = no icon
  $main[$i][6]  // y-top where an item or rollover starts
  $main[$i][7]  // y-rollover-end where a rollover ends
  $main[$i][8]  // y-bottom where an item ends and the next one starts
  $main[$i][9]  // x-icon1 where left icon starts
  $main[$i][10] // x-rollover-start where a rollover starts
  $main[$i][11] // x-rollover-end where rollover ends
  $main[$i][12] // x-rollover-width width of rollover 
  $main[$i][13] // x-rollover-height height of a rollover
  $main[$i][14] // x-text where text starts
  $main[$i][15] // Maximum string for either main menu or sub-menu 
  $main[$i][16] // x-icon2 where right icon starts
  $main[$i][17] // x-icon2 end where right icon ends


Item number and other elements removed.

Produces a relatively small array.


Top

Command core function

The following example code could be used to process our two commands run and runh

I say could because all paths must be specified as absolute paths.

//=== PROCESS COMMAND =========================================================
function process_command($command_array){
// There are only two types of command to process run and runh (run hidden)

  if($command_array[0] == "run"){          // Standard command to run
    $cmd1 = "start ";                      // Start of command
    $cmd2 = $command_array[1];             // Path string including file name
    $cmd3 = " ";                           // Assume user missed the space
    $cmd4 = $command_array[2];             // parameters to include

    $cmd5 = $cmd1.$cmd2.$cmd3.$cmd4;       // build command string
    pclose(popen($cmd5,'r'));              // Run a detached process
  }

  if($command_array[0] == "runh"){         // Standard command run hidden
    $cmd1 = "start uniserv.exe \"";        // Start of command including utility
    $cmd2 = $command_array[1];             // Path string including file name
    $cmd3 = " ";                           // Assume user missed the space
    $cmd4 = $command_array[2];             // parameters to include
    $cmd5 = "\" ";                         // Add final quote

    $cmd6 = $cmd1.$cmd2.$cmd3.$cmd4.$cmd5; // build command string
    pclose(popen($cmd6,'r'));              // Run a detached process
  }
}
//===================================================== END PROCESS COMMAND ===

Problem Paths

Absolute paths are incompatible with portability in particular USB drives. At best only the drive letter will change worst-case scenario a user moves the application (uniform server) to a different folder.

For Uniform Server this is not an issue because it dynamically rewrites all paths and if integrated into the architecture this tray-menu would be no exception.

However our tray-menu is intended to be general purpose. To address the above issue a user can specify relative paths however not all relative paths work the OS insists on absolute paths for some applications.

Solution; prior to command processing replace all relative paths with absolute ones.

Top

(PHP CLI) relative to absolute path conversion function

The following function converts any relative paths in a string to absolute paths. It assumes relatives paths are relative to the script.

//=== CONVERT RELATIVE TO ABSOLUTE PATHS ====================================== 
// Convers any relative paths found in a string to absolute paths
// Assumes paths are relative to this file

function relative_to_absolute_paths($str){
$path_array  = explode("\\",dirname(__FILE__));           // Blow path appart at "\"
                                                          // Path is this file

$str = trim($str);                                        // Remove L&R spaces
$str = preg_replace('/\s+/', ' ', $str);                  // Remove double spaces
$str_array   = explode(" ",$str);                         // Blow string apart at " " 

for($i = 0; $i < count($str_array); $i++) {                // scan str array line by line
  if( strchr($str_array[$i],"../")){                       // Does string contain  ../
   $str_count = substr_count($str_array[$i],"../");        // Yes: How many
   $str_array[$i] = substr_replace($str_array[$i],"",0,$str_count*3); // Remove

   $new_path ="";                                             // reset new path        
   for($i2 = 0; $i2 < count($path_array)-$str_count; $i2++) { // scan original path 
     $new_path = $new_path.$path_array[$i2]."/";              // build new path
   }
   $str_array[$i] =  $new_path.$str_array[$i];          // Replace relative path
  }                                                     // with absolute path
}

for($i = 0; $i < count($str_array); $i++) {             // scan str array line by line
 $new_str = $new_str. $str_array[$i]." ";               // Rebuild new string
}
  return $new_str;                                      // Return modified string
}
//================================== END CONVERT RELATIVE TO ABSOLUTE PATHS ===

To the process_command() function add the two lines as shown (Convert paths):

//=== PROCESS COMMAND =========================================================
function process_command($command_array){
// There are only two types of command to process run and runh (run hidden)

  //== Convert paths
  $command_array[1] = relative_to_absolute_paths($command_array[1]);
  $command_array[2] = relative_to_absolute_paths($command_array[2]);

Top

Array imbalance problem

Having a single array for a spacer introduces an imbalance of arrays. However since the configuration array is processed sequentially we know where this imbalance occurs hence we can rebalance the arrays.

Although it adds additional code, when configuring a menu configuration file makes life easier for an end user.

These arrays are sequentially ordered hence this function fits the bill:

Array insert function

//=== Array Insert =============================================================
function array_insert(&$array, $insert, $position = -1) { 
 $position = ($position == -1) ? count($array) : $position ; 
 if($position != count($array)) {                      // Is it end of array 
      $ta = $array;                                      // New array  
      for($i = $position; $i < (count($array)); $i++) {  // Scan array
           if(!isset($array[$i])) {                      // Check there are no holes in array
                die(print_r($array, 1)."\r\nInvalid array: All keys must be numerical and in sequence."); 
           } 
           $tmp[$i+1] = $array[$i];                      // Build part of array   
           unset($ta[$i]);                               // Kill element 
      } 
      $ta[$position] = $insert;                          // Insert value 
      $array = $ta + $tmp;                               // Build complete array  
      //print_r($array); 
  }
  else {                                                // Yes: End of array 
   $array[$position] = $insert;                         // just insert value
  } 
 
 ksort($array);                                         // Ensure keys are ordered 
 return true; 
} 
//========================================================= END Array Insert ===

Top

Summary

Well in all honesty this page said coding hence filled it with some luddite code. If you are into object orientated programming along with hacking down to “c” level make WinBinder forum your first port of call. They have excellent material.

Hey! They don’t like luddites! However they do respect that we exist. Yep! Supposed to be a joke, point is, WinBinder caters for both traditional and object oriented programming styles. Style is a personal choice there are no restriction imposed by WinBinder.

Tutorial:

That completes this tutorial.

Was the objective meet?

"Objective is to produce a tray menu with format and features similar to Unitray. This ideally would be a replacement for Unitray. Secondary objective is to explore the capabilities of WinBinder."

Secondary objective certainly was and best part of the prime objective. However the menu lacks a right button pop-up menu. Right menu runs the server as a service and is easily catered for by adding items to the left menu.

Currently the menu is generic (see next page for details) and is usable for other applications.

For it to be a UniTray replacement a few Uniform Server specific features require adding. That said if you do not require multi-server support you could use it as is.

Next page looks the tray-menu demo included with the download.


Top