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