1 //------------------------------------------------------------------------------
2 // emFileSelectionBox.h
3 //
4 // Copyright (C) 2015-2016 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20 
21 #ifndef emFileSelectionBox_h
22 #define emFileSelectionBox_h
23 
24 #ifndef emCheckBox_h
25 #include <emCore/emCheckBox.h>
26 #endif
27 
28 #ifndef emListBox_h
29 #include <emCore/emListBox.h>
30 #endif
31 
32 #ifndef emTextField_h
33 #include <emCore/emTextField.h>
34 #endif
35 
36 
37 //==============================================================================
38 //============================= emFileSelectionBox =============================
39 //==============================================================================
40 
41 class emFileSelectionBox : public emBorder {
42 
43 public:
44 
45 	// Class for a file selection box. This allows the user to walk through
46 	// the file system, view the contents of a directory, and select one or
47 	// optionally more files in it. He may also enter a new file name. The
48 	// file selection box is an emBorder whith the following child panels:
49 	//  - An editable text field for the path of the directory.
50 	//  - A check box for switching the showing of hidden files on and off.
51 	//  - A list box which shows the contents of the directory. It has one
52 	//    item for each file or sub-directory, and the item ".." for the
53 	//    parent directory. Each item shows the name and an icon (if it's a
54 	//    directory) or preview (if it's a file).
55 	//  - An editable text field for the file name.
56 	//  - A list box for file type filters.
57 
58 	emFileSelectionBox(
59 		ParentArg parent, const emString & name,
60 		const emString & caption=emString(),
61 		const emString & description=emString(),
62 		const emImage & icon=emImage()
63 	);
64 		// Constructor.
65 		// Arguments:
66 		//   parent      - Parent for this panel (emPanel or emView).
67 		//   name        - The name for this panel.
68 		//   caption     - The label's caption, or empty.
69 		//   description - The label's description, or empty.
70 		//   icon        - The label's icon, or empty.
71 
72 	virtual ~emFileSelectionBox();
73 		// Destructor.
74 
75 	bool IsMultiSelectionEnabled() const;
76 		// Ask whether the user is allowed to select multiple entries.
77 
78 	void SetMultiSelectionEnabled(bool enabled=true);
79 		// Set whether the user is allowed to select multiple entries.
80 		// The default is false.
81 
82 	const emString & GetParentDirectory() const;
83 		// Get the absolute path of the parent directory.
84 
85 	void SetParentDirectory(const emString & parentDirectory);
86 		// Set the parent directory.
87 
88 	emString GetSelectedName() const;
89 		// Get the name of the selected entry. If nothing is selected,
90 		// an empty string is returned. If multiple entries are
91 		// selected, the first one is returned.
92 
93 	const emArray<emString> & GetSelectedNames() const;
94 		// Get an array with the names of all the selected entries.
95 
96 	void SetSelectedName(const emString & selectedName);
97 		// Select a single entry. An empty string means to clear the
98 		// selection.
99 
100 	void SetSelectedNames(const emArray<emString> & selectedNames);
101 		// Select any number of entries.
102 
103 	void ClearSelection();
104 		// Clear the selection.
105 
106 	emString GetSelectedPath() const;
107 		// Get the absolute path of the selected entry. If nothing is
108 		// selected, the absolute path of the parent directory is
109 		// returned. If multiple entries are selected, the absolute path
110 		// of the first selected one is returned.
111 
112 	void SetSelectedPath(const emString & selectedPath);
113 		// Change the parent directory and the selection in one call. If
114 		// the given path is a directory, the parent directory is set to
115 		// that directory, and the selection is cleared. Otherwise the
116 		// parent directory is set to the parent path of the given path,
117 		// and the selection is set to the final name in the given path.
118 
119 	const emSignal & GetSelectionSignal() const;
120 		// Signaled when the selection or the parent directory has
121 		// changed.
122 
123 	const emArray<emString> & GetFilters() const;
124 		// Get the file type filters. See SetFilters for more.
125 
126 	void SetFilters(const emArray<emString> & filters);
127 		// Set the file type filters, from which the user can choose
128 		// one. The default is to have no filters, which means to show
129 		// all entries. If no filter is selected at the time of calling
130 		// SetFilters with a non-empty array, the first filter is
131 		// selected automatically. Each filter is a string of the form:
132 		//   <description>'('<pattern>[<separator><pattern>...]')'
133 		// With:
134 		//   <description> = Any text.
135 		//   <pattern>     = A pattern for the file name. The only supported
136 		//                   meta character is an asterisk ('*'). It
137 		//                   means to match any sequence (including the
138 		//                   empty sequence). Everything else is taken
139 		//                   literal, but case-insensitive.
140 		//   <separator>   = A space char, a semicolon, a comma, or a
141 		//                   vertical bar.
142 		// Examples:
143 		//   "All files (*)"
144 		//   "Targa files (*.tga)"
145 		//   "HTML files (*.htm *.html)"
146 
147 	int GetSelectedFilterIndex() const;
148 		// Get the index of the selected filter, or -1 if none is
149 		// selected.
150 
151 	void SetSelectedFilterIndex(int selectedFilterIndex);
152 		// Set the index of the selected filter. -1 means to select none.
153 
154 	bool AreHiddenFilesShown() const;
155 		// Ask whether hidden files are shown.
156 
157 	void SetHiddenFilesShown(bool hiddenFilesShown=true);
158 		// Set whether hidden files are shown. The default is false.
159 
160 	const emSignal & GetFileTriggerSignal() const;
161 		// This signal is signaled when the user double-clicks an item
162 		// or presses enter in the name field - but only if it is not a
163 		// directory. (If it is a directory, the parent directory is
164 		// changed instead of sending the signal). The associated name
165 		// can be get with GetTriggeredFileName().
166 
167 	const emString & GetTriggeredFileName() const;
168 		// Get the name of the file which was triggered by a
169 		// double-click or enter key press.
170 
171 	void TriggerFile(const emString & name);
172 		// Trigger a file name programmatically.
173 
174 	void EnterSubDir(const emString & name);
175 		// Enter a sub-directory programmatically. This is like
176 		// SetParentDirectory, but the given string is the name of a
177 		// sub-directory instead of a path, and some checks are
178 		// performed whether it is really a directory and whether it is
179 		// readable.
180 
181 	bool IsParentDirFieldHidden() const;
182 		// Ask whether the text field for the parent directory is
183 		// hidden.
184 
185 	void SetParentDirFieldHidden(bool parentDirFieldHidden=true);
186 		// Set whether to hide the text field for the parent directory.
187 		// The default is false.
188 
189 	bool IsHiddenCheckBoxHidden() const;
190 		// Ask whether the "show hidden files" check box is hidden.
191 
192 	void SetHiddenCheckBoxHidden(bool hiddenCheckBoxHidden=true);
193 		// Set whether to hide the "show hidden files" check box. The
194 		// default is false.
195 
196 	bool IsNameFieldHidden() const;
197 		// Ask whether the text field for the name is hidden.
198 
199 	void SetNameFieldHidden(bool nameFieldHidden=true);
200 		// Set whether to hide the text field for the name. The default
201 		// is false.
202 
203 	bool IsFilterHidden() const;
204 		// Ask whether the list box for the filters is hidden.
205 
206 	void SetFilterHidden(bool filterHidden=true);
207 		// Set whether to hide the list box for the filters. The default
208 		// is false.
209 
210 protected:
211 
212 	virtual bool Cycle();
213 	virtual void Input(emInputEvent & event, const emInputState & state,
214 	                   double mx, double my);
215 	virtual void AutoExpand();
216 	virtual void AutoShrink();
217 	virtual void LayoutChildren();
218 
219 private:
220 
221 	void InvalidateListing();
222 	void ReloadListing();
223 	void SelectionToListBox();
224 	void SelectionFromListBox();
225 
226 	static int CompareNames(
227 		const emString * name1, const emString * name2, void * context
228 	);
229 
230 	static bool MatchFileNameFilter(const char * fileName, const char * filter);
231 	static bool MatchFileNamePattern(const char * fileName, const char * pattern,
232 	                                 const char * patternEnd);
233 
234 	class FilesListBox;
235 	class FileItemPanel;
236 	class FileOverlayPanel;
237 	friend class FilesListBox;
238 	friend class FileItemPanel;
239 
240 	class FilesListBox : public emListBox {
241 	public:
242 		FilesListBox(emFileSelectionBox & parent, const emString & name);
243 		virtual ~FilesListBox();
244 		emFileSelectionBox & GetFileSelectionBox() const;
245 		const emImage & GetDirImage() const;
246 		const emImage & GetDirUpImage() const;
247 	protected:
248 		virtual void CreateItemPanel(const emString & name, int itemIndex);
249 	};
250 
251 	class FileItemPanel : public emPanel, public emListBox::ItemPanelInterface {
252 	public:
253 		FileItemPanel(FilesListBox & listBox, const emString & name, int itemIndex);
254 		virtual ~FileItemPanel();
255 	protected:
256 		virtual void Notice(NoticeFlags flags);
257 		virtual void Input(emInputEvent & event, const emInputState & state,
258 		                   double mx, double my);
259 		virtual bool IsOpaque() const;
260 		virtual void Paint(const emPainter & painter, emColor canvasColor) const;
261 		virtual void AutoExpand();
262 		virtual void AutoShrink();
263 		virtual void LayoutChildren();
264 		virtual void ItemTextChanged();
265 		virtual void ItemDataChanged();
266 		virtual void ItemSelectionChanged();
267 	private:
268 		emColor GetBgColor() const;
269 		emColor GetFgColor() const;
270 		friend class FileOverlayPanel;
271 		FilesListBox & ListBox;
272 		emPanel * FilePanel;
273 		emPanel * OverlayPanel;
274 	};
275 
276 	class FileOverlayPanel : public emPanel {
277 	public:
278 		FileOverlayPanel(FileItemPanel & parent, const emString & name);
279 		virtual ~FileOverlayPanel();
280 	protected:
281 		virtual void Input(emInputEvent & event, const emInputState & state,
282 		                   double mx, double my);
283 	};
284 
285 	struct FileItemData {
286 		bool IsDirectory;
287 		bool IsReadable;
288 		bool IsHidden;
289 	};
290 
291 	bool MultiSelectionEnabled;
292 	emString ParentDir;
293 	emArray<emString> SelectedNames;
294 	emSignal SelectionSignal;
295 	emArray<emString> Filters;
296 	int SelectedFilterIndex;
297 	bool HiddenFilesShown;
298 
299 	emSignal FileTriggerSignal;
300 	emString TriggeredFileName;
301 
302 	bool ParentDirFieldHidden;
303 	bool HiddenCheckBoxHidden;
304 	bool NameFieldHidden;
305 	bool FilterHidden;
306 
307 	emTextField * ParentDirField;
308 	emCheckBox * HiddenCheckBox;
309 	FilesListBox * FilesLB;
310 	emTextField * NameField;
311 	emListBox * FiltersLB;
312 
313 	bool ListingInvalid;
314 };
315 
IsMultiSelectionEnabled()316 inline bool emFileSelectionBox::IsMultiSelectionEnabled() const
317 {
318 	return MultiSelectionEnabled;
319 }
320 
GetParentDirectory()321 inline const emString & emFileSelectionBox::GetParentDirectory() const
322 {
323 	return ParentDir;
324 }
325 
GetSelectedNames()326 inline const emArray<emString> & emFileSelectionBox::GetSelectedNames() const
327 {
328 	return SelectedNames;
329 }
330 
GetSelectionSignal()331 inline const emSignal & emFileSelectionBox::GetSelectionSignal() const
332 {
333 	return SelectionSignal;
334 }
335 
GetFilters()336 inline const emArray<emString> & emFileSelectionBox::GetFilters() const
337 {
338 	return Filters;
339 }
340 
GetSelectedFilterIndex()341 inline int emFileSelectionBox::GetSelectedFilterIndex() const
342 {
343 	return SelectedFilterIndex;
344 }
345 
AreHiddenFilesShown()346 inline bool emFileSelectionBox::AreHiddenFilesShown() const
347 {
348 	return HiddenFilesShown;
349 }
350 
GetFileTriggerSignal()351 inline const emSignal & emFileSelectionBox::GetFileTriggerSignal() const
352 {
353 	return FileTriggerSignal;
354 }
355 
GetTriggeredFileName()356 inline const emString & emFileSelectionBox::GetTriggeredFileName() const
357 {
358 	return TriggeredFileName;
359 }
360 
IsParentDirFieldHidden()361 inline bool emFileSelectionBox::IsParentDirFieldHidden() const
362 {
363 	return ParentDirFieldHidden;
364 }
365 
IsHiddenCheckBoxHidden()366 inline bool emFileSelectionBox::IsHiddenCheckBoxHidden() const
367 {
368 	return HiddenCheckBoxHidden;
369 }
370 
IsNameFieldHidden()371 inline bool emFileSelectionBox::IsNameFieldHidden() const
372 {
373 	return NameFieldHidden;
374 }
375 
IsFilterHidden()376 inline bool emFileSelectionBox::IsFilterHidden() const
377 {
378 	return FilterHidden;
379 }
380 
GetFileSelectionBox()381 inline emFileSelectionBox & emFileSelectionBox::FilesListBox::GetFileSelectionBox() const
382 {
383 	return *((emFileSelectionBox*)GetParent());
384 }
385 
GetDirImage()386 inline const emImage & emFileSelectionBox::FilesListBox::GetDirImage() const
387 {
388 	return GetTkResources().ImgDir;
389 }
390 
GetDirUpImage()391 inline const emImage & emFileSelectionBox::FilesListBox::GetDirUpImage() const
392 {
393 	return GetTkResources().ImgDirUp;
394 }
395 
396 
397 #endif
398