plusui-native-core 0.1.102 → 0.1.104
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Core/Features/API/Connect_API.ts +62 -146
- package/Core/Features/API/filedrop-api.ts +12 -1
- package/Core/Features/API/index.ts +3 -4
- package/Core/Features/App/app.cpp +32 -32
- package/Core/Features/Connection/README.md +176 -52
- package/Core/Features/Connection/connect.ts +136 -21
- package/Core/Features/FileDrop/filedrop.ts +139 -36
- package/Core/Features/Keyboard/keyboard.cpp +218 -189
- package/Core/Features/Keyboard/keyboard.ts +100 -31
- package/Core/Features/Keyboard/keyboard_linux.cpp +226 -0
- package/Core/Features/Keyboard/keyboard_macos.cpp +220 -0
- package/Core/Features/Keyboard/keyboard_windows.cpp +56 -0
- package/Core/Features/Window/webview.cpp +248 -57
- package/Core/Features/Window/webview.ts +1 -1
- package/Core/Features/Window/window.cpp +433 -63
- package/Core/include/plusui/api.hpp +2 -2
- package/Core/include/plusui/app.hpp +41 -41
- package/Core/include/plusui/connect.hpp +125 -81
- package/Core/include/plusui/window.hpp +38 -40
- package/package.json +1 -1
|
@@ -25,47 +25,47 @@ private:
|
|
|
25
25
|
std::unique_ptr<Impl> pImpl;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
class App::Builder {
|
|
29
|
-
public:
|
|
30
|
-
struct Config {
|
|
31
|
-
std::string title = "PlusUI App";
|
|
32
|
-
int width = 1200;
|
|
33
|
-
int height = 800;
|
|
34
|
-
bool resizable = true;
|
|
35
|
-
bool devtools = true;
|
|
36
|
-
std::string trayIconPath;
|
|
37
|
-
std::string trayTooltip;
|
|
38
|
-
bool alwaysOnTop = false;
|
|
39
|
-
bool centered = true;
|
|
40
|
-
bool transparent = false;
|
|
41
|
-
bool decorations = true;
|
|
42
|
-
bool skipTaskbar = false;
|
|
43
|
-
bool scrollbars = true;
|
|
44
|
-
bool
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
Builder();
|
|
48
|
-
|
|
49
|
-
Builder &title(const std::string &t);
|
|
50
|
-
Builder &width(int w);
|
|
51
|
-
Builder &height(int h);
|
|
52
|
-
Builder &resizable(bool r);
|
|
53
|
-
Builder &devtools(bool d);
|
|
54
|
-
Builder &trayIcon(const std::string &icon);
|
|
55
|
-
Builder &trayTooltip(const std::string &tooltip);
|
|
56
|
-
Builder &alwaysOnTop(bool top);
|
|
57
|
-
Builder ¢ered(bool center);
|
|
58
|
-
Builder &transparent(bool transparent);
|
|
59
|
-
Builder &decorations(bool decorations);
|
|
60
|
-
Builder &skipTaskbar(bool skip);
|
|
61
|
-
Builder &scrollbars(bool show);
|
|
62
|
-
Builder &
|
|
63
|
-
|
|
64
|
-
Window build();
|
|
65
|
-
|
|
66
|
-
private:
|
|
67
|
-
Config config;
|
|
68
|
-
};
|
|
28
|
+
class App::Builder {
|
|
29
|
+
public:
|
|
30
|
+
struct Config {
|
|
31
|
+
std::string title = "PlusUI App";
|
|
32
|
+
int width = 1200;
|
|
33
|
+
int height = 800;
|
|
34
|
+
bool resizable = true;
|
|
35
|
+
bool devtools = true;
|
|
36
|
+
std::string trayIconPath;
|
|
37
|
+
std::string trayTooltip;
|
|
38
|
+
bool alwaysOnTop = false;
|
|
39
|
+
bool centered = true;
|
|
40
|
+
bool transparent = false;
|
|
41
|
+
bool decorations = true;
|
|
42
|
+
bool skipTaskbar = false;
|
|
43
|
+
bool scrollbars = true;
|
|
44
|
+
bool fileDrop = true; // Enable OS file drop
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
Builder();
|
|
48
|
+
|
|
49
|
+
Builder &title(const std::string &t);
|
|
50
|
+
Builder &width(int w);
|
|
51
|
+
Builder &height(int h);
|
|
52
|
+
Builder &resizable(bool r);
|
|
53
|
+
Builder &devtools(bool d);
|
|
54
|
+
Builder &trayIcon(const std::string &icon);
|
|
55
|
+
Builder &trayTooltip(const std::string &tooltip);
|
|
56
|
+
Builder &alwaysOnTop(bool top);
|
|
57
|
+
Builder ¢ered(bool center);
|
|
58
|
+
Builder &transparent(bool transparent);
|
|
59
|
+
Builder &decorations(bool decorations);
|
|
60
|
+
Builder &skipTaskbar(bool skip);
|
|
61
|
+
Builder &scrollbars(bool show);
|
|
62
|
+
Builder &fileDrop(bool enable);
|
|
63
|
+
|
|
64
|
+
Window build();
|
|
65
|
+
|
|
66
|
+
private:
|
|
67
|
+
Config config;
|
|
68
|
+
};
|
|
69
69
|
|
|
70
70
|
App::Builder createApp();
|
|
71
71
|
|
|
@@ -6,59 +6,69 @@
|
|
|
6
6
|
#include <string>
|
|
7
7
|
#include <vector>
|
|
8
8
|
|
|
9
|
-
//
|
|
10
|
-
// PlusUI Connect
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
// };
|
|
60
|
-
//
|
|
61
|
-
//
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// PlusUI Connect
|
|
11
|
+
// ============================================================================
|
|
12
|
+
//
|
|
13
|
+
// SEMANTIC SYNTAX. ZERO CONFIG. ALL 5 PATTERNS.
|
|
14
|
+
//
|
|
15
|
+
// IMPORTANT: This is for CUSTOM user-defined communication only!
|
|
16
|
+
// Built-in features (window, clipboard, app, etc.) use their own APIs:
|
|
17
|
+
// window.minimize();
|
|
18
|
+
// clipboard.setText("hello");
|
|
19
|
+
// app.quit();
|
|
20
|
+
//
|
|
21
|
+
// Just write code using connect::namespace.method() syntax for custom
|
|
22
|
+
// frontend ↔ backend communication, then run `plusui connect`.
|
|
23
|
+
//
|
|
24
|
+
// Patterns are auto-detected from your code:
|
|
25
|
+
//
|
|
26
|
+
// connect::user.handleFetch = [](const json& p) -> json { ... }; // CALL
|
|
27
|
+
// connect::app.notify({{"msg", "Hello!"}}); // FIRE
|
|
28
|
+
// connect::files.onUpload = [](const json& p) { ... }; // EVENT
|
|
29
|
+
//
|
|
30
|
+
// Custom channels are auto-generated by `plusui connect`.
|
|
31
|
+
//
|
|
32
|
+
// ============================================================================
|
|
33
|
+
// THE 5 COMMUNICATION PATTERNS
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// ALL PATTERNS WORK BIDIRECTIONALLY - frontend ↔ backend
|
|
36
|
+
// ============================================================================
|
|
37
|
+
//
|
|
38
|
+
// 1. REQUEST-RESPONSE (Call)
|
|
39
|
+
// Frontend → Backend:
|
|
40
|
+
// const user = await connect.user.fetch(123);
|
|
41
|
+
// connect::user.handleFetch = [](const json& p) -> json { ... };
|
|
42
|
+
// Backend → Frontend:
|
|
43
|
+
// auto result = connect.call("ui.handlePrompt", {{"msg", "Hi"}});
|
|
44
|
+
// connect.ui.handlePrompt = async (data) => { ... return result; };
|
|
45
|
+
//
|
|
46
|
+
// 2. SIMPLEX (Fire & Forget) — One-way, no response expected
|
|
47
|
+
// Frontend → Backend:
|
|
48
|
+
// connect.files.upload({ file: myFile })
|
|
49
|
+
// connect::files.onUpload = [](const json& p) { ... };
|
|
50
|
+
// Backend → Frontend:
|
|
51
|
+
// connect::app.notify({{"msg", "Update complete!"}});
|
|
52
|
+
// connect.app.onNotify((msg) => toast.success(msg));
|
|
53
|
+
//
|
|
54
|
+
// 3. PUBLISH-SUBSCRIBE (One-to-Many) — Broadcast to multiple listeners
|
|
55
|
+
// Backend → Frontend:
|
|
56
|
+
// connect::sensors.publishTemperature({{72.5}});
|
|
57
|
+
// connect.sensors.onTemperature(cb1); connect.sensors.onTemperature(cb2);
|
|
58
|
+
// Frontend → Backend:
|
|
59
|
+
// connect.auth.login({ user: "john" });
|
|
60
|
+
// connect::auth.onLogin = [](const json& p) { ... };
|
|
61
|
+
//
|
|
62
|
+
// 4. FULL-DUPLEX (Bidirectional Stream) — Continuous both ways
|
|
63
|
+
// Frontend sends chunks, backend sends progress
|
|
64
|
+
// connect.files.onChunk(chunk); connect.files.onProgress(cb);
|
|
65
|
+
// connect::files.onChunk = [](json) { ... }; connect::files.progress({{...}});
|
|
66
|
+
//
|
|
67
|
+
// 5. HALF-DUPLEX (State Sync) — Both sides can update, one at a time
|
|
68
|
+
// connect.settings.setTheme("dark"); connect.settings.onThemeChange(cb);
|
|
69
|
+
// connect::settings.onSetTheme = [](json) { ... }; connect::settings.themeChange({{...}});
|
|
70
|
+
//
|
|
71
|
+
// ============================================================================
|
|
62
72
|
|
|
63
73
|
namespace plusui {
|
|
64
74
|
|
|
@@ -107,7 +117,7 @@ public:
|
|
|
107
117
|
};
|
|
108
118
|
|
|
109
119
|
// ============================================================
|
|
110
|
-
// Channel — single-name channel object
|
|
120
|
+
// Channel — single-name channel object (legacy / backward compat)
|
|
111
121
|
//
|
|
112
122
|
// Mirror of the TypeScript createChannel() object:
|
|
113
123
|
// download.on([](const json& p) { ... });
|
|
@@ -178,10 +188,6 @@ public:
|
|
|
178
188
|
Feature feature(const std::string &scope) { return Feature(this, scope); }
|
|
179
189
|
|
|
180
190
|
// Create a named channel object — mirrors TypeScript createChannel('name')
|
|
181
|
-
// Returns by value; store as a member or local:
|
|
182
|
-
// auto download = connect.channel("download");
|
|
183
|
-
// download.on([](const json& p) { ... });
|
|
184
|
-
// download.emit({{"progress", 50}});
|
|
185
191
|
Channel channel(const std::string &name) { return Channel(this, name); }
|
|
186
192
|
|
|
187
193
|
// Request/response helper for call primitive
|
|
@@ -205,12 +211,11 @@ public:
|
|
|
205
211
|
|
|
206
212
|
/**
|
|
207
213
|
* emit() - Send a message to the frontend
|
|
208
|
-
*
|
|
209
|
-
* Works for all 5
|
|
210
|
-
* -
|
|
211
|
-
* - CALL:
|
|
212
|
-
* - STREAM: emit("updates", {{"value", x}}) // call repeatedly
|
|
213
|
-
* - QUERY: emit("result", item) // call for each result
|
|
214
|
+
*
|
|
215
|
+
* Works for all 5 communication patterns:
|
|
216
|
+
* - SIMPLEX: emit("notification", {{"msg", "Hi!"}})
|
|
217
|
+
* - CALL RESPONSE: emitResult(id, name, payload)
|
|
218
|
+
* - STREAM/PUB-SUB: emit("updates", {{"value", x}}) // call repeatedly
|
|
214
219
|
* - STATE: emit("theme", {{"mode", "dark"}})
|
|
215
220
|
*/
|
|
216
221
|
void emit(const std::string &name, const nlohmann::json &payload) {
|
|
@@ -227,6 +232,32 @@ public:
|
|
|
227
232
|
emitEnvelope("error", name, nlohmann::json::object(), id, message);
|
|
228
233
|
}
|
|
229
234
|
|
|
235
|
+
/**
|
|
236
|
+
* call() - Make a call to the frontend and wait for response
|
|
237
|
+
*
|
|
238
|
+
* Enables bidirectional request/response:
|
|
239
|
+
* Backend: auto answer = connect.call("ui.promptUser", {{"msg", "Sure?"}});
|
|
240
|
+
* Frontend: connect.ui.handlePromptUser = async (data) => { ... return result; };
|
|
241
|
+
*/
|
|
242
|
+
void call(const std::string &name, const nlohmann::json &payload,
|
|
243
|
+
std::function<void(const nlohmann::json &)> onResult = nullptr,
|
|
244
|
+
std::function<void(const std::string &)> onError = nullptr) {
|
|
245
|
+
auto id = std::to_string(std::chrono::steady_clock::now().time_since_epoch().count());
|
|
246
|
+
|
|
247
|
+
if (onResult || onError) {
|
|
248
|
+
// Store pending callback for when frontend responds
|
|
249
|
+
on(name + ".__result__." + id, [this, id, name, onResult, onError](const nlohmann::json &p) {
|
|
250
|
+
if (p.contains("error") && onError) {
|
|
251
|
+
onError(p["error"].get<std::string>());
|
|
252
|
+
} else if (onResult) {
|
|
253
|
+
onResult(p.value("payload", nlohmann::json::object()));
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
emitEnvelope("call", name, payload, id);
|
|
259
|
+
}
|
|
260
|
+
|
|
230
261
|
// Parse and dispatch incoming messages from frontend
|
|
231
262
|
void dispatchMessage(const std::string &message) {
|
|
232
263
|
try {
|
|
@@ -276,6 +307,25 @@ public:
|
|
|
276
307
|
return;
|
|
277
308
|
}
|
|
278
309
|
|
|
310
|
+
if (kind == "result" || kind == "error") {
|
|
311
|
+
// Response from a frontend call — dispatch to pending listeners
|
|
312
|
+
std::string resultKey = name + ".__result__." + id;
|
|
313
|
+
auto listenersIt = eventHandlers.find(resultKey);
|
|
314
|
+
if (listenersIt != eventHandlers.end()) {
|
|
315
|
+
nlohmann::json resultPayload;
|
|
316
|
+
if (kind == "error") {
|
|
317
|
+
resultPayload["error"] = envelope.value("error", "Unknown error");
|
|
318
|
+
} else {
|
|
319
|
+
resultPayload["payload"] = payload;
|
|
320
|
+
}
|
|
321
|
+
for (const auto &listener : listenersIt->second) {
|
|
322
|
+
listener(resultPayload);
|
|
323
|
+
}
|
|
324
|
+
eventHandlers.erase(resultKey);
|
|
325
|
+
}
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
|
|
279
329
|
if (kind == "sub") {
|
|
280
330
|
auto subIt = subscriptionHandlers.find(name);
|
|
281
331
|
if (subIt != subscriptionHandlers.end()) {
|
|
@@ -325,23 +375,17 @@ protected:
|
|
|
325
375
|
|
|
326
376
|
/**
|
|
327
377
|
* handleMessage() - Receive messages from the frontend
|
|
328
|
-
*
|
|
378
|
+
*
|
|
329
379
|
* Override this to handle incoming messages. This is your "on()" equivalent.
|
|
330
|
-
*
|
|
331
|
-
*
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
*
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
* void handleMessage(const std::string& name, const nlohmann::json& data) override {
|
|
340
|
-
* if (name == "greet") {
|
|
341
|
-
* auto userName = data["name"].get<std::string>();
|
|
342
|
-
* emit("greeting", {{"message", "Hello " + userName}});
|
|
343
|
-
* }
|
|
344
|
-
* }
|
|
380
|
+
*
|
|
381
|
+
* For the new semantic API, prefer using the generated connect:: namespace
|
|
382
|
+
* instead of overriding this method:
|
|
383
|
+
*
|
|
384
|
+
* connect::user.handleFetch = [](const json& p) -> json {
|
|
385
|
+
* return database.getUser(p["id"]);
|
|
386
|
+
* };
|
|
387
|
+
*
|
|
388
|
+
* This method remains for backward compatibility and catch-all handling.
|
|
345
389
|
*/
|
|
346
390
|
virtual void handleMessage(const std::string &name,
|
|
347
391
|
const nlohmann::json &payload) {
|
|
@@ -352,7 +396,7 @@ protected:
|
|
|
352
396
|
|
|
353
397
|
void bindConnect(Window &window, Connect &connect);
|
|
354
398
|
|
|
355
|
-
// Legacy
|
|
399
|
+
// Legacy aliases for backwards compatibility
|
|
356
400
|
using Bridge = Connect;
|
|
357
401
|
using Connection = Connect;
|
|
358
402
|
|
|
@@ -11,46 +11,44 @@ namespace plusui {
|
|
|
11
11
|
|
|
12
12
|
class TrayManager;
|
|
13
13
|
|
|
14
|
-
struct WindowConfig {
|
|
15
|
-
// Window properties
|
|
16
|
-
std::string title = "PlusUI Window";
|
|
17
|
-
int x = -1;
|
|
18
|
-
int y = -1;
|
|
19
|
-
int width = 800;
|
|
20
|
-
int height = 600;
|
|
21
|
-
int minWidth = 100;
|
|
22
|
-
int minHeight = 100;
|
|
23
|
-
int maxWidth = -1;
|
|
24
|
-
int maxHeight = -1;
|
|
25
|
-
bool resizable = true;
|
|
26
|
-
bool minimizable = true;
|
|
27
|
-
bool maximizable = true;
|
|
28
|
-
bool closable = true;
|
|
29
|
-
bool alwaysOnTop = false;
|
|
30
|
-
bool center = true;
|
|
31
|
-
bool frame = true;
|
|
32
|
-
bool transparent = false;
|
|
33
|
-
bool decorations = true;
|
|
34
|
-
bool skipTaskbar = false;
|
|
35
|
-
double opacity = 1.0;
|
|
36
|
-
bool fullscreen = false;
|
|
37
|
-
bool
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// WebView properties
|
|
41
|
-
std::string userAgent = "";
|
|
42
|
-
bool devtools = true;
|
|
43
|
-
bool contextMenu = true;
|
|
44
|
-
bool javascript = true;
|
|
45
|
-
bool webSecurity = true;
|
|
46
|
-
bool allowFileAccess = false;
|
|
47
|
-
bool allowRemoteContent = true;
|
|
48
|
-
std::string dataPath = "";
|
|
49
|
-
int cacheSize = 100; // MB
|
|
50
|
-
bool scrollbars = true; // Show/hide scrollbars
|
|
51
|
-
|
|
52
|
-
true; // Disable webview drag-drop (usually set by enableFileDrop)
|
|
53
|
-
};
|
|
14
|
+
struct WindowConfig {
|
|
15
|
+
// Window properties
|
|
16
|
+
std::string title = "PlusUI Window";
|
|
17
|
+
int x = -1;
|
|
18
|
+
int y = -1;
|
|
19
|
+
int width = 800;
|
|
20
|
+
int height = 600;
|
|
21
|
+
int minWidth = 100;
|
|
22
|
+
int minHeight = 100;
|
|
23
|
+
int maxWidth = -1;
|
|
24
|
+
int maxHeight = -1;
|
|
25
|
+
bool resizable = true;
|
|
26
|
+
bool minimizable = true;
|
|
27
|
+
bool maximizable = true;
|
|
28
|
+
bool closable = true;
|
|
29
|
+
bool alwaysOnTop = false;
|
|
30
|
+
bool center = true;
|
|
31
|
+
bool frame = true;
|
|
32
|
+
bool transparent = false;
|
|
33
|
+
bool decorations = true;
|
|
34
|
+
bool skipTaskbar = false;
|
|
35
|
+
double opacity = 1.0;
|
|
36
|
+
bool fullscreen = false;
|
|
37
|
+
bool fileDrop = true; // Enable OS file drop (drag files from Explorer/Finder into window)
|
|
38
|
+
bool disableWebviewDragDrop = true; // Disable browser HTML drag-drop (auto-set by fileDrop)
|
|
39
|
+
|
|
40
|
+
// WebView properties
|
|
41
|
+
std::string userAgent = "";
|
|
42
|
+
bool devtools = true;
|
|
43
|
+
bool contextMenu = true;
|
|
44
|
+
bool javascript = true;
|
|
45
|
+
bool webSecurity = true;
|
|
46
|
+
bool allowFileAccess = false;
|
|
47
|
+
bool allowRemoteContent = true;
|
|
48
|
+
std::string dataPath = "";
|
|
49
|
+
int cacheSize = 100; // MB
|
|
50
|
+
bool scrollbars = true; // Show/hide scrollbars
|
|
51
|
+
};
|
|
54
52
|
|
|
55
53
|
struct WindowState {
|
|
56
54
|
int x = 0;
|