summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/dialog/haiku
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/dialog/haiku
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/dialog/haiku')
-rw-r--r--contrib/SDL-3.2.8/src/dialog/haiku/SDL_haikudialog.cc293
1 files changed, 293 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/dialog/haiku/SDL_haikudialog.cc b/contrib/SDL-3.2.8/src/dialog/haiku/SDL_haikudialog.cc
new file mode 100644
index 0000000..d60e343
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/dialog/haiku/SDL_haikudialog.cc
@@ -0,0 +1,293 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
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 char* err = SDL_strdup(SDL_GetError());
226 SDL_SetError("Couldn't init Be app: %s", err);
227 SDL_free(err);
228 callback(userdata, NULL, -1);
229 return;
230 }
231
232 if (filters) {
233 const char *msg = validate_filters(filters, nfilters);
234
235 if (msg) {
236 SDL_SetError("%s", msg);
237 callback(userdata, NULL, -1);
238 return;
239 }
240 }
241
242 if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) {
243 SDL_SetError("File dialog driver unsupported");
244 callback(userdata, NULL, -1);
245 return;
246 }
247
248 // No unique_ptr's because they need to survive the end of the function
249 CallbackLooper *looper = new(std::nothrow) CallbackLooper(callback, userdata);
250 BMessenger *messenger = new(std::nothrow) BMessenger(NULL, looper);
251 SDLBRefFilter *filter = new(std::nothrow) SDLBRefFilter(filters, nfilters);
252
253 if (looper == NULL || messenger == NULL || filter == NULL) {
254 SDL_free(looper);
255 SDL_free(messenger);
256 SDL_free(filter);
257 SDL_OutOfMemory();
258 callback(userdata, NULL, -1);
259 return;
260 }
261
262 BEntry entry;
263 entry_ref entryref;
264 if (location) {
265 entry.SetTo(location);
266 entry.GetRef(&entryref);
267 }
268
269 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);
270
271 if (title) {
272 panel->Window()->SetTitle(title);
273 }
274
275 if (accept) {
276 panel->SetButtonLabel(B_DEFAULT_BUTTON, accept);
277 }
278
279 if (cancel) {
280 panel->SetButtonLabel(B_CANCEL_BUTTON, cancel);
281 }
282
283 if (window) {
284 SDL_BWin *bwin = (SDL_BWin *)(window->internal);
285 panel->Window()->SetLook(B_MODAL_WINDOW_LOOK);
286 panel->Window()->SetFeel(B_MODAL_SUBSET_WINDOW_FEEL);
287 panel->Window()->AddToSubset(bwin);
288 }
289
290 looper->SetToBeFreed(messenger, panel, filter);
291 looper->Run();
292 panel->Show();
293}