# $Header:   P:\source\wmacros\history.pev   1.63.1.0   31 Mar 1995 16:23:52   WALKER  $
## $Tabs:4 7$

##############################################################################
#
#       Compuware Corporation
#         31440 Northwestern Highway
#           Farmington Hills, Michigan 48334-2564
#
#   This source code listing contains information that is
#   proprietary to Compuware Corporation and may not be copied
#   duplicated, translated, transmitted, stored, retrieved
#   or in any manner or by any method conveyed or disclosed
#   to a third party or parties without express written
#   permission from Compuware Corporation.
#
#  
##############################################################################

#### $Workfile:   history.pel  $: Response history support

local   historyArray
local   historyName
local   historyElement
local   historyPromptString  # current prompt string displayed by prompt_history

local writeConfigArray[]

global  edit_file_dir = 1  # set to 1 to display dir list from edit_file_key()
global  MAX_HISTORY   = 10
global  history_font  = -1 # Font to use for History List,
                           # Default is FONT_MODERN8

# This function will return an array containing the history of a
# specified type of history given an index into the history array, 
function history_config( index )
{
   local i           = 0
   local end         = (index 0 in historyArray) ? historyArray[index 0] : 0

   local data_index  = 1
   local data[]

   local word = "";
   
   if (writeConfigArray[index] != 1)
      return;

   #
   # check to make sure something is in array
   #
   if (!(index i in historyArray))
      historyArray[ index i ] = i;
   
   # 
   # Write list to file
   #
   if ( end > MAX_HISTORY )
      i = end - MAX_HISTORY 
   
   while ( (i=i+1) <= end )
   {
#     gsub("\"", "'", historyArray[index i] )
      word = historyArray[index i];

      #  Although this line appears to be pointless, it fixes the problem
      #  of actual new lines being written to the config file.
      gsub("\\n", "\\n", word);

      data[ data_index++ ] = sprintf(  "add_prompt_history %s \"%s\"\n", 
                                       index, 
                                       quote_quote(quote_regex( word )) )
   }
   data[ data_index++ ] = sprintf( "\n" )
   return data   
}

global function get_history_list(history_name)
{
   local end
   local i = 0
   local data[]
   local retval = ""

   setup_prompt_history( history_name )
   end = (history_name 0 in historyArray) ? historyArray[history_name 0] : 0

   if (history_name i in historyArray)
   {
      data = history_config( history_name )
   
      for ( i = 1; i < end; i++ ) 
      { 
         retval = retval historyArray[history_name i] "^"
      }
   }

   return retval
}

local IDM_ADD_EDITFILE = 0x300
global function add_editfile_to_menu()
{
   local main_menu = menu_info(0, MI_MENUHANDLE)
   local menu = menu_info( main_menu, MI_MENUHANDLE, IDM_FILE )
   local menu_id = IDM_ADD_EDITFILE
   local MAX_ITEMS = 5
   local history_name = "EDITFILE"
   local end
   local i = 0
   local count = 1
   local data[]

   delete_event(EVENT.NEW_EDIT_FILE, "add_editfile_to_menu")
   attach_event_handler(EVENT.NEW_EDIT_FILE, "add_editfile_to_menu")

   setup_prompt_history( history_name )
   end = (history_name 0 in historyArray) ? historyArray[history_name 0] : 0

   if (!(history_name i in historyArray))
      return

   data = history_config( history_name )

   for ( i = menu_id; i <= menu_id + MAX_ITEMS; i++ )
      delete_menuitem(main_menu, i)

   for ( i = end; i > 0 && i > end - MAX_ITEMS; i-- ) 
   { 
      insert_menuitem(menu, menu_id, IDM_EXIT, MI_MENUITEM, "~" count++ " " historyArray[history_name i] )
      menu_functions[menu_id] = "create_buf_and_win " historyArray[history_name i]
      menu_id++
   }

   insert_menuitem(menu, menu_id++, IDM_EXIT, MI_SEPARATOR )
}

