KNOWLEDGE BASE
Log In    |    Knowledge Base    |    4D Home
Tech Tip: How to display a Popup menu with Icons
PRODUCT: 4D | VERSION: 12.3 | PLATFORM: Mac & Win
Published On: March 30, 2012

A common goal for a developer is to make the User Interface as easy to understand as possible. One UI widget that can make the complex look simple is a popup menu with icons. This Tech Tip will demonstrate how to create a popup menu that transforms a path string into a popup with icons.

It is poor to assume that the end user will understand even simple programming structures such as a file path string when presented to them, especially a user used to a graphical interface instead of a command line interface. The method below demonstrates how to take a path string and present with as a popup with icons representing the different parts of the path: the file, the folders, and the root as shown in the image below.



The source code to methods called by this method follow it.

If (True)
   If (False)
      Begin SQL
         /*
          MENU_PathnamePopup ($Type_L;$Path_T;$Prompt_T) -> Menu Choice
         
          Purpose: Present a popup of the path tree and prompt
         
          $0 - TEXT - Menu Choice
          $1 - Longint - Path type, directory or document
          $2 - TEXT - The path string
          $3 - TEXT - Prompt
         */
      End SQL
   End if
   C_TEXT($MethodName_T)
   $MethodName_T:=Current method name
    //================== Declare Variables =================
    //method_parameters_declarations
   C_TEXT($0;;$Choice_T)
   C_LONGINT($Type_L;$1)
   C_TEXT($Path_T;$2)
   C_TEXT($Prompt_T;$3)
    //---------------------------------------------------------
    //method_wide_constants_declarations
    //---------------------------------------------------------
    //local_variable_declarations
   C_LONGINT($Ndx;$SOA;$RIS;$Params_L;$OS_L)
   C_TEXT($MenuRef_T;$Delim_T;$Icon_T)
End if
//================= Initialize and Setup =================

