corz.org text viewer..
[currently viewing: /public/machine/source/windows/ffe.au3 - raw]
global $my_version = "2.0.0.0"

#cs

    ffe - an ffmpeg front-end, from corz.org.

    http://www.google.com/search?q=ffmpeg


        *** BEFORE COMPILING ***

        Please see the compile options at the foot of this program. You may want
        to change the locations of the copied binaries, for starters.


About:

    ffe is a simple yet powerful Windows® front-end for ffmpeg, designed for
    rapid testing of its various multimedia conversion parameters, enabling you
    to save lots of slightly different versions of a file very, very quickly; in
    other words, "find the best settings".

    ffmpeg, by Fabrice Bellard, et al., is a quite incredible multimedia
    converter, capable of converting a vast number of input and output media
    formats, and depending on which binary you use, supports either a HUGE
    number of control parameters, or a REALLY HUGE number of control parameters.

    ffe uniquely uses MATOF technology to automatically update output filenames
    to match your encoding parameters; you can tweak-and-go without worrying
    about obliterating your previous tests.

    While converting, the console output from ffmpeg can be viewed live inside
    ffe, and when complete, the entire process log is available for
    viewing/searching.

    ffe supports batch operation, automatic concatenation, infinite and
    infinitely customizable presets and customizable parameter buttons, pre- and
    post-job shell commands, dynamic @tokens, Media Info Reporting, Windows
    Batch Script Output, floating drop-window, command-line control and a host
    of other handy features and functions.

    Enjoy!

    More info here:

        http://corz.org/windows/software/ffe/

To use:

    Drop ffe.exe next to ffmpeg.exe (the ffmpeg binary).

    Run ffe.exe

    That's it.

    See inside ffe.ini and the current itstory for LOTS of notes and tricks..

        http://corz.org/engine?section=beta/windows/ffe&source=version.nfo

        _IniReadSection


;bugs..

    No known bugs.


2do..

    All done!


2do maybe..


    *    Watch Mode        (use Windows API directly for this)

        >> Automatically encode to current preset ("go") all files dropped in X folder.

        Add done files to a $known_files array and/or moving originals when done
        moving is better or else clear array after X days, to prevent long-term
        memory issues for instances running for months, processing millions of files


done, 2document..

        Aaargh.. Everything!

notes..

    The program architecture; to use the term loosely; is fairly linear.
    As these things (GUIs) go, one or two functions becomes three, and
    so on. On the bright side, it should be pretty clear how to hack in
    new stuff.

    if you are compiling this yourself, you need to use "AutoIt Wrapper"
    to add the extra icons. You will also need to use AT LEAST version
    1.9.3 of AutoIt Wrapper for the paths to work correctly. You can
    download it here..

        http://www.autoitscript.com/autoit3/scite/downloads.shtml

    version info here..

    http://corz.org/machine/source/beta/windows/ffe/version.nfo

#ce


#include <String.au3>
#include <GuiEdit.au3>
#include <Constants.au3>
#include <GuiConstants.au3>
#include <WindowsConstants.au3>
#include <ComboConstants.au3>
#include <GuiButton.au3>
#include <Date.au3>
#include <Misc.au3>
#include <WinAPIFiles.au3>
#include <InetConstants.au3>
#include <GuiDateTimePicker.au3>
#include <GuiToolTip.au3>
#include <gdiplus.au3>

; Fun with animated GIF drop windows..
;
; Of course this is sheer madness, a moving drop target!! lol
;
; BUT, if you want a dancing girl or throbbing arrow or whatever, on your
; desktop go right ahead. Enjoy your insanity!
;
; Of course you will need trancexx's lovely GIFAnimation.au3 script available.
; It will be around the site/distro somewhere.
;
#include "GIFAnimation.au3"
global $hGIF
global $enable_animated_gif = true
; this gets set on image load, to use GIF routines for gifs..
global $gif_method = false
;
; While this started out as a bit of fun, I have since discovered a few animated
; gifs that work really well, with gentle visual indicators. I've spruced up the
; gif code a bit, too. I'll probably leave it in for the release.


; we put these functions directly into ffe.au3 now (it's easier for everyone).
;#include "Include/corz_essentials.au3" ; forked years ago. see foot of this file

global const $LOG_LF                = @CRLF    ; for logs/saved text files
global const $MSG_LF                = @LF    ; for dialog boxes

; These make great AutoIt booleans for sooooooo many reasons..
global const $ON                    = $GUI_CHECKED            ; 1
global const $OFF                    = $GUI_UNCHECKED        ; 4
global const $UNSET                    = $GUI_INDETERMINATE    ; 2

global const $MF_BYPOSITION            = 0x00000400
global const $MF_SEPARATOR            = 0x00000800
global const $MF_CHECKED            = 0x00000008
Global Const $MF_UNCHECKED            = 0x0
global const $MF_POPUP                = 0x00000010

global const $exit_preset            = "FFE-EXIT-SETTINGS"


; depending on your version of AutoIt, you might need to un/comment this next line..
;const $WM_SYSCOMMAND            = 0x0112

AutoItSetOption("GUIOnEventMode", 1)
AutoItSetOption("TrayMenuMode", 11)
AutoItSetOption("TrayOnEventMode", 1)
AutoItSetOption("GUICoordMode", 1) ; NEVER AGAIN!!!    (getting there now, see MakeGUI())
AutoItSetOption("GUIEventOptions", 1)


; init vars..
global $me_app$my_name = "ffe"
global $my_title = " ffe.. ffmpeg front-end"
global $ini_path = $my_name & ".ini"
global $abort_batch = false
global $got_helps = ""
global $ffmpeg = 0; the ffmpeg proccess
global $my_domain = "corz.org"
global $my_url = "http://" & $my_domain & "/windows/software/ffe/"
global $versioncheck_url = "http://" & $my_domain & "/inc/versions.php?app=ffe"
global $download_url = "http://" & $my_domain & "/windows/software/ffe/#section-Download"

global const $NAME_BUTTONS = "custom buttons"
global const $NAME_SETTINGS = "main settings"
global const $NAME_PRESETS = "presets"


; this may get switched on..
global $do_debug = $OFF
;if $do_debug = $ON then debug("foo =>" & $foo & "<=" , @ScriptLineNumber);debug
;if $do_debug = $ON then PrintArray($array,  "$array", 0, @ScriptLineNumber);debug

; enables you to see icons and such without compiling.
; alter the second $me_app to match the place where you keep ffe.exe..
if @Compiled then
    $me_app = @ScriptFullPath
    $do_debug = $OFF
else
    $do_debug = $ON
    ; enter the path to your own local binary..
    $me_app = "C:\Program Files\corz\ffe\ffe.exe"
endif

global $data_parent = @AppDataDir & "\corz\" & $my_name

; memory is cheap! ;)
global $inputfile$old_inputfile$extra_args$v_codec$a_codec$resize_preset$args$msgs$count_ints
global $installed_ini$matof_string$old_matof$no_video$no_audio$launch_preset$user_inputfile$user_outputfile
global $find_count = 0, $switches$go$do_gen=false, $do_quit=false, $do_shutdown=false, $log_string$am_custom_buttons_disable
global $arTransItems[10], $arCPUItems[6], $ReportTypesMenuItems[7], $DropCommandMenuItems[3], $CustomButtonMenuItems[502]
global $tray_abort_batch$tray_toggle_drop_window$tray_toggle_start_minimized$tray_toggle_delayed_start$tray_toggle_fluid_image_menu$tray_toggle_auto_copy_images$tray_choose_image_folder
global $ctxt_toggle_fluid_image_menu$ctxt_toggle_auto_copy_images$ctxt_choose_image_folder$tray_toggle_retain_recent_files

global $ffeGUI$GUI_DropWindow$GUI_DropWindowResizer$output_dir$inp_inputfile$lab_inputfile$inp_outputfile$ini_outputfile
global $inp_input_params$combo_presets$butt_add_file_arg_to_input_params$check_do_drop_window$check_do_matof
global $radio_preset_replace$check_store_filepaths$combo_v_codec$combo_v_bitrate$combo_frames_per_second
global $inp_crop_top$inp_crop_right$inp_crop_bottom$inp_crop_left$inp_x_size$inp_y_size$check_concatenate
global $check_run_pre_job_commands$check_run_post_job_commands$check_overwrite
global $combo_preset_resizes$check_resize_first$combo_a_codec$combo_a_bitrate$combo_target_type
global $inp_extra_args$butt_quicktest$butt_mediareport$lab_help_info$edit_in_args$edit_console_output
global $butt_find$butt_copy2clip$butt_clearout$butt_doit$label_abort$previous_pos$do_countdown_timer
global $am_always_on_top$am_console_wordwrap$am_trans$am_reptypes$am_image_buttons$am_do_tooltips$am_sort_presets_list$am_cpu$am_drop_command
global $am_retain_exit_settings$am_use_mediainfo$am_log_each_job$am_log_append$am_job_log_append
global $check_quit_when_done$check_shutdown_when_done$am_about$clean_outputfile_ext$outputfile
global $am_custom_buttons_columns$custom_buttons_array$custom_buttons[502] ;arbitary number - will change
global $paused$generate_script = false, $shifted = false, $timeout=false, $portable = false, $delay_start_at = false
global $current_preset = $my_name$title_msg_string

global $dropwin_visible$dropwin_trans_real$lab_main_drop$image_handle$half_trans$drop_win_state
global $hover$hovering$switching$blocking
global $monitors_list[1][5]
$monitors_list[0][0] = 0


global $img_index = 1
global $drop_images[1][3] ; trayID and item text


global $made_files[1]
global $recent_files[1]

global $min_width = 875
global $min_height = 442
global $height_magic = 24 ; Magic!
global $maximized = $OFF$minimized = $OFF
global $start_minimized

global $nTPChecked = 0
global $nCPUChecked = 0
global $DropCommands[3] = ["None""Go""Report"]
global $ReportTypes[7] = ["default""compact""csv""flat""ini""json""xml"]
global $arCPU[6] = ["Idle/Low""Below Normal""Normal""Above Normal""High""Realtime (Use with caution!)"]

"known" files we have probed already..
global $oMyError = ObjEvent("AutoIt.Error""AAError"; Initialize a COM error handler
global $known_files
; Associative arrays in AutoIt? Hells yeah!
AAInit($known_files)

global $concat_list = @TempDir & "\ffe-concat-list.txt"

global $grid_x = 465
global $grid_y = 145
global $buttons_y_shunt$button_spacing

; ToolTips..
global $tip_icon$tip_icon_index$tip_style


; ini prefs..
global $presets$x$y$width$height$video_codecs$audio_codecs$file_types$video_bitrates$audio_bitrates$frames_per_second$target_types
global $preset_resizes$always_on_top$user_trans$console_wordwrap$log_location$job_log_location$log_append$job_log_append$replace_mode$store_filepaths
global $image_buttons$magic_butt_icon_index$dropwin_butt_icon_index$folder_icon_index$time_icon_index ; ; should not change, but /could/, so they're up here.

global $matof_separator$log_each_job$cpu_priority$short_test_frames$fallback_folder$console_output_font
global $console_output_font_size$custom_buttons_columns$custom_buttons_font_size$CBMChecked$custom_buttons_width$custom_buttons_height$do_output$do_tooltips$tooltip_time$drop_command
global $retain_exit_settings$sort_presets_list$ffmpeg_binary$plugins_path$help_texts$help_butts$not_presets$retain_recent_files
global $GDI_dll$allowed_image_types$do_drop_window$drop_win_image$drop_win_transparency$drop_win_image_folder$fluid_image_menu$auto_copy_images
global $pre_job_commands_file$post_job_commands_file$batch_commands_timeout$run_commands_with_shell$post_file_command$check_run_post_file_command$run_as_dos

; ffprobe/mediainfo reporting..
global $ffprobe_loc$report_format$report_directory$report_extension$report_switches$nRTChecked$store_probe_type$un_escape_output
global $use_mediainfo$mediainfo_location$mediainfo_switches$nDCChecked

; preset-level ffe settings..

; if we set "defaults" here, we can use GetPrefs() to reload at any time using existing values as fall-backs
global $resize_first = $OFF
global $do_matof = $ON

; ffe job buttons.
global $run_pre_job_commands = $UNSET
global $run_post_job_commands = $UNSET
global $run_post_file_command = $UNSET
global $overwrite = $UNSET
global $concatenate = $UNSET
global $quit_when_done = $UNSET
global $shutdown_when_done = $UNSET

; read-only settings..
global $default_extension = "mkv"
global $kill_ffmpeg_on_exit = $ON

Global Const $iMargin = 4
; Set max and min Resize_GUI sizes



; command-line parameters..

$CmdLineRaw = StringStripWS($CmdLineRaw, 3)

if $CmdLine[0] then

    for $i = 1 to $CmdLine[0]
        $CmdLine[$i] = StringStripWS($CmdLine[$i], 3)
    next

    ; file path supplied..
    if StringRight($CmdLineRaw, 1) <> ")" then
        $inputfile = StringStripWS($CmdLine[$CmdLine[0]], 3)
        for $i = 1 to $CmdLine[0]
            if StringStripWS($CmdLine[$i], 3) <> $inputfile then $switches &= " " & StringStripWS($CmdLine[$i], 3)
        next
    else
        $inputfile = ""
        for $i = 1 to $CmdLine[0]
            $switches &= " " & StringStripWS($CmdLine[$i], 3)
        next
    endif
endif

ConsoleWrite(".\" & @ScriptName & "(" & @ScriptLineNumber & "): ==> " & "cli switches: " & $switches & $LOG_LF)
ConsoleWrite(".\" & @ScriptName & "(" & @ScriptLineNumber & "): ==> " & "specified inputfile: " & $inputfile & $LOG_LF)



; process special switches..
$go = true means we run the job immediately

if $switches then
    $switches = StringStripWS($switches, 3)
    if StringLeft($switches, 2) = "go" then
        $launch_preset = StringTrimRight(StringMid($switches, 4, -1), 1)
        $go = true
    elseif StringLeft($switches, 8) = "generate" then
        $launch_preset =  StringTrimRight(StringMid($switches, 10, -1), 1)
        $go = true
        $do_gen = true
        $do_quit = true
    elseif StringLeft($switches, 4) = "load" then
        $launch_preset =  StringTrimRight(StringMid($switches, 6, -1), 1)
        $go = false
    elseif StringLeft($switches, 3) = "run" then
        $launch_preset = StringTrimRight(StringMid($switches, 5, -1), 1)
        $go = true
        $do_quit = true
    elseif StringLeft($switches, 8) = "shutdown" then
        $launch_preset = StringTrimRight(StringMid($switches, 10, -1), 1)
        $go = true
        $do_shutdown = true
    endif
endif

ConsoleWrite(".\" & @ScriptName & "(" & @ScriptLineNumber & "): ==> " & "launch preset: " & $launch_preset & $LOG_LF)


; one-time special portable install switch..
if $inputfile = "portable" then
    $installed_ini = FileInstall(".\stuff\ffe.ini", @ScriptDir & "\" & $ini_path; no overwrite flag, so will fail if ffe.ini already exists.
    $inputfile = ""
endif

; portable mode..
if FileExists($ini_path) then
    $portable = true
    $data_parent = @ScriptDir
    $ini_path = $data_parent & "\" & $ini_path
else
    ; regular AppData usage..
    if not FileExists($data_parent) then DirCreate($data_parent)
    $ini_path = $data_parent & "\" & $ini_path
    $installed_ini = FileInstall(".\stuff\ffe.ini"$ini_path)
endif

; update ini to latest version..
if not $installed_ini then UpdateIniFile()

; STILL NO INI FILE!
if not FileExists($ini_path) then
    ConsoleWrite(".\" & @ScriptName & "(" & @ScriptLineNumber & "): problem with ini ==> " & $ini_path & $LOG_LF)
    MsgBox(0, "No ffe.ini found!""ffe.ini was not found and cound not be created." & $MSG_LF & "ffe will now exit... ", 10)
    exit -99
endif







; we grab /one/ pref here..
global $allow_multiple = IniReadCheckBoxValue($ini_path$my_name"allow_multiple"$OFF)

; if already running and multiple instances disallowed, pass the inputfile path to the already running instance..
if $allow_multiple = $OFF then
    ce_Singleton($my_name, 1)
    if @error = 183 then
        WinActivate($my_title)
        if $inputfile then ControlSetText($my_title"""[CLASS:Edit; INSTANCE:1]"$inputfile, 1)
        exit 5
    endif
endif






; OK!

GetPrefs()
MakeTray()
SetHotKeys()
MakeGUI()
SetOnTop()
MakeAppMenu()


; load either the default settings [ffe] or some specified preset..
LoadPreset($launch_preset, true) ; 2nd param set here only, for "INIT".


; Do it now?
if $launch_preset and $go and $inputfile then
    DoIt()
else
    if $retain_exit_settings = $ON and InArray($presets$exit_preset) and not ce_IsPressed(10) then
        LoadPreset($exit_preset, true)
        IniDelete($ini_path$exit_preset)
        ConsoleAdd("previous settings restored")
    endif
endif


; idle loop..

global $now_time$on_top_counter

while true

    if $delay_start_at then DoIt()

    CheckMouse()

    ; this is set if mouse is hovering over one of our controls..
    $hover = @extended

    ; mouseover transparency change..
    if $dropwin_visible then

        $now_time = TimerDiff ($on_top_counter)
        if Mod($now_time, 10000) < 100 then SetDropWinOnTop() ; every 10s or so

        ; mouse-over Drop Window - provide feedback..
        if $hover and not $hovering then

            if $gif_method then
                _WinAPI_SetLayeredWindowAttributes($GUI_DropWindow, 0x345, $half_trans)
            else
                SetTransparentBitmap($GUI_DropWindow$image_handle$half_trans)
            endif

            ; this flag indicates the mouse is inside the DropWindow
            ; if we didn't set & check for this, we'd be updating the transparency every 1/100th second.
            ; Using the two varables we get two states: switch-in & switch-out
            $hovering = true

        ; mouse leaves Drop Window..
        elseif $hovering and not $hover then

            if $gif_method then
                _WinAPI_SetLayeredWindowAttributes($GUI_DropWindow, 0x345, $dropwin_trans_real)
            else
                SetTransparentBitmap($GUI_DropWindow$image_handle$dropwin_trans_real)
            endif
            $hovering = false

        endif
    endif

    ; Close the Drop Window any time (with HideDropWindow()) and THIS opens it again, so long as $do_drop_window = $ON
    if $do_drop_window = $ON and not $dropwin_visible then ShowDropWindow()
    Sleep(100)

wend




; fin!





; okay, here goes.
; run the job..

func DoIt()

    ConsoleWrite(".\" & @ScriptName & "(" & @ScriptLineNumber & "): ==> " & "DoIt() processing: inputfile / outputfile: " & $inputfile & " / " & $outputfile & $LOG_LF)

    if ce_IsPressed(10) or $do_gen then $generate_script = true

    if $inputfile = "" then
        if not BrowseForInputFile() then return
        DoIt()
        return
    endif

    if not $outputfile and not IsWild($inputfile) and $do_output = $ON then
        if not BrowseForOutputFile() then return
        DoIt()
        return
    endif

    $user_inputfile = $inputfile
    $user_outputfile = $outputfile

    UnSetHotKeys()
    ClearOutput()
    DisableActiveInputs()
    HideOutputButts()

    ; store this so we can show the dropwin again at the end, if enabled..
    $drop_win_state = $do_drop_window

    if $dropwin_visible then CloseDropWindow()


    ; Delayed Start + Countdown Timer..
    if $delay_start_at then

        ConsoleAdd("delayed start activated")
        local $d_diff$h_diff$m_diff$t_str$pl$ad$tdiff
        local $diff = _DateDiff("s", _NowCalc(), $delay_start_at)

        while $diff > 0

            ; all this for a countdown timer!
            if $do_countdown_timer = $ON then

                $t_str = ""

                ; Days..
                $d_diff = _DateDiff("D", _NowCalc(), $delay_start_at)
                $pl = ""
                if $d_diff > 1 then $pl = "s"
                if $d_diff then $t_str = $d_diff & " day" & $pl

                ; Hours..
                $h_diff = _DateDiff("h", _NowCalc(), $delay_start_at)
                $pl = ""
                $ad = ""
                $tdiff = $h_diff-($d_diff*24)
                if $tdiff > 1 then $pl = "s"
                if $t_str then $ad = ", "
                if $tdiff then $t_str &= $ad & $tdiff & " hour" & $pl
                $tdiff = ""

                ; Minutes..
                $m_diff = _DateDiff("n", _NowCalc(), $delay_start_at)
                $pl = ""
                $ad = ""
                $tdiff = $m_diff-($h_diff*60)
                if $tdiff > 1 then $pl = "s"
                if $t_str then $ad = ", "
                if $tdiff then $t_str &= $ad & $tdiff & " minute" & $pl
                $tdiff = ""

                ; Seconds..
                $diff = _DateDiff("s", _NowCalc(), $delay_start_at)
                $tdiff = $diff-($m_diff*60)
                $pl = ""
                if $tdiff > 1 then $pl = "s"
                if $tdiff then
                    if $t_str then $t_str &= " and "
                    $t_str &= $tdiff & " second" & $pl
                endif

                WinSetTitle($ffeGUI""$my_title & " delayed start in " & $t_str)
            endif

            if not $delay_start_at then return ReturnNow("delayed start aborted", -7)
            Sleep(1000)
        wend
        WinSetTitle($ffeGUI""$my_title)
    endif


    local $job_log$msg$generated$run_command
    if FileExists($concat_list) then FileDelete($concat_list)



    ; Pre-Job Commands..

    if $run_pre_job_commands = $ON then
        LoadPreCommands() ;always nice to grab this fresh, in case of recent edits..
        RunCommandsFile($pre_job_commands_file$job_log$generated"Pre")
        Sleep(1000)
    endif



    $run_files is always an array.. for single files, we create an array with a single element..
    local $run_files[2] = [1, $inputfile]


    ; BATCH RUN..

    if IsWild($inputfile) then ; it's a batch, e.g. "I:\Rip\ffe\*.mkv"

        local $run_parent = GetParent($inputfile)    "I:\Rip\ffe"
        local $inputfile_extension = GetExtension($inputfile)    ;    "mkv"
        local $full_filename = ""

        ; user entered wildcards: send the entire filename with wildcards to ReadDir()
        if IsWild(Basename($inputfile)) then $full_filename = Basename($inputfile)

        ; gather names of all matching files in the directory..
        if StringInStr($inputfile"://") then ; ftp/http
            return ReturnNow("error: cannot process wilcards in URLS.", -3)
        else
            $run_files = ReadDir($run_parent$inputfile_extension$full_filename)
        endif

        if IsArray($run_files) and $run_files[0] > 0 then
            ; enable "Abort Batch" menu option.
            ; put back base path..
            for $ra = 1 to $run_files[0]
                local $this_fn = $run_parent & "\" & $run_files[$ra]
                if IsDir($this_fn) then
                    $run_files[$ra] = ""
                else
                    $run_files[$ra] = $this_fn
                endif
            next
        else
            return ReturnNow($LOG_LF & "error creating batch. sorry.", -1)
        endif
    endif

    local $batch = $OFF
    $abort_batch = false
    if $run_files[0] > 1 then
        $batch = $ON
        TrayItemSetState($tray_abort_batch$TRAY_ENABLE)
    endif

    ; reset "made files" for this job..
    redim $made_files[1]


    for $runs = 1 to $run_files[0]

        if not $run_files[$runs] then continueloop ; in case of empties from bad dir items

        $inputfile = $run_files[$runs]
        DoArgsCreate($batch; the only place this is set - right inside a batch.. we call the function directly, too.

        if $inputfile = $outputfile then
            if $go then
                ; this should never happen, but just in case..
                $outputfile = RemoveExtension($outputfile) & MakeRandomAlphaNumericString(8) & "." & GetExtension($outputfile)
            else
                MsgBox(0, "file name clash!""You will need to choose a different output filename.. ", 0, $ffeGUI)
                if (BrowseForOutputFile() = 0) then
                    return ReturnNow($LOG_LF & "error starting job: file name clash.", -2)
                endif
                DoIt()
                return
            endif
        endif

        ; Already made this file - add random suffix to file name..
        if InArray($made_files$outputfile) then
            local $old_of = $outputfile
            $outputfile = RemoveExtension($outputfile) & MakeRandomAlphaNumericString(8) & "." & GetExtension($outputfile)
            ; update args with new file name..
            $args = StringReplace($args$old_of$outputfile)
        endif


        $outputfile is now SET!


        if $concatenate = $ON and $batch = $ON then
            FileWriteLine($concat_list"file '" & $outputfile & "'")
        endif

        GUICtrlSetState($label_abort$GUI_SHOW)

        $title_msg_string = $my_title & " [press 'F4' to abort]"
        if IsWild(GUICtrlRead($inp_inputfile)) then $title_msg_string = $my_title & " [press pause/break to abort batch]"
        WinSetTitle($ffeGUI""$title_msg_string)


        ; we will need to pass the !q" to ffmpeg manually..
        HotKeySet("
{F4}", "HK_FFmpegAbort")
        ; this also aborts a regular job..
        HotKeySet("
{PAUSE}", "HK_RunningAbortBatch")
        HotKeySet("
{SCROLLLOCK}", "HK_ProcessPauseSuspend")



        ; RUN the amazing ffmpeg..

        $paused = false
        $msg = $LOG_LF & "
starting ffe job on " & @YEAR & "-" & @MON & "-" & @MDAY & " @ " & @hour & ":" & @min & ":" & @sec & "." & @msec & $LOG_LF & "command-line: " & $args & $LOG_LF & $LOG_LF
        DoLog($msg)
        $job_log &= $msg

        ; This is REQUIRED to get plugins to work..
        EnvSet("
FREI0R_PATH", $plugins_path)


        ; Windows batch script output..
        if $generate_script then

            $generated &= $args & $LOG_LF

        else

            ConsoleWrite("
.\" & @ScriptName & "(" & @ScriptLineNumber & "): ==> " & "Run() ffmpeg with args: " & $args & $LOG_LF)
            $ffmpeg = Run($args, @ScriptDir, @SW_HIDE, BitOr($STDERR_CHILD$STDIN_CHILD))

            ProcessSetPriority($ffmpeg$cpu_priority)
            local $timestamp = TimerInit()
            local $console_out

            while true

                Sleep(25)

                ; Capture Output..
                $console_out = StderrRead($ffmpeg)

                if @error then exitloop
                if $abort_batch then
                    StdinWrite($ffmpeg, "
q")
                    Sleep(250)
                    ProcessClose($ffmpeg)
                    exitloop 2
                endif
                if not @extended then continueloop

                if StringInStr($console_out, "
already exists. Overwrite ? [y/N]") then
                    WinActivate($ffeGUI)
                    WinSetTitle($ffeGUI, "
", $my_title & "  [Overwrite existing file? (hit 'y' or 'n')]")
                    HotKeySet("
y", "HK_FFmpegResponseYes")
                    HotKeySet("
n", "HK_FFmpegResponseNo")
                endif

                $console_out = StringStripWS($console_out, 3)
                $job_log &= DoLog(SetConsoleOutput($console_out)) & $LOG_LF ; only $job_log gets the extra $LOG_LF

            wend
            StdioClose($ffmpeg)

            $msg = $LOG_LF & "
Completed in " & SecondsToDHMS(TimerDiff($timestamp)/1000) & "    (" & Round(TimerDiff($timestamp) / 1000, 2) & " seconds)"  & $LOG_LF & _
                    "
--------------------------------------------------------------------------------" & $LOG_LF & $LOG_LF & $LOG_LF
            DoLog($msg)
            $job_log &= $msg
                $job_log &= DoLog(SetConsoleOutput($console_out)) & $LOG_LF ; only $job_log gets the extra $LOG_LF
        endif


        ; We keep a tally of all files created during the job.
        ; if ffmpeg wants to output some file with the same name, we will add a random suffix to the name.
        ; This is designed to catch a situation where the user has used a *.* wildcard and there are associated
        ; files in the same dir as the videos, e.g. "movie.srt". The user sets up a batch job and wakes the
        ; next morning to find 10 *tiny* movie files which won't play. Nope, it's never happened to me. Seriously.
        if FileExists($outputfile) then

            ArrayAdd($made_files$outputfile)

            ; add file to recent files and re-build the tray..
            ArrayAdd($recent_files$outputfile, true, true)

            ; we also use this data to create a "Recent Files" list in the Tray menu..
            MakeTray()


            ; Run the Post-File Command..    (you almost could do this in one line, but where's the fun in that?)
            ; Also, tricks like > redirection would be out.

            if $run_post_file_command = $ON then

                $timeout = false
                if $batch_commands_timeout then AdLibRegister("
RunCommandsTimeout", $batch_commands_timeout*1000*60)

                $run_command = DeTokenize(String($post_file_command))
                local $pipe_to=false, $pipe_data="
"

                ; recognise user redirection in post-fiele command..
                if StringInStr($run_command, "
>") then
                    local $run_arr = StringSplit($run_command, "
>")
                    if IsArray($run_arr) and $run_arr[0] = 2 then
                        $run_command = $run_arr[1]
                        $pipe_to = StringStripWS(StringReplace($run_arr[2], '"
', ""), 3)
                        $job_log &= DoLog(ConsoleAdd("detected '>' redirection in command. outputting STDIO to file: " & $pipe_to)) & $LOG_LF
                    endif
                endif

                $msg = "running post-file command: " & $run_command
                $job_log &= DoLog(ConsoleAdd($msg)) & $LOG_LF
                local $err
                local $command_run = Run($run_command"", @SW_HIDE, $STDOUT_CHILD)

                while true
                    $err = false
                    $console_out = StdOutRead($command_run)
                    $err = @error
                    $console_out = StringStripWS($console_out, 3)
                    if $console_out then
                        if $pipe_to then $pipe_data &= $console_out
                        $job_log &= DoLog(ConsoleAdd($console_out)) & $LOG_LF
                    endif
                    if $err or $timeout then exitloop
                    Sleep(25)
                wend
                StdioClose($command_run)
                ; write out user ">" redirection..
                if $pipe_to then FileWrite($pipe_to$pipe_data)
                AdLibUnRegister("RunCommandsTimeout")
            endif

        endif

    next



    ; ConCATenate Output files..

    if $concatenate = $ON and $batch = $ON then

        local $write_loc = $ffmpeg_binary
        local $write_cat = $concat_list
        if $generate_script then
            $write_loc = '"' & $ffmpeg_binary & '"'
            $write_cat = "ffe-concat-list.txt"
        endif

        local $ow_args
        if $overwrite = $ON then $ow_args &= " -y "
        $run_command = $write_loc & " -f concat -i """ & $write_cat & """ " & $ow_args & "-c copy " & $output_dir & "\joined." & $clean_outputfile_ext

        if $generate_script then
            $generated &= $run_command & $LOG_LF
        else
            $msg = "Concatenating files.."
            $job_log &= DoLog(ConsoleAdd($msg)) & $LOG_LF
            $ffmpeg = Run($run_command, @ScriptDir, @SW_HIDE, BitOr($STDERR_CHILD$STDIN_CHILD$STDOUT_CHILD))    ; re-use process handle so ffmpeg hotkeys still work in concat job
            while true
                Sleep(25)
                $err = false
                $console_out = StderrRead($ffmpeg)
                $err = @error
                if not @extended then continueloop
                if $abort_batch then
                    Sleep(250)
                    exitloop
                endif
                $console_out = StringStripWS($console_out, 3)
                $job_log &= DoLog(SetConsoleOutput($console_out)) & $LOG_LF
                if $err then exitloop
            wend
            StdioClose($ffmpeg)
        endif

    endif



    ; Post-Job Commands..

    if $run_post_job_commands = $ON then
        LoadPostCommands()
        RunCommandsFile($post_job_commands_file$job_log$generated"Post")
        Sleep(1000)
    endif



    DoLog("out"$log_append$LOG_LF & $LOG_LF)

    TrayItemSetState($tray_abort_batch$TRAY_DISABLE)

    HotKeySet("{PAUSE}")
    HotKeySet("{SCROLLLOCK}")
    HotKeySet("{F4}")
    HotKeySet("y")
    HotKeySet("n")

    WinSetTitle($ffeGUI""$my_title)
    GUICtrlSetState($label_abort$GUI_HIDE)

    SetConsoleOutput($job_log)
    ShowOutputButts()

    if $log_each_job = $ON and not $generate_script then SaveOutput($job_log)

    if $generate_script then

        local $save_bat

        if $do_gen then
            $save_bat = @WorkingDir & "\ffe.bat"
        else
            local $save_bat_dir = IniRead($ini_path$my_name"save_bat_dir", @MyDocumentsDir)
            DialogOpen()
            $save_bat = FileSaveDialog("Save/Append Batch Script"$save_bat_dir"All (*.*)|Batch files (*.bat)|Command files (*.cmd)"$FD_PATHMUSTEXIST"ffe.bat"$ffeGUI)
            DialogClose()
            if FileExists(GetParent($save_bat)) then IniWrite($ini_path$my_name"save_bat_dir", GetParent($save_bat))
        endif

        if not @error then
            local $job_batch_file = FileOpen($save_bat$FO_APPEND+$FO_UTF8_NOBOM)
            FileWrite($job_batch_file$generated)
            FileClose($job_batch_file)
            ConsoleAdd($LOG_LF & "saved batch script to: " & $save_bat)
        endif

        FileMove($concat_list, GetParent($save_bat) & "\ffe-concat-list.txt"$FC_OVERWRITE)

    endif


    ; Shutdown PC..
    if $do_shutdown or $shutdown_when_done = $ON then
        local $shutdown_response
        if not $do_shutdown then

            DialogOpen()
            $shutdown_response = MsgBox(1, "ffe will now shutdown your computer..", _
                                                "As instructed, ffe will now shutdown your computer.  " & $MSG_LF & $MSG_LF & _
                                                "To abort the shutdown process, click [Cancel] within the next 60 seconds." & $MSG_LF & $MSG_LF & _
                                                "Click [OK] to shutdown immediately.", 60, $ffeGUI)
            DialogClose()
        else
            $shutdown_response = 1
        endif
        if $shutdown_response = 1 or $shutdown_response = -1 then
            Shutdown(BitOr($SD_SHUTDOWN$SD_POWERDOWN))
            DoQuit()
        endif

    ; QUIT..
    elseif $do_quit or $quit_when_done = $ON then

        local $quit_response
        if not $do_quit then
            DialogOpen()
            $quit_response = MsgBox(1, "ffe will now quit..", _
                                            "As instructed, ffe will now quit.  " & $MSG_LF & $MSG_LF & _
                                            "To abort, click [Cancel] within the next 10 seconds.", 10, $ffeGUI)
            DialogClose()
        else
            $quit_response = 1
        endif
        if $quit_response = 1 or $quit_response = -1 then
            DoQuit()
        endif
    endif

    $do_drop_window = $drop_win_state
    EnableActiveInputs()
    UpdateInput()
    SetHotKeys()
    GUICtrlSetState($edit_console_output$GUI_FOCUS)


    if $delay_start_at then
        TrayItemSetState($tray_toggle_delayed_start$OFF)
        $delay_start_at = false
        ConsoleAdd("Delayed Job Complete (like you can see this!)")
    endif

endfunc







; get ini values..

func GetPrefs($current_section=$my_name)    ; specify section (for later use)

    ; the available sections (presets+)
    $presets = IniReadSectionNames($ini_path)

    $x = Int(IniRead($ini_path$my_name"x", -1))
    $y = Int(IniRead($ini_path$my_name"y", -1))
    $width = Int(IniRead($ini_path$my_name"width", 935))
    if $width < $min_width then $width = $min_width
    $height = Int(IniRead($ini_path$my_name"height", 590))
    if $height < $min_height then $height = $min_height

    $minimized = IniReadCheckBoxValue($ini_path$my_name"minimized"$OFF)
    $maximized = IniReadCheckBoxValue($ini_path$my_name"maximized"$OFF)
    $start_minimized = IniReadCheckBoxValue($ini_path$my_name"start_minimized"$OFF)
    if $start_minimized = $ON then $minimized = $ON
    if $minimized = $ON and $maximized = $ON then $maximized = SwitchBool($maximized)

    $always_on_top = IniReadCheckBoxValue($ini_path$my_name"always_on_top"$OFF)

    $user_trans = IniRead($ini_path$my_name"transparency", 0)

    $do_output = IniReadCheckBoxValue($ini_path$my_name"do_output"$ON)

    ; Master ToolTips Switch..
    $do_tooltips = IniReadCheckBoxValue($ini_path$my_name"do_tooltips"$ON)
    $tooltip_time = IniRead($ini_path$my_name"tooltip_time", 10000)

    ; ToolTip Icon:
    local $tip_icon_res = IniRead($ini_path$my_name"tip_icon_res"$me_app)
    if not $tip_icon_res then $tip_icon_res = $me_app
    $tip_icon_index = IniRead($ini_path$my_name"tip_icon_index", 0)
    if not $tip_icon_index then $tip_icon_index = 0
    $tip_icon = $me_app & "," & $tip_icon_index

    ; System ToolTip Icon override..
    local $system_tip_icon = IniRead($ini_path$my_name"system_tip_icon""")
    if $system_tip_icon and $system_tip_icon >= 0 and $system_tip_icon < 7 then $tip_icon = $system_tip_icon

    ; ToolTip Style..
    $tip_style = IniRead($ini_path$my_name"tip_style", 1)


    $sort_presets_list = IniReadCheckBoxValue($ini_path$my_name"sort_presets_list"$ON)
    ; use images on (some) buttons?
    $image_buttons = IniReadCheckBoxValue($ini_path$my_name"image_buttons"$ON)

    $replace_mode = IniReadCheckBoxValue($ini_path$my_name"replace_mode"$ON)
    $store_filepaths = IniReadCheckBoxValue($ini_path$my_name"store_filepaths"$OFF, true) ; tristate - unset to grey control

    $console_wordwrap = IniReadCheckBoxValue($ini_path$my_name"console_wordwrap"$OFF)

    $drop_command = IniRead($ini_path$my_name"drop_command""")

    $retain_exit_settings = IniReadCheckBoxValue($ini_path$my_name"retain_exit_settings"$ON)

    $do_countdown_timer = IniReadCheckBoxValue($ini_path$my_name"do_countdown_timer"$ON)

    ; The nifty custom buttons..
    $custom_buttons_columns = IniRead($ini_path$my_name"custom_buttons_columns""auto")
    if $custom_buttons_columns = "auto" then
        $CBMChecked = 501
    else
        if $custom_buttons_columns and $custom_buttons_columns < 0 then $custom_buttons_columns = 0
        $CBMChecked = $custom_buttons_columns
    endif

    $custom_buttons_width = int(IniRead($ini_path$my_name"custom_buttons_width", 75))
    if $custom_buttons_width and ($custom_buttons_width < 8 or $custom_buttons_width > 150) then $custom_buttons_width = 75

    $custom_buttons_height = int(IniRead($ini_path$my_name"custom_buttons_height", 27))

    $buttons_y_shunt = int(IniRead($ini_path$my_name"buttons_y_shunt", 11))
    $button_spacing = int(IniRead($ini_path$my_name"button_spacing", 3))

    $custom_buttons_font_size = Round(IniRead($ini_path$my_name"custom_buttons_font_size", 9), 2)

    LoadCustomButtonData()

    ; Logging..
    $log_append = IniReadCheckBoxValue($ini_path$my_name"log_append"$OFF)
    $job_log_append = IniReadCheckBoxValue($ini_path$my_name"job_log_append"$OFF)
    $log_each_job = IniReadCheckBoxValue($ini_path$my_name"log_each_job"$ON)

    ; Log location..
    GetLogLocation()

    $job_log_location = DeTokenize(IniRead($ini_path$my_name"job_log_location""@datadir\logs"))

    ; ffmpeg binary location..
    $i = DeTokenize(IniRead($ini_path$my_name"ffmpeg_binary"""))
    if FileExists($i) then
        $ffmpeg_binary = $i
    else
        SetFFMpegBinaryLocation()
    endif

    ; ffprobe/mediainfo..
    GetReportingValues()


    ; ffprobe plugins..
    $plugins_path = DeTokenize(IniRead($ini_path$my_name"plugins_path"""))
    if (not $plugins_path) and FileExists($ffmpeg_binary) then
        $plugins_path = GetParent($ffmpeg_binary) & "\plugins"
        IniWrite($ini_path$my_name"plugins_path", TokenizeString($plugins_path))
    endif

    ; custom help..
    $help_texts = IniRead($ini_path$my_name"help_texts""Main|help.nfo|-h,Formats|help-formats.nfo|-formats,Filters|help-filters.nfo|-filters,Codecs|help-codecs.nfo|-codecs,Full|help-full.nfo|-h full")
    if StringInStr($help_texts"|") then
        $help_texts = StringSplit($help_texts",")
        global $help_butts[$help_texts[0]+1] = [$help_texts[0]]
    else
        $help_texts = ""
    endif

    $not_presets = IniRead($ini_path$my_name"not_presets"$my_name & "," & $NAME_BUTTONS & "," & $exit_preset)
    if not $not_presets then $not_presets = $my_name & "," & $NAME_BUTTONS & "," & $exit_preset
    $not_presets = StringSplit($not_presets",")


    ; button image indexes..
    $magic_butt_icon_index = IniRead($ini_path$my_name"magic_butt_icon_index", -6)
    $dropwin_butt_icon_index = IniRead($ini_path$my_name"dropwin_butt_icon_index", -13)
    $folder_icon_index = IniRead($ini_path$my_name"folder_icon_index", -5)
    $time_icon_index = IniRead($ini_path$my_name"time_icon_index", -11)



    $matof_separator = IniRead($ini_path$my_name"matof_separator"" ")
    ; cuz above " " don't work, for some reason :/ ..
    if $matof_separator = "" then $matof_separator = " "


    ; CPU priority..
    $cpu_priority = int(IniRead($ini_path$my_name"cpu_priority", 2))
    if $cpu_priority < 0 or $cpu_priority > 5 then $cpu_priority = 2
    $nCPUChecked = $cpu_priority


    $video_codecs = IniRead($ini_path$current_section"video_codecs""||copy|a64multi|a64multi5|alias_pix|amv|apng|asv1|asv2|avrp|avui|ayuv|bmp|libxavs|cinepak|cljr|libschroedinger|dnxhd|dpx|dvvideo|ffv1|ffvhuff|flashsv|flashsv2|flv|gif|h261|h263|h263p|libx264|libx264rgb|libx265|huffyuv|jpeg2000|libopenjpeg|jpegls|ljpeg|mjpeg|mpeg1video|mpeg2video|mpeg4|libxvid|msmpeg4v2|msmpeg4|msvideo1|pam|pbm|pcx|pgm|pgmyuv|png|ppm|prores|prores_aw|prores_ks|qtrle|r10k|r210|rawvideo|roqvideo|rv10|rv20|sgi|snow|sunrast|svq1|targa|libtheora|tiff|utvideo|v210|v308|v408|v410|libvpx|libvpx-vp9|libwebp|wmv1|wmv2|xbm|xface|xwd|y41p|yuv4|- disable video -")
    $audio_codecs = IniRead($ini_path$current_section"audio_codecs""||copy|aac|libvo_aacenc|ac3|ac3_fixed|adpcm_adx|g722|g726|adpcm_ima_qt|adpcm_ima_wav|adpcm_ms|adpcm_swf|adpcm_yamaha|alac|libopencore_amrnb|libvo_amrwbenc|comfortnoise|dca|eac3|flac|g723_1|libgsm|libgsm_ms|libilbc|mp2|mp2fixed|libtwolame|libmp3lame|nellymoser|libopus|pcm_alaw|pcm_f32be|pcm_f32le|pcm_f64be|pcm_f64le|pcm_mulaw|pcm_s16be|pcm_s16be_planar|pcm_s16le|pcm_s16le_planar|pcm_s24be|pcm_s24daud|pcm_s24le|pcm_s24le_planar|pcm_s32be|pcm_s32le|pcm_s32le_planar|pcm_s8|pcm_s8_planar|pcm_u16be|pcm_u16le|pcm_u24be|pcm_u24le|pcm_u32be|pcm_u32le|pcm_u8|real_144|roq_dpcm|s302m|sonic|sonicls|libspeex|tta|vorbis|libvorbis|wavpack|libwavpack|wmav1|wmav2|- disable audio -")
    $file_types = IniRead($ini_path$current_section"file_types""All (*.*)|Audio Files (*.mp3;*.wav;*.ogg;*.mp2;*.wma;*.asf;*.asx;*.ape;*.shn;*.mpc;*.flac;*.tta;*.m4a;*.aif;*.aac)|Movie files (*.avi;*.mpg;*.mpeg;*.mov;*.mkv;*.ogm;*.ogv;*.mp4;*.asf;*.wmv;*.rm;*.flv;*.vob;*.webm;*.rmvb;*.nsv;*.mpe;*.3gp)")


    $video_bitrates = IniRead($ini_path$current_section"video_bitrates""||360k|512k|640k|768k|1000k|1200k|1600k|1800k|2000k|4000k|8000K|16000K|32000K|64000K")
    $audio_bitrates = IniRead($ini_path$current_section"audio_bitrates""||32k|48k|56k|64k|80k|96k|112k|128k|160k|192k|256k|320k|480k")
    $frames_per_second = IniRead($ini_path$current_section"frames_per_second""||12|15|20|23.976|24|25|29.97|30|50|60")

    $target_types = IniRead($ini_path$current_section"target_types""||pal-vcd|dvd|ntsc-svcd|vcd|svcd|dv|dv50")
    $preset_resizes = IniRead($ini_path$current_section"preset_resizes""||sqcif|qcif|cif|4cif|qqvga|qvga|vga|svga|xga|uxga|qxga|sxga|qsxga|hsxga|wvga|wxga|wsxga|wuxga|woxga|wqsxga|wquxga|whsxga|whuxga|cga|ega|hd480|hd720|hd1080")

    $console_output_font = IniRead($ini_path$current_section"console_output_font""Lucida Console")
    $console_output_font_size = IniRead($ini_path$current_section"console_output_font_size", 9)

    $short_test_frames = IniRead($ini_path$current_section"short_test_frames", 1000)

    ; we will read this again, as-needed, as dynamic @tokens may change, also we can use this as a fall-back, in case no fallback_folder is specified insside the preset
    $fallback_folder = DeTokenize(IniRead($ini_path$current_section"fallback_folder""@parent"))


    ; preset-level settings..


    $resize_first = IniReadCheckBoxValue($ini_path$current_section"resize_first"$resize_first)
    $do_matof = IniReadCheckBoxValue($ini_path$current_section"do_matof"$do_matof)

    ; ffe job buttons..
    $run_pre_job_commands = IniReadCheckBoxValue($ini_path$current_section"run_pre_job_commands"$run_pre_job_commands, true)
    $run_post_job_commands = IniReadCheckBoxValue($ini_path$current_section"run_post_job_commands"$run_post_job_commands, true)

    $run_post_file_command = IniReadCheckBoxValue($ini_path$current_section"run_post_file_command"$run_post_file_command, true)

    $post_file_command = IniRead($ini_path$current_section"post_file_command""")

    $overwrite = IniReadCheckBoxValue($ini_path$current_section"overwrite"$overwrite, true)
    $concatenate = IniReadCheckBoxValue($ini_path$current_section"concatenate"$concatenate, true)
    $quit_when_done = IniReadCheckBoxValue($ini_path$current_section"quit_when_done"$quit_when_done, true)
    $shutdown_when_done = IniReadCheckBoxValue($ini_path$current_section"shutdown_when_done"$shutdown_when_done, true)


    ; read-only preset-level settings..
    $default_extension = IniRead($ini_path$current_section"default_extension"$default_extension)
    $kill_ffmpeg_on_exit = IniReadCheckBoxValue($ini_path$current_section"kill_ffmpeg_on_exit"$kill_ffmpeg_on_exit)

    ; funky drop target..
    $do_drop_window = IniReadCheckBoxValue($ini_path$my_name"do_drop_window"$ON)
    GetDropWinImage()
    GetDropWinImageFolder()

    $drop_win_transparency = IniRead($ini_path$current_section"drop_win_transparency", 0)
    GetRealTrans()

    $allowed_image_types = IniRead($ini_path$current_section"allowed_image_types""bmp,png,ico,emf,wmf")
    if $allowed_image_types = "*" then $allowed_image_types = "bmp,png,ico,emf,wmf,jpg,jpeg,gif,tif,tiff"
    $allowed_image_types = "," & $allowed_image_types & ","
    $fluid_image_menu = IniReadCheckBoxValue($ini_path$my_name"fluid_image_menu"$OFF)

    $auto_copy_images = IniReadCheckBoxValue($ini_path$my_name"auto_copy_images"$ON)

    $GDI_dll = IniRead($ini_path$my_name"GDI_dll""gdiplus.dll")

endfunc







; The main ffe GUI/Window..


func MakeGUI()

    ; handy measurements..
    local $tip$ttt$column_two = 590

    if ($width / 2) > $column_two then $column_two = ($width / 2)

    ; Biting the bullet..
    AutoItSetOption("GUICoordMode", 0)


    ; create the GUI..
    $ffeGUI = GUICreate($my_title$width$height$x$y, BitOr($WS_SIZEBOX$WS_MINIMIZEBOX$WS_MAXIMIZEBOX$WS_CAPTION$WS_POPUP), $WS_EX_ACCEPTFILES)
    GUISetIcon($me_app, 0)

    ; setup some GUI events..
    GUISetOnEvent($GUI_EVENT_CLOSE"User_DoQuit")
    GUISetOnEvent($GUI_EVENT_RESIZED"ResizeSaveXYPrefs")
    GUISetOnEvent($GUI_EVENT_MINIMIZE"ToggleWindow")
    GUISetOnEvent($GUI_EVENT_MAXIMIZE"ToggleMaximizeWindow")
    GUISetOnEvent($GUI_EVENT_RESTORE"ToggleMaximizeWindow")
    GUISetOnEvent($GUI_EVENT_PRIMARYUP"PrimaryUpCheckSize")
    GUISetOnEvent($GUI_EVENT_DROPPED"GetDroppedItem")


    ; Catch focus passing to $inp_outputfile
    GUIRegisterMsg($WM_COMMAND"CheckFocus")



    ; input file input..
    GUISetCoord(10, 12)

    $lab_inputfile = GUICtrlCreateLabel("input:", 0, 0, 36)
    $ttt = "Input File(s)"
    $tip = "Enter the full path to the input file (or just drag it in). "
    GUICtrlSetTipOptional(-1, $tip & $MSG_LF & "Click here to view the source file directory. "$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "OpenSourceDir")

    $inp_inputfile = GUICtrlCreateInput($inputfile, 40, 0, $width-110, 18)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetOnEvent(-1, "UpdateInput")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKRIGHT$GUI_DOCKSIZE))
    GUICtrlSetState(-1, $GUI_DROPACCEPTED)



    ; Drag-And-Drop Window Activation..
    if $image_buttons = $ON then
        $check_do_drop_window = GUICtrlCreateCheckbox(""$width-103, -1, 20, 20, BitOr($BS_AUTOCHECKBOX$BS_PUSHLIKE$BS_ICON))
        if @compiled then
            GUICtrlSetImage(-1,$me_app$dropwin_butt_icon_index, 0)
        else
            GUICtrlSetImage(-1, ".\icons\target.ico", -1, 0)
        endif
    else
        $check_do_drop_window = GUICtrlCreateCheckbox("ꙩ"$width-103, 0, 20, 20, BitOr($BS_AUTOCHECKBOX$BS_PUSHLIKE))
    endif
    GUICtrlSetTipOptional(-1, "Opens a shaped (with the right image), transparent window you can use to drop files into.     " & $MSG_LF & _
                              "It behaves just like your regular input file input, files are queued up or processed with your" & $MSG_LF & _
                              "current 'Drag-And-Drop Command'. Also use it to set the location of your ffmpeg binary.""Floating Drop Window      (F9)")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKRIGHT$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "ClickToggleDropWindow")
    GUICtrlSetState(-1, $do_drop_window)


    if $image_buttons = $ON then
        GUICtrlCreateButton("...", 24, 0, 20, 20, BitOr($WS_TABSTOP,$BS_FLAT,$BS_ICON))
        if @compiled then
            GUICtrlSetImage(-1,$me_app$folder_icon_index, 0)
        else
            GUICtrlSetImage(-1, ".\icons\document-outline.ico", -1, 0)
        endif
    else
        GUICtrlCreateButton("..."$width-79, 0, 20, 20, BitOr($WS_TABSTOP,$BS_FLAT))
    endif
    GUICtrlSetTipOptional(-1, "Browse to locate the input file."$ttt)
    GUICtrlSetOnEvent(-1, "BrowseForInputFile")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKRIGHT$GUI_DOCKSIZE))




    ; output file input!..
    GUISetCoord(10, 39)

    $ttt = "Output File(s)"

    GUICtrlCreateLabel("output: ", 0, 0, 36)
    $tip = "Enter the full path to the output file (or drag in a file or folder)."
    GUICtrlSetTipOptional(-1, $tip & $MSG_LF & _
                            "NOTE: you can click this label to disable output altogether," & $MSG_LF & _
                            "e.g. for creating image sequences (enter your output directly" & $MSG_LF & _
                            "into the extra agruments input)." & $MSG_LF & $MSG_LF & _
                            "NOTE; You Must Put The Output File(s) LAST"$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "ToggleOutput")



    ; the actual input area for file output *phew*..
    $inp_outputfile = GUICtrlCreateInput($outputfile, 40, 0, $width-110, 18)
    GUICtrlSetTipOptional(-1, $tip & $MSG_LF & "NOTE: As soon as you click inside here, MATOF is disabled. "$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKRIGHT$GUI_DOCKSIZE))
    GUICtrlSetState(-1, $GUI_DROPACCEPTED)



    ; magic auto-transforming output filename [MATOF!] ..
    if $image_buttons = $ON then
        $check_do_matof = GUICtrlCreateCheckbox(""$width-103, -1, 20, 20, BitOr($BS_AUTOCHECKBOX$BS_PUSHLIKE$BS_ICON))
        if @compiled then
            GUICtrlSetImage(-1,$me_app$magic_butt_icon_index, 0)
        else
            GUICtrlSetImage(-1, ".\icons\magic-wand.ico", -1, 0)
        endif
    else
        $check_do_matof = GUICtrlCreateCheckbox("!!!"$width-103, 0, 20, 20, BitOr($BS_AUTOCHECKBOX$BS_PUSHLIKE))
    endif
    GUICtrlSetTipOptional(-1, "Magic Auto-Transforming Output Filename   (MATOF!)      (Ctrl+M)" & $MSG_LF & $MSG_LF & _
                              "Check this to have the output file automatically transformed when " & $MSG_LF & _
                              "you change stuff below (handy for doing lots of quick tests). "$MSG_LF & $MSG_LF & _
                              "NOTE: When you are running a batch, you cannot disable this. ""MATOF!")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKRIGHT$GUI_DOCKSIZE))
    GUICtrlSetState(-1, $do_matof)
    GUICtrlSetOnEvent(-1, "ClickToggleMatofStatus")



    ; browse for output file..
    if $image_buttons = $ON then
        GUICtrlCreateButton("...", 24, 0, 20, 20, BitOr($WS_TABSTOP,$BS_FLAT,$BS_ICON))
            if @compiled then
            GUICtrlSetImage(-1,$me_app$folder_icon_index, 0)
        else
            GUICtrlSetImage(-1, ".\icons\document-outline.ico", -1, 0)
        endif
    else
        GUICtrlCreateButton("...", 24, 0, 20, 20, BitOr($WS_TABSTOP,$BS_FLAT))
    endif
    GUICtrlSetTipOptional(-1, "Browse to specify the output file. "$ttt)
    GUICtrlSetOnEvent(-1, "BrowseForOutputFile")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKRIGHT$GUI_DOCKSIZE))






    ; ffe job buttons..

    ; tip not seen for groups.. bummer :/ Hmm.. what if
    ; hey this is clever (even cleverer for combos - see below)
    GUISetCoord(10, 62)
    GUICtrlCreateLabel("", 0, 0, $column_two-18, 14, 0, 0)