#------------------------------------------------------------------#
##      prompt_history()
#
# Prompt the user for a string and process all illegally typed characters
# through the _bad_prompt_key() function.  The parameters passed are as
# follows:
#
#       index     - a string identifying which history stack to use
#       promptstr - first parameter to prompt()
#       defaultstr- second parameter to prompt()
#       usehistory- if defaultstr == "" and usehistory == 1, use the
#                   last history item
#
# Example:
#       prompt_history( "SEARCH", "Search for: ", "noname" )
#
#       Each time this is called an a valid input string is entered
#       and returned by prompt(), it is added to the history stack
#       and subsequent calls can access this stack.
#
global function setup_prompt_history(index, element)
{
   local   patt
   local   i     = 0;
   local   id    = function_id( "_bad_prompt_key" );

   # don't setup a history twice
   #
   if ( index == historyName)
      return

   #
   #  initialize historyArray in need to
   #
   if (!(index i in historyArray))
   {
      historyArray[ index i ] = i;

      writeConfigArray[index] = 1
      read_config_section("$" index "_HISTORY$")
   }
   #
   # let the command history functions know where to find
   # the command history for this specified call.
   #
   historyName = index;
   historyElement = element ? -1 : 0;

   # install an event handler to make history
   # available to the prompt function.
   # only needs to be installed once
   #
   delete_event( EVENT.INVALID_PCHAR, id )
   attach_event_handler( EVENT.INVALID_PCHAR, id )

}

global function prompt_history( index, promptstr, defaultstr, usehistory, highlight, helpid ) 
{
   local patt

   if ( argcount() < 5 )
      highlight = TRUE

   setup_prompt_history( index )

   historyElement = defaultstr ? -1 : 0;
   #
   # prompt for the search pattern and provide command history
   #
   if ((historyElement == 0) && (usehistory))
   {
      defaultstr = current_history_item( index );
      historyElement = -1;
   }

   if (!helpid)
      helpid = "default_prompt"
   patt = prompt( historyPromptString = promptstr, defaultstr, helpid, highlight )

   cleanup_prompt_history();

   return patt;
}

global function cleanup_prompt_history()
{
   delete_event( EVENT.INVALID_PCHAR, function_id( "_bad_prompt_key" ) )

   if ( historyName == "SEARCH" )
      optional_function("delete_regex_table")

   historyName = ""
}

# This function is useful for those edit controls in dialogs that may
# cause a DM_INVALID_PCHAR message because they want to use history
# features
#
function dialog_history( dlgHand, dlgId, histName )
{
   local old_prompt_response

   prompt_response = query_dialog_item(dlgHand, dlgId, DAC_EDIT_TEXT)
      
   # save prompt_response before the we execute the event
   #
   old_prompt_response = prompt_response

   setup_prompt_history( histName, prompt_response )

   execute_event_handler( EVENT.INVALID_PCHAR )

   # only update edit box if any event handlers for EVENT.INVALID_PCHAR
   # have changed the prompt_response variable.  Every time an edit box
   # is updated the cursor is positioned at the end of the line.
   if ( prompt_response != old_prompt_response )
   {
      set_dialog_item(dlgHand, dlgId, DAC_EDIT_TEXT, prompt_response "", 1)
   }

}