$Params_L:=Count parameters
If ($Params_L#3)
   ASSERT(False;"Parameter conunt not equal to 3!")

Else
   $Type_L:=$1
   $Path_T:=$2
   $Prompt_T:=$3
   
    //================= Method Actions =================
   
   $OS_L:=Pathname_OSType ($Path_T)
   If ($OS_L=Windows)
      $Delim_T:="\\"
   Else
      $Delim_T:=":"
   End if
   
   $RIS:=STR_CountFields ($Path_T;$Delim_T)
   If ($Prompt_T#"")
      ARRAY TEXT($Items_aT;$RIS+2)
   Else
      ARRAY TEXT($Items_aT;$RIS)
   End if
   
   If ($OS_L=Windows)
       // Match regex comand used in STR_Parse method has problems
       // with Window folder separater as used in this variable.
       // substituting a tab character and changing the delimiter
       // works around the issue.
       // (
      $Path_T:=Replace string($Path_T;$Delim_T;"\t")
      $Delim_T:="\t"
       // )
   End if
   
   $Items_aT:=0
   For ($Ndx;$RIS;1;-1)
      $Items_aT:=$Items_aT+1
      $Items_aT{$Items_aT}:=STR_Parse ($Path_T;$Ndx;$Delim_T)
      If ($Items_aT=$RIS)
         $Items_aT{$RIS}:=Replace string($Items_aT{$RIS};":";"")
      End if
   End for
   If ($Prompt_T#"")
      $Items_aT:=$Items_aT+1
      $Items_aT{$Items_aT}:="(-" // Menu separator line
      $Items_aT:=$Items_aT+1
      $Items_aT{$Items_aT}:=$Prompt_T
   End if
   
   $MenuRef_T:=Create menu
   For ($Ndx;1;$RIS)
      APPEND MENU ITEM($MenuRef_T;$Items_aT{$Ndx})
      If ($Ndx=$RIS)
         If ($OS_L=Windows)
            SET MENU ITEM ICON($MenuRef_T;$Ndx;"File:Win_HD_icon.png")
         Else
            SET MENU ITEM ICON($MenuRef_T;$Ndx;"File:Mac_HD_icon.png")
         End if
      Else
         $Icon_T:=MENU_Icon ($OS_L;$Items_aT{$Ndx})
         SET MENU ITEM ICON($MenuRef_T;$Ndx;$Icon_T)
      End if
   End for
   
   If ($Prompt_T#"")
      APPEND MENU ITEM($MenuRef_T;$Items_aT{$Items_aT-1})
       // Prompt menu and value to be returned by the choice
       // (
      APPEND MENU ITEM($MenuRef_T;$Items_aT{$Items_aT})
      SET MENU ITEM PARAMETER($MenuRef_T;-1;String($Items_aT{$Items_aT}))
       // )
   End if
   
    // Present the popup menu to the user
    // (
   $Choice_T:=Dynamic pop up menu($MenuRef_T;"")
    // )
   
    // Clear the menu from memory
    // (
   RELEASE MENU ($MenuRef_T)
    // )

End if

//================= Clean up and Exit =================

$0:=$Choice_T



The method below, Pathname_OSType, will test the string and return its native OS type.

If (True)
   If (False)
      Begin SQL
         /*
          Pathname_OSType ($Path_T) -> OSType
         
          Purpose: Given a path string, determine what is its native OS
         
          $0 - Longint - purpose
          $1 - TEXT - purpose
         */
      End SQL
   End if
   C_TEXT($MethodName_T)
   $MethodName_T:=Current method name
    //================= Declare Variables =================
    //method_parameters_declarations
   C_LONGINT($0)
   C_TEXT($Path_T;$1)
    //--------------------------------------------------------------------------------
    //method_wide_constants_declarations
    //--------------------------------------------------------------------------------
    //local_variable_declarations
   C_LONGINT($Pos_L)
   C_TEXT($RegExPat_T)
   C_BOOLEAN($Found_B)
End if
//================= Initialize and Setup =================

$Path_T:=$1

  // msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
  //
  // Valid start for Windows absolute path strings such as:
  // ([a-zA-Z]:\\\\) - A disk designator with a backslash, e.g. "C:\" or "d:\"
  // (\\\\) - A UNC name of any format, starts with two backslash characters ("\\").
  // (
$RegExPat_T:="(([a-zA-Z]:\\\\)|(\\\\))"
  // )

//================= Method Actions =================

$Found_B:=Match regex($RegExPat_T;$Path_T;1;$Pos_L)
If ($Found_B & ($Pos_L=1))
   $0:=Windows
Else
   $0:=Mac OS
End if


The method below, STR_CountFields, will how many delimited elements are in the string.

If (True)
   If (False)
      Begin SQL
       /*
       STR_CountFields($Buf_T;$Delim_T)
      
       Purpose: Count how many fields exist in a conpacted string
      
       $1 - TEXT - Contains the String to be tested
       $2 - TEXT - Contains the Delimiter to test with
       /*
      End SQL
   End if
   C_TEXT($MethodName_T)
   $MethodName_T:="CVT_CountFields"
    //===================== Declare Variables =================
    //method_parameters_declarations
   C_TEXT($Buf_T;$1)
   C_TEXT($Delim_T;$2)
    //--------------------------------------------------------------------------------
    //method_wide_constants_declarations
    //--------------------------------------------------------------------------------
    //local_variable_declarations
   C_LONGINT($Ndx;$Len;$Cnt)
End if

//====================== Initialize & Setup ================================
$Buf_T:=$1
$Delim_T:=$2
$Cnt:=0
$Len:=Length($Buf_T)

//======================== Method Actions =================
If ($Len>0)
   $Ndx:=Position($Delim_T;$Buf_T) // Count the record delimiters in the chunk.
   While ($Ndx#0)
      If ($Len>0)
         $Buf_T:=Substring($Buf_T;$Ndx+1)
         $Cnt:=$Cnt+1
         $Ndx:=Position($Delim_T;$Buf_T)
         $Len:=Length($Buf_T)
      End if
   End while
   
   If ($Len>0)
      $Cnt:=$Cnt+1
   End if
End if

//======================== Clean up & Exit =================================

$0:=$Cnt


The method below, STR_Parse, will return Nth delimited element from a string.

If (True)
   If (False)
      Begin SQL
       /*
       STR_Parse (SourseText_T; OccuranceWanted_L{{; Delimiter_T}; Truncate_P}) -> String
      
       Purpose: To return nth element from a delimited string
      
       $1 - TEXT - string to search in
       $2 - LONGINT - integer number of times to locate character
       $3 - STRING - (optional) string, the character to search for
       $4 - POINTER - (optional) pointer - pointer to initial string to allow truncation
             (Destructive parsing)
       /*
      End SQL
   End if
   C_TEXT($MethodName_T)
   $MethodName_T:=Current method name
    //===================== Declare Variables =================
    //method_parameters_declarations
   C_TEXT($0;$String;$1;$Result)
   C_LONGINT($Wanted;$2)
   C_STRING(80;$Search;$3)
   C_POINTER($4;$Truncate) // 12/20/96
    //--------------------------------------------------------------------------------
    //method_wide_constants_declarations
    //--------------------------------------------------------------------------------
    //local_variable_declarations
   C_LONGINT($Ndx;$SOA;$Pos_L;$Len_L;$Params_L)
   C_BOOLEAN($Success)
End if
//====================== Initialize and Setup ================================

$String:=$1
$Wanted:=$2 // the number of the character to find
$Result:=""

//======================== Method Actions =================

If (($String#"") & ($Wanted>0))
   $Params_L:=Count parameters
   If ($Params_L=2) // if this is looking just for tabs
      $Search:="\t"
   Else // assign passed string
      $Search:=$3
      If ($Params_L=4)
         $Truncate:=$4 // pointer to value to truncate
      End if
   End if
   
   $SOA:=1
   $Pos_L:=1
   
   $Ndx:=STR_CountFields ($String;$Search)
   If ($Ndx>=$Wanted)
      
       //======================== Method Actions =================
      
      For ($Ndx;1;$Wanted)
         $Success:=Match regex($Search;$String;$SOA;$Pos_L;$Len_L)
         Case of
            : ($Success) & ($Ndx=$Wanted))
               If ($Params_L<4)
                  $Result:=Substring($String;$SOA;$Pos_L-$SOA)
               Else
                   // replace the incomming string with the truncated version (found removed)
                  $Truncate->:=Substring($String;1;$SOA)
               End if

         : ($Ndx=$Wanted)
            If ($Params_L<4)
               $Result:=Substring($String;$SOA)
            Else
                // replace the incomming string with the truncated version (found removed)
               $Truncate->:=Substring($String;1;$SOA)
            End if

         Else
            $SOA:=$Pos_L+$Len_L
         
         End case
      End for
      
       //======================== Clean up and Exit =================================
   
   End if
End if

$0:=$Result


The method below, MENU_Icon, will return the path string to the icon.

If (True)
   If (False)
      Begin SQL
      /*
       MENU_Icon ( OS_L; File Suffix {; "*" }) -> $Path_L
      
       Purpose: Return the path to the Icon to be included in a Menu item
          or to be loaded using READ PICTURE FILE
      
       $0 - TEXT - File path to the icon
       $1 - LONGINT - OS, Windows or Mac OS
       $2 - TEXT - File suffix
       $3 - TEXT - Option param
      */
      End SQL
   End if
   C_TEXT($MethodName_T)
   $MethodName_T:=Current method name
    //===================== Declare Variables =================
    //method_parameters_declarations
   C_TEXT($0;$Path_T)
   C_LONGINT($OS_L;$1)
   C_TEXT($Suffix_T;$2)
    //--------------------------------------------------------------------------------
    //method_wide_constants_declarations
    //--------------------------------------------------------------------------------
    //local_variable_declarations
   C_LONGINT($Ndx;$Params_L)
End if
//====================== Initialize and Setup ================================

$Path_T:=""
$Params_L:=Count parameters
If (Asserted(($Params_L>1) & ($Params_L<4);"Bad param count"))
   $OS_L:=$1
   $Suffix_T:=$2
   $Suffix_T:=Pathname_Suffix ($Suffix_T)
   
    //======================== Method Actions =================
   
   Case of
      : ($Suffix_T="")
         If ($OS_L=Windows)
            $Path_T:="File:Win_Folder_icon.png"
         Else
            $Path_T:="File:Mac_Folder_icon.png"
         End if
      
      : ($Suffix_T=".4DD")
         $Path_T:="File:4DD.png"
      
      : ($Suffix_T=".4DIndx")
         $Path_T:="File:4DIndx.png"
      
      : ($Suffix_T=".4DIndy")
         $Path_T:="File:4DIndy.png"
      
      : ($Suffix_T=".4DMatch")
         $Path_T:="File:4DGeneric.png"
      
      : ($Suffix_T=".4BK")
         $Path_T:="File:4DGeneric.png"
      
      : ($Suffix_T=".4BL")
         $Path_T:="File:4DGeneric.png"
      
      : ($Suffix_T=".4DSyncData")
         $Path_T:="File:4D_Server.png"
      
      : ($Suffix_T=".4DSyncHeader")
         $Path_T:="File:4D_Server.png"
      
      : ($Suffix_T=".BLOB")
         $Path_T:="File:4D_BLOB.png"
      
      Else
         $Path_T:="File:Generic-Document-icon.png"
   
   End case
   
   If ($Params_L=3)
       // When using READ PICTURE FILE "File:" must be replaced with absolute path
       // (
      $Path_T:=Replace string($Path_T;"File:";Get 4D folder(Current Resources folder))
       // )
   End if
   
    //======================== Clean up and Exit =================================

End if

$0:=$Path_T


The method below, Pathname_Suffix, will return the suffix on the file name or "" on a path.

If (True)
   If (False)
      Begin SQL
         /*
          Pathname_Suffix ( $Path_T ) -> $Suffix_T
         
          Written by Charles Vass - 01/25/2012, 10:46
         
          Purpose: Return the suffix off a file path or an empty string
         
          $0 - TEXT - File suffix or empty string
          $1 - TEXT - Pathname
         */
      End SQL
   End if
   C_TEXT($MethodName_T)
   $MethodName_T:=Current method name
    //===================== Declare Variables ==================================
    //method_parameters_declarations
   C_TEXT($0;$Suffix_T)
   C_TEXT($Path_T;$1)
    //--------------------------------------------------------------------------------
    //method_wide_constants_declarations
    //--------------------------------------------------------------------------------
    //local_variable_declarations
   C_LONGINT($Ndx;$SOA)
End if
//====================== Initialize and Setup ================================

$Path_T:=$1

//======================== Method Actions ==================================

$Ndx:=STR_PositionR (".";$Path_T)
If ($Ndx>0)
   $Suffix_T:=Substring($Path_T;$Ndx)
End if

//======================== Clean up and Exit =================================

$0:=$Suffix_T


The method below, STR_PositionR, preforms the Position function from the end of the string.

If (True)
   If (False)
      Begin SQL
       /*
      
       STR_PositionR
      
       Purpose: Position of target string from the right
      
       $0 - LONGINT - Position
       $1 - TEXT - What to find
       $2 - TEXT - Source string
      
       /*
      End SQL
   End if
   C_TEXT($MethodName_T)
   $MethodName_T:=Current method name
    //===================== Declare Variables ==================================
    //method_parameters_declarations
   C_LONGINT($0;$PosLast_L)
   C_TEXT($1;$Find_T)
   C_TEXT($2;$String_T)
    //--------------------------------------------------------------------------------
    //method_wide_constants_declarations
    //--------------------------------------------------------------------------------
    //local_variable_declarations
   C_LONGINT($PosNext_L)
   C_TEXT($Marker_T)
End if
//====================== Initialize and Setup ================================

$Find_T:=$1
$String_T:=$2

//======================== Method Actions ==================================

$Marker_T:=Char(1)*Length($Find_T)
If ($Find_T=$Marker_T)
   $Marker_T:=Char(2)*Length($Find_T)
End if

$PosLast_L:=0
Repeat
   $PosNext_L:=Position($Find_T;$String_T)
   If ($PosNext_L>0)
      $PosLast_L:=$PosNext_L
      $$String_T:=Replace string($$String_T;$Find_T;$Marker_T;1)
   End if
Until ($PosNext_L=0)

//======================== Clean up and Exit =================================

$0:=$PosLast_L