corz.org text viewer..
[currently viewing: /public/machine/source/beta/windows/ffe/ffe.au3 - raw]
global $version = "2.5.4"
global $my_version = FileGetVersion(@ScriptFullPath, "FileVersion")
global $special_build = "Eejit Soup"

#cs

    ffe - FFmpeg front-end for Windows

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


        *** BEFORE COMPILING ***

        This will compile with the latest AutoIt or AutoIt Beta (recommended).
        At the time of writing, that is v3.3.14.5 and v3.3.15.3, respectively.

        You will want to edit this file before compiling.
        Please see the compile options at the foot of this program.

        Search for "::dev::" in the code.


About:

    FFmpeg, by Fabrice Bellard, et al., is a quite incredible multimedia
    converter (and much more!), 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 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". It can then go on to perform the
    final job, of course, and a whole lot more.

    ffe uniquely uses MATOF technology to automatically update output file names
    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, infinitely
    customizable presets and customizable parameter buttons, pre- and post-job
    (and post-file) 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.

    More info here:

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


    ffe version info here..

        http://corz.org/machine/source/beta/windows/ffe/Itstory.txt


To use:

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

    Run ffe.exe

    That's it.

    If you run ffe somewhere else, it will ask you to locate FFmpeg before you
    begin work.

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

        http://corz.org/engine?section=beta/windows/ffe&source=Itstory.txt




Bugs..


    When toggling MATOF, old output paths return
    (no biggie - delete and boom! - but mildly inconvenient)


2do..

    Search for "2do" inside the code..


  2do Maybe..

    *    Grab post-file exit codes and (if waiting)
        (optionally) only process next file on success (0)

    *    Auto Parameter Increment testing.

            Use a button (next to outputfile?) to set a "sequence".

                <parameter to target> = <sequence>

                    <sequence> can be a range, e.g. 1-10,1    (step 1)
                        or 1-10,2 (step 2)

                    or a list: 1,3,5,6,8,9,10

            button/manually in extra parameters..

                    crf=[[20,21,22,24,25,27]]
                    crf=[[20-30,2]]


    *    Watch Mode        (use Windows API directly for this)

                _WinAPI_FindFirstChangeNotification()

        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.

        If no move-to folder specified, create a "DONE" folder in the working dir.



Done, to document..

        Aaargh.. A lot!


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

    Grab a ready-made binary (with source) here..

        http://corz.org/public/machine/download/beta/windows/


#ce


#include <Constants.au3>
#include <GuiConstants.au3>
#include <WinAPIConstants.au3>
#include <WinAPISysWin.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 <Array.au3>
#include <gdiplus.au3>

#include <WinAPIShellEx.au3>
#include <File.au3>
#include <GuiMenu.au3>

; Bite the bullet..!
#include "Resources\cel.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. Included.
;
; global Const $AC_SRC_ALPHA = 0x011
global Const $AC_SRC_ALPHA = 1
#include "Resources\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 leave it in for the release.


global const $EXIT_PRESET            = "FFE-EXIT-SETTINGS"
global const $PRESET_BACKUP_STRING    = "--backup--"


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


; Init vars..

; Set in ce.au3..
$my_name = "ffe"
$ini_path = $my_name & ".ini"
$my_domain = "corz.org"
$data_dir = @AppDataDir & "\corz\" & $my_name

global $me_app
global $my_title = " ffe.. FFmpeg front-end"
global $abort_batch = false
global $got_helps = ""
; Will become the FFmpeg process PID..
global $ffmpeg = 0
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_SETTINGS = "main settings"

global const $NAME_BUTTONS = "custom buttons"
global const $NAME_PRESETS = "presets"

global const $NAME_VIDEO_MAPPINGS = "mappings-video"
global const $NAME_AUDIO_MAPPINGS = "mappings-audio"

global $not_presets
global const $NOT_PRESETS_LIST = $my_name & "," & $NAME_BUTTONS & "," & $NAME_VIDEO_MAPPINGS & "," & $NAME_AUDIO_MAPPINGS & "," & $EXIT_PRESET


; For find in output..
#include "Resources\EditFind.au3"


; 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
else
    ;::dev::..
    ; Enter the path to your own local binary..
    $me_app = "C:\Program Files\corz\ffe\ffe.exe"
endif

; Set in cel.au3..
$debug_level = 10
$dump_file = $data_dir & "\ffe_debug.log"

; 0 = no limit, or a number (in MB). Set in ini prefs.
$max_debug_log_size = 0

; Quick pre-check for installed users, prevents spurious debugging output bugging you..
if FileExists($data_dir & "\" & $ini_path) then
    $debug_level = Int(IniRead($data_dir & "\" & $ini_path$my_name"debug_level"$debug_level))
endif
if FileExists($dump_file) then FileDelete($dump_file)


; Memory is cheap!
global $inputfile$old_inputfile$extra_args$v_codec$a_codec$resize_preset$args$short_args$msgs$count_ints
global $installed_ini$matof_string$old_matof$no_video$no_audio
global $launch_preset$user_inputfile$user_outputfile$enable_custom_buttons
global $find_count = 0, $switches$go$do_gen=false, $do_quit=false, $do_shutdown=false
global $button_delim$am_enable_custom_buttons$am_button_notes_to_console
global $tray_abort_batch$tray_toggle_drop_window$tray_toggle_start_minimized$tray_toggle_delayed_start
global $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
global $tray_toggle_retain_recent_files$tray_about_ffmpeg
global $now_time$on_top_counter$clean_comments$warn_control
global $delete_to_recycle_bin$am_delete_to_recycle_bin$always_warn_on_delete$am_always_warn_on_delete

global $ffeGUI$GUI_DropWindow$GUI_DropWindowResizer$batch_output_dir$inp_inputfile
global $lab_inputfile$inp_outputfile$lab_outputfile$ini_outputfile$butt_wipe$inp_input_params

global $combo_presets$ctxt_combo_sort
global $x_param

; Prefs where restart is required..
global $sort_presets_list$sort_presets_list_orig
global $sort_presets_list_texts = "&Sort Presets    (Restart"

global $allow_console_tooltip$allow_console_tooltip_orig
global $allow_console_tooltip_text = "&ToolTips over Console Output    (Restart"

global $console_wordwrap$console_wordwrap_orig
global $console_wordwrap_text = "&Wrap Console Output    (Restart"

global $image_buttons$image_buttons_orig
global $image_buttons_text = "&Images on (some) Buttons    (Restart"

global $do_tooltips_orig
global $do_tooltips_text = "Show &MouseOver ToolTip Help    (Restart"



global $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_x$inp_crop_y$inp_crop_width$inp_crop_height$inp_x_size$inp_y_size$check_concatenate
global $label_active_crop_wh$label_active_crop_xy
global $check_run_pre_job_commands$check_run_post_job_commands$check_overwrite
global $check_run_ffmpeg_task$check_run_ffplay_task$butt_reset
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
global $set_wh$set_xy$set_if$set_of$previous_pos$do_countdown_timer$time_in_title
global $am_post_file_run_style$am_post_file_capture$am_post_file_show$am_auto_codecs
global $am_always_on_top$am_allow_multiple$am_do_countdown_timer$am_kill_ffmpeg_on_exit$am_start_minimized$am_pause_is_global
global $am_console_wordwrap$am_trans$am_reptypes$am_image_buttons$am_about_ffmpeg$am_default_extension$am_show_ffplay_output
global $am_do_tooltips$am_time_in_title,  $am_sort_presets_list$am_cpu$am_drop_command$am_launch_with_drop_command$am_allow_output_tooltip
global $am_retain_exit_settings$am_use_mediainfo$am_save_reports$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$title_msg_string
global $am_custom_buttons_columns$custom_buttons_array$preset_notes$notes_prefix
global $paused$pause_is_global$output_paused=false, $generate_script = false, $shifted = false, $timeout=false
global $portable = false, $delay_start_at = false, $loaded_exit_settings = false
global $current_preset = $my_name

global $ctxt_vcombo$ctxt_acombo


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][2]

global $min_width = 860
global $min_height = 442
global $height_magic = 33 ; Magic!
global $maximized = $OFF$minimized = $OFF
global $start_minimized

; App Menu Sub-Menus..
global $DropCommands[5] = ["None""Go""Generate""Report""Play"]
global $DropCommandMenuItems[UBound($DropCommands)]

global $arTransItems[10], $nTPChecked = 0

global $nCPUChecked = 0
global $arCPU[6] = ["Idle/Low""Below Normal""Normal""Above Normal""High""Realtime (Use with caution!)"]
global $arCPUItems[UBound($arCPU)]

global $ReportTypes[7] = ["default""compact""csv""flat""ini""json""xml"]
global $ReportTypesMenuItems[UBound($ReportTypes)]

global $PostFileRunStyles[3] = ["Direct""DOS""ShellExecute"]
global $PostFileRunStylesMenuItems[UBound($PostFileRunStyles)]

global $CBMChecked$custom_buttons[502], $CustomButtonMenuItems[502] ; Arbitrary number


"Known" files we have probed already..
global $known_files
; Associative arrays in AutoIt? Hells yeah!
AAInit($known_files)

; We feed this list to FFmpeg for concatenation (join) jobs..
global $concat_list = @TempDir & "\ffe-concat-list.txt"


; Custom Button Grid..
; Well, we put the button grid right *here*..
global $grid_x = 448
global $grid_y = 143

; You can mess with size and spacing in your ini..
global $buttons_x_shunt$buttons_y_shunt$button_spacing

; ToolTips..
global $tip_icon_index

; global ToolTips we update on change (we update others, too, but differently)
global $tip_post_file$tip_pre_job$tip_post_job$tip_overwrite$tip_concatenate
global $tip_ffmpeg_task$tip_ffplay_task$tip_quit$tip_shutdown$tip_short_test


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

global $matof_separator$cpu_priority$short_test_frames$fallback_folder$console_output_font
global $console_output_font_size$custom_buttons_columns$custom_buttons_font_size
global $custom_buttons_width$custom_buttons_height$do_output$button_notes_to_console
global $drop_command$launch_with_drop_command
global $retain_exit_settings$show_ffe_in_sorted_list$ffmpeg_binary$plugins_path$ffplay_binary
global $help_texts$help_butts$retain_recent_files
global $GDI_dll$allowed_image_types$do_drop_window$drop_win_image
global $drop_win_transparency$drop_win_hover_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
global $post_file_command$check_run_post_file_command
global $post_file_run_style="direct"$post_file_capture=$ON$post_file_show=$ON


; FFprobe/MediaInfo reporting..
global $ffprobe_loc$report_format$save_reports$report_directory$report_extension
global $report_switches$nRTChecked$pfsChecked$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

global $default_extension = "mkv"
global $kill_ffmpeg_on_exit = $ON
; Read-only setting..
global $default_audio_extension = "aac"

; Red. You can set this in your ini.
global $warn_colour = "FF0000"


; We check the user has actually altered these. If not, we don't save to the preset..
global $altered_resize_first$altered_do_matof$altered_do_output

global $current_control_focus$buttons_xy$double_check_rclicks
global $show_ffplay_output$ffmpeg_command$ffplay_command$play_command

global $too_far = false
global $right_clicking = false

; We will update the ToolTips with the current state, so set the strings now for re-use..
;
global $tristate_prejob_title = "Pre-Job Commands"
global $tristate_prejob_tip = "Before the job runs, run your specified pre-job commands batch file? " & $MSG_LF & _
                                "Right-click to specify/create a pre-job commands file." & $MSG_LF & $MSG_LF & _
                                "Running " & $tristate_prejob_title & " is currently: "

global $tristate_postfile_title = "Post-File Commands"
global $tristate_postfile_tip = "After each file is processed, run your specified post-file command. " & $MSG_LF & _
                                "Right-click to specify a post-file command." & $MSG_LF & $MSG_LF & _
                                "Running " & $tristate_postfile_title & " is currently: "

global $tristate_postjob_title = "Post-Job Commands"
global $tristate_postjob_tip = "After the job runs, run your specified post-job commands batch file? " & $MSG_LF & _
                                "Right-click to specify/create a post-job commands file." & $MSG_LF & $MSG_LF & _
                                "Running " & $tristate_postjob_title & " is currently: "

global $tristate_overwrite_title = "Overwrite Existing Files"
global $tristate_overwrite_tip = "Should ffe tell FFmpeg to overwrite existing files? " & $MSG_LF & $MSG_LF & _
                                    $tristate_overwrite_title & " is currently: "

global $tristate_concatenate_title = "Join Output Files"
global $tristate_concatenate_tip = "During batches, should ffe tell FFmpeg to join the output files together? " & $MSG_LF & $MSG_LF & _
                                    $tristate_concatenate_title & " is currently: "

global $tristate_quit_title = "Quit When Done"
global $tristate_quit_tip = "Should ffe quit when the job is complete? " & $MSG_LF & $MSG_LF & _
                            $tristate_quit_title & " is currently: "

global $tristate_shutdown_title = "Shutdown PC When Done"
global $tristate_shutdown_tip = "Should ffe shutdown your computer when the job is complete? " & $MSG_LF & $MSG_LF & _
                            $tristate_shutdown_title & " is currently: "






; Unused functions are stripped at compile-time.
; This makes for easy navigation in a good text editor.
; You can click your function list to get straight here.
;
func __________________START_HERE()
endfunc



; 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



debug("", @ScriptLineNumber, 2);debug
debug($LOG_LF & "Begin DEBUG output for ffe at " & DateTimeString() & $LOG_LF, @ScriptLineNumber, 2);debug
debug("Command-Line Switches:  ($switches): " & $switches, @ScriptLineNumber, 3);debug
debug("Input File ($inputfile): " & $inputfile, @ScriptLineNumber, 3);debug


; Process special switches..
$go = true : we run the job immediately
$do_gen = true : generate a batch (.bat) file

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, 4) = "quit" then
        $launch_preset = StringTrimRight(StringMid($switches, 6, -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

debug("$launch_preset: " & $launch_preset, @ScriptLineNumber, 3);debug

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


CheckDirWild($inputfile)
debug("Input File ($inputfile) now: " & $inputfile, @ScriptLineNumber, 3);debug


; Portable mode..
; :bug: weird dev bug - if running program from exec command in notepad++, it
"finds" the ini inside my "Resources" folder and then goes on to create a
; portable ini next to the program.exe.
; If this happens to you during dev, let me know!
;
if FileExists($ini_path) then
    debug("ffe running in Portable Mode..", @ScriptLineNumber, 2);debug
    $portable = true
    $data_dir = @ScriptDir
    $ini_path = $data_dir & "\" & $ini_path
else
    ; Regular AppData usage..
    debug("ffe running in Installed/Dev Mode..", @ScriptLineNumber, 2);debug
    if not FileExists($data_dir) then DirCreate($data_dir)
    $ini_path = $data_dir & "\" & $ini_path
    $installed_ini = FileInstall(".\Resources\ffe.ini"$ini_path)
endif

; Update ini to latest version..
if not $installed_ini then UpdateffeIniFile()




; STILL NO INI FILE!
if not FileExists($ini_path) then
    debug("Problem with ini ==> " & $ini_path, @ScriptLineNumber, 1);debug
    MsgBox(0, "No ffe.ini found!""ffe.ini was not found and could 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
    _Singleton($my_name, 1)
    if @error = 183 then
        WinActivate($my_title; Quite why this is now instance 2, I have no idea. Instance 1 is now the presets combo! Go figure.
        if $inputfile then ControlSetText($my_title"""[CLASS:Edit; INSTANCE:2]"$inputfile, 1)
        debug("ffe already running. Passing file to existing ffe instance.. ", @ScriptLineNumber, 2);debug
        exit 5
    endif
endif





; OK!

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


; Load either the default settings [ffe] or some specified preset..
global $preset_loaded = LoadPreset($launch_preset, true) ; 2nd param set here only, for "INIT".
; We will find other uses for this variable!



; If ini file gets too big, or the user chose this now, clean up the comments.
if FileGetSize($ini_path) > (1024*60) then $clean_comments = $ON
CleanIniComments()



; Do it now?


; Command-line action..
if $launch_preset and $inputfile and $go then

    if $preset_loaded then DoIt()

else

    ; Start where we left off..
    if $retain_exit_settings = $ON then
        if not $launch_preset and not _IsPressed(10) and InArray($presets$EXIT_PRESET) then
            $preset_loaded = LoadPreset($EXIT_PRESET, true)
            if $preset_loaded then $loaded_exit_settings = true
            ConsoleAdd("Previous exit settings restored.", @ScriptLineNumber)
        ; Hold down SHIFT during launch to disable exit settings..
        elseif _IsPressed(10) then
            $retain_exit_settings = $OFF
            IniWriteCheckBoxValue($ini_path$my_name"retain_exit_settings"$retain_exit_settings)
            ConsoleAdd("Retain exit settings disabled.", @ScriptLineNumber)
        endif
    endif

    ; launch_with_drop_command ?
    ;
    if $launch_with_drop_command = $ON and $inputfile then
        if FileExists($inputfile) then
            DoDropCommand()
        else
            ConsoleAdd("Launch with drop command aborted: " & $inputfile & " does not exist", @ScriptLineNumber)
        endif
    endif

endif





; Idle loop..

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 variables 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!





; Get user ini values..

func GetPrefs($current_section=$my_name)    ; Specify section (for reference (see IniReads below) and later use)

    debug("", @ScriptLineNumber, 6);debug
    debug("GetPrefs($current_section)" & $current_section, @ScriptLineNumber, 4);debug

    ; NOW we set the user debug level..
    $debug_level = Int(IniRead($ini_path$my_name"debug_level"$debug_level))
    if $debug_level > 1 then debug("***    ffe running debug level: " & $debug_level & "    ***", @ScriptLineNumber, 2);debug

    debug("Dumping prefs:: ", @ScriptLineNumber, 8);debug

    $dump_file = ffeDeTokenizeString(FixPathSlashes(IniRead($ini_path$my_name"dump_file"$data_dir & "\ffe_debug.log")))
    debug("USER SET $dump_file: " & $dump_file, @ScriptLineNumber, 8);debug
    if not $dump_file then $dump_file = $data_dir & "\ffe_debug.log" $data_dir & "\ffe_debug.log"
    debug("$dump_file: " & $dump_file, @ScriptLineNumber, 8);debug

    $max_debug_log_size = Int(IniRead($ini_path$my_name"max_debug_log_size", 0 ))
    debug("$max_debug_log_size: " & $max_debug_log_size, @ScriptLineNumber, 8);debug

    ; The available sections (presets+)
    $presets = IniReadSectionNames($ini_path)
    debug_PrintArray($presets"$presets:", @ScriptLineNumber, 8);debug

    $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", 864))
    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
    debug("Dimensions: " & "x: " & $x & " y: " & $y & " width: " & $width & " height: " & $height, @ScriptLineNumber, 8);debug


    $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 = $OFF
    debug("$minimized: " & Human($minimized), @ScriptLineNumber, 8);debug
    debug("$maximized: " & Human($maximized), @ScriptLineNumber, 8);debug

    $always_on_top = IniReadCheckBoxValue($ini_path$my_name"always_on_top"$OFF)
    debug("$always_on_top: " & Human($always_on_top), @ScriptLineNumber, 8);debug

    $user_trans = IniRead($ini_path$my_name"transparency", 0)
    debug("$user_trans: " & $user_trans, @ScriptLineNumber, 8);debug

    $do_output = IniReadCheckBoxValue($ini_path$my_name"do_output"$ON)
    debug("$do_output: " & Human($do_output), @ScriptLineNumber, 8);debug

    ; Master ToolTips Switch..
    $do_tooltips = IniReadCheckBoxValue($ini_path$my_name"do_tooltips"$ON)
    debug("$do_tooltips: " & Human($do_tooltips), @ScriptLineNumber, 8);debug
    $do_tooltips_orig = $do_tooltips

    $allow_console_tooltip = IniReadCheckBoxValue($ini_path$my_name"allow_console_tooltip"$ON)
    debug("$allow_console_tooltip: " & Human($allow_console_tooltip), @ScriptLineNumber, 8);debug
    $allow_console_tooltip_orig = $allow_console_tooltip

    $tooltip_time = IniRead($ini_path$my_name"tooltip_time", 10000)
    debug("$tooltip_time: " & $tooltip_time, @ScriptLineNumber, 8);debug

    ; 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
    debug("$tip_icon_res,idx: " & $tip_icon_res & "," & $tip_icon_index, @ScriptLineNumber, 8);debug

    ; 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
    debug("$system_tip_icon: " & $system_tip_icon, @ScriptLineNumber, 8);debug

    ; ToolTip Style..
    $tip_style = IniRead($ini_path$my_name"tip_style", 1)
    debug("$tip_style: " & $tip_style, @ScriptLineNumber, 8);debug

    $sort_presets_list = IniReadCheckBoxValue($ini_path$my_name"sort_presets_list"$ON)
    debug("$sort_presets_list: " & Human($sort_presets_list), @ScriptLineNumber, 8);debug

    ; Flag set for *initial* sorting pref
    $sort_presets_list_orig = $sort_presets_list

    $show_ffe_in_sorted_list = IniReadCheckBoxValue($ini_path$my_name"show_ffe_in_sorted_list"$ON)
    debug("$show_ffe_in_sorted_list: " & Human($show_ffe_in_sorted_list), @ScriptLineNumber, 8);debug


    ; Use images on (some) buttons?
    $image_buttons = IniReadCheckBoxValue($ini_path$my_name"image_buttons"$ON)
    debug("$image_buttons: " & Human($image_buttons), @ScriptLineNumber, 8);debug
    $image_buttons_orig = $image_buttons

    $replace_mode = IniReadCheckBoxValue($ini_path$my_name"replace_mode"$ON)
    debug("$replace_mode: " & Human($replace_mode), @ScriptLineNumber, 8);debug

    ; Tristate - unset to remove control...
    $store_filepaths = IniReadCheckBoxValue($ini_path$my_name"store_filepaths"$OFF, true)
    debug("$store_filepaths: " & Human($store_filepaths), @ScriptLineNumber, 8);debug

    $console_wordwrap = IniReadCheckBoxValue($ini_path$my_name"console_wordwrap"$OFF)
    debug("$console_wordwrap: " & Human($console_wordwrap), @ScriptLineNumber, 8);debug
    $console_wordwrap_orig = $console_wordwrap

    $drop_command = IniRead($ini_path$my_name"drop_command""")
    debug("$drop_command: " & $drop_command, @ScriptLineNumber, 8);debug

    $launch_with_drop_command = IniReadCheckBoxValue($ini_path$my_name"launch_with_drop_command"$OFF)
    debug("$launch_with_drop_command: " & Human($launch_with_drop_command), @ScriptLineNumber, 8);debug

    ; Recent 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_rfstr = IniRead($ini_path$my_name"recent_files""")
        CRT($tmp_rfstr"|"; Shouldn't be required - ArrayJoin() does it on writing.
        if $tmp_rfstr then
            $recent_files = StringSplit($tmp_rfstr"|")
            $recent_files = OneToTwoDArray($recent_files)
        endif
    endif
    debug_PrintArray($recent_files"$recent_files:", @ScriptLineNumber, 8);debug

    $retain_exit_settings = IniReadCheckBoxValue($ini_path$my_name"retain_exit_settings"$ON)
    debug("$retain_exit_settings: " & Human($retain_exit_settings), @ScriptLineNumber, 8);debug

    $do_countdown_timer = IniReadCheckBoxValue($ini_path$my_name"do_countdown_timer"$ON)
    debug("$do_countdown_timer: " & Human($do_countdown_timer), @ScriptLineNumber, 8);debug

    $time_in_title = IniReadCheckBoxValue($ini_path$my_name"time_in_title"$ON)
    debug("$time_in_title: " & Human($time_in_title), @ScriptLineNumber, 8);debug

    $enable_custom_buttons = IniReadCheckBoxValue($ini_path$my_name"enable_custom_buttons"$ON)
    debug("$enable_custom_buttons: " & Human($enable_custom_buttons), @ScriptLineNumber, 8);debug

    $button_delim = IniRead($ini_path$my_name"button_delim""***")
    debug("$button_delim: " & $button_delim, @ScriptLineNumber, 8);debug

    ; The nifty custom buttons..
    $custom_buttons_columns = IniRead($ini_path$my_name"custom_buttons_columns""auto")
    debug("$custom_buttons_columns: " & $custom_buttons_columns, @ScriptLineNumber, 8);debug
    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
    debug("$CBMChecked: " & $CBMChecked, @ScriptLineNumber, 8);debug

    $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
    debug("$custom_buttons_width: " & $custom_buttons_width, @ScriptLineNumber, 8);debug

    $custom_buttons_height = Int(IniRead($ini_path$my_name"custom_buttons_height", 27))
    debug("$custom_buttons_height: " & $custom_buttons_height, @ScriptLineNumber, 8);debug

    $buttons_x_shunt = Int(IniRead($ini_path$my_name"buttons_x_shunt", 0))
    $buttons_y_shunt = Int(IniRead($ini_path$my_name"buttons_y_shunt", 11))
    $button_spacing = Int(IniRead($ini_path$my_name"button_spacing", 3))
    debug("$buttons_x_shunt: " & $buttons_x_shunt, @ScriptLineNumber, 8);debug
    debug("$buttons_y_shunt: " & $buttons_y_shunt, @ScriptLineNumber, 8);debug
    debug("$button_spacing: " & $button_spacing, @ScriptLineNumber, 8);debug

    $custom_buttons_font_size = Round(IniRead($ini_path$my_name"custom_buttons_font_size", 9), 2)
    debug("$custom_buttons_font_size: " & $custom_buttons_font_size, @ScriptLineNumber, 8);debug

    $button_notes_to_console = IniReadCheckBoxValue($ini_path$my_name"button_notes_to_console"$ON)
    debug("$button_notes_to_console: " & Human($button_notes_to_console), @ScriptLineNumber, 8);debug

    LoadCustomButtonData()


    $double_check_rclicks = IniReadCheckBoxValue($ini_path$my_name"double_check_rclicks"$ON)
    debug("$double_check_rclicks: " & Human($double_check_rclicks), @ScriptLineNumber, 8);debug

    $show_ffplay_output = IniReadCheckBoxValue($ini_path$my_name"show_ffplay_output"$OFF)
    $ffmpeg_command = IniRead($ini_path$my_name"ffmpeg_command""-help")
    $ffplay_command = IniRead($ini_path$my_name"ffplay_command""-help")

    debug("$show_ffplay_output: " & Human($show_ffplay_output), @ScriptLineNumber, 8);debug
    debug("$ffmpeg_command: " & $ffmpeg_command, @ScriptLineNumber, 8);debug
    debug("$ffplay_command: " & $ffplay_command, @ScriptLineNumber, 8);debug

    ; Play Command. This is for when you right-click on the input file label.
    
    $play_command = IniRead($ini_path$my_name"play_command""shellex")

    ; 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)
    debug("$log_append: " & Human($log_append), @ScriptLineNumber, 8);debug
    debug("$job_log_append: " & Human($job_log_append), @ScriptLineNumber, 8);debug
    debug("$log_each_job: " & Human($log_each_job), @ScriptLineNumber, 8);debug


    ; Log location..
    GetLogLocation()

    $job_log_location = ffeDeTokenizeString(IniRead($ini_path$my_name"job_log_location""@datadir\logs"))
    debug("$job_log_location: " & $job_log_location, @ScriptLineNumber, 8);debug


    ; FFmpeg binary location..
    $i = ffeDeTokenizeString(IniRead($ini_path$my_name"ffmpeg_binary"""))
    if FileExists($i) then
        $ffmpeg_binary = $i
    else
        SetFFmpegBinLocation()
    endif
    debug("$ffmpeg_binary: " & $ffmpeg_binary, @ScriptLineNumber, 8);debug


    ; ffprobe/mediainfo..
    GetReportingValues()


    ; FFmpeg plugins..
    $plugins_path = ffeDeTokenizeString(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", ffeTokenizeString($plugins_path))
    endif
    debug("$plugins_path: " & $plugins_path, @ScriptLineNumber, 8);debug


    LoadHelpTexts()


    $not_presets = IniRead($ini_path$my_name"not_presets""")
    if not $not_presets then $not_presets = $NOT_PRESETS_LIST
    debug("$not_presets: " & $not_presets, @ScriptLineNumber, 8);debug

    $not_presets = StringSplit($not_presets",")
    debug_PrintArray($not_presets"$not_presets:", @ScriptLineNumber, 8);debug

    ; 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)
    $ffmpeg_task_butt_icon_index = IniRead($ini_path$my_name"ffmpeg_task_butt_icon_index", -11)

    debug("$magic_butt_icon_index: " & $magic_butt_icon_index, @ScriptLineNumber, 8);debug
    debug("$dropwin_butt_icon_index: " & $dropwin_butt_icon_index, @ScriptLineNumber, 8);debug
    debug("$folder_icon_index: " & $folder_icon_index, @ScriptLineNumber, 8);debug
    debug("$time_icon_index: " & $time_icon_index, @ScriptLineNumber, 8);debug


    $matof_separator = IniRead($ini_path$my_name"matof_separator"" ")
    ; Cuz above " " don't work..
    if $matof_separator = "" then $matof_separator = " "
    debug("$matof_separator: " & $matof_separator, @ScriptLineNumber, 8);debug

    ; CPU priority..
    $cpu_priority = int(IniRead($ini_path$current_section"cpu_priority", 2))
    if $cpu_priority < 0 or $cpu_priority > 5 then $cpu_priority = 2
    $nCPUChecked = $cpu_priority
    debug("$cpu_priority: " & $cpu_priority, @ScriptLineNumber, 8);debug


    ; Drop-Downs..

    GetUserCodecs()

    $file_types = IniRead($ini_path$my_name"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;*.gif)")

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

    $target_types = IniRead($ini_path$my_name"target_types""||pal-vcd|dvd|ntsc-svcd|vcd|svcd|dv|dv50")
    $preset_resizes = IniRead($ini_path$my_name"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$my_name"console_output_font""Lucida Console")
    $console_output_font_size = IniRead($ini_path$my_name"console_output_font_size", 9)
    debug("$console_output_font: " & $console_output_font, @ScriptLineNumber, 8);debug
    debug("$console_output_font_size: " & $console_output_font_size, @ScriptLineNumber, 8);debug

    $short_test_frames = IniRead($ini_path$my_name"short_test_frames", 1000)
    debug("$short_test_frames: " & $short_test_frames, @ScriptLineNumber, 8);debug

    ; 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 inside the preset..
    $fallback_folder = IniRead($ini_path$current_section"fallback_folder""@parent")
    ;$fallback_folder = ffeDeTokenizeString($fallback_folder)
    CRT($fallback_folder)
    debug("$fallback_folder: " & $fallback_folder, @ScriptLineNumber, 8);debug

    ; 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)
    debug("$resize_first: " & Human($resize_first), @ScriptLineNumber, 8);debug
    debug("$do_matof: " & Human($do_matof), @ScriptLineNumber, 8);debug

    ; 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)
    debug("$run_pre_job_commands: " & Human($run_pre_job_commands), @ScriptLineNumber, 8);debug
    debug("$run_post_job_commands: " & Human($run_post_job_commands), @ScriptLineNumber, 8);debug

    LoadPostFileSettings(true)

    $batch_commands_timeout = Int(IniRead($ini_path$current_section"batch_commands_timeout"$batch_commands_timeout))
    debug("$batch_commands_timeout: " & $batch_commands_timeout, @ScriptLineNumber, 8);debug

    $run_commands_with_shell = IniReadCheckBoxValue($ini_path$current_section"run_commands_with_shell"$run_commands_with_shell)
    debug("$run_commands_with_shell: " & $run_commands_with_shell, @ScriptLineNumber, 8);debug


    $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)

    debug("$overwrite: " & Human($overwrite), @ScriptLineNumber, 8);debug
    debug("$concatenate: " & Human($concatenate), @ScriptLineNumber, 8);debug
    debug("$quit_when_done: " & Human($quit_when_done), @ScriptLineNumber, 8);debug
    debug("$shutdown_when_done: " & Human($shutdown_when_done), @ScriptLineNumber, 8);debug

    ; Read-only preset-level settings..
    $default_extension = IniRead($ini_path$current_section"default_extension"$default_extension)
    debug("$default_extension: " & $default_extension, @ScriptLineNumber, 8);debug
    $default_audio_extension = IniRead($ini_path$current_section"default_audio_extension"$default_audio_extension)
    debug("$default_audio_extension: " & $default_audio_extension, @ScriptLineNumber, 8);debug

    $kill_ffmpeg_on_exit = IniReadCheckBoxValue($ini_path$current_section"kill_ffmpeg_on_exit"$kill_ffmpeg_on_exit)
    debug("$kill_ffmpeg_on_exit: " & Human($kill_ffmpeg_on_exit), @ScriptLineNumber, 8);debug

    ; Funky drop target..
    $do_drop_window = IniReadCheckBoxValue($ini_path$my_name"do_drop_window"$ON)
    debug("$do_drop_window: " & Human($do_drop_window), @ScriptLineNumber, 8);debug
    GetDropWinImage()
    GetDropWinImageFolder()

    $drop_win_transparency = IniRead($ini_path$my_name"drop_win_transparency", 0)
    debug("$drop_win_transparency: " & $drop_win_transparency, @ScriptLineNumber, 8);debug
    GetRealTrans()

    $drop_win_hover_transparency = IniRead($ini_path$my_name"drop_win_hover_transparency", -1)
    debug("$drop_win_hover_transparency: " & $drop_win_hover_transparency, @ScriptLineNumber, 8);debug


    $allowed_image_types = IniRead($ini_path$my_name"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)
    debug("$allowed_image_types: " & $allowed_image_types, @ScriptLineNumber, 8);debug
    debug("$fluid_image_menu: " & Human($fluid_image_menu), @ScriptLineNumber, 8);debug

    $auto_copy_images = IniReadCheckBoxValue($ini_path$my_name"auto_copy_images"$ON)
    debug("$auto_copy_images: " & Human($auto_copy_images), @ScriptLineNumber, 8);debug

    $GDI_dll = IniRead($ini_path$my_name"GDI_dll""gdiplus.dll")
    debug("$GDI_dll: " & $GDI_dll, @ScriptLineNumber, 8);debug

    ; Purge the ini file of all comments..
    $clean_comments = IniReadCheckBoxValue($ini_path$my_name"clean_comments"$OFF)
    debug("$clean_comments: " & Human($clean_comments), @ScriptLineNumber, 8);debug

    $pause_is_global = IniReadCheckBoxValue($ini_path$my_name"pause_is_global"$OFF)
    debug("$pause_is_global: " & Human($pause_is_global), @ScriptLineNumber, 8);debug

    $delete_to_recycle_bin = IniReadCheckBoxValue($ini_path$my_name"delete_to_recycle_bin"$ON)
    debug("$delete_to_recycle_bin: " & Human($delete_to_recycle_bin), @ScriptLineNumber, 8);debug

    $always_warn_on_delete = IniReadCheckBoxValue($ini_path$my_name"always_warn_on_delete"$OFF)
    debug("$always_warn_on_delete: " & Human($always_warn_on_delete), @ScriptLineNumber, 8);debug

    $warn_colour = GetUserColor(IniRead($ini_path$my_name"warn_colour"$warn_colour))
    debug("$warn_colour: " & $warn_colour, @ScriptLineNumber, 8);debug

    $notes_prefix = IniRead($ini_path$my_name"notes_prefix""\nnotes:\n")
    ConvertNewlines($notes_prefix)
    debug("$notes_prefix: " & $notes_prefix, @ScriptLineNumber, 8);debug

endfunc




; Create the main ffe GUI/Window (this only happens one time)..
;
func MakeGUI()

    debug("", @ScriptLineNumber, 6);debug
    debug("MakeGUI()..", @ScriptLineNumber, 6);debug

    ; 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"ResizeSaveXYWHPrefs")
    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")

    GUISetOnEvent($GUI_EVENT_SECONDARYDOWN"CheckForRightClickTask")
    if $double_check_rclicks = $ON then
        GUISetOnEvent($GUI_EVENT_SECONDARYUP"CheckForRightClickTask")
    endif

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


    ; Dummy controls for Keyboard Accelerators.. (App-Specific HotKeys)
    local $dummy_drop_window = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "MenuToggleDropWindow")
    local $dummy_retain_exit_settings = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "MenuRetainExitSettings")
    local $dummy_toggle_auto_codecs = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "MenuToggleAutoCodecs")
    local $dummy_toggle_matof_status = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "ClickToggleMatofStatus")
    local $dummy_select_all_text = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "CtrlASelectAllText")
    local $dummy_delayed_doit = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "DelayedDoIt")
    local $dummy_find_in_output = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "HKFindInOutput")
    local $dummy_f_find_in_output = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "HKFindInOutput")
    local $dummy_find_replace_in_output = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "HKFindReplaceInOutput")
    local $dummy_copy_output = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "CopyConsoleOutput")
    local $dummy_clear_output = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "ClearOutput")
    local $dummy_quit = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "User_DoQuit")

    local $dummy_ffplay_output_toggle = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "ToggleShowFFplayOut")

    local $dummy_set_default_extension = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "SetDefExtension")

    local $dummy_restart = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "Restart")


    ; 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 & $MSG_LF & "Click here to view the source directory with the" & $MSG_LF & _
                                                "input file selected."$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "OpenFolderInFileSelected")


    $inp_inputfile = GUICtrlCreateInput($inputfile, 40, 0, $width-110, 18)
    GUICtrlSetTipOptional(-1, $tip$ttt)
    GUICtrlSetOnEvent(-1, "UpdateOutputArgs")
    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, ".\Resources\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. You can 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, ".\Resources\Icons\document-outline.ico", -1, 0)
        endif
    else
        GUICtrlCreateButton("...", 24, 0, 20, 20, BitOr($WS_TABSTOP,$BS_FLAT))
    endif
    GUICtrlSetTipOptional(-1, "Browse to locate the input file." & $MSG_LF & _
                                "Ctrl-click to open the folder."$ttt)
    GUICtrlSetOnEvent(-1, "BrowseForInputFile")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKRIGHT$GUI_DOCKSIZE))



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

    $ttt = "Output File(s)"

    $lab_outputfile = GUICtrlCreateLabel("output: ", 0, 0, 36)
    $tip = "Enter the full path to the output file (or better yet, drag in folder" & $MSG_LF & _
            "and let ffe work out the rest). Note: Old paths remain until you mindfully" & $MSG_LF & _
            "delete them or drag something else in. This is by design."
    GUICtrlSetTipOptional(-1, $tip & $MSG_LF & $MSG_LF & _
                            "NOTE: click this label to disable output altogether, e.g. for " & $MSG_LF & _
                            "creating image sequences (enter output directly into the extra" & $MSG_LF & _
                            "agruments input)." & $MSG_LF & $MSG_LF & _
                            "NOTE; You Must Put The Output File(s) LAST" & $MSG_LF & $MSG_LF & _
                            "WARNING: " & $MSG_LF & _
                            "Right-Clicking This Label DELETES The Output File."$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: Clicking in here, disables MATOF. "$ttt)
    GUICtrlSetOnEvent(-1, "")
    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, ".\Resources\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, ".\Resources\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. " & $MSG_LF & _
                                "Ctrl-click to open the folder."$ttt)
    GUICtrlSetOnEvent(-1, "BrowseForOutputFile")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKRIGHT$GUI_DOCKSIZE))



    debug("GUI:: Quick Tasks: ", @ScriptLineNumber, 9);debug

    ; Quick Tasks...
    ;

    GUISetCoord(10, 62)

    ; Tip not seen for groups.. bummer :/ Hmm.. what if
    ; Hey this is clever (even cleverer for combos - see below)
    ; A Label for the ToolTip!
    GUICtrlCreateLabel("", 0, 0, 155, 14, 0, 0)
    ; GUICtrlSetBkColor(-1, $COLOR_RED)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetTipOptional(-1, "One button for FFmpeg, another for FFplay." & $MSG_LF & _
                                "Right-Click a button to edit its command.""FFmpeg Quick Tasks..  (F11+F12)" )
    GUISetCoord(10, 62)
    GUICtrlCreateGroup("ffmpeg quick tasks.. ", 0, 0, 155, 35) ; tip not seen.. bummer :/
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))


    ; Right-click these controls to edit the commands (see: CheckForRightClickTask())
    ;
    $check_run_ffmpeg_task = GUICtrlCreateCheckbox("ffmpeg task", 6, 14, 70, 17, BitOr($BS_AUTOCHECKBOX$BS_PUSHLIKE))
    GUICtrlSetFont(-1, 7.5)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    $tip_ffmpeg_task = GUICtrlSetTipOptional(-1, $MSG_LF & "Current command: " & $ffmpeg_command"Quick FFmpeg Task  (F11)")
    GUICtrlSetOnEvent(-1, "RunFFmpegQuickTask")

    $check_run_ffplay_task = GUICtrlCreateCheckbox("ffplay task", 73, 0, 70, 17, BitOr($BS_AUTOCHECKBOX$BS_PUSHLIKE))
    GUICtrlSetFont(-1, 7.5)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    $tip_ffplay_task = GUICtrlSetTipOptional(-1, $MSG_LF & "Current command: " & $ffplay_command"Quick FFplay Task  (F12)" _
                    & $MSG_LF & "Right-Click to set the command used.")
    GUICtrlSetOnEvent(-1, "ClickRunFFplayQuickTask")




    ; ffe (tri-state) job buttons..
    ;

    GUISetCoord(170, 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 & _
        "Until saved to a preset, changes to these settings are volatile (however they will be retained at exit)." & $MSG_LF & _
        "Unless specifically set (on/off) in a preset, the previous setting will be in effect (usually unset).", _
        "ffe job controls (preset-level)")
    GUISetCoord(170, 62)
    GUICtrlCreateGroup("ffe job.. ", 0, 0, $column_two-178, 35) ; tip not seen.. bummer :/
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))


    $ttt = $tristate_prejob_title
    $check_run_pre_job_commands = GUICtrlCreateCheckbox(" pre-job ", 4, 13, 53, 18, BitOr($BS_AUTO3STATE,$BS_RIGHTBUTTON))
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    $tip_pre_job = GUICtrlSetTipOptional(-1, $tristate_prejob_tip & Human($run_pre_job_commands), $ttt)
    GUICtrlSetOnEvent(-1, "ClickSetPreJobState")
    GUICtrlSetState(-1, $run_pre_job_commands)


    $ttt = $tristate_postfile_title
    $check_run_post_file_command = GUICtrlCreateCheckbox(" post-file ", 57, 0, 58, 18, BitOr($BS_AUTO3STATE,$BS_RIGHTBUTTON))
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetState(-1, $run_post_file_command)
    $tip_post_file = GUICtrlSetTipOptional(-1, $tristate_postfile_tip & Human($run_post_file_command), $ttt)
    GUICtrlSetOnEvent(-1, "ClickSetPostFileState")


    $ttt = $tristate_postjob_title
    $check_run_post_job_commands = GUICtrlCreateCheckbox(" post-job ", 62, 0, 58, 18, BitOr($BS_AUTO3STATE,$BS_RIGHTBUTTON))
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    $tip_post_job = GUICtrlSetTipOptional(-1, $tristate_postjob_tip & Human($run_post_job_commands), $ttt)
    GUICtrlSetOnEvent(-1, "ClickSetPostJobState")
    GUICtrlSetState(-1, $run_post_job_commands)


    $ttt = $tristate_overwrite_title
    $check_overwrite = GUICtrlCreateCheckbox(" overwrite ", 63, 0, 63, 20, BitOr($BS_AUTO3STATE,$BS_RIGHTBUTTON))
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetTipOptional(-1, $tristate_overwrite_tip & Human($overwrite), $ttt)
    GUICtrlSetOnEvent(-1, "ClickSetOverwrite")
    GUICtrlSetState(-1, $overwrite)


    $ttt = $tristate_concatenate_title
    $check_concatenate = GUICtrlCreateCheckbox(" join ", 69, 0, 35, 20, BitOr($BS_AUTO3STATE,$BS_RIGHTBUTTON))
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetTipOptional(-1, $tristate_concatenate_tip & Human($concatenate), $ttt)
    GUICtrlSetOnEvent(-1, "ClickSetConcatenateFiles")
    GUICtrlSetState(-1, $concatenate)


    $ttt = $tristate_quit_title
    $check_quit_when_done = GUICtrlCreateCheckbox(" quit ", 39, 0, 35, 20, BitOr($BS_AUTO3STATE,$BS_RIGHTBUTTON))
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetTipOptional(-1, $tristate_quit_tip & Human($quit_when_done), $ttt)
    GUICtrlSetOnEvent(-1, "ClickSetQuitWhenDone")
    GUICtrlSetState(-1, $quit_when_done)


    $ttt = $tristate_shutdown_title
    $check_shutdown_when_done = GUICtrlCreateCheckbox(" shutdown ", 40, 0, 66, 20, BitOr($BS_AUTO3STATE,$BS_RIGHTBUTTON))
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetTipOptional(-1, $tristate_shutdown_tip & Human($shutdown_when_done), $ttt)
    GUICtrlSetOnEvent(-1, "ClickSetShutdownWhenDone")
    GUICtrlSetState(-1, $shutdown_when_done)

    ; Some logic needed for quit/shutdown buttons..
    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 & _
            "NOTE: If you put *anything* here, you must also include the ""-i "" part." & $MSG_LF & _
            $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))


    debug("GUI:: Presets: ", @ScriptLineNumber, 9);debug

    ; 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()

    global $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, "ComboImportData")

        GUICtrlCreateMenuItem(""$ctxt_combo)

        GUICtrlCreateMenuItem("Wipe All Preset Backups"$ctxt_combo)
        GUICtrlSetOnEvent(-1, "WipeBackups")

        GUICtrlCreateMenuItem(""$ctxt_combo)

        GUICtrlCreateMenuItem("Change Default Extension For This Preset"$ctxt_combo)
        GUICtrlSetOnEvent(-1, "SetPresetDefExtension")

        GUICtrlCreateMenuItem(""$ctxt_combo)

        GUICtrlCreateMenuItem("Add/Edit Notes For This Preset"$ctxt_combo)
        GUICtrlSetOnEvent(-1, "AddNotesToPreset")

        GUICtrlCreateMenuItem(""$ctxt_combo)


        $ctxt_combo_sort = GUICtrlCreateMenuItem($sort_presets_list_texts & ")"$ctxt_combo)
        GUICtrlSetOnEvent(-1, "MenuToggleSortPresets")
        GUICtrlSetState(-1, $sort_presets_list)




    $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"
    $butt_wipe = GUICtrlCreateButton("wipe", 46 , 0, 42, 22, BitOr($WS_TABSTOP,$BS_FLAT))
    GUICtrlSetTipOptional(-1,  "Remove this preset from the list. " & $MSG_LF & _
                                "Shift- or right-click to restore backups."$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKRIGHT$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "WipePreset")


    ; GUISetCoord(70-($width-$column_two), 31)

    $ttt = "Replace Settings"
    $radio_preset_replace = GUICtrlCreateRadio("replace", 70-($width-$column_two), 29, default, 18)
    GUICtrlSetTipOptional(-1,  _
        "Selected presets will replace all the current settings with settings from the preset."$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "TogglePresetMode")
    GUICtrlSetState(-1, $replace_mode)

    $ttt = "Add To Settings"
    GUICtrlCreateRadio("add to", 58, 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 'added to';" & $MSG_LF & _
                    " i.e. not toggles and job settings, which are replaced, as usual."$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "TogglePresetMode")
    if $replace_mode = $OFF then GUICtrlSetState(-1, $ON)


    GUICtrlCreateLabel("settings", 52, 2, default, 18, BitOr($WS_TABSTOP,$BS_FLAT), $WS_EX_TOPMOST)
    GUICtrlSetTipOptional(-1,  "Presets can either replace or add to existing settings. " & $MSG_LF & _
                    "This applies to all the visible settings that can be 'added to'," & $MSG_LF & _
                    "such as parameter inputs. When using 'add to', other settings" & $MSG_LF & _
                    "will be replaced with any corresponding settings in the preset.""Add To or Replace Existing Settings")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))


    GUISetCoord($width-102, 111)

    ; Store the input/output file paths inside the preset?
    ;
    $ttt = "Save/Restore File Paths"
    $check_store_filepaths = GUICtrlCreateCheckbox("with file paths", 0, 0, 82, 18, -1, $WS_EX_TOPMOST)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKRIGHT$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "ToggleStorePaths")
    ; GUICtrlSetBkColor(-1, $COLOR_RED)
    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
        GUICtrlDelete(-1)
        GUICtrlCreateLabel(" ", 0, 0, 80, 18)
        GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
        GUICtrlSetTipOptional(-1,    "This feature is disabled inside ffe.ini."$ttt)
    endif




    ; 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))


    debug("GUI:: Codecs: ", @ScriptLineNumber, 9);debug


    ; Video codec..
    ;
    $ttt = "Video Codec"
    $tip = "Here you can select/override the codec used to encode the output video. " & $MSG_LF & _
            "Select a preset codec from the list, or enter one manually. " & $MSG_LF & $MSG_LF & _
            "Note: Auto-Codec Drop-Downs disables this control's context menu."
    GUICtrlCreateLabel("video codec: ", 6, 19)
    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..
  AutoItSetOption("GUICoordMode", 1)
  ; We are working our way slowly through the GUI, removing the following nonsense!


    ; 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, aka, 'framerate'). " & $MSG_LF & _
        "Select a preset bitrate from the list, or enter one 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)




    ; Resize-crop order..
    $ttt = "Resize-Crop Order"
    $check_resize_first = GUICtrlCreateCheckbox("resize first"$out_left+194, $out_top+152)
    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, "RFCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetState($check_resize_first$resize_first)




    ; Cropping..

    ; new syntax =
    ; -vf "crop=out_w:out_h:x:y"

    local $fvwarn =     "Note: You must either specify all four crop values or" & $MSG_LF & _
                            "else specify only width and height (crop will be centred)."

    $ttt = "Crop area dimensions"
    $label_active_crop_wh = GUICtrlCreateLabel("crop  w / h: "$out_left+262, $out_top+90)
    GUICtrlSetTipOptional(-1, "The crop area will be this width and height (pixels or formula).." & $MSG_LF & $MSG_LF & _
                                "Click this label for auto-crop, which will interrogate the file for" & $MSG_LF & _
                                "black borders and insert the cropping values automatically." & $MSG_LF & $MSG_LF & _
                                "Right-Click to set a new default number of test frames." & $MSG_LF & _
                                "Shift+Click to set for THIS test and do it now."$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "DoAutoCrop")

    $ttt = "Crop area width"
    $inp_crop_width = GUICtrlCreateInput(""$out_left+262, $out_top+106, 33, 21, $ES_NUMBER)
    GUICtrlSetTipOptional(-1, "Crop out an area of the video THIS wide (pixels or formula)." & $MSG_LF & $MSG_LF & $fvwarn$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $ttt = "Crop area height"
    $inp_crop_height = GUICtrlCreateInput(""$out_left+302, $out_top+106, 33, 21, $ES_NUMBER)
    GUICtrlSetTipOptional(-1, "Crop out an area of the video THIS high (pixels or formula)." & $MSG_LF & $MSG_LF & $fvwarn$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))




    $ttt = "Crop top-left x/y position"
    $label_active_crop_xy = GUICtrlCreateLabel("crop  x / y: "$out_left+262, $out_top+132)
    GUICtrlSetTipOptional(-1, "The crop area will begin at this X/Y position (pixels or formula).." & _
                                $MSG_LF & $MSG_LF & _
                                "For example, to crop 60px black bars from the top and bottom" & $MSG_LF & _
                                "of a 720p video you might use 0 60 1280 600 (x/y/w/h)." & $MSG_LF & $MSG_LF & _
                                "Click this label for auto-crop, which will interrogate the file for" & $MSG_LF & _
                                "black bars and insert the cropping values automatically."$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "DoAutoCrop")


    $ttt = "Crop beginning X Position"
    $inp_crop_x = GUICtrlCreateInput(""$out_left+262, $out_top+148, 33, 21, $ES_NUMBER)
    GUICtrlSetTipOptional(-1, "Crop the video begining at this X position (pixels or formula)." &$MSG_LF&$MSG_LF&$fvwarn$ttt)
    GUICtrlSetOnEvent(-1, "AutoCreateArgs")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKSIZE))

    $ttt = "Crop beginning Y Position"
    $inp_crop_y = GUICtrlCreateInput(""$out_left+302, $out_top+148, 33, 21, $ES_NUMBER)
    GUICtrlSetTipOptional(-1, "Crop the video begining at this Y position (pixels or formula)." & $MSG_LF & $MSG_LF & $fvwarn$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, 21, $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, 21, $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)





    ; Audio codec..
    $ttt = "Audio Codec"
    $tip = "Here you can select/override the codec used to encode the output audio track. " & $MSG_LF & _
            "Select a preset codec from the list, or enter one manually. " & $MSG_LF & $MSG_LF & _
            "Note: Auto-Codec Drop-Downs disables this control's context menu."
    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))



    debug("GUI:: Raw Parameters: ", @ScriptLineNumber, 9);debug

    ; 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-167, 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"
    $butt_reset = GUICtrlCreateButton("reset"$out_left+$width-65, $out_top+84, 40, 22, BitOr($WS_TABSTOP,$BS_FLAT))
    GUICtrlSetTipOptional(-1, "Click this button to reset all the parameters. " & $MSG_LF & _
                                "Ctrl+Click to also clear input/output." & $MSG_LF & _
                                "Shift+Click to clear ONLY the input/output."$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKTOP$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "ClickResetEverything")


    "Short Test" button..
    $ttt = "Add Quick Test Parameters"
    $butt_quicktest = GUICtrlCreateButton("short test"$out_left+$width-81, $out_top+107, 56, 22, BitOr($WS_TABSTOP,$BS_FLAT))
    $tip_short_test = GUICtrlSetTipOptional(-1, _
        "Adds some parameters to process only the first " & $short_test_frames & " frames of video. " & _
        $MSG_LF & _
        "You can edit this number (right-click the button). "$ttt)
    GUICtrlSetonEvent(-1, "AddShortTestParam")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKTOP$GUI_DOCKSIZE))


    "Report" button..
    $ttt = "Create A Media Report"
    $butt_mediareport = GUICtrlCreateButton("media report"$out_left+$width-95, $out_top+130, 70, 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." & $MSG_LF & _
        "Shift+Click to open in your detault viewer."$ttt)
    GUICtrlSetonEvent(-1, "GenerateReport")
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKTOP$GUI_DOCKSIZE))

    CreateCodecContexts()

    if $enable_custom_buttons = $ON then
        ; The Super-Nifty Custom Buttons..
        CreateButtonGrid()
    endif


    debug("GUI:: Help Buttons: ", @ScriptLineNumber, 9);debug

    ; HELP!

    if IsArray($help_texts) then

        ; Big info text for help buttons..
        $lab_help_info = GUICtrlCreatelabel(""$width-82, $out_top+153, 65, 18, BitOr($SS_NOTIFY$SS_RIGHT))
        GUICtrlSetFont(-1, 10, 800, 0, "", 5)
        GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKTOP$GUI_DOCKSIZE))
        ;GUICtrlSetBkColor(-1, $COLOR_RED)

        ; The help buttons..
        $buttons_xy = $out_top+170
        CreateHelpButtons()

    endif



    ; Command-Line input..

    $ttt = "Dynamic Command-line Display"
    GUICtrlCreateLabel("Command-line: ", 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))





    ; The Console.
    ; Command-Line output..

    $ttt = "Console Output"
    $edit_console_output = GUICtrlCreateEdit("", 10, $out_top+314, $width-20, $height-($out_top+358), GetEditStyles())
    if $allow_console_tooltip = $ON then GUICtrlSetTipOptional(-1, _
        "You can see the output from FFmpeg here, including any errors, messages, and so on.. " & $MSG_LF & _
        "You can also use it as an editing space for any plain text." & $MSG_LF & _
        "Normal text editing functions apply, e.g. Ctrl+A to select ALL text." & $MSG_LF  & $MSG_LF & _
        "NOTE: You can disable this (somewhat annoying) ToolTip from the app menu."$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 console output (F3). "$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKBOTTOM$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "Butt_FindInOutput")


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


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




    ; DO IT!!!
    $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. " & $MSG_LF & _
                                                "Shift+Click to generate a batch script."$ttt)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKBOTTOM$GUI_DOCKSIZE))
    GUICtrlSetOnEvent(-1, "DoIt")
    if not $ffmpeg_binary then DisableRunningControls()


    ; NO! STOP!
    $ttt = "ABORT THE JOB!    (Pause/Break)"
    $label_abort = GUICtrlCreateLabel( _
        "To abort the current job, press 'Ctrl+Q'. To abort a batch, press 'Pause/Break'. " & _
        "To suspend/resume, use ScrLk/ScrollLock. Alt+C toggles the console.", 10, $height-32)
    GUICtrlSetTipOptional(-1, "Simply hit 'Ctrl+Q' on your keyboard to quit a 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!


    ; Set Keyboard Accelerators..
    ;
    ; F1 became "reserved" in the latest Windows 10, so we are using an accelerator for this now.
    ; And also many other things. This is WAY more elegant than the old method.
    ; For some, we don't need a dummy control as we have an actual control we can fire (eg. $butt_doit)..
    local $AppHotKeys[18][2] = [ _
                        ["{F1}"$butt_doit], _
                        ["{F9}"$dummy_drop_window], _
                        ["^e"$dummy_retain_exit_settings], _
                        ["{F7}"$dummy_toggle_auto_codecs], _
                        ["^m"$dummy_toggle_matof_status], _
                        ["^a"$dummy_select_all_text], _
                        ["^f"$dummy_f_find_in_output], _
                        ["{F3}"$dummy_find_in_output], _
                        ["+{F3}"$dummy_find_replace_in_output], _
                        ["{F8}"$dummy_copy_output], _
                        ["{F5}"$dummy_clear_output], _
                        ["{Esc}"$dummy_quit], _
                        ["{F6}"$dummy_ffplay_output_toggle], _
                        ["{F2}"$dummy_set_default_extension], _
                        ["{F11}"$check_run_ffmpeg_task], _
                        ["{F12}"$check_run_ffplay_task], _
                        ["!{F5}"$dummy_restart], _
                        ["^d"$dummy_delayed_doit]]
    GUISetAccelerators($AppHotKeys)

    debug("GUI:: All done making GUI: ", @ScriptLineNumber, 9);debug

    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$app_menu = -1, $bIsPopup=false, $nPos=0xFFFFFFFF)