##      _bad_prompt_key()
#
# This is the event handler used to handle bad keys entered from the prompt
# primitive.
#
# A few notes:
#
#    o  This function will receive any key which is not a simple upper
#       or lower case letter, including <Enter>, <Spacebar>, <Ctrl-A> etc.
#
#    o  The "prompt_response" variable contains the current input string
#       at the prompt.  This string can be modified in any manner and will
#       be reflected at the prompt line.
#
#    o  The value of "current_key" will be processed when this function
#       returns as if this function was never called.  If you wish that
#       the key not be processed, set "current_key = 0"; or if you wish to
#       replace it with a different key, set "current_key = <your_keycode>".
#       For example, setting current_key to "KEYCODE_HOME" will cause the
#       cursor to move to the beginning of the prompt response.
#
#    o  Setting current_key to the magic value -1 resets prompt() to its
#       initial state, i.e. it highlights the current prompt_response value
#       and places the cursor at the end of the response.  If the
#       prompt_response variable is changed without setting current_key
#       to -1, the cursor position will be left unchanged.
#
global function _bad_prompt_key()
{
   local   min = 0;
   local   max, i
   local   buffer;
   local   tempArray[]
   local   width = 20
   local   response
   local   help_word, start, end, parent
   
   if ( current_key == KEYCODE_TAB )
   {
      #
      # if we are performing an invoke_function (F10) and a TAB
      # was pressed, then display function listing
      #
      if (historyName == "XMACRO" || historyName == "ISPF")
      {
         displayFunctionList(historyName)
         current_key = 0
         return
      }
      # if we are performing an edit_file 
      else if (historyName == "EDITFILE" || historyName == "SRCHFILES")
      {
         # save the prompt_display_handle since the following loop could
         # bring up several dialogs and change the prompt_display_handle
         parent = prompt_display_handle

         # continue displaying directory information as long as a directory
         # is selected
         while ( displayDirContents() && prompt_response ~ /\\$/ ) 
         {}

         current_key = 0
         return
      }
      else if(historyName == "BOOKMARKS")
      {
         displayMatchingBookmark();
         current_key = 0;
         return;
      }
   }
   else if (current_key == KEYCODE_PAGEUP     || current_key == KEYCODE_PAGEDOWN ||
            current_key == KEYCODE_NUM_PAGEUP || current_key == KEYCODE_NUM_PAGEDOWN )
   {
      # display history list
      tempArray = get_history( historyName )

      for ( i in tempArray )
         width = max(width, length(tempArray[i]))

      # i will be set to the last element and our list box is 0 based
      select_index = i - 1

      response = prompt_selection( historyName " History List", width, tempArray )

      # reset select_index back to 0
      select_index = 0
      
      if ( !response )
         prompt_response = old_response
      else 
         prompt_response = response

      delete( tempArray )
      current_key = -1  # highlight the string
      return
   }
#   else if ( current_key == help_key )
   else if ( current_key == 0x9020 )  # CTRL-F1
   {
      if ( historyName == "XMACRO" )
      {
         # initialize start to beginning of word
         start = 1

         # if "?" is found, then start after it
         if ( match(prompt_response, "\\?") == 1 )
            start = 2

         # end the word at either a space or EOL
         end       = match(prompt_response, " |$") - 1
         help_word = trim(substr(prompt_response, start, end))

         display_help_item( help_word )
      }
      else if ( historyName == "SEARCH" )
         display_help_item( "regexpr" )

      current_key = 0;
      return;
   }
   else if (current_key == KEYCODE_ESC)
   {
      if ( status_bar_flags )
         message("Command cancelled.")
      return;
   }
   else if (current_key == KEYCODE_CTRL_R && historyName == "SEARCH" )
      optional_function("display_regex_table")

   #
   # is there something in the list?
   #
   max = historyArray[ historyName min ];
   if (current_key == KEYCODE_DOWN || current_key == KEYCODE_NUM_DOWN)
   {
      # get previous command
      if (max)
         historyElement = (historyElement + 1) % max
   }
   else if (current_key == KEYCODE_UP || current_key == KEYCODE_NUM_UP)
   {
      # get next command
      if (max)
      {
         if (historyElement <= 0)                # skip first entry if < 0
            historyElement = max + historyElement;
         if (historyElement)
            historyElement--;
      }
   }
   else if (int_to_key(current_key) == "<Alt-L>" || int_to_key(current_key) == "<Ctrl-L>" )
   {
      current_key = -1  # highlight the string
      return
   }
   else if (int_to_key(current_key) == "<Alt-D>" || int_to_key(current_key) == "<Ctrl-D>" )
   {
      # remove the current item from the history list
      #
      delete_history_item( historyName, prompt_response )

      # then just fall through and allow the prompt_response to change
   }
   else if (int_to_key(current_key) == "<Enter>" )
   {
      if ( prompt_response )
         add_prompt_history( historyName, prompt_response )

      return
   }
   else
   {
      #             
      # Didn't find any keys that we want to handle so
      # just return.
      #
      return;
   }

   #
   # read the response out of the buffer
   #
   # index was 0..n-1, it should be 1..n
   current_key = 0;
   if (max <= 0)
      return;
   else
   {
      prompt_response = historyArray[ historyName (historyElement + 1) ];
      current_key = -1        # highlight the new prompt response
   }
}

# these function are here so historyElement doesn't need to be global
#
function get_history_element()
{
   return historyElement
}

## find an item in the command history array
#
global function current_history_item( index, i )
{
   i += 0
   if (index i in historyArray)
   {
      i = historyArray[ index i ];
      if (i)
         return historyArray[ index i ];
   }
   return "";
}

## add an item to the command history array
#
global function add_prompt_history( index, patt )
{
   local i = 0;
   local j = 0;
   local promptCount = 0;
   local found = 0;

   setup_prompt_history( index )

   # remove the item from list and just add it to the bottom
   delete_history_item( index, patt )

   promptCount = historyArray[ index i ];

   historyArray[ index 0 ] = ++promptCount;

   # add patten to end of list
   historyArray[ index promptCount ] = patt;

   cleanup_prompt_history()

   return patt
}

