Atlas - SDL_haikudialog.cc
Home / ext / SDL / src / dialog / haiku Lines: 1 | Size: 8436 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22extern "C" { 23#include "../SDL_dialog.h" 24#include "../SDL_dialog_utils.h" 25} 26#include "../../core/haiku/SDL_BeApp.h" 27#include "../../video/haiku/SDL_BWin.h" 28 29#include <string> 30#include <vector> 31 32#include <sys/stat.h> 33 34#include <FilePanel.h> 35#include <Entry.h> 36#include <Looper.h> 37#include <Messenger.h> 38#include <Path.h> 39#include <TypeConstants.h> 40 41bool StringEndsWith(const std::string& str, const std::string& end) 42{ 43 return str.size() >= end.size() && !str.compare(str.size() - end.size(), end.size(), end); 44} 45 46std::vector<std::string> StringSplit(const std::string& str, const std::string& split) 47{ 48 std::vector<std::string> result; 49 std::string s = str; 50 size_t pos = 0; 51 52 while ((pos = s.find(split)) != std::string::npos) { 53 result.push_back(s.substr(0, pos)); 54 s = s.substr(pos + split.size()); 55 } 56 57 result.push_back(s); 58 59 return result; 60} 61 62class SDLBRefFilter : public BRefFilter 63{ 64public: 65 SDLBRefFilter(const SDL_DialogFileFilter *filters, int nfilters) : 66 BRefFilter(), 67 m_filters(filters), 68 m_nfilters(nfilters) 69 { 70 } 71 72 virtual bool Filter(const entry_ref *ref, BNode *node, struct stat_beos *stat, const char *mimeType) override 73 { 74 BEntry entry(ref); 75 BPath path; 76 entry.GetPath(&path); 77 std::string result = path.Path(); 78 79 if (!m_filters) 80 return true; 81 82 struct stat info; 83 node->GetStat(&info); 84 if (S_ISDIR(info.st_mode)) 85 return true; 86 87 for (int i = 0; i < m_nfilters; i++) { 88 for (const auto& suffix : StringSplit(m_filters[i].pattern, ";")) { 89 if (StringEndsWith(result, std::string(".") + suffix)) { 90 return true; 91 } 92 } 93 } 94 95 return false; 96 } 97 98private: 99 const SDL_DialogFileFilter * const m_filters; 100 int m_nfilters; 101}; 102 103class CallbackLooper : public BLooper 104{ 105public: 106 CallbackLooper(SDL_DialogFileCallback callback, void *userdata) : 107 m_callback(callback), 108 m_userdata(userdata), 109 m_files(), 110 m_messenger(), 111 m_panel(), 112 m_filter() 113 { 114 } 115 116 ~CallbackLooper() 117 { 118 delete m_messenger; 119 delete m_panel; 120 delete m_filter; 121 } 122 123 void SetToBeFreed(BMessenger *messenger, BFilePanel *panel, SDLBRefFilter *filter) 124 { 125 m_messenger = messenger; 126 m_panel = panel; 127 m_filter = filter; 128 } 129 130 virtual void MessageReceived(BMessage *msg) override 131 { 132 entry_ref file; 133 BPath path; 134 BEntry entry; 135 std::string result; 136 const char *filename; 137 int32 nFiles = 0; 138 139 switch (msg->what) 140 { 141 case B_REFS_RECEIVED: // Open 142 msg->GetInfo("refs", NULL, &nFiles); 143 for (int i = 0; i < nFiles; i++) { 144 msg->FindRef("refs", i, &file); 145 entry.SetTo(&file); 146 entry.GetPath(&path); 147 result = path.Path(); 148 m_files.push_back(result); 149 } 150 break; 151 152 case B_SAVE_REQUESTED: // Save 153 msg->FindRef("directory", &file); 154 entry.SetTo(&file); 155 entry.GetPath(&path); 156 result = path.Path(); 157 result += "/"; 158 msg->FindString("name", &filename); 159 result += filename; 160 m_files.push_back(result); 161 break; 162 163 case B_CANCEL: // Whenever the dialog is closed (Cancel but also after Open and Save) 164 { 165 nFiles = m_files.size(); 166 const char *files[nFiles + 1]; 167 for (int i = 0; i < nFiles; i++) { 168 files[i] = m_files[i].c_str(); 169 } 170 files[nFiles] = NULL; 171 m_callback(m_userdata, files, -1); 172 Quit(); 173 SDL_QuitBeApp(); 174 delete this; 175 } 176 break; 177 178 default: 179 BHandler::MessageReceived(msg); 180 break; 181 } 182 } 183 184private: 185 SDL_DialogFileCallback m_callback; 186 void *m_userdata; 187 std::vector<std::string> m_files; 188 189 // Only to free stuff later 190 BMessenger *m_messenger; 191 BFilePanel *m_panel; 192 SDLBRefFilter *m_filter; 193}; 194 195void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) 196{ 197 SDL_Window *window = (SDL_Window *)SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_WINDOW_POINTER, NULL); 198 SDL_DialogFileFilter *filters = (SDL_DialogFileFilter *)SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, NULL); 199 int nfilters = (int) SDL_GetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, 0); 200 bool many = SDL_GetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, false); 201 const char *location = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_LOCATION_STRING, NULL); 202 const char *title = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_TITLE_STRING, NULL); 203 const char *accept = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_ACCEPT_STRING, NULL); 204 const char *cancel = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_CANCEL_STRING, NULL); 205 206 bool modal = !!window; 207 208 bool save = false; 209 bool folder = false; 210 211 switch (type) { 212 case SDL_FILEDIALOG_SAVEFILE: 213 save = true; 214 break; 215 216 case SDL_FILEDIALOG_OPENFILE: 217 break; 218 219 case SDL_FILEDIALOG_OPENFOLDER: 220 folder = true; 221 break; 222 }; 223 224 if (!SDL_InitBeApp()) { 225 SDL_SetError("Couldn't init Be app: %s", SDL_GetError()); 226 callback(userdata, NULL, -1); 227 return; 228 } 229 230 if (filters) { 231 const char *msg = validate_filters(filters, nfilters); 232 233 if (msg) { 234 SDL_SetError("%s", msg); 235 callback(userdata, NULL, -1); 236 return; 237 } 238 } 239 240 if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) { 241 SDL_SetError("File dialog driver unsupported"); 242 callback(userdata, NULL, -1); 243 return; 244 } 245 246 // No unique_ptr's because they need to survive the end of the function 247 CallbackLooper *looper = new(std::nothrow) CallbackLooper(callback, userdata); 248 BMessenger *messenger = new(std::nothrow) BMessenger(NULL, looper); 249 SDLBRefFilter *filter = new(std::nothrow) SDLBRefFilter(filters, nfilters); 250 251 if (looper == NULL || messenger == NULL || filter == NULL) { 252 delete looper; 253 delete messenger; 254 delete filter; 255 SDL_OutOfMemory(); 256 callback(userdata, NULL, -1); 257 return; 258 } 259 260 BEntry entry; 261 entry_ref entryref; 262 if (location) { 263 entry.SetTo(location); 264 entry.GetRef(&entryref); 265 } 266 267 BFilePanel *panel = new BFilePanel(save ? B_SAVE_PANEL : B_OPEN_PANEL, messenger, location ? &entryref : NULL, folder ? B_DIRECTORY_NODE : B_FILE_NODE, many, NULL, filter, modal); 268 269 if (title) { 270 panel->Window()->SetTitle(title); 271 } 272 273 if (accept) { 274 panel->SetButtonLabel(B_DEFAULT_BUTTON, accept); 275 } 276 277 if (cancel) { 278 panel->SetButtonLabel(B_CANCEL_BUTTON, cancel); 279 } 280 281 if (window) { 282 SDL_BWin *bwin = (SDL_BWin *)(window->internal); 283 panel->Window()->SetLook(B_MODAL_WINDOW_LOOK); 284 panel->Window()->SetFeel(B_MODAL_SUBSET_WINDOW_FEEL); 285 panel->Window()->AddToSubset(bwin); 286 } 287 288 looper->SetToBeFreed(messenger, panel, filter); 289 looper->Run(); 290 panel->Show(); 291} 292[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.