imitate a windows folder view

typing the file name searches and selects the item that starts with that name.

delete removes it.
are you sure?

double-clicking opens the full-size picture to view

preview panel displays info about the selected picture

X  F2 renames the file

right-click menu has all possible options
	sort by name
	sort by date
	convert to JPG		(if PNG)
	convert to MP4		(if GIF)
	open folder
	delete

top menu bar has all possible options
	sort by name
	sort by date
	convert to JPG		(if a PNG picture is selected)
	convert to MP4		(if a GIF picture is selected)
	open picture folder
	delete						(if a picture is selected)

Drag and drop a picture into the window adds it
Async read artist name and report back
	auto-rename and update pic info

Keep a staging log of changes to make
Click the "save changes" button to apply the staging log
log is saved immediately, and persists between restarts

-----------------------

2 programs
1) The main program.
2) A hidden / minimized background program that handles running scripts.

The hidden tasker program run scripts synchronously and freezes until they finish. The main program continues running seamlessly creating a smooth user experience.

The hidden tasker program minimizes itself when it starts, hopefully releasing focus.
sendToBack() and minimizeToTray() are also options that might release focus.
mdm.Process.create() can launch programs in "hidden" or "minimized" modes.
mdm.Process.lastId OR mdm.System.getWindowList()  +  mdm.System.postMessage( ID, WM_KILLFOCUS )  are also options that might release focus.

Scripts are run synchronously to avoid pop-up DOS windows that steal focus away from the user interface of the main program.

The two programs communicate by writing and reading files in a folder.
Each file contains one command to perform.
The list of files forms an asynchronous sequence of actions. A command queue.
Each program maintains an integer counter.
The main program starts at zero, creates a file named after the counter, then increments its counter.
The hidden tasker program starts at zero, polls for a file named after its counter, then after reading the file, it deletes that file, then increments its counter.
The main program can wait for asynchronous tasks to finish by recieving callbacks over localConnection. It then turns these into various events for multiple child components to react to.
The hidden tasker program can send callbacks to the main program using localConnection.
The main program (hopefully) never freezes, so it should always be able to recieve these localConnection callbacks.
x  I can guard against dropped callbacks by checking whether the localConnection "send" succeeded or failed.
	Respond to each message with an "ack" signal to indicate that it succeeded,  because localConnection's "send" is unreliable. It will "succeed" with failed messages.
	If it fails, then enter a loop and wait before re-trying again, using setTimeout() actions.
	Each failure sets up a long setTimeout().  Success simply does nothing, breaking the loop.
	Use 2 localConnection's. One for each direction of communication.

Use localConnection instead of reading and writing files.
Main program should never pause, so it should try to avoid running Zinc commands directly.
Main program maintains the task queue array.
New tasks are added to the end of the array.
The hidden tasker program removes tasks from the beginning of the array.
Main program sends "updateQueue" events to the hidden tasker program, along with the current task queue.
The hidden tasker program also requests "updateQueue" events to recieve the current task queue.
The hidden tasker program sends "removeTask" events to remove a specific command and request an updated queue.
Each command has a UID so that "removeTask" can indicate exactly which command is being removed instead of making any assumptions about which command is "last"

	To hopefully guard against lost localConnection messages, tasker requests the updated queue whenever it becomes idle.
	If the queue remains empty, then it reports that it is idle and waits for the main program to send a queue when a task is added to it.
	localConnection does have some buffering and can tolerate brief delays.

	tasker has 2 states. "idle" and "busy"
	It reports its state to the main program whenever it changes.
	idle:  main will send the current queue to tasker whenever something is added to the queue.
	busy:  tasker will request the current queue when it becomes idle.

	new items are added to the end of the queue.
	tasker removes items from the beginning of the queue, and becomes "busy"
	each command has a UID.
	after each finished task, tasker reports which command was finished, by its UID
	when the tasker's queue becomes empty, tasker reports that it is "idle" and waits for the main program to send an updated queue.


When making changes to the fav_pictures.json, add a delay before saving and have later saveFile data replace earlier data. When the delay finishes, then save the file. This helps prevent needing to interrupt file-saves.

Of course, this data will need to be sent to the tasker in chunks.