# removes the specified pattern from the history list

function delete_history_item( histName, pattern )
{
   local j, i = 1
   local promptCount = 0;
   local found = 0;

   if (histName 0 in historyArray)
      promptCount = historyArray[ histName 0 ] + 0

   # search the history list for the pattern
   #
   while (histName i in historyArray && i <= promptCount)
   {  
      if (historyArray[ histName i ]  == pattern)
      {
         found = i;
         break
      }
      i = i + 1;
   }
   
   # if the pattern was found, move the item after it up one place
   #
   if ( found )
   {
      i = found
      while (i < promptCount)
      {
         j = 1 + i
         historyArray[histName i] = historyArray[histName j]
         i = i + 1
      }

      delete historyArray[ histName promptCount ]
      historyArray[ histName 0 ] = --promptCount
   }

   return found
}


function get_history( index )
{
   local temp
   local i = 0
   
   while ( ++i <= historyArray[index 0] )
   {
      temp[i] = historyArray[index i]
   }

   return temp
}

#--------- display list of functions and allow movement within it --------#


## displayFunctionList()
#
# Display all of the functions available which start with
# the pattern specified of at least two characters (zero or one might
# take too long)
#
global  symbol_list

local function displayFunctionList(historyName)
{
   local   i
   local   fid
   local   prefix
   local   result
   local   searchFor
   local   numOfEntries
   local   sorted_symbol_list
   local   symbolMatchFlag = PRIMITIVE_ALL + GLOBAL_ALL
   local   width = 20
   local   listdlg
   current_key = 0
   
   # extract question mark
   if ( substr( prompt_response, 1, 1 ) == "?" )
   {
      prefix = "?"
      searchFor = substr( prompt_response, 2 )
   }
   else
   {
      searchFor = prompt_response
      # uncomment the following line to omit variables from
      # <F10> command completion (if no "?" is present)
      # symbolMatchFlag = PRIMITIVE_FUN + GLOBAL_FUN
   }

   # in case symbol_match takes a long time
   if ( status_bar_flags )
      message( "Working..." )
   # read a list of all symbols beginning with the specified pattern
   if ( length( searchFor ) < 2 )
   {
      if ( status_bar_flags )
         message( "Must type at least two characters." )
      beep()
      return
   }
   else if (!(symbol_list = symbol_match( searchFor, symbolMatchFlag )) )
   {
      if ( status_bar_flags )
         message( "no matching symbols found." )
      beep()
      return
   }

   if ( status_bar_flags )
      message( "" )

   # Add emulation-specific commands.
   optional_function( tolower(historyName) "_commands", searchFor )

   # how many did we get?
   for (i in symbol_list)
   {
      sorted_symbol_list[ symbol_list[i] ] = numOfEntries++
      width = max(width, length(symbol_list[i]))
   }

   if ( numOfEntries == 0 )              # no match
      beep()

   else if ( numOfEntries == 1 )         # only one match
   {
      new_response = prefix symbol_list[i]
      current_key = KEYCODE_END
   } 
   else
   {
      # create a dialog box for the list
      listdlg = create_selection_dialog( "Command List", width )
      
      # fill the list box 
      for (i in sorted_symbol_list)
      {
         #add items to list box
         set_dialog_item( listdlg, IDL_LIST, DAC_ADD_ITEM, prefix i )
      }
      begin_dialog(listdlg)
      delete_dialog(listdlg)
   }

   if ( !new_response )
      prompt_response = old_response
   else 
      prompt_response = new_response

   delete( symbol_list )           # deallocate the arrays
   delete( sorted_symbol_list )
}

#--------- display directory specified and allow movement within it --------#


## displayDirContents()
#
# Display all of the files in the current directory which start with
# the pattern specified of *.* if none.
#
# Maybe add changing directories and other items later.
#

