1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2008-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // file selection dialogs
17 
18 #ifndef INC_C4FileSelDlg
19 #define INC_C4FileSelDlg
20 
21 #include "gui/C4Gui.h"
22 #include "c4group/C4Components.h"
23 
24 // callback handler for file selection dialog
25 class C4FileSel_BaseCB
26 {
27 public:
28 	C4FileSel_BaseCB() = default;
29 	virtual ~C4FileSel_BaseCB() = default;
30 
31 public:
32 	virtual void OnFileSelected(const char *szFilename) = 0;
33 };
34 
35 template <class CB> class C4FileSel_CBEx : public C4FileSel_BaseCB
36 {
37 public:
38 	typedef void (CB::*FileSelFunc)(const char *szFilename, int32_t idToken);
39 
40 private:
41 	CB *pCBClass;
42 	FileSelFunc SelFunc;
43 	int32_t idToken;
44 public:
OnFileSelected(const char * szFilename)45 	void OnFileSelected(const char *szFilename) override
46 	{ if (pCBClass && SelFunc) (pCBClass->*SelFunc)(szFilename, idToken); }
47 
48 public:
C4FileSel_CBEx(CB * pCBClass,FileSelFunc SelFunc,int32_t idToken)49 	C4FileSel_CBEx(CB * pCBClass, FileSelFunc SelFunc, int32_t idToken) : pCBClass(pCBClass), SelFunc(SelFunc), idToken(idToken) { }
50 };
51 
52 // dialog to select one or more files
53 class C4FileSelDlg : public C4GUI::Dialog
54 {
55 public:
56 	class ListItem : public C4GUI::Control
57 	{
58 	protected:
59 		StdStrBuf sFilename; // full path to file
60 
IsFocusOnClick()61 		bool IsFocusOnClick() override { return false; } // do not focus; keep focus on listbox
62 
63 	public:
64 		ListItem(const char *szFilename);
65 		~ListItem() override;
66 
GetFilename()67 		const char *GetFilename() { return sFilename.getData(); }
68 
69 		// multisel-checkbox-options
IsChecked()70 		virtual bool IsChecked() const { return false; }
SetChecked(bool fChecked)71 		virtual void SetChecked(bool fChecked) {}
IsGrayed()72 		virtual bool IsGrayed() const { return false; }
UserToggleCheck()73 		virtual bool UserToggleCheck() { return false; }
74 	};
75 
76 	class DefaultListItem : public ListItem
77 	{
78 	private:
79 		typedef ListItem BaseClass;
80 		class C4GUI::Icon *pIco; class C4GUI::Label *pLbl;
81 		class C4GUI::CheckBox *pCheck;
82 		class C4KeyBinding *pKeyCheck; // space activates/deactivates selected file
83 		bool fGrayed;
84 
85 	protected:
86 		void UpdateOwnPos() override;
87 
88 	public:
89 		DefaultListItem(const char *szFilename, bool fTruncateExtension, bool fCheckbox, bool fGrayed, C4GUI::Icons eIcon);
90 		~DefaultListItem() override;
91 
92 		bool IsChecked() const override;
93 		void SetChecked(bool fChecked) override;
IsGrayed()94 		bool IsGrayed() const override { return fGrayed; }
95 		bool UserToggleCheck() override;
96 	};
97 
98 private:
99 	typedef C4GUI::Dialog BaseClass;
100 
101 	C4KeyBinding *pKeyRefresh, *pKeyEnterOverride;
102 
103 	C4GUI::ComboBox *pLocationComboBox;
104 	C4GUI::ListBox *pFileListBox;
105 	C4GUI::TextWindow *pSelectionInfoBox;
106 	C4GUI::Button *btnOK;
107 
108 	StdCopyStrBuf sTitle; // dlg title
109 
110 	StdCopyStrBuf sPath; // current path
111 	struct Location
112 	{
113 		StdCopyStrBuf sName;
114 		StdCopyStrBuf sPath;
115 	};
116 	Location *pLocations;
117 	int32_t iLocationCount;
118 	int32_t iCurrentLocationIndex;
119 
120 
121 	ListItem *pSelection;
122 	C4FileSel_BaseCB *pSelCallback;
123 
124 	void UpdateFileList(); // rebuild file listbox from sPath
125 
126 protected:
127 	void OnShown() override;
128 	void UserClose(bool fOK) override; // allow OK only if something is sth is selected
129 	void OnClosed(bool fOK) override; // callback when dlg got closed
130 
GetFileMask()131 	virtual const char *GetFileMask() const { return nullptr; }
IsMultiSelection()132 	virtual bool IsMultiSelection() const { return false; } // if true, files are checked/unchecked using checkboxes
IsItemGrayed(const char * szFilename)133 	virtual bool IsItemGrayed(const char *szFilename) const { return false; }
134 	virtual void UpdateSelection();
HasNoneItem()135 	virtual bool HasNoneItem() const { return false; } // if true, an empty item can be selected
HasPreviewArea()136 	virtual bool HasPreviewArea() const { return true; }
HasExtraOptions()137 	virtual bool HasExtraOptions() const { return false; }
AddExtraOptions(const C4Rect & rcOptionsRect)138 	virtual void AddExtraOptions(const C4Rect &rcOptionsRect) {}
GetFileItemIcon()139 	virtual C4GUI::Icons GetFileItemIcon() const { return C4GUI::Ico_None; }
GetFileSelColWidth()140 	virtual int32_t GetFileSelColWidth() const { return 0; } // width of each file selection element; 0 for default all listbox
141 
OnSelChange(class C4GUI::Element * pEl)142 	void OnSelChange(class C4GUI::Element *pEl) { UpdateSelection(); }
143 	void OnSelDblClick(class C4GUI::Element *pEl);
KeyRefresh()144 	bool KeyRefresh() { UpdateFileList(); return true; }
145 	void OnLocationComboFill(C4GUI::ComboBox_FillCB *pFiller);
146 	bool OnLocationComboSelChange(C4GUI::ComboBox *pForCombo, int32_t idNewSelection);
147 
148 	void AddLocation(const char *szName, const char *szPath); // add location to be shown in dropdown list
149 	void AddCheckedLocation(const char *szName, const char *szPath); // add location to be shown in dropdown list, only if path exists and isn't added yet
150 	int32_t GetCurrentLocationIndex() const;
151 	void SetCurrentLocation(int32_t idx, bool fRefresh);
152 
153 	virtual ListItem *CreateListItem(const char *szFilename);
BeginFileListUpdate()154 	virtual void BeginFileListUpdate() {}
EndFileListUpdate()155 	virtual void EndFileListUpdate() {}
156 
157 public:
158 	C4FileSelDlg(const char *szRootPath, const char *szTitle, C4FileSel_BaseCB *pSelCallback, bool fInitElements=true);
159 	~C4FileSelDlg() override;
160 	void InitElements();
161 
162 	void SetPath(const char *szNewPath, bool fRefresh=true);
163 	void SetSelection(const char *szNewSelection, bool fFilenameOnly);
164 	StdStrBuf GetSelection(const char *szFixedSelection, bool fFilenameOnly) const; // get single selected file for single selection dlg ';'-separated list for multi selection dlg
165 };
166 
167 // dialog to select a player file
168 class C4PlayerSelDlg : public C4FileSelDlg
169 {
170 protected:
GetFileMask()171 	const char *GetFileMask() const override { return C4CFN_PlayerFiles; }
GetFileItemIcon()172 	C4GUI::Icons GetFileItemIcon() const override { return C4GUI::Ico_Player; }
173 
174 public:
175 	C4PlayerSelDlg(C4FileSel_BaseCB *pSelCallback);
176 };
177 
178 // dialog to select definition files
179 class C4DefinitionSelDlg : public C4FileSelDlg
180 {
181 private:
182 	StdStrBuf sFixedSelection; // initial selection which cannot be deselected
183 
184 protected:
185 	void OnShown() override;
GetFileMask()186 	const char *GetFileMask() const override { return C4CFN_DefFiles; }
IsMultiSelection()187 	bool IsMultiSelection() const override { return true; }
188 	bool IsItemGrayed(const char *szFilename) const override;
GetFileItemIcon()189 	C4GUI::Icons GetFileItemIcon() const override { return C4GUI::Ico_Definition; }
190 
191 public:
192 	C4DefinitionSelDlg(C4FileSel_BaseCB *pSelCallback, const char *szFixedSelection);
193 
194 	static bool SelectDefinitions(C4GUI::Screen *pOnScreen, StdStrBuf *pSelection);
195 };
196 
197 // dialog to select portrait files
198 class C4PortraitSelDlg : public C4FileSelDlg
199 {
200 public:
201 	enum { ImagePreviewSize = 100 };
202 
203 private:
204 	class ListItem : public C4FileSelDlg::ListItem
205 	{
206 	private:
207 		bool fError; // loading error
208 		bool fLoaded; // image loaded but not yet scaled
209 		C4FacetSurface fctImage; // portrait, if loaded
210 		C4FacetSurface fctLoadedImage; // image as loaded by background thread. Must be scaled by main thread
211 		StdCopyStrBuf sFilenameLabelText;
212 
213 	protected:
214 		void DrawElement(C4TargetFacet &cgo) override;
215 
216 	public:
217 		ListItem(const char *szFilename);
218 
219 		void Load();
220 	};
221 
222 	// portrait loader thread
223 	class LoaderThread : public StdThread
224 	{
225 	private:
226 		std::list<ListItem *> LoadItems; // items to be loaded by this thread
227 
228 	public:
229 		LoaderThread() = default;
~LoaderThread()230 		~LoaderThread() override { Stop(); }
231 
232 		void ClearLoadItems(); // stops thread
233 		void AddLoadItem(ListItem *pItem); // not to be called when thread is running!
234 
235 	public:
236 		void Execute() override;
237 	};
238 
239 private:
240 	LoaderThread ImageLoader;
241 
242 protected:
243 	void OnClosed(bool fOK) override;
GetFileMask()244 	const char *GetFileMask() const override { return C4CFN_ImageFiles; }
HasNoneItem()245 	bool HasNoneItem() const override { return true; } // if true, a special <none> item can be selected
HasPreviewArea()246 	bool HasPreviewArea() const override { return false; } // no preview area. Preview images directly
GetFileSelColWidth()247 	int32_t GetFileSelColWidth() const override { return ImagePreviewSize; } // width of each file selection element
248 
249 	C4FileSelDlg::ListItem *CreateListItem(const char *szFilename) override;
250 	void BeginFileListUpdate() override;
251 	void EndFileListUpdate() override;
252 
253 	void OnIdle() override;
254 
255 public:
256 	C4PortraitSelDlg(C4FileSel_BaseCB *pSelCallback);
257 
258 	static bool SelectPortrait(C4GUI::Screen *pOnScreen, StdStrBuf *pSelection);
259 };
260 
261 #endif // INC_C4FileSelDlg
262