;    GUICtrlSetBkColor(-1, $COLOR_RED)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetTipOptional(-1, "These options are always inherited, or not, from the chosen preset. They can be Enabled, Disabled, or Unset." & $MSG_LF & _
                                "Unless an option is specifically set (on/off) in a preset, the old setting will be in effect.""ffe job controls")
    GUISetCoord(10, 62)
    GUICtrlCreateGroup("ffe job.. ", 0, 0, $column_two-18, 35) ; tip not seen.. bummer :/
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))

    $ttt = "Pre-Job Commands"
    $check_run_pre_job_commands = GUICtrlCreateCheckbox(" pre-job-commands ", 6, 13, 105, 18, BitOr($BS_AUTO3STATE,$BS_RIGHTBUTTON))
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetTipOptional(-1, "Before the job runs, run your specified pre-job commands batch file? "$ttt)
    GUICtrlSetOnEvent(-1, "ClickSetPreJobCommands")
    GUICtrlSetState(-1, $run_pre_job_commands)

    local $menu_check_run_pre_job_commands = GUICtrlCreateContextMenu($check_run_pre_job_commands)
    GUICtrlCreateMenuItem("Specify New Pre-Job Commands File.."$menu_check_run_pre_job_commands)
    GUICtrlSetOnEvent(-1, "SpecifyPreJobCommandsFile")


    $ttt = "Post-File Commands"
    $check_run_post_file_command = GUICtrlCreateCheckbox(" post-file-command ", 112, 0, 110, 18, BitOr($BS_AUTO3STATE,$BS_RIGHTBUTTON))
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetTipOptional(-1, "After each file is processed, run your specified post-file command. " & $MSG_LF & "Right-click the control for edit options."$ttt)
    GUICtrlSetOnEvent(-1, "ClickSetPostFileCommand")
    GUICtrlSetState(-1, $run_post_file_command)

    local $menu_check_run_post_file_command = GUICtrlCreateContextMenu($check_run_post_file_command)
    GUICtrlCreateMenuItem("Edit The Post-File Command.."$menu_check_run_post_file_command)
    GUICtrlSetOnEvent(-1, "SpecifyPostFileCommand")



    $ttt = "Post-Job Commands"
    $check_run_post_job_commands = GUICtrlCreateCheckbox(" post-job-commands ", 117, 0, 110, 18, BitOr($BS_AUTO3STATE,$BS_RIGHTBUTTON))
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetTipOptional(-1, "After the job runs, run your specified post-job commands batch file? "$ttt)
    GUICtrlSetOnEvent(-1, "ClickSetPostJobCommands")
    GUICtrlSetState(-1, $run_post_job_commands)

    local $menu_check_run_post_job_commands = GUICtrlCreateContextMenu($check_run_post_job_commands)
    GUICtrlCreateMenuItem("Specify New Post-Job Commands File.."$menu_check_run_post_job_commands)
    GUICtrlSetOnEvent(-1, "SpecifyPostJobCommandsFile")



    $ttt = "Overwrite"
    $check_overwrite = GUICtrlCreateCheckbox(" overwrite ", 115, 0, 62, 20, BitOr($BS_AUTO3STATE,$BS_RIGHTBUTTON))
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetTipOptional(-1, "Should ffe tell ffmpeg to overwrite existing files? "$ttt)
    GUICtrlSetOnEvent(-1, "ClickSetOverwrite")
    GUICtrlSetState(-1, $overwrite)


    $check_concatenate = GUICtrlCreateCheckbox(" join ", 70, 0, 34, 20, BitOr($BS_AUTO3STATE,$BS_RIGHTBUTTON))
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetTipOptional(-1, "During batch operations, should ffe tell ffmpeg to join the output files together? "$ttt)
    GUICtrlSetOnEvent(-1, "ClickSetConcatenateFiles")
    GUICtrlSetState(-1, $concatenate)


    $ttt = "Quit When Done"
    $check_quit_when_done = GUICtrlCreateCheckbox(" quit ", 40, 0, 36, 20, BitOr($BS_AUTO3STATE,$BS_RIGHTBUTTON))
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetTipOptional(-1, "Should ffe quit when the job is complete? "$ttt)
    GUICtrlSetOnEvent(-1, "ClickSetQuitWhenDone")
    GUICtrlSetState(-1, $quit_when_done)


    $ttt = "Shutdown PC When Done"
    $check_shutdown_when_done = GUICtrlCreateCheckbox(" shutdown ", 40, 0, 64, 20, BitOr($BS_AUTO3STATE,$BS_RIGHTBUTTON))
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetTipOptional(-1, "Should ffe shutdown your computer when the job is complete? "$ttt)
    GUICtrlSetOnEvent(-1, "ClickSetShutdownWhenDone")
    GUICtrlSetState(-1, $shutdown_when_done)

    ShutDownOverrideQuit()




    ; input override parameter option things..

    GUISetCoord(10, 97)

    $ttt = "Input Parameter Override"
    GUICtrlCreateGroup("input parameter override.. ", 0, 0, $column_two-18, 39)
    GUICtrlSetResizing(-1, $GUI_DOCKALL)

    $tip =        "If you need to specify special parameters for the input file, do that here. " & $MSG_LF & _
                "This is the place where you would find an SRT file, for example." & $MSG_LF & $MSG_LF & _
                "NOTE: these parameters will usually override output parameters, forcing " & $MSG_LF & _
                "whatever you specify, here." & $MSG_LF & $MSG_LF & _
                "DON'T FORGET to put '-i' in front of, and ""quotes"" around any file " & $MSG_LF & _
                "paths you put/drop here!" & $MSG_LF & $MSG_LF & _
                "AND, that THIS section goes BEFORE the INPUT (above) in the " & $MSG_LF & _
                "arguments (so -map FIRST!) " & $MSG_LF & $MSG_LF & _
                "NOTE: This input accepts @tokens."
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $inp_input_params = GUICtrlCreateInput("", 5, 15, $column_two-76, 20)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    GUICtrlSetState(-1, $GUI_DROPACCEPTED)
    GUICtrlSetFont(-1, $console_output_font_size, 400, 0, $console_output_font, 5)



    $ttt = "Quick Add-A-File Button"
    $butt_add_file_arg_to_input_params = GUICtrlCreateButton("+"$column_two-72, 0, 20, 20, BitOr($WS_TABSTOP,$BS_FLAT,$BS_CENTER,$BS_VCENTER))
    GUICtrlSetTipOptional(-1, "Clicking here adds '-i """"' to the input override and places the caret inbetween the two quotes. " & $MSG_LF & _
                                "Then you can drag a file directly into the input parameter override input and it's ready-to-go. " & $MSG_LF & $MSG_LF & _
                                "Note: The addition is always at the end, so you can easily perform this action multiple times."$ttt)
    GUICtrlSetOnEvent(-1, "AddInputOverrideFileArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))


    $ttt = "Delete"
    GUICtrlCreateButton(" x", 24, 0, 20, 20, BitOr($WS_TABSTOP,$BS_FLAT,$BS_CENTER,$BS_VCENTER))
    GUICtrlSetTipOptional(-1, "Click here to wipe the current input override parameters. "$ttt)
    GUICtrlSetOnEvent(-1, "DelInputOverrideFileArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))




    ; presets..
    ; (aka. parameter favourites)


    $tip =    "Select a preset from the list. The selected preset can either add to" & $MSG_LF & _
            "or replace the current settings NOTE: once selected, you can use " & $MSG_LF & _
            "your arrow keys to navigate this combo control. " & $MSG_LF & _
            "(right-click the combo's chevron for a context menu) "

    GUISetCoord($column_two, 62)
    GUICtrlCreateLabel("", 0, 0, $column_two-12, 20, 0, 0)
    GUICtrlSetTipOptional(-1, $tip$NAME_PRESETS)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKRIGHT$GUI_DOCKSIZE))
;    GUICtrlSetBkColor(-1, $COLOR_RED)

    GUISetCoord($column_two, 62)
    GUICtrlCreateLabel("", 0, 0, 10, 42, 0, 0)
    GUICtrlSetTipOptional(-1, $tip$NAME_PRESETS)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
;    GUICtrlSetBkColor(-1, $COLOR_RED)

    GUISetCoord($column_two, 103)
    GUICtrlCreateLabel("", 0, 0, $column_two-12, 8, 0, 0)
    GUICtrlSetTipOptional(-1, $tip$NAME_PRESETS)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKRIGHT$GUI_DOCKSIZE))
;    GUICtrlSetBkColor(-1, $COLOR_RED)

    ; enable the background color commands and you will see; I am not fucking around here.


    $ttt = $NAME_PRESETS
    GUISetCoord($column_two, 62)

    GUICtrlCreateGroup(StringLower($NAME_PRESETS) & ".. ", 0, 0, ($width-$column_two)-10, 74)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKRIGHT$GUI_DOCKSIZE))


    local $combo_styles = BitOr($CBS_DROPDOWN$CBS_AUTOHSCROLL$WS_VSCROLL)
    if $sort_presets_list = $ON then $combo_styles = BitOr($CBS_SORT$CBS_DROPDOWN$CBS_AUTOHSCROLL$WS_VSCROLL)

    $combo_presets = GUICtrlCreateCombo("", 10, 20, ($width-$column_two)-120, default, $combo_styles)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetOnEvent(-1, "ComboLoadPreset")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKRIGHT$GUI_DOCKSIZE))
    GUICtrlSetState(-1, $GUI_DROPACCEPTED+$GUI_ONTOP)

    UpdatePresetsCombo()

    local $ctxt_combo = GUICtrlCreateContextMenu($combo_presets)
    GUICtrlCreateMenuItem("Rename Preset"$ctxt_combo)
    GUICtrlSetOnEvent(-1, "MenuRenamePreset")
    GUICtrlCreateMenuItem("Refresh List"$ctxt_combo)
    GUICtrlSetOnEvent(-1, "MenuRefreshPresetsList")
    GUICtrlCreateMenuItem(""$ctxt_combo)
    GUICtrlCreateMenuItem("Export Data"$ctxt_combo)
    GUICtrlSetOnEvent(-1, "MenuExportData")
    GUICtrlCreateMenuItem("Import Data"$ctxt_combo)
    GUICtrlSetOnEvent(-1, "ComboMenuImportData")
    GUICtrlCreateMenuItem(""$ctxt_combo)
    GUICtrlCreateMenuItem("Wipe All Preset Backups"$ctxt_combo)
    GUICtrlSetOnEvent(-1, "WipeBackups")


    $ttt = "Save A Preset"
    GUICtrlCreateButton("save", ($width-$column_two)-115, 0, 42, 22, BitOr($WS_TABSTOP,$BS_FLAT), $WS_EX_TOPMOST)
    GUICtrlSetTipOptional(-1,  "Save these settings as a preset  (aka. 'favourite settings') " & $MSG_LF & _
                                "NOTE: when overwriting an existing preset, hold down " & $MSG_LF & _
                                "the <SHIFT> key to skip the warning. "$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKRIGHT$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "ButtSavePreset")


    $ttt = "Wipe A Preset"
    GUICtrlCreateButton("wipe", 46 , 0, 42, 22, BitOr($WS_TABSTOP,$BS_FLAT), $WS_EX_TOPMOST)
    GUICtrlSetTipOptional(-1,  "Remove this preset from the list. "$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKRIGHT$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "WipePreset")


    ; add/replace parameters options..
    GUICtrlCreateLabel(StringLower($NAME_PRESETS) & "..", 70-($width-$column_two), 31, default, 18, BitOr($WS_TABSTOP,$BS_FLAT), $WS_EX_TOPMOST)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))



    $ttt = "Replace Settings"
    $radio_preset_replace = GUICtrlCreateRadio("replace", 47, -2, default, 18, -1)
    GUICtrlSetTipOptional(-1,  "The selected preset will replace all the current settings with settings from the new preset. " & $MSG_LF & _
                                "If your current preset specifies ' -scodec copy', and you load a preset specifying " & $MSG_LF & _
                                "'-metadata:s:s:0 language=eng', the extra parameters input would now contain both."$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "TogglePresetMode")
    GUICtrlSetState(-1, $replace_mode)

    $ttt = "Add To Settings"
    GUICtrlCreateRadio("add to", 60, 0, default, 18, -1)
    GUICtrlSetTipOptional(-1,  "The selected preset will ADD to all the current settings. " & $MSG_LF & "This applies to all the visible settings that can be" & $MSG_LF & " 'added to'; i.e. not toggles and job settings."$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "TogglePresetMode")
    if $replace_mode = $OFF then GUICtrlSetState(-1, $ON)

    GUICtrlCreateLabel("..my settings.", 54, 2, default, 18, -1, $WS_EX_TOPMOST)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))


    ; store the input/output file paths inside the preset?
    $ttt = "Save/Restore File Paths"
    $check_store_filepaths = GUICtrlCreateCheckbox("with file paths", ($width-$column_two)-276, -1, default, 18, -1, $WS_EX_TOPMOST)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKRIGHT$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "ToggleStorePaths")
    GUICtrlSetTipOptional(-1,    "Store the full path of the input and output files inside the preset " & $MSG_LF & _
                                "and (usually) restore those file paths along with the preset. "$ttt)

    if $store_filepaths <> $GUI_INDETERMINATE then
        GUICtrlSetState(-1, $store_filepaths)
    else
        GUICtrlSetState(-1, $GUI_DISABLE)
        GUICtrlSetTipOptional(-1,    "This feature is disabled inside ffe.ini."$ttt; won't show - it's diabled!
    endif

    ;2do - more of this - consider hiding completely



    ; output options..
    local $out_top = 66
    local $out_left = 10

    GUISetCoord(10, 137)


    GUICtrlCreateGroup(" output parameter override.. ", 0, 0, $width-20, 150)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKRIGHT$GUI_DOCKSIZE))



    ; video codec..
    $ttt = "Video Codec"
    $tip = "Override the output video codec here. " & $MSG_LF & "Select a preset codec from the list, " & $MSG_LF & "or enter one manually. "
    GUICtrlCreateLabel("video codec: ", 6, 18)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))


    $combo_v_codec = GUICtrlCreateCombo($v_codec, -1, 16, 128, default, BitOr($CBS_SORT$CBS_DROPDOWN$CBS_AUTOHSCROLL$WS_VSCROLL))
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    GUICtrlSetData(-1, $video_codecs)


;2do..
; we are working our way slowly through the GUI, removing this nonsense!
AutoItSetOption("GUICoordMode", 1)



    ;2do.. Need to re-organize from here, into groups, not rows!

    ; video bitrate..

    $ttt = "Video Bitrate"
    $tip = "Override the output video bitrate(bits/s). " & $MSG_LF & "Select a preset, or enter manually. "
    GUICtrlCreateLabel("bitrate: "$out_left+142, $out_top+90)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $combo_v_bitrate = GUICtrlCreateCombo(""$out_left+142, $out_top+106, 42, default)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    GUICtrlSetData(-1, $video_bitrates)


    ; video fps..

    $ttt = "Video FPS"
    $tip = "Override the output video fps (frames per second). " & $MSG_LF & "Select a preset bitrate from the list, or enter one " & $MSG_LF & "manually. "
    GUICtrlCreateLabel("fps: "$out_left+194, $out_top+90)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $combo_frames_per_second = GUICtrlCreateCombo(""$out_left+194, $out_top+106, 42, default)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    GUICtrlSetData(-1, $frames_per_second)


    ; cropping..

    ; crop x ..

    $ttt = "Cropping"
    $tip = "Crop the video.."
    GUICtrlCreateLabel("crop the video.. "$out_left+241, $out_top+90)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $inp_crop_top = GUICtrlCreateInput(""$out_left+275, $out_top+106, 33, 20, $ES_NUMBER)
    GUICtrlSetTipOptional(-1, "Crop the TOP of the video."$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $inp_crop_right = GUICtrlCreateInput(""$out_left+309, $out_top+127, 33, 20, $ES_NUMBER)
    GUICtrlSetTipOptional(-1, "Crop the RIGHT side of the video."$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $inp_crop_bottom = GUICtrlCreateInput(""$out_left+275, $out_top+148, 33, 20, $ES_NUMBER)
    GUICtrlSetTipOptional(-1, "Crop the  BOTTOM of the video."$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $inp_crop_left = GUICtrlCreateInput(""$out_left+242, $out_top+127, 33, 20, $ES_NUMBER)
    GUICtrlSetTipOptional(-1, "Crop the LEFT side of the video."$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))



    ; video resizing..
    $ttt = "Resizing"

    ; x ..
    $tip = "Rescale the video width. "
    GUICtrlCreateLabel("resize x: "$out_left+350, $out_top+90)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $inp_x_size = GUICtrlCreateInput(""$out_left+350, $out_top+106, 33, 20, $ES_NUMBER)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    ; the "x" in 640x480!
    GUICtrlCreateLabel("x"$out_left+389, $out_top+108)
    GUICtrlSetResizing(-1, $GUI_DOCKALL)


    $ttt = "Rescaling"
    ; y ..
    $tip = "Rescale the video height. "
    GUICtrlCreateLabel("resize y: "$out_left+400, $out_top+90)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $inp_y_size = GUICtrlCreateInput(""$out_left+400, $out_top+106, 33, 20, $ES_NUMBER)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))


    ; preset sizes..
    $ttt = "Preset Sizes"
    $tip = ".. or you can select a named preset size from the list (if you know what they mean!) " & $MSG_LF & "Note: this will override the manual settings (above) "
    GUICtrlCreateLabel("preset sizes: "$out_left+350, $out_top+132)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $combo_preset_resizes = GUICtrlCreateCombo($resize_preset$out_left+350, $out_top+148, 64, default)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    GUICtrlSetData(-1, $preset_resizes)


    ; resize-crop order..
    $ttt = "Resize-Crop Order"
    $check_resize_first = GUICtrlCreateCheckbox("resize first"$out_left+260, $out_top+169)
    GUICtrlSetTipOptional(-1,    "Check this to resize the video BEFORE the cropping operation (it depends on how your logic goes).." & $MSG_LF & _
                                "The order of things affects the dimensions. You might crop THEN resize, or the reverse... "$ttt)
    GUICtrlSetonEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetState($check_resize_first$resize_first)



    ; audio codec..
    $ttt = "Audio Codec"
    $tip = "Override the output audio codec here " & $MSG_LF & "Select a preset codec from the list, or " & $MSG_LF & "enter one manually. "
    GUICtrlCreateLabel("audio codec: "$out_left+6, $out_top+132)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $combo_a_codec = GUICtrlCreateCombo($a_codec$out_left+5, $out_top+148, 128, default, BitOr($CBS_SORT$CBS_DROPDOWN$CBS_AUTOHSCROLL$WS_VSCROLL))
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    GUICtrlSetData(-1, $audio_codecs)

    ; audio bitrate
    $ttt = "Audio Bitrate"
    $tip = "Override the output audio bitrate (Hz).     " & $MSG_LF & "Select a preset bitrate from the list, or " & $MSG_LF & "enter one manually. "
    GUICtrlCreateLabel("bitrate: "$out_left+142, $out_top+132)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $combo_a_bitrate = GUICtrlCreateCombo(""$out_left+142, $out_top+148, 42, default)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    GUICtrlSetData(-1, $audio_bitrates)



    ; quick targets..
    $ttt = "Quick Targets"
    $tip = "Allow ffmpeg to automatically set all the options for THIS file type. " & $MSG_LF & _
            "You can also override individual parameters manually, so long as " & $MSG_LF & "they are compatible with the target file type. "
    GUICtrlCreateLabel("quick config types: "$out_left+5, $out_top+174)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $combo_target_type = GUICtrlCreateCombo(""$out_left+6, $out_top+190, 128, default)
    GUICtrlSetData(-1, $target_types)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))



    ; extra raw parameters..
    $ttt = "Extra Raw Parameters"
    $tip ="Feel free to add any other command-line parameters you might need right here. " & $MSG_LF & _
            "The possibilities are almost infinite! Check the manual! " & $MSG_LF & $MSG_LF & _
            "NOTE: This input accepts @tokens."
    GUICtrlCreateLabel("extra parameters.. "$out_left+142, $out_top+174)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $inp_extra_args = GUICtrlCreateInput(""$out_left+141, $out_top+190, $width-168, 21)
    GUICtrlSetTipOptional(-1, $tip & $MSG_LF$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKRIGHT$GUI_DOCKSIZE))
    GUICtrlSetState(-1, $GUI_DROPACCEPTED)
    GUICtrlSetFont(-1, $console_output_font_size, 400, 0, $console_output_font, 5)



    ; reset all parameters..
    $ttt = "Reset ALL Parameters"
    GUICtrlCreateButton("reset"$out_left+$width-65, $out_top+84, 40, 20, BitOr($WS_TABSTOP,$BS_FLAT))
    GUICtrlSetTipOptional(-1, "Click this button to reset all the parameters"$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "ClickButtWipeSettings")


    "Short Test" button..
    $ttt = "Add Quick Test Parameters"
    $butt_quicktest = GUICtrlCreateButton("short test"$out_left+$width-85, $out_top+105, 60, 22, BitOr($WS_TABSTOP,$BS_FLAT))
    GUICtrlSetTipOptional(-1,    "Adds some parameters to process only the first " & $short_test_frames & " frames of video. " & $MSG_LF & _
                                "Feel free to edit this number! (hold SHIFT key while you click to do this first). "$ttt)
    GUICtrlSetonEvent(-1, "AddShortTestParam")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKTOP$GUI_DOCKSIZE))

    local $ctxt_short_test = GUICtrlCreateContextMenu($butt_quicktest)
    GUICtrlCreateMenuItem("Edit Short Test Frames"$ctxt_short_test)
    GUICtrlSetOnEvent(-1, "UserEditShortTestParams")


    "Report" button..
    $ttt = "Create A Media Report"
    $butt_mediareport = GUICtrlCreateButton("media report"$out_left+$width-105, $out_top+128, 80, 22, BitOr($WS_TABSTOP,$BS_FLAT))
    GUICtrlSetTipOptional(-1,    "Use ffprobe or MediaInfo to generate a media report for your input file " & $MSG_LF & "The report will appear in your console output area "$ttt)
    GUICtrlSetonEvent(-1, "GenerateReport")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKTOP$GUI_DOCKSIZE))



    ; The Super-Nifty Custom Buttons..
    CreateButtonGrid($custom_buttons_array$grid_x$grid_y)



    ; HELP!

    if IsArray($help_texts) then

        ; BIG info text for help buttons..
        $lab_help_info = GUICtrlCreatelabel(""$width-115, $out_top+150, 104, 20)
        GUICtrlSetFont(-1, 12, 800, 0, "", 5)
        GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKTOP$GUI_DOCKSIZE))

        for $h = 1 to $help_texts[0]
            local $help_data = StringSplit($help_texts[$h], "|")
            local $help_x = 134-($h*20) - (20 * (5-$help_texts[0]))
            $help_butts[$h] = GUICtrlCreateButton("?"$width-$help_x$out_top+170, 18, 18, BitOr($WS_TABSTOP,$BS_FLAT))
            $ttt = $help_data[1]
            GUICtrlSetTipOptional(-1, "Click this button to view the " & StringUpper($help_data[1]) & " help file in the console output window (below). " & $MSG_LF & _
                                        "Shift-click to instead open the help file in your default ." & GetExtension($help_data[2]) & " file viewer "$ttt)
            GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKTOP$GUI_DOCKSIZE))
            GUICtrlSetOnEvent(-1, "HelpMeNow")
        next
    endif



    ; command-line input..

    $ttt = "Dynamic Command-Line Display"
    GUICtrlCreateLabel("command-line input: ", 10, $out_top+228, $width-20, 20)
    GUICtrlSetResizing(-1, BitOr( $GUI_DOCKRIGHT$GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    $edit_in_args = GUICtrlCreateEdit("", 10, $out_top+244, $width-20, 64, BitOr($ES_MULTILINE$ES_READONLY))
    GUICtrlSetTipOptional(-1, "This is the actual command-line that will be used. "$ttt)
    GUICtrlSetResizing(-1, BitOr( $GUI_DOCKRIGHT$GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))


    ; command-line output..

    $ttt = "Console Output"
    $edit_console_output = GUICtrlCreateEdit("", 10, $out_top+314, $width-20, $height-($out_top+358), GetEditStyles())
    GUICtrlSetTipOptional(-1, "You can see the output from ffmpeg here, including any errors, messages, and so on.. " & $MSG_LF & _
                                "Normal text editing functions apply, e.g. use Ctrl+A to select ALL text."$ttt)
    GUICtrlSetResizing(-1, BitOr( $GUI_DOCKRIGHT$GUI_DOCKTOP$GUI_DOCKBOTTOM$GUI_DOCKLEFT$GUI_DOCKSIZE))
    GUICtrlSetLimit(-1, 2147483647)
    GUICtrlSetFont(-1, $console_output_font_size, 400, 0, $console_output_font, 5)
    GUICtrlSetState(-1, $GUI_DROPACCEPTED)


    ;search in output window..
    $ttt = "Search      (F3)"
    $butt_find = GUICtrlCreateButton("search in output", 10, $height-32, 90, 24, BitOr($WS_TABSTOP,$BS_FLAT))
    GUICtrlSetTipOptional(-1, "Click this button to find text inside the output window (or use Ctrl+F / F3). "$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKBOTTOM$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "FindInOutput")

    ; copy output to clipboard..
    $ttt = "Copy Output To Clipboard      (F8)"
    $butt_copy2clip = GUICtrlCreateButton("copy output to clipboard"$column_two-94, $height-32, 130, 24, BitOr($WS_TABSTOP,$BS_FLAT))
    GUICtrlSetTipOptional(-1, "Click this button (or hit F8) to copy the contents of the output window to the clipboard. "$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKBOTTOM$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "CopyOutput")

    ; clear the output..
    $ttt = "Clear The Output      (F5)"
    $butt_clearout = GUICtrlCreateButton("clear"$column_two+36, $height-32, 32, 24, BitOr($WS_TABSTOP,$BS_FLAT))
    GUICtrlSetTipOptional(-1, "Click this button (or hit F5) to clear the output window. "$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKBOTTOM$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "ClearOutput")


    ; GO!
    $ttt = "Start The Job      (F1)"
    $butt_doit = GUICtrlCreateButton("do it!"$width-82, $height-32, 72, 24, BitOr($WS_TABSTOP,$BS_FLAT), $WS_EX_TOPMOST)
    GUICtrlSetTipOptional(-1, "Click this button (or hit F1) to begin the job. "$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKBOTTOM$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "DoIt")
    if not $ffmpeg_binary then DisableActiveInputs()


    ; NO!
    $ttt = "ABORT THE JOB!    (Pause/Break)"
    $label_abort = GUICtrlCreateLabel("To abort a job, press 'F4'. To abort a job or batch, 'Pause/Break'.  To suspend/resume, use ScrLk/ScrollLock ", 10, $height-32)
    GUICtrlSetTipOptional(-1, "Simply hit 'F4' on your keyboard to quit the job. "$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKBOTTOM$GUI_DOCKSIZE))
    GUICtrlSetState(-1, $GUI_HIDE)


    ; all done with creating the gui .. *phew* Like I said, NEVER AGAIN!

    CheckSize()

    ; show the main gui..
    if not $do_gen and $minimized = $OFF then GUISetState(@SW_SHOW, $ffeGUI)
    if $maximized = $ON then GUISetState(@SW_MAXIMIZE, $ffeGUI)

    if $minimized = $ON then UnSetHotKeys()
    WinSetTrans($ffeGUI"", 255 * (100 - $user_trans) / 100)


endfunc








; The Application (system, aka. "App") Menu..
; built from the bottom, up..

;    CreateSystemMenuItem($sText$hMenu = -1, $bIsPopup=false, $nPos=0xFFFFFFFF)
;    0xFFFFFFFF means "insert at the end"

func MakeAppMenu()

    GUIRegisterMsg($WM_SYSCOMMAND"CheckAppMenu")

    CreateSystemMenuItem("", -1, false, 0)

    ; so we can start checking items right away..
    local $hMenu = GetSystemMenu($ffeGUI, 0)


    ; Transparency Sub-Menu..
    $am_trans = CreateSystemMenuItem("&Transparency..", -1, true, 0)
        for $i = 0 to 9
            $arTransItems[$i] = CreateSystemMenuItem($i * 10 & "%"$am_trans; we filll top-down here
            if $i = $user_trans / 10 then
                $nTPChecked = $arTransItems[$i]
                CheckMenuItem($am_trans$nTPChecked$MF_CHECKED)
            endif
        next


    ; Visual prefs Sub-Menu..
    CreateSystemMenuItem("", -1, false, 0)
    local $am_visual = CreateSystemMenuItem("&Visual Preferences..", -1, true, 0)

        $am_always_on_top = CreateSystemMenuItem("A&lways on Top"$am_visual, false, 0)
        CheckMenuItem($hMenu$am_always_on_top$always_on_top)

        CreateSystemMenuItem(""$am_visual, false, 0)

        $am_console_wordwrap = CreateSystemMenuItem("&Wrap Console Output    (Restart)"$am_visual, false, 0)
        CheckMenuItem($hMenu$am_console_wordwrap$console_wordwrap)

        CreateSystemMenuItem(""$am_visual, false, 0)

        $am_image_buttons = CreateSystemMenuItem("&Images on (some) Buttons    (Restart)"$am_visual, false, 0)
        CheckMenuItem($hMenu$am_image_buttons$image_buttons)

        CreateSystemMenuItem(""$am_visual, false, 0)

        $am_do_tooltips = CreateSystemMenuItem("Show &Mouseover Help    (Restart)"$am_visual, false, 0)
        CheckMenuItem($hMenu$am_do_tooltips$do_tooltips)

        CreateSystemMenuItem(""$am_visual, false, 0)

        $am_sort_presets_list = CreateSystemMenuItem("&Sort Presets List    (Restart)"$am_visual, false, 0)
        CheckMenuItem($hMenu$am_sort_presets_list$sort_presets_list)



    ; Custom Button Column Menu..
    CreateSystemMenuItem("", -1, false, 0)
    $am_custom_buttons_columns = CreateSystemMenuItem("Custom Button Columns..", -1, true, 0)

        ; we only show 1-24, but you can set higher inside ffe.ini
        for $i = 1 to 24
            $CustomButtonMenuItems[$i] = CreateSystemMenuItem($i$am_custom_buttons_columns; we fill top-down here
            if $i = $custom_buttons_columns then
                $CBMChecked = $CustomButtonMenuItems[$i]
                CheckMenuItem($am_custom_buttons_columns$CBMChecked$MF_CHECKED)
            endif
        next

        ; Automatic columns..
        CreateSystemMenuItem(""$am_custom_buttons_columns, false, 0)
        $CustomButtonMenuItems[501] = CreateSystemMenuItem("Automatic"$am_custom_buttons_columns, false, 0)
        if $custom_buttons_columns = "auto" then
            $CBMChecked = $CustomButtonMenuItems[501]
            CheckMenuItem($am_custom_buttons_columns$CBMChecked$MF_CHECKED)
        endif

        ; Disable CUstom Buttons altogether..
        CreateSystemMenuItem(""$am_custom_buttons_columns, false, 0)
        $am_custom_buttons_disable = CreateSystemMenuItem("Disable Custom Buttons"$am_custom_buttons_columns, false, 0)


    ; CPU Priority Sub-Menu..
    CreateSystemMenuItem("", -1, false, 0)
     $am_cpu = CreateSystemMenuItem("ffmpeg.exe Process Priorit&y..", -1, true, 0)
        for $i = 0 to 5
            $arCPUItems[$i] = CreateSystemMenuItem($arCPU[$i], $am_cpu)
            if $i = $cpu_priority then
                $nCPUChecked = $arCPUItems[$i]
                CheckMenuItem($am_cpu$nCPUChecked$MF_CHECKED)
            endif
        next


    CreateSystemMenuItem("", -1, false, 0)
    $am_retain_exit_settings = CreateSystemMenuItem("Retain Exit Settings    (Ctrl+E)", -1, false, 0)
    CheckMenuItem($hMenu$am_retain_exit_settings$retain_exit_settings)


    ; Reporting types sub-menu..

    CreateSystemMenuItem("", -1, false, 0)
    local $am_reptypes = CreateSystemMenuItem("Media Probe &Reporting Type..", -1, true, 0)

    local $am_ffprobe = CreateSystemMenuItem("Use ffprobe.."$am_reptypes, false, 0)
    AppMenuItemSetState($hMenu$am_ffprobe$OFF)

    for $i = 0 to 6
        $ReportTypesMenuItems[$i] = CreateSystemMenuItem("            " & $ReportTypes[$i], $am_reptypes)
        if $ReportTypes[$i] = $report_format then
            $nRTChecked = $ReportTypesMenuItems[$i]
            CheckMenuItem($am_reptypes$nRTChecked$MF_CHECKED)
        endif
    next

    CreateSystemMenuItem(""$am_reptypes, false, 0)
    $am_use_mediainfo = CreateSystemMenuItem("Use MediaInfo"$am_reptypes, false, 0)
    if $use_mediainfo = $ON then SetUseMediaInfo()


    ; Logging sub-menu..
    CreateSystemMenuItem("", -1, false, 0)
    local $am_logging = CreateSystemMenuItem("&Logging..", -1, true, 0)

;        CreateSystemMenuItem(""$am_logging, false, 0)
        $am_log_append = CreateSystemMenuItem("Append &Session Log"$am_logging, false, 0)
        CheckMenuItem($hMenu$am_log_append$log_append)

        CreateSystemMenuItem(""$am_logging, false, 0)
        $am_job_log_append = CreateSystemMenuItem("&Append Job Logs"$am_logging, false, 0)
        CheckMenuItem($hMenu$am_job_log_append$job_log_append)

        CreateSystemMenuItem(""$am_logging, false, 0)
        $am_log_each_job = CreateSystemMenuItem("&Log Each Job"$am_logging, false, 0)
        CheckMenuItem($hMenu$am_log_each_job$log_each_job)



    ; Drop Command sub-menu..
    CreateSystemMenuItem("", -1, false, 0)
    $am_drop_command = CreateSystemMenuItem("&Drag-And-Drop Command..", -1, true, 0)
    for $i = 0 to 2
        if $i = 2 then CreateSystemMenuItem(""$am_drop_command, false, 1)
        $DropCommandMenuItems[$i] = CreateSystemMenuItem("&" & $DropCommands[$i], $am_drop_command)
        if $DropCommands[$i] = $drop_command then
            $nDCChecked = $DropCommandMenuItems[$i]
            CheckMenuItem($hMenu$nDCChecked$MF_CHECKED)
        endif
    next


    CreateSystemMenuItem("", -1, false, 0)
    $am_about = CreateSystemMenuItem("&About " & $my_name, -1, false, 0)

endfunc





; next = 34 !        ; unused = 27

func MakeTray()

    ; wipe the tray..
    for $i = 0 to 999 ; tell me a better way! no, really.
        TrayItemDelete($i)
    next

    ; tray menu..
    TrayCreateItem("About " & $my_name)
    TrayItemSetOnEvent(-1, "DoAboutBox")

    TrayCreateItem("")

    local $tray_recent_files = TrayCreateMenu("Recent Files..")

        $tray_toggle_retain_recent_files = TrayCreateItem("Retain Recent Files    (opened in system's default app)"$tray_recent_files)
        TrayItemSetOnEvent(-1, "TrayToggleRetainRecentFiles")
        TrayItemSetState(-1, $retain_recent_files)

        TrayCreateItem(""$tray_recent_files)

        if IsArray($recent_files) and $recent_files[0] then

            TrayCreateItem("Clear Recent Files List"$tray_recent_files)
            TrayItemSetOnEvent(-1, "ClearRecentFiles")
            TrayCreateItem(""$tray_recent_files)

            for $i = $recent_files[0] to 1 step -1
                TrayCreateItem($recent_files[$i], $tray_recent_files)
                TrayItemSetOnEvent(-1, "OpenRecentFile")
            next

        else
            TrayCreateItem("No Recent Files Yet!"$tray_recent_files)
            TrayItemSetState(-1, $TRAY_DISABLE)
        endif

    TrayCreateItem("")

    $tray_toggle_delayed_start = TrayCreateItem("Delayed Start    (Ctrl+D)")
    TrayItemSetOnEvent(-1, "DelayedDoIt")

    TrayCreateItem("")

    $tray_abort_batch = TrayCreateItem("Abort Batch    Pause/Break")
    TrayItemSetOnEvent(-1, "AbortBatch")
    TrayItemSetState(-1, $TRAY_DISABLE)

    TrayCreateItem("")

    TrayCreateItem("Edit ffe.ini..")
    TrayItemSetOnEvent(-1, "EditIniFile")

    TrayCreateItem("")

    if $pre_job_commands_file and FileExists($pre_job_commands_file) then
        TrayCreateItem("Edit Pre-Job Commands..")
        TrayItemSetOnEvent(-1, "EditPreJobCommands")
    else
        TrayCreateItem("Create Pre-Job Commands..")
        TrayItemSetOnEvent(-1, "CreatePreJobCommands")
    endif


    if $post_job_commands_file and FileExists($post_job_commands_file) then
        TrayCreateItem("Edit Post-Job Commands..")
        TrayItemSetOnEvent(-1, "EditPostJobCommands")
    else
        TrayCreateItem("Create Post-Job Commands..")
        TrayItemSetOnEvent(-1, "CreatePostJobCommands")
    endif

    TrayCreateItem("")

    TrayCreateItem("Open Log File..")
    TrayItemSetOnEvent(-1, "OpenLogFile")

    TrayCreateItem("")

    TrayCreateItem("Export Data..")
    TrayItemSetOnEvent(-1, "TrayMenuExportData")

    TrayCreateItem("Import Data..")
    TrayItemSetOnEvent(-1, "TrayMenuImportData")

    TrayCreateItem("")

    TrayCreateItem("Locate FFmpeg Binary..")
    TrayItemSetOnEvent(-1, "TraySetFFMpegBinaryLocation")

    TrayCreateItem("")

    $tray_toggle_drop_window = TrayCreateItem("Show Drop Window    (F9)")
    TrayItemSetOnEvent(-1, "MenuToggleShowDropWindow")
    TrayItemSetState(-1, $do_drop_window)

    $tray_toggle_fluid_image_menu = TrayCreateItem("Fluid Menu    (follows current image)")
    TrayItemSetOnEvent(-1, "MenuToggleDropWindowFluidMenu")
    TrayItemSetState(-1, $fluid_image_menu)

    $tray_toggle_auto_copy_images = TrayCreateItem("Copy Dragged Images    (to fixed menu)")
    TrayItemSetOnEvent(-1, "MenuToggleAutoCopy")
    TrayItemSetState(-1, $auto_copy_images)
    if $fluid_image_menu = $ON then TrayItemSetState(-1, $TRAY_DISABLE)

    $tray_choose_image_folder = TrayCreateItem("Pick Images Folder..    (for fixed menu)")
    TrayItemSetOnEvent(-1, "MenuChooseFixedImageLocation")
    if $fluid_image_menu = $ON then TrayItemSetState(-1, $TRAY_DISABLE)

    TrayCreateItem("")

    TrayCreateItem("Reset Drop Window")
    TrayItemSetOnEvent(-1, "MenuResetDropWindow")

    TrayCreateItem("")

    $tray_toggle_start_minimized = TrayCreateItem("Start Minimized")
    TrayItemSetOnEvent(-1, "MenuToggleStartMinimized")
    TrayItemSetState(-1, $start_minimized)
    if $minimized = $ON then TrayItemSetState(-1, $TRAY_DISABLE)

    TrayCreateItem("")

    TrayCreateItem("Exit    (Alt+F4 or Esc)")
    TrayItemSetOnEvent(-1, "User_DoQuit")

    ; system tray event..
    ; left-click to show/hide the main window.
    TraySetOnEvent($TRAY_EVENT_PRIMARYDOWN"ToggleWindow")
    TraySetClick(8)
    TraySetIcon($me_app, 0)

    TraySetState()
    TraySetToolTip("left-click to toggle the main window" & $MSG_LF & "right-click to bring up the tray menu")

endfunc


; If the user has no "Open" key in this filetype, this will fail..

func OpenRecentFile()
    local $tray_item_full_path = TrayItemGetText(@tray_id)
    ShellExecute($tray_item_full_path""""$SHEX_OPEN)
endfunc


func ClearRecentFiles()
    redim $recent_files[1]
    $recent_files[0] = ""
    MakeTray()
endfunc



;    rtmp://fms.12E5.edgecastcdn.net/0012E5/mp4:videos/8Juv1MVa-485.mp4

; The input has changed - update the output and arguments..

func UpdateInput()

    $inputfile = Detokenize(GUICtrlRead($inp_inputfile))

    ; only update if there was a change..
    if $old_inputfile <> $inputfile then

        $old_inputfile = $inputfile
        if IsDir($inputfile) then CRT($inputfile)

        ; If the currently set output dir is valid, leave it there..
        local $out_parent = Detokenize(GUICtrlRead($inp_outputfile))
        CRT($out_parent)

        ; if output is a dir, use that for $out_parent, otherwise the outfile parent dir..
        if not IsDir($out_parent) then $out_parent = GetParent(Detokenize(GUICtrlRead($inp_outputfile)))

        ; valid, use it..
        if FileExists($out_parent) then
            GUICtrlSetData($inp_outputfile$out_parent)
        else
            ; blank it - start again!
            GUICtrlSetData($inp_outputfile"")
        endif

    endif

    DoArgsCreate()

endfunc



; Create Arguments..

; Create the arguments for the command-line input and MATOF extensions..
; This wrapper function is called when controls are changed.

func AutoCreateArgs()    ; outputfile either single complete name or a dir
;    if @GUI_CtrlId = $inp_outputfile then $outputfile = GUICtrlRead($inp_outputfile)
    DoArgsCreate()
endfunc

func DoArgsCreate($batch="null")

    ; during batch, this is set inside DoIt()
    if not $inputfile then
        $inputfile = GUICtrlRead($inp_inputfile)
    endif

    if not $inputfile then return

    local $input_params$read_vcodec$read_acodec$write_outputfile

    ; for single files, we will put back $output, later.
    $outputfile = ""

    local $outputfileCtrlRead = DeTokenize(GUICtrlRead($inp_outputfile))
    CRT($outputfileCtrlRead)

    $extra_args = DeTokenize(GUICtrlRead($inp_extra_args))

    ; we will build this string as we go..
    $matof_string = ""

    if GUICtrlRead($inp_input_params) then
        $input_params = Detokenize(GUICtrlRead($inp_input_params))
    else
        $input_params = ""
    endif

    if GUICtrlRead($check_resize_first) = $ON then
        AddSizing()
        AddCropping()
    else
        AddCropping()
        AddSizing()
    endif

    ; YES! DO IT!
    if $overwrite = $ON then $extra_args &= " -y "

    $read_vcodec = GUICtrlRead($combo_v_codec)
    $read_acodec = GUICtrlRead($combo_a_codec)

    if StringInStr($read_vcodec"disable") and $do_output = $ON then
        $extra_args = " -vn " & $extra_args
        $no_video = true

        if StringInStr($read_acodec"disable") then
            GUICtrlSetData($combo_a_codec$audio_codecs)
            $read_acodec = GUICtrlRead($combo_a_codec)
        endif
    else
        $no_video = false
    endif


    if StringInStr($read_acodec"disable") then
        $extra_args = " -an " & $extra_args
        $no_audio = true
    else
        $no_audio = false
    endif


    ; this over-rides everything..
    if GUICtrlRead($combo_target_type) then
        $extra_args &= " -target " & GUICtrlRead($combo_target_type)
        $matof_string &= "[" & GUICtrlRead($combo_target_type) & "]"
        $no_video = false
    endif


    if $read_vcodec and not StringInStr($read_vcodec"disable") then
        $v_codec = " -vcodec " & $read_vcodec
        $matof_string &= "[" & $read_vcodec  & "]"
    else
        $v_codec = ""
    endif

    if not $no_video then
        if GUICtrlRead($combo_v_bitrate) then
            $extra_args &= " -b:v " & GUICtrlRead($combo_v_bitrate)
            $matof_string &= "[" & GUICtrlRead($combo_v_bitrate) & "]"
        endif

        if GUICtrlRead($combo_frames_per_second) then
            $extra_args &= " -r " & GUICtrlRead($combo_frames_per_second)
            $matof_string &= "[" & GUICtrlRead($combo_frames_per_second) & "]"
        endif
    endif

    if not $no_audio then
        if $read_acodec then
            $a_codec = " -acodec " & $read_acodec
        else
            $a_codec = ""
        endif

        if $read_acodec then $matof_string &= "[" & $read_acodec  & "]"
        if GUICtrlRead($combo_a_bitrate) then
            $extra_args &= " -ab " & GUICtrlRead($combo_a_bitrate)
            if not $no_video then $matof_string &= "[" & GUICtrlRead($combo_a_bitrate) & "]"
        endif
    endif

    if GUICtrlRead($inp_extra_args) then
        $matof_string &= "[" & CleanPath(GUICtrlRead($inp_extra_args)) & "]"
    endif


    ; finished adding args / MATOF strings.



    ; not inside a job (for display purposes only)..
    if $batch == "null" then
        $batch = $OFF
        ; it *will* be a batch, when it is actually run..
        if IsWild($inputfile) then $batch = $ON
    endif


    ; if it's a batch, you need matof, or SOMETHING..

    if $do_matof = $OFF and $batch = $ON then
        ToggleMatofStatus(false)
        ConsoleAdd("MATOF: required (batch operation)")
    endif




    ; Now we set $outputfile..


    ; ffe is handling the output file path.. (not disabled)
    if $do_output = $ON then

        ; during preset load, $inp_outputfile is set to $ini_outputfile (ini preset setting)
        ; Or user may have set it to some other gibberish!

        ; BE CAREFUL with StringReplace(!). If $old_matof = "" then it would return "", hence we check first
        if $old_matof then $outputfileCtrlRead = StringReplace($outputfileCtrlRead$old_matof"")

        local $inputfile_basename = RemoveExtension(BaseName($inputfile))

        ; Set output directory from $outputfileCtrlRead/fallback dir..
        if $outputfileCtrlRead then
            ; Directory already specified in outputfile..
            if IsDir($outputfileCtrlRead) then
                $output_dir = $outputfileCtrlRead
            else
                ; otherwise, we will use parent dir of specified outputfile, if it exists..
                if IsDir(GetParent($outputfileCtrlRead)) then $output_dir = GetParent($outputfileCtrlRead)
            endif
        endif


        ; blank output_dir: perhaps a URL and no outputfile (dir) specified in ini. Use fall-back

        if not $output_dir then
            ; grab here, not LoadPreset() as dynamic @tokens may have changed..
            $fallback_folder = IniRead($ini_path$current_preset"fallback_folder"$fallback_folder)

            if not $fallback_folder or ($fallback_folder = "@parent" and StringInStr($inputfile"://")) then    ;bug LFN???
                $fallback_folder = @MyDocumentsDir
            else
                $fallback_folder = DeTokenize($fallback_folder)
            endif
            $output_dir = $fallback_folder
        endif


        local $fallback_path = $output_dir & "\" & $inputfile_basename & "." & $default_extension




        ; SINGLE FILE..
        ; http://jell.yfish.us/media/Jellyfish-3-Mbps.mkv


        ; leave output file path as-is (user-set, single file)..
        if $batch = $OFF then    $do_matof = $OFF

            ; set to ini setting (or last-used $outputfile) first. could be blank.
            $outputfile = $ini_outputfile

            ; user changed since ini read (manual outputfile)..
            if $outputfileCtrlRead <> $ini_outputfile then $outputfile = $outputfileCtrlRead

            if IsDir($outputfile) or not $outputfile then
                $outputfile = $fallback_path
            endif

            ; ffmpeg needs an extension to work out codecs; they didn't use one, so we add it..
            if not StringInStr(Basename($outputfile), ".") then $outputfile &= "." & $default_extension


        ; BATCH RUN..

        else
            ; if counter - increment and create new base name     - nah!

            ; simply set to input filename + default_extension, for now (MATOF is enabled, so this will get extras added to it)..
            $outputfile = $fallback_path
        endif



        ; by now, $outputfile is an actual file name..



         ; DO MATOF!
        if $do_matof = $ON and $matof_string then

            ; default..
            local $clean_outputfile_noext = RemoveExtension($outputfile)
            $clean_outputfile_ext = GetExtFromCodec($read_vcodec$inputfile)

            local $separator
            ; MATOF has a new filename..
            if $matof_string then
                $separator = $matof_separator
            else
                $separator = ""
            endif
            ; we save the matof string, to be removed before re-checking inputs again.
            $old_matof = $separator & $matof_string
            $outputfile = $clean_outputfile_noext & $old_matof & "." & $clean_outputfile_ext

        endif

;        ; reset this (new "base" outputfile)..
;        if not $ini_outputfile then $ini_outputfile = $outputfile
;
        ; updates live during batch run..
        GUICtrlSetData($inp_outputfile$outputfile)

        $write_outputfile = """" & $outputfile & """"


    ; user handling output file in extra args..
    else
        $write_outputfile = ""
    endif


    local $write_loc = $ffmpeg_binary
    if $generate_script then $write_loc = '"' & $ffmpeg_binary & '"'

    ; Create the final ffmpeg argument..
    $args = $write_loc & " " & $input_params &  " -i " & """" & $inputfile & """" & $v_codec & " " & $a_codec & " " & $extra_args & " " & $write_outputfile


    ; update the command-line input display..
    GUICtrlSetData($edit_in_args$args)

endfunc




; context menu wrapper func..
func MenuRefreshPresetsList()
    UpdatePresetsCombo()
endfunc


; update the combo box with the current presets..
func UpdatePresetsCombo()
    local $presets_string = ""
    $presets = IniReadSectionNames($ini_path)
    if not IsArray($presets) then return

    for $i = 1 to $presets[0]
        ; only list the first occurence of each preset (you can have backups inside the ini - only the first is used)
        if not StringInStr($presets_string$presets[$i] & "|") and StringLeft($presets[$i], 10) <> "--backup--" then
            $presets_string &= $presets[$i] & "|"
        endif
    next

    ; now we just show it in the list regardless, so users can more easily see how to set defaults.
    ;$presets_string = StringReplace($presets_string"ffe|""", 1)

    ; remove special section..
    $presets_string = StringReplace($presets_string"custom buttons|""")
    $presets_string = StringReplace($presets_string$exit_preset & "|""")

    CRT($presets_string"|")
    GUICtrlSetData($combo_presets"")
    GUICtrlSetData($combo_presets$presets_string)
endfunc

;"DelString", occurrence

func AddInputOverrideFileArgs()
    local $current_data = GUICtrlRead($inp_input_params)
    if $current_data then $current_data &= " "
    GUICtrlSetData($inp_input_params$current_data & '-i ""')
    ;_GUICtrlEdit_Scroll($inp_input_params$__EDITCONSTANT_SB_SCROLLCARET)
    ControlFocus($ffeGUI""$inp_input_params)
    ; Better yet, once you set focus, you can use these..
    ControlSend($ffeGUI""$inp_input_params"{RIGHT}")
    ControlSend($ffeGUI""$inp_input_params"{LEFT}")
endfunc


func DelInputOverrideFileArgs()
    GUICtrlSetData($inp_input_params"")
endfunc



; wrapper function
func ComboLoadPreset()
    $inputfile = ""
    LoadPreset()
endfunc


; load the settings from a saved preset into the GUI controls..
; a bit brain-dead, but logical..
func LoadPreset($this_preset=""$init=false)

    ; Generally speaking, IF the preference is specified, we update the pref &
    ; GUI, otherwise we leave the preference as-is.


    local $param$dep_param

    ; command-line preset launch..
    if $this_preset then
        if InArray($presets$this_preset) and not InArray($not_presets$this_preset) then GUICtrlSetData($combo_presets$this_preset)

    ; user selected from drop-down..
    else
        $this_preset = GUICtrlRead($combo_presets)
        $store_filepaths = GUICtrlRead($check_store_filepaths)
    endif

    ; blank, load defaults..
    if not $this_preset then $this_preset = $my_name

    ; Set this handy global variable..
    $current_preset = $this_preset

    if not $init then ConsoleAdd("loading preset: " & $current_preset)
    ConsoleWrite(".\" & @ScriptName & "(" & @ScriptLineNumber & "): ==> " & "loading preset: " & $current_preset & $LOG_LF)

    ; load file paths from ini, or don't..
    if $store_filepaths = $ON then

        ; INPUT File..

        $inputfile not sent on command-line, use ini value..
        if not $inputfile then ; this is reset during manual preset loading
            ; in..
            $param = Detokenize(IniRead($ini_path$current_preset"inputfile"""))
            if $param then GUICtrlSetData($inp_inputfile$param)

        endif


        ; OUTPUT File..

        $ini_outputfile = ""

        ; not a batch, read outputfile from ini, also handle deprecated pref, the nice way..
        $param = Detokenize(IniRead($ini_path$current_preset"outputfile"""))
        $dep_param = Detokenize(IniRead($ini_path$current_preset"outfile"""))
        if $dep_param then
            $param = $dep_param
            IniDelete($ini_path$current_preset"outfile")
            IniWrite($ini_path$current_preset"outputfile"$param)
        endif

        if $param then
            CRT($param)
            $ini_outputfile = $param
            GUICtrlSetData($inp_outputfile$param)
        endif

    endif

    local $x_param
    if $replace_mode = $ON then
        WipeSettings()
    else
        $x_param = GUICtrlRead($inp_extra_args) & " "
    endif

    $param = IniRead($ini_path$current_preset"input_params""")

    if $param then GUICtrlSetData($inp_input_params$param)

    $param = IniRead($ini_path$current_preset"v_codec""")
    if $param then GUICtrlSetData($combo_v_codec$param)
    $param = IniRead($ini_path$current_preset"v_bitrate""")
    if $param then GUICtrlSetData($combo_v_bitrate$param)
    $param = IniRead($ini_path$current_preset"frames_per_second""")
    if $param then GUICtrlSetData($combo_frames_per_second$param)

    $param = IniRead($ini_path$current_preset"x_size""")
    if $param then GUICtrlSetData($inp_x_size$param)
    $param = IniRead($ini_path$current_preset"y_size""")
    if $param then GUICtrlSetData($inp_y_size$param)
    $param = IniRead($ini_path$current_preset"preset_resize""")
    if $param then GUICtrlSetData($combo_preset_resizes$param)

    $param = IniRead($ini_path$current_preset"crop_top""")
    if $param then GUICtrlSetData($inp_crop_top$param)
    $param = IniRead($ini_path$current_preset"crop_left""")
    if $param then GUICtrlSetData($inp_crop_left$param)
    $param = IniRead($ini_path$current_preset"crop_right""")
    if $param then GUICtrlSetData($inp_crop_right$param)
    $param = IniRead($ini_path$current_preset"crop_bottom""")
    if $param then GUICtrlSetData($inp_crop_bottom$param)

    $param = IniRead($ini_path$current_preset"a_codec""")
    if $param then GUICtrlSetData($combo_a_codec$param)
    $param = IniRead($ini_path$current_preset"a_bitrate""")
    if $param then GUICtrlSetData($combo_a_bitrate$param)

    $param = IniRead($ini_path$current_preset"target_type""")
    if $param then GUICtrlSetData($combo_target_type$param)

    $param = IniRead($ini_path$current_preset"raw_params""")
    if $param then GUICtrlSetData($inp_extra_args$x_param & $param)

    ; another deprecated preference..
    $param = IniReadCheckBoxValue($ini_path$current_preset"resize_first""")
    $dep_param = IniReadCheckBoxValue($ini_path$current_preset"resize_order""")
    if $dep_param then
        $param = $dep_param
        IniDelete($ini_path$current_preset"resize_order")
        IniWriteCheckBoxValue($ini_path$current_preset"resize_first"$param)
    endif
    if $param then GUICtrlSetState($check_resize_first$param)


    $param = IniReadCheckBoxValue($ini_path$current_preset"do_output""")
    if $param then
        $do_output = $param
        if $do_output = $ON then
            GUICtrlSetState($inp_outputfile$GUI_ENABLE)
        else
            GUICtrlSetState($inp_outputfile$GUI_DISABLE)
        endif
    endif



    ; job button functions..        (TRI-STATE)

    ; if ini setting is blank, IniReadCheckBoxValue() will, by design, return 2 ($GUI_INDETERMINATE)
    ; ideally (ffe-generated) prefs are deleted; truly "unset".

    $do_matof = IniReadCheckBoxValue($ini_path$current_preset"do_matof"$do_matof, true)
    GUICtrlSetState($check_do_matof$do_matof)

    $overwrite = IniReadCheckBoxValue($ini_path$current_preset"overwrite"$overwrite, true)
    GUICtrlSetState($check_overwrite$overwrite)

    $concatenate = IniReadCheckBoxValue($ini_path$current_preset"concatenate"$concatenate, true)
    GUICtrlSetState($check_concatenate$concatenate)

    $quit_when_done = IniReadCheckBoxValue($ini_path$current_preset"quit_when_done"$quit_when_done, true)
    GUICtrlSetState($check_quit_when_done$quit_when_done)

    $shutdown_when_done = IniReadCheckBoxValue($ini_path$current_preset"shutdown_when_done"$shutdown_when_done, true)
    GUICtrlSetState($check_shutdown_when_done$shutdown_when_done)



    ; Read-Only Settings - don't change GUI, must be set manually inside ffe.ini..

    $param = IniRead($ini_path$current_preset"default_extension""")
    if $param then
        if $default_extension <> $param and not $init then ConsoleAdd('default_extension: "' & $param & '"')
        $default_extension = $param
    endif

    $param = IniReadCheckBoxValue($ini_path$current_preset"kill_ffmpeg_on_exit""")
    if $param then
        if $param <> $kill_ffmpeg_on_exit and not $init then ConsoleAdd('kill_ffmpeg_on_exit: ' & ProcessWriteHumanCheckBoxValue($param))
        $kill_ffmpeg_on_exit = $param
    endif

    GetLogLocation($current_preset)
    UpdateInput()


    ; do this after input/output is set, so 'tokens work..
    $pre_job_commands_file and $batch_commands_timeout grabbed and Toggles performed inside Load*Commands()
    LoadPreCommands()
    LoadPostCommands()

    $run_post_file_command = IniReadCheckBoxValue($ini_path$current_preset"run_post_file_command"$run_post_file_command, true)
    GUICtrlSetState($check_run_post_file_command$run_post_file_command)

    $post_file_command = IniRead($ini_path$current_preset"post_file_command"$post_file_command)

    $batch_commands_timeout = IniRead($ini_path$current_preset"batch_commands_timeout"$batch_commands_timeout)


    ; recnet files list in tray menu..
    $retain_recent_files = IniReadCheckBoxValue($ini_path$my_name"retain_recent_files"$OFF)

    if $retain_recent_files = $ON then
        local $tmp_rfstring = IniRead($ini_path$this_preset"recent_files""")
        CRT($tmp_rfstring"|"; shouldn't be required (Stringjoin() does it on writing)
        if $tmp_rfstring then
            $recent_files = StringSplit($tmp_rfstring"|")
            MakeTray()
        endif
    endif

endfunc




func ButtSavePreset()
    local $this_preset = GUICtrlRead($combo_presets)

    if $this_preset = $my_name and not ce_IsPressed(10) then
        DialogOpen()
        local $replace_defaults = MsgBox($MB_YESNO+$MB_TASKMODAL"Are you SURE?""If you use the name " & $my_name & ", your settings will become the defaults, " & _
                                                $MSG_LF & "and will be loaded automatically at startup.  Is this what you want?", 0, $ffeGUI)
        DialogClose()
        if $replace_defaults = 7 then return
    endif
    SavePreset($this_preset)
endfunc



; Save the current settings to a preset..

; We save the setting regardless of whether or not it has a value, in case the
; old preset /does/ have a value; then we are sure to overwrite it.

func SavePreset($this_preset)

    if not $this_preset then return

    ; no square brackets inside names - it will mess up "EVERYTHING".
    $this_preset = StringReplace($this_preset"[""(")
    $this_preset = StringReplace($this_preset"]"")")
    $this_preset = StringStripWS($this_preset, 3)

    $presets = IniReadSectionNames($ini_path)
    if InArray($presets$this_preset) and $this_preset <> $my_name  and $this_preset <> $exit_preset and not ce_IsPressed(10) then
        DialogOpen()
        local $replaceit = MsgBox(4, "Replace Preset?""That preset exists!" & $MSG_LF & "Do you wish to replace it?", 30, $ffeGUI)
        DialogClose()
        if $replaceit = 7 then return
    endif

    ; we read these prefs directly from the GUI controls..

    if GUICtrlRead($check_store_filepaths) = $ON then
        IniWrite($ini_path$this_preset"inputfile", GUICtrlRead($inp_inputfile))
        ; don't save the MATOF string with the pref..
        if $old_matof then $outputfile = StringReplace($outputfile$old_matof"")
        CRT($outputfile)
        if $outputfile then IniWrite($ini_path$this_preset"outputfile"$outputfile)
    endif

    SavePref($this_preset"input_params"$inp_input_params)
    SavePref($this_preset"v_codec"$combo_v_codec)
    SavePref($this_preset"v_bitrate"$combo_v_bitrate)
    SavePref($this_preset"frames_per_second"$combo_frames_per_second)
    SavePref($this_preset"x_size"$inp_x_size)
    SavePref($this_preset"y_size"$inp_y_size)
    SavePref($this_preset"preset_resize"$combo_preset_resizes)
    SavePref($this_preset"crop_top"$inp_crop_top)
    SavePref($this_preset"crop_left"$inp_crop_left)
    SavePref($this_preset"crop_right"$inp_crop_right)
    SavePref($this_preset"crop_bottom"$inp_crop_bottom)
    SavePref($this_preset"a_codec"$combo_a_codec)
    SavePref($this_preset"a_bitrate"$combo_a_bitrate)
    SavePref($this_preset"target_type"$combo_target_type)
    SavePref($this_preset"raw_params"$inp_extra_args)

    SavePref($this_preset"resize_first"$check_resize_first, true)

    SavePref($this_preset"do_matof"$check_do_matof, true)


    ; inherited/set and saved...    (don't use SavePref() for this, no need, also, 0 would not get saved.)
    IniWrite($ini_path$this_preset"batch_commands_timeout"$batch_commands_timeout)
    IniWriteCheckBoxValue($ini_path$this_preset"run_commands_with_shell"$run_commands_with_shell)


    ; job buttons..    (state and bool set on preset load)
    ; we don't read the GUI for these next prefs, so the controls better have set the pref itself!

    SavePref($this_preset"run_pre_job_commands"$check_run_pre_job_commands, true)
    if $pre_job_commands_file then IniWrite($ini_path$this_preset"pre_job_commands_file", TokenizeString($pre_job_commands_file))

    SavePref($this_preset"run_post_job_commands"$check_run_post_job_commands, true)
    if $post_job_commands_file then IniWrite($ini_path$this_preset"post_job_commands_file", TokenizeString($post_job_commands_file))


    SavePref($this_preset"run_post_file_command"$check_run_post_file_command, true)
    if $post_file_command then IniWrite($ini_path$this_preset"post_file_command"$post_file_command)


    SavePref($this_preset"overwrite"$check_overwrite, true)
    SavePref($this_preset"concatenate"$check_concatenate, true)

    if $this_preset <> $my_name then ;2do - or show dialog with 1-time warning
        SavePref($this_preset"quit_when_done"$check_quit_when_done, true)
        SavePref($this_preset"shutdown_when_done"$check_shutdown_when_done, true)
    endif

;    We don't save these, this is for reference only..
;    $default_extension
;    $kill_ffmpeg_on_exit

    ; not read from GUI, but directly..
    IniWriteCheckBoxValue($ini_path$this_preset"do_output"$do_output)

    ; keep recent files..    (do this last, in case it's large and we hit the ini character length linit before it parses out)
    if $retain_recent_files = $ON and $recent_files[0] then IniWrite($ini_path$this_preset"recent_files", StringJoin($recent_files"|"))

    ; update "current preset" global variable..
    $current_preset = $this_preset

    UpdatePresetsCombo()
    GUICtrlSetData($combo_presets$this_preset)
    if $this_preset = $my_name then $this_preset &= " (default preset)"
    ConsoleAdd("saved preset " & $this_preset)
endfunc


func SavePref($this_preset$pref_name_string$ctrl_to_read$checkbox=false)
    local $ctrl_val = GUICtrlRead($ctrl_to_read)
    if $checkbox then
        IniWriteCheckBoxValue($ini_path$this_preset$pref_name_string$ctrl_val)
        ; IniWriteCheckBoxValue() handles empty entries internally (deletes them).
    else
        IniWrite($ini_path$this_preset$pref_name_string$ctrl_val)
        if IniRead($ini_path$this_preset$pref_name_string"") = "" then IniDelete($ini_path$this_preset$pref_name_string)
    endif
endfunc






; delete the current preset from the ini file..

func WipePreset()
    local $this_preset = GUICtrlRead($combo_presets)
    if not $this_preset then return
    $presets = IniReadSectionNames($ini_path)
    if not InArray($presets$this_preset) then
        ConsoleAdd($LOG_LF & "error wiping preset: " & $this_preset & " does not exist!")
        return false
    endif

    if $this_preset <> $my_name then
        ConsoleAdd("backup """ & $this_preset & """ to " & """--backup--" & $this_preset & '"')
        local $backup_preset = IniReadSection($ini_path$this_preset)
        if IniDelete($ini_path$this_preset) then
            ConsoleAdd("
wiped preset: " & $this_preset)
            IniWriteSection($ini_path, "
--backup--" & $this_preset$backup_preset)
        else
            ConsoleAdd($LOG_LF & "
error wiping preset: " & $this_preset)
        endif
    else
        DialogOpen()
        MsgBox(0, "
Not quite!", "If you wish to reset the default settings, simple hit the reset button" & $MSG_LF & _
                    "
and then save the (blank) settings to a preset, using the name " & $my_name & "", 0, $ffeGUI)
        DialogClose()
    endif
    ; reset..
    $current_preset = $my_name
    UpdatePresetsCombo()
    return
endfunc



; delete all the backup presets..

func WipeBackups()
    local $got_backups = false
    $presets = IniReadSectionNames($ini_path)
    if not IsArray($presets) then return
    for $i = 1 to $presets[0]
        ; only list the first occurence of each preset (you can have backups inside the ini - only the first is used)
        if StringLeft($presets[$i], 10) = "
--backup--" then
            $got_backups = true
            if IniDelete($ini_path$presets[$i]) then ConsoleAdd("
wiped backup preset: " & $presets[$i])
        endif
    next
    if not $got_backups then ConsoleAdd("
no backups found")
endfunc



func MenuRenamePreset()
    if $current_preset = $my_name then
        ConsoleAdd("
cannot rename the default preset!")
        return
    endif
    DialogOpen()
    local $new_preset_name = InputBox("
Rename Preset.. ", "Enter a new name for the preset.. ", $current_preset , "" , 350, 130, default, default, 0, $ffeGUI)
    DialogClose()
    if $new_preset_name then
        if InArray($not_presets$new_preset_name) then
            ConsoleAdd("
cannot rename: " & $new_preset_name & "!")
            return
        endif
        IniRenameSection($ini_path$current_preset$new_preset_name)
        ConsoleAdd("
reset: " & $current_preset &  " renamed to : " & $new_preset_name )
        $new_preset_name = $new_preset_name
    endif
endfunc



; Some Tray Toggles..


func MenuToggleDropWindowFluidMenu()
    if $fluid_image_menu = $ON then
        $fluid_image_menu = $OFF
    else
        $fluid_image_menu = $ON
    endif
    IniWriteCheckBoxValue($ini_path$my_name, "
fluid_image_menu", $fluid_image_menu)
    TrayItemSetState($tray_toggle_fluid_image_menu$fluid_image_menu)
    if $fluid_image_menu = $ON then
        TrayItemSetState($tray_toggle_auto_copy_images$TRAY_DISABLE)
        TrayItemSetState($tray_choose_image_folder$TRAY_DISABLE)
        GUICtrlSetState($ctxt_toggle_fluid_image_menu$GUI_DISABLE)
        GUICtrlSetState($ctxt_toggle_auto_copy_images$GUI_DISABLE)
    else
        TrayItemSetState($tray_toggle_auto_copy_images$TRAY_ENABLE)
        TrayItemSetState($tray_choose_image_folder$TRAY_ENABLE)
        GUICtrlSetState($ctxt_toggle_fluid_image_menu$GUI_ENABLE)
        GUICtrlSetState($ctxt_toggle_auto_copy_images$GUI_ENABLE)
    endif
    HideDropWindow()
endfunc



func TrayToggleRetainRecentFiles()
    if $retain_recent_files = $ON then
        $retain_recent_files = $OFF
    else
        $retain_recent_files = $ON
    endif
    IniWriteCheckBoxValue($ini_path$my_name, "
retain_recent_files", $retain_recent_files)
    TrayItemSetState($tray_toggle_retain_recent_files$retain_recent_files)
endfunc


func MenuToggleAutoCopy()
    if $auto_copy_images = $ON then
        $auto_copy_images = $OFF
    else
        $auto_copy_images = $ON
    endif
    IniWriteCheckBoxValue($ini_path$my_name, "
auto_copy_images", $auto_copy_images)
    TrayItemSetState($tray_toggle_auto_copy_images$auto_copy_images)
    HideDropWindow()
endfunc


func MenuToggleShowDropWindow()
    if $do_drop_window = $ON then
        CloseDropWindow()
    else
        TrayItemSetState($tray_toggle_drop_window$ON)
        GUICtrlSetState($check_do_drop_window$ON)
        $do_drop_window = $ON
    endif
endfunc


; closed from drop window context menu..
func CloseDropWindow()
    GUICtrlSetState($check_do_drop_window$OFF)
    ClickToggleDropWindow()
endfunc


; User Toggles Drop Window..
func ClickToggleDropWindow()
    $do_drop_window = GUICtrlRead($check_do_drop_window)
    TrayItemSetState($tray_toggle_drop_window$do_drop_window)
    IniWriteCheckBoxValue($ini_path$my_name, "
do_drop_window", $do_drop_window)
    if $do_drop_window = $OFF then HideDropWindow()
endfunc

; read ini setting and create valid image path for DropWindow, defaulting to built-in image on failure..
func GetDropWinImage()
    $drop_win_image = SetRelPathToDataDir(Detokenize(IniRead($ini_path$my_name, "
drop_win_image", "")))
    if not $drop_win_image or not FileExists($drop_win_image) then $drop_win_image = SetRelPathToDataDir("
images\ffe.png")
    if not FileExists(GetParent($drop_win_image)) then
        DirCreate(GetParent($drop_win_image))
        FileInstall("
.\stuff\ffe.png", $drop_win_image, 1)
    endif
    Check4GIFmethod()
endfunc

func GetDropWinImageFolder()
    $drop_win_image_folder = SetRelPathToDataDir(Detokenize(IniRead($ini_path$my_name, "
drop_win_image_folder", "images")))
    if not $drop_win_image_folder or not FileExists($drop_win_image_folder) then $drop_win_image_folder = SetRelPathToDataDir("
images")
    if not FileExists($drop_win_image_folder) then DirCreate($drop_win_image_folder)
endfunc




func MenuResetDropWindow()
    if $dropwin_visible then HideDropWindow()
    IniWrite($ini_path$my_name, "
drop_win_image", "images\ffe.png")
    IniWrite($ini_path$my_name, "
drop_win_image_folder", "images")
    IniWrite($ini_path$my_name, "
drop_window_x", 0)
    IniWrite($ini_path$my_name, "
drop_window_y", 0)
    GetDropWinImage()
    GetDropWinImageFolder()
endfunc



; Show it!
; The Funky Drop Window.. v2

func ShowDropWindow()

    $dropwin_visible = true
    ; we could start this at app start, but this keeps the numbers down..
    $on_top_counter = TimerInit()

    ; GDIPLUS.DLL --> Vista/Win 2008 installations    (gdiplus.dll location must be specified)..
    if StringinStr(@OSVersion, "
WIN_2008") or StringinStr(@OSVersion, "VISTA") then
        if not $GDI_dll then
            ConsoleAdd($LOG_LF & "
cannot create png drop window.")
            ConsoleAdd("
location of gdiplus.dll not specified.")
            ConsoleAdd("
vista or windows server 2008 operating system detected.")
            ConsoleAdd("
location of the gdiplus.dll must be manually specified.")
            ConsoleAdd($LOG_LF & "
ffe is searching for a likely candidate. please wait...")
            local $find_gdi = RecurseDir(@WindowsDir & "
\winsxs", "gdiplus.dll")

            ; Find the biggest DLL..
            local $dsize$oldbig=0, $biggest_dll
            for $i = 1 to $find_gdi[0]
                $dsize = FileGetSize($find_gdi[$i])
                if $dsize > $oldbig then
                    $oldbig = $dsize
                    $biggest_dll = $find_gdi[$i]
                endif
            next

            if _GDIPlus_Startup($biggest_dll) then
                $GDI_dll = $biggest_dll
                ConsoleAdd("
gdiplus.dll sucessfully located and loaded. saving path to ffe.ini..")
                IniWrite($ini_path$my_name, "
GDI_dll", $GDI_dll)
            else
                ; nah, this won't happen..
                ConsoleAdd("
gdiplus.dll was found but could not be loaded.")
                ConsoleAdd("
please look in %windows%\winsxs for one that works! (use f3!).")
                ConsoleAdd("
then set the full location inside ffe.ini and give it a whirl!")
                $do_drop_window = $OFF
                $dropwin_visible = false
                return
            endif
            _GDIPlus_Shutdown()
        endif
    else
        $GDI_dll = "
gdiplus.dll"
    endif


    if not FileExists($drop_win_image) then
        ConsoleAdd("
ffe could not find specified drop window image: " & $drop_win_image)
        return ResetAndReturn()
    endif

    Check4GIFmethod()

    ; load user settings..
    local $dw_width$dw_height
    local $dw_x = IniRead($ini_path$my_name, "
drop_window_x", 1)
    local $dw_y = IniRead($ini_path$my_name, "
drop_window_y", 1)
    $drop_win_transparency = IniRead($ini_path$my_name, "
drop_win_transparency", 0)
    GetRealTrans()

    ; this will load a transparent, animated GIF..
    if $gif_method then
        local $aGIFDimension = _GIF_GetDimension($drop_win_image)
        $dw_width = $aGIFDimension[0]
        $dw_height = $aGIFDimension[1]
    else
        _GDIPlus_Startup($GDI_dll)
        ; this will load ANY image type (except animated gif)..

        ; Using this method would involve a lot of code to load WMF/EMF files..
        ;$image_handle = _GDIPlus_ImageLoadFromFile($drop_win_image)

        ; but this works fine..
        $image_handle = _GDIPlus_BitmapCreateFromFile($drop_win_image)

        if not $image_handle then
            ConsoleAdd("
could not load image file: " & $drop_win_image)
            return ResetAndReturn()
        endif
        $dw_width = _GDIPlus_ImageGetWidth($image_handle)
        $dw_height = _GDIPlus_ImageGetHeight($image_handle)
    endif
    ; check we can see this image on-screen, if not, move it..
    _GetMonitors() ; get far-dimensions of multi-monitor setup..
    local $far_left = $monitors_list[0][1]
    local $far_top = $monitors_list[0][2]
    local $far_right = $monitors_list[0][3]
    local $far_height = $monitors_list[0][4]
    if ($dw_x+$dw_width) < $far_left then $dw_x = $far_left ; 1 = visible pixels
    if ($dw_x-$dw_width) > $far_right then $dw_x = $far_right-$dw_width
    if ($dw_y+$dw_height) > $far_height then $dw_y = $far_height-$dw_height
    if ($dw_y+$dw_height) < $far_top then $dw_y = $far_top
    ; This is flawed (unless we use ALL monitors dimensions;2do.). If monitor 2 is smaller...        but hey, it will mostly save yer butt!

    ;                                                      ********* NEED pop-up style here or else title bar becomes inactive for CheckMouse(GUIGetCursorInfo())
    $GUI_DropWindow = GUICreate("
ffe file drop", $dw_width$dw_height$dw_x$dw_y$WS_POPUP, BitOR($WS_EX_LAYERED$WS_EX_TOOLWINDOW$WS_EX_TOPMOST$WS_EX_ACCEPTFILES))

    GUISetOnEvent($GUI_EVENT_DROPPED, "
GetDroppedItem")
    GUISetOnEvent($GUI_EVENT_PRIMARYUP, "
SaveDropWinLocation")

    HotKeySet("
{LEFT}", "PreviousDropImage")
    HotKeySet("
{RIGHT}", "NextDropImage")

    $lab_main_drop = GUICtrlCreateLabel("
", 0, 0, $dw_width$dw_height$SS_NOTIFY$GUI_WS_EX_PARENTDRAG)
    GUICtrlSetTipOptional(-1,    "
Drag media files into here to have them inserted into ffe's file input." & $MSG_LF & _
                                "
Right-click the Drop Window for a handy context menu." & $MSG_LF & $MSG_LF & _
                                "
Use your Left/Right arrow keys to quickly cycle through all the" & $MSG_LF & _
                                "
images in the current directory (and sub-directories) ." & $MSG_LF & $MSG_LF & _
                                "
Drag images into here to use them as your Drop Window.", "The Drop Window")

    if $gif_method then
        $hGIF = _GUICtrlCreateGIF($drop_win_image, "
", 0, 0, default, default, default, 0x345)
        _WinAPI_SetLayeredWindowAttributes($GUI_DropWindow, 0x345, $dropwin_trans_real)
        GUISetBkColor(0x345) ; some random color
    else
        SetTransparentBitmap($GUI_DropWindow$image_handle$dropwin_trans_real)
    endif

    GUICtrlSetState(-1, $GUI_DROPACCEPTED)
    GUICtrlSetResizing(-1, $GUI_DOCKBORDERS)

    _WinAPI_SetParent($GUI_DropWindow, 0)

    ; if it takes longer than one second, post a notice..
    AdLibRegister("
PostScanningNotice", 1000)
    CreateDropWinContextMenu()
    AdLibUnRegister("
PostScanningNotice")

    ; Let's go!
    GUISetState(@SW_SHOW, $GUI_DropWindow)

    ; on launch, switch immediately back to main window..
    if $minimized = $OFF and not $switching then WinActivate($ffeGUI)

    ; we only save the new path if it loaded okay..
    if $switching then SetNewDropWinImage()

    $switching = false
    return true
endfunc


func ResetAndReturn()
    ConsoleAdd("
resetting to default image")
    IniWrite($ini_path$my_name, "
drop_win_image", "images\ffe.png")
    $dropwin_visible = false
    _GDIPlus_Shutdown()
    GetDropWinImage()
    return false
endfunc


; GDI Error Codes..

;    $GDIP_ERROK =                        0    ; Method call was successful
;    $GDIP_ERRGENERICERROR =                1    ; Generic method call error
;    $GDIP_ERRINVALIDPARAMETER =            2    ; One of the arguments passed to the method was not valid
;    $GDIP_ERROUTOFMEMORY =                3    ; The operating system is out of memory
;    $GDIP_ERROBJECTBUSY =                4    ; One of the arguments in the call is already in use
;    $GDIP_ERRINSUFFICIENTBUFFER =        5    ; A buffer is not large enough
;    $GDIP_ERRNOTIMPLEMENTED =            6    ; The method is not implemented
;    $GDIP_ERRWIN32ERROR =                7    ; The method generated a Microsoft Win32 error
;    $GDIP_ERRWRONGSTATE =                8    ; The object is in an invalid state to satisfy the API call
;    $GDIP_ERRABORTED =                    9    ; The method was aborted
;    $GDIP_ERRFILENOTFOUND =                10    ; The specified image file or metafile cannot be found
;    $GDIP_ERRVALUEOVERFLOW =            11    ; The method produced a numeric overflow
;    $GDIP_ERRACCESSDENIED =                12    ; A write operation is not allowed on the specified file
;    $GDIP_ERRUNKNOWNIMAGEFORMAT =        13    ; The specified image file format is not known
;    $GDIP_ERRFONTFAMILYNOTFOUND =        14    ; The specified font family cannot be found
;    $GDIP_ERRFONTSTYLENOTFOUND =        15    ; The specified style is not available for the specified font
;    $GDIP_ERRNOTTRUETYPEFONT =            16    ; The font retrieved is not a TrueType font
;    $GDIP_ERRUNSUPPORTEDGDIVERSION =    17    ; The installed GDI+ version is incompatible
;    $GDIP_ERRGDIPLUSNOTINITIALIZED =    18    ; The GDI+ API is not in an initialized state
;    $GDIP_ERRPROPERTYNOTFOUND =            19    ; The specified property does not exist in the image
;    $GDIP_ERRPROPERTYNOTSUPPORTED =        20    ; The specified property is not supported

; Of course comments don't get compiled in!


; Hide it!
func HideDropWindow()

    ; not required, but good practice..
    if not $dropwin_visible then return

    if $gif_method then
        _GIF_DeleteGIF($hGIF)
    else
        _GDIPlus_BitmapDispose($image_handle)
    endif
    _GDIPlus_Shutdown()
    SaveDropWinLocation()
    HotKeySet("
{LEFT}")
    HotKeySet("
{RIGHT}")

    GUIDelete($GUI_DropWindow)

    $dropwin_visible = false
    $on_top_counter = 0
    ; when switching images, $do_drop_window is still true, so idle loop catches this and re-opens the Drop Window. We don't have to.
    return
endfunc


func SaveDropWinLocation()
    local $dw_coords = WinGetPos($GUI_DropWindow)
    if IsArray($dw_coords) then
        ; prevent saving "center" default setting when user puts window at -1 px..
        if $dw_coords[0] = -1 then $dw_coords[0] = 0
        if $dw_coords[1] = -1 then $dw_coords[1] = 0
        IniWrite($ini_path$my_name, "
drop_window_x", $dw_coords[0])
        IniWrite($ini_path$my_name, "
drop_window_y", $dw_coords[1])
    endif
endfunc


; create transparent image GUI..
func SetTransparentBitmap($hGUI$image_handle$iOpacity)
    local $hScrDC$hMemDC$hBitmap$hOld$pSize$tSize$pSource$tSource$pBlend$tBlend
    $hScrDC = _WinAPI_GetDC(0)
    $hMemDC = _WinAPI_CreateCompatibleDC($hScrDC)
    $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($image_handle)
    $hOld = _WinAPI_SelectObject($hMemDC$hBitmap)
    $tSize = DllStructCreate($tagSIZE)
    $pSize = DllStructGetPtr($tSize)
    DllStructSetData($tSize, "
X", _GDIPlus_ImageGetWidth($image_handle))
    DllStructSetData($tSize, "
Y", _GDIPlus_ImageGetHeight($image_handle))
    $tSource = DllStructCreate($tagPOINT)
    $pSource = DllStructGetPtr($tSource)
    $tBlend = DllStructCreate($tagBLENDFUNCTION)
    $pBlend = DllStructGetPtr($tBlend)
    DllStructSetData($tBlend, "
Alpha", $iOpacity)
    DllStructSetData($tBlend, "
Format", $AC_SRC_ALPHA)$AC_SRC_ALPHA = 0x011
    _WinAPI_UpdateLayeredWindow($hGUI$hScrDC, 0, $pSize$hMemDC$pSource, 0, $pBlend$ULW_ALPHA)
    _WinAPI_ReleaseDC(0, $hScrDC)
    _WinAPI_SelectObject($hMemDC$hOld)
    _WinAPI_DeleteObject($hBitmap)
    _WinAPI_DeleteDC($hMemDC)
endfunc


; right-click menu of current images and some controls..
func CreateDropWinContextMenu()

    redim $drop_images[1][3]

    local $img_dir = GetParent($drop_win_image)
    if $fluid_image_menu = $OFF then $img_dir = $drop_win_image_folder

    local $ctxt_the_pic = GUICtrlCreateContextMenu($lab_main_drop)

    GUICtrlCreateContextMenu($lab_main_drop)
    GUICtrlCreateMenuItem("
Refresh This Menu", $lab_main_drop)
    GUICtrlSetOnEvent(-1, "
HideDropWindow")

    GUICtrlCreateMenuItem("
", $lab_main_drop)

    GUICtrlCreateMenuItem("
Open Images Folder..", $lab_main_drop)
    GUICtrlSetOnEvent(-1, "
OpenImagesFolder")

    GUICtrlCreateMenuItem("
", $lab_main_drop)

    ; menu of available images..
    local $img_menu = GUICtrlCreateMenu("
Images..", $ctxt_the_pic)
    DigToMenu($img_dir$img_menu)

    GUICtrlCreateMenuItem("
", $lab_main_drop)

    $ctxt_toggle_fluid_image_menu = GUICtrlCreateContextMenu($lab_main_drop)
    GUICtrlCreateMenuItem("
Fluid Menu    (follows current image)", $lab_main_drop)
    GUICtrlSetOnEvent(-1, "
MenuToggleDropWindowFluidMenu")
    GUICtrlSetState(-1, $fluid_image_menu)

    GUICtrlCreateMenuItem("
", $lab_main_drop)

    $ctxt_toggle_auto_copy_images = GUICtrlCreateContextMenu($lab_main_drop)
    GUICtrlCreateMenuItem("
Copy Dragged Images    (to fixed menu)", $lab_main_drop)
    GUICtrlSetOnEvent(-1, "
MenuToggleAutoCopy")
    GUICtrlSetState(-1, $auto_copy_images)
    if $fluid_image_menu = $ON then GUICtrlSetState(-1, $GUI_DISABLE)

    $ctxt_choose_image_folder = GUICtrlCreateContextMenu($lab_main_drop)
    GUICtrlCreateMenuItem("
Pick Images Folder..    (for fixed menu)", $lab_main_drop)
    GUICtrlSetOnEvent(-1, "
MenuChooseFixedImageLocation")
    if $fluid_image_menu = $ON then GUICtrlSetState(-1, $GUI_DISABLE)


    GUICtrlCreateMenuItem("
", $lab_main_drop)

    GUICtrlCreateMenuItem("
Close    (F9)", $lab_main_drop)
    GUICtrlSetOnEvent(-1, "
CloseDropWindow")

    GUICtrlCreateMenuItem("
", $lab_main_drop)

    GUICtrlCreateMenuItem("
Exit ffe", $lab_main_drop)
    GUICtrlSetOnEvent(-1, "
User_DoQuit")

endfunc




; recursive search function to dig-and-add-items-to-context-menu-as-it-goes..
; Damn! I love recursive functions!
func DigToMenu($root_dir$menu_id=false)
    if not FileExists($root_dir) then return
    local $item_text$item_id$full_item
    local $dir_list = ReadDir($root_dir, "
", "*.*")
    if IsArray($dir_list) then
        for $i = 1 to $dir_list[0]
            $item_text = BaseName($dir_list[$i])
            $full_item = $root_dir & "
\" & $dir_list[$i]
            if IsDir($full_item) then
                local $submenu = GUICtrlCreateMenu($item_text$menu_id)
                DigToMenu($full_item$submenu)
            elseif IsAllowedImage($item_text) then
                $item_id = GUICtrlCreateMenuItem("
  " & $item_text$menu_id; slight indentation for files cuz you ain't gettin' sortin!
                GUICtrlSetOnEvent(-1, "
MenuSwitchImage")
                local $new_index = AddImageToMenuList($drop_images$item_id$item_text$full_item)
                if $full_item = $drop_win_image then
                    $img_index = $new_index
                    GUICtrlSetState($item_id$ON)
                endif
            endif
        next
    endif
endfunc


; usefully returns the index of the newly created row..
func AddImageToMenuList(ByRef $array$id$text$fullpath)
    if not IsArray($array) then
        global $array[1][3]
    else
        redim $array[UBound($array)+1][3] ; Redim = SLOW!
    endif
    local $idx = UBound($array)-1
    $array[$idx][0] = $id
    $array[$idx][1] = $text
    $array[$idx][2] = $fullpath
    return $idx
endfunc


; user chose a new image frmom the context menu..
func MenuSwitchImage()
    if not @GUI_CtrlId then return false
    SwitchDropImage()
endfunc

; we are scanning a LARGE directory..
func PostScanningNotice()
    AdLibUnRegister("
PostScanningNotice")
    ConsoleAdd("
scanning for images. please wait a moment..")
endfunc

; choose a new image (hotkeys or menu)..
func SwitchDropImage($updown=false)

    GUICtrlSetState($drop_images[$img_index][0], $OFF)
    HideDropWindow()
    $switching = true

    local $i
    if $updown <> false then
        $i = $img_index + $updown
        ; wrap around..
        if $i = 0 then $i = Ubound($drop_images)-1
        if $i = Ubound($drop_images) then $i = 1
    else
        if not @GUI_CtrlId then return false
        for $i = 1 to Ubound($drop_images)-1
            if @GUI_CtrlId = $drop_images[$i][0] then exitloop
        next
    endif

    $img_index = $i
    GUICtrlSetState($drop_images[$img_index][0], $ON)
    $drop_win_image = $drop_images[$i][2]
    Check4GIFmethod()
    ConsoleAdd("
setting drop window image to: " & $drop_images[$i][2])

endfunc


; also used when dropping images into drop-window..
func SetNewDropWinImage()
    local $write_img_path = $drop_win_image
    if StringInStr($drop_win_image$data_parent & "
\") then $write_img_path = StringReplace($drop_win_image$data_parent & "\", "")
    $write_img_path = TokenizeString($write_img_path)
    if $write_img_path then IniWrite($ini_path$my_name, "
drop_win_image", $write_img_path)
endfunc


; we run this after loading an image (sometimes more than once!)
func Check4GIFmethod()
    $gif_method = false
    if $enable_animated_gif and GetExtension($drop_win_image) = "
gif" then $gif_method = true
endfunc


; We prepare the string on ini-load, by adding a "," to both ends.
; Then we can check for ",ps," without matching it in, for example, "eps".
; It's quicker than creating an array, especially when used inside recursive
; functions, which it is.
func IsAllowedImage($image_file)
    if StringInStr($allowed_image_types, "
," & GetExtension($image_file) & ",") then return true
    return false
endfunc


; on-top status on windows in Windows can "drift". This ensures it styas on top..
func SetDropWinOnTop()
    WinSetOnTop($GUI_DropWindow, "
", $WINDOWS_ONTOP)
endfunc





; Those Lovely Custom Buttons..



; Load custom buttons..
func LoadCustomButtonData()
    $custom_buttons_array = IniReadSection($ini_path$NAME_BUTTONS)
    if IsArray($custom_buttons_array) then
        if $custom_buttons_array[0][0] > 500 then $custom_buttons_array[0][0] = 500
        global $custom_buttons[$custom_buttons_array[0][0]+1]
        global $custom_buttons_rename_menu[$custom_buttons_array[0][0]+1]
        global $custom_buttons_delete_menu[$custom_buttons_array[0][0]+1]
        global $custom_buttons_notes[$custom_buttons_array[0][0]+1]
        for $i = 1 to $custom_buttons_array[0][0]
            if StringInStr($custom_buttons_array[$i][1], "
|") then
                local $command_array = StringSplit($custom_buttons_array[$i][1], "
|")
                if IsArray($command_array) and $command_array[0] = 2 then
                    $custom_buttons_array[$i][1] = $command_array[1]
                    $custom_buttons_notes[$i] = $command_array[2]
                endif
            endif
        next
    endif
endfunc




; Create a grid of buttons from an array (probably created by IniReadSection())
; Supply the button array and the x/y coordinates (top-left origin of grid)..

func CreateButtonGrid(ByRef $buttons_array$start_x$start_y)

    if not IsArray($buttons_array) then return false
    local $i = 1, $row_num$bmenu
    $start_y += $buttons_y_shunt
    local $rows = int((110-$buttons_y_shunt) / ($custom_buttons_height+$button_spacing)) - 1 ; -1 cuz we start at 0 for rows

    for $j = 0 to $rows ; 3 rows max, to fit in GUI.

        if $custom_buttons_columns = "
auto" then
            $row_num = Round((($width - 150) - $grid_x)/$custom_buttons_width)-1
        else
            $row_num = $custom_buttons_columns-1
        endif

        ; x/y start at 0, buttons start at 1 ($i)
        for $k = 0 to $row_num    ; no limit here - how wide is your screen?

            local $cbutt_left = $start_x+(($custom_buttons_width+$button_spacing-1)*$k)
            local $cbutt_top = $start_y+(($custom_buttons_height+$button_spacing)*$j)

            local $custom_notes = "
"
            $custom_buttons[$i] = GUICtrlCreateButton($buttons_array[$i][0], $cbutt_left$cbutt_top$custom_buttons_width-2, $custom_buttons_height, BitOr($WS_TABSTOP,$BS_FLAT))
            GUICtrlSetonEvent(-1, "
ClickCustomButton")

            if $custom_buttons_notes[$i] then $custom_notes = $MSG_LF & $MSG_LF & '[' & StringReplace($custom_buttons_notes[$i], '\n', $MSG_LF & "
 ") & ']'
            ; tip options::  1 = normal balloon tip, above. 3 = center tip, under control, 7 = left-side center tip, below

            GUICtrlSetTipOptional(-1, $MSG_LF & $buttons_array[$i][1] & $custom_notes, "
 " & StringReplace($buttons_array[$i][0], "&", "") & ":", $tip_icon$tip_style)
            GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
            GUICtrlSetFont(-1, $custom_buttons_font_size)
            $bmenu = GUICtrlCreateContextMenu($custom_buttons[$i])
            $custom_buttons_delete_menu[$i] = GUICtrlCreateMenuItem("
Delete:  """ & $buttons_array[$i][0] & '"', $bmenu)
            GUICtrlSetOnEvent(-1, "DeleteButton")
            $custom_buttons_rename_menu[$i] = GUICtrlCreateMenuItem("Rename:  """ & $buttons_array[$i][0] & '"', $bmenu)
            GUICtrlSetOnEvent(-1, "
RenameButton")
            GUICtrlCreateMenuItem("
", $bmenu)
            GUICtrlCreateMenuItem("
Import Buttons", $bmenu)
            GUICtrlSetOnEvent(-1, "
ImportButtons")
            GUICtrlCreateMenuItem("
Export Buttons", $bmenu)
            GUICtrlSetOnEvent(-1, "
MenuExportButtons")

            if $i = $buttons_array[0][0] then exitloop 2
            $i += 1
        next
    next
endfunc



; Re-Build the Custom Button Grid to show new/updated buttons and columns..

func ReCreateButtonGrid(ByRef $buttons_array$start_x$start_y)

    ; no button array exists, return immediately..
    if not IsArray($buttons_array) then return false

    ; wipe existing buttons first..
    for $i = 1 to $buttons_array[0][0]
        GUICtrlDelete($custom_buttons[$i])
    next

    if $custom_buttons_columns then
        LoadCustomButtonData()
        CreateButtonGrid($buttons_array$start_x$start_y)
    endif
endfunc


func ClickCustomButton()
    DoCustomButton()
endfunc


; click once to add the code, a second time to remove..
func DoCustomButton($edit_only=false, $clicked=@GUI_CtrlId)

    local $do_edit$do_input_args
    if ce_IsPressed(10) or $edit_only then $do_edit = true
    if ce_IsPressed(11) then $do_input_args = true

    local $clicked_butt = InArray($custom_buttons$clicked)    ; returns index of match
    if $clicked_butt < 1 or $clicked_butt > $custom_buttons_array[0][0] then
        ConsoleAdd("
custom button error!")
        return
    endif

    local $this_command = $custom_buttons_array[$clicked_butt][1]

    if $do_edit then
        local $edit_butt_name = CorzFancyInputBox("
Custom Button Name.. ",    "Specify a name for the custom button.. " & $MSG_LF & _
                                                                            "
Enter a new name to create a new button.", $custom_buttons_array[$clicked_butt][0] , "" , 350 , 117, default, default, 0, $ffeGUI)
        if not $edit_butt_name then return

        local $edit_butt_args = CorzFancyInputBox("
Arguments.. ", "Enter the arguments for the " & '"' & StringReplace($edit_butt_name"&""") & "" &  " custom button.. "$this_command , "" , 480, 100, default, default, 0, $ffeGUI)
        if not $edit_butt_args then return

        local $edit_butt_notes = CorzFancyInputBox("notes.. ""Optionally, enter any explanatory notes for .. " & '"' & _
                                                    StringReplace($edit_butt_name, "
&", "") & '"..', $custom_buttons_notes[$clicked_butt] , "" , @DesktopWidth/2, 100, default, default, 0, $ffeGUI)
        if @error = 1 then
            if $custom_buttons_notes[$clicked_butt] then $edit_butt_notes = $custom_buttons_notes[$clicked_butt; they can cancel this dialog, old notes will be saved.
        endif

        local $insert = "updated custom button: "
        if $custom_buttons_array[$clicked_butt][0] <> $edit_butt_name then $insert = "Created NEW Button: "

        ; I usually avoid ternary operators, because they look like this..
        ;            (the expression)   ?    <-- question mark there                                <Do if True>                      colon there! ->  :                            <Do if False>
        ConsoleAdd( ($edit_butt_notes) ? $insert & '"' & $edit_butt_name & '"' & " command: " & $edit_butt_args & "    (" & $edit_butt_notes & ")" : $insert & '"' & $edit_butt_name & '"' & " command: " & $edit_butt_args)
        ; if we switched the order of things here, we wouldn't need this. I'll leave it "as an exercise".

        if $edit_butt_notes then $edit_butt_notes = "|" & $edit_butt_notes
        IniWrite($ini_path$NAME_BUTTONS$edit_butt_name$edit_butt_args & $edit_butt_notes)
        $this_command = $edit_butt_args
        ReCreateButtonGrid($custom_buttons_array$grid_x$grid_y)
        if $edit_only then return
    endif

    if StringLeft($this_command, 1) <> " " then $this_command = " " & $this_command

    local $my_control = $inp_extra_args
    if $do_input_args then $my_control = $inp_input_params

    ; existing extra arguments..
    local $current_params = GUICtrlRead($my_control)

    ; add/remove the command..
    if not StringInStr($current_params$this_command) then
        GUICtrlSetData($my_control$current_params & $this_command)
    else
        GUICtrlSetData($my_control, StringReplace($current_params$this_command""))
    endif
endfunc


func RenameButton()
    local $clicked_butt = InArray($custom_buttons_rename_menu, @GUI_CtrlId)    ; returns index of match (button 1 - 15, or whatever)
    if $clicked_butt < 1 or $clicked_butt > $custom_buttons_array[0][0] then
        ConsoleAdd("custom button out of bounds!")
        return
    endif
    DialogOpen()
    local $edit_butt_name = InputBox("Custom Button Name.. ""Specify a new name for this custom button.. "$custom_buttons_array[$clicked_butt][0] , "" , 300, 130, default, default, 0, $ffeGUI)
    DialogClose()
    if not $edit_butt_name or $edit_butt_name == $custom_buttons_array[$clicked_butt][0] then return ; case-sensitive match - user can change case of button ok

    local $tmp_inival = IniRead($ini_path$NAME_BUTTONS$custom_buttons_array[$clicked_butt][0], "")
    if not $tmp_inival then return

    if IniDelete($ini_path$NAME_BUTTONS$custom_buttons_array[$clicked_butt][0]) then
        if IniWrite($ini_path$NAME_BUTTONS$edit_butt_name$tmp_inival) then
            ConsoleAdd("custom button """ & $custom_buttons_array[$clicked_butt][0] & """ renamed to """ & $edit_butt_name & '"')
            ReCreateButtonGrid($custom_buttons_array$grid_x$grid_y)
        endif
    endif
endfunc


func DeleteButton()
    local $clicked_butt = InArray($custom_buttons_delete_menu, @GUI_CtrlId)
    if $clicked_butt < 1 or $clicked_butt > $custom_buttons_array[0][0] then
        ConsoleAdd("
custom button out of bounds!")
        return
    endif
    local $check_warn = IniReadCheckBoxValue($ini_path$my_name, "
warning_seen_butt_delete", $OFF)
    if $check_warn = $OFF then
        DialogOpen()
        MsgBox($MB_OK,    "
This is your only warning!", _
                        "
ffe isn't some namby-pamby, hold-your-hand baby-app, it's designed for WORK.  " & $MSG_LF & $MSG_LF & _
                        "
In future, when you choose to delete a custom button it will be DELETED, GONE," & $MSG_LF & _
                        "
VANISHED; NO AUTO-BACKUP, NO SECOND CHANCE. It's away to happen now..", 60, $ffeGUI)
        DialogClose()
        IniWriteCheckBoxValue($ini_path$my_name, "
warning_seen_butt_delete", $ON)
    endif
    if IniDelete($ini_path$NAME_BUTTONS$custom_buttons_array[$clicked_butt][0]) then
        ConsoleAdd("
deleted button: """ & $custom_buttons_array[$clicked_butt][0] & '"')
        ReCreateButtonGrid($custom_buttons_array$grid_x$grid_y)
    else
        ConsoleAdd("error deleting custom button: """ & $custom_buttons_array[$clicked_butt][0] & '"')
    endif
endfunc






; delayed start..

func DelayedDoIt()

    if $delay_start_at then
        TrayItemSetState($tray_toggle_delayed_start$OFF)
        $delay_start_at = false
        return false
    endif

    DialogOpen()
    local $event_mode = AutoItSetOption("
GUIOnEventMode", 0)
    local $coord_mode = AutoItSetOption("
GUICoordMode", 0)
    local $datetime_picker$now_date[7] = [False, @YEAR, @mon, @mday, @hour, @min, @sec]

    local $msg$tip$ttt$aw = 285, $ah = 190
    local $GUI_Delayed = GUICreate("
Delayed Start Options.. ", $aw$ah, -1, @DesktopHeight/4, $WS_CAPTION$WS_EX_TOPMOST$ffeGUI)

    local $dummy_first_control = GUICtrlCreateDummy()

    GUICtrlCreateLabel("
You can run the job at a later time." , 15, 15, $aw-25)
    GUICtrlCreateLabel("
Select the required countdown delay:" , 0, 20, $aw-25)

    $tip = "
Select the number of days to wait before starting the job "
    $ttt = "
Days Delay"
    local $lab_days = GUICtrlCreateLabel("
Days:", 0, 27)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    local $combo_delay_days = GUICtrlCreateCombo("
", 30, -2, 42)
    for $i = 1 to 365
        GUICtrlSetData(-1, $i)
    next
    GUICtrlSetTipOptional(-1, $tip$ttt)

    $tip = "
Select the number of hours to wait before starting the job "
    $ttt = "
Hours Delay"
    GUICtrlCreateLabel("
Hours:", 55, 2)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    local $combo_delay_hours = GUICtrlCreateCombo("
", 35, -2, 42)
    for $i = 1 to 24
        GUICtrlSetData(-1, $i)
    next
    GUICtrlSetTipOptional(-1, $tip$ttt)

    $tip = "
Select the number of minutes to wait before starting the job "
    $ttt = "
Minutes Delay"
    GUICtrlCreateLabel("
Minutes:", 50, 2)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    local $combo_delay_minutes = GUICtrlCreateCombo("
", 45, -2, 42)
    for $i = 1 to 60
        GUICtrlSetData(-1, $i)
    next
    GUICtrlSetTipOptional(-1, $tip$ttt)

    GUISetCoord(15, 75)
    GUICtrlCreateLabel("
Alternatively, pick a date/time directly:" , 0, 20, $aw-25)

    local $check_enable_datepick = GUICtrlCreateCheckbox("
", 0, 22, 26, 26, BitOr($BS_AUTOCHECKBOX$BS_PUSHLIKE,$BS_ICON))
    if @compiled then
        GUICtrlSetImage(-1,$me_app$time_icon_index, 0)
    else
        GUICtrlSetImage(-1, "
.\icons\ffe-time.ico", -1, 0)
    endif
    local $picker = GUICtrlCreateDate($GUI_Delayed, 30, 1, 226, 24, $DTS_UPDOWN)
    GUICtrlSetFont(-1, 9.5)
    GUICtrlSetState(-1, $GUI_DISABLE)
    $ttt = "
Direct Date & Time Input"
    GUICtrlSetTipOptional(-1, "
click here to instead enable direct date & time settings ", $ttt)

    ; grab the handle and we can use the groovy _GUICtrlDTP_* functions (similar, but better, to using _GUICtrlDTP_Create())..
    $datetime_picker = GUICtrlGetHandle($picker)
    _GUICtrlDTP_SetFormat($datetime_picker, "
ddd yyyy MMM dd  hh:mm ttt")
    _GUICtrlDTP_SetSystemTime($datetime_picker$now_date)

    local $range_array[14] = [true, @YEAR, @MON, @MDAY, @HOUR, @MIN, @SEC]
    _GUICtrlDTP_SetRange ($datetime_picker$range_array )

    local $dummy_last_control = GUICtrlCreateDummy()

    for $i = $dummy_first_control to $dummy_last_control
        GUICtrlSetResizing($i, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    next

    guiSetCoord($aw-172, $ah-28)
    local $GUI_Delayed_NO = GUICtrlCreateButton("
Cancel", 0, 0, 75, 20, BitOr($WS_TABSTOP$BS_FLAT))
    local $GUI_Delayed_OK = GUICtrlCreateButton("
Set Delay", 80, 0, 80, 20, BitOr($WS_TABSTOP$BS_FLAT$BS_DEFPUSHBUTTON))

    ControlFocus($ffeGUI, "
", $combo_delay_days)
    GUISetState(@SW_SHOW, $GUI_Delayed)

    while true

        sleep(10)
        $msg = GUIGetMsg()

        switch $msg

            case $GUI_EVENT_CLOSE$GUI_Delayed_NO
                exitloop

            case $GUI_Delayed_OK

                ; not required, but makes things clear..
                $delay_start_at = "
"

                if GUICtrlRead($check_enable_datepick) = $ON then
                    local $user_time_array = _GUICtrlDTP_GetSystemTime($datetime_picker)
                    _GUICtrlDTP_Destroy($datetime_picker)
                    $delay_start_at = $user_time_array[0] & "
/" & $user_time_array[1] & "/" & $user_time_array[2] & " " & $user_time_array[3] & ":" & $user_time_array[4] & ":" & $user_time_array[5]
                else
                    ; Countdown..
                    if GUICtrlRead($combo_delay_days) then
                        $delay_start_at = _DateAdd("
D", GUICtrlRead($combo_delay_days), _NowCalc())
                    else
                        $delay_start_at = _NowCalc()
                    endif
                    if GUICtrlRead($combo_delay_hours) then $delay_start_at = _DateAdd("
h", GUICtrlRead($combo_delay_hours), $delay_start_at)
                    if GUICtrlRead($combo_delay_minutes) then $delay_start_at = _DateAdd("
n", GUICtrlRead($combo_delay_minutes), $delay_start_at)
                endif

                exitloop

            case $check_enable_datepick

                local $state = $GUI_ENABLE

                if GUICtrlRead($check_enable_datepick) = $ON then
                    GUICtrlSetData($GUI_Delayed_OK, "
Set Time")
                    GUICtrlSetState($picker$GUI_ENABLE)
                    $state = $GUI_DISABLE
                else
                    GUICtrlSetData($GUI_Delayed_OK, "
Set Delay")
                    GUICtrlSetState($picker$GUI_DISABLE)
                endif

                for $i = $lab_days to $combo_delay_minutes
                    GUICtrlSetState($i$state)
                next
        endswitch

        dim $range_array[14] = [true, @YEAR, @MON, @MDAY, @HOUR, @MIN, @SEC]
        _GUICtrlDTP_SetRange($datetime_picker$range_array)

    wend

    GUIDelete($GUI_Delayed)
    AutoItSetOption("
GUIOnEventMode", $event_mode )
    AutoItSetOption("
GUICoordMode", $coord_mode)
    DialogClose()

    if $delay_start_at then TrayItemSetState($tray_toggle_delayed_start$ON)

endfunc




; Import / Export..


func ComboMenuImportData()
    MenuImportData()
endfunc
func TrayMenuImportData()
    MenuImportData()
endfunc
func ImportButtons()
    MenuImportData($NAME_BUTTONS)
endfunc

func MenuImportData($dtype="
")
    local $import_dir = IniRead($ini_path$my_name, "
import_dir", @MyDocumentsDir)
    local $i_type = "
data"
    if $dtype then $i_type = $dtype
    local $data_inifile = FileOpenDialog("
locate the " & $i_type & " file..", $import_dir, "Ini files (*.ini)|All files (*.*)", $FD_PATHMUSTEXIST, "", $ffeGUI)
    if not $data_inifile then return
    if not FileExists($data_inifile) then
        ConsoleAdd("
import aborted")
        return false
    endif
    IniWrite($ini_path$my_name, "
import_dir", GetParent($data_inifile))
    ImportData($data_inifile$dtype)
endfunc




func ImportData($import_file$dtype="
")

    if not FileExists($import_file) then return false

    ConsoleAdd($LOG_LF & "
beginning data import..")
    local $import_ini_sections = IniReadSectionNames($import_file)

    ; present dialog for importing:    main settings, presets, custom buttons..
    DialogOpen()
    local $user_choice = CorzImportExportChooser($import_ini_sections, "
import", 0, $dtype)
    local $err = @error
    DialogClose()
    if not $user_choice then
        local $msg = "
import aborted"
        if not $dtype then $dtype = "
usable data"
        if $err then $msg &= "
: no " & $dtype & " found in file"
        ConsoleAdd($msg)
        return false
    endif

    local $do_add=false, $r_type$do_added=false
    local $tmp_ini = @TempDir & "
\ffe-import-temp.ini"

    local $restart_required = false
    local $restart_settings = StringSplit("
image_buttons,sort_presets_list,do_tooltips,console_wordwrap", ",")

    FileCopy($ini_path$tmp_ini)

    for $i = 1 to $import_ini_sections[0]

        $do_add = false

        switch $import_ini_sections[$i]
            case $my_name
                if StringInStr($user_choice$NAME_SETTINGS) then
                    $do_add = true
                    $r_type = $NAME_SETTINGS
                endif
            case $NAME_BUTTONS
                if StringInStr($user_choice$NAME_BUTTONS) then
                    $do_add = true
                    $r_type = $NAME_BUTTONS
                endif
            case else
                if StringInStr($user_choice$NAME_PRESETS) and not StringInStr($import_ini_sections[$i], "
--backup--") then
                    $do_add = true
                    $r_type = "
preset" & "" & $import_ini_sections[$i]
                endif
        endswitch

        ; we have something to add from this section..

        if $do_add then

            local $this_section = IniReadSection($import_file$import_ini_sections[$i])
            if not @error then

                switch $import_ini_sections[$i]

                    ; main settings..
                    case $my_name
                        DialogOpen()
                        local $warn_main_settings = MsgBox($MB_OKCANCEL+$MB_ICONWARNING, "
Overwrite MAIN Settings?!?", _
                                                                                            "
This will COMPLETELY OVERWRITE MAIN FFE SETTINGS!!!" & $MSG_LF & _
                                                                                            "
(but only those settings present in the imported ini file)" & $MSG_LF & $MSG_LF & _
                                                                                            "
Are you ABSOLUTELY sure you wish to do this? ", 30, $ffeGUI)
                        DialogClose()
                        if $warn_main_settings = 1 then
                            for $st = 1 to $this_section[0][0]
                                if IniWrite($ini_path$my_name$this_section[$st][0], $this_section[$st][1]) then
                                    ConsoleAdd("
wrote setting: " & $this_section[$st][0] & "=" & $this_section[$st][1])
                                    ; Ahhhh.. NOW we see the beauty of matching ini pref and var names...
                                    Assign($this_section[$st][0], $this_section[$st][1], $ASSIGN_EXISTFAIL)
                                    if InArray($restart_settings$this_section[$st][0]) then $restart_required = true
                                    $do_added = true
                                endif
                            next
                        endif

                    case $NAME_BUTTONS
                        ; we add/overwrite individual buttons, not simply replace the section..
                        for $st = 1 to $this_section[0][0]
                            if IniWrite($ini_path$NAME_BUTTONS$this_section[$st][0], $this_section[$st][1]) then
                                ConsoleAdd("
wrote button: " & $this_section[$st][0] & "=" & $this_section[$st][1])
                                $do_added = true
                            endif
                        next

                    ; preset..
                    case else
                        if IniWriteSection($ini_path$import_ini_sections[$i], $this_section) then
                            ConsoleAdd("
imported " & $r_type)
                            $do_added = true
                        endif
                endswitch
            endif
        endif
    next

    if StringInStr($user_choice$NAME_PRESETS) then UpdatePresetsCombo()
    if StringInStr($user_choice$NAME_BUTTONS) then ReCreateButtonGrid($custom_buttons_array$grid_x$grid_y)

    if $do_added then
        local $bax_ini = GetParent($ini_path) & "
\PRE-IMPORT [" & @YEAR & "-" & @MON & "-" & @MDAY & "@" & @hour & "." & @min & "] ffe.ini"
        if $restart_required then ConsoleAdd("
init settings detected - restart to see changes")
        if FileMove($tmp_ini$bax_ini) then
            ConsoleAdd("
old ffe.ini backed up to: " & $bax_ini)
        endif
    else
        FileDelete($tmp_ini)
    endif

endfunc




func MenuExportData()
    ExportData()
endfunc

func TrayMenuExportData()
    ExportData()
endfunc

func MenuExportButtons()
    ExportData($NAME_BUTTONS)
endfunc

func ExportData($dtype="
")

    $presets = IniReadSectionNames($ini_path)
    if not IsArray($presets) then return

    ConsoleAdd($LOG_LF & "
beginning data export..")
    local $tmp_ini_path = @TempDir & "
\ffe-data-export.ini"
    if FileExists($tmp_ini_path) then FileDelete($tmp_ini_path)

    ; present dialog for exporting:    main settings, presets, custom buttons..
    DialogOpen()
    local $user_choice = CorzImportExportChooser($presets, "
export", 0, $dtype)
    DialogClose()

    if not $user_choice then
        ConsoleAdd("
export aborted")
        return false
    endif
    local $do_add=false, $r_type$do_added=false

    ; run through section-by-section..
    for $i = 1 to $presets[0]

        $do_add = false

        switch $presets[$i]
            case $my_name
                if StringInStr($user_choice$NAME_SETTINGS) then
                    $do_add = true
                    $r_type = $NAME_SETTINGS
                endif
            case $NAME_BUTTONS
                if StringInStr($user_choice$NAME_BUTTONS) then
                    $do_add = true
                    $r_type = $NAME_BUTTONS
                endif
            case else
                if StringInStr($user_choice$NAME_PRESETS) and not StringInStr($presets[$i], "
--backup--") then
                    $do_add = true
                    $r_type = "
preset" & "" & $presets[$i]
                endif
        endswitch

        if $do_add then

            ; ANY additions will set this flag.
            $do_added = true

            local $this_section = IniReadSection($ini_path$presets[$i])
            if not @error then
                switch $presets[$i]
                    ; main settings..
                    case $my_name
                        if IniWriteSection($tmp_ini_path$my_name$this_section) then ConsoleAdd("
exported " & $r_type)
                    ; custom buttons..
                    case $NAME_BUTTONS
                        if IniWriteSection($tmp_ini_path$NAME_BUTTONS$this_section) then ConsoleAdd("
exported " & $r_type)
                    ; preset..
                    case else
                        if not InArray($not_presets$presets[$i]) and StringLeft($presets[$i], 10) <> "
--backup--" then
                            if IniWriteSection($tmp_ini_path$presets[$i], $this_section) then ConsoleAdd("
exporting preset: " & $r_type)
                        endif
                endswitch
            endif
        endif
    next

    if $do_added then
        local $export_name = "
ffe-export-"
        if StringInStr($user_choice$NAME_SETTINGS) then $export_name &= StringLower(StringReplace($NAME_SETTINGS, "
 ", "-")) & "-"
        if StringInStr($user_choice$NAME_BUTTONS) then $export_name &= StringLower(StringReplace($NAME_BUTTONS, "
 ", "-")) & "-"
        if StringInStr($user_choice$NAME_PRESETS) then $export_name &= StringLower(StringReplace($NAME_PRESETS, "
 ", "-")) & "-"
        CRT($export_name, "
-")
        local $export_dir = IniRead($ini_path$my_name, "
export_dir", @MyDocumentsDir)
        DialogOpen()
        local $saved_file = FileSaveDialog("
specify a location to save the file..", $export_dir, "Ini files (*.ini)|All files (*.*)", $FD_PROMPTOVERWRITE , $export_name & ".ini", $ffeGUI)
        DialogClose()
        if $saved_file then
            IniWrite($ini_path$my_name, "
export_dir", GetParent($saved_file))
            local $i_type = "
data"
            if $dtype then $i_type = $dtype
            if FileMove($tmp_ini_path$saved_file, 9) then ConsoleAdd("
finished exporting " & $i_type & " to: " & $saved_file)
        else
            ConsoleAdd("
well, that was fun.")
        endif
    endif

endfunc






; Custom inport/export user chooser..

; returns a string containing relebant substrings, "main settings", "presets" and "custom buttons".
; e.g., if everything is selected the string is, "mainpresetsbuttons".

func CorzImportExportChooser(ByRef $ini_sections_array$mode="
import", $timeout=0, $dtype="")

    if not IsArray($ini_sections_array) then
        if $mode = "
import" then
            ConsoleAdd("
no ini [sections] found to import!")
        else
            ConsoleAdd("
a serious ini-based error of some unknown description occured")
        endif
        return false
    endif

    local $ie_title = "
ffe " & $mode & " choices.."
    local $prompt = "
Which data do you wish to " & $mode & "?"
    local $err = 0, $i_type$no_match = false

    local $ie_x = IniRead($ini_path$my_name, "
import_export_chooser_x", $x + 6)
    local $ie_y = IniRead($ini_path$my_name, "
import_export_chooser_y", $y + 26)
    local $ie_w = IniRead($ini_path$my_name, "
import_export_chooser_width", 300)

    local $ie_h = 170
    local $min_w = 300
    if $ie_w < $min_w then $ie_w = $min_w


    local $return = false, $last_event_mode = AutoItSetOption("
GUIOnEventMode", 0)
    local $coord = AutoItSetOption("
GUICoordMode", 0)

    local $style = BitOr($WS_CAPTION$WS_SYSMENU$WS_POPUP$WS_SIZEBOX)
    local $styleX = BitOr($WS_EX_CONTEXTHELP$WS_EX_TOPMOST$WS_EX_TOOLWINDOW)

    local $ie_GUI = GUICreate($ie_title$ie_w$ie_h$ie_x$ie_y$style$styleX$ffeGUI)
    GUIsetFont(9)

    local $but_Cancel = GUICtrlCreateButton("
Cancel", 6, $ie_h-26, 60, 22)
    GUICtrlSetState(-1, $GUI_ONTOP)
    GUICtrlSetResizing(-1, $GUI_DOCKSTATEBAR+$GUI_DOCKLEFT+$GUI_DOCKWIDTH)

    local $but_OK = GUICtrlCreateButton("
OK", $ie_w-60, 0, 50, 22, $BS_DEFPUSHBUTTON)
    GUICtrlSetState(-1, $GUI_ONTOP)
    GUICtrlSetResizing(-1, $GUI_DOCKSTATEBAR+$GUI_DOCKWIDTH+$GUI_DOCKRIGHT)


    GUISetCoord(10, 7)

    GUICtrlCreateLabel($prompt, 0, 0, $ie_w-30)
    GUICtrlSetFont(-1, default, 800)
    GUICtrlSetResizing(-1, $GUI_DOCKALL)


    GUISetCoord(20, 27)
    local $chk_everything$chk_main_settings$chk_presets$chk_custom_buttons$got_main=false, $got_presets=false, $got_buttons=false, $t_count=0



    $i_type = $NAME_SETTINGS
    $chk_main_settings = GUICtrlCreateCheckbox(_StringProper($i_type), 0, 0)
    GUICtrlSetResizing(-1, $GUI_DOCKALL)
    if InArray($ini_sections_array$my_name) then
        $got_main = true
        $t_count += 1
        if $dtype = $i_type then GUICtrlSetState(-1, $ON)
    else
        if $dtype = $i_type then $no_match = true
        GUICtrlSetState(-1, $GUI_DISABLE)
    endif


    $i_type = $NAME_PRESETS
    $chk_presets = GUICtrlCreateCheckbox(_StringProper($i_type), 0, 22)
    GUICtrlSetResizing(-1, $GUI_DOCKALL)

    if HasPresets($ini_sections_array) then
        $got_presets = true
        $t_count += 1
        if $dtype = $i_type then GUICtrlSetState(-1, $ON)
    else
        if $dtype = $i_type then $no_match = true
        GUICtrlSetState(-1, $GUI_DISABLE)
    endif


    $i_type = $NAME_BUTTONS
    $chk_custom_buttons = GUICtrlCreateCheckbox(_StringProper($i_type), 0, 22)
    GUICtrlSetResizing(-1, $GUI_DOCKALL)
    if InArray($ini_sections_array$i_type) then
        $got_buttons = true
        $t_count += 1
        if $dtype = $i_type then GUICtrlSetState(-1, $ON)
    else
        if $dtype = $i_type then $no_match = true
        GUICtrlSetState(-1, $GUI_DISABLE)
    endif


    if $t_count > 1 then
        $chk_everything = GUICtrlCreateCheckbox("
All", 120, 0)
        GUICtrlSetResizing(-1, $GUI_DOCKALL)
    endif


    if $no_match then

        ; no matching (specific) sections in specified import file..
        $err = 1


    ; we have a match..
    else

        ; single type specified (from contextual control)
        if $dtype then

            ; no choosing required., return type directly.
            $return = $dtype

        else

            ; OK, let's CHOOSE...

            GUISetState(@SW_SHOW, $ie_GUI)
            WinMove($ie_title, "
", default, default, $ie_w$ie_h)

            if $timeout <> 0 then local $dialog_begin = TimerInit()
            local $size_array$got_ok=false
            WinActivate($ie_title)

            while true

                switch GUIGetMsg()

                    case $GUI_EVENT_RESIZED
                        $size_array = WinGetPos($ie_title)
                        if not IsArray($size_array) then continueloop
                        if $size_array[2] < $min_w then WinMove($ie_title, "
", default, default, $min_w$ie_h)
                        if $size_array[3] <> $ie_h then WinMove($ie_title, "
", default, default, $min_w$ie_h)

                    case $GUI_EVENT_CLOSE$but_Cancel
                        $return = "
"
                        exitloop

                    case $but_OK
                        if GUICtrlRead($chk_main_settings) = $ON then $return &= $NAME_SETTINGS
                        if GUICtrlRead($chk_presets) = $ON then $return &= $NAME_PRESETS
                        if GUICtrlRead($chk_custom_buttons) = $ON then $return &= $NAME_BUTTONS
                        $got_ok = true
                        exitloop


                    case $chk_everything
                        if GUICtrlRead($chk_everything) = $OFF then
                            GUICtrlSetState($chk_main_settings$OFF)
                            GUICtrlSetState($chk_presets$OFF)
                            GUICtrlSetState($chk_custom_buttons$OFF)
                        else
                            if $got_main then GUICtrlSetState($chk_main_settings$ON)
                            if $got_presets then GUICtrlSetState($chk_presets$ON)
                            if $got_buttons then GUICtrlSetState($chk_custom_buttons$ON)
                        endif
                endswitch

                if $timeout <> 0 then
                    if TimerDiff($dialog_begin)/1000 > $timeout then exitloop
                endif

            wend

            if $return or $got_ok then

                ; save position/size for next time..
                $size_array = WinGetPos($ie_title)    ; 0-1-2-3:x-y-w-h
                if IsArray($size_array) then
                    if $size_array[0] then IniWrite($ini_path$my_name, "
import_export_chooser_x", $size_array[0])
                    if $size_array[1] then IniWrite($ini_path$my_name, "
import_export_chooser_y", $size_array[1])
                    if $size_array[2] then IniWrite($ini_path$my_name, "
import_export_chooser_width", $size_array[2])
                endif

            endif

        endif

    endif

    AutoItSetOption("
GUIOnEventMode", $last_event_mode)
    AutoItSetOption("
GUICoordMode", $coord)
    GUIDelete($ie_GUI)

    return SetError($err, 0, $return)

endfunc


; checks if a given list of ini sections contains presets (return true) or is just settings and custom buttons (return false)..
func HasPresets(ByRef $ini_section_names_array)
    if not IsArray($ini_section_names_array) then return false
    for $i = 1 to $ini_section_names_array[0]
        if $ini_section_names_array[$i] = $my_name or $ini_section_names_array[$i]  = $NAME_BUTTONS then continueloop
        return true
    next
endfunc






; clear all the paramater dials and switches back to their defaults..

func ClickButtWipeSettings()
    WipeSettings()
    DoArgsCreate()
endfunc

func WipeSettings()
    GUICtrlSetData($inp_input_params, "
")
    GUICtrlSetData($combo_v_codec$video_codecs)
    GUICtrlSetData($combo_v_bitrate$video_bitrates)
    GUICtrlSetData($combo_frames_per_second$frames_per_second)
    GUICtrlSetData($inp_x_size, "
")
    GUICtrlSetData($inp_y_size, "
")
    GUICtrlSetData($inp_crop_top, "
")
    GUICtrlSetData($inp_crop_left, "
")
    GUICtrlSetData($inp_crop_right, "
")
    GUICtrlSetData($inp_crop_bottom, "
")
    GUICtrlSetData($combo_a_codec$audio_codecs)
    GUICtrlSetData($combo_a_bitrate$audio_bitrates)
    GUICtrlSetData($combo_target_type$target_types)
    GUICtrlSetData($combo_preset_resizes$preset_resizes)
    GUICtrlSetData($inp_extra_args, "
")
    ; note GUICtrlSetSTATE! ..
    GUICtrlSetState($check_resize_first$OFF)
endfunc

;2do - think about whether inherited settings like job buttons should follow this wipe/add toggle.



func AddShortTestParam()
    if ce_IsPressed(10) then UserEditShortTestParams()
    local $current_params = GUICtrlRead($inp_extra_args)
    local $this_command = "
 " & "-vframes " & $short_test_frames
    if not StringInStr($current_params$this_command) then
        if not StringInStr($current_params, "
vframes") then GUICtrlSetData($inp_extra_args$current_params & $this_command)
    else
        GUICtrlSetData($inp_extra_args, StringReplace($current_params$this_command, "
"))
    endif
endfunc


func UserEditShortTestParams()
    DialogOpen()
    local $user_frames = InputBox("
Short Test Frames.. ", "Specify a number of frames for the short test button.. ", $short_test_frames , "" , 350, 130, default, default, 0, $ffeGUI)
    DialogClose()
    if $user_frames then
        $user_frames = Number($user_frames)
        if $user_frames < 1 or $user_frames > 10000 then $user_frames = 300
        $short_test_frames = $user_frames
        IniWrite($ini_path$my_name, "
short_test_frames", $short_test_frames)
        GUICtrlSetTipOptional($butt_quicktest ,    "
 Adds some parameters to process only the first " & $short_test_frames & " frames of video. " & $MSG_LF & _
                                                "
 Feel free to edit this number! (hold SHIFT key while you click to do this first) ", "Add Quick Test Parameters")
    endif
endfunc



func HelpMeNow()

    local $this_helpfile$this_command$console_out
    local $clicked_butt = InArray($help_butts, @GUI_CtrlId)

    if $clicked_butt < 1 or $clicked_butt > 5 then
        SetConsoleOutput("
ERROR!")
        return
    endif

    ; SHIFT+Click to open in viewer/editor..    (grab NOW!)
    local $do_open = false
    if ce_IsPressed(10) then $do_open = true

    local $my_help_entry = StringSplit($help_texts[$clicked_butt], "
|")

    $this_helpfile = $my_help_entry[2]
    $this_command = $my_help_entry[3]

    local $err$full_log = "
"
    local $nfo_loc = $data_parent & "
\" & $this_helpfile
    if $portable then $nfo_loc = @ScriptDir & "
\" & $this_helpfile

    ; always grab fresh each run, but grab only once (ffmpeg binary assumed not to be updated in this time).
    if not StringInStr($got_helps$this_helpfile) or not FileExists($nfo_loc) then

        ; run ffmpeg with help flags (capture stdout)..

        local $gethelp = Run($ffmpeg_binary & "
 " & $this_command, "", @SW_HIDE, $STDOUT_CHILD)
        while true
            $err = false
            $console_out = StdoutRead($gethelp)
            $err = @error
            if $console_out then $full_log &= $console_out
            if $err then exitloop
            Sleep(5)
        wend
        StdioClose($gethelp)

        ; just in case..
        ProcessClose($gethelp)

        ; write out help text to .nfo file..
        if FileExists($nfo_loc) then FileDelete($nfo_loc)
        local $help_file_open = FileOpen($nfo_loc$FO_OVERWRITE$FO_CREATEPATH+$FO_UTF8_NOBOM)
        FileWrite($help_file_open$full_log)
        FileClose($help_file_open)

        ; add this help file to "already seen" list
        if not StringInStr($got_helps$this_helpfile) then $got_helps &= $this_helpfile & "
|"

    else
        ; read existing help file..
        $full_log = FileRead($nfo_loc)
    endif

    if $do_open then
        ShellExecute($nfo_loc)
    else
        SetConsoleOutput($full_log, true)
    endif

endfunc


func ShowOutputButts()
    GUICtrlSetState($butt_copy2clip$GUI_SHOW)
    GUICtrlSetState($butt_clearout$GUI_SHOW)
    GUICtrlSetState($butt_find$GUI_ENABLE)
    GUICtrlSetState($butt_find$GUI_SHOW)
endfunc

func HideOutputButts()
    GUICtrlSetState($butt_copy2clip$GUI_HIDE)
    GUICtrlSetState($butt_clearout$GUI_HIDE)
    GUICtrlSetState($butt_find$GUI_HIDE)
    GUICtrlSetState($butt_find$GUI_DISABLE)
endfunc



func EnableActiveInputs()
    if not $ffmpeg_binary then return
    GUICtrlSetState($butt_doit$GUI_ENABLE)
    GUICtrlSetState($inp_inputfile$GUI_ENABLE)
    GUICtrlSetState($butt_quicktest$GUI_ENABLE)
    GUICtrlSetState($butt_mediareport$GUI_ENABLE)
    if IsArray($help_texts) then
        for $i = 1 to $help_texts[0]
            GUICtrlSetState($help_butts[$i], $GUI_ENABLE)
        next
    endif
    if $do_output = $ON then GUICtrlSetState($inp_outputfile$GUI_ENABLE)
    $generate_script = false
endfunc

func DisableActiveInputs()
    GUICtrlSetState($butt_doit$GUI_DISABLE)
    GUICtrlSetState($inp_inputfile$GUI_DISABLE)
    GUICtrlSetState($butt_quicktest$GUI_DISABLE)
    GUICtrlSetState($butt_mediareport$GUI_DISABLE)
    if IsArray($help_texts) then
        for $i = 1 to $help_texts[0]
            GUICtrlSetState($help_butts[$i], $GUI_DISABLE)
        next
    endif
    GUICtrlSetState($inp_outputfile$GUI_DISABLE)
endfunc


func ReturnNow($msg="
error", $retval=-1)
    ConsoleAdd($msg)
    SetHotKeys()
    $do_drop_window = $drop_win_state
    ShowOutputButts()
    EnableActiveInputs()
    WinSetTitle($ffeGUI, "
", $my_title)
    return $retval
endfunc





func CopyOutput()
    if GUICtrlRead($edit_console_output) then ClipPut(GUICtrlRead($edit_console_output))
endfunc


;2do - logging for non-output files (i.e. image sequences)

func SaveOutput($output_data)

    if not $output_data then return false
    local $log_outputfile

    $job_log_location = DeTokenize(IniRead($ini_path$current_preset, "
job_log_location", $job_log_location))
    if not $job_log_location then $job_log_location = "
@datadir\logs"
    CRT($job_log_location)

    local $use_job_log_location = $job_log_location & "
\"
    if IsWild($user_inputfile) then $use_job_log_location &= "
[BATCH]_"

    if IsWild($user_outputfile) then
        $log_outputfile = $use_job_log_location & CleanPath(RemoveExtension($outputfile)) & $matof_separator & $matof_string & "
.log"
    else
        $log_outputfile = $use_job_log_location & RemoveExtension(BaseName($outputfile)) & "
.log"
    endif

    local $dl_append = 10
    if $job_log_append = $ON then $dl_append = 9
    local $my_log_file = FileOpen($log_outputfile$dl_append)
    FileWriteLine($my_log_file$output_data)
    FileClose($my_log_file)
endfunc



func ClearOutput()
    SetConsoleOutput("
")
endfunc



func OpenSourceDir()
    local $srcdir = GetParent($inputfile)
    if IsDir($srcdir) then
        ShellExecute($srcdir)
    else
        GuiCtrlSetColor($lab_inputfile$COLOR_RED)
        AdlibRegister("
EndWarning", 150)
    endif
endfunc

func EndWarning()
    GuiCtrlSetColor($lab_inputfile, default)
endfunc





; file/folder dropped onto some input..

func GetDroppedItem()

    if @GUI_DRAGID = -1 then

        switch @GUI_DROPID

            case $inp_inputfile$lab_main_drop$hGIF

                if IsAllowedImage(@GUI_DRAGFILE) then
                    $drop_win_image = @GUI_DRAGFILE
                    if $fluid_image_menu = $OFF and $auto_copy_images = $ON then
                        FileCopy(@GUI_DRAGFILE, $drop_win_image_folder & "
\" & BaseName(@GUI_DRAGFILE))
                        if FileExists($drop_win_image_folder & "
\" & BaseName(@GUI_DRAGFILE)) then
                            $drop_win_image = $drop_win_image_folder & "
\" & BaseName(@GUI_DRAGFILE)
                        else
                            ConsoleAdd("
error copying image to fixed drop images directory")
                        endif
                    endif
                    $switching = true
                    Check4GIFmethod()
                    HideDropWindow()
                else

                    if StringInStr(FileGetAttrib(@GUI_DRAGFILE), "
D") then
                        GUICtrlSetData($inp_inputfile, @GUI_DRAGFILE & "
\*.*")
                    else
                        if BaseName(@GUI_DRAGFILE) = "
ffmpeg.exe" then
                            SetFFMpegBinaryLocation(@GUI_DRAGFILE)
                            GUICtrlSetData($inp_inputfile, StringReplace(GUICtrlRead($inp_inputfile), @GUI_DRAGFILE, "
"))
                            return
                        else
                            ; replace..
                            GUICtrlSetData($inp_inputfile, @GUI_DRAGFILE)
                        endif
                    endif
                endif

                UpdateInput()

                if $drop_command then
                    switch $drop_command
                        case "
Go"
                            DoIt()
                        case "
Report"
                            if not StringInStr(FileGetAttrib(@GUI_DRAGFILE), "
D") then GenerateReport()
                    endswitch
                    DoArgsCreate()
                endif


            case $inp_outputfile
                ; replace data..
                GUICtrlSetData($inp_outputfile, @GUI_DRAGFILE)
                $ini_outputfile = @GUI_DRAGFILE
                DoArgsCreate()


            case $combo_presets
                ImportData(@GUI_DRAGFILE)
                IniWrite($ini_path$my_name, "
import_dir", GetParent(@GUI_DRAGFILE))

            case $inp_input_params
                ; default behaviour (drop path @ caret)

            case $edit_console_output
                ; ditto

        endswitch

    else
        ; @GUI_DRAGID <> -1
        return false
    endif

endfunc



; browse for an input file..

func BrowseForInputFile()
    local $input_dir = IniRead($ini_path$my_name, "
input_dir", @MyDocumentsDir)
    DialogOpen()
    local $tmp_ipf = FileOpenDialog("
locate the input file..", $input_dir$file_types$FD_PATHMUSTEXIST, "", $ffeGUI)
    DialogClose()
    if not $tmp_ipf then return false
    IniWrite($ini_path$my_name, "
input_dir", GetParent($tmp_ipf))
    $inputfile = $tmp_ipf
    GUICtrlSetData($inp_inputfile$inputfile)
    DoArgsCreate()
    return true
endfunc


; browse for an output file..

func BrowseForOutputFile()
    local $save_output_dir = IniRead($ini_path$my_name, "
save_output_dir", @MyDocumentsDir)
    DialogOpen()
    local $tmp_output = FileSaveDialog("
specify the output file..", $save_output_dir$file_types, 0, "", $ffeGUI)
    DialogClose()
    if not $tmp_output then return 0
    if not StringInStr($tmp_output, "
.") then $tmp_output &= "." & $default_extension
    IniWrite($ini_path$my_name, "
save_output_dir", GetParent($tmp_output))
    $outputfile = $tmp_output
    GUICtrlSetData($inp_outputfile$outputfile)
    DoArgsCreate()
    return true
endfunc


func MenuChooseFixedImageLocation()
    local $choose_root = "
::{450D8FBA-AD25-11D0-98A8-0800361B1103}; "My Documents"
    if $drop_win_image_folder then $choose_root = $drop_win_image_folder
    DialogOpen()
    local $user_choose_folder = FileSelectFolder("
Select a new image folder (for the FIXED menu)", $choose_root, 7, $choose_root$ffeGUI)
    local $err = @error
    DialogClose()
    if not $user_choose_folder then
        if $err then
            ConsoleAdd("
select image folder aborted: user cancelled")
        else
            ConsoleAdd("
select image folder aborted: invalid selection")
        endif
        return
    endif
    if FileExists($user_choose_folder) then
        $drop_win_image_folder = $user_choose_folder
        ConsoleAdd("
fixed menu image folder set to: " & $drop_win_image_folder)
        IniWrite($ini_path$my_name, "
drop_win_image_folder", $drop_win_image_folder)
        GetDropWinImageFolder()
        HideDropWindow()
    endif
endfunc


; add resizing parameters..

func AddSizing()

    local $resize = "
"
    local $matof_tmp_string = "
"

    local $x_size = GUICtrlRead($inp_x_size)
    local $y_size = GUICtrlRead($inp_y_size)

    if $x_size and $y_size then
        $resize = $x_size & "
x" & $y_size
        $matof_tmp_string ="
[" & $resize & "]"
    endif

    if GUICtrlRead($combo_preset_resizes) then
        $resize = GUICtrlRead($combo_preset_resizes)
        $matof_tmp_string ="
[size=" & $resize & "]"
    endif

    $matof_string &= $matof_tmp_string
    if $resize then $extra_args &= "
 -s " & $resize
endfunc



; add cropping parameters..

func AddCropping()

    local $matof_tmp_string = "
[crop "

    if GUICtrlRead($inp_crop_top) then
        $extra_args &= "
 -croptop " & GUICtrlRead($inp_crop_top)
        $matof_tmp_string &= "
t=" & GUICtrlRead($inp_crop_top) & ";"
    endif
    if GUICtrlRead($inp_crop_right) then
        $extra_args &= "
 -cropright " & GUICtrlRead($inp_crop_right)
        $matof_tmp_string &= "
r=" & GUICtrlRead($inp_crop_right) & ";"
    endif
    if GUICtrlRead($inp_crop_bottom) then
        $extra_args &= "
 -cropbottom " & GUICtrlRead($inp_crop_bottom)
        $matof_tmp_string &= "
b=" & GUICtrlRead($inp_crop_bottom) & ";"
    endif
    if GUICtrlRead($inp_crop_left) then
        $extra_args &= "
 -cropleft " & GUICtrlRead($inp_crop_left)
        $matof_tmp_string &= "
l=" & GUICtrlRead($inp_crop_left) & ";"
    endif
    ; trim space or comma..
    $matof_tmp_string = StringTrimRight($matof_tmp_string, 1)
    $matof_tmp_string &= "
]"

    if $matof_tmp_string <> "
[crop]" then $matof_string &= $matof_tmp_string
endfunc




; check for correct extension (by codec)..

func GetExtFromCodec($v_codec$file_name="
")

    local $this_ext

    if not StringInStr($extra_args, "
-vn") then

        ;    VIDEO:
        ;    copy|a64multi|a64multi5|alias_pix|amv|apng|asv1|asv2|avrp|avui|ayuv|bmp|libxavs|cinepak|cljr|libschroedinger|dnxhd|dpx|dvvideo|ffv1|ffvhuff|flashsv|flashsv2|
        ;    flv|gif|h261|h263|h263p|libx264|libx264rgb|libx265|huffyuv|jpeg2000|libopenjpeg|jpegls|ljpeg|mjpeg|mpeg1video|mpeg2video|mpeg4|libxvid|msmpeg4v2|msmpeg4|
        ;    msvideo1|pam|pbm|pcx|pgm|pgmyuv|png|ppm|prores|prores_aw|prores_ks|qtrle|r10k|r210|rawvideo|roqvideo|rv10|rv20|sgi|snow|sunrast|svq1|targa|libtheora|tiff|
        ;    utvideo|v210|v308|v408|v410|libvpx|libvpx-vp9|libwebp|wmv1|wmv2|xbm|xface|xwd|y41p|yuv4|- disable video -

        switch true
            case $v_codec = "
copy"
                $this_ext = GetExtension($inputfile)
                if IsWild($this_ext) then $this_ext = $default_extension

            case StringInStr($v_codec, "
xvid"), StringInStr($v_codec, "mjpeg")
                $this_ext = "
avi"

            case StringInStr($v_codec, "
mpeg4")
                $this_ext = "
mp4"

            case StringInStr($v_codec, "
mpeg")
                $this_ext = "
mpg"

            case StringInStr($v_codec, "
flv"), StringInStr($v_codec, "flash")
                $this_ext = "
flv"

            case StringInStr($v_codec, "
wmv"), StringInStr($v_codec, "msvideo")
                $this_ext = "
wmv"

            case StringInStr($v_codec, "
vp"), StringInStr($v_codec, "webp")
                $this_ext = "
webm"

            case else ; mkv
                $this_ext = $default_extension
        endswitch


    ; video is disabled..
    ; try to guess some likely types..

    else

        local $a_codec_inp = GUICtrlRead($combo_a_codec)

        if $a_codec_inp = "
copy" then
            ; already exists in "$known_files" (associative array), use the pre-determined extension..
            if AAExists($known_files$file_name) then
                $this_ext = AAItem($known_files$file_name)
            ; unknown file - run probe and find out what audio codec is used..
            else
                $this_ext = ProbeFileForCodec($file_name)
                $this_ext = GetCodecExtFromCodecName($this_ext)
                ; store file = audio-ext key=val pair in AA
                if $this_ext then AAAdd($known_files$file_name$this_ext)
            endif
        else
            $this_ext = GetCodecExtFromCodecName($a_codec_inp)
        endif
    endif

    return $this_ext

endfunc




; Use ffprobe to grab the audio codec name..

func ProbeFileForCodec($file)
    if not FileExists($file) then return false

    ; already probed this file.. (this should have been checked before calling!)
    if AAExists($known_files$file) then return AAItem($known_files$file)

    if IsWild($file) then return false

    ; if not already in $known_files Associative Array - run probe and find out what audio codec is used..
    local $probe_data$err

    if FileExists($ffprobe_loc) then ; select first audio stream..
        local $probe_file = Run( $ffprobe_loc & "
 -v error -select_streams a:0 -show_entries stream=codec_name " & ' "'& $file & '"', "", @SW_HIDE, $STDOUT_CHILD)
    else
        return false
    endif

    local $console_out
    while true
        $err = false
        $console_out = StdoutRead($probe_file)
        $err = @error
        if $console_out then $probe_data &= $console_out
        if $err then exitloop
        Sleep(5)
    wend
    StdioClose($probe_file)
    ProcessClose($probe_file)

    if not StringInStr($probe_data, "
codec_name") then return false    ; better than simply checking existence of variable

    $probe_data = StringSplit($probe_data, "
=")
    ; could specify StringInStr(,,-3), but best to let StringStripWS() handle /whatever/ line-break comes - who knows how you built your ffprobe!
    return StringStripWS(StringMid($probe_data[2], 1, StringInStr($probe_data[2], "
[")-1), 3)

endfunc


; Convert codec names into usable audio file extensions..

;    AUDIO:
;    copy|aac|libvo_aacenc|ac3|ac3_fixed|adpcm_adx|g722|g726|adpcm_ima_qt|adpcm_ima_wav|adpcm_ms|adpcm_swf|adpcm_yamaha|alac|libopencore_amrnb|
;    libvo_amrwbenc|comfortnoise|dca|eac3|flac|g723_1|libgsm|libgsm_ms|libilbc|mp2|mp2fixed|libtwolame|libmp3lame|nellymoser|libopus|pcm_alaw|
;    pcm_f32be|pcm_f32le|pcm_f64be|pcm_f64le|pcm_mulaw|pcm_s16be|pcm_s16be_planar|pcm_s16le|pcm_s16le_planar|pcm_s24be|pcm_s24daud|pcm_s24le|
;    pcm_s24le_planar|pcm_s32be|pcm_s32le|pcm_s32le_planar|pcm_s8|pcm_s8_planar|pcm_u16be|pcm_u16le|pcm_u24be|pcm_u24le|pcm_u32be|pcm_u32le|
;    pcm_u8|real_144|roq_dpcm|s302m|sonic|sonicls|libspeex|tta|vorbis|libvorbis|wavpack|libwavpack|wmav1|wmav2|- disable audio -"


func GetCodecExtFromCodecName($codec_name)
    local $ext
    switch true
        case StringInStr($codec_name"dca")
            $ext = "dts"
        case StringInStr($codec_name"flac")
            $ext = "flac"
        case StringInStr($codec_name"gsm")
            $ext = "gsm"
        case StringInStr($codec_name"mp3")
            $ext = "mp3"
        case StringInStr($codec_name"mp2")
            $ext = "mp2"
        case StringInStr($codec_name"ac3")
            $ext = "ac3"
        case StringInStr($codec_name"aac")
            $ext = "aac"
        case StringInStr($codec_name"opus")
            $ext = "opus"
        case StringInStr($codec_name"real")
            $ext = "ra"
        case StringInStr($codec_name"tta")
            $ext = "tta"
        case StringInStr($codec_name"vorbis")
            $ext = "ogg"
        case StringInStr($codec_name"wma")
            $ext = "wma"
        case else
            $ext = "wav"
    endswitch
    return $ext
endfunc






; application menu functions..
; https://msdn.microsoft.com/en-us/library/windows/desktop/ff468865%28v=vs.85%29.aspx

func GetSystemMenu($hWnd$bRevert)
    local $hMenu = DllCall("user32.dll""hwnd""GetSystemMenu", _
                                                "hwnd"$hWnd, _
                                                "int"$bRevert)
    return $hMenu[0]
endfunc


func InsertMenu($hMenu$nPosition$nFlags$nIDNewItem$lpNewItem)
    local $nResult = DllCall("user32.dll""int""InsertMenu", _
                                                "hwnd"$hMenu, _
                                                "int"$nPosition, _
                                                "int"$nFlags, _
                                                "int"$nIDNewItem, _
                                                "str"$lpNewItem)
    return $nResult[0]
endfunc


func CreatePopupMenu()
    local $hMenu = DllCall("user32.dll""hwnd""CreatePopupMenu")
    return $hMenu[0]
endfunc

; 0xFFFFFFFF means "insert at the end"
func CreateSystemMenuItem($sText$hMenu = -1, $bIsPopup=false, $nPos=0xFFFFFFFF)

    if $hMenu = -1 then $hMenu = GetSystemMenu($ffeGUI, 0)

    local $nID = GUICtrlCreateDummy()
    local $nFlags = 0

    if $sText = "" then
        $nFlags = $MF_SEPARATOR
    elseif $bIsPopup then
        $nID = CreatePopupMenu()
        $nFlags = $MF_POPUP
    endif

    $nFlags = BitOr($MF_BYPOSITION$nFlags)
    InsertMenu($hMenu$nPos$nFlags$nID$sText)
    return $nID
endfunc

func CheckMenuItem($hMenu$nID$nFlags)
    ; so we can pass values directly from "checkboxe boolean" values..
    if $nFlags = $ON then $nFlags = $MF_CHECKED    ; 0x00000008
    if $nFlags = $OFF then $nFlags = $MF_UNCHECKED ; 0x0
    DllCall("user32.dll""int""CheckMenuItem""hwnd"$hMenu"int"$nID"int"$nFlags)
endfunc

func AppMenuItemSetState($hMenu$nID$state=$ON)
    if $state = $ON then
        ; enabled
        $state = 0x0
    else
        ; disabled (greyed)
        $state = 0x00000002
    endif
    DllCall("user32.dll""int""EnableMenuItem""hwnd"$hMenu"int"$nID"int"$state)
endfunc


; An app menu item was clicked..

func CheckAppMenu($hWnd$Msg$wParam$lParam)
#forceref $hWnd$Msg$lParam

    local $nID = BitAnd($wParam, 0x0000FFFF)

    switch $nID
        case $arTransItems[0] to $arTransItems[9]
            SetTransparency($nID)

        case $arCPUItems[0] to $arCPUItems[5]
            SetffmpegCPUPririty($nID)

        case $ReportTypesMenuItems[0] to $ReportTypesMenuItems[6]
            SetFFprobeFormat($nID)

        case $am_use_mediainfo
            MenuSetUseMediaInfo()

        case $DropCommandMenuItems[0] to $DropCommandMenuItems[2]
            SetDropCommand($nID)

        case $am_about
            DoAboutBox()

        case $am_retain_exit_settings
            MenuRetainExitSettings()

        case $am_always_on_top
            MenuToggleOnTop()

        case $am_console_wordwrap
            MenuToggleWrapConsole()

        case $am_log_each_job
            MenuToggleLogEachJob()

        case $am_log_append
            ToggleLogAppend()

        case $am_job_log_append
            ToggleJobLogAppend()

        case $am_do_tooltips
            MenuToggleToolTipHelp()

        case $am_sort_presets_list
            MenuToggleSortPresets()

        case $am_image_buttons
            MenuToggleImgButts()

        ; we keep these down here in case they get set off when adjusting visual prefs. That's right! :/
        case $CustomButtonMenuItems[0] to $CustomButtonMenuItems[501]
            SetCustomButtonColumns($nID)

        case $am_custom_buttons_disable
            SetCustomButtonColumns($nID)
    endswitch
endfunc





; Non-Toggling AppMenu commands..


; Set the window transparency..

func SetTransparency($nID)
    ; although you can access menu vars directly in many cases, it's smart to set a convention for these calls and always use $hMenu.
    local $hMenu = GetSystemMenu($ffeGUI, 0)
    for $i = 0 to 9
        if $arTransItems[$i] = $nID then exitloop
    next
    $user_trans = 10 * $i
    local $trans_level = 255 * (100 - $user_trans) / 100

    WinSetTrans($ffeGUI""$trans_level)
    if $nTPChecked <> $nID then CheckMenuItem($hMenu$nTPChecked$MF_UNCHECKED)
    CheckMenuItem($hMenu$nID$MF_CHECKED)
    IniWrite($ini_path$my_name"transparency"$user_trans)
    $nTPChecked = $nID
    ConsoleAdd("transparency: " & $user_trans & "%")
endfunc

; Set ffmpeg process priority..

func SetffmpegCPUPririty($nID)
    local $hMenu = GetSystemMenu($ffeGUI, 0)
    for $i = 0 to 5
        if $arCPUItems[$i] = $nID then exitloop
    next
    $cpu_priority = $i
    ProcessSetPriority($ffmpeg$cpu_priority; only works if running
    if $nCPUChecked <> $nID then CheckMenuItem($hMenu$nCPUChecked$MF_UNCHECKED)
    CheckMenuItem($hMenu$nID$MF_CHECKED)
    IniWrite($ini_path$my_name"cpu_priority"$cpu_priority)
    $nCPUChecked = $nID
    ConsoleAdd("ffmpeg process priority: " & $cpu_priority & " (" & $arCPU[$i] & ")")
endfunc

; Set the type of reporting ffprobe does..

func SetFFprobeFormat($nID)
    local $hMenu = GetSystemMenu($ffeGUI, 0)
    for $i = 0 to 6
        if $ReportTypesMenuItems[$i] = $nID then exitloop
    next
    ; we access the original report types array by index (and access the menu by idx), so we can style the actual menu however we want.
    $report_format = $ReportTypes[$i]

    if $nRTChecked <> $nID then CheckMenuItem($hMenu$nRTChecked$MF_UNCHECKED)
    if $store_probe_type <> $nID then CheckMenuItem($hMenu$store_probe_type$MF_UNCHECKED)
    CheckMenuItem($hMenu$nID$MF_CHECKED)
    CheckMenuItem($hMenu$am_use_mediainfo$MF_UNCHECKED)
    IniWrite($ini_path$my_name"report_format"$report_format)
    $use_mediainfo = $OFF
    IniWriteCheckBoxValue($ini_path$my_name"use_mediainfo"$use_mediainfo)
    if not $nRTChecked then ConsoleAdd("ffprobe reporting: enabled")
    $nRTChecked = $nID
    ConsoleAdd("ffprobe format: " & $report_format)
endfunc


func MenuSetUseMediaInfo()
    if $use_mediainfo = $ON then
        $use_mediainfo = $OFF
    else
        $use_mediainfo = $ON
    endif
    ConsoleAdd("mediainfo reporting: " & ProcessWriteHumanCheckBoxValue($use_mediainfo))
    IniWriteCheckBoxValue($ini_path$my_name"use_mediainfo"$use_mediainfo)
    SetUseMediaInfo()
endfunc


func SetUseMediaInfo()
    local $hMenu = GetSystemMenu($ffeGUI, 0)

    if not FileExists($mediainfo_location) then
        ConsoleAdd("MediaInfo.exe not found!")
        LocateMediaInfo()
        if not FileExists($mediainfo_location) then
            AppMenuItemSetState($hMenu$am_use_mediainfo$OFF)
            $use_mediainfo = $OFF
            IniWriteCheckBoxValue($ini_path$my_name"use_mediainfo"$use_mediainfo)
        endif
    endif

    if $use_mediainfo = $ON then
        CheckMenuItem($hMenu$am_use_mediainfo$ON)
        CheckMenuItem($hMenu$nRTChecked$MF_UNCHECKED)
        $store_probe_type = $nRTChecked
        $nRTChecked = ""
    else
        CheckMenuItem($hMenu$am_use_mediainfo$OFF)
        CheckMenuItem($hMenu$store_probe_type$ON)
        ConsoleAdd("ffprobe reporting: enabled")
        ConsoleAdd("ffprobe format: " & $report_format)
    endif

endfunc

func LocateMediaInfo()
    local $mi_lookin = GetParent($mediainfo_location)
    if not $mi_lookin then $mi_lookin = @ProgramFilesDir
    DialogOpen()
    local $tmp_mediainfo_location = FileOpenDialog("Please locate MediaInfo.exe.."$mediainfo_location"MediaInfo executable (MediaInfo.exe)"$ffeGUI)
    DialogClose()
    if not $tmp_mediainfo_location or @error then
        ConsoleAdd("still not got a valid path for mediainfo. disabling..")
        return false
    endif
    if FileExists($tmp_mediainfo_location) then
        $mediainfo_location = $tmp_mediainfo_location
    endif
endfunc



; Set the current drag-and-drop command..

func SetDropCommand($nID)
    local $hMenu = GetSystemMenu($ffeGUI, 0)
    for $i = 0 to 2
        if $nID = $DropCommandMenuItems[$i] then exitloop    $DropCommandMenuItems[$i] = 142, or whatever.
    next
    $drop_command = $DropCommands[$i]

    if $nDCChecked <> $nID then CheckMenuItem($hMenu$nDCChecked$MF_UNCHECKED)
    CheckMenuItem($hMenu$nID$MF_CHECKED)
    IniWrite($ini_path$my_name"drop_command"$drop_command)
    $nDCChecked = $nID
    ConsoleAdd("drag-and-drop command: " & $drop_command)
endfunc


; Set the number of custom button columns (updates live)..

func SetCustomButtonColumns($nID)
    local $hMenu = GetSystemMenu($ffeGUI, 0)
    for $i = 1 to 500
        if $CustomButtonMenuItems[$i] = $nID then exitloop
    next
    if $i = 26 then $i = 0
    if $i = 501 then $i = "auto"

    $custom_buttons_columns = $i
    if $CBMChecked <> $nID then CheckMenuItem($hMenu$CBMChecked$MF_UNCHECKED)
    CheckMenuItem($hMenu$nID$MF_CHECKED)
    IniWrite($ini_path$my_name"custom_buttons_columns"$custom_buttons_columns)
    $CBMChecked = $nID

    ReCreateButtonGrid($custom_buttons_array$grid_x$grid_y)
endfunc






; AppMenu Toggles..



; Generic AppMenu toggling function..

func ToggleAppMenuItem(ByRef $setting$menu_item$ini_name$report=true)
    local $hMenu = GetSystemMenu($ffeGUI, 0)
    if $setting = $OFF then
        $setting = $ON
        CheckMenuItem($hMenu$menu_item$MF_CHECKED)
        if $report then ConsoleAdd($ini_name & ": enabled")
    else
        $setting = $OFF
        CheckMenuItem($hMenu$menu_item$MF_UNCHECKED)
        if $report then ConsoleAdd($ini_name & ": disabled")
    endif
    IniWriteCheckBoxValue($ini_path$my_name$ini_name$setting)
endfunc



; Global AppMenu items..


func MenuToggleLogEachJob()
    ToggleAppMenuItem($log_each_job$am_log_each_job"log_each_job")
endfunc

func ToggleLogAppend()
    ToggleAppMenuItem($log_append$am_log_append"log_append")
endfunc

func ToggleJobLogAppend()
    ToggleAppMenuItem($job_log_append$am_job_log_append"job_log_append")
endfunc

func MenuRetainExitSettings()
    ToggleAppMenuItem($retain_exit_settings$am_retain_exit_settings"retain_exit_settings")
endfunc

func MenuToggleImgButts()
    ToggleAppMenuItem($image_buttons$am_image_buttons"image_buttons", false)
    ConsoleAdd("image_buttons: " & ProcessWriteHumanCheckBoxValue($image_buttons) & " (restart to see changes)")
endfunc

func MenuToggleSortPresets()
    ToggleAppMenuItem($sort_presets_list$am_sort_presets_list"sort_presets_list", false)
    ConsoleAdd("sort_presets_list: " & ProcessWriteHumanCheckBoxValue($sort_presets_list) & " (restart to see changes)")
endfunc

func MenuToggleToolTipHelp()
    ToggleAppMenuItem($do_tooltips$am_do_tooltips"do_tooltips", false)
    ConsoleAdd("do_tooltips: " & ProcessWriteHumanCheckBoxValue($do_tooltips) & " (restart to see changes)")
endfunc

func MenuToggleWrapConsole()
    ToggleAppMenuItem($console_wordwrap$am_console_wordwrap"console_wordwrap", false)
    ConsoleAdd("console_wordwrap: " & ProcessWriteHumanCheckBoxValue($console_wordwrap) & " (restart to see changes)")
endfunc


func MenuToggleOnTop()
    ToggleAppMenuItem($always_on_top$am_always_on_top"on_top")
    SetOnTop()
endfunc

func SetOnTop()
    if $always_on_top = $ON then
        WinSetOnTop($ffeGUI"", 1)
    else
        WinSetOnTop($ffeGUI"", 0)
    endif
endfunc




; Other Global Toggles..


; Toggle Main Window...
func ToggleWindow()
    if $minimized = $OFF then
        UnSetHotKeys()
        GUISetState(@SW_HIDE, $ffeGUI)
        $minimized = $ON
        if $do_drop_window = $ON then GUISetState(@SW_SHOW, $GUI_DropWindow)
    else
        GUISetState(@SW_SHOW, $ffeGUI)
        TrayItemSetState($tray_toggle_start_minimized$TRAY_ENABLE)
        SetHotKeys()
        $minimized = $OFF
    endif
    IniWriteCheckBoxValue($ini_path$my_name"minimized"$minimized)
endfunc


func MenuToggleStartMinimized()
    if $start_minimized = $ON then
        $start_minimized = $OFF
    else
        $start_minimized = $ON
    endif
    IniWriteCheckBoxValue($ini_path$my_name"start_minimized"$start_minimized)
    TrayItemSetState($tray_toggle_start_minimized$start_minimized)
endfunc


func ToggleMaximizeWindow()
    if $maximized = $ON then
        GUISetState(@SW_RESTORE, $ffeGUI)
        $maximized = $OFF
    else
        GUISetState(@SW_MAXIMIZE, $ffeGUI)
        $maximized = $ON
    endif
    IniWriteCheckBoxValue($ini_path$my_name"maximized"$maximized)
endfunc


; replace/add parameters from presets..
func TogglePresetMode()
    $replace_mode = GUICtrlRead($radio_preset_replace)
    IniWriteCheckBoxValue($ini_path$my_name"replace_mode"$replace_mode)
endfunc

func ToggleStorePaths()
    $store_filepaths = GUICtrlRead($check_store_filepaths)
endfunc








; preset-level toggles..


; ffe job button toggles..

func ClickSetPreJobCommands()
    $run_pre_job_commands = GUICtrlRead($check_run_pre_job_commands)
    ConsoleAdd("pre-job commands: " & ProcessWriteHumanCheckBoxValue($run_pre_job_commands))
endfunc

func ClickSetPostJobCommands()
    $run_post_job_commands = GUICtrlRead($check_run_post_job_commands)
    ConsoleAdd("post-job commands: " & ProcessWriteHumanCheckBoxValue($run_post_job_commands))
endfunc

func ClickSetPostFileCommand()
    $run_post_file_command = GUICtrlRead($check_run_post_file_command)
    ConsoleAdd("run post-file command: " & ProcessWriteHumanCheckBoxValue($run_post_file_command))
    if $run_post_file_command = $ON then ConsoleAdd("post-file command: " & TokenizeString($post_file_command))

endfunc




func ClickSetOverwrite()
    $overwrite = GUICtrlRead($check_overwrite)
    ConsoleAdd("overwrite: " & ProcessWriteHumanCheckBoxValue($overwrite))
    AutoCreateArgs()
endfunc

func ClickSetConcatenateFiles()
    $concatenate = GUICtrlRead($check_concatenate)
    ConsoleAdd("concatenate: " & ProcessWriteHumanCheckBoxValue($concatenate))
endfunc

func ClickSetQuitWhenDone()
    $quit_when_done = GUICtrlRead($check_quit_when_done)
    ConsoleAdd("quit_when_done: " & ProcessWriteHumanCheckBoxValue($quit_when_done))
endfunc

func ClickSetShutdownWhenDone()
    $shutdown_when_done = GUICtrlRead($check_shutdown_when_done)
    ShutDownOverrideQuit()
    ConsoleAdd("shutdown_when_done: " & ProcessWriteHumanCheckBoxValue($shutdown_when_done))
endfunc


; Other preset-level toggles..

; enable/disable output (for image sequences, etc.)..
func ToggleOutput()
    if $do_output = $ON then
        $do_output = $OFF
        GUICtrlSetState($inp_outputfile$GUI_DISABLE)
        ConsoleAdd("output: disabled")
    else
        $do_output = $ON
        GUICtrlSetState($inp_outputfile$GUI_ENABLE)
        ConsoleAdd("output: enabled")
    endif
endfunc


func ClickToggleMatofStatus()
    ToggleMatofStatus()
endfunc

; Toggle MATOF..
; this can be set inside DoArgsCreate, hence the loop-preventing flag.
func ToggleMatofStatus($new_args=true)
    if $do_matof = $ON then
        $do_matof = $OFF
    else
        $do_matof = $ON
    endif
    ; in case called from inside batch (not clicked)
    GUICtrlSetState($check_do_matof$do_matof)
    if $ini_outputfile then
        GUICtrlSetData($inp_outputfile$ini_outputfile)
    else
        GUICtrlSetData($inp_outputfile, Detokenize(GUICtrlRead($inp_inputfile)))
    endif
    if $new_args then DoArgsCreate()
endfunc


; Toggling Shutdown on exit greys/ungreys Quit on exit
func ShutDownOverrideQuit()
    if $shutdown_when_done = $ON then
        GuiCtrlSetState($check_quit_when_done$ON)
        GuiCtrlSetState($check_quit_when_done$GUI_DISABLE)
    else
        GuiCtrlSetState($check_quit_when_done$quit_when_done)
        GuiCtrlSetState($check_quit_when_done$GUI_ENABLE)
    endif
endfunc





; Auxiliary Functions..



; Check if mouse is over certain controls and act accordingly..
; Returns the ID the mouse is currently over, if required.

func CheckMouse()

    local $mouse_pos = GUIGetCursorInfo($ffeGUI)
    if not IsArray($mouse_pos) then return false
    if IsArray($help_texts) then
        if $previous_pos <> $mouse_pos[4] then
            if IsArray($help_butts) then
                if IsArray($mouse_pos) then
                    local $help_hover = InArray($help_butts$mouse_pos[4])
                    if $help_hover then
                        GUICtrlSetData($lab_help_info, _StringProper(StringLeft($help_texts[$help_hover], StringInStr($help_texts[$help_hover], "|") - 1)))
                    else
                        GUICtrlSetData($lab_help_info"")
                    endif
                    $previous_pos = $mouse_pos[4]
                endif
            endif
        endif
    endif

    ; Button text changes..
    ; We set a $shifted flag to prevent updating the buttons every 1/100th second when nothing is happening
    select
        case ce_IsPressed(10)
            $shifted = true
            "Do It!" becomes script output..
            GUICtrlSetData($butt_doit"script output")
            ; set the number of frames (saved to ini)
            GUICtrlSetData($butt_quicktest"set frames")
            ; custom buttons - let the user know these can be edited..
            for $i = 1 to $custom_buttons_array[0][0]
                GUICtrlSetFont($custom_buttons[$i], $custom_buttons_font_size-2)
                GUICtrlSetData($custom_buttons[$i], "Edit " & $custom_buttons_array[$i][0])
            next
        case $shifted
            GUICtrlSetData($butt_doit"do it!")
            GUICtrlSetData($butt_quicktest"short test")
            for $i = 1 to $custom_buttons_array[0][0]
                GUICtrlSetFont($custom_buttons[$i], $custom_buttons_font_size)
                GUICtrlSetData($custom_buttons[$i], $custom_buttons_array[$i][0])
            next
            $shifted = false
    endselect

    ; check if mouse hovering over drop window..
    local $drop_mouse_pos = GUIGetCursorInfo($GUI_DropWindow)
    if IsArray($drop_mouse_pos) and $drop_mouse_pos[4] then
        return SetExtended($drop_mouse_pos[4], $mouse_pos[4])
    endif
    return $mouse_pos[4]
endfunc


; focus detected on $inp_outputfile..
func CheckFocus($hWnd$iMsg$wParam$lParam)
#forceref $hWnd$iMsg
    local $iFlag = BitShift($wParam, 16)
    switch $lParam
        case GUICtrlGetHandle($inp_outputfile)
            switch $iFlag
                case $EN_SETFOCUS
                    FocusTo_inp_output()
            endswitch
    endswitch
endfunc

func FocusTo_inp_output()
    if $do_matof = $ON then
        ConsoleAdd("MATOF: disabled.")
        ToggleMatofStatus()
    endif
endfunc






; Special "Running" HotKeys..
; in case the user needs to respond to an ffmpeg prompt..
; these send the keys to StdIn, which ffmpeg intercepts.

func HK_FFmpegResponseYes()
    if WinActive($ffeGUI) then
        StdinWrite($ffmpeg"y" & $LOG_LF)
        WinSetTitle($ffeGUI""$title_msg_string)
    else
        HotKeySet("y")
        Send("y")
        HotKeySet("y""HK_FFmpegResponseYes")
    endif
endfunc

func HK_FFmpegResponseNo()
    if WinActive($ffeGUI) then
        StdinWrite($ffmpeg"n" & $LOG_LF)
        WinSetTitle($ffeGUI""$title_msg_string)
    else
        HotKeySet("n")
        Send("n")
        HotKeySet("n""HK_FFmpegResponseNo")
    endif
endfunc

; send an abort command to the running console application (ffmpeg)..

func HK_FFmpegAbort()
    if WinActive($ffeGUI) then
        StdinWrite($ffmpeg"q")
        Sleep(250)
        ProcessClose($ffmpeg)
        ConsoleAdd("user aborted")
        DoLog($LOG_LF & "user sent abort command!" & $LOG_LF & $LOG_LF)
    else
        HotKeySet("{F4}")
        Send("{F4}")
        HotKeySet("{F4}""HK_FFmpegAbort")
    endif
endfunc

func HK_RunningAbortBatch()
    if WinActive($ffeGUI) then
        $abort_batch = true
    else
        HotKeySet("{PAUSE}")
        Send("{PAUSE}")
        HotKeySet("{PAUSE}""HK_RunningAbortBatch")
    endif
endfunc

func HK_ProcessPauseSuspend()
    if WinActive($ffeGUI) then
        if $paused then
            $paused = false
            ProcessSuspendResume($ffmpeg, false)
            WinSetTitle($ffeGUI""$title_msg_string)
        else
            $paused = true
            ProcessSuspendResume($ffmpeg)
            WinSetTitle($ffeGUI""$title_msg_string & " [paused]")
        endif
    else
        HotKeySet("{SCROLLLOCK}")
        Send("{SCROLLLOCK}")
        HotKeySet("{SCROLLLOCK}""HK_ProcessPauseSuspend")
    endif
endfunc






func PrimaryUpCheckSize()
    CheckSize()
endfunc

; get window to conform to minimum sizes..
func CheckSize()

    local $size_array = WinGetClientSize($ffeGUI)
    if not IsArray($size_array) then return false
    local $too_far = false

    ; user window made too small for controls..
    if $size_array[0] < $min_width then
        WinMove($my_title"", default, default , $min_width+8)
        $too_far = true
    endif
    if $size_array[1] < $min_height then
        WinMove($my_title"", default, default , default, $min_height+$height_magic)
        $too_far = true
    endif

    if $too_far then
        $size_array = WinGetClientSize($ffeGUI)
        $width = $size_array[0]
        $height = $size_array[1] ; not actually required
        ; this will cause a double-run for the grid, but the wobble works well - the user went too far! It's almost Android-like..
        if $custom_buttons_columns = "auto" then ReCreateButtonGrid($custom_buttons_array$grid_x$grid_y)
    endif

    if $minimized = $OFF then GUISetState(@SW_SHOW, $ffeGUI)

    return true
endfunc



func ResizeSaveXYPrefs()
    SaveXYPrefs()
endfunc


func SaveXYPrefs()

    if not CheckSize() then return
    ; set the actual variables, too, so we can refer to them (e.g. $width, for dynamic inp_output - no longer used. hmm).
    local $size_array = WinGetPos($ffeGUI)
    if not IsArray($size_array) then return
    if $size_array[0] < (@desktopWidth-25) then
        $x = $size_array[0]
        IniWrite($ini_path$my_name"x"$x)
    endif
    if $size_array[1] < (@desktopHeight-25) then
        $y = $size_array[1]
        IniWrite($ini_path$my_name"y"$y)
    endif

    $size_array = WinGetClientSize($ffeGUI)
    if not IsArray($size_array) then return
    if $size_array[0] >= $min_width then
        $width = $size_array[0]
        IniWrite($ini_path$my_name"width"$size_array[0])

    endif
    if $size_array[1] >= $min_height-$height_magic then
        $height = $size_array[1]
        IniWrite($ini_path$my_name"height"$size_array[1])
    endif

    ; we may need to re-calculate the number of custom button columns..
    if $custom_buttons_columns = "auto" then ReCreateButtonGrid($custom_buttons_array$grid_x$grid_y)

endfunc



func AbortBatch()
    $abort_batch = true
endfunc


; Pre-Job Commands have gone on too long..
func RunCommandsTimeout()
    $timeout = true
endfunc






; DoLog()

; logs stuff..
;
; the optional second parameter tells DoLog to append, or not.
$dl_append will most likely receive the output from a checkbox..
; 1 (append) or 4 [or anything else] (create new log)
;
; to stop and close the log, send "out" as your log string
; the optional third parameter '$log_extra' goes at top of log,
; and, if required, you must send it along with your "out" command, eg..
;
; DoLog("out", 0, "command-line: " & $my_arguments & $LOG_LF & $LOG_LF)
;
;
; and now the function itself..

func DoLog($dl_string$dl_append=4, $log_extra="")
    if $dl_string = "out" then
        if $log_string then
            if $dl_append = 1 then
                $dl_append = 9
            else
                $dl_append = 10
            endif

            local $my_log_file = FileOpen($log_location$dl_append)
            FileWriteLine($my_log_file$my_name & " log @ "&@year&"-"&@mon&"-"&@mday&@hour&"."&@min&"."&@sec&".. " & $LOG_LF & _
                "--------------------------------------------------------------------------------" & $LOG_LF)
            if not $log_extra then FileWriteLine($my_log_file"command-line: " & $CmdLineRaw & $LOG_LF & $LOG_LF)
            FileWriteLine($my_log_file$log_extra)
            FileWriteLine($my_log_file$log_string & $LOG_LF)
            FileClose($my_log_file)
            $log_string = ""
            ;2do - put per-job logging here..
        endif
    else
        $log_string &= UnifyCRLF($dl_string) & $LOG_LF
    endif
    return $dl_string
endfunc



func TestFileWrite($tmpfile)
    local $t = FileWrite($tmpfile"")
    if $t = -1 then return false
    return true
endfunc



; Update the user's existing ini with any new prefs..
;
"The maximum supported size of an INI file is 64KB. The maximum size of an individual INI section is 32KB"
;
func UpdateIniFile()

    local $old_version = IniRead($ini_path$my_name"version", 0)
    local $vcomp = _VersionCompare($my_version$old_version)

    switch $vcomp
        case 0, -1    ; both equal
            return false
    endswitch

    local $sample_custom_butts

    ; drop a temporary ini file somewhere..
    local $tmp_ini = @TempDir & "\ffe.ini.new"
    FileInstall(".\stuff\ffe.ini"$tmp_ini, 1)

    ; delete all non-application prefs from the new (temp) ini
    ; basically, remove the sample batches..
    local $existing_sections = IniReadSectionNames($tmp_ini)

    for $a = 1 to $existing_sections[0]
        if $existing_sections[$a] = $NAME_BUTTONS then $sample_custom_butts = IniReadSection($tmp_ini$existing_sections[$a])
        if $existing_sections[$a] <> $my_name then IniDelete($tmp_ini$existing_sections[$a])
    next

    ; grab settings from user's old ini file..
    $existing_sections = IniReadSectionNames($ini_path)
    for $a = 1 to $existing_sections[0]
        local $section = IniReadSection($ini_path$existing_sections[$a])
        if IsArray($section) then
            for $b = 1 to $section[0][0]
                ; we manually check for # comments, as AutoIt does not..
                if StringLeft($section[$b][0], 1) <> "#" then
                    IniWrite($tmp_ini$existing_sections[$a], $section[$b][0], $section[$b][1])
                endif
            next
        endif
    next

    ; special circumstance - new section added - ensure old users get this..
    if not InArray($existing_sections$NAME_BUTTONS) then
        IniWriteSection($tmp_ini$NAME_BUTTONS$sample_custom_butts)
    endif


    ; rename their existing Batch Runner.ini to "[@date] Batch Runner.ini"
    FileMove($ini_path, GetParent($ini_path) & "\[" & @YEAR & "-" & @MON & "-" & @MDAY & "@" & @hour & "." & @min & "] ffe.ini")
    ; move the newly created ini into place, and delete temp file..
    FileMove($tmp_ini$ini_path, 1)
    ; finally, update the version info in the ini file..
    IniWrite($ini_path$my_name"version"$my_version)

endfunc



func DialogOpen()
    GUISetState(@SW_DISABLE, $ffeGUI)
    UnSetHotKeys()
endfunc

func DialogClose()
    GUISetState(@SW_ENABLE, $ffeGUI)
    WinActivate($ffeGUI)
    SetHotKeys()
endfunc


; HotKeys.
;
; Also used, set elsewhere..
;
;    {SCROLLLOCK}
;    {PAUSE}
;    {F4}
;    n
;    y

func SetHotKeys()
    HotKeySet("^f""HK_FindInOutput")
    HotKeySet("{F3}""HK_FindInOutput2")
    HotKeySet("{F8}""HK_CopyOutput")
    HotKeySet("{F9}""HK_MenuToggleShowDropWindow")
    HotKeySet("{F5}""HK_ClearOutput")
    HotKeySet("{Esc}""HK_DoQuit")
    HotKeySet("{TAB}""TabToCreateArgs")
    if $ffmpeg_binary then HotKeySet("{F1}""HK_DoIt")
    HotKeySet("^a""HK_SelectAllConsoleOutput")
    HotKeySet("^e""HK_MenuRetainExitSettings")
    HotKeySet("^d""HK_MenuDelayedDoIt")
    HotKeySet("^m""HK_ToggleMatofStatus")
endfunc

; ^ = Ctrl
func UnSetHotKeys()
    HotKeySet("^f")
    HotKeySet("{F3}")
    HotKeySet("{F8}")
    HotKeySet("{Esc}")
    HotKeySet("{TAB}")
    HotKeySet("{F1}")
    HotKeySet("^a")
    HotKeySet("^e")
;    HotKeySet("^d")
    HotKeySet("^m")
endfunc





; create the arguments afresh every time you use the <TAB> key..
func TabToCreateArgs()
    HotKeySet("{TAB}")
    Send("{TAB}")
    HotKeySet("{TAB}","TabToCreateArgs")
    if WinActive($ffeGUI) then DoArgsCreate()
endfunc

; hit {F1} to start the encoding process..
func HK_DoIt()
    ; ffe is at the front..
    if WinActive($ffeGUI) then
        DoIt()
    else
        ; you are in some other application..
        HotKeySet("{F1}")
        Send("{F1}")
        HotKeySet("{F1}","HK_DoIt")
    endif
endfunc

; find and select the user's query text..
func HK_FindInOutput()
    if WinActive($ffeGUI) then
        FindInOutput()
    else
        HotKeySet("^f")
        Send("^f")
        HotKeySet("^f""HK_FindInOutput")
    endif
endfunc
func HK_FindInOutput2()
    if WinActive($ffeGUI) then
        FindInOutput()
    else
        HotKeySet("{F3}")
        Send("{F3}")
        HotKeySet("{F3}""HK_FindInOutput2")
    endif
endfunc

func FindInOutput()
    AutoItSetOption("GUIOnEventMode", 0)
    _GUICtrlEdit_Find($edit_console_output)
    AutoItSetOption("GUIOnEventMode", 1)
endfunc


func HK_SelectAllConsoleOutput()
    if WinActive($ffeGUI) then
        SelectAllConsoleOutput()
    else
        HotKeySet("^a")
        Send("^a")
        HotKeySet("^a""HK_SelectAllConsoleOutput")
    endif
endfunc
func SelectAllConsoleOutput()
    GUICtrlSelectAllText($edit_console_output)
endfunc

func HK_MenuDelayedDoIt()
    if WinActive($ffeGUI) then
        DelayedDoIt()
    else
        HotKeySet("^d")
        Send("^d")
        HotKeySet("^d","HK_MenuDelayedDoIt")
    endif
endfunc


func HK_CopyOutput()
    if WinActive($ffeGUI) then
        CopyOutput()
    else
        HotKeySet("{F8}")
        Send("{F8}")
        HotKeySet("{F8}","HK_CopyOutput")
    endif
endfunc

func HK_ClearOutput()
    if WinActive($ffeGUI) then
        ClearOutput()
    else
        HotKeySet("{F5}")
        Send("{F5}")
        HotKeySet("{F5}","HK_ClearOutput")
    endif
endfunc

func HK_MenuRetainExitSettings()
    if WinActive($ffeGUI) then
        MenuRetainExitSettings()
    else
        HotKeySet("^e")
        Send("^e")
        HotKeySet("^e","HK_MenuRetainExitSettings")
    endif
endfunc


func HK_ToggleMatofStatus()
    if WinActive($ffeGUI) then
        ToggleMatofStatus()
    else
        HotKeySet("^m")
        Send("^m")
        HotKeySet("^m","HK_ToggleMatofStatus")
    endif
endfunc


func HK_MenuToggleShowDropWindow()
    if WinActive($ffeGUI) or WinActive($GUI_DropWindow) then
        MenuToggleShowDropWindow()
    else
        HotKeySet("{F9}")
        Send("{F9}")
        HotKeySet("{F9}","HK_MenuToggleShowDropWindow")
    endif
endfunc


$switching, in case they are going nuts on the keys.
; Sending a second SwitchDropImage() before the first is complete could be problematic.
func PreviousDropImage()
    if $switching then return
    if WinActive($GUI_DropWindow) then
        SwitchDropImage(-1)
    else
        HotKeySet("{LEFT}")
        Send("{LEFT}")
        HotKeySet("{LEFT}","PreviousDropImage")
    endif
endfunc

func NextDropImage()
    if $switching then return
    if WinActive($GUI_DropWindow) then
        SwitchDropImage(1)
    else
        HotKeySet("{RIGHT}")
        Send("{RIGHT}")
        HotKeySet("{RIGHT}","NextDropImage")
    endif
endfunc





; Generic File & Folder Opening function.
;
; If it's a file, opens the given file in the user's editor.
; If it's a directory, opens in Explorer.

func OpenSomething($filepath)
    if not FileExists($filepath) then
        ConsoleAdd($filepath & " not found!")
        return false
    endif
    if IsDir($filepath) then
        if not WinExists($filepath) then
            Run("Explorer.exe " & $filepath)
            ;ShellExecute($filepath)
        else
            WinActivate($filepath)
        endif
    else
        local $user_editor = IniRead($ini_path$my_name"editor""notepad.exe")
        if not run($user_editor & " " & $filepath) then
            ConsoleAdd("ERROR! I couldn't run:" & '"' & $user_editor & '"')
            ConsoleAdd("Ironically, you need to check your ini settings! ")
        endif
    endif
endfunc



; Functions that use it..

; edit ini prefs..
func EditIniFile()
    OpenSomething($ini_path)
endfunc

; log file..
func OpenLogFile()
    OpenSomething($log_location)
endfunc


; open a folder
func OpenImagesFolder()
    OpenSomething(GetParent($drop_win_image))
endfunc


; converts user 0-100 into real 0-255, also sets "half transparency" for mouse hover
; (normally 50%, but if user trans is too close, we make it 100%)
func GetRealTrans()
    $dropwin_trans_real = 255 * (100 - $drop_win_transparency) / 100
    $half_trans = 127
    if $drop_win_transparency > 44 and $drop_win_transparency < 56 then $half_trans = 255
endfunc



; Select all the text in a control, usually edit or input controls..
; Pass the ID of the control..
func GUICtrlSelectAllText($control)
    GUICtrlSetState($control$GUI_FOCUS)
    DllCall('user32.dll', 'long', 'SendMessage', 'hwnd', GUICtrlGetHandle($control), 'uint', $EM_SETSEL, 'int', 0, 'int', -1)
endfunc




; Fancy Custom Input Box..    (accepts drag&drop of files)

;    returns:

;    Success:    The value input by the user.
;                @error contains the X coordinate of the window when closed
;                @extended contains the X coordinate of the window when closed
;
;                If you leave the width at the default (-1), CorzFancyInputBox will
;                save and restore its own width settings. Or else specify your own.
;
;    Failure:    Empty "" value.
;                @error contains a non-0 value..
;
;                1 = The Cancel/Close button was pushed.
;                2 = The Timeout time was reached.
;
; As well as being a drop-in replacement for InputBox, you can optionally supply
; the  full path to an ini file and section name to have CorzFancyInputBox save
; the x/y/width specifications for the inputbox, recall them the next time the
; user accesses the same inputbox.
;
; NOTE: CorzFancyInputBox() uses the title to create a preference name. If you
; send 100 separate titles for say, 100 buttons, you will create 100 preferences (x3!)
;
; So put any control-specific text into the prompt, instead.


func CorzFancyInputBox($title$prompt$default=""$pass=""$ib_w=-1, $ib_h=-1, $ib_x=-1, $ib_y=-1, $timeout=0, $gui_ex=false, $style=-1, $inipath=$ini_path$sectionname=$my_name)

    DialogOpen()
    local $last_event_mode = AutoItSetOption("GUIOnEventMode", 0)
    local $coord = AutoItSetOption("GUICoordMode", 1)

    local $pref_name = CompressToPrefName($title)
    $ib_x = IniRead($ini_path$my_name"inputbox_" & $pref_name & "_x"$ib_x)
    $ib_y = IniRead($ini_path$my_name"inputbox_" & $pref_name & "_y"$ib_y)
    $ib_w = IniRead($inipath$sectionname"inputbox_" & $pref_name & "_width"$ib_w)

    if not $ib_x or $ib_x = default then $ib_x = -1
    if not $ib_y or $ib_y = default then $ib_y = -1
    if not $ib_h or $ib_h = default then $ib_h = 96
    if not $ib_w or $ib_w = default then $ib_w = @DesktopWidth/2

    local $min_w = 200
    local $return = false, $error
    local $inputstyle = $ES_AUTOHSCROLL
    local $exStyle = BitOr($WS_EX_ACCEPTFILES$WS_EX_TOPMOST)

    if $style = -1 then $style = BitOr($WS_MINIMIZEBOX$WS_CAPTION$WS_POPUP$WS_SYSMENU$WS_SIZEBOX)
    if $pass <> 0 then $inputstyle = BitOr($ES_AUTOHSCROLL$ES_PASSWORD)

    ; make the dialog..
    local $ib_GUI = GUICreate($title$ib_w$ib_h$ib_x$ib_y$style$exStyle$gui_ex)


    local $lab_prompt = GUICtrlCreateLabel($prompt, 10, 5, $ib_w-30)
    GUICtrlSetFont(-1, 10)

    local $but_OK = GUICtrlCreateButton("OK"$ib_w-45, $ib_h-30, 40, 22, $BS_DEFPUSHBUTTON)
    GUICtrlSetState(-1, $GUI_ONTOP)

    local $but_Cancel = GUICtrlCreateButton("Cancel", 5, $ib_h-30, 60, 22)
    GUICtrlSetState(-1, $GUI_ONTOP)

    local $inp_MyID = GUICtrlCreateInput($default, 70, $ib_h-30, $ib_w-125, 22, $inputstyle)
    GUICtrlSetState(-1, $GUI_FOCUS)
    GUICtrlSetFont (-1, 10 , 400, """Lucida Console")
    GUICtrlSetState(-1, $GUI_DROPACCEPTED)


    GUICtrlSetResizing($lab_prompt$GUI_DOCKALL)
    GUICtrlSetResizing($but_OK$GUI_DOCKSTATEBAR+$GUI_DOCKWIDTH+$GUI_DOCKRIGHT)
    GUICtrlSetResizing($but_Cancel$GUI_DOCKSTATEBAR+$GUI_DOCKLEFT+$GUI_DOCKWIDTH)
    GUICtrlSetResizing($inp_MyID$GUI_DOCKSTATEBAR+$GUI_DOCKLEFT+$GUI_DOCKRIGHT)

    GUISetState(@SW_SHOW, $ib_GUI)
    WinMove($title"", default, default, $ib_w$ib_h)

    if $timeout <> 0 then local $dialog_begin = TimerInit()
    local $size_array

    while true
        switch GUIGetMsg()
            case $GUI_EVENT_RESIZED
                $size_array = WinGetPos($title)
                if not IsArray($size_array) then continueloop
                if $size_array[2] < $min_w then WinMove($title"", default, default, $min_w$ib_h)
                if $size_array[3] <> $ib_h then WinMove($title"", default, default, $min_w$ib_h)
            case $GUI_EVENT_CLOSE$but_Cancel
                $return = false
                $error = 1
                exitloop
            case $but_OK
                $return = StringStripWS(GUICtrlRead($inp_MyID), 3)
                exitloop
        endswitch

        if $timeout <> 0 then
            if TimerDiff($dialog_begin)/1000 > $timeout then
                $return = false
                $error = 2
                exitloop
            endif
        endif

    wend

    ; return X & Y in @error & @extended..
    if $return then
        local $x_coord = -1, $y_coord = -1, $ib_width
        $size_array = WinGetPos($title)    ; 0-1-2-3:x-y-w-h
        if IsArray($size_array) then
            $x_coord = $size_array[0]
            $y_coord = $size_array[1]
            $ib_width = $size_array[2]
        endif
    endif

    AutoItSetOption("GUIOnEventMode"$last_event_mode)
    AutoItSetOption("GUICoordMode"$coord)
    GUIDelete($ib_GUI)

    DialogClose()

    if $return then
        ; only write prefs if the user actually changed the position/dimensions..
        if $x_coord and $x_coord <> -1 then IniWrite($inipath$sectionname"inputbox_" & $pref_name & "_x"$x_coord)
        if $y_coord and $y_coord <> -1 then IniWrite($inipath$sectionname"inputbox_" & $pref_name & "_y"$y_coord)
        if $ib_width and $ib_width <> @DesktopWidth/2 then IniWrite($inipath$sectionname"inputbox_" & $pref_name & "_width"$ib_width)
        return $return
    endif
    return SetError($error, 0, "")
endfunc




; POST-FILE command..

func SpecifyPostFileCommand()
    local $user_command = CorzFancyInputBox("Post-File Command..",    "Enter the FULL command. Put quotes around any paths with spaces. NOTE: You can drag files into this input. You can also use @tokens.", _
                                                                    $post_file_command"", @DesktopWidth/2, 96, default, default, 0, $ffeGUI)
    if $user_command then
        $post_file_command = $user_command
        ConsoleAdd("post-file command set to: " & $post_file_command)
    endif
endfunc



func SpecifyPreJobCommandsFile()
    CreateJobCommands($pre_job_commands_file"Pre")
endfunc
func SpecifyPostJobCommandsFile()
    CreateJobCommands($post_job_commands_file"Post-Job")
endfunc

func CreatePreJobCommands()
    CreateJobCommands($pre_job_commands_file"Pre-Job")
endfunc

func CreatePostJobCommands()
    CreateJobCommands($post_job_commands_file"Post-File")
endfunc

func CreateJobCommands(ByRef $commands_file$type$do_edit=true)

    local $def_input = "@datadir\" & StringLower($type) & "-commands.bat"
    if $commands_file then $def_input = TokeniZeString($commands_file)
    local $user_prc_filename = CorzFancyInputBox( "Specify A " & $type & " Commands File.. ", _
                                                        "Please specify the location of the " & $type & " Commands file.. " & $MSG_LF & _
                                                        "NOTE: You can use @Tokens in this setting."$def_input , "" , @DesktopWidth/2, 115, default, default, 0, $ffeGUI)
    if $user_prc_filename then

        local $real_user_prc_filename = DeTokenize($user_prc_filename)

        if $user_prc_filename and StringLeft($real_user_prc_filename, 2) <> '\\' and StringMid($real_user_prc_filename, 2, 1) <> ':' then
            $real_user_prc_filename = $data_parent & "\" & $real_user_prc_filename
        endif
        $commands_file = $real_user_prc_filename

        if FileExists($real_user_prc_filename) then
            ConsoleAdd('"' & $commands_file & """ already exists")
        else
            ConsoleAdd("
creating: """ & $commands_file & '"')
            FileWrite($real_user_prc_filename":: ffe " & $type & " commands" & $LOG_LF & $LOG_LF)
        endif

        switch $type
            case "Pre-Job"
                LoadPreCommands()
            case "Post-Job"
                LoadPostCommands()
        endswitch
        if $do_edit then OpenSomething($commands_file)
    endif

;    return $commands_file

endfunc




; these functions are called whenever there is a change in command file or presets..



func LoadPreCommands()
    local $tmp_cf = IniRead($ini_path$current_preset"pre_job_commands_file""---")
    if not $tmp_cf or $tmp_cf = "---" then $tmp_cf = $pre_job_commands_file
    $pre_job_commands_file = Detokenize($tmp_cf)
    LoadCommandsFile($pre_job_commands_file"Pre""run_pre_job_commands"$check_run_pre_job_commands)
endfunc

func LoadPostCommands()
    local $tmp_cf = IniRead($ini_path$current_preset"post_job_commands_file""---")
    if not $tmp_cf or $tmp_cf = "---" then $tmp_cf = $post_job_commands_file
    $post_job_commands_file = Detokenize($tmp_cf)
    LoadCommandsFile($post_job_commands_file"Post""run_post_job_commands"$check_run_post_job_commands)
endfunc

; the master command-file loader.
; reads the ini value for the file's path, sets the checkboxes to the correct values
; enables/disables checkboxes.

func LoadCommandsFile(ByRef $commands_file$type$main_switch$control)

    $type = StringLower($type)

    if $commands_file then
        $commands_file = SetRelPathToDataDir($commands_file)
    else
        if $main_switch = $ON then ConsoleAdd("no " & $type & "-job commands file specified!")
        return
    endif

    ;MAY NOT EXIST YET!!!!!!!!!!; @parent\batch.bat might not yet exist!!!!!!!!
    if not FileExists($commands_file) then
        ConsoleAdd("specified " & $type & "-job commands file not found: " & $commands_file)
        return
    endif

    ConsoleWrite(".\" & @ScriptName & "(" & @ScriptLineNumber & "): ==> " & "loading " & $type & "-commands file (" & $commands_file & ") for: " & $current_preset & $LOG_LF)

    local $tmp_do_run_cmds = IniReadCheckBoxValue($ini_path$current_preset$main_switch"---", true) ; may be working from non-preset, or exit-settings
    if not $tmp_do_run_cmds or $tmp_do_run_cmds = "---" then $tmp_do_run_cmds = Eval($main_switch; may get set back, but that's okay


    if $commands_file and FileExists($commands_file) then    ; @parent\batch.bat might not yet exist.    ;2do - check for no @tokens or @tokens that WON'T exist, and disable control.
        GUICtrlSetState($control$GUI_ENABLE)
        ConsoleWrite(".\" & @ScriptName & "(" & @ScriptLineNumber & "): ==> " & $type & "-job-commands ENABLED" & $LOG_LF)
    else
        GUICtrlSetState($control$GUI_DISABLE)
        ConsoleWrite(".\" & @ScriptName & "(" & @ScriptLineNumber & "): ==> " & $type & "-job-commands DISABLED" & $LOG_LF)
    endif

    if $tmp_do_run_cmds then Assign($main_switch, Int($tmp_do_run_cmds))    $run_pre_job_commands = $tmp_do_run_cmds

    GUICtrlSetState($control, Eval($main_switch))
    $batch_commands_timeout = IniRead($ini_path$current_preset"batch_commands_timeout", 0)
    $run_commands_with_shell = IniReadCheckBoxValue($ini_path$current_preset"run_commands_with_shell"$run_commands_with_shell)

    ; Update "create" / "edit" tray menu item..
    MakeTray()
endfunc


; There are easier ways, but none so much FUN!

func RunCommandsFile(ByRef $commands_file, ByRef $logfile, ByRef $gen_file$type)

    if $commands_file and FileExists($commands_file) then    ; we check again before running!

        local $msg$run_command$console_out

        if $generate_script then
            ; simply read the batch file into our new batch file..
            $gen_file &= FileRead($commands_file)
        else
            if $batch_commands_timeout then AdLibRegister("RunCommandsTimeout"$batch_commands_timeout*1000*60)
            $timeout = false
            local $command_run$err

            if $run_commands_with_shell = $ON then

                if GetExtension($commands_file) <> "bat" then
                    $msg = $type & "-job command processing aborted" & $LOG_LF & "please give your batch script a .bat extension"
                    $logfile &= DoLog(ConsoleAdd($msg)) & $LOG_LF
                    AdLibUnRegister("RunCommandsTimeout")
                    return false
                endif

                ; run the .bat file directly.
                $msg = $LOG_LF & "running batch file: """ & $commands_file & """.."
                $logfile &= DoLog(ConsoleAdd($msg)) & $LOG_LF
                $run_command = @ComSpec & " /c " & ' "' & $commands_file & '" '
                $command_run = Run($run_command"", @SW_HIDE, $STDOUT_CHILD)
                while true
                    $err = false
                    $console_out = StdoutRead($command_run)
                    $err = @error
                    $console_out = StringStripWS($console_out, 3)
                    $logfile &= DoLog(ConsoleAdd($console_out)) & $LOG_LF
                    if @error or $timeout or not @extended then exitloop
                    Sleep(25)
                wend
                StdioClose($command_run)

            else

                ; ffe will run the commands one-by-one, replacing @tokens along the way.
                local $run_commands_list
                FileReadToArrayOptimized($commands_file$run_commands_list; populates $run_commands_list
                $msg = $LOG_LF & "running " & StringLower($type) & "-job commands: " & $commands_file
                $logfile &= DoLog(ConsoleAdd($msg)) & $LOG_LF
                for $i = 1 to $run_commands_list[0]

                    if StringLeft($run_commands_list[$i], 1) = ":" or StringStripWS($run_commands_list[$i], 3) = "" then continueloop    ; ignore comments and such

                    $run_command = @ComSpec & " /c " & DeTokenize($run_commands_list[$i])
                    $command_run = Run($run_command"", @SW_HIDE, $STDOUT_CHILD)

                    while true
                        $err = false
                        $console_out = StdoutRead($command_run)
                        $err = @error
                        $console_out = StringStripWS($console_out, 3)
                        $logfile &= DoLog(ConsoleAdd($console_out)) & $LOG_LF
                        if $err or $timeout then exitloop
                        Sleep(25)
                    wend
                    StdioClose($command_run)
                 next

            endif

             AdLibUnRegister("RunCommandsTimeout")
        endif
    else
        $msg = $type & "-Job Commands File NOT FOUND!"
        $logfile &= DoLog(ConsoleAdd($msg)) & $LOG_LF
    endif

    return true
endfunc


; feed it a path, if it is a full, valid path it is returned as-is
; if it's a relative path, it is added to the datadir path and that full path is returned.
func SetRelPathToDataDir($some_path)
    if $some_path and StringLeft($some_path, 2) <> '\\' and StringMid($some_path, 2, 1) <> ':' then
        CLT($some_path)
        $some_path = $data_parent & "\" & $some_path
        CRT($some_path)
    endif
    return $some_path
endfunc


func EditPostJobCommands()
    if $post_job_commands_file then
        OpenSomething($post_job_commands_file)
        LoadPostCommands()
    endif
endfunc

func EditPreJobCommands()
    if $pre_job_commands_file then
        OpenSomething($pre_job_commands_file)
        LoadPreCommands()
    endif
endfunc






; Where oh where is ffmpeg.exe..

func TraySetFFMpegBinaryLocation()
    SetFFMpegBinaryLocation()
endfunc

func SetFFMpegBinaryLocation($binary_location=false)

    ; binary location not supplied in arguments, locate..

    if not $binary_location then
        local $ffmpeg_bin_dir = IniRead($ini_path$my_name"ffmpeg_bin_dir", @ProgramFilesDir)
        if FileExists(Getparent($ffmpeg_binary)) then $ffmpeg_bin_dir = Getparent($ffmpeg_binary)
        DialogOpen()
        local $tmp_ffmpeg_binary = FileOpenDialog("Please locate the ffmpeg binary.."$ffmpeg_bin_dir"ffmpeg binary (ffmpeg.exe)"$ffeGUI)
        DialogClose()

        if not $tmp_ffmpeg_binary or @error then
            ConsoleAdd("ffmpeg binary location setting unchanged: user aborted")
            return false
        endif
        $tmp_ffmpeg_binary = Detokenize($tmp_ffmpeg_binary)
        $binary_location = Detokenize($tmp_ffmpeg_binary)
    endif


    if $binary_location = $ffmpeg_binary then
        ConsoleAdd("ffmpeg binary location setting unchanged")
        return false
    endif

    IniWrite($ini_path$my_name"ffmpeg_bin_dir", GetParent($binary_location))

    if FileExists($binary_location) then
        $ffmpeg_binary = $binary_location
        local $user_ffmpeg_binary = TokenizeString($ffmpeg_binary)
        IniWrite($ini_path$my_name"ffmpeg_binary"$user_ffmpeg_binary)
        ConsoleAdd("ffmpeg binary location set to: """ & $user_ffmpeg_binary & """")
        EnableActiveInputs()
    endif

endfunc




; add some text onto the end of the console output and scroll to end of the output..
func ConsoleAdd($out_string)
    GUICtrlSetData($edit_console_output, StringStripWS(GUICtrlRead($edit_console_output), 2) & $LOG_LF & $out_string)
    _GUICtrlEdit_Scroll($edit_console_output$__EDITCONSTANT_SB_SCROLLCARET)
    return $out_string
endfunc


; REPLACE the console output with some new output..
func SetConsoleOutput($out_string$scroll_top=false)
    GUICtrlSetData($edit_console_output$out_string)
    if $scroll_top then
        _GUICtrlEdit_Scroll($edit_console_output, 0)
    else
        _GUICtrlEdit_Scroll($edit_console_output$__EDITCONSTANT_SB_SCROLLCARET)
    endif
    return $out_string
endfunc



func GetEditStyles()
    if $console_wordwrap = $ON then
        return BitOR($ES_AUTOVSCROLL$WS_VSCROLL$ES_WANTRETURN$ES_MULTILINE$ES_NOHIDESEL)
    else
        return BitOR($WS_HSCROLL$ES_AUTOVSCROLL$WS_VSCROLL$ES_AUTOHSCROLL$ES_MULTILINE$ES_WANTRETURN$ES_NOHIDESEL)
    endif
endfunc




; Optional ToolTips

; Set a tooltip or don't, dependant on the GLOBAL $do_tooltips variable,
; which you should set first, generally when gathering global prefs.
;
; This is a drop-in replacement for GUICtrlSetTip() and will happily work in this simple state.
;
$options: these numbers can be added together..
;
;    1 = Display as Balloon Tip
;    2 = Center the tip horizontally under the control
;    And so on. See below this function for more details.
;
func GUICtrlSetTipOptional($control_ID$tip_text$title="Information:"$icon=$tip_icon$options=$tip_style)

    if $do_tooltips = $OFF then return

    local $style = 0, $hicon$ret
    $control_ID = GUICtrlGetHandle($control_ID)

    if BitAND($options, 1) then $style = $TTS_BALLOON
    $style = BitOr($style$TTS_ALWAYSTIP$TTS_NOPREFIX)


    local $hToolTip = _GUIToolTip_Create(0, $style)

    $options = BitOr($options$TTF_SUBCLASS$TTF_IDISHWND)
    _GUIToolTip_AddTool($hToolTip, 0, $tip_text$control_ID, default, default, default, default, $options, 0)

    _GUIToolTip_SetDelayTime($hToolTip$TTDT_INITIAL, 400)        ; (500ms) Time the pointer must remain stationary within a tool's bounding rectangle before the window appears.
    _GUIToolTip_SetDelayTime($hToolTip$TTDT_AUTOPOP$tooltip_time)    ; (5000ms) Time the ToolTip window remains visible if the pointer is stationary within a tool's bounding rectangle.
    _GUIToolTip_SetDelayTime($hToolTip$TTDT_RESHOW, 150)        ; (100ms) Time it takes for subsequent ToolTip windows to appear as the pointer moves from one tool to another.

    if not StringInStr($icon".") then
        _GUIToolTip_SetTitle($hToolTip$title$icon)
    else
        $hicon = DllStructCreate("ptr")
        $icon = StringSplit($icon",")
        if $icon[0] > 1 then
            $ret = DllCall("shell32.dll""uint""ExtractIconExW""wstr"$icon[$icon[0] - 1], "int", -1 * (Int($icon[$icon[0]])), "ptr", 0, "ptr", DllStructGetPtr($hicon), "uint", 1)
            if not @error and $ret[0] then
                $hicon = DllStructGetData($hicon, 1)
            else
                $hicon = 0
            endif
            _GUIToolTip_SetTitle($hToolTip$title$hicon)
            DllCall("user32.dll""none""DestroyIcon""handle"$hIcon)
        endif
    endif

    return $hToolTip
endfunc

;
;    [optional] Flags that control the ToolTip display:
;
;        Global Const $TTF_IDISHWND = 0x00000001        - Indicates that $iID is a window or control handle, instead of the ID of the tool
;        Global Const $TTF_CENTERTIP = 0x00000002    - Centers the tooltip below the control specified by $iID
;        Global Const $TTF_RTLREADING = 0x00000004    - Indicates that text will be displayed in the opposite direction of the parent window (see remarks)
;        Global Const $TTF_SUBCLASS = 0x00000010        - Indicates that the control should subclass the tool's window
;        Global Const $TTF_TRACK = 0x00000020        - Positions the tooltip window next to the tool to which it corresponds
;        Global Const $TTF_ABSOLUTE = 0x00000080        - Positions the window at the same coordinates provided by TTM_TRACKPOSITION. (see remarks)
;        Global Const $TTF_TRANSPARENT = 0x00000100    - Causes the control to forward mouse messages to the parent window
;        Global Const $TTF_PARSELINKS = 0x00001000    - Indicates that links in the control text should be displayed as links
;        Global Const $TTF_DI_SETITEM = 0x00008000
;
;        Default = BitOr($TTF_SUBCLASS$TTF_IDISHWND)
;
;    _GUIToolTip_Create STYLE
;
;        $TTS_ALWAYSTIP (0x01)    - Indicates that the ToolTip control appears when the cursor is on a tool even if the ToolTip control's owner window is inactive.
;                                  Without this style, the ToolTip appears only when the tool's owner window is active.
;        $TTS_NOPREFIX (0x02)    - Prevents the system from stripping the ampersand character from a string. Without this style the system automatically strips ampersand characters.
;                                  This allows an application to use the same string as both a menu item and as text in a ToolTip control.
;        $TTS_NOANIMATE (0x10)    - Disables sliding ToolTip animation.
;        $TTS_NOFADE (0x20)        - Disables fading ToolTip animation.
;        $TTS_BALLOON (0x40)        - Indicates that the ToolTip control has the appearance of a cartoon "balloon"
;        $TTS_CLOSE (0x80)        - Displays a close icon so that the tooltip can be cancelled
;
;        Default: $_TT_ghTTDefaultStyle = BitOr($TTS_ALWAYSTIP$TTS_NOPREFIX)
;
; Icon idx..
;
;     [optional] Set to one of the values below:.
;         $TTI_NONE (0) - No icon [default]
;         $TTI_INFO (1) - Information icon
;         $TTI_WARNING (2) - Warning icon
;         $TTI_ERROR (3) - Error Icon
;         $TTI_INFO_LARGE (4) - Large Information Icon
;         $TTI_WARNING_LARGE (5) - Large Warning Icon
;         $TTI_ERROR_LARGE (6) - Large Error Icon



func IsWild($string)
    if StringInStr($string"*") or StringInStr($string"?") then return true
    return false
endfunc



; there are 8 path tokens.
; the usual error checking has been omitted here - let the user

func DeTokenize($string)

    if not $string then return $string
    if not StringInStr($string"@") then return $string
    $string = FixPathSlashes($string)

    ; dynamic @tokens..
    $string = StringReplace($string"@item", RemoveExtension(BaseName($inputfile)))
    $string = StringReplace($string"@ext", GetExtension($inputfile))
    $string = StringReplace($string"@oext", GetExtension($outputfile))
    $string = StringReplace($string"@ofilename", BaseName($outputfile))

    $string = StringReplace($string"@sec", @sec)
    $string = StringReplace($string"@min", @min)
    $string = StringReplace($string"@hour", @hour)
    $string = StringReplace($string"@mday", @mday)
    $string = StringReplace($string"@mon", @mon)
    $string = StringReplace($string"@year", @year)
    $string = StringReplace($string"@wday", @wday)
    $string = StringReplace($string"@yday", @yday)

    ; path @tokens..
    $string = StringReplace($string"@mydocuments", @MyDocumentsDir)
    $string = StringReplace($string"@desktop", @DesktopDir)
    $string = StringReplace($string"@tempdir", @TempDir)
    $string = StringReplace($string"@datadir"$data_parent)
    $string = StringReplace($string"@outdir", GetParent($outputfile))
    $string = StringReplace($string"@parent", GetParent($inputfile))

    $string = StringReplace($string"@homedir", @HomeDrive & @HomePath)
    $string = StringReplace($string"@programfiles", @ProgramFilesDir)
    $string = StringReplace($string"@outputfile"$outputfile)

    return $string
endfunc



func TokenizeString($string)
    if not $string then return $string
    $string = FixPathSlashes($string)
    $string = StringReplace($string, @DesktopDir, "@desktop")
    $string = StringReplace($string, @MyDocumentsDir, "@mydocuments")
    $string = StringReplace($string, @TempDir, "@tempdir")
    if $data_parent <> "" then $string = StringReplace($string$data_parent"@datadir")
    if GetParent($outputfile) <> "" then $string = StringReplace($string, GetParent($outputfile), "@outdir")
    if GetParent($inputfile) <> "" then $string = StringReplace($string, GetParent($inputfile), "@parent")
    $string = StringReplace($string, @HomeDrive & @HomePath, "@homedir")
    $string = StringReplace($string, @ProgramFilesDir, "@programfiles")
    return $string
endfunc



; fix potentially messed-up slashes..
func FixPathSlashes($string)
    if StringInStr($string"://") then return $string ; but not for URLs
    $string = StringReplace($string"/""\")
    $string = StringReplace($string"\\""\")
    return $string
endfunc




; Conditional Right/Left Trim
;
; If the far-right character(s) is(are) such-and-such, remove it(them).
; Handy for normalizing path ends and other stuff.
;
; We do this a lot..
;
;    if StringRight($string, 1) = "\" then $string = StringTrimRight($string, 1)
;
; Functions work on the string ByRef, so you simply do:
;
;    CRT("my string")
;
; The idea of the names is; quick to type.
;
; so..

func CRT(ByRef $string$character="\")
    local $char_num = StringLen($character)
    if StringRight($string$char_num) = $character then $string = StringTrimRight($string$char_num)
endfunc

; And for the left-hand side.
func CLT(ByRef $string$character="\")
    local $char_num = StringLen($character)
    if StringLeft($string$char_num) = $character then $string = StringTrimLeft($string$char_num)
endfunc



; Add a single item to an AutoIt array..
;
; ArrayAdd() automatically increases the [0] index, but DOES NOT rely upon it.
;
; Enable the third parameter to NOT add items which already exist in the array.
;
; Set the fourth parameter to true, and when an item is added which already
; exists, the array is re-indexed, moving the entry to the END of the array.
; In other words, it becomes the "most recent entry".
;
func ArrayAdd(byref $array$item$dont_dupe=false, $update=false)

    if not IsArray($array) then return
    local $size = UBound($array)

    if $dont_dupe and $update = false then
        if InArray($array$item) then return
    endif

    if $update then
        local $idx = InArray($array$item)
        if $idx then
            for $i = $idx to $size-2
                $array[$i] = $array[$i+1]
            next
            $size -= 1
        endif

    endif

    redim $array[$size+1]
    $array[$size] = $item
    $array[0] = $size

endfunc




; Just for fun, reverses a StringSplit - handy if you have split a string to
; manipulate and now want it back as a string..
; Pass it an AutioIt array, as returned by StringSplit
;
; This also makes a great part 1 of a 1-2 WriteArrayToFromFile type function.
; (see above for exactly that)
;
func StringJoin(ByRef $array$join_str=$LOG_LF)
    local $ret_str
    for $i = 1 to $array[0]
        $ret_str &= $array[$i] & $join_str
    next
    CRT($ret_str$join_str)
    return $ret_str
endfunc



; ffprobe/mediainfo media reporting..

func GenerateReport()

    if IsWild($inputfile) then
        ConsoleAdd("cannot report on directories or multiple files!"  & $LOG_LF & "replace the wildcards with a file name!")
        return false
    endif

    if not GetReportingValues() then return false
;    GetReportingValues()

    ; SHIFT+Click to open in viewer/editor (grab this input NOW)..
    local $do_open = false
    if ce_IsPressed(10) then $do_open = true

    local $report_name = Basename(RemoveExtension($inputfile)) & "." & $report_extension
    if not FileExists($report_directory) then $report_directory = GetParent($inputfile)
    local $report_loc = $report_directory & "\" & $report_name

    local $report_str$err$probe_file$sw = ""

    ; run ffprobe (capturing stdout)..
    if $use_mediainfo = $ON and FileExists($mediainfo_location) then
        if $mediainfo_switches then $sw = ' ' & $mediainfo_switches & " "
        $probe_file = Run( $mediainfo_location & $sw & ' "' & $inputfile & '"', "", @SW_HIDE, $STDOUT_CHILD)
    else
        if $report_switches then $sw = " " & $report_switches & " "
        $probe_file = Run( $ffprobe_loc & " -v error -show_format -show_streams -print_format " & $report_format & $sw & ' "'& $inputfile & '"', "", @SW_HIDE, $STDOUT_CHILD)
    endif

    while true
        $err = false
        local $console_out = StdoutRead($probe_file)
        $err = @error
        if $console_out then $report_str &= $console_out
        if $err then exitloop
        Sleep(5)
    wend
    StdioClose($probe_file)
    ProcessClose($probe_file)

    if $un_escape_output = $ON then
        $report_str = StringReplace($report_str"\\""\")
        $report_str = StringReplace($report_str"\:"":")
    endif

    if FileExists($report_loc) then FileDelete($report_loc)
    local $report_file_open = FileOpen($report_loc$FO_OVERWRITE$FO_CREATEPATH+$FO_UTF8_NOBOM)
    FileWrite($report_file_open$report_str)
    FileClose($report_file_open)


    if $do_open then
        ShellExecute($report_loc)
    else
        SetConsoleOutput($report_str, true)
    endif

endfunc


; grab this fresh for every report..

func GetReportingValues()

    $report_format = IniRead($ini_path$my_name"report_format""ini")
    $report_directory = Detokenize(IniRead($ini_path$my_name"report_directory""@parent"))
    $report_extension = IniRead($ini_path$my_name"report_extension""ini")
    $report_switches = IniRead($ini_path$my_name"report_switches""")
    $un_escape_output = IniReadCheckBoxValue($ini_path$my_name"un_escape_output"$ON)

    $use_mediainfo = IniReadCheckBoxValue($ini_path$my_name"use_mediainfo"$OFF)
    $mediainfo_location = IniRead($ini_path$my_name"mediainfo_location""")
    $mediainfo_switches = IniRead($ini_path$my_name"mediainfo_switches""")
    local $mediainfo_extension = IniRead($ini_path$my_name"mediainfo_extension""nfo")

    if $use_mediainfo = $ON then
        $report_extension = $mediainfo_extension
        if not FileExists($mediainfo_location) then
            ConsoleAdd("MediaInfo.exe not found")
            return false
        endif
    else
        if $report_extension = "auto" then
            switch $report_format
                case "compact"
                    $report_extension = "txt"
                case else
                    $report_extension = "nfo"
            endswitch
        endif
        $ffprobe_loc = GetParent($ffmpeg_binary) & "\ffprobe.exe"
        if not FileExists($ffprobe_loc) then
            ConsoleAdd("ffprobe.exe not found next to ffmpeg" & $LOG_LF & "please place ffprobe.exe next to ffmpeg.exe")
            return false
        endif
    endif
    return true
endfunc




func GetLogLocation($this_preset=$my_name)

    $i = DeTokenize(IniRead($ini_path$this_preset"log_location"""))

    if $i <> "-" then
        if $portable then
            if $i and TestFileWrite($i) then
                $log_location = $i
            else
                if TestFileWrite(@ScriptDir & "\" & $my_name & ".log") then $log_location = @ScriptDir & "\" & $my_name & ".log"
            endif
        elseif IsDir($i) and TestFileWrite($i & "\" & $my_name & ".log") then
            $log_location = $i & "\" & $my_name & ".log"
        elseif $i and TestFileWrite($i) then
            $log_location = $i
        else
            $log_location = @TempDir & "\" & $my_name & ".log"
        endif
    endif
endfunc


; Suspend/Resume a process.
; NOTE: You *must* do this before sending DebugSetProcessKillOnExit, or else it will have no effect.
func ProcessSuspendResume($proc_name$do_suspend=true)
   if IsString($proc_name) then $proc_name = ProcessExists($proc_name)
   if not $proc_name then return SetError(2, 0, 0)
   if $do_suspend then
      DllCall('kernel32.dll','ptr','DebugActiveProcess','int',$proc_name; note: opens process with PROCESS_ALL_ACCESS
   else
      DllCall('kernel32.dll','ptr','DebugActiveProcessStop','int',$proc_name)
   endif
endfunc








;; Functions from from corz_essentials..



; BaseName()
;
; get the base name of a file from a full path..
; in other words; returns the path name without the folders part (ie. file name only)

func BaseName($bn_path)
    $bn_path = StringReplace($bn_path"/""\")
    CRT($bn_path)
    local $parts = StringSplit($bn_path"\")
    local $bn_tmp = $parts[$parts[0]]
    CRT($bn_tmp":")
    return $bn_tmp
endfunc


; GetExtension()
;
; returns the extension of a file name, e.g. "txt"
; if the file has no extension, returns a blank "" string

func GetExtension($some_name)
    local $parts = StringSplit($some_name".")
    local $e = $parts[$parts[0]]
    if $e <> $some_name and not StringInStr($e"\") then  "." was not found - extensionless file, possibly in a path with a dot
        return $e
    else
        return ""
    endif
endfunc


; RemoveExtension()
;
; removes the extension of a file name (including the dot ".")
; requires the above functions

func RemoveExtension($some_name)
    local $add = 0
    if StringInStr(BaseName($some_name), ".") then $add = 1
    return StringTrimRight($some_name, StringLen(GetExtension($some_name)) + $add)
endfunc


; CleanName()
;
; returns a file name minus the path AND the extension
; basically does two of the above functions, all-in-one..

func CleanName($some_name)
    return RemoveExtension(BaseName($some_name))
endfunc



; GetParent()
;
; returns the parent directory of a given file or directory path..

func GetParent($gp_dir)
    local $gp_full_path = StringSplit($gp_dir"\"; array
    return StringTrimRight($gp_dir, StringLen($gp_full_path[$gp_full_path[0]]) + 1) ; 1 = "\"
endfunc




; IsDir()
;
; is the given path a directory?

func IsDir($some_path)
    ; simple but slow..
    ; (although the fastest of all the methods I've tried - a lot)
    return StringInStr(FileGetAttrib($some_path), "D";, 2 = slower!
endfunc




; ReadDir()
;
; open a folder and return files with a particular $extension (no "." dot)
; as an array of file names. See RecurseDir() (below) for
; more functionality.
;
; NO Wild-Cards Allowed.
;
; Alternatively, supply full file name. Wilcards allowed.

func ReadDir($folder$extension$full_filename="")

    ; AutoIt array handling is basic, to say the least!
    local $files[1]
    local $new_array[2]
    local $filename = "*."
    if $full_filename then
        $filename = $full_filename
        $extension = ""
    else
        CLT($extension".")
    endif

    local $init_dir = $folder & "\" & $filename & $extension

    ; create a "search handle" of all the *.$extension files in the folder
    local $search_files = FileFindFirstFile($init_dir)

    if $search_files = -1 then
        FileClose($search_files)
        $search_files = FileFindFirstFile($init_dir)
    endif
    local $i = 1
    do
        local $tmp = FileFindNextFile($search_files)
        $files[$i-1] = $tmp
        $i += 1 ; like php, same as $i = $i + 1
        redim $files[$i]
    until @error

    FileClose($search_files; close the search handle

    ; this removes the extraneous/empty elements from the array
    $i = 2
    for $this_file in $files
        local $entry = StringStripWS($this_file, 3)
        if $entry then
            redim $new_array[$i]
            $new_array[0] = $i-1
            $new_array[$i-1] = $entry
            $i = $i + 1
        endif
    next

    ; wipe this array..
    $files = 0

    if $new_array[0] = "" then return 0

    ; return the array of filenames..
    return $new_array

endfunc


;
; RecurseDir()    v2.3
;
; Recursively search a directory structure for files matching a pattern
; and return its files as an array of file paths, the first value being the
; total number of file paths in the array (a-la "AutoIt Array").
;
; I spent some time testing many different routines. _GetFileList, by Jos van
; der Zande, always gave me the best results, and nicely coded, but around ten
; times slower (52s) than Larry (and Beerman's) recursion routines (4.9s) when
; recursing my home folder.**
;
; ** 1000 folders, 4773 files, 702MB. [cpu:1.3GHz, 640MB RAM] at time of writing
;
; This function is based on _GetFileList, but after a few hacks and tweaks is now
; more than fifteen times faster than the original.** The results are still as good,
; but instead of 50+ seconds to recurse my home folder, it now takes 3.3 seconds,
; making it fastest and bestest of all the AutoIt recursion routines! *tic*
;
; Note: you can now supply multiple file masks (needed for backup). It makes a lot
; of sense to grab any other extensions while we are in a directory.
; The delimiter is a comma..
;
;        RecurseDir("C:\Program Files""*.reg,*.ini,*.cfg")
;
; When searching for multiple masks the speed improvements are *staggering*, and
; logarithmic; basically multiply the number of masks. For instance, a backup of
; all the pref files in my Program Files folder is scanned, copied, zipped and
; completed in around a minute. pretty good, considering it's over 12GB; all
; tools, no big game installs, and ten file masks to search.
;
; The optional third parameter "$dont_recurse" tells RecurseDir() to only return
; matches for files in the top level directory, no deeper. (true/false)
; see also ReadDir() above.
;
; You can also supply an optional fourth parameter which is a string; the path to
; a "dump file" to dump (log) the paths of all matched files; for debugging only,
; because it will slow things down some.
;
; In v2.2 you can also supply an optional fifth parameter, "$return_dirs" which
; will do exactly that, returning an AutoIt array of all the directories in the
; path, and *only* the directories. (true/false)
;
; The optional 6th parameter ($max) is the maximum limit for returned paths,
; which is normally 1,000,000 (one million). Bigger sizes use more memory, roughly
; 10MB per million (for the initial *empty* array - before it gets filled with
; values).  The absolute maximum size for an array is around 8,388,606, so don't
; go above that, or you will get errors. Also, ensure this value is never zero.
;
; This function gets used a lot in my apps.
;
; **    A lot to do with using the "&=" operator. Those wee differences mount up.
;        Probably that operator wasn't available when the code was first written.
;

;global $quit = false

func RecurseDir($dir$mask$dont_recurse=false, $dump=""$return_dirs=false, $mx=1000000)

    local $n_dirnames[$mx]    ; maximum number of directories which can be scanned
    local $n_dircount = 0    ; ^ could be set much higher, if required
    local $n_file
    local $n_search
    local $n_tfile
    local $file_array
    local $filenames
;    local $filecount
    local $dircount = 1

    ; if there was an "\" on the end of the given directory, remove that..
    CRT($dir)

    $n_dirnames[$dircount] = $dir

    if not FileExists($dir) then return 0

    while $dircount > $n_dircount ; keep on looping until all directories are scanned..

;        if $quit = 1 then return

        $n_dircount += 1
        $n_search = FileFindFirstFile($n_dirnames[$n_dircount] & "\*.*")

        while true  ; find all subdirs in this directory and store them in a array..
            $n_file = FileFindNextFile($n_search)
            if @error then exitloop
            ; skip directory references..
            if $n_file = "." or $n_file = ".." then continueloop

            $n_tfile = $n_dirnames[$n_dircount] & "\" & $n_file

            ; if it's a directory, add it to the list of directories to be processed..
            if StringInStr(FileGetAttrib($n_tfile ), "D") and not $dont_recurse then
                $dircount += 1
                $n_dirnames[$dircount] = $n_tfile
            endif
        wend
        FileClose($n_search)

        ; multiple masks..
        if StringInStr($mask",", 2) then
            local $mask_array = StringSplit($mask",")
        else ; or else create a dummy array..
            local $mask_array[2] = [1, $mask]
        endif

        ; loop through the array of masks..
        for $mask_c = 1 to $mask_array[0]
            ; find all files that match this mask..
            $n_search = FileFindFirstFile($n_dirnames[$n_dircount] & "\" & $mask_array[$mask_c] )
            if $n_search = -1 then continueloop

            while true
                $n_file = FileFindNextFile($n_search)
                if @error then exitloop ; end of dir
                if $n_file = "." or $n_file = ".." then continueloop

                $n_tfile = $n_dirnames[$n_dircount] & "\" & $n_file
                if not StringInStr(FileGetAttrib( $n_tfile ), "D") then
;                    $filecount += 1
                    $filenames &= $n_tfile & @LF
                endif
            wend
            FileClose($n_search)
        next
    wend

    ; flip to a string and back to remove extraneous entries
    ; this is quicker than redimming on every loop
    if $return_dirs then
        local $tmp_str = ""
        $i = 1
        while $n_dirnames[$i] <> ""
            $tmp_str &= $n_dirnames[$i] & "|"
            $i += 1
        wend
        $tmp_str = StringTrimRight($tmp_str, 1)
        $n_dirnames = StringSplit($tmp_str"|")
        return $n_dirnames
    endif

    $filenames = StringTrimRight($filenames, 1)
    if $filenames = "" then return 0
    $file_array = StringSplit($filenames, @LF)

    ; dump results to a file..
    if $dump then
        local $dump_file = FileOpen($dump, 2)
        FileWrite($dump_file$filenames)
        FileClose($dump_file)
    endif
    return($file_array)
endfunc




; IniReadCheckBoxValue()
;
; Slightly altered for ffe and its "tristate" checkboxes..
;
; This function "transforms" an AutoIt or human unchecked value (4 or 0, respectively),
; into plain old 4, which AutoIt can understand. this function is intended as a drop-in
; replacement for the IniRead command, simply replace the function name.
; Of course, it's only useful when reading checkbox values, e.g..
;
;    $big_switch = IniReadCheckBoxValue($ini_path$my_name"big_switch"$GUI_UNCHECKED)
;
; However I've gotten into the habit of using $GUI_CHECKED and $GUI_UNCHECKED as
; general booleans, which has proven to be very effective, especially when coupled
; with these two functions. Why? ..
;
; Windows annoyingly uses 1 as the value for checked checkboxes, and 4 as the value
; for unchecked checkboxes.* This makes passing the values directly in and out of ini
; files undesirable, because "4" is not a logical value, and most humans would expect
; it to be 0 (zero). The following two functions act as interface between the program
; and the ini file, making sense of the "human" equivalents. Other "human" values are
; also understood, just in case..

func IniReadCheckBoxValue($rcbv_inifile$rcbv_section$rcbv_key$rcbv_default$three_state=false)

    ; IF key NOT FOUND, returns DEFAULT
    ; IF key BLANK (empty) returns INTERMEDIATE

    local $ircbv_val = IniRead($rcbv_inifile$rcbv_section$rcbv_key"---")

    if $ircbv_val = "---" then $ircbv_val = $rcbv_default
    if $three_state and $ircbv_val = "" then return $GUI_INDETERMINATE

    switch $ircbv_val
        case $GUI_UNCHECKED    ; 4
            return $GUI_UNCHECKED
        case "false""off""no""not""nope""nay""nay!""nah""nah!""no way!""no sir!""negative""neg""no!""disable""disabled"
            return $GUI_UNCHECKED
        case "true""on""yes""yes!""yay""yay!""yup""hell yes!""indeed""yes sir!""yessir!""affirmative""cool""enable""enabled"
            return $GUI_CHECKED
        case "2", 2, "unset""-"
            return $GUI_INDETERMINATE
        case "0"
            return $GUI_UNCHECKED
        case "1"$GUI_CHECKED ; 1
            return $GUI_CHECKED
        case else ; some special value
            return $ircbv_val
    endswitch
endfunc


; for display purposes..
func ProcessWriteHumanCheckBoxValue($some_string$on_str="enabled"$off_str="disabled",$indet_str="unset")
    switch $some_string
        case $ON
            return $on_str
        case $OFF
            return $off_str
        case $GUI_INDETERMINATE""
            return $indet_str
        case else
            return $some_string
    endswitch
endfunc


; IniWriteCheckBoxValue()
;
; This function transforms an AutoIt checkbox value into a 'human' unchecked value (4 into 0, basically)
; this is intended as a drop-in replacement for the IniWrite command, simply replace the function name.
; Of course, it's only useful when writing checkbox values that will be read by 'IniReadCheckBoxValue'
; above. Instead of 0, you can also write "no""off", or whatever, by passing the optional 5th parameter..

func IniWriteCheckBoxValue($wcbv_inifile$wcbv_section$wcbv_key$wcbv_val$tru_val="true"$fal_val="false")
    switch $wcbv_val
        case $GUI_CHECKED
            $wcbv_val = $tru_val
        case $GUI_UNCHECKED
            $wcbv_val = $fal_val
        case $GUI_INDETERMINATE
            $wcbv_val = ""
    endswitch
    if $wcbv_val then
        IniWrite($wcbv_inifile$wcbv_section$wcbv_key$wcbv_val)
    else
        ; we delete empty values - then they are "unset" proper!
        IniDelete($wcbv_inifile$wcbv_section$wcbv_key)
    endif
endfunc

; The above functions are useful until you create a proper preferences interface for your application!
; actually, I tend to use $GUI_CHECKED and $GUI_UNCHECKED as general-purpose booleans these days.



; quick switcharoo..
func SwitchBool($bool)
    if $bool = $ON then return $OFF
    return $ON
endfunc




; InArray()        [for single-dimension arrays]
;
; Feed it an AutoIt array and a string, returns true if $ia_string
; is one of the $ia_array's *values*. Non-AutoIt arrays work fine,
; the first element is not relied upon, it is simply ignored.
;
; The search is case-insensitive, but must be an exact (not partial) match.
; There's probably a real function for this these days. (Not yet!)

func InArray(ByRef $ia_array$ia_string)
    if not IsArray($ia_array) then return false
    local $ia_limit = UBound($ia_array) - 1
    for $i = 1 to $ia_limit ; not 0, which would return the total as a positive result if $ia_array[0]= e.g. "1"
        if $ia_string = $ia_array[$i] then return $i
    next
    return false
endfunc



; from the UDF's..
; here to save including the whole files.

; Description:    _Singleton
; Author(s):      Valik
Func ce_Singleton($occurenceName$flag = 0)
    Local $ERROR_ALREADY_EXISTS = 183
    $occurenceName = StringReplace($occurenceName"\"""; to avoid error
    Local $handle = DllCall("kernel32.dll""int""CreateMutex""int", 0, "long", 1, "str"$occurenceName)
    Local $lastError = DllCall("kernel32.dll""int""GetLastError")
    If $lastError[0] = $ERROR_ALREADY_EXISTS Then
        If $flag = 0 Then
            Exit -1
        Else
            SetError($lastError[0])
            Return 0
        endif
    endif
    Return $handle[0]
EndFunc   ;==>_Singleton


; _IsPressed (is a key pressed?)
; Author(s):    ezzetabi and Jon / Valik

func ce_IsPressed($Key)
    local $kp = DllCall('user32.dll', "int""GetAsyncKeyState""int", '0x' & $Key)
    if not @error and BitAND($kp[0], 0x8000) = 0x8000 then return 1
    return 0
endfunc



; VisitURL()
;
; send the "default browser" to our URL..

; This uses the USER'S SYSTEM BROWSER! (eg. Firefox)

func VisitURL($vu_url="http://corz.org/")
    ShellExecute($vu_url)
    if @error <> 0 then
        return true
    else
        return SetError (@error, default , true)
    endif
endfunc



; CleanPath()
;
; Clean-up potentially problematic Windows file path characters..

func CleanPath($string)
;    The very brave might use this..
;    $string = StringReplace($string"|""¦")
;    $string = StringReplace($string, '"', "¨")
;    $string = StringReplace($string, ":", "")
;    $string = StringReplace($string, "*", "˚")
;    $string = StringReplace($string, "/", "")
;    $string = StringReplace($string, "\", "~")
;    $string = StringReplace($string, ">", "˂")
;    $string = StringReplace($string, "<", "~")
;    $string = StringReplace($string, "?", "¿")
;    For compatibility, I recommend this..
    $string = StringReplace($string, "
|", ".")
    $string = StringReplace($string, '"
', ".")
    $string = StringReplace($string":"".")
    $string = StringReplace($string"*"".")
    $string = StringReplace($string"/"".")
    $string = StringReplace($string"\"".")
    $string = StringReplace($string">"".")
    $string = StringReplace($string"<"".")
    $string = StringReplace($string"?"".")
    return $string
endfunc


func CompressToPrefName($string)
    $string = CleanPath($string)
    $string = StringReplace($string, '"', "_")
    $string = StringReplace($string, "
'", "_")
    $string = StringReplace($string, "
=", "_")
    $string = StringReplace($string, "
[", "_")
    $string = StringReplace($string, "
]", "_")
    $string = StringReplace($string, "
(", "_")
    $string = StringReplace($string, "
)", "_")
    $string = StringReplace($string, "
.", "_")
    $string = StringReplace($string, "
 ", "_")
    $string = StringReplace($string, "
-", "_")
    return $string
endfunc



; Normalize all line-endings
; to @CRLF, or whatever..

; this is the fastest, bestest, simplest method..
func UnifyCRLF($some_text$LF=@CRLF)
    return StringRegExpReplace($some_text, "
\R", $LF)
;    return StringRegExpReplace($string, '(*BSR_ANYCRLF)\R', @CRLF)
endfunc



; convert seconds to readable H/M/S time..

func SecondsToDHMS($sec=0)

    if $sec < 0 then return -1
    select
        case  $sec < 61
            return $sec & "
 seconds"
        case $sec < 3601
            return StringFormat('%.01dm %.01ds', Mod(($sec / 60), 60), Mod($sec, 60))
        case $sec < 86401
            return StringFormat('%.01dh %.01dm %.01ds', Mod($sec / 3600, 24), Int(Mod(($sec / 60), 60)), Mod($sec, 60))
        case else
            return StringFormat('%.01dd %.01dh %.01dm %.01ds', Mod($sec / 86400, 7), Mod($sec / 3600, 24), Int(Mod(($sec / 60), 60)), Mod($sec, 60))
    endselect
endfunc




; from octet.au3, author unknown..    (note: this is slow)

func MakeRandomAlphaNumericString($iLen)
    local $sString = ''
    do
        switch Random ( 1, 3, 1 )
            case 1
                $sString &= Chr(Random( 48, 57, 1))  ; 0 to 9
            case 2
                $sString &= Chr(Random( 65, 90, 1))  ; A to Z
            case 3
                $sString &= Chr(Random( 97, 122, 1)) ; a to z
        endswitch
    until StringLen($sString) = $iLen
    return $sString
endfunc



; UDF updates..

; these are improvements on the UDF-supplied versions posted in the AutoIt forum..
;
; This is the fastest FileReadToArray, but uses the most memory for big files (x64: 4.5s/1.02GB on a 106MB file, 912515 lines)
;
#FUNCTION# ====================================================================================================================
; Name...........:    FileReadToArrayOptimized
; Description ...:    Reads the specified file into an array.
; Syntax.........:    FileReadToArrayOptimized($TmpFile, ByRef $aArray [, $iFlag])
; Parameters ....:    $TmpFile        - Full path and filename of the file to be read.
;                    $aArray            - The array in which to store the contents of the file.
;                    $iFlag            - Optional: (add the flags together for multiple operations):
;                    |$iFlag = 0 Return the array count in the [0] element (create 1-based array index - the Default)
;                    |$iFlag = 1 Don't return the array count (create 0-based array index)
;                    |$iFlag = 2 Don't return Line empty (ignores @CR & @LF & @CRLF)
;                    |$iFlag = 4 Don't return Line empty or lines containing only whitespace character (ignores @CRLF, " ", @CR, @TAB, @CR, @LF, etc.)
;                    |$iFlag = 8 Strip Line leading white space
; Return values .:    Success - Returns a 1
;                    Failure - Returns a 0
;                    @error  - 0 = No error.
;                    |1 = Error opening specified file
;                    |2 = Unable to Split the file
; Authors ........:    Jonathan Bennett, Valik, Jpm, Gary, guinness, DXRW4E, Cor
; ===============================================================================================================================
func FileReadToArrayOptimized($TmpFile, byref $aArray$iFlag = 0)
    local $ArrayCount$RegExp = "
(?:\r\n|\n|\r)([^\r\n]*)"
    local $hFileOpen = FileOpen($TmpFile, 0)
    if $hFileOpen = -1 then return SetError(1, 0, 0)
    local $sFileRead = StringStripWS(FileRead($hFileOpen), 3)
    FileClose($hFileOpen)

    ; Flags..
    if not BitAND($iFlag, 1) then $ArrayCount = "
ArrayCount" & @LF
    if BitAND($iFlag, 2) then $RegExp = "
(?:\r\n|\n|\r)([^\r\n]+)"
    if BitAND($iFlag, 4) then $RegExp = "
s*(?:\r\n|\n|\r)([^\r\n]+)"
    if BitAND($iFlag, 8) then $RegExp = StringReplace($RegExp, "
)", ")h*", 1, 1)

    $aArray = StringRegExp(@LF & $ArrayCount & $sFileRead$RegExp, 3)

    if @error then
        if StringLen($sFileRead) then
            local $ret[2] = [1, $sFileRead]
            $aArray = $ret
        else
            return SetError(2, 0, 0)
        endif
    elseif $ArrayCount then
        $aArray[0] = UBound($aArray) - 1
    endif
    return 1
endfunc







;;    debugging functions..




; debug()
;
; provides quick debug report in your console..
;
; if your text editor can do it (probably), this is a great
; way to get debug output without halting the script execution..
;
; NOTE: if you call debug() in a compiled script, and $c-debug is set to $ON,
; you will get the debug() output dump()ed, instead.

func debug($d_string$ln=false)
    if @compiled then
        return 0
    endif
    ; unlikely to catch anything under normal circumstances (string prepended to input)..
    if IsArray($d_string) then return PrintArray($d_string, "
NOT A STRING!")
    local&nb