local function displayDirContents( parent )
{
   local   fname
   local   numOfEntries = 0        # number of files in current directory
   local   lastname
   local   prompt_start
   local   l,r,c,i
   local   srchname, tmp
   local   insert_prev_dir = FALSE
   local   find_flags, dir_list, file_list
   local   dirInfo = ""
   local   maxWidth = 20
   local   ft, status
   local   listdlg

   prompt_start = prompt_response
   l = rindex( prompt_start, "\\" )
   r = rindex( prompt_start, "/" )
   c = rindex( prompt_start, ":" )
   l = l > r ? l : r
   l = l > c ? l : c
   prompt_start = prefix( prompt_start, l )

   #
   # read in all of normal file names from the current directory
   # and insert them into the current_buffer
   #
   srchname = prompt_response
   if ( (!srchname) || (rindex(srchname, "?") != length( srchname )))
   {
      tmp = path_ext( srchname )
      if ( !tmp )
      {
         if ( length(path_fname(srchname)) >= 8 )
            srchname = srchname ".*"
         else
            srchname = srchname "*.*"
      }
      else
      {
         if ( length(tmp) < 4 )
            srchname = srchname "*"
      }
   }

   find_flags = ONLY_SUBDIR            # include only directories

   # in case directory search takes a long time
   if (status_bar_flags)
      message( "Working..." )

   for (i=0; i < 2; i++)
   {
      fname = findfirst( srchname, find_flags )
      fname = path_fname( fname ) path_ext( fname )

      while (fname)
      {
         if (i == 0)
         {
            lastname = fname "\\"
            if ( edit_file_dir )
            {
               ft = filetime()
               dirInfo = sprintf( "  <DIR>  %8s  %8s  %s", dos_date(ft), dos_time(ft), lastname)
            }
            else
               dirInfo = lastname

            dir_list[ toupper(lastname) ] = dirInfo
            maxWidth = max(length(dirInfo), maxWidth)
         }
         else
         {
            lastname = tolower(fname)
            if ( edit_file_dir )
            {
               if ( filesize() >= 0 )
               {
                  ft = filetime()
                  dirInfo = sprintf( "%7d  %8s  %8s  %s", filesize(), dos_date(ft), dos_time(ft), lastname)
               }
            }
            else 
               dirInfo = lastname

            file_list[ lastname ] = dirInfo 
            maxWidth = max(length(file_list[lastname]), maxWidth)
         }
         numOfEntries++
         fname = findnext()
      }
      find_flags = _NORMAL           # include normal files
   }

   if (".\\" in dir_list){
      numOfEntries--;
      delete( dir_list[ ".\\" ] )
   }

   if ( numOfEntries == 0 )
   {
      # no files match the file pattern
      if ( status_bar_flags )
         message( "No match found." )
      current_key = 0;
      beep();
      return;
   }
   else if ((numOfEntries == 1) && (!insert_prev_dir))
   {
      if ( status_bar_flags )
         message( "" )
      #
      # only one file that matched, just set the prompt response
      # and return
      #
      prompt_response = prompt_start lastname;
      current_key = KEYCODE_END
      return;
   }

   if ( status_bar_flags )
      message( "" )

   if (status_bar_flags)
      message( "File: " prompt_response )

   # create a dialog box with the dir list
   listdlg = create_selection_dialog( "File List", maxWidth, dir_list, parent )
   
#   for (i in dir_list)
#   {
#      # fill the list box 
#      set_dialog_item( listdlg, IDL_LIST, DAC_ADD_ITEM, dir_list[i] )
#   }

   # now add the file_list
   for (i in file_list)
   {
      # fill the list box 
      set_dialog_item( listdlg, IDL_LIST, DAC_ADD_ITEM, file_list[i])
   }

   begin_dialog(listdlg)
   delete_dialog(listdlg)

   # new_response won't have a value if we cancelled from 
   # the above dialog.  We will save this value and return it
   status = !!new_response

   if ( edit_file_dir )
   {
      if(!status)
         prompt_response = old_response
      else
         prompt_response = prompt_start substr(new_response, 30)
   }
   else
      prompt_response = prompt_start new_response

   delete dir_list
   delete file_list
   
   return status
}

function displayMatchingBookmark()
{
   local count = 0, i, name, pos;
   local length = length(prompt_response);
   local dhMark, mark_list;

   mark_list = build_bookmark_list()
   for(name in mark_list)
   {
      if(substr(name, 1, length) == prompt_response)
      {
         count++;
      }
      else
         delete mark_list[name]
   }
   if(count == 1)
   {
      current_key = KEYCODE_END;
      new_response = mark_list[name];
   }
   else if(count > 1)
   {
      dhMark = create_selection_dialog("Bookmarks", 0, mark_list);
      begin_dialog(dhMark);
      delete_dialog(dhMark);
   }
   else
      beep();

   if ( !new_response ) 
      prompt_response = old_response
   else
   {
      pos = match(new_response, ":");
      prompt_response = substr(new_response, 1, pos-1);
   }
}

