GUI-FileDialog Designer






4.76/5 (5 votes)
Design unique looking FileDialogs you can include in your own applications
- Download source code - 3.9 MB
- Download GUI-FileDialog samples - 2MB
- Download source images - 2.9 MB
- Download image editing tool - 1.9 MB
The Balad of the Unloved FileDialog
There once was a FileDialog
Who took his task most seriously.
Through the files with never a backlog
He’d proven his navigability.
To others he seemed a pedagogue,
Who with sneers they glared most cynically.
Though their files he kept in catalog
His masters treated him neglectfully.
Fattened records he fetched as might a trained bird-dog
But still they treated him most odiously.
His appearance was clean and never unkempt,
For he presented himself unpretentiously,
Still their regards for him neared mild contempt
Though requests he delivered impeccably
Reporting what was sought on his first attempt
The faithful FileDialog tried ever more diligently
And though Fickle Fate he never did tempt
On he strove for love and sensitivity
Without which he’d never be content
This with ardent fire he swore vociferously
Then one day he realized that his hairstyle
Was perceived most unfashionably
No longer the demur and stately bibliophile
He would ever again want to be
Since his demure aspect was so reviled
Determined he was to cast off his modesty
His old self he molted and left for erstwhile
As he shed his stale clothing like a priest does heterodoxy
Conventions soon he broke with a smile
And among deriding peers he walked with eccentricity
Dressing in stripes and polka-dot
He changed it up episodically
A hat he donned then as an after thought
Off he doffed it very luxuriously
Pulling on chameleon like culottes
He pranced and danced lackadaisically
As if he’d won the Lottery-Jackpot
A great many new friends arrived spontaneously
But it was no wealth of his they sought
For they only loved his endless mutability.
GUI-FileDialog
Granted, Visual Studio FileDialog
s are work-horses that do what they're supposed to. That may be all well and good but there are times when you don't need the versatility of a stately File Explorer Dialog window to interact with the Users of your cool looking App or game. There's no greater mood-killer than a boring old FileDialog
that brings you back to reality. When you're playing a game and you're lost in NeverLand, Narnia or Mordor, you never want to come back down to reality and interact with the same interface that reminds you of the Office or school work you're trying to get away from. If you're distracted living in an alter-world of pixillated slaughter and the long sought treasure is only five Yellow-Moonstones and a Pixie fight away, the last thing you want is to be reminded that you're not really the Fuzzy-Red-Fox you've worked so hard to become. Here's where the standard Visual Studio FileDialog
s can stunt a player's imagination and drive her back to the mundane chores of reality instead of racking up points in that awesome game you put so much time and effort into. Getting players to try your app is hard enough without having to worry about chasing them away with the boring standard interface they use to save the homework they wish they didn't have to think about.
So here you have it, what you never knew you needed, a really cool way to create FileDialog
s of endless variation. The GUI-FileDialog
Designer app allows you to create FileDialog
s using images you either draw yourself or download off the Internet. The only limit to this awesome creative tool is your imagination.
Have a look at this demo.
You can see that the versatility is not lacking. Even though users can't
- edit the names of files already on the hard-drive
- view Extra-Large Icons
- view file details (or reorder files in the list)
The GUI-FileDialog
allows the developer to specify
- use any source image as the basis for their
FileDialog
- select position, size, font and colors of each region independently
- single or multi-file mode
- and search pattern filters
So when you don't want all the features of a File Explorer type FileDialog
, you might just want to play with a GUI-tar or GUI-nea Hen. And at other times, you'll discover that what you really need is a GUI-nea Pig... because sometimes, you just really need a GUI-nea Pig!
I've been working on this project for about a month and a half. Really thought it would only take me a week but that was wishful thinking. Adding features and debugging as I went along, I've used it in several of my other projects and have it running pretty well. There was an issue with the DirectoryTree
not scrolling to the appropriate location when the Collapse/Expand buttons were pressed (or double-skipping whenever the User double-clicked and opened a file folder in the CurrentDirectoryContents
region) that appear in the demo-video above but these issues have been fixed and I'm just too lazy to make another video that reflects those changes. So download the source-code above, load the .fdGUI example files and have a look for yourself.
Using the Code
As the video demonstrates, using the GUI-FileDialog
and including it in your own code is very simple.
- You first design your
GUI-FileDialog
using the GUI-FileDialog Designer app - Then add the FileDialog_Gui.cs file to your project through the Project-Add_Existing_Item menu-selection
- (optional) Add your .fdGUI file (
GUI-FileDialog
you designed) to your project's resources - Declare an instance of the
FileDialog
you need in your code - and load the .fdGUI file you've designed
The code shown below assumes the FileDialog_Gui.cs and your .fdGUI design file have been added to the project:
FileDialog_GUI.OpenFileDialog_GUI ofd = new FileDialog_GUI.OpenFileDialog_GUI();
ofd.Title = "This GUI-nea Pig fetches files";
ofd.MultiSelect = false; // default setting
ofd.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
ofd.GUI_Load(Properties.Resources.FileDialog_GUI_nea_Pig);
if (ofd.ShowDialog() == DialogResult.OK)
{
MessageBox.Show(ofd.FileName);
}
About the Code
The GUI-FileDialog
inherits a PerPixelAlpha Form which allows your form to take the shape and appearance of its background Image. Unfortunately, as I have discovered, PerPixelAlpha
Forms will not allow you to display any objects on the form. You can add TextBox
es and Label
s all you want but your User
won't be able to see them. This can be a problem when you try to use the form for anything that involves any of the copious myriads of objects, widgets and whatsits Microsoft provides for your interactive leisure.
Therefore, all commerce between the Monkey-in-the-Chair and the app has to be carried out using the mouse and two hidden TextBox
es that are Focused alternately depending on which region the User
is busy with. In order to do this, the form is divided into several regions which can be easily and quickly detected whenever your Monkey interacts with the form by moving and clicking the mouse. Here, we rely on a SweepAndPrune algorithm which orders your sub-regions in two lists (horizontal and vertical) and partitions them into sequences of contiguous sub-regions. When you do a search for a point at (x, y), SweepAndPrune
scans through the horizontal list of partitions, finds the one that contains the X requested and returns the list of regions that contain that value (if any such regions exist), then it does the same thing with the Vertical list and compares the results to return the sub-region that contains both the X and the Y of the point you're looking for.
That's SweepAndPrune
, in a nut-shell.
In the case of the GUI-FileDialog
, the SweepAndPrune
class is the work-horse without which this project could not be possible (that and coffee ... lots of coffee). So the Form
itself is first divided into 9 distinct regions and their associated ScrollBars
:
public enum enuRegions
{
Title,
CurrentDirectory,
DirTree,
ContentCurrentDirectory,
UserInput_Label,
UserInput_TextInput,
UserInput_Filter,
UserInput_Confirm,
UserInput_Cancel,
Resize,
_num
};
The class classRegion
defines the area each of these regions occupy on the form in the rectangle
variable rec
as well as Font
, ForegroundColor
and BackgroundColor
. Each region is drawn separately and has an image of itself it keeps ready in the variable bmp
. Title
, CurrentDirectory
and UserInput_Label
are straightforward regions that do not interact with the User, but simply display information that is put to them. The Confirm and Cancel Regions are buttons that react when the Mouse moves over them or they are clicked by the User but by far the most complicated regions are DirectoryTree
, CurrentDirectoryContents
and UserInput_TextInput
which we'll look into in a moment. The form's SweepAndPrune
algorithm not only keeps track of these Regions but also any ScrollBar
s those regions may need and we'll have a look at those in turn.
DirectoryTree
The Directory Tree shows the User where in the tree of directories they are currently exploring. Each item in the DirectoryTree
is both a classButton
(that interacts with the User
) and a classTreeItem
that acts in a way similar to an element in a data tree by pointing to one parent and one, several or no child Tree Item elements. To build the tree, the app first starts in the current directory and recursively tracks its parents and ancestors until it reaches the root-directory while setting each Tree-Item's (sub-directory between the root and current directory) boolean Expanded
variable to true
. From there, it branches forward in a breadth-first-search (BFS) manner into all Expanded
Tree Items while adding the contents of each expanded Tree-Item to their respective child-Tree-Items lists until the visible tree is complete. Since the User determines which Directory is expanded/collapsed as she goes along, every change made must be reflected on the screen but the process of adding Child-Tree-Items only occurs when a previously un-expanded Tree-Item is expanded and its contents needs to be loaded. The contents of Tree-Items are never deleted, nor are they revised to reflect changes made outside your app. Once this is complete, the algorithm counts how many ancestors each Tree-Item has and uses that value to determine each Tree-Item's horizontal tab location when it will later be drawn onto a bitmap.
Before the Directory Tree can be drawn however, an imaginary field is created onto which all the Tree-Items are positioned as if they were drawn onto a Bitmap
. The size of this imagary field is then recorded in szBmp
variable which is used by both of the DirectoryTree
Region's Horizontal and Vertical scroll bars (more about the scroll-bars later). Once all the Tree-Items have been positioned in memory, the CurrentDirectory
is used to determine what information needs to be drawn to the screen. After a bit of magic to determine whether or not either or both Scroll-Bars will need to be drawn (and cut into the space available for the Directory-Tree itself) a Bitmap
is created that is four times the size of the space available for the Region on the output form (50% along all four edges). The Region's Rectangle
variable recVisible
tracks which part of the imagary field is on the screen while a Point
variable ptOffset
adjusts for the fact that the bitmap that is drawn is not the complete imaginary field but only a small portion of it. Which part of that Bitmap
is drawn to the screen is a function of recVisible
and ptOffset
DrawDirTree();
Rectangle recVisible = new Rectangle(regDirTree.ptRecVisible_Offset.X,
regDirTree.ptRecVisible_Offset.Y,
regDirTree.recVisible.Width,
regDirTree.recVisible.Height);
g.DrawImage(regDirTree.bmp, regDirTree.rec, recVisible, GraphicsUnit.Pixel);
Here, DrawDirTree();
ensures regDirTree
's bmp
is up to date (included MouseOver
highlights). Then a rectangular region called recVisible
is defined to source that region's bitmap
. The Region
's recVisible
tracks which part of the Region
's imaginary field is on the screen while this local recVisible
tracks which part of the Region's bmp
image is put to the screen depending on the current value of the Region
's ScrollBar
s.
When the User scrolls along that region, the recVisible
and ptOffset
variables are altered so that the region's bmp
(which only draws a small portion of the entire Directory Tree) can be sampled at the appropriate point in order to display the information requested on the screen. When the User scrolls beyond what is readily available in the bmp
image (beyond 50% of the width of the Region's visible area defined by its rec
variable), another Bitmap
is drawn and the ptOffset
value is reset and we start again.
As the User Expands and Collapses directories in the Directory Tree, the contents of newly expanded Tree-Items are searched on the Hard-Drive and added to their list of Child-Tree-Items. The DirectoryTree
itself expands as the contents are added but they are not removed when the Directories are collapsed again. The data related to each sub-directory is retained once it has been retrieved but the appearance on the screen reflects the User's requests. Therefore, the imaginary field of Tree-Items in memory needs to be rebuilt and the Region's bmp
redrawn whenever a change is made to any of the already visible Tree-Item's Expanded/Collapsed states.
Since the mouse is directly over any Expand/Collapse buttons the User may click, it is not necessary to locate that button in the DirectoryTree
at that time, however, when the User DoubleClick
s a FileFolder
in the CurrentDirectoryContent
Region and expects that folder to be Expanded, the location of the corresponding Tree-Item in the TreeDirectory
must be retrieved in order to determine its location and set the ScrollBar
's value to put that Tree-Item within the visible area. To do this a binary-tree keeps track of the Tree-Items and can be searched using FullPath
names. In this way, when the User does expand a folder while in the CurrentDirectoryContent
Region the Tree-Item is quickly retrieved, its location in the imaginary field determined and used to calculate the appropriate scrollBar Value
which will place that Tree-Item on the screen for the User to see.
Current Directory Contents
The CurrentDirectoryContent
Region is drawn in a fashion similar to the DirectoryTree
but must take into consideration the Icon-Size (display style) the User has selected when creating the buttons for its imagary field. Once the buttons are positioned in the imaginary field, it is drawn using the same scheme as the Directory Tree. The file Icons are retrieved using the code seen here.
Icon icon_File(string strPath)
{
string strExtension = getExtensionFromPath(strPath);
Icon icoRetVal = classFileIcons.Search(strExtension);
if (icoRetVal == null)
{
try
{
icoRetVal = System.Drawing.Icon.ExtractAssociatedIcon(strPath);
}
catch (Exception)
{
}
if (icoRetVal != null)
{
classFileIcons.Insert(cTI.fileInfo.Extension, ref icoRetVal);
}
else
;
}
return icoRetVal;
}
The classFileIcons
holds a static binary-tree which is used to store the icons that have already been found. When an Icon is needed, the binary tree is first searched. Then if the Icon that is sought is not found there, it is extracted using the System.Drawing.Icon.ExtractAssociatedIcon()
function native to Visual Studio and inserted into the tree for later retrieval.
UserInput_TextInput
This is the Region where Users can type the name of the file they want to load. Although the form can detect KeyDown
and KeyUp
events, two TextBoxes
were used to interact with the User when any typing or keyboard operations are required. Focus is always shifted to either of these two TextBoxes
. The first txtInput
is focused when the User selects the UserInput_TextInput
Region and the other is focused the rest of the time. The contents of the txtInput TextBox
are set to the current directory whenever the directory changes, or the name of any file that the User selects in the CurrentDirectoryContent
Region. Whenever the text content of this TextBox
is altered, it's TextChanged
event is triggered and its contents are reflected on the screen.
Each character that is drawn in the UserInput_TextInput
Region is an instance of the classButton
. Its image is stored in the class's binary-tree which has its root element reset to null
whenever the Region's Font
or Color
s are changed. Using the TextRender.MeasureText()
function provides too large an image size for individual alphanumeric characters that need to be squeezed closely together in order to give the appearance of continuous text and not a collection of disjointed images. Therefore, each character's image is first measured by making a string
of 64 samples of the same character. That string
is then measured and the width is divided by the number of samples to give a more accurate result.
public static classCharImage get(char chrSearch)
{
classCharImage cCI_RetVal = search(chrSearch);
if (cCI_RetVal == null)
{
int intNum = 64;
Size szTest = TextRenderer.MeasureText("".PadRight(intNum, chrSearch), fnt);
Size szChar = new Size(szTest.Width / intNum + 1, szTest.Height);
cCI_RetVal = new classCharImage();
cCI_RetVal.chr = chrSearch;
cCI_RetVal.bmp = new Bitmap(szChar.Width, szChar.Height);
using (Graphics g = Graphics.FromImage(cCI_RetVal.bmp))
{
g.FillRectangle(brBackgroundIdle, 0, 0, szChar.Width, szChar.Height);
g.DrawString(chrSearch.ToString(), fnt, brForegroundIdle, new Point(0, 0));
}
cCI_RetVal.bmpHighlight = new Bitmap(szChar.Width, szChar.Height);
using (Graphics g = Graphics.FromImage(cCI_RetVal.bmpHighlight))
{
g.FillRectangle(brBackgroundHighlight, 0, 0, szChar.Width, szChar.Height);
g.DrawString(chrSearch.ToString(), fnt, brForegroundHighlight, new Point(0, 0));
}
Insert(ref cCI_RetVal);
}
return cCI_RetVal;
}
In the code above, you can see that the character's image is first searched in the static binary-tree. When it is not located there, it is drawn for the first time since the most recent changes were made to its appearance and inserted into the tree before being returned to the calling function. As the screen-time of a FileDialog
rarely exceeds the time it takes for your niece's guinea-pig to chew its way through a leaf of lettuce, the life of a non-static binary-tree would be short. Since a designer's apps are likely to use the same fonts and colors for their FileDialog
's TextInput
Regions (if they use more than one design) the static
tree will still be valid the next time the User
decides to save or load whatever adventure they've lost themselves in.
ScrollBars
ScrollBar
s are similar to Regions in that they are mapped out in the same SweepAndPrune
field that defines the form as a whole but they are ScrollBar
s attached to a Region
and not Region
s in themselves. The classScrollBar
has Minimum
, Maximum
and Value
variables just as the ScrollBar
s native to the language and they behave in a way your Users will be used to and find intuitive. The Value
changes affect the ptOffset
Point
variable mentioned earlier and when that Point
variable's values exceed a given limit then the Region's bmp sample source image needs to be redrawn.
History
It took exactly one month to get to this point but it seems longer. Though there are plenty of features left to implement and improve, since I have recently started new projects on top of unfinished projects that I've been neglecting as they simmer on a back-burner, its good to be able to wash my hands of this one and go back to stuff I've left unattended for so long. You might be interested to know, there's a Picture Jigsaw Puzzle Generator game in the works. That project is advanced enough that at the end of my day I can relax and play it for a half hour. That'll probably be the next thing I publish so, until then, ski-doo safe, eh!