;    0xFFFFFFFF means "insert at the end"

func MakeAppMenu()

    debug("", @ScriptLineNumber, 6);debug
    debug("MakeAppMenu()..", @ScriptLineNumber, 6);debug

    GUIRegisterMsg($WM_SYSCOMMAND"CheckAppMenu")

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

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


    ; ffe System Menu..
    local $am_system = CreateSystemMenuItem("&ffe..", -1, true, 0)




        $am_always_warn_on_delete = CreateSystemMenuItem(" Always Warn On Delete"$am_system, false, 0)
        CheckMenuItem($app_menu$am_always_warn_on_delete$always_warn_on_delete)

        $am_delete_to_recycle_bin = CreateSystemMenuItem(" Delete To Recycle Bin"$am_system, false, 0)
        CheckMenuItem($app_menu$am_delete_to_recycle_bin$delete_to_recycle_bin)

        local $ofdeleteoptions = CreateSystemMenuItem("Output File Deletion.."$am_system, false, 0)
        AppMenuItemSetState($app_menu$ofdeleteoptions$OFF)
        CreateSystemMenuItem(""$am_system, false, 0)

        $am_do_countdown_timer = CreateSystemMenuItem("Show &Countdown Timer"$am_system, false, 0)
        CheckMenuItem($app_menu$am_do_countdown_timer$do_countdown_timer)

        CreateSystemMenuItem(""$am_system, false, 0)

        $am_allow_multiple = CreateSystemMenuItem("Allow &Multiple Instances"$am_system, false, 0)
        CheckMenuItem($app_menu$am_allow_multiple$allow_multiple)

        CreateSystemMenuItem(""$am_system, false, 0)

        $am_pause_is_global = CreateSystemMenuItem("&Pause HotKey is Global"$am_system, false, 0)
        CheckMenuItem($app_menu$am_pause_is_global$pause_is_global)

        CreateSystemMenuItem(""$am_system, false, 0)

        $am_kill_ffmpeg_on_exit = CreateSystemMenuItem("&Kill FFmpeg On Exit"$am_system, false, 0)
        CheckMenuItem($app_menu$am_kill_ffmpeg_on_exit$kill_ffmpeg_on_exit)

        CreateSystemMenuItem(""$am_system, false, 0)

        $am_start_minimized = CreateSystemMenuItem("&Start Minimized"$am_system, false, 0)
        CheckMenuItem($app_menu$am_start_minimized$start_minimized)

        CreateSystemMenuItem(""$am_system, false, 0)

        $am_default_extension = CreateSystemMenuItem("Change Default &Extension..    (F2)"$am_system, false, 0)


        CreateSystemMenuItem(""$am_system, false, 0)

        $am_show_ffplay_output = CreateSystemMenuItem("Show FFplay Output in Console..    (F6)"$am_system, false, 0)
        CheckMenuItem($app_menu$am_show_ffplay_output$show_ffplay_output)


    CreateSystemMenuItem("", -1, false, 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


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

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

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

        CreateSystemMenuItem(""$am_visual, false, 0)

        $am_allow_output_tooltip = CreateSystemMenuItem($allow_console_tooltip_text & ")"$am_visual, false, 0)
        CheckMenuItem($app_menu$am_allow_output_tooltip$allow_console_tooltip)

        $am_console_wordwrap = CreateSystemMenuItem($console_wordwrap_text & ")"$am_visual, false, 0)
        CheckMenuItem($app_menu$am_console_wordwrap$console_wordwrap)

        CreateSystemMenuItem(""$am_visual, false, 0)

        $am_image_buttons = CreateSystemMenuItem($image_buttons_text & ")"$am_visual, false, 0)
        CheckMenuItem($app_menu$am_image_buttons$image_buttons)

        CreateSystemMenuItem(""$am_visual, false, 0)

        $am_do_tooltips = CreateSystemMenuItem($do_tooltips_text & ")"$am_visual, false, 0)
        CheckMenuItem($app_menu$am_do_tooltips$do_tooltips)

        CreateSystemMenuItem(""$am_visual, false, 0)

        $am_time_in_title = CreateSystemMenuItem("Show &Running Time In Title Bar    (Ctrl+R)"$am_visual, false, 0)
        CheckMenuItem($app_menu$am_time_in_title$time_in_title)

        CreateSystemMenuItem(""$am_visual, false, 0)


        $am_sort_presets_list = CreateSystemMenuItem($sort_presets_list_texts & ")"$am_visual, false, 0)
        CheckMenuItem($app_menu$am_sort_presets_list$sort_presets_list)


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

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

        ; Defined column number..
        ; We only show 1-12, but you can set higher inside ffe.ini
        for $i = 1 to 12
            $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..
        $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

        local $col_itm = CreateSystemMenuItem("Button Columns.."$am_custom_buttons_columns, false, 0)
        AppMenuItemSetState($app_menu$col_itm$OFF)
        CreateSystemMenuItem(""$am_custom_buttons_columns, false, 0)

        $am_button_notes_to_console = CreateSystemMenuItem("Button &Notes In Console"$am_custom_buttons_columns, false, 0)
        CheckMenuItem($app_menu$am_button_notes_to_console$button_notes_to_console)

        CreateSystemMenuItem(""$am_custom_buttons_columns, false, 0)
        ; Disable Custom Buttons altogether..
        $am_enable_custom_buttons = CreateSystemMenuItem("&Enable Custom Buttons"$am_custom_buttons_columns, false, 0)
        CheckMenuItem($app_menu$am_enable_custom_buttons$enable_custom_buttons)


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


    ; CPU Priority Sub-Menu..    (no accelerators for these)
     $am_cpu = CreateSystemMenuItem("ffmpeg.exe Process &Priority..", -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 Ex&it Settings    (Ctrl+E)", -1, false, 0)
    CheckMenuItem($app_menu$am_retain_exit_settings$retain_exit_settings)


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

    $am_auto_codecs = CreateSystemMenuItem("A&utomatic Codec Drop-downs    (F7)", -1, false, 0)
    CheckMenuItem($app_menu$am_auto_codecs$auto_codecs)


    ; Reporting types sub-menu..

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

    local $am_ffprobe = CreateSystemMenuItem("Use &ffprobe.."$am_reptypes, false, 0)
    AppMenuItemSetState($app_menu$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()


    CreateSystemMenuItem(""$am_reptypes, false, 0)

    $am_save_reports = CreateSystemMenuItem("&Save Reports"$am_reptypes, false, 0)
    CheckMenuItem($app_menu$am_save_reports$save_reports)



    ; Post-File Controls sub-menu..
    CreateSystemMenuItem("", -1, false, 0) ; Oooh! dash works as an accelerator!
    local $am_post_file_controls = CreateSystemMenuItem("Post&-File Controls..", -1, true, 0)

        local $am_pf_runstyle = CreateSystemMenuItem("&Run Style.."$am_post_file_controls, false, 0)
        AppMenuItemSetState($app_menu$am_pf_runstyle$OFF)

            for $i = 0 to 2
                $PostFileRunStylesMenuItems[$i] = CreateSystemMenuItem(" &" & $PostFileRunStyles[$i], $am_post_file_controls)
                if $PostFileRunStyles[$i] = $post_file_run_style then
                    $pfsChecked = $PostFileRunStylesMenuItems[$i]
                    CheckMenuItem($am_post_file_controls$pfsChecked$MF_CHECKED)
                endif
            next


        CreateSystemMenuItem(""$am_post_file_controls, false, 0)

        $am_post_file_capture = CreateSystemMenuItem("&Capture To Console"$am_post_file_controls, false, 0)
        CheckMenuItem($app_menu$am_post_file_capture$post_file_capture)

        $am_post_file_show = CreateSystemMenuItem("&Show Post-File Program"$am_post_file_controls, false, 0)
        CheckMenuItem($app_menu$am_post_file_show$post_file_show)



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

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

        CreateSystemMenuItem(""$am_logging, false, 0)
        $am_job_log_append = CreateSystemMenuItem("&Append Job Logs"$am_logging, false, 0)
        CheckMenuItem($app_menu$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($app_menu$am_log_each_job$log_each_job)


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

    $am_launch_with_drop_command = CreateSystemMenuItem("Run Drag-And-Dr&op Command At Launch", -1, false, 0)
    CheckMenuItem($app_menu$am_launch_with_drop_command$launch_with_drop_command)

    ; Drop Command sub-menu..
    $am_drop_command = CreateSystemMenuItem("&Drag-And-Drop Command..", -1, true, 0)
    local $ud = UBound($DropCommands)-1
    for $i = 0 to $ud
        if $i = $ud 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($app_menu$nDCChecked$MF_CHECKED)
        endif
    next


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

endfunc



func MakeTray()

    debug("", @ScriptLineNumber, 6);debug
    debug("MakeTray()..", @ScriptLineNumber, 6);debug

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

    ; Tray menu..

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

        debug_PrintArray($recent_files"$recent_files:", @ScriptLineNumber, 9);debug

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

        if $recent_files[0][0] then

            local $tray_clear = TrayCreateItem("Clear Recent Files List"$tray_recent_files)
            TrayItemSetOnEvent(-1, "ClearRecentFiles")
            local $spc_clear = TrayCreateItem(""$tray_recent_files)

            local $removed_rf = $recent_files[0][0]
            debug("$removed_rf: " & $removed_rf, @ScriptLineNumber, 9);debug

            for $i = $recent_files[0][0] to 1 step -1
                if FileExists($recent_files[$i][0]) then
                    $recent_files[$i][1] = TrayCreateItem(BaseName($recent_files[$i][0]), $tray_recent_files)
                    TrayItemSetOnEvent(-1, "OpenRecentFile")
                else
                    if $recent_files[$i][0] then
                        ConsoleAdd("Removed '" & $recent_files[$i][0] & "' from Recent Files menu.", @ScriptLineNumber)
                        $recent_files[$i][0] = ""
                        $removed_rf -= 1
                    endif
                endif
                debug("$removed_rf: " & $removed_rf, @ScriptLineNumber, 9);debug
            next

            ; ALL recent files were removed..
            if $removed_rf = 0 then
                TrayCreateItem("Recent Files list was emptied"$tray_recent_files)
                TrayItemDelete($tray_clear)
                TrayItemDelete($spc_clear)
                ClearRecentFiles()
            endif

        else
            ; No recent files were stored from previous session..
            TrayCreateItem("No Recent Files Exist!"$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("")

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


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

    TrayCreateItem("")

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

    TrayCreateItem("")

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

    TrayCreateItem("Open Data Folder..")
    TrayItemSetOnEvent(-1, "OpenDataDir")

    TrayCreateItem("")

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

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

    TrayCreateItem("")

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

    $tray_toggle_fluid_image_menu = TrayCreateItem("Fluid Menu    (follows current image)")
    TrayItemSetOnEvent(-1, "MenuToggleFluidMenu")
    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, "MenuChooseFixedImgLoc")
    if $fluid_image_menu = $ON then TrayItemSetState(-1, $TRAY_DISABLE)

    TrayCreateItem("")

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

    TrayCreateItem("")

    TrayCreateItem("Download Drop Window Image Pack")
    TrayItemSetOnEvent(-1, "TrayDownloadImagePack")

    TrayCreateItem("")

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

    TrayCreateItem("")

    TrayCreateItem("Restart ffe..    Alt+F5")
    TrayItemSetOnEvent(-1, "Restart")

    TrayCreateItem("")

    $tray_about_ffmpeg = TrayCreateItem("About FFmpeg")
    TrayItemSetOnEvent(-1, "DoAboutFFmpeg")
    if not $ffmpeg_binary then TrayItemSetState(-1, $TRAY_DISABLE)

    TrayCreateItem("About " & $my_name)
    TrayItemSetOnEvent(-1, "DoAboutBox")

    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


; Okay, here goes.
; Run the job..

func DoIt()

    debug("", @ScriptLineNumber, 6);debug
    debug("DoIt(): inputfile / outputfile: " & $inputfile & " / " & $outputfile, @ScriptLineNumber, 3);debug

    ; SHIFT held down or 'generate' set in switches..
    if _IsPressed(10) or $do_gen then $generate_script = true

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


    ; outputfile loaded in presets???    ::BUG?::
    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()
    DisableRunningControls()
    HideOutputButts()

    local $emsg

    ; 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.", @ScriptLineNumber)

        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
                SetWinTitleText(" delayed start in " & $t_str)
            endif

            if not $delay_start_at then
                $emsg  = "Delayed start aborted."
                debug($emsg, @ScriptLineNumber, 2);debug
                return ReturnNow($emsg, -7)
            endif
            Sleep(1000)
        wend
        debug("delayed start set for: " & $delay_start_at, @ScriptLineNumber, 4);debug

        SetWinTitleText()
    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(500)
    endif


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


    ; BATCH RUN..

    ; If there turns out to be only one item in the batch, no problem.
    ; Even single files are a batch!

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

        debug("IsWild(!)" & $inputfile, @ScriptLineNumber, 7);debug

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

        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..
        debug($run_parent"$run_parent:", @ScriptLineNumber, 7);debug
        debug($inputfile_extension"$inputfile_extension:", @ScriptLineNumber, 7);debug
        debug($full_filename"$full_filename:", @ScriptLineNumber, 7);debug

        ; ftp/http
        if StringInStr($inputfile"://") then
            $emsg  = "Error: Cannot process wildcards in URLS."
            debug($emsg, @ScriptLineNumber, 1);debug
            return ReturnNow($emsg, -3)
        else
            $run_files = ReadDir($run_parent$inputfile_extension$full_filename)
        endif
        debug_PrintArray($run_files"$run_files:", @ScriptLineNumber, 7);debug

        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
            $delay_start_at = false
            $emsg  = "Error creating batch. Sorry."
            debug($emsg, @ScriptLineNumber, 1);debug
            return ReturnNow($emsg, -1)
        endif
    endif

    $abort_batch = false
    local $batch = $OFF

    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]
    local $total_timestamp = TimerInit()
    local $secprt$thistime


    ; Process each file in the batch.. (the BIG loop!)
    ;
    for $runs = 1 to $run_files[0]

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

        $inputfile = $run_files[$runs]
        debug("DoIt()-->DoArgsCreate($batch): =>" & $batch & "<=", @ScriptLineNumber, 7);debug
        DoArgsCreate($batch; the only place this is set - right inside a batch.. we call the function directly, too.

        if $inputfile = $outputfile and $do_output = $ON then
            ; Running from command-line, just get on with *something*..
            if $go then
                ; This should rarely happen, but just in case..
                $outputfile = RemoveExtension($outputfile) & TimerInit() & "." & GetExtension($outputfile)
            else
                MsgBox(0, "file name clash!""You will need to choose a different output filename.. ", 0, $ffeGUI)
                if (BrowseForOutputFile() = 0) then
                    $emsg  = "Error starting job: File name clash."
                    debug($emsg, @ScriptLineNumber, 1);debug
                    return ReturnNow($emsg, -2)
                endif
                DoIt()
                return
            endif
        endif

        debug("$outputfile: " & $outputfile, @ScriptLineNumber, 7);debug

        ; 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 timestamp 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.
        ; It also catches situations where you are converting a batch where more than one file shares the same
        ; name but has a different extension, e.g. "movie.avi" and "movie.mpg" both being converted to say, MP3.

        ; Already made this file - add timestamp suffix to file name..
        if InArray($made_files$outputfile) then
            local $old_of = $outputfile
            $outputfile = RemoveExtension($outputfile) & "_[" & TimerInit() & "]" & "." & GetExtension($outputfile)
            ; Update args with new file name..
            $args = StringReplace($args$old_of$outputfile)
        endif

        debug("$outputfile: " & $outputfile, @ScriptLineNumber, 7);debug

        $outputfile is now SET!

        ; Just in case..
        local $out_parent = GetParent($outputfile)
        if not FileExists($out_parent) then DirCreate($out_parent)

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

        GUICtrlSetState($label_abort$GUI_SHOW)

        $title_msg_string = "    --> Processing: " & BaseName($inputfile) & "    (Press Ctrl+Q or Pause/Break to abort)"
        if IsWild(GUICtrlRead($inp_inputfile)) then
            $title_msg_string = "    --> Processing: " & BaseName($inputfile) & "    (Press Pause/Break to abort batch)"
        endif
        SetWinTitleText($title_msg_string)

        ; We will need to pass the "q" to ffmpeg manually..
        HotKeySet("^q""HK_FFmpegAbort")
        HotKeySet("^r""HK_ToggleTitleTime")
        ; HotKeySet("^{PAUSE}""PauseOutPut")    ; Works, but risky!
        HotKeySet("!c""PauseOutPut")

        ; 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 " & DateTimeString(true)  & $LOG_LF & "command-line: " & $args & $LOG_LF & $LOG_LF
        DoLog($msg)
        $job_log &= $msg

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

        ; Documentation is scant online. Try these..
        ; https://www.mltframework.org/plugins/FilterFrei0r-edgeglow/
        ; https://gstreamer.freedesktop.org/documentation/frei0r/index.html?gi-language=c


        ; Windows batch script output..
        if $generate_script then

            $generated &= $args & $LOG_LF

        else

            debug("Run() FFmpeg with args: " & $args, @ScriptLineNumber, 3);debug
            $ffmpeg = Run($args, @ScriptDir, @SW_HIDE, BitOr($STDERR_CHILD$STDIN_CHILD))
            debug("$ffmpeg running with PID: " & $ffmpeg, @ScriptLineNumber, 4);debug

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

            local $ease_time
            local $done_response = 0

            while true

                $ease_time += 1

                Sleep(50)
                if $time_in_title = $ON and Mod($ease_time, 10) = 0 then
                    SetWinTitleText($title_msg_string & "      [" & SecondsToDHMS(TimerDiff($total_timestamp)/1000, true) & "]")
                endif
                ; Capture Output..
                $console_out = StdErrRead($ffmpeg)

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

                if StringInStr($console_out"write? [y/N]", 0, -1) then
                    WinActivate($ffeGUI)
                    WinFlash($ffeGUI"", 2, 999)
                    SetWinTitleText("                [Overwrite Existing File? (hit 'y' or 'n')]")
                    HotKeySet("y""HK_FFmpegResponseYes")
                    HotKeySet("n""HK_FFmpegResponseNo")
                    $done_response = 1
                endif

                $console_out = StringStripWS($console_out, 3)
                if $console_out then
                    ; Only $job_log gets the extra $LOG_LF..
                    $job_log &= DoLog(ConsoleAdd($console_out, @ScriptLineNumber)) & $LOG_LF
                    if $done_response then
                        switch $done_response
                            case 1
                                $done_response = 2
                            case 2
                                HotKeySet("y")
                                HotKeySet("n")
                                $done_response = 0
                        endswitch
                    endif
                endif
            wend

            ProcessClose($ffmpeg)
            StdioClose($ffmpeg)

            $thistime = TimerDiff($timestamp)/1000
            $secprt = "    (" & Round($thistime, 2) & " seconds)"
            if $thistime <= 60 then $secprt = ""

            $msg = $LOG_LF & "Completed in " & SecondsToDHMS($thistime) & $secprt  & $LOG_LF & _
                    "-----------------------------------" & $LOG_LF
            DoLog($msg)
            $job_log &= $msg
            $job_log &= DoLog(ConsoleAdd($console_out, @ScriptLineNumber)) & $LOG_LF

            if $abort_batch then
                ProcessClose($ffmpeg)
                StdioClose($ffmpeg)
                exitloop
            endif

        endif


        if FileExists($outputfile) then

            if FileGetSize($outputfile) > 0 then

                ArrayAdd($made_files$outputfile)

                ; Add file to recent files and re-build the tray..
                ; OK, we're cheating, for now (I'd need to write a 2DAddArray).
                $recent_files = TwoDCol2OneDArray($recent_files)
                ArrayAdd($recent_files$outputfile, true, true)
                $recent_files = OneToTwoDArray($recent_files)

                ; We use this data to re-create our "Recent Files" Tray menu..
                MakeTray()
            else

                $job_log &= DoLog(ConsoleAdd("Deleting zero-length output file: " & $outputfile & $LOG_LF, @ScriptLineNumber)) & $LOG_LF
                FileDelete($outputfile)

            endif

            ; Run Post-File Commands, if any..
            $job_log &= RunPostFileCommand()

        endif

    next
    ; for $runs = 1 to $run_files[0]



    ; ConCATenate Output files..

    if not $abort_batch then

        if $concatenate = $ON and $batch = $ON and $run_files[0] > 1 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$err
            if $overwrite = $ON then $ow_args &= " -y "
            $run_command = $write_loc & " -f concat -safe 0 -i """ & $write_cat & """ " & $ow_args _
                            & "-c copy " & $batch_output_dir & "\joined." & $clean_outputfile_ext

            if $generate_script then
                $generated &= $run_command & $LOG_LF
            else
                $msg = "Concatenating files.."
                $job_log &= DoLog(ConsoleAdd($LOG_LF & $msg & $LOG_LF, @ScriptLineNumber))
                ; re-use process handle so FFmpeg hotkeys still work in concat job..
                $ffmpeg = Run($run_command, @ScriptDir, @SW_HIDE, BitOr($STDERR_CHILD$STDIN_CHILD$STDOUT_CHILD))

                while true

                    $err = false
                    $console_out = StdErrRead($ffmpeg)
                    $err = @error

                    if $abort_batch then
                        Sleep(250)
                        exitloop
                    endif

                    if StringInStr($console_out"Overwrite? [y/N]", 0, -1) then
                        WinActivate($ffeGUI)
                        WinFlash($ffeGUI"", 2, 999)
                        SetWinTitleText("                [Overwrite Existing File? (hit 'y' or 'n')]")
                        HotKeySet("y""HK_FFmpegResponseYes")
                        HotKeySet("n""HK_FFmpegResponseNo")
                    endif

                    $console_out = StringStripWS($console_out, 3)

                    if $console_out then
                        $job_log &= DoLog(ConsoleAdd($console_out, @ScriptLineNumber)) & $LOG_LF
                    endif

                    if $err then exitloop
                    Sleep(25)
                wend
                ProcessClose($ffmpeg)
                StdioClose($ffmpeg)
            endif

        endif
    endif

    ; Report total time for batch..
    if $run_files[0] > 1 then

        $thistime = TimerDiff($total_timestamp)/1000
        $secprt = "    (" & Round($thistime, 2) & " seconds)"
        if $thistime <= 60 then $secprt = ""
        $msg =  $LOG_LF & "Batch completed in " & SecondsToDHMS($thistime) & $secprt & $LOG_LF & _
                "-----------------------------------" & $LOG_LF
        DoLog($msg)
        $job_log &= DoLog(ConsoleAdd($msg, @ScriptLineNumber)) & $LOG_LF

    endif

    ; Post-Job Commands..

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


    DoLog("out"$log_append$LOG_LF & $LOG_LF)
    TrayItemSetState($tray_abort_batch$TRAY_DISABLE)

    HotKeySet("{PAUSE}")
    HotKeySet("{SCROLLLOCK}")
    HotKeySet("^q")
    HotKeySet("^r")
    HotKeySet("y")
    HotKeySet("n")

    SetWinTitleText()
    GUICtrlSetState($label_abort$GUI_HIDE)

    SetConsoleOutput($job_log)
    ShowOutputButts()

    ; Grab fresh..
    $log_each_job = IniReadCheckBoxValue($ini_path$my_name"log_each_job"$ON)
    if $log_each_job = $ON and not $generate_script then SaveOutput($job_log)


    if not $abort_batch then

        if $generate_script then

            local $save_bat$error = 0
            ; Called from command-line, with "generate" flag..
            if $do_gen then
                $save_bat = @WorkingDir & "\ffe.bat"

            ; Called from button in GUI..
            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)
                $error = @error
                DialogClose()
                if FileExists(GetParent($save_bat)) then IniWrite($ini_path$my_name"save_bat_dir", GetParent($save_bat))
            endif

            if $error == 0 then
                local $job_batch_file = FileOpen($save_bat$FO_APPEND+$FO_UTF8_NOBOM)
                FileWrite($job_batch_file$generated)
                FileClose($job_batch_file)
                ConsoleAdd("Saved batch script to: " & $save_bat & ".", @ScriptLineNumber)
            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

    endif


    $do_drop_window = $drop_win_state
    EnableRunningControls()
    UpdateOutputArgs()
    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.", @ScriptLineNumber)
    endif

endfunc








func ______________________PRESETS()
endfunc




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

    debug("", @ScriptLineNumber, 6);debug
    debug("", @ScriptLineNumber, 6);debug
    debug("=>>> XXX >>> LoadPreset(): >>>XXX>>>" & $this_preset & "<<<XXX<<<=" & "    INIT: " & $init , @ScriptLineNumber, 6);debug

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

    local $param
    local $app_menu = GetSystemMenu($ffeGUI, 0)

    ; Command-Line preset launch..
    ;
    if StringInStr($this_preset"|") then
        local $launch_presets = StringSplit($this_preset"|")
            for $lp = 1 to $launch_presets[0]
                local $loaded = LoadPreset($launch_presets[$lp], $init)
                if not $loaded then return false
            next
            ; Will only check the most recently-loaded..
            return true
    endif

    if $this_preset then
        if InArray($presets$this_preset) and not InArray($not_presets$this_preset) then
            GUICtrlSetData($combo_presets$this_preset)
        endif
    else
        if not $init then
            ; User selected from drop-down..
            $this_preset = GUICtrlRead($combo_presets)
            $store_filepaths = GUICtrlRead($check_store_filepaths)
            debug("$this_preset: " & $this_preset, @ScriptLineNumber, 8);debug
            debug("$store_filepaths: " & $store_filepaths, @ScriptLineNumber, 8);debug
        endif
    endif


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

    if not PresetExists($this_preset) then
        ConsoleAdd("No such preset: " & $this_preset, @ScriptLineNumber)
        return false
    endif

    ; Set this handy global variable..
    $current_preset = $this_preset
    
    if not $init then ConsoleAdd($LOG_LF & "Loading preset: " & $current_preset, @ScriptLineNumber)

    local $read_ini_inputfile = ""
    local $read_ini_outputfile = ""
    
    $inputfile not sent on command-line, read ini value..
    if not $inputfile then
        $read_ini_inputfile = ffeDeTokenizeString(IniRead($ini_path$current_preset"inputfile"""))
    endif

    $read_ini_outputfile = ffeDeTokenizeString(IniRead($ini_path$current_preset"outputfile"""))
    
    debug("$read_ini_outputfile: " & $read_ini_outputfile, @ScriptLineNumber, 8);debug

    ; Load file paths from ini.
    ; IF $store_filepaths = $ON (specified by user in GUI or prefs/preset)        run(SpeedUp x2) "B:\Test\ffe\IN\ScooterRace.flv"
    ; or we are loading the $EXIT_PRESET
    
    ; Also if in and out are both specified/discoverable and we are in a go/run() situation..
    
    if $store_filepaths = $ON or $current_preset = $EXIT_PRESET or _
        ($go = true and $read_ini_inputfile) or ($go = true and $inputfile and $read_ini_outputfile) then

        ; INPUT File..
        CRT($inputfile)

        ; CheckDirWild() will return true if $inputfile is valid.
        ; If the supplied path is a dir and has no wildcards, they will be added by CheckDirWild()..
        if CheckDirWild($inputfile) then GUICtrlSetData($inp_inputfile$inputfile)
        
        debug("$inputfile: " & $inputfile, @ScriptLineNumber, 7);debug

        $inputfile not sent on command-line, use ini value..
        ; This is reset during manual preset loading
        if $read_ini_inputfile then
            $inputfile = $read_ini_inputfile
            GUICtrlSetData($inp_inputfile$read_ini_inputfile)
        endif

        ; OUTPUT File..

        $ini_outputfile = ""
        if $read_ini_outputfile then
            CRT($read_ini_outputfile)
            $ini_outputfile = $read_ini_outputfile
            GUICtrlSetData($inp_outputfile$ini_outputfile)
        endif
        debug("$ini_outputfile: " & $ini_outputfile, @ScriptLineNumber, 8);debug

    endif
    

    if $current_preset = $EXIT_PRESET then
        ; prevent this popping back into outputfile from exit settings..
        $ini_outputfile = ""
    endif


    if $replace_mode = $ON then
        WipeSettings()
        $x_param = ""
    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)
    $param = IniRead($ini_path$current_preset"v_bitrate""")
    if $param then GUICtrlSetData($combo_v_bitrate$param$param)

    $param = IniRead($ini_path$current_preset"frames_per_second""")
    if $param then GUICtrlSetData($combo_frames_per_second$param$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)

    $param = IniRead($ini_path$current_preset"crop_width""")
    if $param then GUICtrlSetData($inp_crop_width$param)
    $param = IniRead($ini_path$current_preset"crop_height""")
    if $param then GUICtrlSetData($inp_crop_height$param)
    $param = IniRead($ini_path$current_preset"crop_x""")
    if $param then GUICtrlSetData($inp_crop_x$param)
    $param = IniRead($ini_path$current_preset"crop_y""")
    if $param then GUICtrlSetData($inp_crop_y$param)

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

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

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

    $param = IniReadCheckBoxValue($ini_path$current_preset"resize_first""")
    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



    $param = IniRead($ini_path$current_preset"default_extension""")
    if $param then
        if $default_extension <> $param and not $init then
            ; Let the user know they have a new default extension loaded..
            ConsoleAdd("default_extension: '." & $param & "'", @ScriptLineNumber)
        endif
        $default_extension = $param
    endif

    $param = IniRead($ini_path$current_preset"default_audio_extension""")
    if $param then
        if $default_audio_extension <> $param and not $init then
            ConsoleAdd("default_audio_extension: '." & $param & "'", @ScriptLineNumber)
        endif
        $default_audio_extension = $param
    endif

    ; Yes, you can hack this into your presets, if required..
    $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: " & Human($param), @ScriptLineNumber)
        endif
        $kill_ffmpeg_on_exit = $param
        CheckMenuItem($app_menu$am_kill_ffmpeg_on_exit$kill_ffmpeg_on_exit)
    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)
    debug("$do_matof: " & Human($do_matof), @ScriptLineNumber, 8);debug


    $overwrite = IniReadCheckBoxValue($ini_path$current_preset"overwrite"$overwrite, true)
    GUICtrlSetState($check_overwrite$overwrite)
    debug("$overwrite: " & Human($overwrite), @ScriptLineNumber, 8);debug

    $concatenate = IniReadCheckBoxValue($ini_path$current_preset"concatenate"$concatenate, true)
    GUICtrlSetState($check_concatenate$concatenate)
    debug("$concatenate: " & Human($concatenate), @ScriptLineNumber, 8);debug

    $param = IniReadCheckBoxValue($ini_path$current_preset"quit_when_done"$quit_when_done, true)
    if $param then
        if $quit_when_done <> $param and not $init then
            ; Inform user of this change from default..
            ConsoleAdd("quit_when_done: " & Human($param), @ScriptLineNumber)
        endif
        $quit_when_done = $param
        GUICtrlSetState($check_quit_when_done$quit_when_done)
    endif
    debug("$quit_when_done: " & Human($quit_when_done), @ScriptLineNumber, 8);debug

    $param = IniReadCheckBoxValue($ini_path$current_preset"shutdown_when_done"$shutdown_when_done, true)
    if $param then
        if $shutdown_when_done <> $param and not $init then
            ConsoleAdd("shutdown_when_done: " & Human($param), @ScriptLineNumber)
        endif
        $shutdown_when_done = $param
        GUICtrlSetState($check_shutdown_when_done$shutdown_when_done)
    endif
    debug("$shutdown_when_done: " & Human($shutdown_when_done), @ScriptLineNumber, 8);debug

    SetOverwriteTip()
    SetConcatenateFilesTip()
    SetQuitWhenDoneTip()
    SetShutdownWhenDoneTip()

    GetLogLocation($current_preset)
    UpdateOutputArgs()

    ; Pre-Post Commands..
    ; 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()

    debug("LOADING PRE+POST COMMANDS.. ", @ScriptLineNumber, 8);debug
    LoadPreCommands(true)
    LoadPostCommands(true)
    LoadPostFileSettings(true)

    GUICtrlSetState($check_run_pre_job_commands$run_pre_job_commands)
    GUICtrlSetState($check_run_post_job_commands$run_post_job_commands)
    GUICtrlSetState($check_run_post_file_command$run_post_file_command)

    SetPreJobTip()
    SetPostJobTip()
    SetPostFileTip()
    GetPresetNotes()

    local $display_pf = $notes_prefix
    if $init then $display_pf = ""
    if $preset_notes then ConsoleAdd($display_pf & $preset_notes & $LOG_LF)

    ; All controls are now considered "unaltered"..
    ResetAlteredControls()

    return true