function prompt_selection(title, width, list, parent, sort)
{
   local dlgid = create_selection_dialog(title, width, list, parent, sort)
   begin_dialog( dlgid )
   delete_dialog( dlgid )
   return new_response
}                

# The following variables are used as storing results from the 
# history list selection dialog.  These values are later used
# to set prompt_response depending on how the dialog box was
# ended.
local  old_response      # response before dialog was invoked
global new_response      # response selected from dialog box

function create_selection_dialog(title, width, list, parent, sort)
{
   local cursize, i
   local dhFile

   # if no parent is specified, default to the the prompt_display_handle
   if ( !parent ) 
      parent = prompt_display_handle

   new_response = ""

   old_response = prompt_response

   # create a dialog box for the list
   #
   dhFile = create_dialog( function_id("selection_list_callback"), 
                           parent, IDD_LIST, resource_dll, title )
   
   #add the list box
   add_dialog_item( dhFile, IDL_LIST,  DCTRL_LIST_BOX )
   if (sort == 2)
      set_dialog_item( dhFile, IDL_LIST, DAC_SORT_DESCENDING )
   else if (sort)
      set_dialog_item( dhFile, IDL_LIST, DAC_SORT_ASCENDING )
   add_dialog_item( dhFile, DI_OK,     DCTRL_DEFAULT_PUSH_BUTTON )
   add_dialog_item( dhFile, DI_CANCEL, DCTRL_PUSH_BUTTON )
   save_button_positions(dhFile)

   if (history_font)
      set_dialog_item( dhFile, IDL_LIST, DAC_FONT, history_font+0, FONT_NORMAL)

   set_dialog_window( dhFile, DWC_SIZEBORDER )

   if ( width )
   {
      width = min(500, width * 12)
      cursize = query_dialog_window(dhFile, DWC_SIZE)
      set_dialog_window(dhFile, DWC_SIZE, width, cursize % 65536 )
   }


   # fill the list box 
   if ( list )
      for (i in list)
         set_dialog_item( dhFile, IDL_LIST, DAC_ADD_ITEM, list[i])

   return dhFile
}

local select_index = 0
function selection_list_callback()
{
   local new_width, new_height

   if ( callback_msg == DM_INIT )
   {
      set_dialog_item(callback_dialog_handle, IDL_LIST, DAC_SETFOCUS)
      set_dialog_item(callback_dialog_handle, IDL_LIST, DAC_SELECT_INDEX, select_index)
   }
   else if ( callback_msg == DM_OK || callback_msg == DM_DOUBLE_CLICK )
   {
      # get the response from the list box and store in temporary spot
      # so we can clean it up if we have to
      new_response = query_dialog_item(callback_dialog_handle, IDL_LIST, DAC_SELECT_ITEM )
      
      return DRC_EXIT
   }
   else if ( ( callback_msg == DM_CLICK && callback_index == DI_CANCEL ) \
            || callback_msg == DM_CANCEL)
   {
      new_response = ""
      return DRC_EXIT
   }
   else if ( callback_msg == DM_RESIZE )
   {
      # new size is stored in a long as (short width)(short height)
      new_width  = callback_data / 65536
      new_height = callback_data % 65536
      
      if ( new_width && new_height )
      {
         # resize list box to match new dialog size
         set_dialog_item(callback_dialog_handle, IDL_LIST, DAC_SIZE,
                         new_width - 40, new_height - 120 )

         # Move the buttons for Windows.
         if (isWindows())
         {
            set_dialog_item(callback_dialog_handle, DI_OK, DAC_POSITION,
                            button_pos[DI_OK] / 65536,
                            button_pos[DI_OK] % 65536)
   
            set_dialog_item(callback_dialog_handle, DI_CANCEL, DAC_POSITION,
                            button_pos[DI_CANCEL] / 65536,
                            button_pos[DI_CANCEL] % 65536)
         }
      }
      return DRC_MSG_PROCESSED
   }
   return DRC_CONTINUE
}              

local button_pos[]
local function save_button_positions(handle)
{
   if (isWindows())
   {
      button_pos[DI_OK]     = query_dialog_item( handle, DI_OK,     DAC_POSITION)
      button_pos[DI_CANCEL] = query_dialog_item( handle, DI_CANCEL, DAC_POSITION)
   }
}