endfunc



func GetPresetNotes()
    $preset_notes = IniRead($ini_path$current_preset"notes""")
    ConvertNewlines($preset_notes)
endfunc


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



func ButtSavePreset()
    local $this_preset = GUICtrlRead($combo_presets)
    if $this_preset = $my_name and not _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




; Ensure user-supplied preset name is safe..
;
func MakePresetNameSafe($user_preset_name)

    debug("$user_preset_name: " & $user_preset_name, @ScriptLineNumber, 6);debug

    ; We will use a pipe to separate multiple presets on the command-line..
    $user_preset_name = StringReplace($user_preset_name"|""!")
    if @extended then ConsoleAdd("Pipe (special) character replaced with '!'" & $LOG_LF & _
                                "A pipe is used to layer multiple presets on the command-line. e.g.." & $LOG_LF & $LOG_LF & _
                                "    C:\path\to\ffe.exe run(Test Setup|Test Preset) ""B:\Test\file.mp4""", @ScriptLineNumber)

    ; No square brackets inside names - it will mess up "EVERYTHING"..
    $user_preset_name = StringReplace($user_preset_name"[""(")
    $user_preset_name = StringReplace($user_preset_name"]"")")
    if @extended then ConsoleAdd("Square Brace characters replaced with regular braces." & $LOG_LF & _
                                "Preset names are stored *iniside* [square braces].", @ScriptLineNumber)

    ; Strip off white space from start+end..
    $user_preset_name = StringStripWS($user_preset_name, 3)

    return $user_preset_name

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

    $this_preset = MakePresetNameSafe($this_preset)


    $presets = IniReadSectionNames($ini_path)
    if InArray($presets$this_preset) and $this_preset <> $my_name  and $this_preset <> $EXIT_PRESET and not _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..

    ; Don't store file path if that is disabled. But do on exit..
    if GUICtrlRead($check_store_filepaths) = $ON or $this_preset = $EXIT_PRESET then

        $inputfile = GUICtrlRead($inp_inputfile)
        if $inputfile then IniWrite($ini_path$this_preset"inputfile"$inputfile)

        $outputfile = GUICtrlRead($inp_outputfile)
        ; 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_width"$inp_crop_width)
    SavePref($this_preset"crop_height"$inp_crop_height)
    SavePref($this_preset"crop_x"$inp_crop_x)
    SavePref($this_preset"crop_y"$inp_crop_y)
    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)

    if $altered_resize_first then SavePref($this_preset"resize_first"$check_resize_first, true)
    if $altered_do_matof then SavePref($this_preset"do_matof"$check_do_matof, true)


    ; Don't use SavePref() for this, no need, also, 0 would not get saved.
    ; Users advanced enough to be using this stuff can add parameters to their presets manually.
    ; IniWrite($ini_path$this_preset"batch_commands_timeout", Int($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!

    ; Master switch, save setting or delete if unset..
    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", ffeTokenizeString($pre_job_commands_file))
    endif


    SavePref($this_preset"run_post_file_command"$check_run_post_file_command, true)
    ; If not unset, save the associated string (this one is a direct command)..
    if $post_file_command then
        IniWrite($ini_path$this_preset"post_file_command", StringReplace($post_file_command, '"', "&quot;"))
    endif

    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", ffeTokenizeString($post_job_commands_file))
    endif

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

    ; Don't save these to master (ffe) settings..
    if $this_preset <> $my_name then
        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 with preset save (though they are read from presets). For reference only..
;    $default_extension    $default_audio_extension $kill_ffmpeg_on_exit


    ; Not read from GUI, but directly from current $do_output..
    if $altered_do_output then IniWriteCheckBoxValue($ini_path$this_preset, "
do_output", $do_output)


    UpdatePresetsCombo()
    GUICtrlSetData($combo_presets$this_preset)

    local $sp_str
    local $saved_preset = IniReadSection($ini_path$this_preset)
    if not IsArray($saved_preset) then return ConsoleAdd("
Error displaying saved preset (might be empty).", @ScriptLineNumber)

    ; Report the data saved..
    $sp_str = "
Saved preset.. " & $LOG_LF & "[" & $this_preset & "]" & $LOG_LF
    for $i = 1 to $saved_preset[0][0]
        $sp_str &= $saved_preset[$i][0] & "
=" & $saved_preset[$i][1] & $LOG_LF
    next

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

    ConsoleAdd($LOG_LF & $sp_str, @ScriptLineNumber)

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/unset 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
    endif
endfunc


; Delete the current preset from the ini file..

func WipePreset()

    if _IsPressed(10) then return RestoreBackupPreset()

    local $this_preset = GUICtrlRead($combo_presets)
    if not $this_preset then return
    $presets = IniReadSectionNames($ini_path)
    if not InArray($presets$this_preset) then
        ConsoleAdd("
Error wiping preset: '" & $this_preset & "' does not exist!", @ScriptLineNumber)
        return false
    endif

    if $this_preset <> $my_name then
        local $backup_preset = IniReadSection($ini_path$this_preset)
        if IniDelete($ini_path$this_preset) then
            ; Backup previous backup..
            if InArray($presets$PRESET_BACKUP_STRING & $this_preset) then
                local $existing_backup = IniReadSection($ini_path$PRESET_BACKUP_STRING & $this_preset)
                IniWriteSection($ini_path$PRESET_BACKUP_STRING  & "
(previous)--" & $this_preset$existing_backup)
            endif
            IniWriteSection($ini_path$PRESET_BACKUP_STRING & $this_preset$backup_preset)
            ConsoleAdd("
Created backup of preset: " & $this_preset, @ScriptLineNumber)
            ConsoleAdd("
Wiped preset: " & $this_preset, @ScriptLineNumber)
        else
            ConsoleAdd("
Error wiping preset: " & $this_preset & ".", @ScriptLineNumber)
        endif
    else
        DialogOpen()
        MsgBox(0, "
Not quite!", _
            "
If you wish to reset the default settings, simply 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) = $PRESET_BACKUP_STRING then
            $got_backups = true
            if IniDelete($ini_path$presets[$i]) then ConsoleAdd("
Wiped backup preset: " & $presets[$i] & ".", @ScriptLineNumber)
        endif
    next
    if not $got_backups then ConsoleAdd("
No backups found!", @ScriptLineNumber)
endfunc



func RestoreBackupPreset()

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

    local $got_backups = false
    local $msg = "
Choose a backup to restore.."

    DialogOpen()

    local $previous_event_mode = AutoItSetOption("
GUIOnEventMode", 0)
    local $previous_coord_mode = AutoItSetOption("
GUICoordMode", 0)

    local $uw_width = 318
    local $uw_height = 60

    $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
    debug("
Dimensions: " & "x: " & $x & " y: " & $y & " width: " & $width & " height: " & $height, @ScriptLineNumber, 8);debug

    local $uw_x = Int(IniRead($ini_path$my_name, "
unwipe_x", -1))
    local $uw_y = Int(IniRead($ini_path$my_name, "
unwipe_y", -1))

    local $butt_width = 50
    local $combo_width = 180

    local $UnWipe = GUICreate("
Restore Backup Preset..", $uw_width$uw_height$uw_x$uw_y)

    local $butt_cancel = GUICtrlCreateButton("
Cancel", 10, 28, $butt_width, 23)
    local $combo = GUICtrlCreateCombo("
", $butt_width+10, 1, $combo_width, 20)
    local $butt_import = GUICtrlCreateButton("
Restore", $combo_width+10, -1, $butt_width, 23)

    ; Fill up the combo..
    for $i = 1 to $presets[0]
        if StringLeft($presets[$i], 10) = $PRESET_BACKUP_STRING then
            GUICtrlSetData($combo$presets[$i])
            $got_backups = true
        endif
    next

    GUISetCoord(9, 7)

    ; Pay attention people!
    if not $got_backups then $msg = "
Got no backups to restore!"
    GUICtrlCreateLabel($msg, 0, 0, $uw_width-20, 20)

    GUISetState(@SW_SHOW, $UnWipe)
    ControlCommand($ffeGUI, "
", $combo, "SelectString", $presets[1])

    local $combo_selection$save_xy

    while 1
        switch GUIGetMsg()
            case $GUI_EVENT_CLOSE$butt_cancel
                exitloop
            case $butt_import
                $save_xy = true
                $combo_selection = GUICtrlRead($combo)
                if InArray($presets$combo_selection) then
                    local $backup_section = IniReadSection($ini_path$combo_selection)
                    IniDelete($ini_path$combo_selection)
                    local $new_name = StringReplace($combo_selection$PRESET_BACKUP_STRING, "
")
                    IniWriteSection($ini_path$new_name$backup_section)
                    ConsoleAdd("
Restored preset: " & $new_name, @ScriptLineNumber)
                endif
                exitloop
        endswitch
        Sleep(10) ; required?
    wend

    if $save_xy then
        local $x_coord = -1, $y_coord = -1
        local $size_array = WinGetPos($UnWipe; 0-1-2-3:x-y-w-h
        if IsArray($size_array) then
            $x_coord = $size_array[0]
            $y_coord = $size_array[1]
        endif
        if $x_coord and $x_coord <> -1 then IniWrite($ini_path$my_name, "
unwipe_x", $x_coord)
        if $y_coord and $y_coord <> -1 then IniWrite($ini_path$my_name, "
unwipe_y", $y_coord)
    endif

    GUIDelete($UnWipe)
    AutoItSetOption("
GUIOnEventMode", $previous_event_mode)
    AutoItSetOption("
GUICoordMode", $previous_coord_mode)
    DialogClose()

    UpdatePresetsCombo()

endfunc



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


; Update the combo box with the current presets..
func UpdatePresetsCombo()

    debug("
UpdatePresetsCombo()...", @ScriptLineNumber, 9);debug

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

    for $i = 1 to $presets[0]
        ; Only list the first occurrence 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], StringLen($PRESET_BACKUP_STRING)) <> $PRESET_BACKUP_STRING 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. Unless..
    if $sort_presets_list = $ON and $show_ffe_in_sorted_list = $OFF then
        $presets_string = StringReplace($presets_string, "
ffe|", "", 1)
    endif

    ; Remove special section(s)..
    $presets_string = StringReplace($presets_string$NAME_BUTTONS & "
|", "")
    $presets_string = StringReplace($presets_string$EXIT_PRESET & "
|", "")
    $presets_string = StringReplace($presets_string$NAME_VIDEO_MAPPINGS & "
|", "")
    $presets_string = StringReplace($presets_string$NAME_AUDIO_MAPPINGS & "
|", "")


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

    debug("
$presets_string" & $presets_string, @ScriptLineNumber, 9);debug

endfunc





; These four functions could be rolled into one..

func MenuAddToACodecs()
    local $new_user_preset = GUICtrlRead($combo_a_codec)
    if $new_user_preset then
        ; This string will *always* be present..
        $audio_codecs = StringReplace($audio_codecs, "
|- disable audio -", "|" & $new_user_preset & "|- disable audio -")
        IniWrite($ini_path$my_name, "
audio_codecs", $audio_codecs)
        ConsoleAdd($new_user_preset & "
 added to audio codecs ", @ScriptLineNumber)
        GUICtrlSetData($combo_a_codec$audio_codecs)
        ControlCommand($ffeGUI, "
", $combo_a_codec, "SelectString", $new_user_preset)
    endif
endfunc
func MenuAddToVCodecs()
    local $new_user_preset = GUICtrlRead($combo_v_codec)
    if $new_user_preset then
        $video_codecs = StringReplace($video_codecs, "
|- disable video -", "|" & $new_user_preset & "|- disable video -")
        IniWrite($ini_path$my_name, "
video_codecs", $video_codecs)
        ConsoleAdd($new_user_preset & "
 added to video codecs ", @ScriptLineNumber)
        GUICtrlSetData($combo_v_codec$video_codecs)
        ControlCommand($ffeGUI, "
", $combo_v_codec, "SelectString", $new_user_preset)
    endif
endfunc
func MenuRemoveFromACodecs()
    local $new_user_preset = GUICtrlRead($combo_a_codec)
    if $new_user_preset then
        ; So we don't get a partial match..
        $audio_codecs = StringReplace($audio_codecs, "
|" & $new_user_preset & "|", "|")
        IniWrite($ini_path$my_name, "
audio_codecs", $audio_codecs)
        ConsoleAdd($new_user_preset & "
 removed from audio codecs ", @ScriptLineNumber)
        GUICtrlSetData($combo_a_codec$audio_codecs)
        $a_codec = IniRead($ini_path$my_name, "
a_codec", "")
        ControlCommand($ffeGUI, "
", $combo_a_codec, "SelectString", $a_codec)
    endif
endfunc
func MenuRemoveFromVCodecs()
    local $new_user_preset = GUICtrlRead($combo_v_codec)
    if $new_user_preset then
        ; Check for the full string within the codecs..
        $video_codecs = StringReplace($video_codecs, "
|" & $new_user_preset & "|", "|")
        IniWrite($ini_path$my_name, "
video_codecs", $video_codecs)
        ConsoleAdd($new_user_preset & "
 removed from video codecs ", @ScriptLineNumber)
        GUICtrlSetData($combo_v_codec$video_codecs)
        $v_codec = IniRead($ini_path$my_name, "
v_codec", "")
        ControlCommand($ffeGUI, "
", $combo_v_codec, "SelectString", $v_codec)
    endif
endfunc




func MenuRenamePreset()

    if $current_preset = $my_name or  $current_preset = $EXIT_PRESET then
        ConsoleAdd("
Cannot rename " & $current_preset & "!", @ScriptLineNumber)
        return
    endif

    DialogOpen()
    local $new_preset_name = CorzFancyInputBox("
Rename Preset.. ", _
        "
Enter a new name for the preset.. ", $current_preset , "" , 350, 95, default, default, 0, $ffeGUI)
    DialogClose()

    debug("
$new_preset_name" & $new_preset_name, @ScriptLineNumber, 8);debug

    if $new_preset_name then
        if InArray($not_presets$new_preset_name) then
            ConsoleAdd("
Cannot rename: " & $new_preset_name & "!", @ScriptLineNumber)
            return
        endif

        $new_preset_name = MakePresetNameSafe($new_preset_name)
        debug("
$new_preset_name" & $new_preset_name, @ScriptLineNumber, 8);debug

        BetterIniRenameSection($ini_path$current_preset$new_preset_name)
        debug("
BetterIniRenameSection() error: " & @error, @ScriptLineNumber, 8);debug

        ConsoleAdd("
Preset: " & $current_preset &  " renamed to : " & $new_preset_name & ".", @ScriptLineNumber)
        $current_preset = $new_preset_name
        UpdatePresetsCombo()
        ControlCommand($ffeGUI, "
", $combo_presets, "SelectString", $current_preset)
    endif
endfunc




func MenuToggleFluidMenu()

    TogglePref($fluid_image_menu)
    IniWriteCheckBoxValue($ini_path$my_name, "
fluid_image_menu", $fluid_image_menu)
    ConsoleAdd("
fluid_image_menu set to: " & $fluid_image_menu, @ScriptLineNumber)
    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





; Some Tray Toggles..



func TrayToggleRetainRecentFiles()
    TogglePref($retain_recent_files)
    IniWriteCheckBoxValue($ini_path$my_name, "
retain_recent_files", $retain_recent_files)
    ConsoleAdd("
retain_recent_files set to: " & $retain_recent_files, @ScriptLineNumber)
    TrayItemSetState($tray_toggle_retain_recent_files$retain_recent_files)
endfunc


func MenuToggleAutoCopy()
    TogglePref($auto_copy_images)
    IniWriteCheckBoxValue($ini_path$my_name, "
auto_copy_images", $auto_copy_images)
    ConsoleAdd("
auto_copy_images set to: " & $auto_copy_images, @ScriptLineNumber)
    TrayItemSetState($tray_toggle_auto_copy_images$auto_copy_images)
    HideDropWindow()
endfunc




; Checks if ffe.ini contains the specified preset (case-insensitive).
; A bit dumb in that it doesn't check if the [section] is or isn't a preset,
; simply that the section exists inside ffe.ini, which is all we need.
; Note: This function is used to check for EXIT_PRESET.
;
func PresetExists($this_preset)
    $presets = IniReadSectionNames($ini_path)
    if not IsArray($presets) then return false
    if InArray($presets$this_preset) then return $this_preset
    return false
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 InArray($not_presets$ini_section_names_array[$i]) then continueloop
        return true
    next
endfunc





func ______________INPUT_OUTPUT()
endfunc




;2do - check which control we click in/out and only update if required

; DoArgsCreate()
; Called on *every* change, user <tab>, click, dropped item, etc..

; A black box. Here be dragons!
;
func DoArgsCreate($batch="
null")
    debug("
", @ScriptLineNumber, 6);debug
    debug("
", @ScriptLineNumber, 6);debug
    debug("
DoArgsCreate() $batch=" & $batch, @ScriptLineNumber, 6);debug
    debug("
$inputfile" & $inputfile, @ScriptLineNumber, 6);debug

    ; Store text selection, if any.
    ; This code enables us to retain user text selections even whilst MATOF
    ; is working and the input is updating..
    local $caret = _GUICtrlEdit_GetSel($inp_outputfile)

    ; During batch, this is set inside DoIt()
    if not $inputfile then
        $inputfile = GUICtrlRead($inp_inputfile)
    endif
    debug("
$inputfile NOW: " & $inputfile, @ScriptLineNumber, 5);debug

    if not $inputfile then return

    local $input_params$read_vcodec$read_acodec$write_outputfile


    $extra_args = ffeDeTokenizeString(GUICtrlRead($inp_extra_args))
    debug("
$extra_args" & $extra_args, @ScriptLineNumber, 7);debug
    $x_param = $extra_args

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

    if GUICtrlRead($inp_input_params) then
        $input_params = ffeDeTokenizeString(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
    debug("
$matof_string" & $matof_string, @ScriptLineNumber, 7);debug

    if $read_vcodec and not StringInStr($read_vcodec, "
disable") then
        $v_codec = "
 -vcodec " & $read_vcodec
        $matof_string &= "
[" & $read_vcodec  & "]"
    else
        $v_codec = "
"
    endif
    debug("
$matof_string" & $matof_string, @ScriptLineNumber, 7);debug

    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) & "bps]"
        endif

        if GUICtrlRead($combo_frames_per_second) then
            $extra_args &= "
 -r " & GUICtrlRead($combo_frames_per_second)
            $matof_string &= "
[" & GUICtrlRead($combo_frames_per_second) & "fps]"
        endif
    endif
    debug("
$matof_string" & $matof_string, @ScriptLineNumber, 7);debug

    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
    debug("
$matof_string" & $matof_string, @ScriptLineNumber, 7);debug


    if GUICtrlRead($inp_extra_args) then
        $matof_string &= "
[" & CleanPath(GUICtrlRead($inp_extra_args), ".") & "]"
    endif
    debug("
$matof_string" & $matof_string, @ScriptLineNumber, 7);debug
    ; 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

    debug("
$batch" & Human($batch), @ScriptLineNumber, 8);debu
    debug("
$do_matof" & Human($do_matof), @ScriptLineNumber, 8);debug

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

    if $do_matof = $OFF and $batch = $ON then
        ToggleMatofStatus(false)
        ConsoleAdd("
MATOF required for batch operation!", @ScriptLineNumber)
    endif
    debug("
$do_matof" & Human($do_matof), @ScriptLineNumber, 8);debug



    ; Now we set $outputfile..


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

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

        ; local $read_inp_outputfile = ffeDeTokenizeString(GUICtrlRead($inp_outputfile))
        local $read_inp_outputfile = GUICtrlRead($inp_outputfile)
        debug("
$read_inp_outputfile" & $read_inp_outputfile, @ScriptLineNumber, 7);debug
        $read_inp_outputfile = ffeDeTokenizeString($read_inp_outputfile)

        CRT($read_inp_outputfile)
        debug("
$read_inp_outputfile" & $read_inp_outputfile, @ScriptLineNumber, 7);debug


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

        debug("
$old_matof" & $old_matof, @ScriptLineNumber, 7);debug

        ; BE CAREFUL with StringReplace(!). If $old_matof = "" then it would return "", hence we check first
        if $old_matof then $read_inp_outputfile = StringReplace($read_inp_outputfile, ffeDetokenizeString($old_matof), "
")
        debug("
$read_inp_outputfile" & $read_inp_outputfile, @ScriptLineNumber, 7);debug

        ; :look: what if it is wild??
        local $inputfile_basename = RemoveExtension(BaseName($inputfile))
        debug("
$inputfile_basename" & $inputfile_basename, @ScriptLineNumber, 7);debug

        ; Set output directory from $read_inp_outputfile/fallback dir..

        if $read_inp_outputfile then

            ; Directory already specified in outputfile..                go(Simple Test)

            if IsDir($read_inp_outputfile) then
                $batch_output_dir = $read_inp_outputfile
                debug("
$batch_output_dir: SET to: " & $batch_output_dir, @ScriptLineNumber, 7);debug
            else
                ; Otherwise, we will use parent dir of specified outputfile, if it exists..
                if IsDir(GetParent($read_inp_outputfile)) then $batch_output_dir = GetParent($read_inp_outputfile)
            endif

            ;:look: if batch_output_dir is not set, when generating scripts, if user specifies a non-existent output path
            ; (that may exists then generated script is /run/) ffe will "fix" the path and use the fall-back (below).

        endif
        debug("
$read_inp_outputfile" & $read_inp_outputfile, @ScriptLineNumber, 7);debug
        debug("
$batch_output_dir" & $batch_output_dir, @ScriptLineNumber, 7);debug


        ; Blank output_dir: perhaps a URL and no outputfile (dir) specified in ini. Use fall-back..
        ;
        if not $batch_output_dir then

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

            ; Check we aren't grabbing a URL, which has no "parent"..
            if not $fallback_folder or (StringInStr($fallback_folder, "
@parent") and StringInStr($inputfile, "://")) then
                $fallback_folder = @MyDocumentsDir
            else
                $fallback_folder = ffeDeTokenizeString($fallback_folder)
            endif
            $batch_output_dir = $fallback_folder
        endif


        local $fallback_path = $batch_output_dir & "
\" & $inputfile_basename & "." & $default_extension
        debug("
$fallback_path" & $fallback_path, @ScriptLineNumber, 5);debug


        debug("
$ini_outputfile" & $ini_outputfile, @ScriptLineNumber, 8);debug

        ; 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

            ; Set to ini setting (or last-used $outputfile) first. could be blank.
            $outputfile = $ini_outputfile
            debug("
$outputfile" & $outputfile, @ScriptLineNumber, 7);debug

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

            ;:look: looks like a bug. Erm...
            if IsDir($outputfile) or not $outputfile then
                $outputfile = $fallback_path
            endif
            debug("
$outputfile" & $outputfile, @ScriptLineNumber, 7);debug

            ; 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
        debug("
$outputfile" & $outputfile, @ScriptLineNumber, 6);debug



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



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

            debug("
$matof_string" & $matof_string, @ScriptLineNumber, 7);debug


            ; 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
        debug("
FINAL $outputfile" & $outputfile, @ScriptLineNumber, 5);debug
        debug("
$ini_outputfile" & $ini_outputfile, @ScriptLineNumber, 8);debug

        ; Reset this (new "base" outputfile)..
        if not $ini_outputfile then $ini_outputfile = $outputfile
        
        debug("
FINAL $ini_outputfile" & $ini_outputfile, @ScriptLineNumber, 8);debug
        
        ;:look: the trouble here is that $ini_outputfile is being used for more
        ; than one thing. Here it's a "base name". Oh dear.

        ; 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..

    ; Input parameters override.
    $input_params = StringStripWS($input_params, 3)

    $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)
    debug("
All done creating $args" & $args, @ScriptLineNumber, 5);debug

    _GUICtrlEdit_SetSel($inp_outputfile$caret[0], $caret[1])

endfunc




func RFCreateArgs()
    $altered_resize_first = true
    AutoCreateArgs()
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)
    debug("
AutoCreateArgs() --> DoArgsCreate()", @ScriptLineNumber, 6);debug
    DoArgsCreate()
endfunc






; File/Folder dropped onto some input..
; We only handle single files.
; Dropping multiple items results in the last item being placed.
;
; You can, of course, drop folders in, use wildcards to create batches.
;
func GetDroppedItem()

    debug("
", @ScriptLineNumber, 6);debug
    debug("
GetDroppedItem()..", @ScriptLineNumber, 5);debug

    local $real_file
    ; Shift Key down..
    if _IsPressed(10) then
        $real_file = @GUI_DRAGFILE
    else
        $real_file = LnkToReal(@GUI_DRAGFILE)
    endif

    debug("
Dropped File ($real_file) set to: " & $real_file, @ScriptLineNumber, 5);debug

    if @GUI_DRAGID = -1 then

        switch @GUI_DROPID

            case $inp_inputfile$lab_main_drop$hGIF

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

                ; Not an allowed image..
                else
                    ; A folder..
                    if StringInStr(FileGetAttrib($real_file), "
D") then
                        GUICtrlSetData($inp_inputfile$real_file & "
\*")
                    else
                        ; Setting the location of FFmpeg binary..
                        if BaseName($real_file) = "
ffmpeg.exe" then
                            SetFFmpegBinLocation($real_file)
                            GUICtrlSetData($inp_inputfile, StringReplace(GUICtrlRead($inp_inputfile), $real_file, "
"))
                            return
                        else
                            ; Replace Input..
                            $outputfile = "
"
                            GUICtrlSetData($inp_inputfile$real_file)
                        endif
                    endif
                endif

                UpdateOutputArgs()

                if $drop_command then
                    DoDropCommand()
                    DoArgsCreate()
                endif


            case $inp_outputfile
                ; Replace data..
                $ini_outputfile = $real_file
                GUICtrlSetData($inp_outputfile$ini_outputfile)
                DoArgsCreate()


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

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

            case $edit_console_output
                ; Ditto

        endswitch

    else
        ; @GUI_DRAGID <> -1
        return false
    endif

endfunc



; :look: single files!

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

func UpdateOutputArgs()


    $inputfile = ffeDeTokenizeString(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 = ffeDeTokenizeString(GUICtrlRead($inp_outputfile))
        CRT($out_parent)

        ; If outputfile is a dir, use that for $out_parent, otherwise its parent dir..
        if not IsDir($out_parent) then $out_parent = GetParent(ffeDeTokenizeString(GUICtrlRead($inp_outputfile)))

        ;:look: overwriting user set outputfile

        debug("
UpdateOutputArgs():  outputfile: " & $outputfile, @ScriptLineNumber, 3);debug

        if not $ini_outputfile then

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

        endif

        debug("
UpdateOutputArgs():  outputfile: " & $outputfile, @ScriptLineNumber, 3);debug

    endif
    debug("
DoArgsCreate(UpdateOutputArgs)..", @ScriptLineNumber, 6);debug
    DoArgsCreate()

endfunc



; Use FFmpeg to interrogate the file for cropping values.
; Automatically remove black bars.
;
func DoAutoCrop()

    debug("
", @ScriptLineNumber, 6);debug
    debug("
DoAutoCrop()...", @ScriptLineNumber, 5);debug

    local $shift_down = false
    if _IsPressed(10) then $shift_down = true

    local $test_file = ffeDeTokenizeString(GUICtrlRead($inp_inputfile))

    if not FileExists($test_file) then
        ConsoleAdd("
Unable to detect cropping. File does not exist.")
        return
    endif

    if IsWild($test_file) then
        ConsoleAdd("
Can't get cropping values from multiple files!" & $LOG_LF & _
                    "
If all files have the same cropping, drag in one file and try again."  & $LOG_LF & $LOG_LF & _
                    "
Afterwards, you can drag in the folder and keep the crop values.")
        return
    endif

    local $auto_crop_frames = Int(IniRead($ini_path$my_name, "
auto_crop_frames", 24))
    local $auto_crop_limit = Int(IniRead($ini_path$my_name, "
auto_crop_limit", 24))
    local $auto_crop_round = Int(IniRead($ini_path$my_name, "
auto_crop_round", 16))
    local $auto_crop_reset = Int(IniRead($ini_path$my_name, "
auto_crop_reset", 0))


    ; If <shift> is down, number of frames to test can be set..

    ; false = don't save value (right-click the control for that)
    if $shift_down then
        $auto_crop_frames = UserEditCropTestFrames($auto_crop_frames, false)
        if @error then ConsoleAdd($LOG_LF & "
Frame test number change cancelled." & $LOG_LF & " Using default values..")
    endif

    debug("
$auto_crop_frames" & $auto_crop_frames, @ScriptLineNumber, 8);debug
    debug("
$auto_crop_limit" & $auto_crop_limit, @ScriptLineNumber, 8);debug
    debug("
$auto_crop_round" & $auto_crop_round, @ScriptLineNumber, 8);debug
    debug("
$auto_crop_reset" & $auto_crop_reset, @ScriptLineNumber, 8);debug

    local $tmpfile = @TempDir & "
\ffe_crop_detect.mkv"
    local $detect_args = "
 -frames:v " & $auto_crop_frames & _
                        "
  -vf cropdetect=" & $auto_crop_limit & ":" & $auto_crop_round & ":" & $auto_crop_reset & " "
    local $ffmpeg_get_crop = Run($ffmpeg_binary & ' -i "
' & $test_file & '" ' & $detect_args & $tmpfile, "", @SW_HIDE, $STDERR_MERGED)
    local $c_out$v_out

    ConsoleAdd($LOG_LF & _
        "
Running FFmpeg cropdetect with the following settings:" & $LOG_LF & $LOG_LF& _
        "
Cropdetect frames: " & $auto_crop_frames & $LOG_LF & _
        "
Black threshold: " & $auto_crop_limit  & $LOG_LF & _
        "
Dimension rounding :" & $auto_crop_round & $LOG_LF & _
        "
Calculation reset: " & $auto_crop_reset & $LOG_LF & $LOG_LF & _
        "
Please wait a moment.." & $LOG_LF)

    while true
        $c_out = StdOutRead($ffmpeg_get_crop)
        if @error then exitloop
        if StringInStr($c_out, "
crop=") then $v_out &= $c_out
        Sleep(10)
    wend

    debug("
cropdetect out: " & $v_out, @ScriptLineNumber, 9);debug
    ProcessClose($ffmpeg_get_crop)
    StdioClose($ffmpeg_get_crop)
    FileDelete($tmpfile)

    local $crop_settings
    $crop_settings = StringMid($v_out, StringInStr($v_out, "
crop=", 0, -1))
    $crop_settings = StringStripWS($crop_settings, 3)
    ; Although this value happens to *exactly* match the string we will send to FFmpeg,
    ; we don't do that. We fill in the inputs and let DoArgsCreate() generate the arguments.
    local $display_cs = $crop_settings
    $crop_settings = StringTrimLeft($crop_settings, 5)
    $crop_settings = StringSplit($crop_settings, "
:")

    if IsArray($crop_settings) and $crop_settings[0] = 4 then
        GUICtrlSetData($inp_crop_width$crop_settings[1])
        GUICtrlSetData($inp_crop_height$crop_settings[2])
        GUICtrlSetData($inp_crop_x$crop_settings[3])
        GUICtrlSetData($inp_crop_y$crop_settings[4])
        ConsoleAdd("
FFmpeg cropdetect (" & BaseName($test_file) & "): " & $display_cs)
    endif

endfunc




func AddInputOverrideFileArgs()
    local $current_data = GUICtrlRead($inp_input_params)
    if $current_data then $current_data &= "
 "
    GUICtrlSetData($inp_input_params$current_data & '-i "
"')
    ControlFocus($ffeGUI, "
", $inp_input_params)
    ControlSend($ffeGUI, "
", $inp_input_params, "{RIGHT}")
    ControlSend($ffeGUI, "
", $inp_input_params, "{LEFT}")
endfunc


func DelInputOverrideFileArgs()
    GUICtrlSetData($inp_input_params, "
")
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..
;
; New syntax:
; -vf "crop=out_w:out_h:x:y"
;
func AddCropping()

    debug("
", @ScriptLineNumber, 6);debug
    debug("
AddCropping()...", @ScriptLineNumber, 6);debug

    local $do_tally = 0
    if GUICtrlRead($inp_crop_width) then $do_tally += 1
    if GUICtrlRead($inp_crop_height) then $do_tally += 1
    if GUICtrlRead($inp_crop_x) then $do_tally += 3
    if GUICtrlRead($inp_crop_y) then $do_tally += 3

    local $my_args

    switch $do_tally
        case 2
            $my_args = ' -vf "
crop=' & GUICtrlRead($inp_crop_width) & ':' & GUICtrlRead($inp_crop_height) & '"'
        case 8
            $my_args = ' -vf "
crop=' & GUICtrlRead($inp_crop_width) & ':' & GUICtrlRead($inp_crop_height) & _
                        ':' & GUICtrlRead($inp_crop_x) & ':' & GUICtrlRead($inp_crop_y) & '"'
    endswitch

    if $my_args then
        $extra_args &= $my_args
        ;2do write a generic function for this..
        $matof_string &= "
[" & StringStripWS(CleanPath(StringReplace($my_args, '"', ""), "."), 3) & "]"
    endif

    debug("$matof_string: " & $matof_string, @ScriptLineNumber, 7);debug

endfunc


func CreateCodecContexts()
    debug("", @ScriptLineNumber, 6);debug
    debug("$CreateCodecContexts(): $auto_codecs = " & Human($auto_codecs), @ScriptLineNumber, 6);debug

    GUICtrlDelete($ctxt_vcombo)
    GUICtrlDelete($ctxt_acombo)

    $ctxt_vcombo = GUICtrlCreateContextMenu($combo_v_codec)

    local $itm_v1 = GUICtrlCreateMenuItem("Add to Codecs List.."$ctxt_vcombo)
    GUICtrlSetOnEvent(-1, "MenuAddToVCodecs")
    local $itm_v2 = GUICtrlCreateMenuItem("Remove from Codecs List.."$ctxt_vcombo)
    GUICtrlSetOnEvent(-1, "MenuRemoveFromVCodecs")

    $ctxt_acombo = GUICtrlCreateContextMenu($combo_a_codec)

    local $itm_a1 = GUICtrlCreateMenuItem("Add to Codecs List.."$ctxt_acombo)
    GUICtrlSetOnEvent(-1, "MenuAddToACodecs")
    local $itm_a2 = GUICtrlCreateMenuItem("Remove from Codecs List.."$ctxt_acombo)
    GUICtrlSetOnEvent(-1, "MenuRemoveFromACodecs")


    if $auto_codecs = $ON then
        GUICtrlSetState($itm_v1$GUI_DISABLE)
        GUICtrlSetState($itm_v2$GUI_DISABLE)
        GUICtrlSetState($itm_a1$GUI_DISABLE)
        GUICtrlSetState($itm_a2$GUI_DISABLE)
    endif

endfunc




; Check for correct extension (by codec)..

func GetExtFromCodec($video_codec$file_name="")

    debug("GetExtFromCodec()     video_codec: " & $video_codec & "    file_name: " & $file_name, @ScriptLineNumber, 6);debug

    local $this_ext
    if not StringInStr($extra_args"-vn") then
    ; -vn = disable video

        local $map_set = false

        switch true

            case $video_codec = "copy"
                $this_ext = GetExtension($inputfile)
                if IsWild($this_ext) then $this_ext = $default_extension
                debug("COPY >> $this_ext: " & $this_ext, @ScriptLineNumber, 8);debug
                $map_set = true

            case else
                ; Read video extension mappings from ini file into an array..
                local $video_mappings = IniReadSection($ini_path$NAME_VIDEO_MAPPINGS)
                debug_PrintArray($video_mappings"$video_mappings:", @ScriptLineNumber, 8);debug

                if IsArray($video_mappings) then
                    for $i = 1 to $video_mappings[0][0]
                        if StringInStr($video_codec$video_mappings[$i][0]) then
                            $this_ext = $video_mappings[$i][1]
                            $map_set = true
                            exitloop
                        endif
                    next
                endif

        endswitch

        if not $map_set then $this_ext = $default_extension
        debug("$this_ext: " & $this_ext, @ScriptLineNumber, 8);debug



    ; 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 = AAGetItem($known_files$file_name)
                debug("this_ext1: " & $this_ext, @ScriptLineNumber, 7);debug

            ; Unknown file - run probe and find out what audio codec is used..
            else
                $this_ext = ProbeFileForCodec($file_name)
                debug("this_ext2: " & $this_ext, @ScriptLineNumber, 7);debug
                $this_ext = GetExtFromCodecName($this_ext)
                debug("this_ext3: " & $this_ext, @ScriptLineNumber, 7);debug
                ; Store file = audio-ext key=val pair in AA
                if $this_ext then AAAdd($known_files$file_name$this_ext)
            endif
        else
            $this_ext = GetExtFromCodecName($a_codec_inp)
        endif
    endif

    return $this_ext

endfunc




; Use ffprobe to grab the audio codec name..
; Used when video is disabled and user is copying audio to a pure audio track..
;
func ProbeFileForCodec($file)

    debug("ProbeFileForCodec: " & $file, @ScriptLineNumber, 6);debug

    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 AAGetItem($known_files$file)

    ; Need an actual file to work on..
    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
    GetFFprobeLocation()
    debug("ffprobe_loc: " & $ffprobe_loc, @ScriptLineNumber, 7);debug

    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

    ProcessClose($probe_file)
    StdioClose($probe_file)

    debug("$probe_data: " & $probe_data, @ScriptLineNumber, 8);debug

    ; Better than simply checking existence of variable
    if not StringInStr($probe_data"codec_name") then return false
    $probe_data = StringSplit($probe_data"=")

    debug_PrintArray($probe_data"$probe_data:", @ScriptLineNumber, 8);debug

    ; Could specify StringInStr(,,-3), but best to let StringStripWS() handle /whatever/
    ; Line-break comes - I don't know 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..
;
func GetExtFromCodecName($codec_name)

    debug("GetExtFromCodecName() Codec name: " & $codec_name, @ScriptLineNumber, 7);debug

    local $this_ext
    local $map_set = false

    local $audio_mappings = IniReadSection($ini_path$NAME_AUDIO_MAPPINGS)
    debug_PrintArray($audio_mappings"$audio_mappings:", @ScriptLineNumber, 8);debug

    if IsArray($audio_mappings) then

        for $i = 1 to $audio_mappings[0][0]
            if StringInStr($codec_name$audio_mappings[$i][0]) then
                $this_ext = $audio_mappings[$i][1]
                $map_set = true
                exitloop
            endif
        next
    endif

    if not $map_set then $this_ext = $default_audio_extension
    debug("$this_ext: " & $this_ext, @ScriptLineNumber, 8);debug

    return $this_ext

endfunc





; Hardly worth combining these..
;
func EditFFmpegTask()
    local $insert = "remains"
    debug("EditFFmpegTask()..", @ScriptLineNumber, 6);debug
    local $ffmpeg_command = IniRead($ini_path$my_name"ffmpeg_command""-help")
    DialogOpen()
    ; They can enter an empty value, no problem.
    local $new_ffmpeg_command = CorzFancyInputBox("New FFmpeg Command.. ", _
        "Enter a command for the FFmpeg button (you can use @tokens).. "$ffmpeg_command"", 350, 95, default, default, 0, $ffeGUI)
    if @error = 0 then
        $new_ffmpeg_command = ffeTokenizeString($new_ffmpeg_command)
        if $ffmpeg_command <> $new_ffmpeg_command then
            ; Not strictly necessary - it's picked-up at run-time..
            $ffmpeg_command = $new_ffmpeg_command
            $insert = "now set to"
            _GUIToolTip_Destroy($tip_ffmpeg_task)
            $tip_ffmpeg_task = GUICtrlSetTipOptional($check_run_ffmpeg_task$MSG_LF & _
                                    "Current command: " & $new_ffmpeg_command"Quick FFmpeg Task")
            IniWrite($ini_path$my_name"ffmpeg_command", ffeTokenizeString($new_ffmpeg_command))
        endif
    endif
    DialogClose()
    ConsoleAdd("FFmpeg command " & $insert & ": " & $ffmpeg_command, @ScriptLineNumber)
endfunc


func EditFFplayTask()
    local $insert = "remains"
    debug("EditFFplayTask()..", @ScriptLineNumber, 6);debug
    $ffplay_command = IniRead($ini_path$my_name"ffplay_command""-help")
    DialogOpen()
    local $new_ffplay_command = CorzFancyInputBox("New FFplay Command.. ", _
        "Enter a command for the FFplay button (you can use @tokens).. "$ffplay_command"", 350, 95, default, default, 0, $ffeGUI)
    if @error = 0 then
        $new_ffplay_command = ffeTokenizeString($new_ffplay_command)
        if $ffplay_command <> $new_ffplay_command then
            $ffplay_command = $new_ffplay_command
            ConsoleAdd("FFplay command now set to: " & $ffplay_command, @ScriptLineNumber)
            $insert = "now set to"
            _GUIToolTip_Destroy($tip_ffplay_task)
            $tip_ffplay_task = GUICtrlSetTipOptional($check_run_ffplay_task$MSG_LF & _
                                "Current command: " & $new_ffplay_command"Quick FFplay Task")
            IniWrite($ini_path$my_name"ffplay_command", ffeTokenizeString($new_ffplay_command))
        endif
    endif
    DialogClose()
    ConsoleAdd("FFplay command " & $insert & ": " & $ffplay_command, @ScriptLineNumber)
endfunc




; Launch FFmpeg and display the output (used for Quick Task and About FFmpeg)..
; Note $STDERR_MERGED for the ffmpeg task..
;
func DoFFmpegCommand($my_args)

    debug("DoFFmpegCommand() $my_args = .." & $my_args, @ScriptLineNumber, 7);debug

    local $ffmpeg_info = Run($ffmpeg_binary & " " & $my_args"", @SW_HIDE, $STDERR_MERGED)
    local $c_out$v_out

    while true
        $c_out = StdOutRead($ffmpeg_info)
        if @error then exitloop
        if $c_out then
            ConsoleAdd($c_out, @ScriptLineNumber)
            $v_out &= $c_out
        endif
        Sleep(10)
    wend

    ProcessClose($ffmpeg_info)
    StdioClose($ffmpeg_info)
    SetConsoleOutput(StringStripWS($v_out, 3), true) ; and scroll to top

endfunc


; Quick Task..
func RunFFmpegQuickTask()
    GUICtrlSetState($check_run_ffmpeg_task$GUI_UNCHECKED)
    $ffmpeg_command = ffeDeTokenizeString(IniRead($ini_path$my_name"ffmpeg_command""-help"))
    DoFFmpegCommand($ffmpeg_command)
endfunc


; Drop command..
;
func PlayIt()
    RunFFplayQuickTask($inputfile)
endfunc


func ClickRunFFplayQuickTask()
    RunFFplayQuickTask()
endfunc


; User clicked the ffplay task button..
;
func RunFFplayQuickTask($command="")

    debug("RunFFplayQuickTask() ", @ScriptLineNumber, 7);debug

    GUICtrlSetState($check_run_ffplay_task$GUI_UNCHECKED)

    ; We expect the ffplay.exe binary to be next to ffmpeg.exe, of course..
    local $ffplay_binary = GetParent($ffmpeg_binary) & "\ffplay.exe"
    if not FileExists($ffplay_binary) then
        ConsoleAdd("ffplay.exe not found! Please place it next to ffmpeg.exe", @ScriptLineNumber)
        return false
    endif

    if $command then
        $ffplay_command = $command
    else
        $ffplay_command = ffeDeTokenizeString(IniRead($ini_path$my_name"ffplay_command""-help"))
    endif

    ConsoleAdd("Running FFplay task: " & $ffplay_binary & " " & $ffplay_command, @ScriptLineNumber)

    $show_ffplay_output = IniReadCheckBoxValue($ini_path$my_name"show_ffplay_output"$OFF)
    if $show_ffplay_output = $ON then
        local $ffplay_run = Run($ffplay_binary & " " & $ffplay_command"", @SW_SHOW, $STDERR_CHILD)
        local $c_out
        while true
            $c_out = StdErrRead($ffplay_run)
            if @error then exitloop
            if $c_out then ConsoleAdd($c_out, @ScriptLineNumber)
            Sleep(10)
        wend
        ProcessClose($ffplay_run)
        StdioClose($ffplay_run)
    else
        Run($ffplay_binary & " " & $ffplay_command)
    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










func _____________JOB_CONTROLS()
endfunc




func EditPostJob()
    if $post_job_commands_file then
        OpenSomething($post_job_commands_file)
        LoadPostCommands()
    endif
endfunc

func EditPreJob()
    if $pre_job_commands_file then
        OpenSomething($pre_job_commands_file)
        LoadPreCommands()
    endif
endfunc



; Load all post-file settings and the post-file command..
;
$get_fresh is set to true during preset load, which is the only time manually
; set controls are replaced.
;
; Inherit these from default preset and current settings..
;
func LoadPostFileSettings($get_fresh=false)
    debug("", @ScriptLineNumber, 6);debug
    debug("LoadPostFileSettings((get_fresh:" & $get_fresh & ") current preset: " & Human($current_preset), @ScriptLineNumber, 8);debug
    if $get_fresh then
        ; We don't want to change this if it's been altered manually..
        $post_file_command = IniRead($ini_path$current_preset"post_file_command"$post_file_command)
        $post_file_command = StringReplace($post_file_command"&quot;", '"')
        $run_post_file_command = IniReadCheckBoxValue($ini_path$current_preset, "
run_post_file_command", $run_post_file_command, true)
    endif
    $post_file_run_style = IniRead($ini_path$current_preset, "
post_file_run_style", $post_file_run_style)
    $post_file_capture = IniReadCheckBoxValue($ini_path$current_preset, "
post_file_capture", $post_file_capture)
    $post_file_show = IniReadCheckBoxValue($ini_path$current_preset, "
post_file_show", $post_file_show)
    debug("
$run_post_file_command" & Human($run_post_file_command), @ScriptLineNumber, 8);debug
    debug("
$post_file_command" & $post_file_command, @ScriptLineNumber, 8);debug
    debug("
$post_file_run_style" & $post_file_run_style, @ScriptLineNumber, 8);debug
    debug("
$post_file_capture" & Human($post_file_capture), @ScriptLineNumber, 8);debug
    debug("
$post_file_show" & Human($post_file_show), @ScriptLineNumber, 8);debug
    return $post_file_command
endfunc



; Pre / Post Commands..
;
; These functions are called whenever there is a change in command file or presets..
;
; Return true if command file loaded successfully. False if not.
;
func LoadPreCommands($get_fresh=false)
    debug("
", @ScriptLineNumber, 6);debug
    debug("
LoadPreCommands(get_fresh:" & $get_fresh & ")...............", @ScriptLineNumber, 5);debug
    if $get_fresh then
        $run_pre_job_commands = IniReadCheckBoxValue($ini_path$current_preset, "
run_pre_job_commands", $run_pre_job_commands)
    endif
    debug("
$run_pre_job_commands" & Human($run_pre_job_commands), @ScriptLineNumber, 8);debug

    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 = ffeDeTokenizeString($tmp_cf)

    debug("
$pre_job_commands_file" & $pre_job_commands_file, @ScriptLineNumber, 8);debug
    if LoadCommandsFile($pre_job_commands_file, "
pre", "run_pre_job_commands", $check_run_pre_job_commands) then
        return true
    endif
    return false
endfunc

func LoadPostCommands($get_fresh=false)
    debug("
", @ScriptLineNumber, 6);debug
    debug("
LoadPostCommands(get_fresh:" & $get_fresh & ").................", @ScriptLineNumber, 5);debug
    if $get_fresh then
        $run_post_job_commands = IniReadCheckBoxValue($ini_path$current_preset, "
run_post_job_commands", $run_post_job_commands)
    endif
    debug("
$run_post_job_commands" & Human($run_post_job_commands), @ScriptLineNumber, 8);debug

    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 = ffeDeTokenizeString($tmp_cf)

    debug("
$post_job_commands_file" & $post_job_commands_file, @ScriptLineNumber, 8);debug
    if LoadCommandsFile($post_job_commands_file, "
post", "run_post_job_commands", $check_run_post_job_commands) then
        return true
    endif
    return false
endfunc


; The master pre-job and post-job command file loader.
;
; Reads the ini value for the file's path, sets the checkboxes to the correct values.
; Enables/disables checkboxes.
;
; Returns true if command file exists, false if not.
;
func LoadCommandsFile(ByRef $commands_file$type$main_switch$control)

    debug("
", @ScriptLineNumber, 6);debug
    debug("
LoadCommandsFile(" & $commands_file & "," & $type  & "," & $main_switch & "," & $control & ")...", @ScriptLineNumber, 5);debug

    local $do_this = Eval($main_switch)
    local $return = false

    if $commands_file then
        $commands_file = SetRelPathToDataDir($commands_file)
    else
        if $do_this = $ON then ConsoleAdd("
No " & $type & "-job commands file specified!", @ScriptLineNumber)
        return
    endif

    ; NOTE: @parent\batch.bat (for example) might not yet exist.
    if FileExists($commands_file) then
        if $do_this = $ON then
            ConsoleAdd($type & "
-job commands file loaded: " & $commands_file, @ScriptLineNumber)
        endif
        $return = true
    else
        if $do_this = $ON then
            ConsoleAdd($type & "
-job commands file not found: " & $commands_file, @ScriptLineNumber)
        endif
    endif

    $batch_commands_timeout = Int(IniRead($ini_path$current_preset, "
batch_commands_timeout", 0))
    debug("
$batch_commands_timeout" & $batch_commands_timeout, @ScriptLineNumber, 8);debug

    $run_commands_with_shell = IniReadCheckBoxValue($ini_path$current_preset, "
run_commands_with_shell", $run_commands_with_shell)
    debug("
$run_commands_with_shell" & Human($run_commands_with_shell), @ScriptLineNumber, 8);debug

    ; Update "create" / "edit" tray menu item..
    MakeTray()
    return $return
endfunc



; Pre-Job command FILE..
func SpecifyPreJobCMDsFile()
    CreateJobCommands($pre_job_commands_file, "
pre-job")
endfunc

; Post-File COMMAND..
func SpecifyPostFileCommand()
    DialogOpen()
    local $user_command = CorzFancyInputBox("
Post-File Command..",    _
        "
Enter the FULL command. Put quotes around any paths with spaces. " & $MSG_LF & _
        "
NOTE: You can drag files into this input. You can also use @tokens.", _
    $post_file_command, "
", @DesktopWidth/2, 115, default, default, 0, $ffeGUI)
    switch @error
        case 1
            ConsoleAdd("
Dialog cancelled. Post-File Command still: '" & $post_file_command & "'.", @ScriptLineNumber)
        case 2
            ConsoleAdd("
Dialog time-out. Post-File Command still: '" & $post_file_command & "'.", @ScriptLineNumber)
        case 0
            $post_file_command = $user_command
            ConsoleAdd("
Post-File Command set to '" & $post_file_command & "'", @ScriptLineNumber)
    endswitch
    DialogClose()
endfunc

; Post-Job command FILE..
func SpecifyPostJobCMDsFile()
    CreateJobCommands($post_job_commands_file, "
post-job")
endfunc



func CreateJobCommands(ByRef $commands_file$type$do_edit=true)

    local $def_input = "
@datadir\" & StringLower($type) & "-commands.bat"
    if $commands_file then $def_input = ffeTokenizeString($commands_file)
    DialogOpen()
    local $user_prc_filename = CorzFancyInputBox( "
Specify A " & $type & " Commands File.. ", _
                        "
Please specify the location of the " & $type & " Commands file.. " & $MSG_LF & _
                        "
NOTE: You can drag files into this input. You can also use @Tokens.", $def_input , "" , @DesktopWidth/2, 115, _
                        default, default, 0, $ffeGUI)
    DialogClose()
    if $user_prc_filename then

        local $real_user_prc_filename = ffeDeTokenizeString($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_dir & "
\" & $real_user_prc_filename
        endif
        $commands_file = $real_user_prc_filename

        if FileExists($real_user_prc_filename) then
            ConsoleAdd("
'" & $commands_file & "' already exists!", @ScriptLineNumber)
        else
            ConsoleAdd("
Creating: """ & $commands_file & '"', @ScriptLineNumber)
            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

endfunc



; User clicked on a (tri-state) job button..

func ClickSetPreJobState()
    $run_pre_job_commands = GUICtrlRead($check_run_pre_job_commands)
    SetPreJobTip()
    if $run_pre_job_commands = $ON then
        ConsoleAdd("Pre-job commands: " & Human($run_pre_job_commands), @ScriptLineNumber)
        if not LoadPreCommands() then
            SpecifyPreJobCMDsFile()
        endif
    endif
endfunc
func SetPreJobTip()
    _GUIToolTip_Destroy($tip_pre_job)
    $tip_pre_job = GUICtrlSetTipOptional($check_run_pre_job_commands$tristate_prejob_tip & _
                                                    Human($run_pre_job_commands), $tristate_prejob_title)
endfunc

func ClickSetPostJobState()
    $run_post_job_commands = GUICtrlRead($check_run_post_job_commands)
    SetPostJobTip()
    if $run_post_job_commands = $ON then
        ConsoleAdd("Post-job commands: " & Human($run_post_job_commands), @ScriptLineNumber)
        if not LoadPostCommands() then
            SpecifyPostJobCMDsFile()
        endif
    endif
endfunc
func SetPostJobTip()
    _GUIToolTip_Destroy($tip_post_job)
    $tip_post_job = GUICtrlSetTipOptional($check_run_post_job_commands$tristate_postjob_tip & _
                                                    Human($run_post_job_commands), $tristate_postjob_title)
endfunc

func ClickSetPostFileState()
    $run_post_file_command = GUICtrlRead($check_run_post_file_command)
    SetPostFileTip()
    if $run_post_file_command = $ON then
        ConsoleAdd("post-file command: " & $post_file_command, @ScriptLineNumber)
        if not LoadPostFileSettings() then
            SpecifyPostFileCommand()
        endif
    endif
endfunc
func SetPostFileTip()
    _GUIToolTip_Destroy($tip_post_file)
    $tip_post_file = GUICtrlSetTipOptional($check_run_post_file_command$tristate_postfile_tip & _
                                                    Human($run_post_file_command), $tristate_postfile_title)
endfunc



func ClickSetOverwrite()
    $overwrite = GUICtrlRead($check_overwrite)
    SetOverwriteTip()
    ConsoleAdd($tristate_overwrite_title & ": " & Human($overwrite), @ScriptLineNumber)
endfunc
func SetOverwriteTip()
    _GUIToolTip_Destroy($tip_overwrite)
    $tip_overwrite = GUICtrlSetTipOptional($check_overwrite$tristate_overwrite_tip & _
                                            Human($overwrite), $tristate_overwrite_title)
endfunc

func ClickSetConcatenateFiles()
    $concatenate = GUICtrlRead($check_concatenate)
    SetConcatenateFilesTip()
    ConsoleAdd($tristate_concatenate_title & ": " & Human($concatenate), @ScriptLineNumber)
endfunc
func SetConcatenateFilesTip()
    _GUIToolTip_Destroy($tip_concatenate)
    $tip_concatenate = GUICtrlSetTipOptional($check_concatenate$tristate_concatenate_tip & _
                                                    Human($concatenate), $tristate_concatenate_title)
endfunc

func ClickSetQuitWhenDone()
    $quit_when_done = GUICtrlRead($check_quit_when_done)
    SetQuitWhenDoneTip()
    ConsoleAdd($tristate_quit_title & ": " & Human($quit_when_done), @ScriptLineNumber)
endfunc
func SetQuitWhenDoneTip()
    _GUIToolTip_Destroy($tip_quit)
    $tip_quit = GUICtrlSetTipOptional($check_quit_when_done$tristate_quit_tip & _
                                                    Human($quit_when_done), $tristate_quit_title)
endfunc

func ClickSetShutdownWhenDone()
    $shutdown_when_done = GUICtrlRead($check_shutdown_when_done)
    SetShutdownWhenDoneTip()
    ConsoleAdd($tristate_quit_title & ": " & Human($shutdown_when_done), @ScriptLineNumber)
endfunc
func SetShutdownWhenDoneTip()
    ShutDownOverrideQuit()
    _GUIToolTip_Destroy($tip_shutdown)
    $tip_shutdown = GUICtrlSetTipOptional($check_shutdown_when_done$tristate_shutdown_tip & _
                                                    Human($shutdown_when_done), $tristate_shutdown_title)
endfunc



; There are easier ways, but none so much FUN!
;
; Run the Pre-Job or Post-Job commands (.bat) file..
;
func RunCommandsFile(ByRef $commands_file, ByRef $logfile, ByRef $gen_file$type)

    debug("", @ScriptLineNumber, 6);debug
    debug("RunCommandsFile(" & $commands_file & "," & $logfile  & "," & $gen_file & "," & $type & ")...", @ScriptLineNumber, 5);debug

    ; We check again before running..
    if $commands_file and FileExists($commands_file) then

        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
                                            ; The AdLib func simply sets $timeout to true
            if $batch_commands_timeout then AdLibRegister("RunCommandsTimeout"$batch_commands_timeout*1000*60)
            debug("$batch_commands_timeout: " & $batch_commands_timeout, @ScriptLineNumber, 8);debug

            $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, @ScriptLineNumber)) & $LOG_LF
                    AdLibUnRegister("RunCommandsTimeout")
                    return false
                endif

                ; Run the .bat file directly.
                ;2do - we could detokenize this before running
                $msg = $LOG_LF & "Running batch file: """ & $commands_file & """.."
                $logfile &= DoLog(ConsoleAdd($msg, @ScriptLineNumber)) & $LOG_LF
                $run_command = @ComSpec & " /c " & ' "' & $commands_file & '" '
                $command_run = Run($run_command"", @SW_HIDE, $STDOUT_CHILD)
                $command_run = Run($run_command"", @SW_HIDE, BitOr($STDERR_CHILD$STDOUT_CHILD))
                $err = false
                while true
                    $console_out = StdErrRead($command_run)
                    $err = @error
                    $console_out = StringStripWS($console_out, 3)
                    if $console_out then
                        $logfile &= DoLog(ConsoleAdd($console_out, @ScriptLineNumber)) & $LOG_LF
                    endif
                    if $err or $timeout then exitloop
                    Sleep(25)
                wend
                if $timeout then ProcessClose($command_run)
                StdioClose($command_run)

            else

                ; ffe will run the commands one-by-one, replacing @tokens along the way.
                local $run_commands_list
                FileReadIntoArray($commands_file$run_commands_list; populates $run_commands_list
                $msg = $LOG_LF & "Running " & StringLower($type) & "-job commands: " & $commands_file
                $logfile &= DoLog(ConsoleAdd($msg, @ScriptLineNumber)) & $LOG_LF

                for $i = 1 to $run_commands_list[0]
                    ; Ignore comments and such..
                    if StringLeft($run_commands_list[$i], 1) = ":" or StringStripWS($run_commands_list[$i], 3) = "" then continueloop

                    $run_command = ffeDeTokenizeString($run_commands_list[$i])
                    $command_run = Run(@ComSpec & " /c " & $run_command"", @SW_HIDE, $STDOUT_CHILD)
                    $command_run = Run(@ComSpec & " /c " & $run_command"", @SW_HIDE, BitOr($STDERR_CHILD$STDOUT_CHILD))
                    $logfile &= DoLog(ConsoleAdd("exec: " & $run_command, @ScriptLineNumber)) & $LOG_LF

                    while true
                        $err = false
                        $console_out = StdErrRead($command_run)
                        $err = @error
                        $console_out = StringStripWS($console_out, 3)
                        if $console_out then
                            $logfile &= DoLog(ConsoleAdd($console_out, @ScriptLineNumber)) & $LOG_LF
                        endif
                        if $err or $timeout then exitloop
                        Sleep(25)
                    wend

                    if $timeout then ProcessClose($command_run)
                    StdioClose($command_run)
                 next

            endif

             AdLibUnRegister("RunCommandsTimeout")
        endif
    else
        $msg = $type & "-Job Commands File NOT FOUND!"
        $logfile &= DoLog(ConsoleAdd($msg, @ScriptLineNumber))
    endif

    return true
endfunc



; Post file command.
; We have a few choices about how to run this..
;
; Return value is fed to DoLog(), so if you "return false", or you get "False" in your log.
;
func RunPostFileCommand()

    debug("", @ScriptLineNumber, 6);debug
    debug("RunPostFileCommand()...", @ScriptLineNumber, 5);debug

    ; Do not get fresh values from ini - use curent values..
    LoadPostFileSettings()

    debug("RunPostFileCommand() " & Human($run_post_file_command), @ScriptLineNumber, 8);debug
    if $run_post_file_command <> $ON then return "" ; do it like this!

    local $job_log$show_flag$dos_add
    local $run_command = StringStripWS(ffeDeTokenizeString(String($post_file_command)), 3)

    if not $run_command then return ""

    debug("RunPostFileCommand() *** run_command: " & $run_command, @ScriptLineNumber, 6);debug

    ; Whether or not to show the program we are running..
    switch $post_file_show
        case $OFF
            $show_flag = @SW_HIDE
        case else
            $show_flag = @SW_SHOW
    endswitch

    ; And how shall we run the program..
    switch $post_file_run_style

        case "shellexecute""shell"
            debug("*** *** *** ShellExecute POST FILE ", @ScriptLineNumber, 7);debug
            ShellExecute($run_command)

        case "dos"
            debug("*** *** *** DOS POST FILE.. ", @ScriptLineNumber, 7);debug
            $dos_add = @ComSpec & ' /c '
            continuecase

        "direct"..
        case else
            debug("*** *** *** DIRECT POST FILE ", @ScriptLineNumber, 7);debug

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

            local $pipe_to = false, $pipe_data = ""

            ; Recognise user redirection in post-file command..
            ; if StringInStr($run_command">") and $post_file_run_style <> "dos" then
            if StringInStr($run_command">") then
                local $run_arr = StringSplit($run_command">")
                if $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, @ScriptLineNumber))
                endif
            endif

            local $msg = "
Running post-file command: " & $run_command
            $job_log &= DoLog(ConsoleAdd($msg & $LOG_LF, @ScriptLineNumber))

            local $err$console_out

            ; Capture the output and feed to console..
            if $post_file_capture = $ON then

                local $command_run = Run($dos_add & $run_command, "
", $show_flag$STDERR_MERGED)

                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, @ScriptLineNumber))
                    endif
                    if $err or $timeout then exitloop
                    Sleep(25)
                wend

                if $timeout then ProcessClose($command_run)
                StdioClose($command_run)

            ; Not waiting around.
            ; Just run the command and move on..
            else
                Run($dos_add & $run_command, "
", $show_flag)
            endif

            ; Write out any user ">" redirection..
            if $pipe_to then FileWrite($pipe_to$pipe_data)
            AdLibUnRegister("
RunCommandsTimeout")

    endswitch

    return $job_log

endfunc





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








func _____________DROP_WINDOW()
endfunc



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

func ShowDropWindow()

    debug("
", @ScriptLineNumber, 6);debug
    debug("
ShowDropWindow()..", @ScriptLineNumber, 6);debug

    $dropwin_visible = true
    $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("
Cannot create png drop window.", @ScriptLineNumber)
            ConsoleAdd("
Location of gdiplus.dll not specified.", @ScriptLineNumber)
            ConsoleAdd("
Vista or windows server 2008 operating system detected.", @ScriptLineNumber)
            ConsoleAdd("
Location of the gdiplus.dll must be manually specified.", @ScriptLineNumber)
            ConsoleAdd("
ffe is searching for a likely candidate. Please wait...", @ScriptLineNumber)
            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..", @ScriptLineNumber)
                IniWrite($ini_path$my_name, "
GDI_dll", $GDI_dll)
                ConsoleAdd("
GDI_dll location set to: " & $GDI_dll, @ScriptLineNumber)
            else
                ; Nah, this won't happen..
                ConsoleAdd("
gdiplus.dll was found but could not be loaded.", @ScriptLineNumber)
                ConsoleAdd("
please look in %windows%\winsxs for one that works! (use F3!).", @ScriptLineNumber)
                ConsoleAdd("
then set the full location inside ffe.ini and give it a whirl!", @ScriptLineNumber)
                $do_drop_window = $OFF
                $dropwin_visible = false
                return
            endif
            _GDIPlus_Shutdown()
        endif
    else
        $GDI_dll = "
gdiplus.dll"
    endif

    debug("
$GDI_dll" & $GDI_dll, @ScriptLineNumber, 7);debug
    debug("
$drop_win_image" & $drop_win_image, @ScriptLineNumber, 6);debug


    if not FileExists($drop_win_image) then
        ConsoleAdd("
ffe could not find specified drop window image: " & $drop_win_image & ".", @ScriptLineNumber)
        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, @ScriptLineNumber)
            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..
    ; Get far-dimensions of multi-monitor setup..
    _GetMonitors()
    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
    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")

    local $dummy_drop_windowi = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "
MenuToggleDropWindow")


    $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")

    local $AppHotKeys[1][2] = [["
{F9}", $dummy_drop_windowi]]
    GUISetAccelerators($AppHotKeys)

    ; 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



; Drop Windows Context menu: current images and 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")

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

    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)


    local $ctxt_menu_transparency = GUICtrlCreateMenu("
Transparency..", $ctxt_the_pic)
    for $i = 0 to 100 step 5
        GUICtrlCreateMenuItem($i & "
%", $ctxt_menu_transparency)
        GUICtrlSetOnEvent(-1, "
MenuSwitchTransparency")
        if $i = $drop_win_transparency then
            GUICtrlSetState(-1, $ON)
        endif
    next

    GUICtrlCreateMenuItem("
", $lab_main_drop)

    $ctxt_toggle_fluid_image_menu = GUICtrlCreateContextMenu($lab_main_drop)
    GUICtrlCreateMenuItem("
Fluid Menu    (follows current image)", $lab_main_drop)
    GUICtrlSetOnEvent(-1, "
MenuToggleFluidMenu")
    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)

    GUICtrlCreateMenuItem("
", $lab_main_drop)

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

    GUICtrlCreateMenuItem("
", $lab_main_drop)

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

endfunc



func ResetAndReturn()
    ConsoleAdd("
Resetting to default image..  [Images\ffe.png]", @ScriptLineNumber)
    IniWrite($ini_path$my_name, "
drop_win_image", "Images\ffe.png")
    ConsoleAdd("
drop_win_image reset to: " & "Images\ffe.png", @ScriptLineNumber)
    $dropwin_visible = false
    _GDIPlus_Shutdown()
    GetDropWinImage()
    return false
endfunc


#cs

    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!

#ce



; 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)
    _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




; Toggled from a menu or accelerator..
func MenuToggleDropWindow()
    if $do_drop_window = $ON then
        CloseDropWindow()
    else
        TrayItemSetState($tray_toggle_drop_window$ON)
        GUICtrlSetState($check_do_drop_window$ON)
        $do_drop_window = $ON
        IniWriteCheckBoxValue($ini_path$my_name, "
do_drop_window", $do_drop_window)
    endif
endfunc

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

; User Toggles Drop Window (or closed directly, see above)..
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(ffeDeTokenizeString(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")
    endif
    if not FileExists(GetParent($drop_win_image)) then
        DirCreate(GetParent($drop_win_image))
        FileInstall("
.\Resources\ffe.png", $drop_win_image, 1)
    endif
    debug("
GetDropWinImage() $drop_win_image" & $drop_win_image, @ScriptLineNumber, 5);debug
    Check4GIFmethod()
endfunc

func GetDropWinImageFolder()
    $drop_win_image_folder = _
        SetRelPathToDataDir(ffeDeTokenizeString(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)
    debug("
GetDropWinImageFolder() $drop_win_image_folder" & $drop_win_image_folder, @ScriptLineNumber, 5);debug
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



; 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

                ; Slight indentation for files cuz you ain't gettin' sortin!
                $item_id = GUICtrlCreateMenuItem("
  " & $item_text$menu_id)
                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 switched transparency from the drop window context menu..
;
func MenuSwitchTransparency()
    local $drop_win_transparency = GUICtrlRead(@GUI_CtrlId, 1)
    CRT($drop_win_transparency, "
%")
    ConsoleAdd("
Switching Transparency To " & $drop_win_transparency & "%", @ScriptLineNumber);debug
    IniWrite($ini_path$my_name, "
drop_win_transparency", $drop_win_transparency)
    GetRealTrans()
    HideDropWindow()
endfunc


; User chose a new image from 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..", @ScriptLineNumber)
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()

endfunc


; Also used when dropping images into drop-window..
;
func SetNewDropWinImage()
    local $write_img_path = $drop_win_image
    if StringInStr($drop_win_image$data_dir & "
\") then
        $write_img_path = StringReplace($drop_win_image$data_dir & "
\", "")
    endif
    $write_img_path = ffeTokenizeString($write_img_path)
    if $write_img_path then
        IniWrite($ini_path$my_name, "
drop_win_image", $write_img_path)
        ConsoleAdd("
drop_win_image set to: " & $write_img_path, @ScriptLineNumber)
    endif
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 stays on top..
func SetDropWinOnTop()
    WinSetOnTop($GUI_DropWindow, "
", $WINDOWS_ONTOP)
endfunc


func MenuChooseFixedImgLoc()
    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.", @ScriptLineNumber)
        else
            ConsoleAdd("
Select image folder aborted: invalid selection.", @ScriptLineNumber)
        endif
        return
    endif
    if FileExists($user_choose_folder) then
        $drop_win_image_folder = $user_choose_folder
        IniWrite($ini_path$my_name, "
drop_win_image_folder", $drop_win_image_folder)
        ConsoleAdd("
Fixed menu image folder set to: " & $drop_win_image_folder, @ScriptLineNumber)
        GetDropWinImageFolder()
        HideDropWindow()
    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




; Converts user 0-100 into real 0-255, also sets "half transparency" for mouse hover
; (normally 50%, but if user transparency is too close to 50%, we make it 100%),
; unless the user has explicitly set the mouseover transparency level.
;
func GetRealTrans()

    $dropwin_trans_real = 255 * (100 - $drop_win_transparency) / 100

    if $drop_win_hover_transparency >= 0 and $drop_win_hover_transparency <= 100 then
        $half_trans =  255 * (100 - $drop_win_hover_transparency) / 100
    else
        $half_trans = 127
        if $drop_win_transparency >= 45 and $drop_win_transparency <= 55 then
            $half_trans = 255
        endif
    endif
endfunc





; Those Lovely Custom Buttons..
func ____________________BUTTONS()
endfunc




; Load custom buttons data from ini..
;
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], $button_delim) then
                local $command_array = StringSplit($custom_buttons_array[$i][1], $button_delim, 1)
                debug_PrintArray($command_array, "
Custom Buttons $command_array:", @ScriptLineNumber, 8);debug
                if $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



; We don't check for enable_custom_buttons in these functions. We may be
; awaiting restart, and these shouldn't be fired if enable_custom_buttons is
; properly set to false (after a restart).


; 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()

    debug("
", @ScriptLineNumber, 6);debug
    debug("
CreateButtonGrid()...", @ScriptLineNumber, 6);debug

    if not IsArray($custom_buttons_array) then return false
    debug_PrintArray($custom_buttons_array, "
$custom_buttons_array:", @ScriptLineNumber, 7);debug

    local $i = 1, $row_num$bmenu
    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

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

        ; x/y start at 0, buttons start at 1 ($i)

        ; No limit here - how wide is your screen?
        for $k = 0 to $row_num

            local $cbutt_left = $grid_x + $buttons_x_shunt + (($custom_buttons_width+$button_spacing-1)*$k)
            local $cbutt_top = $grid_y + $buttons_y_shunt + (($custom_buttons_height+$button_spacing)*$j)

            local $custom_notes = "
"
            $custom_buttons[$i] = GUICtrlCreateButton($custom_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 & "
 ") & ']'

            GUICtrlSetTipOptional(-1, $MSG_LF & $custom_buttons_array[$i][1] & $custom_notes, "
 " & $custom_buttons_array[$i][0] & ":")

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

            if $i = $custom_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()

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

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

    if $custom_buttons_columns then
        LoadCustomButtonData()
        CreateButtonGrid()
    endif
endfunc




func ClickCustomButton()
    DoCustomButtonAction()
endfunc


; Click once to add the code, a second time to remove..
;
; Shift+Click (10) to rename/edit/add buttons..
; Ctrl+Click (11) to add params to input override.
;
func DoCustomButtonAction($edit_only=false, $clicked=@GUI_CtrlId)

    local $do_edit$do_input_args
    if _IsPressed(10) or $edit_only then $do_edit = true
    if _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!", @ScriptLineNumber)
        return
    endif

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

    if $do_edit then
        DialogOpen()
        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)
        DialogClose()
        if not $edit_butt_name then return

        DialogOpen()
        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)
        DialogClose()
        if not $edit_butt_args then return

        DialogOpen()
        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
        DialogClose()

        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>
        ; Ouch!
        ConsoleAdd( ($edit_butt_notes) ? _
            $insert & $edit_butt_name & $LOG_LF  & "arguments: " & $edit_butt_args & $LOG_LF & "notes/tips: " & $edit_butt_notes : _
            $insert & $edit_butt_name & $LOG_LF & "arguments: " & $edit_butt_args, @ScriptLineNumber)
        ; 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 = $button_delim & $edit_butt_notes
        IniWrite($ini_path$NAME_BUTTONS$edit_butt_name$edit_butt_args & $edit_butt_notes)
        $this_command = $edit_butt_args
        ReCreateButtonGrid()
        if $edit_only then return
    endif

    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)

    debug("$current_params: " & $current_params, @ScriptLineNumber, 8);debug
    debug("$this_command: " & $this_command, @ScriptLineNumber, 8);debug

    $this_command = StringStripWS($this_command, 3)

    if $custom_buttons_notes[$clicked_butt] and $button_notes_to_console = $ON then
        ConsoleAdd($LOG_LF & "BUTTON: " & $custom_buttons_array[$clicked_butt][0] & ": " & $custom_buttons_notes[$clicked_butt])
    endif
    AddRemoveParam($current_params$this_command$my_control)

endfunc



; Rename Custom Button..
;
func RenameButton()

    local $custom_buttons_array = IniReadSection($ini_path$NAME_BUTTONS)

    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!", @ScriptLineNumber)
        return
    endif
    DialogOpen()
    local $edit_butt_name = CorzFancyInputBox("Custom Button Name.. ""Specify a new name for this custom button.. ", _
                                                                $custom_buttons_array[$clicked_butt][0] , "" , 300, 94)
    DialogClose()
    ; Case-Sensitive Match - User can change case of button ok..
    if not $edit_butt_name or $edit_butt_name == $custom_buttons_array[$clicked_butt][0] then return

    ; We are about to change this..
    local $old_name = $custom_buttons_array[$clicked_butt][0]
    for $i = 1 to $custom_buttons_array[0][0]
        if $custom_buttons_array[$i][0] == $custom_buttons_array[$clicked_butt][0] then
            $custom_buttons_array[$i][0] = $edit_butt_name
            exitloop
        endif
    next

    if IniWriteSection($ini_path$NAME_BUTTONS$custom_buttons_array) then
        ConsoleAdd("Custom button """ & $old_name & """ renamed to """ & $edit_butt_name & '"', @ScriptLineNumber)
        ReCreateButtonGrid()

        return true
    endif
    ConsoleAdd("
Error renaming button """ & $old_name & """ to """ & $edit_butt_name & '"', @ScriptLineNumber)

endfunc




; Remove a Custom Button..
;
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!", @ScriptLineNumber)
        return
    endif
    local $seen_delete_warning = IniReadCheckBoxValue($ini_path$my_name"warning_seen_butt_delete"$OFF)
    if $seen_delete_warning = $OFF then
        DialogOpen()
        MsgBox($MB_OK,    "This is your only warning!", _
            "ffe isn't some namby-pamby, hold-your-hand baby-app." & $MSG_LF & _
            "It's a program designed for working." & $MSG_LF & $MSG_LF & _
            "When you choose to delete a custom button, it will be deleted." & $MSG_LF & _
            "Gone. Vanished. No auto-backup. No second chance." & $MSG_LF & $MSG_LF & _
            "It's about to happen now, even if you cancel this dialog.", 60, $ffeGUI)
        DialogClose()
        IniWriteCheckBoxValue($ini_path$my_name"warning_seen_butt_delete"$ON)
        ConsoleAdd("User warned about permanent button deletion: Check!", @ScriptLineNumber)
    endif
    if IniDelete($ini_path$NAME_BUTTONS$custom_buttons_array[$clicked_butt][0]) then
        ConsoleAdd("Deleted button: """ & $custom_buttons_array[$clicked_butt][0] & '".', @ScriptLineNumber)
        ReCreateButtonGrid()
    else
        ConsoleAdd("
Error deleting custom button: """ & $custom_buttons_array[$clicked_butt][0] & '".', @ScriptLineNumber)
    endif
endfunc




func SetPresetDefExtension()
    ChooseDefaultExtension(true)
endfunc

func SetDefExtension()
    ChooseDefaultExtension()
endfunc


; Change the default extension..
;
func ChooseDefaultExtension($preset_level=false)

    local $insert$d_add
    local $section = $my_name

    if $preset_level then
        if not $current_preset then
            return ConsoleAdd("No preset currently selected!", @ScriptLineNumber)
        endif
        if $current_preset = $my_name then
            return ConsoleAdd("No preset currently selected! To set the global default extension, use {F2}", @ScriptLineNumber)
        endif
        $section = $current_preset
        $insert &= "(for " & $current_preset & ") "
        $d_add = " (for " & $current_preset & ") "
    endif

    local $current_extension = IniRead($ini_path$current_preset"default_extension"$default_extension)
    debug("Current default_extension for this preset: " & $default_extension, @ScriptLineNumber, 8);debug

    DialogOpen()
    local $edit_default_extension = CorzFancyInputBox("Enter the default extension" & $d_add & ".. ", _
        "You can use any extension you want. No need for the dot (.) here. " & $MSG_LF & _
        "NOTE: Under most circumstances you DO NOT need to alter this. " & $MSG_LF & _
        "File extension mapping is handled internally by ffe. Be Careful!"$default_extension , _
        "" , 440, 128, default, default, 0, $ffeGUI)
    DialogClose()
    CLT($edit_default_extension".")

    ; Need *something*! ..
    if not $edit_default_extension then return

    if $edit_default_extension == $current_extension then
        $insert &= "remains"
    else
        $insert &= "set to"
        $default_extension = $edit_default_extension
        IniWrite($ini_path$section"default_extension"$default_extension)
    endif

    ConsoleAdd("Default extension " & $insert & ": " & $default_extension, @ScriptLineNumber)
endfunc





func AddNotesToPreset()

    if not $current_preset or $current_preset = $EXIT_PRESET then
        return ConsoleAdd("No user preset currently selected!", @ScriptLineNumber)
    endif

    DialogOpen()

    local $previous_event_mode = AutoItSetOption("GUIOnEventMode", 0)
    local $previous_coord_mode = AutoItSetOption("GUICoordMode", 1)

    local $new_notes = false
    local $size_array

    local $min_w = 300
    local $min_h = 100
    local $notes_x = IniRead($ini_path$my_name"notes_x", -1)
    local $notes_y = IniRead($ini_path$my_name"notes_y", -1)
    local $notes_w = IniRead($ini_path$my_name"notes_w", 320)
    local $notes_h = IniRead($ini_path$my_name"notes_h", 150)
    if $notes_w < $min_w then $notes_w = $min_w
    if $notes_h < $min_h then $notes_h = $min_h

    local $old_notes = $preset_notes

    local $notes_styles = BitOr($WS_CAPTION$WS_SIZEBOX$WS_POPUP)
    local $input_styles = BitOr($ES_LEFT$ES_AUTOHSCROLL$ES_MULTILINE$ES_WANTRETURN)
    local $input_exstyles = BitOr($WS_EX_CLIENTEDGE$WS_EX_ACCEPTFILES$WS_EX_TOPMOST)

    local $e_type = "Edit"
    if not $old_notes then $e_type = "Add"
    global $notesGUI = GUICreate($e_type & " notes for " & $current_preset & ".."$notes_w$notes_h$notes_x$notes_y$notes_styles)

    global $notes_input = GUICtrlCreateInput($old_notes, 10, 10, $notes_w-20, $notes_h-45, $input_styles$input_exstyles)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKTOP$GUI_DOCKLEFT$GUI_DOCKRIGHT$GUI_DOCKBOTTOM))
    GUICtrlSetTipOptional(-1 , "These notes will be spat out into your ffe console on preset load" & $MSG_LF & _
                                "and are a handy place to keep information you might need when" & $MSG_LF & _
                                "working with this preset.""Add some notes for this preset.. ")

    local $butt_cancel = GUICtrlCreateButton("Cancel", 10, $notes_h-30, 75, 22)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKLEFT$GUI_DOCKBOTTOM$GUI_DOCKSIZE))

    local $butt_ok = GUICtrlCreateButton("Save"$notes_w-60, $notes_h-30, 50, 22)
    GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKBOTTOM$GUI_DOCKSIZE))

    GUISetState(@SW_SHOW, $notesGUI)
    HotKeySet("{tab}""DoTabChar")

    local $msg
    while true

        $msg = GUIGetMsg()
        switch $msg

            case $GUI_EVENT_RESIZED

                $size_array = WinGetPos($notesGUI)
                if not IsArray($size_array) then continueloop

                local $my_width = $size_array[2]
                if $size_array[2] < $min_w then
                    WinMove($notesGUI"", default, default, $min_w$notes_h)
                    $my_width = $min_w
                endif
                if $size_array[3] <> $notes_h then WinMove($notesGUI"", default, default, $my_width, default)

                local $my_height = $size_array[3]
                if $size_array[3] < $min_h then
                    WinMove($notesGUI"", default, default, default, $min_h)
                    $my_height = $min_h
                endif
                if $size_array[3] <> $notes_h then WinMove($notesGUI"", default, default, default, $my_height)

            case $butt_ok
                $new_notes = GUICtrlRead($notes_input)
                exitloop

            case $GUI_EVENT_CLOSE$butt_cancel
                exitloop
        endswitch
    wend

    if $msg = $butt_ok then
        $size_array = WinGetPos($notesGUI)
        if IsArray($size_array) then
            IniWrite($ini_path$my_name"notes_x"$size_array[0])
            IniWrite($ini_path$my_name"notes_y"$size_array[1])
            IniWrite($ini_path$my_name"notes_w"$size_array[2])
            IniWrite($ini_path$my_name"notes_h"$size_array[3])
        endif
    endif

    AutoItSetOption("GUIOnEventMode"$previous_event_mode)
    AutoItSetOption("GUICoordMode"$previous_coord_mode)
    GUIDelete($notesGUI)


    if $msg = $butt_ok then

        ; Set the global variable..
        debug("$new_notes: " & $new_notes, @ScriptLineNumber, 8);debug
        $preset_notes = $new_notes

        ; Removing notes..
        if $preset_notes = "" then
            IniDelete($ini_path$current_preset"notes")
            ConsoleAdd("Notes removed from " & $current_preset, @ScriptLineNumber)
        else
            ; Adding / Editing notes..
            ConvertNewlines($preset_notes, true)
            debug("$preset_notes: " & $preset_notes, @ScriptLineNumber, 8);debug
            IniWrite($ini_path$current_preset"notes"$preset_notes)
            GetPresetNotes()
            ConsoleAdd("Preset notes for " & $current_preset & ":" & $LOG_LF & $preset_notes, @ScriptLineNumber)
        endif
    endif

    HotKeySet("{tab}")
    DialogClose()

endfunc


func DoTabChar()
    if WinActive($notesGUI) then
        _GUICtrlEdit_ReplaceSel ($notes_input, chr(9), true)
    else
        HotKeySet("{tab}")
        Send("{tab}")
        HotKeySet("{tab}""DoTabChar")
    endif
endfunc



; Add or remove parameters to input/output parameters..
; Used by Custom Buttons and Short Test button.
;
func AddRemoveParam($my_current_params$my_command$control)

    ; If parameters aren't already there, add them..
    if not StringInStr($my_current_params$my_command) then

        ; Remove all leading and trailing spaces..
        $my_current_params = StringStripWS($my_current_params, 3)
        ; If (and only if) there are current parameters, pad with one single leading space..
        if $my_current_params then $my_current_params = PadLeft($my_current_params)
        ; Finally, add our new command to the existing parameters..
        GUICtrlSetData($control$my_current_params & PadLeft($my_command))

    ; Otherwise, remove them..
    else
        ; Remove all leading and trailing spaces from current parameters..
        $my_current_params = StringStripWS($my_current_params, 3)
        ; Remove the supplied command and strip leading/trailing spaces from result..
        local $new_params = StringStripWS(StringReplace($my_current_params$my_command""), 3)
        ; We might have removed from the middle of the arguments, so replace
        ; that double-space then pad the whole lot with a single leading space..
        $new_params = PadLeft(StringReplace($new_params"  "" "))
        GUICtrlSetData($control$new_params)
    endif

endfunc








func _______________MISC_BUTTON()
endfunc

; Clear all the paramater dials and switches back to their defaults..
; Ctrl+Click to also wipe file input/output file paths..
; Shift+Click to ONLY clear the input+output file paths.
func ClickResetEverything()
    if _IsPressed(10) or _IsPressed(11) then
        $inputfile = ""
        $outputfile = ""
        GUICtrlSetData($inp_inputfile$inputfile)
        GUICtrlSetData($inp_outputfile$outputfile)
    endif
    if _IsPressed(10) then return
    WipeSettings()
    DoArgsCreate()
    ResetAlteredControls()
    ConsoleAdd("Dials and Switches to Zero!", @ScriptLineNumber)
endfunc


func WipeSettings()

    debug("WipeSettings(!): ", @ScriptLineNumber, 8);debug

    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_x"")
    GUICtrlSetData($inp_crop_height"")
    GUICtrlSetData($inp_crop_y"")
    GUICtrlSetData($inp_crop_width"")
    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"")

    ; GUICtrlSetSTATE ..
    GUICtrlSetState($check_resize_first$OFF)

    GUICtrlSetState($check_run_pre_job_commands$UNSET)
    GUICtrlSetState($check_run_post_file_command$UNSET)
    GUICtrlSetState($check_run_post_job_commands$UNSET)

    GUICtrlSetState($check_overwrite$UNSET)
    GUICtrlSetState($check_concatenate$UNSET)
    GUICtrlSetState($check_quit_when_done$UNSET)
    GUICtrlSetState($check_shutdown_when_done$UNSET)

endfunc



func ResetAlteredControls()
    $altered_resize_first = false
    $altered_do_matof = false
    $altered_do_output = false
endfunc



func AddShortTestParam()
    if _IsPressed(10) then UserEditShortTestParams()
    AddRemoveParam(GUICtrlRead($inp_extra_args), "-frames:v " & $short_test_frames$inp_extra_args)
endfunc



func UserEditShortTestParams()

    DialogOpen()
    local $user_frames = CorzFancyInputBox("Short Test Frames.. ", _
        "Specify a number of frames for the short test button.. "$short_test_frames , "" , _
                                                        370, 100, 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

        if $short_test_frames <> $user_frames then
            ConsoleAdd("short_test_frames set to: " & $user_frames, @ScriptLineNumber)
            $short_test_frames = $user_frames
            IniWrite($ini_path$my_name"short_test_frames"$short_test_frames)
            _GUIToolTip_Destroy($tip_short_test)
            $tip_short_test = GUICtrlSetTipOptional($butt_quicktest , _
                "Adds parameters to process only the first " & $short_test_frames & " frames of video. " & $MSG_LF & _
                "You can edit this number (right-click the button). ""Add Quick Test Parameters")
        else
            ConsoleAdd("short_test_frames still " & $short_test_frames, @ScriptLineNumber)
        endif
    endif
endfunc




; User altering the cropdetect frames..

func UserEditCropTestFrames($in_crop_frames=default, $save_as_default=false)

    if $in_crop_frames = default then
        $in_crop_frames = Int(IniRead($ini_path$my_name"auto_crop_frames", 24))
    endif

    local $error = 0
    local $dialog_title = "For THIS Test.."
    if $save_as_default then $dialog_title = "Set New Default Number.."

    DialogOpen()
    local $new_auto_crop_frames = CorzFancyInputBox($dialog_title, _
        "Enter the number of frames to interrogate.. "$in_crop_frames"", 350, 95, default, default, 0, $ffeGUI)
    if @error = 0 then
        if $in_crop_frames <> $new_auto_crop_frames then
            $in_crop_frames = $new_auto_crop_frames
            if $save_as_default then
                IniWrite($ini_path$my_name"auto_crop_frames"$in_crop_frames)
                ConsoleAdd($LOG_LF & "AutoCrop default test frames set to: " & $in_crop_frames, true)
            endif
        endif
    else
        $error = 1
    endif

    DialogClose()
    return SetError($error$in_crop_frames)

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




; Controls we disable/show during an FFmpeg job..
;
func DisableRunningControls()
    GUICtrlSetState($butt_doit$GUI_DISABLE)
    GUICtrlSetState($inp_inputfile$GUI_DISABLE)
    GUICtrlSetState($butt_quicktest$GUI_DISABLE)
    GUICtrlSetState($butt_mediareport$GUI_DISABLE)
    ; GUICtrlSetState($butt_reset$GUI_DISABLE)
    ; Nah, they might want to reset before they begin changing settings and
    ; queing up buttons for the next test, while ffmpeg runs.. (yes you can!)
    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)
    TrayItemSetState($tray_about_ffmpeg$TRAY_DISABLE)
endfunc


; Re-enable/hide controls after FFmpeg job..
;
func EnableRunningControls()
    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
    TrayItemSetState($tray_about_ffmpeg$TRAY_ENABLE)
    GUICtrlSetState($edit_console_output$GUI_ENABLE)
endfunc


func ReturnNow($msg="Error"$retval=-1)
    ConsoleAdd($msg, @ScriptLineNumber)
    SetHotKeys()
    $do_drop_window = $drop_win_state
    ShowOutputButts()
    EnableRunningControls()
    SetWinTitleText()
    return $retval
endfunc










;         xxx  xxx           xxx            xxx
;         xxx  xxx           xxx            xxx
;         xxx  xxx           xxx            xxx
;         xxx  xxx           xxx            xxx
;         xxx  xxx   xxxxx   xxx   xxxxxxx  xxx
;         xxx  xxx  xxxxxxx  xxx   xxxxxxx  xxx
;         xxxxxxxx  xxx xxx  xxx   xxx  xx  xxx
;         xxxxxxxx  xxx  xx  xxx   xxx  xxx xxx
;         xxx  xxx  xxx  xx  xxx   xxx  xxx xxx
;         xxx  xxx  xxxxxxx  xxx   xxx  xxx xxx
;         xxx  xxx  xxx      xxx   xxx  xxx xxx
;         xxx  xxx  xxx      xxx   xxx  xxx
;         xxx  xxx  xxx xxx  xxx   xxx xxx
;         xxx  xxx  xxxxxxx  xxxx  xxxxxxx  xxx
;         xxx  xxx   xxxxx    xxx  xxxxxx   xxx
;                                  xxx
;                                  xxx
;                                  xxx
;                                  xxx



func _________________________HELP()
endfunc



; Custom help..
;
func LoadHelpTexts()
    local $default_help = "Main|help.txt|-h,Filters|help-filters.txt|-filters,Encoders|help-encoders.txt|-encoders,Full|help-full.txt|-h full,ffprobe|ffprobe-help.txt|@appdir\ffprobe.exe -h,ffplay|ffplay-help.txt|@appdir\ffplay.exe -h"
    $help_texts = IniRead($ini_path$my_name"help_texts"$default_help)
    $help_texts = StringReplace($help_texts",,"","; in case of erm, user error
    if StringInStr($help_texts"|") then
        $help_texts = StringSplit($help_texts",")
        global $help_butts[$help_texts[0]+1] = [$help_texts[0]]
    else
        $help_texts = ""
    endif
endfunc




; Draw the user's help buttons..
;
func CreateHelpButtons()

    debug("CreateHelpButtons().. ", @ScriptLineNumber, 6);debug

    if not IsArray($help_texts) then return false
    debug_PrintArray($help_texts"$help_texts:", @ScriptLineNumber, 7);debug

    ; A wee array of button IDs for easy editing/removal of buttons..
    global $help_butts_remove[$help_texts[0]+1] = [$help_texts[0]]
    global $help_butts_editme[$help_texts[0]+1] = [$help_texts[0]]

    ; We draw the buttons from right-to-left, so reverse the array first..
    _ArrayReverse($help_texts, 1)


    ; Run through the help buttons array..
    ;
    for $h = 1 to $help_texts[0]

        debug("$help_texts[$h]: " & $help_texts[$h] & ":" & $h, @ScriptLineNumber, 7);debug

        local $help_data = StringSplit($help_texts[$h], "|")
        if $help_data[0] <> 3 then continueloop
        debug_PrintArray($help_data"$help_data:", @ScriptLineNumber, 7);debug

        local $border = 13
        local $help_x = $h*20
        $help_butts[$h] = GUICtrlCreateButton("?"$width-$help_x-$border$buttons_xy, 18, 18, BitOr($WS_TABSTOP,$BS_FLAT))

        GUICtrlSetTipOptional(-1, "Click this button to view the " & _
        $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 "$help_data[1] & " (Command: " & $help_data[3] & ")")

        GUICtrlSetResizing(-1, BitOr($GUI_DOCKRIGHT$GUI_DOCKTOP$GUI_DOCKSIZE))
        GUICtrlSetOnEvent(-1, "HelpMeNow")


        ; Context Menu for help buttons..
        local $menu_help_buttons = GUICtrlCreateContextMenu($help_butts[$h])

            ; Edit a button..
            $help_butts_editme[$h] = GUICtrlCreateMenuItem("Edit this button"$menu_help_buttons)
            GUICtrlSetOnEvent(-1, "EditHelpButton")

            GUICtrlCreateMenuItem(""$menu_help_buttons)

            ; Remove a button..
            $help_butts_remove[$h] = GUICtrlCreateMenuItem("Remove this button"$menu_help_buttons)
            GUICtrlSetOnEvent(-1, "RemoveHelpButton")

            GUICtrlCreateMenuItem(""$menu_help_buttons)

            ; Add a button..
            GUICtrlCreateMenuItem("Add a button"$menu_help_buttons)
            GUICtrlSetOnEvent(-1, "AddHelpButton")

    next

endfunc




; Add a help button.. Top-Notch Idea!
;
func AddHelpButton()

    ; This should never happen..
    if not IsArray($help_texts) then return false
    local $new_help = EnterHelpButtonDetails("CUSTOM""custom." & $report_extension"-help topic", default, default, 0, 6, 6, 11)
    if not $new_help then return false

    _ArrayReverse($help_texts, 1)
    $help_texts = ArrayJoin($help_texts",")
    $help_texts &= "," & $new_help

    IniWrite($ini_path$my_name"help_texts"$help_texts)
    ConsoleAdd("Adding button: " & StringLeft($new_help, StringInStr($new_help"|")-1), @ScriptLineNumber)
    ReCreateGUIHelpButtons()

endfunc


func EditHelpButton()

    ; This should never happen.
    if not IsArray($help_butts_editme) then return false
    ; Again, this should never happen..
    if not IsArray($help_texts) then return false

    local $clicked_butt = InArray($help_butts_editme, @GUI_CtrlId)
    if $clicked_butt < 1 or $clicked_butt > $help_butts_editme[0] then
        ConsoleAdd("Help button out of bounds!", @ScriptLineNumber)
        return
    endif

    local $edit_me = $help_texts[$clicked_butt]
    local $help_data = StringSplit($edit_me"|")
    if $help_data[0] <> 3 then return

    ; So we can select only the basename (minus extension) part, for the user to start typing away..
    local $filename_len = StringLen(CleanName($help_data[2]))
    local $new_details = EnterHelpButtonDetails($help_data[1], $help_data[2], $help_data[3], default, default, 0, $filename_len)
    if not $new_details then return false

    _ArrayReverse($help_texts, 1)
    $help_texts = ArrayJoin($help_texts",")
    $help_texts = StringReplace($help_texts$edit_me$new_details)

    IniWrite($ini_path$my_name"help_texts"$help_texts)
    ConsoleAdd("Edited help button: " & $new_details, @ScriptLineNumber)
    ReCreateGUIHelpButtons()

endfunc



; Three dialogs to return the help button title, file name and command
; already concatenated into the final string..
;
; You can set the text selection start and end points for the three dialogs;
; 0 being the far left side, and -1 being the right. For example, to set the
; selection to the extension part of "file.txt", use 5, -1. By default, the
; entire input text is selected (0,-1).
;
func EnterHelpButtonDetails($title$filename$command$sel1=0, $sel2=-1, $sel3=0, $sel4=-1, $sel5=0, $sel6=-1)

    debug("EnterHelpButtonDetails(title: " & $title & ", filename: " & $filename  & ", command: " & $command & ", sel1: " & $sel1  & ", sel2: " & $sel2  & ", sel3: " & $sel3  & ", sel4: " & $sel4  & ", sel5: " & $sel5  & ", sel6: " & $sel6 & ")...", @ScriptLineNumber, 6);debug

    ; Text selection defaults..
    if $sel1 = default then $sel1 = 0
    if $sel2 = default then $sel2 = -1
    if $sel3 = default then $sel3 = 0
    if $sel4 = default then $sel4 = -1
    if $sel5 = default then $sel5 = 0
    if $sel6 = default then $sel6 = -1

    DialogOpen()
    local $butt_title = CorzFancyInputBox("Help Button Title.. ",    _
        "Specify a title for the help button.. "$title"", 350 , 90, default, default, 0, $ffeGUI, _
                                                                default, default, default, $sel1$sel2)
    DialogClose()
    if not $butt_title then return false

    DialogOpen()
    local $butt_filename = CorzFancyInputBox("Help File Name.. ",    _
        "Specify a file name for this (saved) help.. "$filename"", 350 , 90, default, default, 0, $ffeGUI, _
                                                                    default, default, default, $sel3$sel4)
    DialogClose()
    if not $butt_filename then return false

    DialogOpen()
    local $butt_command = CorzFancyInputBox("FFmpeg Command.. ",    _
        "Specify the FFmpeg command used to output this help file. "$command"", 350 , 90, default, default, 0, $ffeGUI, _
                                                                        default, default, default, $sel5$sel6)
    DialogClose()
    if not $butt_command then return false

    return $butt_title & "|" & $butt_filename & "|" & $butt_command
endfunc






; Remove a help button.. Why Oh Why!
;
func RemoveHelpButton()

    debug("RemoveHelpButton()", @ScriptLineNumber, 7);debug

    ; This should never happen..
    if not IsArray($help_butts_remove) then return false
    debug_PrintArray($help_butts_remove"$help_butts_remove:", @ScriptLineNumber, 7);debug

    local $clicked_butt = InArray($help_butts_remove, @GUI_CtrlId)

    if $clicked_butt < 1 or $clicked_butt > $help_butts_remove[0] then
        ConsoleAdd("Help button out of bounds!", @ScriptLineNumber)
        return
    endif

    local $removed = $help_texts[$clicked_butt]
    _ArrayReverse($help_texts, 1)
    $help_texts = ArrayJoin($help_texts",")
    $help_texts = StringReplace($help_texts$removed"")
    $help_texts = StringReplace($help_texts",,"",")
    CBT($help_texts",")
    debug("$help_texts: " & $help_texts, @ScriptLineNumber, 7);debug

    IniWrite($ini_path$my_name"help_texts"$help_texts)
    ConsoleAdd("Removed help button: " & StringLeft($removed, StringInStr($removed"|")-1), @ScriptLineNumber)
    ReCreateGUIHelpButtons()

endfunc



func ReCreateGUIHelpButtons()
    for $i = 1 to Ubound($help_butts)-1
        GUICtrlDelete($help_butts[$i])
    next
    GUICtrlSetData($lab_help_info"")
    LoadHelpTexts()
    CreateHelpButtons()
endfunc





func HelpMeNow()
    debug("HelpMeNow()...", @ScriptLineNumber, 7);debug

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

    if $clicked_butt < 1 or $clicked_butt > $help_texts[0] then
        ConsoleAdd("ILLEGAL BUTTON ERROR!", @ScriptLineNumber)
        return
    endif

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

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

    if $my_help_entry[0] <> 3 then
        ConsoleAdd("Error: Invalid help button text.", @ScriptLineNumber)
        return
    endif

    $this_helpfile = $my_help_entry[2]
    $this_command = ffeDeTokenizeString($my_help_entry[3])
    debug("$this_command: " & $this_command, @ScriptLineNumber, 7);debug

    local $err$full_log = ""
    local $help_dir = $data_dir & "\Help\"
    if $portable then $help_dir = @ScriptDir & "\Help\"
    if not FileExists($help_dir) then DirCreate($help_dir)
    local $nfo_loc = $help_dir & $this_helpfile
    debug("$nfo_loc: " & $nfo_loc, @ScriptLineNumber, 7);debug

    ; 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 & $this_command) or not FileExists($nfo_loc) then
        debug("Creating FRESH help file: " & $nfo_loc, @ScriptLineNumber, 7);debug

        ; Fall-back to ffmpeg help output..
        if not StringInStr($this_command":\") then
            $this_command = $ffmpeg_binary & " " & $this_command
        endif
        debug("$this_command: " & $this_command, @ScriptLineNumber, 7);debug

        ; Run FFmpeg with help flags (capture stdout only - not merged, which would mess up the help)..
        local $gethelp = Run($this_command"", @SW_HIDE, $STDOUT_CHILD)
        debug("$gethelp: " & $gethelp, @ScriptLineNumber, 8);debug

        while true
            $err = false
            $console_out = StdOutRead($gethelp)
            $err = @error
            if $console_out then $full_log &= $console_out
            if $err then exitloop
            Sleep(25)
        wend

        ; Just in case..
        StdioClose($gethelp)

        ; Write out help text to a 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 & $this_command) then $got_helps &= $this_helpfile & $this_command & "|"

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

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

endfunc





; AppMenu..
;
; I LOVE this thing!
; Get to it like this (any method works)..
;
; Alt+Space
; Click App Icon (top-left of window)
; Right-Click app's title bar
;

func __________APP_MENU_FUNCS()
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]
            SetffmpegCPUPriority($nID)

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

        case $am_post_file_capture
            MenuTogglePostFileCapture()

        case $am_post_file_show
            MenuTogglePostFileShow()

        case $PostFileRunStylesMenuItems[0] to $PostFileRunStylesMenuItems[2]
            SetPostFileRunStyle($nID)

        case $am_save_reports
            MenuToggleSaveReports()

        case $am_use_mediainfo
            MenuSetUseMediaInfo()

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

        case $am_launch_with_drop_command
            SetLaunchDropCommand()

        case $am_about
            DoAboutBox()

        case $am_about_ffmpeg
            DoAboutFFmpeg()

        case $am_retain_exit_settings
            MenuRetainExitSettings()

        case $am_auto_codecs
            MenuToggleAutoCodecs()

        case $am_allow_multiple
            MenuToggleAllowMultiple()

        case $am_pause_is_global
            TogglePauseIsGlobal()

        case $am_kill_ffmpeg_on_exit
            ToggleKillffmpegOnExit()

        case $am_start_minimized
            MenuToggleStartMin()

        case $am_always_warn_on_delete
            SetWarnOnDelete()

        case $am_delete_to_recycle_bin
            SetDeleteToRecycleBin()

        case $am_default_extension
            SetDefExtension()

        case $am_show_ffplay_output
            ToggleShowFFplayOut()

        case $am_do_countdown_timer
            ToggleDoCountdown()

        case $am_always_on_top
            MenuToggleOnTop()

        case $am_console_wordwrap
            MenuToggleWrapConsole()

        case $am_allow_output_tooltip
            MenuToggleConsoleTips()

        case $am_log_each_job
            MenuToggleLogEachJob()

        case $am_log_append
            ToggleLogAppend()

        case $am_job_log_append
            ToggleJobLogAppend()

        case $am_do_tooltips
            MenuToggleToolTipHelp()

        case $am_time_in_title
            MenuToggleTimeInTitle()

        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_button_notes_to_console
            MenuToggleNotesInConsole()

        case $am_enable_custom_buttons
            MenuToggleCustomButtons()
            if $enable_custom_buttons = $OFF then
                ConsoleAdd("Custom button disabled. Restart required.", @ScriptLineNumber)
            else
                ConsoleAdd("Custom button enabled.", @ScriptLineNumber)
                LoadCustomButtonData()
                ReCreateButtonGrid()
            endif
    endswitch
endfunc





; Generic AppMenu toggling function (for booleans).
; This makes it trivial to add new menu items.

func ToggleAppMenuItem(ByRef $setting$menu_item$ini_name$report=true, $restart=false, $orig_setting=-1, $menu_text="")
    local $app_menu = GetSystemMenu($ffeGUI, 0)
    if $setting = $OFF then
        $setting = $ON
        CheckMenuItem($app_menu$menu_item$MF_CHECKED)
        if $report then ConsoleAdd($ini_name & ": enabled", @ScriptLineNumber)
    else
        $setting = $OFF
        CheckMenuItem($app_menu$menu_item$MF_UNCHECKED)
        if $report then ConsoleAdd($ini_name & ": disabled", @ScriptLineNumber)
    endif

    local $pend_add = ")"
    if $restart and $menu_text then
        if $setting <> $orig_setting then $pend_add = " Pending)"
        _GUICtrlMenu_SetItemText($app_menu$menu_item$menu_text & $pend_add, false)
    endif

    IniWriteCheckBoxValue($ini_path$my_name$ini_name$setting)

    return $pend_add
endfunc



func MenuToggleSortPresets()
    local $pend_add = ")"
    $pend_add = ToggleAppMenuItem($sort_presets_list$am_sort_presets_list"sort_presets_list", _
                                    false, true, $sort_presets_list_orig$sort_presets_list_texts)
    GUICtrlSetState($ctxt_combo_sort$sort_presets_list)
    GUICtrlSetData($ctxt_combo_sort$sort_presets_list_texts & $pend_add)
    ConsoleAdd("Preset List Sorting: " & Human($sort_presets_list) & " (restart to see changes)", @ScriptLineNumber)
endfunc



; global AppMenu items..

func MenuToggleLogEachJob()
    ToggleAppMenuItem($log_each_job$am_log_each_job"log_each_job", false)
    ConsoleAdd("Preset list sorting: " & Human($sort_presets_list) & " (restart to see changes)", @ScriptLineNumber)
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")
    if $retain_exit_settings = $ON and not $loaded_exit_settings and PresetExists($EXIT_PRESET) then
        local $ldset = MsgBox($MB_OKCANCEL"Load Previous Exit Settings?""Do you wish to load the saved exit settings?")
        if $ldset = $IDOK then
            debug("Loading preset : " & $EXIT_PRESET, @ScriptLineNumber, 4);debug
            $preset_loaded = LoadPreset($EXIT_PRESET)
        endif
    endif
endfunc


func MenuToggleAutoCodecs()
    ToggleAppMenuItem($auto_codecs$am_auto_codecs"auto_codecs")
    UpdateCodecCombos()
endfunc

func UpdateCodecCombos()
    local $current_vcodec = GUICtrlread($combo_v_codec)
    local $current_acodec = GUICtrlread($combo_a_codec)
    GUICtrlSetData($combo_v_codec"")
    GUICtrlSetData($combo_a_codec"")
    GetUserCodecs()
    GUICtrlSetData($combo_v_codec$video_codecs)
    GUICtrlSetData($combo_a_codec$audio_codecs)
    GUICtrlSetData($combo_v_codec$current_vcodec)
    GUICtrlSetData($combo_a_codec$current_acodec)
    CreateCodecContexts()
endfunc



func SetLaunchDropCommand()
    ToggleAppMenuItem($launch_with_drop_command$am_launch_with_drop_command"launch_with_drop_command")
endfunc


func MenuToggleImgButts()
    ToggleAppMenuItem($image_buttons$am_image_buttons"image_buttons", false, true, $image_buttons_orig$image_buttons_text)
    ConsoleAdd("Images On (some) Buttons: " & Human($image_buttons) & " (restart to see changes)", @ScriptLineNumber)
endfunc


func MenuToggleToolTipHelp()
    ToggleAppMenuItem($do_tooltips$am_do_tooltips"do_tooltips", false, true, $do_tooltips_orig$do_tooltips_text)
    ConsoleAdd("Help(ful) ToolTips: " & Human($do_tooltips) & " (restart to see changes)", @ScriptLineNumber)
endfunc


func MenuToggleConsoleTips()
    ToggleAppMenuItem($allow_console_tooltip$am_allow_output_tooltip"allow_console_tooltip", false, true, $allow_console_tooltip_orig$allow_console_tooltip_text)
    ConsoleAdd("Console ToolTips: " & Human($allow_console_tooltip) & " (restart to see changes)", @ScriptLineNumber)
endfunc


func MenuToggleWrapConsole()
    ToggleAppMenuItem($console_wordwrap$am_console_wordwrap"console_wordwrap", false, true, $console_wordwrap_orig$console_wordwrap_text)
    ConsoleAdd("Console Wordwrap: " & Human($console_wordwrap) & " (restart to see changes)", @ScriptLineNumber)
endfunc


func MenuToggleCustomButtons()
    ToggleAppMenuItem($enable_custom_buttons$am_enable_custom_buttons"enable_custom_buttons")
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


func MenuToggleTimeInTitle()
    ToggleAppMenuItem($time_in_title$am_time_in_title"time_in_title")
    if $time_in_title = $OFF then SetWinTitleText($title_msg_string)
endfunc


func MenuToggleAllowMultiple()
    ToggleAppMenuItem($allow_multiple$am_allow_multiple"allow_multiple")
endfunc


func ToggleDoCountdown()
    ToggleAppMenuItem($do_countdown_timer$am_do_countdown_timer"do_countdown_timer")
endfunc


func ToggleKillffmpegOnExit()
    ToggleAppMenuItem($kill_ffmpeg_on_exit$am_kill_ffmpeg_on_exit"kill_ffmpeg_on_exit")
endfunc

func TogglePauseIsGlobal()
    ToggleAppMenuItem($pause_is_global$am_pause_is_global"pause_is_global")
endfunc


func SetWarnOnDelete()
    ToggleAppMenuItem($always_warn_on_delete$am_always_warn_on_delete"always_warn_on_delete")
endfunc


func SetDeleteToRecycleBin()
    ToggleAppMenuItem($delete_to_recycle_bin$am_delete_to_recycle_bin"delete_to_recycle_bin")
    if $delete_to_recycle_bin = $OFF then
        IniWriteCheckBoxValue($ini_path$my_name"warning_seen_output_delete"$OFF)
        ConsoleAdd("Re-enabled one-time warning about permanent deletion. ", @ScriptLineNumber)
    endif
endfunc

func MenuToggleStartMin()
    ToggleAppMenuItem($start_minimized$am_start_minimized"start_minimized")
endfunc


func ToggleShowFFplayOut()
    ToggleAppMenuItem($show_ffplay_output$am_show_ffplay_output"show_ffplay_output")
endfunc



func MenuTogglePostFileCapture()
    ToggleAppMenuItem($post_file_capture$am_post_file_capture"post_file_capture")
endfunc

func MenuTogglePostFileShow()
    ToggleAppMenuItem($post_file_show$am_post_file_show"post_file_show")
endfunc


func MenuToggleNotesInConsole()
    ToggleAppMenuItem($button_notes_to_console$am_button_notes_to_console"button_notes_to_console")
endfunc


func MenuToggleSaveReports()
    ToggleAppMenuItem($save_reports$am_save_reports"save_reports")
endfunc

func MenuSetUseMediaInfo()
    TogglePref($use_mediainfo)
    IniWriteCheckBoxValue($ini_path$my_name"use_mediainfo"$use_mediainfo)
    ConsoleAdd("MediaInfo reporting set to: " & Human($use_mediainfo), @ScriptLineNumber)
    SetUseMediaInfo()
endfunc


func SetUseMediaInfo()
    local $app_menu = GetSystemMenu($ffeGUI, 0)
    if not FileExists($mediainfo_location) then
        ConsoleAdd("MediaInfo.exe not found! Locating..", @ScriptLineNumber)
        LocateMediaInfo()
        if not FileExists($mediainfo_location) then
            AppMenuItemSetState($app_menu$am_use_mediainfo$OFF)
            $use_mediainfo = $OFF
            IniWriteCheckBoxValue($ini_path$my_name"use_mediainfo"$use_mediainfo)
        endif
    endif
    if $use_mediainfo = $ON then
        CheckMenuItem($app_menu$am_use_mediainfo$ON)
        CheckMenuItem($app_menu$nRTChecked$MF_UNCHECKED)
        $store_probe_type = $nRTChecked
        $nRTChecked = ""
    else
        CheckMenuItem($app_menu$am_use_mediainfo$OFF)
        CheckMenuItem($app_menu$store_probe_type$ON)
        ConsoleAdd("ffprobe reporting enabled.", @ScriptLineNumber)
        ConsoleAdd("ffprobe format: " & $report_format, @ScriptLineNumber)
    endif
endfunc




; Non-Toggling AppMenu commands..

func SetPostFileRunStyle($nID)
    debug("SetPostFileRunStyle(nID:" & $nID & ")...", @ScriptLineNumber, 5);debug

    local $app_menu = GetSystemMenu($ffeGUI, 0)

    for $i = 0 to 2
        if $PostFileRunStylesMenuItems[$i] = $nID then exitloop
    next

    $post_file_run_style = $PostFileRunStyles[$i]
    if $pfsChecked <> $nID then CheckMenuItem($app_menu$pfsChecked$MF_UNCHECKED)
    CheckMenuItem($app_menu$nID$MF_CHECKED)
    IniWrite($ini_path$my_name"post_file_run_style"$post_file_run_style)
    $pfsChecked = $nID
    ConsoleAdd("Post-File Run Style set to: " & $post_file_run_style, @ScriptLineNumber)
endfunc



; 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 $app_menu.
    local $app_menu = 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($app_menu$nTPChecked$MF_UNCHECKED)
    CheckMenuItem($app_menu$nID$MF_CHECKED)
    IniWrite($ini_path$my_name"transparency"$user_trans)
    $nTPChecked = $nID
    ConsoleAdd("Transparency set to: " & $user_trans & "%", @ScriptLineNumber)
endfunc


; Set FFmpeg process priority..

func SetffmpegCPUPriority($nID)
    local $app_menu = 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($app_menu$nCPUChecked$MF_UNCHECKED)
    CheckMenuItem($app_menu$nID$MF_CHECKED)
    IniWrite($ini_path$my_name"cpu_priority"$cpu_priority)
    $nCPUChecked = $nID
    ConsoleAdd("FFmpeg process priority: " & $cpu_priority & " (" & $arCPU[$i] & ")", @ScriptLineNumber)
endfunc





; Set the type of reporting ffprobe does..

func SetFFprobeFormat($nID)
    local $app_menu = 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($app_menu$nRTChecked$MF_UNCHECKED)
    if $store_probe_type <> $nID then CheckMenuItem($app_menu$store_probe_type$MF_UNCHECKED)
    CheckMenuItem($app_menu$nID$MF_CHECKED)
    CheckMenuItem($app_menu$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", @ScriptLineNumber)
    $nRTChecked = $nID
    ConsoleAdd("ffprobe format: " & $report_format, @ScriptLineNumber)
endfunc


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

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

    if $nDCChecked <> $nID then CheckMenuItem($app_menu$nDCChecked$MF_UNCHECKED)
    CheckMenuItem($app_menu$nID$MF_CHECKED)
    IniWrite($ini_path$my_name"drop_command"$drop_command)
    $nDCChecked = $nID
    ConsoleAdd("Drag-and-drop command set to: " & $drop_command, @ScriptLineNumber)
endfunc


; Set the number of custom button columns (from app menu - updates live)..
;
func SetCustomButtonColumns($nID)
    local $app_menu = 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($app_menu$CBMChecked$MF_UNCHECKED)
    CheckMenuItem($app_menu$nID$MF_CHECKED)
    IniWrite($ini_path$my_name"custom_buttons_columns"$custom_buttons_columns)
    $CBMChecked = $nID
    ReCreateButtonGrid()
endfunc







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

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


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


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

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

    if $app_menu = -1 then $app_menu = 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($app_menu$nPos$nFlags$nID$sText)
    return $nID
endfunc

func CheckMenuItem($app_menu$nID$nFlags)
    ; So we can pass values directly from "checkboxe boolean" values..
    if $nFlags = $ON then $nFlags = $MF_CHECKED
    if $nFlags = $OFF then $nFlags = $MF_UNCHECKED
    DllCall("user32.dll",    "int""CheckMenuItem", _
                            "hwnd"$app_menu, _
                            "int"$nID, _
                            "int"$nFlags)
endfunc


func AppMenuItemSetState($app_menu$nID$state=$ON)
    if $state = $ON then
        ; Enabled
        $state = 0x0
    else
        ; Disabled (greyed)
        $state = 0x00000002
    endif
    DllCall("user32.dll",    "int""EnableMenuItem", _
                            "hwnd"$app_menu, _
                            "int"$nID, _
                            "int"$state)
endfunc








func _____________OTHER_TOGGLES()
endfunc





; Other global Toggles..


; Toggle Main Window...
func ToggleWindow()
    if $minimized = $OFF then
        $minimized = $ON
        UnSetHotKeys()
        GUISetState(@SW_HIDE, $ffeGUI)
        if $do_drop_window = $ON then GUISetState(@SW_SHOW, $GUI_DropWindow)
    else
        $minimized = $OFF
        GUISetState(@SW_SHOW, $ffeGUI)
        TrayItemSetState($tray_toggle_start_minimized$TRAY_ENABLE)
        SetHotKeys()
    endif
    IniWriteCheckBoxValue($ini_path$my_name"minimized"$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)
    ConsoleAdd("maximized: " &  Human($maximized), @ScriptLineNumber)
endfunc


; Replace or add parameters from presets..
func TogglePresetMode()
    $replace_mode = GUICtrlRead($radio_preset_replace)
    IniWriteCheckBoxValue($ini_path$my_name"replace_mode"$replace_mode)
    ConsoleAdd("replace_mode: " &  Human($replace_mode), @ScriptLineNumber)
endfunc

func ToggleStorePaths()
    $store_filepaths = GUICtrlRead($check_store_filepaths)
    IniWriteCheckBoxValue($ini_path$my_name"store_filepaths"$store_filepaths)
    ConsoleAdd("store_filepaths: " &  Human($store_filepaths), @ScriptLineNumber)
endfunc





; Other preset-level toggles..

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


func ClickToggleMatofStatus()
    $altered_do_matof = true
    ToggleMatofStatus()
endfunc

; Toggle MATOF..
; This can be set inside DoArgsCreate, hence the loop-preventing flag.            go(Simple Test)
func ToggleMatofStatus($new_args=true)

    TogglePref($do_matof)
    IniWriteCheckBoxValue($ini_path$my_name"do_matof"$do_matof)
    ConsoleAdd("MATOF Status set to: " & Human($do_matof), @ScriptLineNumber)

    ; In case called from inside batch (not clicked)
    GUICtrlSetState($check_do_matof$do_matof)
    debug("$ini_outputfile: " & $ini_outputfile, @ScriptLineNumber, 8);debug

    if $do_matof = $ON then $ini_outputfile = ""

    if $ini_outputfile then
        GUICtrlSetData($inp_outputfile$ini_outputfile)
    else
        GUICtrlSetData($inp_outputfile, ffeDeTokenizeString(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






func _____________________HOTKEYS()
endfunc

; HotKeys.

; ^ = Ctrl
; + = Shift

; Also used, set elsewhere..

;    {SCROLLLOCK}    (when FFmpeg is running)
;    {PAUSE}            (when FFmpeg is running)
;    ^q                (when FFmpeg is running)
;    n                (temporarily, when an FFmpeg response is required)
;    y                (temporarily, when an FFmpeg response is required)


func SetHotKeys()
    HotKeySet("{TAB}""TabToCreateArgs")
endfunc


func UnSetHotKeys()
    HotKeySet("{TAB}")
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




; 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
        local $ret = StdinWrite($ffmpeg"y" & $LOG_LF)
        debug("StdInWrite returned: " & $ret, @ScriptLineNumber, 6);debug
        SetWinTitleText($title_msg_string)
    else
        HotKeySet("y")
        Send("y")
        HotKeySet("y""HK_FFmpegResponseYes")
    endif
endfunc

func HK_FFmpegResponseNo()
    if WinActive($ffeGUI) then
        local $ret = StdinWrite($ffmpeg"n" & $LOG_LF)
        debug("StdInWrite returned: " & $ret, @ScriptLineNumber, 6);debug
        SetWinTitleText($title_msg_string)
    else
        HotKeySet("n")
        Send("n")
        HotKeySet("n""HK_FFmpegResponseNo")
    endif
endfunc


; Suspend/Resume console output during a job..
;
func PauseOutPut()
    if WinActive($ffeGUI) then
        if $output_paused then
            $output_paused = false
            GUICtrlSetState($edit_console_output$GUI_ENABLE)
            GUICtrlSetState($edit_console_output$GUI_FOCUS)
        else
            $output_paused = true
            GUICtrlSetState($edit_console_output$GUI_DISABLE)
        endif
    else
        HotKeySet("!c")
        Send("!c")
        HotKeySet("!c""PauseOutPut")
    endif
endfunc



; Send an abort command to the running console application (FFmpeg)..

func HK_FFmpegAbort()
    if WinActive($ffeGUI) then
        debug("sending 'q' to FFmpeg..", @ScriptLineNumber, 7);debug
        local $siw = StdInWrite($ffmpeg"q")
        debug("wrote " & $siw & " characters to StdIn.", @ScriptLineNumber, 7);debug
        Sleep(250)
        ProcessClose($ffmpeg)
        ConsoleAdd("User aborted.", @ScriptLineNumber)
        DoLog($LOG_LF & "user sent abort command!" & $LOG_LF & $LOG_LF)
    else
        HotKeySet("^q")
        Send("^q")
        HotKeySet("^q""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) or $pause_is_global = $ON then
        if $paused then
            $paused = false
            ProcessSuspendResume($ffmpeg, false)
            SetWinTitleText($title_msg_string)
        else
            $paused = true
            ProcessSuspendResume($ffmpeg)
            SetWinTitleText($title_msg_string & " (Paused)")
        endif
    else
        HotKeySet("{SCROLLLOCK}")
        Send("{SCROLLLOCK}")
        HotKeySet("{SCROLLLOCK}""HK_ProcessPauseSuspend")
    endif
endfunc


; Ctrl+R during FFmpeg run
func HK_ToggleTitleTime()
    if WinActive($ffeGUI) then
        MenuToggleTimeInTitle()
    else
        HotKeySet("^r")
        Send("^r")
        HotKeySet("^r""HK_ToggleTitleTime")
    endif
endfunc








func _________________________FIND()
endfunc

; Find..


func HKFindInOutput()
    FindInOutput(false)
endfunc

func HKFindReplaceInOutput()
    FindInOutput(true)
endfunc

func Butt_FindInOutput()
    ; Shift Key down (replace)..
    if _IsPressed(10) then
        FindInOutput(true)
    else
        FindInOutput(false)
    endif
endfunc

func FindInOutput($use_replace=false)
    local $con_txt = GUICtrlRead($edit_console_output)
    if $con_txt then
        local $previous_event_mode = AutoItSetOption("GUIOnEventMode", 0)
        if $use_replace then
            _GUICtrlCustomEdit_Find($edit_console_output, 1) ; test replace
        else
            _GUICtrlCustomEdit_Find($edit_console_output)
        endif
        AutoItSetOption("GUIOnEventMode"$previous_event_mode)
    else
        SetWinTitleText("                *** The console is empty. Use the force. ***")
        AdLibRegister("ResetTitle", 3000)
    endif
endfunc






func _______________STRING_FUNCS()
endfunc





; The usual error checking has been omitted here - let the user

func ffeDeTokenizeString($string)

    if not $string then return $string
    if not StringInStr($string"@") then return $string
    $string = FixPathSlashes($string)

    ; Dynamic @tokens..
    $string = StringReplace($string"@inputfile"$inputfile)
    $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_dir)
    $string = StringReplace($string"@outdir", GetParent($outputfile))
    $string = StringReplace($string"@parent", GetParent($inputfile))
    $string = StringReplace($string"@appdir", @ScriptDir)

    $string = StringReplace($string"@homedir", @HomeDrive & @HomePath)
    $string = StringReplace($string"@programfiles", @ProgramFilesDir)
    $string = StringReplace($string"@outputfile"$outputfile)

    $string = StringReplace($string"@arguments"$extra_args)
    $string = StringReplace($string"@params"$x_param)


    return $string
endfunc



func ffeTokenizeString($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_dir <> "" then $string = StringReplace($string$data_dir"@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")
    $string = StringReplace($string, @ScriptDir, "@appdir")
    return $string
endfunc




func CtrlASelectAllText()
    GUICtrlSelectAllText($current_control_focus)
endfunc


; Select all the text in a control, usually edit or input controls..
; Pass the ID of the control..
func GUICtrlSelectAllText($control)
    DllCall('user32.dll', 'long', 'SendMessage',    'hwnd', GUICtrlGetHandle($control), _
                                                    'uint', $EM_SETSEL, _
                                                    'int', 0, _
                                                    'int', -1)
endfunc




func ResetTitle()
    SetWinTitleText()
    AdLibUnRegister("ResetTitle")
endfunc


func SetWinTitleText($extra="")
    WinSetTitle($ffeGUI""$my_title & $extra)
endfunc






func ___________FILES_AND_PATHS()
endfunc






; Update the user's existing ini with any new prefs..
;
func UpdateffeIniFile()

    debug("UpdateIniFile()..", @ScriptLineNumber, 7);debug

    if FileGetSize($ini_path) < 1 then
        FileInstall(".\Resources\ffe.ini"$ini_path, 1)
        return
    endif

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

    debug("Checking versions: old version: " & $old_version & " my version: " & $my_version, @ScriptLineNumber, 7);debug
    local $vcomp = _VersionCompare($my_version$old_version)

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

    debug("Updating INI FILE: " & $ini_path & "from: v" & $old_version & " to: v" & $my_version, @ScriptLineNumber, 7);debug

    local $sample_custom_butts$sample_vmappings$sample_amappings

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

    ; Delete all non-application prefs from the new (temp) ini
    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])
        endif

        if $existing_sections[$a] = $NAME_VIDEO_MAPPINGS then
            $sample_vmappings = IniReadSection($tmp_ini$existing_sections[$a])
        endif
        if $existing_sections[$a] = $NAME_AUDIO_MAPPINGS then
            $sample_amappings = IniReadSection($tmp_ini$existing_sections[$a])
        endif

        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

    ; 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

    if not InArray($existing_sections$NAME_VIDEO_MAPPINGS) then
        IniWriteSection($tmp_ini$NAME_VIDEO_MAPPINGS$sample_vmappings)
    endif
    if not InArray($existing_sections$NAME_AUDIO_MAPPINGS) then
        IniWriteSection($tmp_ini$NAME_AUDIO_MAPPINGS$sample_amappings)
    endif

    local $backup_dir = GetParent($ini_path) & "\Backup"
    if not FileExists($backup_dir) then DirCreate($backup_dir)

    ; Rename their existing ffe.ini to "[@date] ffe.ini"
    FileMove($ini_path$backup_dir & "\[" & FileDateStamp() & "][v " & $old_version & "] 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





; Remove all comments from the user's ini file. This will take the standard ffe
; ini from around 41KB to around 7KB. If your ini file grows to more than 60KB
; in size, this happens automatically, to prevent losing actual data.
;
"The maximum supported size of an INI file is 64KB.
;  The maximum size of an individual INI section is 32KB"

;
; If this becomes an issue for anyone; let me know.
; I'll write my own ini functions.
;
func CleanIniComments()
    if $clean_comments = $ON then
        debug("Removing comments from: " & $ini_path, @ScriptLineNumber, 7);debug
        local $file_array
        if FileReadIntoArray($ini_path$file_array) then
            local $new_array[1] = [0]
            for $i = 1 to $file_array[0]
                local $line = StringStripWS($file_array[$i], 3)
                if StringLeft($line, 1) <> ";" then
                    if $line then ArrayAdd($new_array$line)
                endif
            next
            local $file_handle = Fileopen($ini_path$FO_UTF8_NOBOM+$FO_OVERWRITE)
            if $file_handle <> -1 then
                _FileWriteFromArray($file_handle$new_array, 1)
                FileClose($file_handle)
            endif
        endif
    endif
endfunc





; ffprobe/MediaInfo media reporting..

func GenerateReport()

    debug("GenerateReport()", @ScriptLineNumber, 5);debug

    ; SHIFT+Click to open in viewer/editor (grab this modifier NOW)..
    local $shift_open = false
    if _IsPressed(10) then $shift_open = true

    if IsWild($inputfile) then
        ConsoleAdd("Cannot report on directories or multiple files!", @ScriptLineNumber)
        return false
    endif

    if not GetReportingValues() then return false

    if $save_reports = $ON then
        if not FileExists($report_directory) then $report_directory = GetParent($inputfile)
        local $report_loc = $report_directory & "\" & Basename(RemoveExtension($inputfile)) & "." & $report_extension
        debug("$report_loc: " & $report_loc, @ScriptLineNumber, 5);debug
    endif

    local $report_str$err$probe_file$sw = ""

    if $use_mediainfo = $ON and FileExists($mediainfo_location) then
        ConsoleAdd("Running MediaInfo Command-Line: " & $mediainfo_location & $sw & ' "' & $inputfile & '".', @ScriptLineNumber)
        if $mediainfo_switches then $sw = ' ' & $mediainfo_switches & " "
        $probe_file = Run('"' & $mediainfo_location & '"' & $sw & ' "' & $inputfile & '"', "", @SW_HIDE, $STDERR_MERGED)
    else
        ; Run ffprobe (capturing stdout)..
        ConsoleAdd("Running ffprobe Command-Line: " & $ffprobe_loc & _
            " -v error -show_format -show_streams -print_format " & $report_format & $sw & ' "'& $inputfile & '".', @ScriptLineNumber)
        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, $STDERR_MERGED)
    endif

    debug("$probe_file: " & $probe_file, @ScriptLineNumber, 5);debug
    $err = false
    while true
        local $console_out = StdOutRead($probe_file)
        $err = @error
        if $console_out then $report_str &= $console_out
        if $err then exitloop
        Sleep(25)
    wend
    ProcessClose($probe_file)
    StdioClose($probe_file)

    if $un_escape_output = $ON then
        $report_str = StringReplace($report_str"\\""\")
        $report_str = StringReplace($report_str"\:"":")
    endif

    if $save_reports = $ON then
        if FileExists($report_loc) then FileDelete($report_loc)
        debug("Media Report Location: " & $report_loc, @ScriptLineNumber, 5);debug
        local $report_file_open = FileOpen($report_loc$FO_OVERWRITE$FO_CREATEPATH+$FO_UTF8_NOBOM)
        FileWrite($report_file_open$report_str)
        FileClose($report_file_open)
    endif

    debug($LOG_LF & "Report String: " & $LOG_LF & $report_str, @ScriptLineNumber, 9);debug

    local $report_to_console = true

    ; Shift key held down - open in viewer..
    if $shift_open then
        if $save_reports = $ON then
            debug("ShellExecute(" & $report_loc & ")...", @ScriptLineNumber, 5);debug
            ShellExecute($report_loc)
            $report_to_console = false
        else
            $report_str = "No report saved (disabled). Switching to console output.." & $LOG_LF & $LOG_LF & $report_str
        endif
    endif

    if $report_to_console = true then
        SetConsoleOutput($report_str, true)
    endif

endfunc


; Grab this fresh for every report..

func GetReportingValues()

    debug("GetReportingValues()...", @ScriptLineNumber, 5);debug

    $save_reports = IniReadCheckBoxValue($ini_path$my_name"save_reports"$ON)
    $report_format = IniRead($ini_path$my_name"report_format""ini")
    $report_directory = ffeDeTokenizeString(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)

    debug("$save_reports: " & Human($save_reports), @ScriptLineNumber, 8);debug
    debug("$report_format: " & $report_format, @ScriptLineNumber, 8);debug
    debug("$report_directory: " & $report_directory, @ScriptLineNumber, 8);debug
    debug("$report_extension: " & $report_extension, @ScriptLineNumber, 8);debug
    debug("$report_switches: " & $report_switches, @ScriptLineNumber, 8);debug
    debug("$un_escape_output: " & Human($un_escape_output), @ScriptLineNumber, 8);debug

    $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")

    debug("$use_mediainfo: " & Human($use_mediainfo), @ScriptLineNumber, 8);debug
    debug("$mediainfo_location: " & $mediainfo_location, @ScriptLineNumber, 8);debug
    debug("$mediainfo_switches: " & $mediainfo_switches, @ScriptLineNumber, 8);debug
    debug("$mediainfo_extension: " & $mediainfo_extension, @ScriptLineNumber, 8);debug

    if $use_mediainfo = $ON then
        $report_extension = $mediainfo_extension
        if not FileExists($mediainfo_location) then
            ConsoleAdd("MediaInfo.exe not found.", @ScriptLineNumber)
            return false
        endif
    else
        if $report_extension = "auto" then
            switch $report_format
                case "compact"
                    $report_extension = "txt"
                case else
                    $report_extension = "nfo"
            endswitch
        endif
        GetFFprobeLocation()
    endif
    return true
endfunc



; Right-Click on input file label..
;
func PlayInputFile()
    switch $play_command
        case "shellex"
            ; ShellExecute($inputfile"" , "" , "open")
            ShellExecute($inputfile)
        case else
            Run($play_command & " " & $inputfile)
    endswitch
endfunc


; Right-click on output file label..
;
func DeleteOutputFile()

    local $outfile = GUICtrlRead($inp_outputfile)

    if not FileExists($outfile) then
        ConsoleAdd("Can't delete " & $outfile & ". File does not exist.")
        return
    endif
    
    local $seen_delete_warning
    local $msg = "Are you sure you wish to delete the output file?"
    local $do_warning = false
    local $response

    if $delete_to_recycle_bin = $ON then
        ; It's still there. No biggie..
        $response = $IDOK
        ; No reason to post a warning, then..
        $do_warning = false
    else
        ; File will be GONE! If user has not been warned, warn them now, one time..
        $seen_delete_warning = IniReadCheckBoxValue($ini_path$my_name"warning_seen_output_delete"$OFF)

        if $seen_delete_warning = $ON then
            $response = $IDOK
            $do_warning = false
        else
            $msg = "In future, when you right-click on the label for the output file," & $MSG_LF & _
                    "it DELETES the output file. Gone. Vanished. No backup." & $MSG_LF & _
                    "(you can also delete to the recycle bin - see your prefs)" & $MSG_LF & $MSG_LF & _
                    "It's about to happen now. You will not see this warning again."
                IniWriteCheckBoxValue($ini_path$my_name"warning_seen_output_delete"$ON)
                ConsoleAdd("User warned about permanent button deletion: Check!", @ScriptLineNumber)
            $do_warning = true
        endif
    endif

    ; Everything can change, if the user has set this..
    if $always_warn_on_delete = $ON then $do_warning = true

    if $do_warning then
        DialogOpen()
        $response = MsgBox($MB_OKCANCEL"Delete Output File?"$msg, 60, $ffeGUI)
        DialogClose()
    endif

    if $response = $IDOK then
        if $delete_to_recycle_bin = $ON then
            if FileRecycle($outfile) then
                ConsoleAdd("Recycled: " & $outfile)
            endif
        else
            if FileDelete($outfile) then
                ConsoleAdd("Deleted: " & $outfile)
            endif
        endif
    endif

endfunc



func OpenImagesFolder()
    OpenSomething(GetParent($drop_win_image))
endfunc


func OpenFolderInFileSelected()
    OpenFolderFileSelected($inputfile$inp_inputfile)
endfunc

func OpenFolderOutFileSelected()
    OpenFolderFileSelected($outputfile$inp_outputfile)
endfunc



; Send a file path to open the parent folder in explorer, with the file selected.
; The $control will flash $warn_colour momentarily if the file does not exist.
;
func OpenFolderFileSelected($file$control=$inp_inputfile)
    debug("OpenFolderFileSelected " & $file, @ScriptLineNumber, 8);debug
    select
        case FileExists($file)
            ; This neat function removes the need to check window already exists..
            _WinAPI_ShellOpenFolderAndSelectItems($file)

        case FileExists(GetParent($file))
            OpenSomething(GetParent($file), true)

        case else
            $warn_control = $control
            SetWarning(true)
    endselect

endfunc




; All this so we can have smaller menu items!
;
; We create a 2D array to store the control IDs.
; Then we can get back the full path to check; basenames may be the same.

; If the user has no "Open" key (highly unlikely) in this filetype, this will fail..
;
func OpenRecentFile()
    debug("OpenRecentFile() ID: " & @tray_id, @ScriptLineNumber, 6);debug
    local $tray_item_full_path
    for $id = 1 to $recent_files[0][0]
        if @tray_id = $recent_files[$id][1] then
            $tray_item_full_path = $recent_files[$id][0]
            exitloop
        endif
    next
    debug("$tray_item_full_path: " & $tray_item_full_path, @ScriptLineNumber, 6);debug
    if FileExists($tray_item_full_path) then
        ShellExecute($tray_item_full_path""""$SHEX_OPEN)
    else
        MakeTray()
    endif
endfunc


func ClearRecentFiles()
    redim $recent_files[1][2]
    $recent_files[0][0] = ""
    ConsoleAdd("Recent Files list was emptied.", @ScriptLineNumber)
    IniDelete($ini_path$my_name"recent_files")
    MakeTray()
endfunc





; Browse for an input file..
; When Ctrl key is down, open the current inputfile directory
; with inputfile selected.

func BrowseForInputFile()
    ; Ctrl Key down..
    if _IsPressed(11) then
        OpenFolderInFileSelected()
        return
    endif
    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..
; When Ctrl key is down, open the current outputfile directory
; with outputfile selected.
;
func BrowseForOutputFile()
    if _IsPressed(11) then
        OpenFolderOutFileSelected()
        return
    endif
    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
    local $mum = GetParent($tmp_output)
    IniWrite($ini_path$my_name"save_output_dir"$mum)
    ConsoleAdd("Output dir set to: " & $mum, @ScriptLineNumber)
    $outputfile = $tmp_output
    GUICtrlSetData($inp_outputfile$outputfile)
    DoArgsCreate()
    return true
endfunc






; Where oh where is ffmpeg.exe..

func TraySetFFmpegBinLocation()
    SetFFmpegBinLocation()
endfunc

func SetFFmpegBinLocation($binary_location=false)

    debug("SetFFmpegBinLocation(" & $binary_location & ")...", @ScriptLineNumber, 5);debug

    ; 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)
        local $error = @error
        DialogClose()

        if not $tmp_ffmpeg_binary or $error then
            ConsoleAdd("FFmpeg binary location setting unchanged: User aborted.", @ScriptLineNumber)
            return false
        endif
        $tmp_ffmpeg_binary = ffeDeTokenizeString($tmp_ffmpeg_binary)
        $binary_location = ffeDeTokenizeString($tmp_ffmpeg_binary)
    endif

    debug("$binary_location: " & $binary_location, @ScriptLineNumber, 7);debug


    if $binary_location = $ffmpeg_binary then
        ConsoleAdd("FFmpeg binary location setting unchanged.", @ScriptLineNumber)
        return false
    endif

    if StringMid($binary_location, 1, 2) = "\\" then
        ConsoleAdd("Cannot set network location for FFmpeg binary. Please try again.", @ScriptLineNumber)
        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 = ffeTokenizeString($ffmpeg_binary)
        IniWrite($ini_path$my_name"ffmpeg_binary"$user_ffmpeg_binary)
        ConsoleAdd("FFmpeg binary location set to: """ & $user_ffmpeg_binary & """", @ScriptLineNumber)
        EnableRunningControls()
        $got_helps = ""
        UpdateCodecCombos()
    endif

endfunc




func GetFFprobeLocation()
    $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.", @ScriptLineNumber)
        return false
    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)
    local $error = @error
    DialogClose()
    if not $tmp_mediainfo_location or $error then
        ConsoleAdd("Still not got a valid path for MediaInfo. Disabling..", @ScriptLineNumber)
        return false
    endif
    if FileExists($tmp_mediainfo_location) then
        $mediainfo_location = $tmp_mediainfo_location
        IniWrite($ini_path$my_name"mediainfo_location"$mediainfo_location)
        ConsoleAdd("MediaInfo location set to: " & $mediainfo_location, @ScriptLineNumber)
    endif
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 = ffeDeTokenizeString(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 _____________IMPORT_EXPORT()
endfunc





; Import / Export..


func ComboImportData()
    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.", @ScriptLineNumber)
        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("Beginning data import..", @ScriptLineNumber)
    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, @ScriptLineNumber)
        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_VIDEO_MAPPINGS
                if StringInStr($user_choice$NAME_SETTINGS) then
                    $do_add = true
                    $r_type = $NAME_VIDEO_MAPPINGS
                endif
            case $NAME_AUDIO_MAPPINGS
                if StringInStr($user_choice$NAME_SETTINGS) then
                    $do_add = true
                    $r_type = $NAME_AUDIO_MAPPINGS
                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], $PRESET_BACKUP_STRING) 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], @ScriptLineNumber)
                                    ; 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_VIDEO_MAPPINGS$NAME_AUDIO_MAPPINGS
                        for $st = 1 to $this_section[0][0]
                            if IniWrite($ini_path$import_ini_sections[$i], $this_section[$st][0], $this_section[$st][1]) then
                                ConsoleAdd("Wrote mapping: " & $this_section[$st][0] & "=>" & $this_section[$st][1], @ScriptLineNumber)
                                $do_added = true
                            endif
                        next


                    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], @ScriptLineNumber)
                                $do_added = true
                            endif
                        next

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

    if StringInStr($user_choice$NAME_PRESETS) then UpdatePresetsCombo()
    if StringInStr($user_choice$NAME_BUTTONS) and $enable_custom_buttons = $ON then ReCreateButtonGrid()

    if $do_added then
        local $bax_ini = GetParent($ini_path) & "\PRE-IMPORT [" & FileDateStamp() & "] ffe.ini"
        if $restart_required then ConsoleAdd("Init settings detected - restart to see changes.", @ScriptLineNumber)
        if FileMove($tmp_ini$bax_ini) then
            ConsoleAdd("Old ffe.ini backed up to: " & $bax_ini & ".", @ScriptLineNumber)
        endif
    else
        FileDelete($tmp_ini)
    endif

endfunc



func MenuExportData()
    ExportData()
endfunc

func TrayMenuExportData()
    ExportData()
endfunc

func MenuExportButtons()
    ExportData($NAME_BUTTONS)
endfunc

func ExportData($dtype="")

    local $ini_sections = IniReadSectionNames($ini_path)
    if not IsArray($ini_sections) then return

    ConsoleAdd("Beginning data export..", @ScriptLineNumber)
    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($ini_sections"export", 0, $dtype)
    DialogClose()

    if not $user_choice then
        ConsoleAdd("Export aborted.", @ScriptLineNumber)
        return false
    endif
    local $do_add = false, $r_type$do_added = false

    ; Run through section-by-section..
    for $i = 1 to $ini_sections[0]

        $do_add = false

        switch $ini_sections[$i]
            case $my_name$NAME_VIDEO_MAPPINGS$NAME_AUDIO_MAPPINGS
                if StringInStr($user_choice$NAME_SETTINGS) then
                    $do_add = true
                    $r_type = $ini_sections[$i]
                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($ini_sections[$i], $PRESET_BACKUP_STRING) then
                    $do_add = true
                    $r_type = "preset" & ": " & $ini_sections[$i]
                endif
        endswitch

        if $do_add then

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

            local $this_section = IniReadSection($ini_path$ini_sections[$i])
            if not @error then
                switch $ini_sections[$i]
                    ; Main settings..
                    case $my_name$NAME_VIDEO_MAPPINGS$NAME_AUDIO_MAPPINGS
                        if IniWriteSection($tmp_ini_path$ini_sections[$i], $this_section) then
                        if $r_type = $my_name then $r_type = $NAME_SETTINGS
                            ConsoleAdd("Exported '" & $r_type & "'.", @ScriptLineNumber)
                        endif
                    ; Custom buttons..
                    case $NAME_BUTTONS
                        if IniWriteSection($tmp_ini_path$NAME_BUTTONS$this_section) then
                            ConsoleAdd("Exported '" & $r_type & "'.", @ScriptLineNumber)
                        endif
                    ; Preset..
                    case else
                        if not InArray($not_presets$ini_sections[$i]) and _
                            StringLeft($ini_sections[$i], StringLen($PRESET_BACKUP_STRING)) <> $PRESET_BACKUP_STRING then
                            if IniWriteSection($tmp_ini_path$ini_sections[$i], $this_section) then
                                ConsoleAdd("Exporting preset '" & $r_type & "'.", @ScriptLineNumber)
                            endif
                        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" ""-")) & "-"
        endif
        if StringInStr($user_choice$NAME_BUTTONS) then
            $export_name &= StringLower(StringReplace($NAME_BUTTONS" ""-")) & "-"
        endif
        if StringInStr($user_choice$NAME_PRESETS) then
            $export_name &= StringLower(StringReplace($NAME_PRESETS" ""-")) & "-"
        endif
        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 & ".", @ScriptLineNumber)
            endif
        else
            ConsoleAdd("Well, that was fun.", @ScriptLineNumber)
        endif
    endif

endfunc






; Custom inport/export user chooser..

; Returns a string containing relevant substrings, "main settings""presets" and "custom buttons".
; e.g., if everything is selected the string is, "main settingspresetsbuttons".

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!", @ScriptLineNumber)
        else
            ConsoleAdd("A serious ini-based error of some unknown description occured.", @ScriptLineNumber)
        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
    local $previous_event_mode = AutoItSetOption("GUIOnEventMode", 0)
    local $previous_coord_mode = 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
    local $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) _
        or InArray($ini_sections_array$NAME_VIDEO_MAPPINGS) _
        or InArray($ini_sections_array$NAME_AUDIO_MAPPINGS) 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"$previous_event_mode)
    AutoItSetOption("GUICoordMode"$previous_coord_mode)
    GUIDelete($ie_GUI)

    return SetError($err, 0, $return)

endfunc









func __________________________INFO()
endfunc





; Add some text onto the end of the console output and scroll to end of the output..
; The original text is returned so we can wrap this function, if required..
func ConsoleAdd($out_string$ln=@ScriptLineNumber)
    if $output_paused then return $out_string
    local $dlevl = 3
    ; Automatically switch the level of any message containing "error"
    if StringInStr($out_string"error"$STR_NOCASESENSEBASIC) then
        $dlevl = 1
        SetWinTitleText("                        ERROR!   [see console for details]")
        AdLibRegister("ResetTitle", 3000)
    endif
    debug("Console Add: " & $out_string$ln$dlevl);debug
    local $end = StringLen(GUICtrlRead($edit_console_output))
    _GUICtrlEdit_SetSel($edit_console_output$end$end)
    GUICtrlSetData($edit_console_output$out_string & $LOG_LF, 1)
    _GUICtrlEdit_Scroll($edit_console_output$__EDITCONSTANT_SB_SCROLLCARET)
    return $out_string
endfunc



; REPLACE the console output with some new output..
; The original text is returned so we can wrap this function, if required..
;
func SetConsoleOutput($out_string$scroll_top=false)
    GUICtrlSetState($edit_console_output$GUI_ENABLE)
    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 CopyConsoleOutput()
    CopyControlToClipBoard($edit_console_output"console output")
endfunc

func CopyControlToClipBoard($control$name)
    local $msg
    if GUICtrlRead($control) then
        ClipPut(GUICtrlRead($control))
        $msg = "                *** " & $name & " copied to the clipboard ***"
    else
        $msg = "                *** the " & $name & " is empty! nothing copied to the clipboard! ***"
    endif
    SetWinTitleText($msg)
    AdLibRegister("ResetTitle", 3000)
endfunc


func ClearOutput()
    SetConsoleOutput("")
endfunc




func DoAboutBox()

    DialogOpen()
    AutoItSetOption("GUIOnEventMode", 0)

    local $aw = 330, $ah = 210
    local $GUI_About = GUICreate(" about " & $my_name & ".. "$aw$ah, -1, @DesktopHeight/4, $WS_CAPTION$WS_EX_TOPMOST$ffeGUI)

    GUICtrlCreateIcon($me_app, 0, 15, 10, 32, 32)
    
    local $build = GetExtension($my_version)
    if $build then $build = "." & $build
    if $special_build then $build = $build & "    ( " & $special_build & ")"

    GUICtrlCreateLabel($my_name & " v" & $version & $build, 55, 10, default, 22)
    GUICtrlCreateLabel(chr(169) & " " & $my_domain & " 2007-" & @Year & ;o) ", 55, 28, default, 22)

    GUICtrlCreateLabel($my_name & " is a simple, powerful front-end for FFmpeg, " & _
        "enabling quick alterations to its parameters for rapid testing and production. " & $MSG_LF & $MSG_LF & _
        "ffe uniquely uses MATOF" & chr(153) & " technology to automatically update output filenames to " & _
        "match your encoding parameters, enabling you to save lots of slightly different versions of a file " & _
        "very, very quickly; in other words, 'find the best settings'" & $MSG_LF & $MSG_LF & _
        "Do you want to visit the " & $my_name & " web page at this time? ", 15, 50, $aw-25, $ah-90)

    local $GUI_About_NO = GUICtrlCreateButton("No"$aw-140, $ah-25, 60, 20, BitOr($WS_TABSTOP,$BS_FLAT))
    local $GUI_About_OK = GUICtrlCreateButton("Yes"$aw-72, $ah-25, 60, 20, BitOr($WS_TABSTOP,$BS_FLAT))

    ; GUICtrlSetState($GUI_About_OK$GUI_FOCUS)
    GUISetState(@SW_SHOW, $GUI_About)

    local $msg
    while true
        sleep(10)
        $msg = GUIGetMsg()
        switch $msg
            case $GUI_EVENT_CLOSE$GUI_About_NO
                exitloop
            case $GUI_About_OK
                VisitURL($my_url)
                exitloop
        endswitch
    wend

    GUIDelete($GUI_About)
    AutoItSetOption("GUIOnEventMode", 1)
    DialogClose()

endfunc




func DoAboutFFmpeg()
    DoFFmpegCommand("-version")
endfunc




func GetLogLocation($this_preset=$my_name)

    local $i = ffeDeTokenizeString(IniRead($ini_path$this_preset"log_location"$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
            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
    debug("$log_location set to: " & $log_location, @ScriptLineNumber, 7);debug

endfunc








func TrayDownloadImagePack()
    DownloadImagePack($x + 15, $y+338, $width-26, 58)
endfunc



; Download a wee selection of sample images to get you started.
; There are more images at the download URL, below..
;
func DownloadImagePack($windoid_x=default, $windoid_y=default, $windoid_w=default, $windoid_h=default)

    if $windoid_x = default then $windoid_x = -1
    if $windoid_y = default then $windoid_y = -1
    if $windoid_w = default then $windoid_w = 400
    if $windoid_h = default then $windoid_h = 46

    DialogOpen()
    ConsoleAdd("Downloading ffe image pack..", @ScriptLineNumber)

    local $image_pack_url$img_files$img_url$local_img_path$local_img_list
    $image_pack_url = IniRead($ini_path$my_name"image_pack_url""")
    if not $image_pack_url then $image_pack_url = "https://corz.org/windows/software/ffe/files/DropWindowImages/"

    local $list_file = "image_pack_urls.txt"
    $local_img_list = $data_dir & "\" & $list_file
    debug("$local_img_list: =>" & $local_img_list & "<=", @ScriptLineNumber, 6);debug
    FileDelete($local_img_list)

    local $tooltip_windoid = GUICreate("downloading"$windoid_w$windoid_h$windoid_x$windoid_y, _
            BitOr($WS_POPUP,$WS_DLGFRAME,$DS_MODALFRAME), BitOR($WS_EX_TOOLWINDOW,$WS_EX_TOPMOST,$GUI_WS_EX_PARENTDRAG), $ffeGUI)
    GUICtrlCreateLabel("Downloading ffe image pack..", 5, 3, $windoid_w-10, 22, $SS_LEFT$GUI_WS_EX_PARENTDRAG)
    local $tool_label = GUICtrlCreateLabel("", 5, 25, $windoid_w-10, 24, $SS_LEFT$GUI_WS_EX_PARENTDRAG)
    GUISetState(@SW_SHOW, $tooltip_windoid)

    ConsoleAdd("Grabbing image list..", @ScriptLineNumber)
    local $dl = BackGroundDownload($image_pack_url & $list_file, default, default, $local_img_list)

    if @error == 0 then

        FileReadIntoArray($local_img_list$img_files)

        if not IsArray($img_files) then
            ConsoleAdd("Error reading Image List.", @ScriptLineNumber)
            return false
        endif

        debug_PrintArray($img_files"List of $img_files:", @ScriptLineNumber, 7);debug

        local $current_img

        ; Run through the list..
        for $this_img = 1 to $img_files[0]


            $current_img = StringStripWS($img_files[$this_img], 3)
            debug("Current image file: =>" & $current_img & "<=", @ScriptLineNumber, 11);debug

            ; Ignore comments..
            if $current_img and StringLeft($current_img, 1) <> ";" then

                $img_url = $image_pack_url & $current_img
                $local_img_path = $drop_win_image_folder & "\" & StringReplace($current_img"/""\")

                if not FileExists(GetParent($local_img_path)) then DirCreate(GetParent($local_img_path))

                if FileExists($local_img_path) then
                    GUICtrlSetData($tool_label"Skipping: " & $current_img)
                    ConsoleAdd("File exists (skipped): " & $current_img, @ScriptLineNumber)
                    Sleep(166) ; The "doing something" delay. It's a human thing.
                else
                    GUICtrlSetData($tool_label"Downloading: " & $current_img)
                    Sleep(500)
                    $dl = BackGroundDownload($img_url, default, default, $local_img_path)
                    if @error <> 0 then
                        debug("@error: " & @error, @ScriptLineNumber, 1);debug
                        debug("@extended: " & @extended, @ScriptLineNumber, 1);debug
                        ConsoleAdd($dl, @ScriptLineNumber)
                        exitloop
                    endif
                    ConsoleAdd("Downloaded: " & $current_img, @ScriptLineNumber)
                endif
            endif
            if $this_img = $img_files[0] then
                ConsoleAdd("Downloading complete.", @ScriptLineNumber)
            endif
        next

        ; Clean-up..
        FileDelete($local_img_list)
        GUICtrlSetData($tool_label"Image Pack Downloaded!")

    else
        debug("@error: " & @error, @ScriptLineNumber, 1);debug
        debug("@extended: " & @extended, @ScriptLineNumber, 1);debug
        ConsoleAdd("", @ScriptLineNumber)
        ConsoleAdd("Download ERROR!", @ScriptLineNumber)
        ConsoleAdd("ffe could not retrieve the image list!" & $LOG_LF & _
                    "Without the image list, no images can be downloaded.", @ScriptLineNumber)
        GUICtrlSetData($tool_label$dl)
        ConsoleAdd($dl, @ScriptLineNumber)
    endif

    GUIDelete($tooltip_windoid)
    DialogClose()
    HideDropWindow()

endfunc







func __________ANCILLARY_FUNCS()
endfunc




func DialogOpen()
    GUISetState(@SW_DISABLE, $ffeGUI)
    UnSetHotKeys()
endfunc

func DialogClose()
    GUISetState(@SW_ENABLE, $ffeGUI)
    WinActivate($ffeGUI)
    SetHotKeys()
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





; 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

    ; So these functions aren't firing a zillion times a second..
    if $previous_pos <> $mouse_pos[4] then

        ; Help buttons..
        if IsArray($help_texts) then
            if IsArray($help_butts) then
                local $help_hover = InArray($help_butts$mouse_pos[4])
                if $help_hover then
                    GUICtrlSetData($lab_help_info, _
                        StringLeft($help_texts[$help_hover], StringInStr($help_texts[$help_hover], "|") - 1))
                else
                    GUICtrlSetData($lab_help_info"")
                endif
            endif
        endif

        ; Highlight active labels.
        ; Nice idea, but we should think about some kind of AA instead of many
        ; global flags to store on/off states.

        ;2do - consider different colours for different actions, e.g. right-now-click button = green on mouseover

        ; We don't put them all into a single select, as it would make mouse-overs less responsive.
        ;
        select
            ; inputfile label..
            case $set_if = false and $mouse_pos[4] = $lab_inputfile
                GUICtrlSetColor($lab_inputfile$COLOR_SKYBLUE)
                $set_if = true

            case $set_if = true
                GUICtrlSetColor($lab_inputfile, default)
                $set_if = false
        endselect
        select
            ; outputfile label..
            case $set_of = false and $mouse_pos[4] = $lab_outputfile
                GUICtrlSetColor($lab_outputfile$COLOR_SKYBLUE)
                $set_of = true

            case $set_of = true
                GUICtrlSetColor($lab_outputfile, default)
                $set_of = false
        endselect
        select
            ; crop w / h label..
            case $set_wh = false and $mouse_pos[4] = $label_active_crop_wh
                GUICtrlSetColor($label_active_crop_wh$COLOR_SKYBLUE)
                $set_wh = true

            case $set_wh = true
                GUICtrlSetColor($label_active_crop_wh, default)
                $set_wh = false
        endselect
        select
            ; crop x / y label..
            case $set_xy = false and $mouse_pos[4] = $label_active_crop_xy
                GUICtrlSetColor($label_active_crop_xy$COLOR_SKYBLUE)
                $set_xy = true

            case $set_xy = true
                GUICtrlSetColor($label_active_crop_xy, default)
                $set_xy = false
        endselect

        $previous_pos = $mouse_pos[4]

    endif



    ; Button text changes..
    ; We set a $shifted flag to prevent updating the buttons every 1/100th second when nothing is happening
    select

        case _IsPressed(10) and WinActive($ffeGUI) and not $shifted
            $shifted = true
            "Do It!" becomes script output..
            GUICtrlSetData($butt_doit"script output")
            GUICtrlSetData($butt_wipe"restore")
            ; Set the number of frames (saved to ini)
            GUICtrlSetData($butt_quicktest"set frames")
            GUICtrlSetData($butt_mediareport"open report")

            ; 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 not _IsPressed(10) and $shifted
            GUICtrlSetData($butt_doit"do it!")
            GUICtrlSetData($butt_wipe"wipe")
            GUICtrlSetData($butt_quicktest"short test")
            GUICtrlSetData($butt_mediareport"media report")
            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
        ; @extended is read inside the main loop.
        return SetExtended($drop_mouse_pos[4], $mouse_pos[4])
    endif

    return $mouse_pos[4]
endfunc



; Focus detected on $inp_outputfile and others..
;2do - could store selections of all intputs and restore.. a rainy-day task!
func CheckFocus($hWnd$iMsg$wParam$lParam)
#forceref $hWnd$iMsg

    debug("CheckFocus(current current_control_focus): " & $current_control_focus, @ScriptLineNumber, 9);debug
    local $iFlag = BitShift($wParam, 16)

    switch $lParam
        case GUICtrlGetHandle($inp_outputfile)
            switch $iFlag
                case $EN_SETFOCUS
                    $current_control_focus = $inp_outputfile
                    FocusTo_inp_output()
            endswitch

        case GUICtrlGetHandle($inp_inputfile)
            switch $iFlag
                case $EN_SETFOCUS
                    $current_control_focus = $inp_inputfile
            endswitch

        case GUICtrlGetHandle($inp_input_params)
            switch $iFlag
                case $EN_SETFOCUS
                    $current_control_focus = $inp_input_params
            endswitch

        case GUICtrlGetHandle($inp_extra_args)
            switch $iFlag
                case $EN_SETFOCUS
                    $current_control_focus = $inp_extra_args
            endswitch

        case GUICtrlGetHandle($edit_console_output)
            switch $iFlag
                case $EN_SETFOCUS
                    $current_control_focus = $edit_console_output
            endswitch

        case GUICtrlGetHandle($edit_in_args)
            switch $iFlag
                case $EN_SETFOCUS
                    $current_control_focus = $edit_in_args
            endswitch

    endswitch

    debug("$current_control_focus: " & $current_control_focus, @ScriptLineNumber, 9);debug
endfunc



func FocusTo_inp_output()
    if $do_matof = $ON then
        ToggleMatofStatus()
    endif
endfunc





; Right-Now-Click(TM) Functions (skip the context menu, save a click, save time, save your fingers!)
;
func CheckForRightClickTask()

    if $right_clicking then return
    local $cursor_info = GUIGetCursorInfo($ffeGUI)
    
    $right_clicking = true
    AdlibRegister ("EndRightClick", 250)
    
    switch $cursor_info[4]

        case $lab_inputfile
            PlayInputFile()

        case $lab_outputfile
            DeleteOutputFile()
            
        case $check_run_ffmpeg_task
            EditFFmpegTask()

        case $check_run_ffplay_task
            EditFFplayTask()
            
        case $butt_quicktest
            UserEditShortTestParams()
            
        case $butt_wipe
            RestoreBackupPreset()

        case $check_run_pre_job_commands
            SpecifyPreJobCMDsFile()

        case $check_run_post_file_command
            SpecifyPostFileCommand()

        case $check_run_post_job_commands
            SpecifyPostJobCMDsFile()

        case $label_active_crop_wh$label_active_crop_xy
            UserEditCropTestFrames(default, true)

    endswitch
    
endfunc



func EndRightClick()
    $right_clicking = false
    AdlibUnRegister ("EndRightClick")
endfunc



; Yes, every time you press the mouse button in the GUI..

func PrimaryUpCheckSize()
    debug("PrimaryUpCheckSize() --> CheckSize()...", @ScriptLineNumber, 7);debug
    if $current_control_focus <> $edit_in_args then
        CheckSize()
        DoArgsCreate()
    endif
endfunc



; Get window to conform to minimum sizes..

func CheckSize()

    debug("CheckSize()...", @ScriptLineNumber, 7);debug

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

    ; User window made too small for controls..
    if $size_array[0] < $min_width then
        WinMove($my_title"", default, default , $min_width+10)
        $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

        ; The user went too far!
        ; ffe has been automatically resized - re-create the button grid..
        if $enable_custom_buttons = $ON and $custom_buttons_columns = "auto" then
            debug("CheckSize() ---> ReCreateButtonGrid() ....................", @ScriptLineNumber, 7);debug
            ReCreateButtonGrid()
        endif
    endif


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

    ; Quick check on x/y so relative dialogs can remain so..
    $size_array = WinGetPos($ffeGUI)
    if IsArray($size_array) then

        if $size_array[0] <> $x then
            $x = $size_array[0]
            IniWrite($ini_path$my_name"x"$x)
        endif

        if $size_array[1] <> $y then
            $y = $size_array[1]
            IniWrite($ini_path$my_name"y"$y)
        endif

    endif

    return true
endfunc



func ResizeSaveXYWHPrefs()
    SaveXYWHPrefs()
endfunc



func SaveXYWHPrefs($shutdown=false)

    debug("SaveXYWHPrefs()...", @ScriptLineNumber, 7);debug

    if not CheckSize() then return

    ; Set the actual variables, too, so we can refer to them when creating dialogs.
    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

    if not $shutdown then
        ; We may need to re-calculate the number of custom button columns..
        ; the $too_far flag prevents a second firing of ReCreateButtonGrid() after the PRIMARYUP event..
        if $custom_buttons_columns = "auto" and $enable_custom_buttons = $ON and $too_far = false then
            debug("SaveXYWHPrefs() ---> ReCreateButtonGrid() ....................", @ScriptLineNumber, 7);debug
            ReCreateButtonGrid()
        endif
    endif

endfunc







; Either at launch time or on file drop..
;
func DoDropCommand()
    switch $drop_command
        case "Go"
            DoIt()
        case "Play"
            PlayIt()
        case "Generate"
            $do_gen = true
            DoIt()
        case "Report"
            if not StringInStr(FileGetAttrib($inputfile), "D") then GenerateReport()
    endswitch
endfunc



; Read the user's video and audio codec prefs and either load their list or
; use FFmpeg to generate a fresh codec list for the codec combos.
; If the user's list is empty, fall-back to generating a fresh list.
;
func GetUserCodecs()

    $auto_codecs = IniReadCheckBoxValue($ini_path$my_name"auto_codecs"$OFF)
    debug("$auto_codecs: " & Human($auto_codecs), @ScriptLineNumber, 8);debug

    switch $auto_codecs

        case $ON

            ; Conversely; user has specified auto-codecs but that failed (for
            ; some reason). Fall-back to ini file. If that fails, we will try
            ; FFmpeg again, one type at a time..
            if not GetCodecsFromFFmpeg() then continuecase

        case else

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

            if not $video_codecs then
                ; No video codecs specified, get these from FFmpeg..
                GetCodecsFromFFmpeg(true,false)

            ; Video codecs loaded from ffe.ini, so load audio codecs..
            else
                ; Ensure "disable" is included in list..
                if not StringInStr($video_codecs"|- disable video -") then $audio_codecs &= "|- disable video -"
                $audio_codecs = IniRead($ini_path$my_name"audio_codecs""")

                ; No audio codes in ffe.ini, get from FFmpeg..
                if not $audio_codecs then
                    GetCodecsFromFFmpeg(false,true)
                else
                    if not StringInStr($audio_codecs"|- disable audio -") then $audio_codecs &= "|- disable audio -"
                endif
            endif

    endswitch

    debug("$video_codecs: " & $video_codecs, @ScriptLineNumber, 8);debug
    debug("$audio_codecs: " & $audio_codecs, @ScriptLineNumber, 8);debug

endfunc


; Get the -encoders help from FFmpeg and parse it for the currently available
; encoders which we use to create lists for the codec drop-downs (combos).
;
func GetCodecsFromFFmpeg($do_video=true, $do_audio=true)

    local $file = @TempDir & "\encoders"
    RunWait(@ComSpec & " /c """ & $ffmpeg_binary & """ -encoders > " & $file , "", @SW_HIDE)
    if not FileExists($file) then return false

    ; We need a blank item at the start, for intuitive user input..
    local $v_codecs = "||"
    local $a_codecs = "||"
    local $this_codec

    local $encoders_help_array = FileReadToArray($file)
    if not IsArray($encoders_help_array) then return false

    ; Skip intro.
    ; Run through the lines..
    for $i = 9 to Ubound($encoders_help_array)-1

        $this_codec = StringStripWS($encoders_help_array[$i], 3)

        ; Grab this now; we'll use it..
        local $first_letter = StringLeft($this_codec, 1)

        ; Strip off the unwanted parts..    (I do hope they don't change this format! lol)
        $this_codec = StringRegExpReplace($this_codec"\H{6}\h([^\h]+)[\h]*.*""$1", 1)

        switch $first_letter
            case "V"
                if $do_video then $v_codecs &= $this_codec & "|"
            case "A"
                if $do_audio then $a_codecs &= $this_codec & "|"
        endswitch
    next

    ; Quick check to ensure we have what we expect..
    if (StringInStr($v_codecs"x264") and $do_video) or (StringInStr($a_codecs"mp3") and $do_audio) then
        ; Ensure essential list items are present..
        if $do_video then $video_codecs = $v_codecs & "copy|- disable video -"
        if $do_audio then $audio_codecs = $a_codecs & "copy|- disable audio -"
        FileDelete($file)
        return true
    endif

endfunc





func AbortBatch()
    $abort_batch = true
endfunc




; Momentary warning.
; Flash a control background (or foreground) red.
;
$warn_control is a global variable we set to whatever control we want the
; warning to be displayed on. That's really poor English!
; Choose from background (default) or Foreground (text) warning.
;
func SetWarning($bg=true)
    if $bg then
        GuiCtrlSetBkColor($warn_control$warn_colour)
        AdlibRegister("EndBGWarning", 666)
    else
        GuiCtrlSetColor($warn_control$warn_colour)
        AdlibRegister("EndFGWarning", 666)
    endif
endfunc
func EndWarning($bg=true)
    if $bg then
        GuiCtrlSetBkColor($warn_control, default)
    else
        GuiCtrlSetColor($warn_control, default)
    endif
endfunc
func EndBGWarning()
    EndWarning(true)
endfunc
func EndFGWarning()
    EndWarning(false)
endfunc



; Validate the user colour and convert it into a binary string to be used as a
; color value for AutoIt functions (they don't mind that it's a string!)..
func GetUserColor($user_color)
    ; lop off any preceding "#"..
    $user_color = StringRight($user_color, 6)
    debug("$user_color: " & $user_color, @ScriptLineNumber, 8);debug
    ; Magical Binary Conversion..
    return "0x" & $user_color
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 $previous_event_mode = AutoItSetOption("GUIOnEventMode", 0)
    local $previous_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, ".\Resources\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"$previous_event_mode)
    AutoItSetOption("GUICoordMode"$previous_coord_mode)
    DialogClose()

    if $delay_start_at then TrayItemSetState($tray_toggle_delayed_start$ON)

endfunc






func __________________________EXIT()
endfunc

; Bye Now!

func Restart()
    DoQuit(0, true)
endfunc

func User_DoQuit()
    DoQuit(0)
endfunc


; Really, Bye!
;
func DoQuit($ext=0, $reload=false)

    UnSetHotKeys() ; not actually required

    if $kill_ffmpeg_on_exit = $ON then
        ProcessSuspendResume($ffmpeg)
        DllCall('kernel32.dll', 'ptr', 'DebugSetProcessKillOnExit', 'int', true)
    else
        ProcessSuspendResume($ffmpeg, false)
        DllCall('kernel32.dll', 'ptr', 'DebugSetProcessKillOnExit', 'int', false)
    endif

    if $minimized = $OFF and $maximized = $OFF then
        SaveXYWHPrefs(true)
    endif

    if (not $do_quit) and ($retain_exit_settings = $ON) then
        IniDelete($ini_path$EXIT_PRESET)
        SavePreset($EXIT_PRESET)
    endif

    VersionCheckOnline($my_name$versioncheck_url$download_url$ini_path$my_name$my_version)

    ; Keep recent files..
    ; (do this last, in case it's large and we hit the ini character length limit before it parses out)
    ; Invalid (cropped) entries will be automatically removed at launch.
    if $retain_recent_files = $ON and $recent_files[0][0] then
        $recent_files = TwoDCol2OneDArray($recent_files)
        IniWrite($ini_path$my_name"recent_files", ArrayJoin($recent_files"|"))
    endif

    ; Fade-out    (would ideally like a TV power-off, like the HUDL2). Och well..
    for $tc = 255 to 0 step -20
        WinSetTrans($ffeGUI""$tc)
        Sleep(10)
    next

    ; Do this AFTER the saving X/Y prefs for main GUI, or else they will be GONE.
    GUIDelete($ffeGUI)

    if $dropwin_visible then HideDropWindow()

    ; Reclaim small amount of memory..
    AAWipe($known_files)

    if $reload then Run(@ScriptFullPath)
    exit $ext

endfunc








; AutoIt Wrapper / Compiler directives..
;

#Region

; For resources included with FileInstall()
#pragma compile(Compression, 9)

;::dev::..
; If you want your binary NOW, comment this out..
#AutoIt3Wrapper_Run_Au3Stripper=Y

; See the notes above debug() (in cel.au3) for what /rsln does.
#Au3Stripper_Parameters=/StripOnly /rsln

; Like calling the wrapper with /debug, which we do anyway. This is handy, though ..
#AutoIt3Wrapper_Run_Debug_Mode=Y
#AutoIt3Wrapper_LogFile=%scriptdir%\wrapper.log
#AutoIt3Wrapper_UseX64=Y
#AutoIt3Wrapper_UseUpx=N
#AutoIt3Wrapper_Run_AU3Check=Y
#AutoIt3Wrapper_AU3Check_Parameters=-d -w 1 -w 2 -w 3 -w- 4 -w 5 -w 6 -w 7 -v 1
#AutoIt3Wrapper_AU3Check_Stop_OnWarning=Y
#AutoIt3Wrapper_Run_Stop_OnError=Y
; Main program icon..
; NOTE: *** MAY NEED FORWARD SLASHES IN RELATIVE PATHS - YMMV!!! ***
#AutoIt3Wrapper_Icon=Resources\Icons\ffe.ico
;-5.
#AutoIt3Wrapper_Res_Icon_Add=Resources\Icons\document-outline.ico
;-6.
#AutoIt3Wrapper_Res_Icon_Add=Resources\Icons\magic-wand.ico
;-7.
#AutoIt3Wrapper_Res_Icon_Add=Resources\Icons\document-small.ico
;-8.
#AutoIt3Wrapper_Res_Icon_Add=Resources\Icons\folder-small.ico
;-9.
#AutoIt3Wrapper_Res_Icon_Add=Resources\Icons\folder-small-outline.ico
;-10.
#AutoIt3Wrapper_Res_Icon_Add=Resources\Icons\auto-out.ico
;-11.
#AutoIt3Wrapper_Res_Icon_Add=Resources\Icons\ffe-time.ico
;-12.
#AutoIt3Wrapper_Res_Icon_Add=Resources\Icons\tooltip.ico
;-13.
#AutoIt3Wrapper_Res_Icon_Add=Resources\Icons\target.ico


; Free-Form Res Fields..
#AutoIt3Wrapper_Res_Field=Author|Cor
#AutoIt3Wrapper_Res_Field=Contact|windows@corz.org
#AutoIt3Wrapper_Res_Field=Instructions|enable MATOF, drag and drop files into ffe, choose a preset, do it!
#AutoIt3Wrapper_Res_Field=Long Description|ffe is a Windows front-end for the marvelous FFmpeg. It was designed for rapid testing of the many (many) FFmpeg settings, enabling one to quickly find the best settings for a particular file, and when you do, save it as a preset, for future use. Find any cute settings along the way, save those as a handy button. Of course you can also use ffe to perform the actual conversions, with output piped directly into your GUI.
#AutoIt3Wrapper_Res_Field=Publisher|corz.org
#AutoIt3Wrapper_Res_Field=Web Page|http://corz.org/windows/software/ffe/
#AutoIt3Wrapper_Res_Field=Compiled|%date% %time%

; These now have their own fields..
#AutoIt3Wrapper_Res_ProductName=ffe
#AutoIt3Wrapper_Res_CompanyName=corz.org
#AutoIt3Wrapper_Res_LegalCopyright=corz.org

; Application's resource info..
#AutoIt3Wrapper_Res_Comment=ffe

; This is the one that shows up in Process Explorer..
#AutoIt3Wrapper_Res_Description=ffe - FFmpeg Front-End for Windows
#AutoIt3Wrapper_Res_LegalCopyright=corz.org
#AutoIt3Wrapper_Res_ProductVersion=2

;#AutoIt3Wrapper_Res_Field=Build|DEBUG
;#AutoIt3Wrapper_Res_Field=Build|Beta Release
#AutoIt3Wrapper_Res_Field=Build|Public Release


; I must get a shot of my son's Surface and see if this does anything! I suspect not.
#AutoIt3Wrapper_Res_HiDpi=Y


; Run pre- & post-compile tasks elevated (as admin)..
;
#AutoIt3Wrapper_Run_Before_Admin=Y
#AutoIt3Wrapper_Run_After_Admin=Y


; Tasks to perform BEFORE compilation..
;

; You might want to comment this out (kills any running instance of ffe)..
#AutoIt3Wrapper_Run_Before=taskkill /F /T /IM ffe.exe
; But if you do, copying your new binary over (below) probably won't work.



; Tasks to perform AFTER compilation..
;

; Backup this version of the script (dropped into a backup.zip, below). So I don't have to remember to..
#AutoIt3Wrapper_Run_After=copy "%in%"                                     ".\%scriptfile% - %fileversion%.au3"


; Handy to keep a backup of the stripped version, too..
#AutoIt3Wrapper_Run_After=move /Y .\%scriptfile%_stripped.au3             ".\%scriptfile% - %fileversion%_stripped.au3"


;::dev::..
; Copy latest binaries to app folders (overwrites existing binary)..
; Your copy of ffe may be somewhere else..
#AutoIt3Wrapper_Run_After=copy "%outx64%"                                 "C:\Program Files\corz\ffe\ffe.exe"




;::dev::..
; You can probably comment-out this entire next section.
; It relates to building the distribution and source packages.
;
; It has some useful commands for your reference, though.
;
; It should be noted, the copies of cel.au3, etc., that I keep in my Resources
; directory, are hard links to my master files. If you are unfamiliar with the
; wonders of hard (and symbolic) links, see here:
; https://schinagl.priv.at/nt/hardlinkshellext/linkshellextension.html
; Only one version of the files exists. The others, like the ones in here are
"sorta shortcuts that work just like the originals". Check it out.
;
; ffe beta package..
; Move latest binaries, etc. to distro folder (out of the way of the source)..
#AutoIt3Wrapper_Run_After=mkdir "..\ffe"
#AutoIt3Wrapper_Run_After=mkdir "..\ffe\Info"
#AutoIt3Wrapper_Run_After=move /Y "%outx64%"                             "..\ffe\ffe.exe"
#AutoIt3Wrapper_Run_After=copy ".\Resources\QuickStart.txt"             "..\ffe\QuickStart.txt"
#AutoIt3Wrapper_Run_After=copy ".\Resources\ffe.ini"                     "..\ffe\Info\ffe.ini"
#AutoIt3Wrapper_Run_After=copy ".\Itstory.txt"                             "..\ffe\Info\Itstory.txt"
#AutoIt3Wrapper_Run_After=copy ".\Resources\About This Folder.txt"         "..\ffe\Info\About This Folder.txt"
#AutoIt3Wrapper_Run_After=copy "..\..\Free Software License.txt"         "..\ffe\Info\Free Software License.txt"
; Source pack update...
#AutoIt3Wrapper_Run_After=mkdir "..\ffe source pack"
#AutoIt3Wrapper_Run_After=mkdir "..\ffe source pack\Resources"
#AutoIt3Wrapper_Run_After=copy "%in%"                                     "..\ffe source pack\%scriptfile%.au3"
#AutoIt3Wrapper_Run_After=copy ".\Itstory.txt"                             "..\ffe source pack\Resources\Itstory.txt"
#AutoIt3Wrapper_Run_After=copy ".\Resources\cel.au3"                     "..\ffe source pack\Resources\cel.au3"
#AutoIt3Wrapper_Run_After=copy ".\Resources\EditFind.au3"                 "..\ffe source pack\Resources\EditFind.au3"
#AutoIt3Wrapper_Run_After=copy ".\Resources\GIFAnimation.au3"             "..\ffe source pack\Resources\GIFAnimation.au3"
#AutoIt3Wrapper_Run_After=copy ".\Resources\ffe.ini"                     "..\ffe source pack\Resources\ffe.ini"
#AutoIt3Wrapper_Run_After=copy ".\Resources\ffe.png"                     "..\ffe source pack\Resources\ffe.png"
#AutoIt3Wrapper_Run_After=copy ".\Resources\About Resources.txt"         "..\ffe source pack\Resources\About Resources.txt"
#AutoIt3Wrapper_Run_After=copy ".\Resources\QuickStart.txt"             "..\ffe source pack\Resources\QuickStart.txt"
#AutoIt3Wrapper_Run_After=copy "..\..\Free Software License.txt"         "..\ffe source pack\Resources\Free Software License.txt
;
#AutoIt3Wrapper_Run_After=Xcopy ".\Resources\Icons"                     "..\ffe source pack\Resources\Icons"  /E /H /C /I
#AutoIt3Wrapper_Run_After=Xcopy "..\..\stuff\Notepad++Goodies"             "..\ffe source pack\Resources\Notepad++Goodies"  /E /H /C /I
;
;
; RELEASE..
; Create zips of both distro directories..
#AutoIt3Wrapper_Run_After=7z.exe a -mx7 -tzip "..\ffe v%fileversion%.zip" "..\ffe\"
#AutoIt3Wrapper_Run_After=7z.exe a -mx7 -tzip "..\ffe source pack v%fileversion%.zip" "..\ffe source pack\"
; Multi-Hash (MD5+SHA1)..
#AutoIt3Wrapper_Run_After=checksum.exe cq-t "..\ffe v%fileversion%.zip"
#AutoIt3Wrapper_Run_After=checksum.exe csq-t "..\ffe v%fileversion%.zip"
#AutoIt3Wrapper_Run_After=checksum.exe cq-t "..\ffe source pack v%fileversion%.zip"
#AutoIt3Wrapper_Run_After=checksum.exe csq-t "..\ffe source pack v%fileversion%.zip"
; Backup this version of the source files to BackUp.zip..
#AutoIt3Wrapper_Run_After=7z.exe a -mx7 -tzip ".\BackUp.zip" ".\%scriptfile% - %fileversion%.au3"
#AutoIt3Wrapper_Run_After=7z.exe a -mx7 -tzip ".\BackUp.zip" ".\%scriptfile% - %fileversion%_stripped.au3"
;;
;
;
; ; BETA..
; ; Create zips of both distro directories..
#AutoIt3Wrapper_Run_After=7z.exe a -mx7 -tzip "..\ffe beta v%fileversion%.zip" "..\ffe\"
#AutoIt3Wrapper_Run_After=7z.exe a -mx7 -tzip "..\ffe beta source pack v%fileversion%.zip" "..\ffe source pack\"
; ; Multi-Hash (MD5+SHA1)..
#AutoIt3Wrapper_Run_After=checksum.exe cq-t "..\ffe beta v%fileversion%.zip"
#AutoIt3Wrapper_Run_After=checksum.exe csq-t "..\ffe beta v%fileversion%.zip"
#AutoIt3Wrapper_Run_After=checksum.exe cq-t "..\ffe beta source pack v%fileversion%.zip"
#AutoIt3Wrapper_Run_After=checksum.exe csq-t "..\ffe beta source pack v%fileversion%.zip"
; ; Backup this version of the source files to BackUp.zip..
#AutoIt3Wrapper_Run_After=7z.exe a -mx7 -tzip ".\BackUp.zip" ".\%scriptfile% - %fileversion%.au3"
#AutoIt3Wrapper_Run_After=7z.exe a -mx7 -tzip ".\BackUp.zip" ".\%scriptfile% - %fileversion%_stripped.au3"
;;



; NOTE: The 7z and checksum program directories are in my %PATH% (System Properties >> Advanced >> Environment Variables).
; Finally, remove the (now-zipped) source files..
#AutoIt3Wrapper_Run_After=del /f /q ".\%scriptfile% - %fileversion%.au3"
#AutoIt3Wrapper_Run_After=del /f /q ".\%scriptfile% - %fileversion%_stripped.au3"







#cs

A few tests..
In a decent text editor you can simply select a line and run
the test with the current script. Gotta love AutoIt!

:: Load with preset..
load(MP3)

load(Reverse Video+Audio) "
B:\Test\ffe\IN\PS3 Baby_360p.mp4"
go(Reverse Video+Audio) "
B:\Test\ffe\IN\PS3 Baby_360p.mp4"

go(SINGLE FILE TEST)

:: Launch and Go..
go(ffe) "
B:\Test\ffe\IN\ScooterRace.flv"
go(MP3 (True Stereo)) "
B:\Test\ffe\IN\Puffy Ami Yumi.wmv"
go(Grab 150 Frames from URL)


; Launch, go and quit..
run(SpeedUp x2) "
B:\Test\ffe\IN\ScooterRace.flv"
run(Reverse Video+Audio) "
B:\Test\ffe\IN\PS3 Baby_360p.mp4"
quit(MP3) "
B:\Test\ffe\IN\ScooterRace.flv"


; Launch, generate .bat file and quit..
generate(MP3) "
B:\Test\ffe\IN\ScooterRace.flv"


:: batches..

go(x265 Simple) "
B:\Test\ffe\IN\*.mkv"
go(x265 Simple) "
B:\Test\ffe\IN\*.mp4"
go(x265 Simple) "
B:\Test\ffe\IN\*.m??"

generate(x265 Simple) "
B:\Test\ffe\IN\*"


:: FAIL..
go "
B:\Test\ffe\IN\ScooterRace.flv"
^^ this should NOT go!

:: No such preset!
run(FICTION) "
B:\Test\ffe\IN\PS3 Baby_360p.mp4"


generate(x264 Simple Test)  B:\Test\ffe\IN

generate(Simple Test)  B:\Test\ffe\IN


; WTF! Not loading filepaths unless enabled!?!?

go(Simple Test)


#ce




; Fire-up the new version..
#AutoIt3Wrapper_Run_After = start "" "C:\Program Files\corz\ffe\ffe.exe"


; When you run AutoIt wrapper, compile the script; the version number is automatically increased.
; It actually edits this file. So no editing during compiling! And you lose your undos! Nah.
#AutoIt3Wrapper_Res_FileVersion_AutoIncrement=Y


; Version (keep this!)..

; This is visible all over the place (explorer properties, on mouse hover, etc.)
; and also used internally for version checking and the about box..
#AutoIt3Wrapper_Res_Fileversion=2.5.4.4


; find nasty end-of-line comments: (\w+)(\h+);.*$

; ***    BEFORE COMPILING:: 
;        To delete debug lines, do a regex search for:        debug.*\(.*0\)


#EndRegion"

Welcome to corz.org!

I'm always messing around with the back-end.. See a bug? Wait a minute and try again. Still see a bug? Mail Me!