From 6c20eeb0629847623de6f51abada707d0d62fdc2 Mon Sep 17 00:00:00 2001 From: kodecheff Date: Tue, 21 Mar 2023 14:41:50 +0100 Subject: [PATCH 1/6] Update main branch --- CONTRIBUTING.md | 2 +- data/app.gschema.xml | 6 + re.sonny.Workbench.Devel.json | 25 +- re.sonny.Workbench.json | 4 +- src/IconLibrary/main.blp | 14 +- src/Library/Library.js | 9 + src/Library/demos/Box/main.blp | 203 ++++++++++++++++ src/Library/demos/Box/main.css | 12 + src/Library/demos/Box/main.js | 106 +++++++++ src/Library/demos/Box/main.json | 9 + src/Library/demos/Calendar/main.blp | 25 ++ src/Library/demos/Calendar/main.js | 22 ++ src/Library/demos/Calendar/main.json | 10 + src/Library/demos/Color Dialog/main.blp | 58 +++++ src/Library/demos/Color Dialog/main.js | 42 ++++ src/Library/demos/Color Dialog/main.json | 10 + src/Library/demos/Progress Bar/main.blp | 48 ++++ src/Library/demos/Progress Bar/main.js | 46 ++++ src/Library/demos/Progress Bar/main.json | 10 + src/Library/demos/Text Fields/main.blp | 291 +++++++++++++++++++++++ src/Library/demos/Text Fields/main.js | 102 ++++++++ src/Library/demos/Text Fields/main.json | 10 + src/Library/demos/Welcome/main.blp | 2 +- src/Previewer/Previewer.js | 44 ++-- src/Previewer/crasher.vala | 4 + src/Previewer/utils.js | 108 ++++++++- src/about.js | 5 +- src/actions.js | 2 + src/langs/blueprint/blueprint.js | 10 +- src/lsp/LSPClient.js | 88 ++++--- src/window.blp | 43 ++-- src/window.js | 11 +- 32 files changed, 1271 insertions(+), 110 deletions(-) create mode 100644 src/Library/demos/Box/main.blp create mode 100644 src/Library/demos/Box/main.css create mode 100644 src/Library/demos/Box/main.js create mode 100644 src/Library/demos/Box/main.json create mode 100644 src/Library/demos/Calendar/main.blp create mode 100644 src/Library/demos/Calendar/main.js create mode 100644 src/Library/demos/Calendar/main.json create mode 100644 src/Library/demos/Color Dialog/main.blp create mode 100644 src/Library/demos/Color Dialog/main.js create mode 100644 src/Library/demos/Color Dialog/main.json create mode 100644 src/Library/demos/Progress Bar/main.blp create mode 100644 src/Library/demos/Progress Bar/main.js create mode 100644 src/Library/demos/Progress Bar/main.json create mode 100644 src/Library/demos/Text Fields/main.blp create mode 100644 src/Library/demos/Text Fields/main.js create mode 100644 src/Library/demos/Text Fields/main.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fc1057d12..be94c22d6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,7 +40,7 @@ Once you understand these 3 things, try creating something new. There are plenty ## Your first contribution -Your first contribution should be a new example or demo for the Wokbench library. +Your first contribution should be a new example or demo for the Workbench library. Library examples and demos have 3 functions diff --git a/data/app.gschema.xml b/data/app.gschema.xml index b1a3a7c7e..059cf5da7 100644 --- a/data/app.gschema.xml +++ b/data/app.gschema.xml @@ -31,5 +31,11 @@ 0 + + true + + + false + diff --git a/re.sonny.Workbench.Devel.json b/re.sonny.Workbench.Devel.json index f162fe306..afff735fd 100644 --- a/re.sonny.Workbench.Devel.json +++ b/re.sonny.Workbench.Devel.json @@ -31,10 +31,9 @@ ], "sources": [ { - "type": "git", - "url": "https://gitlab.gnome.org/GNOME/vte.git", - "commit": "5bf476f1d7283bc805ac8ae6abe94f81ffd7be05", - "tag": "0.70.1" + "type": "archive", + "url": "https://download.gnome.org/sources/vte/0.71/vte-0.71.99.tar.xz", + "sha256": "15b7f42e4833b3525bbdc006d56c9ee56766c4d638aff56b392954b4ad3dd18b" } ] }, @@ -70,9 +69,9 @@ "buildsystem": "meson", "sources": [ { - "type": "git", - "url": "https://github.com/vala-lang/vala-language-server/", - "commit": "bf978c0cda97cff946f355477ec8da08b1cb4e5e" + "type": "archive", + "url": "https://github.com/vala-lang/vala-language-server/releases/download/0.48.7/vala-language-server-0.48.7.tar.xz", + "sha256": "a93e09497738144792466d0c5ccb1347583d84a9987b65b08f6aa5d5a1e3f431" } ], "modules": [ @@ -82,8 +81,8 @@ "sources": [ { "type": "archive", - "url": "https://download.gnome.org/sources/jsonrpc-glib/3.42/jsonrpc-glib-3.42.0.tar.xz", - "sha256": "221989a57ca82a12467dc427822cd7651b0cad038140c931027bf1074208276b" + "url": "https://download.gnome.org/sources/jsonrpc-glib/3.43/jsonrpc-glib-3.43.0.tar.xz", + "sha256": "0f248746478ef60fdf2fb255f7dbbed45b87150bf2855ec0a866107918dec413" } ], "cleanup": [ @@ -99,8 +98,8 @@ "sources": [ { "type": "archive", - "url": "https://download.gnome.org/sources/libgee/0.20/libgee-0.20.5.tar.xz", - "sha256": "31863a8957d5a727f9067495cabf0a0889fa5d3d44626e54094331188d5c1518" + "url": "https://download.gnome.org/sources/libgee/0.20/libgee-0.20.6.tar.xz", + "sha256": "1bf834f5e10d60cc6124d74ed3c1dd38da646787fbf7872220b8b4068e476d4d" } ] }, @@ -114,8 +113,8 @@ "sources": [ { "type": "archive", - "url": "https://github.com/uncrustify/uncrustify/archive/uncrustify-0.75.1.tar.gz", - "sha256": "fd14acc0a31ed88b33137bdc26d32964327488c835f885696473ef07caf2e182" + "url": "https://github.com/uncrustify/uncrustify/archive/uncrustify-0.76.0.tar.gz", + "sha256": "32e2f95485a933fc5667880f1a09a964ae83132c235bb606abbb0a659453acb3" } ] } diff --git a/re.sonny.Workbench.json b/re.sonny.Workbench.json index 9473beddb..a89903470 100644 --- a/re.sonny.Workbench.json +++ b/re.sonny.Workbench.json @@ -61,8 +61,8 @@ "sources": [ { "type": "git", - "url": "https://gitlab.gnome.org/sonny/blueprint-compiler", - "commit": "87a8ef8a3bdfeff5547dc6d6cc1ca41a303ce6fb" + "url": "https://gitlab.gnome.org/jwestman/blueprint-compiler.git", + "commit": "6f4806bfb3514c3fa01e0880c4bd9d399e058a44" } ] }, diff --git a/src/IconLibrary/main.blp b/src/IconLibrary/main.blp index 624e0329b..cb4ac42dd 100644 --- a/src/IconLibrary/main.blp +++ b/src/IconLibrary/main.blp @@ -1,23 +1,23 @@ using Gtk 4.0; using Adw 1; -Gtk.Window window { +Adw.Window window { width-request: 800; height-request: 600; hide-on-close: true; - title: _("Icon Library"); + Adw.ToastOverlay overlay { Box { orientation: vertical; - Adw.Clamp { - maximum-size: 800; + Adw.HeaderBar { + [title] + Adw.Clamp { + maximum-size: 800; - Box { - styles ["toolbar"] SearchEntry search_entry { hexpand: true; - placeholder-text: _('Search for icons by name, category or tag'); + placeholder-text: _("Search for icons by name, category or tag"); } } } diff --git a/src/Library/Library.js b/src/Library/Library.js index 654fb36f2..119d246ad 100644 --- a/src/Library/Library.js +++ b/src/Library/Library.js @@ -87,6 +87,15 @@ function getDemos() { continue; } + if (demo.name !== child.get_name()) { + console.warn( + `The demo name "${ + demo.name + }" does not match the folder name "${child.get_name()}" and will be ignored.`, + ); + continue; + } + demos.push(demo); } diff --git a/src/Library/demos/Box/main.blp b/src/Library/demos/Box/main.blp new file mode 100644 index 000000000..7511a5351 --- /dev/null +++ b/src/Library/demos/Box/main.blp @@ -0,0 +1,203 @@ +using Gtk 4.0; +using Adw 1; + +Adw.Clamp { + maximum-size: 1024; + + Box { + orientation: vertical; + + Label { + label: "Box"; + margin-top: 12; + margin-bottom: 12; + styles [ + "title-1", + ] + } + + Label { + label: _("A widget that arranges its child widgets into a single row or column"); + } + + Box{ + halign: center; + valign: end; + margin-bottom: 12; + + LinkButton{ + label: "Tutorial"; + uri: "https://developer.gnome.org/documentation/tutorials/beginners/components/box.html"; + } + + LinkButton{ + label: "API Reference"; + uri: "https://docs.gtk.org/gtk4/class.Box.html"; + } + } + + Box { + orientation: vertical; + + Box { + hexpand: true; + orientation: vertical; + spacing: 12; + margin-bottom:24; + + Box { + halign: center; + spacing: 18; + + Button button_append{ + label: _("Append Item"); + styles [ + "pill", + ] + } + + Button button_prepend{ + label: _("Prepend Item"); + styles [ + "pill", + ] + } + + Button button_remove{ + label: _("Remove Item"); + styles [ + "pill", + ] + } + } + } + + Box { + halign:center; + spacing:18; + + Box{ + spacing: 18; + Label { + label: _("orientation"); + } + + Box { + margin-start: 6; + homogeneous: true; + halign: center; + styles ["linked"] + + ToggleButton toggle_orientation_horizontal { + label: _("horizontal"); + active: true; + } + ToggleButton toggle_orientation_vertical { + label: _("vertical"); + group: toggle_orientation_horizontal; + } + } + } + + CheckButton highlight{ + label: _("Highlight Box"); + } + } + + Grid { + margin-top:12; + margin-bottom:12; + margin-start:12; + row-spacing:18; + margin-end: 114; + + Box { + tooltip-text: _("Horizontal Alignment"); + orientation: vertical; + layout { + row:0; + column:1; + } + Label { + margin-top:12; + margin-bottom:12; + label: _("halign"); + } + Box { + homogeneous: true; + halign: center; + spacing: 36; + ToggleButton halign_toggle_fill{ + label: _("fill"); + active:true; + } + ToggleButton halign_toggle_start{ + label: _("start"); + group: halign_toggle_fill; + } + ToggleButton halign_toggle_center{ + label: _("center"); + group: halign_toggle_fill; + } + ToggleButton halign_toggle_end{ + label: _("end"); + group: halign_toggle_fill; + } + } + } + + Box { + tooltip-text: _("Vertical Alignment"); + layout { + row:1; + column:0; + } + Label { + label: _("valign"); + styles ["rotate"] + } + Box { + valign:center; + orientation: vertical; + spacing: 60; + + ToggleButton valign_toggle_fill{ + label: _("fill"); + active:true; + styles ["rotate"] + } + ToggleButton valign_toggle_start{ + label: _("start"); + group: valign_toggle_fill; + styles ["rotate"] + } + ToggleButton valign_toggle_center{ + label: _("center"); + group: valign_toggle_fill; + styles ["rotate"] + } + ToggleButton valign_toggle_end{ + label: _("end"); + group: valign_toggle_fill; + styles ["rotate"] + } + } + } + + ScrolledWindow { + hexpand: true; + vexpand:true; + has-frame: true; + + layout { + row:1; + column:1; + } + Box interactive_box{ + } + } + } + } + } +} + diff --git a/src/Library/demos/Box/main.css b/src/Library/demos/Box/main.css new file mode 100644 index 000000000..fee0d55f5 --- /dev/null +++ b/src/Library/demos/Box/main.css @@ -0,0 +1,12 @@ +.card { + margin: 6px; + padding: 24px; +} + +.border { + border: 3px solid @accent_color; +} + +.rotate { + transform: rotate(-90deg); +} diff --git a/src/Library/demos/Box/main.js b/src/Library/demos/Box/main.js new file mode 100644 index 000000000..4ebc258a7 --- /dev/null +++ b/src/Library/demos/Box/main.js @@ -0,0 +1,106 @@ +import Gtk from "gi://Gtk"; + +const interactive_box = workbench.builder.get_object("interactive_box"); +const button_append = workbench.builder.get_object("button_append"); +const button_prepend = workbench.builder.get_object("button_prepend"); +const button_remove = workbench.builder.get_object("button_remove"); +let count = 0; + +button_append.connect("clicked", () => { + const label = new Gtk.Label({ + name: "card", + label: `Item ${count + 1}`, + css_classes: ["card"], + }); + interactive_box.append(label); + count++; +}); + +button_prepend.connect("clicked", () => { + const label = new Gtk.Label({ + name: "card", + label: `Item ${count + 1}`, + css_classes: ["card"], + }); + interactive_box.prepend(label); + count++; +}); + +button_remove.connect("clicked", () => { + if (count) { + interactive_box.remove(interactive_box.get_last_child()); + count--; + } else { + console.log("The box has no child widgets to remove"); + } +}); + +const toggle_orientation_horizontal = workbench.builder.get_object( + "toggle_orientation_horizontal", +); +const toggle_orientation_vertical = workbench.builder.get_object( + "toggle_orientation_vertical", +); + +toggle_orientation_horizontal.connect("toggled", () => { + if (toggle_orientation_horizontal.active) + interactive_box.orientation = Gtk.Orientation.HORIZONTAL; +}); + +toggle_orientation_vertical.connect("toggled", () => { + if (toggle_orientation_vertical.active) + interactive_box.orientation = Gtk.Orientation.VERTICAL; +}); + +const highlight = workbench.builder.get_object("highlight"); +highlight.connect("toggled", () => { + highlight.active + ? interactive_box.add_css_class("border") + : interactive_box.remove_css_class("border"); +}); + +const halign_toggle_fill = workbench.builder.get_object("halign_toggle_fill"); +const halign_toggle_start = workbench.builder.get_object("halign_toggle_start"); +const halign_toggle_center = workbench.builder.get_object( + "halign_toggle_center", +); +const halign_toggle_end = workbench.builder.get_object("halign_toggle_end"); + +halign_toggle_fill.connect("toggled", () => { + if (halign_toggle_fill.active) interactive_box.halign = Gtk.Align.FILL; +}); + +halign_toggle_start.connect("toggled", () => { + if (halign_toggle_start.active) interactive_box.halign = Gtk.Align.START; +}); + +halign_toggle_center.connect("toggled", () => { + if (halign_toggle_center.active) interactive_box.halign = Gtk.Align.CENTER; +}); + +halign_toggle_end.connect("toggled", () => { + if (halign_toggle_end.active) interactive_box.halign = Gtk.Align.END; +}); + +const valign_toggle_fill = workbench.builder.get_object("valign_toggle_fill"); +const valign_toggle_start = workbench.builder.get_object("valign_toggle_start"); +const valign_toggle_center = workbench.builder.get_object( + "valign_toggle_center", +); +const valign_toggle_end = workbench.builder.get_object("valign_toggle_end"); + +valign_toggle_fill.connect("toggled", () => { + if (valign_toggle_fill.active) interactive_box.valign = Gtk.Align.FILL; +}); + +valign_toggle_start.connect("toggled", () => { + if (valign_toggle_start.active) interactive_box.valign = Gtk.Align.START; +}); + +valign_toggle_center.connect("toggled", () => { + if (valign_toggle_center.active) interactive_box.valign = Gtk.Align.CENTER; +}); +valign_toggle_end.connect("toggled", () => { + if (valign_toggle_end.active) interactive_box.valign = Gtk.Align.END; +}); + diff --git a/src/Library/demos/Box/main.json b/src/Library/demos/Box/main.json new file mode 100644 index 000000000..a1f435dfb --- /dev/null +++ b/src/Library/demos/Box/main.json @@ -0,0 +1,9 @@ +{ + "name": "Box", + "category": "user_interface", + "description": "A widget that arranges its child widgets into a single row or column", + "panels": [ + "preview" + ], + "autorun": true +} \ No newline at end of file diff --git a/src/Library/demos/Calendar/main.blp b/src/Library/demos/Calendar/main.blp new file mode 100644 index 000000000..c6c0c9fb1 --- /dev/null +++ b/src/Library/demos/Calendar/main.blp @@ -0,0 +1,25 @@ +using Gtk 4.0; +using Adw 1; + +Adw.StatusPage { + title: "Calendar"; + description: "Display a Gregorian calendar, one month at a time"; + + Box { + orientation: vertical; + halign: center; + + Calendar calendar { + show-day-names: true; + show-week-numbers: false; + show-heading: true; + margin-bottom: 18; + day: 1; + } + + LinkButton { + label: "API Reference"; + uri: "https://docs.gtk.org/gtk4/class.Calendar.html"; + } + } +} diff --git a/src/Library/demos/Calendar/main.js b/src/Library/demos/Calendar/main.js new file mode 100644 index 000000000..e2cf20e33 --- /dev/null +++ b/src/Library/demos/Calendar/main.js @@ -0,0 +1,22 @@ +const calendar = workbench.builder.get_object("calendar"); + +// calendar.get_date() returns a GLib.DateTime object +// https://docs.gtk.org/glib/struct.DateTime.html + +calendar.connect("notify::day", () => { + console.log(calendar.get_date().format("%e")); +}); + +calendar.connect("notify::month", () => { + console.log(calendar.get_date().format("%B")); +}); + +calendar.connect("notify::year", () => { + console.log(calendar.get_date().format("%Y")); +}); + +calendar.connect("day-selected", () => { + console.log(calendar.get_date().format_iso8601()); +}); + +calendar.mark_day(15); diff --git a/src/Library/demos/Calendar/main.json b/src/Library/demos/Calendar/main.json new file mode 100644 index 000000000..20c1b3f4e --- /dev/null +++ b/src/Library/demos/Calendar/main.json @@ -0,0 +1,10 @@ +{ + "name": "Calendar", + "category": "user_interface", + "description": "Display a Gregorian calendar, one month at a time", + "panels": [ + "ui", + "preview" + ], + "autorun": true +} diff --git a/src/Library/demos/Color Dialog/main.blp b/src/Library/demos/Color Dialog/main.blp new file mode 100644 index 000000000..76257e109 --- /dev/null +++ b/src/Library/demos/Color Dialog/main.blp @@ -0,0 +1,58 @@ +using Gtk 4.0; +using Adw 1; + +Adw.StatusPage { + title: "Color Dialog"; + description: _("Show a dialog to select a color"); + + Box { + orientation: vertical; + halign: center; + spacing:42; + + Box{ + orientation:vertical; + + Label { + label: _("Dialog Button"); + margin-bottom:12; + styles ["title-4"] + } + + ColorDialogButton color_dialog_button { + halign: center; + margin-bottom:12; + } + + + LinkButton { + label: "API Reference"; + uri: "https://docs.gtk.org/gtk4/class.ColorDialogButton.html"; + } + } + + Box{ + orientation: vertical; + + Label { + label: _("Dialog with Custom Button"); + margin-bottom:12; + styles ["title-4"] + } + + Button custom_button { + label: _("Select Color…"); + margin-start:42; + margin-end:42; + margin-bottom:12; + styles ["pill"] + } + + LinkButton { + label: "API Reference"; + uri: "https://docs.gtk.org/gtk4/class.ColorDialog.html"; + } + } + } +} + diff --git a/src/Library/demos/Color Dialog/main.js b/src/Library/demos/Color Dialog/main.js new file mode 100644 index 000000000..02ccb6dec --- /dev/null +++ b/src/Library/demos/Color Dialog/main.js @@ -0,0 +1,42 @@ +import Gtk from "gi://Gtk"; +import Gdk from "gi://Gdk"; +import Gio from "gi://Gio"; + +Gio._promisify(Gtk.ColorDialog.prototype, "choose_rgba", "choose_rgba_finish"); + +const color_dialog_button = workbench.builder.get_object("color_dialog_button"); +const custom_button = workbench.builder.get_object("custom_button"); + +const color = new Gdk.RGBA(); +color.parse("red"); + +const dialog_standard = new Gtk.ColorDialog({ + title: "Select a color", + modal: true, + with_alpha: true, +}); + +color_dialog_button.dialog = dialog_standard; +color_dialog_button.rgba = color; + +color_dialog_button.connect("notify::rgba", () => { + console.log( + `Color Dialog Button: The color selected is ${color_dialog_button.rgba.to_string()}`, + ); +}); + +const dialog_custom = new Gtk.ColorDialog({ + title: "Select a color", + modal: true, + with_alpha: false, +}); + +custom_button.connect("clicked", async () => { + try { + const color = await dialog_custom.choose_rgba(workbench.window, null, null); + console.log(`Custom Button: The color selected is ${color.to_string()}`); + } catch (err) { + logError(err); + } +}); + diff --git a/src/Library/demos/Color Dialog/main.json b/src/Library/demos/Color Dialog/main.json new file mode 100644 index 000000000..7010a3a13 --- /dev/null +++ b/src/Library/demos/Color Dialog/main.json @@ -0,0 +1,10 @@ +{ + "name": "Color Dialog", + "category": "user_interface", + "description": "Show a dialog to select color", + "panels": [ + "ui", + "preview" + ], + "autorun": true +} diff --git a/src/Library/demos/Progress Bar/main.blp b/src/Library/demos/Progress Bar/main.blp new file mode 100644 index 000000000..622590f24 --- /dev/null +++ b/src/Library/demos/Progress Bar/main.blp @@ -0,0 +1,48 @@ +using Gtk 4.0; +using Adw 1; + +Adw.StatusPage { + title: "Progress Bar"; + description: _("Display the progress of a long running operation"); + + Box { + orientation: vertical; + halign: center; + + ProgressBar first { + fraction: 0.2; + show-text: true; + margin-bottom: 24; + } + + ProgressBar second { + inverted: true; + pulse-step: 0.25; + show-text: true; + text: ""; + margin-bottom: 24; + } + + Label progress_tracker { + label: ""; + margin-bottom: 12; + } + + Button play { + halign: center; + margin-bottom: 24; + icon-name: "media-playback-start-symbolic"; + } + + LinkButton { + label: "API Reference"; + uri: "https://docs.gtk.org/gtk4/class.ProgressBar.html"; + } + + LinkButton{ + label: "Human Interface Guidelines"; + uri: "https://developer.gnome.org/hig/patterns/feedback/progress-bars.html"; + } + } + } + diff --git a/src/Library/demos/Progress Bar/main.js b/src/Library/demos/Progress Bar/main.js new file mode 100644 index 000000000..8f4dbd5f1 --- /dev/null +++ b/src/Library/demos/Progress Bar/main.js @@ -0,0 +1,46 @@ +const first_bar = workbench.builder.get_object("first"); +const second_bar = workbench.builder.get_object("second"); +const play = workbench.builder.get_object("play"); +const progress_tracker = workbench.builder.get_object("progress_tracker"); + +function handleProgress() { + //Counters for respective progress bars and for progress tracker label + let counter = 0.3; + let counter_two = 0.25; + let timeLeft = 12; + + //Display a Countdown + const countdownInterval = setInterval(() => { + timeLeft--; + if (timeLeft === 0) { + clearInterval(countdownInterval); + progress_tracker.label = ""; + console.log("Operation Complete!"); + } else { + progress_tracker.label = `${timeLeft} seconds remaining ...`; + } + }, 1000); + + //Advance the first progress bar by 0.1 value every 1.5 seconds + const intervalId_one = setInterval(() => { + first_bar.set_fraction(counter); + counter += 0.1; + if (counter > 1.0) { + clearInterval(intervalId_one); + first_bar.set_fraction((counter = 0.2)); + } + }, 1500); + + //Advance the second progress bar by 0.25 value every 3 seconds + const intervalId_second = setInterval(() => { + second_bar.pulse(); + second_bar.set_fraction(counter_two); + counter_two += 0.25; + if (counter_two > 1.0) { + clearInterval(intervalId_second); + second_bar.set_fraction((counter_two = 0)); + } + }, 3000); +} + +play.connect("clicked", handleProgress); diff --git a/src/Library/demos/Progress Bar/main.json b/src/Library/demos/Progress Bar/main.json new file mode 100644 index 000000000..e01597faf --- /dev/null +++ b/src/Library/demos/Progress Bar/main.json @@ -0,0 +1,10 @@ +{ + "name": "Progress Bar", + "category": "user_interface", + "description": "Display the progress of a long running operation", + "panels": [ + "ui", + "preview" + ], + "autorun": true +} \ No newline at end of file diff --git a/src/Library/demos/Text Fields/main.blp b/src/Library/demos/Text Fields/main.blp new file mode 100644 index 000000000..80d870c8b --- /dev/null +++ b/src/Library/demos/Text Fields/main.blp @@ -0,0 +1,291 @@ +using Gtk 4.0; +using Adw 1; + +Adw.Clamp { + Box { + orientation: vertical; + + Label { + label: "Text Fields"; + margin-top: 12; + margin-bottom: 12; + + styles [ + "title-1", + ] + } + + Label { + label: "Single line widgets to enter text"; + margin-bottom: 12; + } + + LinkButton{ + label: "Human Interface Guidelines"; + uri: "https://developer.gnome.org/hig/patterns/controls/text-fields.html"; + margin-bottom: 6; + } + + Label { + label: "Entry"; + margin-top: 12; + halign: start; + + styles [ + "heading", + ] + } + + Label { + label: "A simple but versatile widget that allows single line text entry and editing."; + margin-top: 12; + margin-bottom: 12; + halign: start; + + styles [ + "dim-label", + ] + } + + FlowBox { + homogeneous: true; + row-spacing: 18; + selection-mode: none; + + Box { + orientation: vertical; + + Label { + label: "Regular"; + margin-bottom: 12; + } + + Entry entry { + input-purpose: free_form; + input-hints: no_spellcheck; + } + } + + Box { + orientation: vertical; + + Label { + label: "Placeholder Text"; + margin-bottom: 12; + } + + Entry entry_placeholder{ + placeholder-text: "Enter text here"; + } + } + + Box { + orientation: vertical; + + Label { + label: "Icons"; + margin-bottom: 12; + } + + Entry entry_icon { + primary-icon-name: "about-symbolic"; + primary-icon-activatable: true; + primary-icon-tooltip-text: "Click on me"; + secondary-icon-name: "bell-symbolic"; + secondary-icon-tooltip-text: "No click on me"; + } + } + + Box { + orientation: vertical; + + Label { + label: "Progress Bar"; + margin-bottom: 12; + + } + + Entry entry_progress { + progress-fraction: 0; + primary-icon-name: "media-playback-start-symbolic"; + primary-icon-tooltip-text: "Play animation"; + } + } + } + + Box { + halign: center; + margin-top: 18; + margin-bottom: 18; + + LinkButton{ + label: "Tutorial"; + uri: "https://developer.gnome.org/documentation/tutorials/beginners/components/entry.html"; + } + + LinkButton{ + label: "API Reference"; + uri: "https://docs.gtk.org/gtk4/class.Entry.html"; + } + } + + Separator { + margin-bottom: 18; + } + + Label { + label: "Completion Entry"; + halign: start; + + styles [ + "heading", + ] + } + + Label { + label: "An entry widget with support for completion."; + margin-top: 12; + margin-bottom: 12; + halign: start; + + styles [ + "dim-label", + ] + } + + + Entry entry_completion { + margin-bottom: 12; + placeholder-text: "Try typing 'apple'"; + } + + LinkButton { + label: "API Reference"; + uri: "https://docs.gtk.org/gtk4/class.EntryCompletion.html"; + margin-top: 18; + margin-bottom: 18; + } + + Separator { + margin-bottom: 18; + } + + Label { + label: "Password Entry"; + halign: start; + + styles [ + "heading", + ] + } + + Label { + label: "An entry with dedicated control for entering secrets and passwords."; + margin-top: 12; + margin-bottom: 12; + halign: start; + + styles [ + "dim-label", + ] + } + + PasswordEntry entry_password{ + show-peek-icon: true; + placeholder-text: "Enter password"; + margin-bottom: 12; + } + + PasswordEntry entry_confirm_password{ + show-peek-icon: true; + placeholder-text: "Confirm password"; + margin-bottom: 12; + } + + Label label_password { + } + + Box { + halign: center; + margin-top: 6; + margin-bottom: 18; + + LinkButton{ + label: "Tutorial"; + uri: "https://developer.gnome.org/documentation/tutorials/beginners/components/password_entry.html"; + } + + LinkButton{ + label: "API Reference"; + uri: "https://docs.gtk.org/gtk4/class.PasswordEntry.html"; + } + } + + Separator { + margin-bottom: 18; + } + + Label { + label: "Style Classes"; + margin-bottom: 12; + halign: start; + + styles [ + "heading", + ] + } + + Box { + homogeneous: true; + margin-bottom: 18; + + Entry { + placeholder-text: "accent"; + margin-start: 6; + margin-end: 6; + styles ["accent"] + } + + Entry { + placeholder-text: "warning"; + margin-start: 6; + margin-end: 6; + styles ["warning"] + } + } + + Box { + homogeneous: true; + margin-bottom: 18; + + Entry { + placeholder-text: "error"; + margin-start: 6; + margin-end: 6; + styles ["error"] + } + + Entry { + placeholder-text: "success"; + margin-start: 6; + margin-end: 6; + styles ["success"] + } + } + + Box { + margin-bottom: 18; + styles ["linked"] + halign: center; + Entry { + placeholder-text: "Street name and number"; + } + Entry { + placeholder-text: "City"; + } + Entry { + placeholder-text: "Country"; + } + } + } +} diff --git a/src/Library/demos/Text Fields/main.js b/src/Library/demos/Text Fields/main.js new file mode 100644 index 000000000..a599943fa --- /dev/null +++ b/src/Library/demos/Text Fields/main.js @@ -0,0 +1,102 @@ +import Adw from "gi://Adw"; +import Gtk from "gi://Gtk"; + +const entry = workbench.builder.get_object("entry"); +const entry_placeholder = workbench.builder.get_object("entry_placeholder"); +const entry_icon = workbench.builder.get_object("entry_icon"); +const entry_progress = workbench.builder.get_object("entry_progress"); + +entry.connect("activate", () => { + console.log(`Regular Entry: "${entry.text}" entered`); +}); + +entry_placeholder.connect("activate", () => { + console.log(`Placeholder Entry: "${entry_placeholder.text}" entered`); +}); + +entry_icon.connect("activate", () => { + console.log(`Icon Entry: "${entry_icon.text}" entered`); +}); + +entry_icon.connect("icon-press", () => { + console.log("Icon Pressed!"); +}); + +entry_icon.connect("icon-release", () => { + console.log("Icon Released!"); +}); + +entry_progress.connect("activate", () => { + console.log(`Progress Bar Entry: "${entry_progress.text}" entered`); +}); + +entry_progress.connect("icon-press", () => { + animation.play(); +}); + +const target = Adw.PropertyAnimationTarget.new( + entry_progress, + "progress-fraction", +); + +const animation = new Adw.TimedAnimation({ + widget: entry_progress, + value_from: 0, + value_to: 1, + duration: 2000, + easing: Adw.Easing["LINEAR"], + target: target, +}); + +animation.connect("done", () => { + animation.reset(); +}); + +const entry_completion = workbench.builder.get_object("entry_completion"); +const completion = new Gtk.EntryCompletion(); + +entry_completion.completion = completion; + +const list_store = Gtk.ListStore.new([String]); +const words = ["a", "app", "apple", "apples", "applets", "application"]; +words.forEach((word) => { + const iter = list_store.append(); + list_store.set_value(iter, 0, word); +}); +completion.model = list_store; + +completion.set_text_column(0); +completion.inline_completion = true; +completion.inline_selection = true; + +const entry_password = workbench.builder.get_object("entry_password"); +const entry_confirm_password = workbench.builder.get_object( + "entry_confirm_password", +); +const label_password = workbench.builder.get_object("label_password"); + +entry_password.connect("activate", () => { + label_password.label = validate_password( + entry_password.text, + entry_confirm_password.text, + ); +}); + +entry_confirm_password.connect("activate", () => { + label_password.label = validate_password( + entry_password.text, + entry_confirm_password.text, + ); +}); + +function validate_password(passwd, confirm_passwd) { + if (passwd && confirm_passwd) { + if (passwd === confirm_passwd) { + return "Password made successfully!"; + } else { + return "Both fields should be matching!"; + } + } else { + return "Both fields are mandatory!"; + } +} diff --git a/src/Library/demos/Text Fields/main.json b/src/Library/demos/Text Fields/main.json new file mode 100644 index 000000000..03898508f --- /dev/null +++ b/src/Library/demos/Text Fields/main.json @@ -0,0 +1,10 @@ +{ + "name": "Text Fields", + "category": "user_interface", + "description": "Single line widgets to enter text", + "panels": [ + "ui", + "preview" + ], + "autorun": true +} diff --git a/src/Library/demos/Welcome/main.blp b/src/Library/demos/Welcome/main.blp index f1aade436..df398547b 100644 --- a/src/Library/demos/Welcome/main.blp +++ b/src/Library/demos/Welcome/main.blp @@ -41,7 +41,7 @@ Box welcome { icon-size: normal; } Label { - label: "Edit Style or UI to reload the Preview"; + label: "Edit Style or UI to update the Preview"; } } diff --git a/src/Previewer/Previewer.js b/src/Previewer/Previewer.js index 363cf0c6f..623fd2874 100644 --- a/src/Previewer/Previewer.js +++ b/src/Previewer/Previewer.js @@ -12,7 +12,7 @@ import Internal from "./Internal.js"; import External from "./External.js"; import { getClassNameType } from "../overrides.js"; -import { isBuilderable, isPreviewable } from "./utils.js"; +import { assertBuildable, detectCrash, isPreviewable } from "./utils.js"; /* Always default to in-process preview @@ -102,10 +102,12 @@ export default function Previewer({ function start() { stop(); if (handler_id_ui === null) { - handler_id_ui = panel_ui.connect("updated", schedule_update); + handler_id_ui = panel_ui.connect("updated", () => schedule_update()); } if (handler_id_css === null) { - handler_id_css = code_view_css.connect("changed", schedule_update); + handler_id_css = code_view_css.connect("changed", () => + schedule_update(), + ); } } @@ -114,7 +116,6 @@ export default function Previewer({ panel_ui.disconnect(handler_id_ui); handler_id_ui = null; } - if (handler_id_css) { code_view_css.disconnect(handler_id_css); handler_id_css = null; @@ -145,8 +146,12 @@ export default function Previewer({ }, ); + settings.connect("changed", () => { + if (settings.get_boolean("auto-preview")) schedule_update(); + }); let symbols = null; - async function update() { + async function update(force = false) { + if (!(force || settings.get_boolean("auto-preview"))) return; let text = panel_ui.xml.trim(); let target_id; let tree; @@ -167,9 +172,18 @@ export default function Previewer({ if (!target_id) return; - // console.time("builderable"); - if (!(await isBuilderable(text))) return; - // console.timeEnd("builderable"); + try { + assertBuildable(tree); + } catch (err) { + console.warn(err.message); + return; + } + + if (settings.get_boolean("safe-mode")) { + // console.time("detectCrash"); + if (await detectCrash(text, target_id)) return; + // console.timeEnd("detectCrash"); + } const builder = new Gtk.Builder(); const scope = new BuilderScope(); @@ -214,16 +228,18 @@ export default function Previewer({ const schedule_update = unstack(update, logError); async function useExternal() { - if (current === external) return; - await setPreviewer(external); + if (current !== external) { + await setPreviewer(external); + } stack.set_visible_child_name("close_window"); - await update(); + await update(true); } async function useInternal() { - if (current === internal) return; - await setPreviewer(internal); - await update(); + if (current !== internal) { + await setPreviewer(internal); + } + await update(true); } async function setPreviewer(previewer) { diff --git a/src/Previewer/crasher.vala b/src/Previewer/crasher.vala index f1e61823c..d5404db4f 100644 --- a/src/Previewer/crasher.vala +++ b/src/Previewer/crasher.vala @@ -2,9 +2,13 @@ public void main (string[] args) { Adw.init (); var builder = new Gtk.Builder(); + var output = new Gtk.Window (); try { builder.add_from_string(args[1], -1); + var object = builder.get_object(args[2]) as Gtk.Widget; + output.set_child(object); + // We are only interested in crashes here // Previewer.js will handle errors } catch {} diff --git a/src/Previewer/utils.js b/src/Previewer/utils.js index a4ef585e8..87d9ce4a1 100644 --- a/src/Previewer/utils.js +++ b/src/Previewer/utils.js @@ -1,6 +1,7 @@ import GObject from "gi://GObject"; import Gtk from "gi://Gtk"; import Gio from "gi://Gio"; +import Adw from "gi://Adw"; Gio._promisify( Gio.Subprocess.prototype, @@ -26,9 +27,106 @@ export function isPreviewable(class_name) { return GObject.type_is_a(klass, Gtk.Widget); } -export async function isBuilderable(str) { - const flags = - Gio.SubprocessFlags.STDOUT_SILENCE | Gio.SubprocessFlags.STDERR_SILENCE; - const proc = Gio.Subprocess.new(["workbench-crasher", str], flags); - return proc.wait_check_async(null); +export function assertBuildable(el) { + for (const el_object of el.getChildren("object")) { + assertObjectBuildable(el_object, true); + } +} + +function getChildProperty(el) { + const property = getProperty(el, "child"); + return property?.getChild("object") || null; +} + +function getProperty(el, name) { + const properties = el.getChildren("property"); + return properties.find((el) => el.attrs.name === name); +} + +function getKlass(el) { + const class_name = el.attrs.class; + if (!class_name) return null; + return getObjectClass(class_name); +} + +function assertObjectBuildable(el_object, root) { + const klass = getKlass(el_object); + if (klass) { + // GLib-GObject-ERROR: cannot create instance of abstract (non-instantiatable) type 'GtkWidget' + if (GObject.type_test_flags(klass, GObject.TypeFlags.ABSTRACT)) { + throw new Error( + `${klass.$gtype.name} is an abstract type. It cannot be instantiated.`, + ); + } + + // Gtk:ERROR:../gtk/gtkbuilder.c:1044:_gtk_builder_add: assertion failed: (GTK_IS_BUILDABLE (parent)) + if (!GObject.type_is_a(klass, Gtk.Buildable)) { + if (el_object.getChildren("child").length > 0) { + throw new Error( + `${klass.$gtype.name} is not a GtkBuildable. It cannot have children.`, + ); + } + } + + // Gtk:ERROR:../gtk/gtkwidget.c:2448:gtk_widget_root: assertion failed: (priv->root == NULL) + if (!root && GObject.type_is_a(klass, Gtk.Root)) { + throw new Error( + `${klass.$gtype.name} is a GtkRoot. GtkRoot objects can only appear at the top-level.`, + ); + } + + // Adwaita-gtk_window_set_titlebar() is not supported for AdwWindow + if ( + GObject.type_is_a(klass, Adw.Window) && + getProperty(el_object, "titlebar") + ) { + throw new Error( + `${klass.$gtype.name} does not support the titlebar property.`, + ); + } + + // Adwaita-gtk_window_set_child() is not supported for AdwWindow + if ( + GObject.type_is_a(klass, Adw.Window) && + getProperty(el_object, "child") + ) { + throw new Error( + `${klass.$gtype.name} does not support the child property.`, + ); + } + } + + // Gtk-ERROR **: 23:19:54.204: GtkStackPage '' [0x55b094802eb0] is missing a child widget + const child_property = getChildProperty(el_object); + if (child_property) { + const child_klass = getKlass(child_property); + if (!GObject.type_is_a(child_klass, Gtk.Widget)) { + throw new Error(`${child_klass.$gtype.name} is not a GtkWidget.`); + } + assertObjectBuildable(child_property, false); + } + + // Iterate over properties + for (const el_property of el_object.getChildren("property")) { + for (const el of el_property.getChildren("object")) { + assertObjectBuildable(el, false); + } + } + + // Iterate over children + for (const el_child of el_object.getChildren("child")) { + for (const el of el_child.getChildren("object")) { + assertObjectBuildable(el, false); + } + } +} + +export async function detectCrash(str, object_id) { + // const flags = + // Gio.SubprocessFlags.STDOUT_SILENCE | Gio.SubprocessFlags.STDERR_SILENCE; + const flags = Gio.SubprocessFlags.NONE; + const proc = Gio.Subprocess.new(["workbench-crasher", str, object_id], flags); + + const success = await proc.wait_check_async(null).catch((_err) => false); + return !success; } diff --git a/src/about.js b/src/about.js index ba69184e2..046d73de6 100644 --- a/src/about.js +++ b/src/about.js @@ -50,10 +50,12 @@ ${getBlueprintVersion()} }); dialog.add_credit_section(_("Contributors"), [ + "Akshay Warrier https://github.com/AkshayWarrier", "Ben Foote http://www.bengineeri.ng", "Brage Fuglseth https://bragefuglseth.dev", "Hari Rana (TheEvilSkeleton) https://theevilskeleton.gitlab.io", "Sriyansh Shivam https://linktr.ee/sonic_here", + "Angelo Verlain https://www.vixalien.com", // Add yourself as // "John Doe", // or @@ -72,6 +74,5 @@ function getValaVersion() { } function getBlueprintVersion() { - // https://gitlab.gnome.org/jwestman/blueprint-compiler/-/issues/61 - return "Blueprint 0.6.0-Workbench"; + return "Blueprint 402677f6"; } diff --git a/src/actions.js b/src/actions.js index 284cff7ba..4f84ac7e9 100644 --- a/src/actions.js +++ b/src/actions.js @@ -135,6 +135,8 @@ export default function Actions({ application }) { application.add_action(action_platform_tools); application.add_action(settings.create_action("color-scheme")); + application.add_action(settings.create_action("safe-mode")); + application.add_action(settings.create_action("auto-preview")); } const lang_filters = languages.map((language) => { diff --git a/src/langs/blueprint/blueprint.js b/src/langs/blueprint/blueprint.js index 596f1146a..f23d4ac39 100644 --- a/src/langs/blueprint/blueprint.js +++ b/src/langs/blueprint/blueprint.js @@ -37,13 +37,9 @@ export function setup({ data_dir, document }) { return xml; }, async decompile(text) { - const { blp } = await lspc.request( - "x-blueprint/decompile", - { - text, - }, - { timeout: 5000 }, - ); + const { blp } = await lspc.request("x-blueprint/decompile", { + text, + }); return blp; }, }; diff --git a/src/lsp/LSPClient.js b/src/lsp/LSPClient.js index 51121afd2..9c4e55960 100644 --- a/src/lsp/LSPClient.js +++ b/src/lsp/LSPClient.js @@ -3,7 +3,7 @@ import Gio from "gi://Gio"; import { LSPError } from "./LSP.js"; -import { getPid, promiseTask, once } from "../../troll/src/util.js"; +import { getPid, once } from "../../troll/src/util.js"; const { addSignalMethods } = imports.signals; @@ -17,6 +17,26 @@ const clientInfo = { version: pkg.version, }; +Gio._promisify( + Gio.InputStream.prototype, + "read_bytes_async", + "read_bytes_finish", +); +Gio._promisify(Gio.InputStream.prototype, "read_all_async", "read_all_finish"); +Gio._promisify(Gio.InputStream.prototype, "close_async", "close_finish"); +Gio._promisify( + Gio.DataInputStream.prototype, + "read_line_async", + "read_line_finish", +); +Gio._promisify(Gio.OutputStream.prototype, "close_async", "close_finish"); +Gio._promisify( + Gio.OutputStream.prototype, + "write_bytes_async", + "write_bytes_finish", +); +Gio._promisify(Gio.Subprocess.prototype, "wait_async", "wait_finish"); + export default class LSPClient { constructor(argv, { rootUri, uri, languageId, buffer }) { this.argv = argv; @@ -76,8 +96,10 @@ export default class LSPClient { } async stop() { - await promiseTask(this.stdin, "close_async", "close_finish", null); - await promiseTask(this.stdout, "close_async", "close_finish", null); + await Promise.all([ + this.stdin.close_async(null), + this.stdout.close_async(null), + ]); // this.proc?.force_exit(); this.proc.send_signal(15); } @@ -134,15 +156,13 @@ export default class LSPClient { flags = flags | Gio.SubprocessFlags.STDERR_SILENCE; this.proc = Gio.Subprocess.new(this.argv, flags); - this.proc.wait_async(null, (_self, res) => { - try { - this.proc.wait_finish(res); - } catch (err) { - logError(err); - } - this.emit("exit"); - // this._start_process(); - }); + this.proc + .wait_async(null) + .then(() => { + this.emit("exit"); + // this._start_process(); + }) + .catch(logError); this.stdin = this.proc.get_stdin_pipe(); this.stdout = new Gio.DataInputStream({ base_stream: this.proc.get_stdout_pipe(), @@ -156,11 +176,8 @@ export default class LSPClient { const headers = Object.create(null); while (true) { - const [bytes] = await promiseTask( - this.stdout, - "read_line_async", - "read_line_finish", - 0, + const [bytes] = await this.stdout.read_line_async( + GLib.PRIORITY_DEFAULT, null, ); if (!bytes) break; @@ -177,15 +194,23 @@ export default class LSPClient { } async _read_content(length) { - const bytes = await promiseTask( - this.stdout, - "read_bytes_async", - "read_bytes_finish", - length, - 0, - null, - ); - const str = decoder_utf8.decode(bytes.toArray()); + // read_bytes is limited by some underlying max buffer size + // see https://github.com/sonnyp/Workbench/issues/240#issuecomment-1475387647 + // read_all is not supported in GJS so we do this instead + // https://gitlab.gnome.org/GNOME/gjs/-/issues/501 + const uint8 = new Uint8Array(length); + let read = 0; + while (read < length) { + const bytes = await this.stdout.read_bytes_async( + length - read, + GLib.PRIORITY_DEFAULT, + null, + ); + uint8.set(bytes.toArray(), read); + read += bytes.get_size(); + } + + const str = decoder_utf8.decode(uint8); try { return JSON.parse(str); } catch (err) { @@ -232,14 +257,7 @@ export default class LSPClient { this.stdin.flush(); } - await promiseTask( - this.stdin, - "write_bytes_async", - "write_bytes_finish", - bytes, - GLib.PRIORITY_DEFAULT, - null, - ); + await this.stdin.write_bytes_async(bytes, GLib.PRIORITY_DEFAULT, null); this.emit("output", message); } @@ -253,7 +271,7 @@ export default class LSPClient { }); const [result] = await once(this, `result::${id}`, { error: `error::${id}`, - timeout: 1000, + timeout: 5000, }); return result; } diff --git a/src/window.blp b/src/window.blp index a9448685d..1bd43fb89 100644 --- a/src/window.blp +++ b/src/window.blp @@ -100,6 +100,18 @@ Gtk.ApplicationWindow window { icon-name: "open-menu-symbolic"; primary: true; } + + [end] + Button button_run { + child: Adw.ButtonContent { + icon-name: "media-playback-start-symbolic"; + label: _("_Run"); + use-underline: true; + }; + action-name: "win.run"; + tooltip-text: _("Run (Ctrl+⏎)"); + styles ["suggested-action"] + } }; [content] @@ -146,18 +158,6 @@ Gtk.ApplicationWindow window { tooltip-text: _("Switch document"); } } - - [end] - Button button_run { - child: Adw.ButtonContent { - icon-name: "media-playback-start-symbolic"; - label: _("_Run"); - use-underline: true; - }; - action-name: "win.run"; - tooltip-text: _("Run (Ctrl+⏎)"); - styles ["suggested-action"] - } } Separator { @@ -266,10 +266,12 @@ Gtk.ApplicationWindow window { styles ["toolbar", "panel_header"] [start] - Label { - label: _("Preview"); - use-markup: true; - styles ["dim-label"] + MenuButton { + halign: center; + valign: center; + label: _("Preview"); + styles ["flat"] + menu-model: preview_menu; } [center] @@ -555,3 +557,12 @@ menu menu_app { } } } + +menu preview_menu { + // FIXME: It's unclear if this is needed or helpful + // know issue: if auto-preview is disabled, Workbench shows a blank preview on start + item (_("Auto-Update"), "app.auto-preview") + // FIXME: This will probably be removed in favor of + // automatcally enabling when we detect a crash + item (_("Safe Mode"), "app.safe-mode") +} diff --git a/src/window.js b/src/window.js index b4605be6b..fd1fa0ba8 100644 --- a/src/window.js +++ b/src/window.js @@ -250,7 +250,7 @@ export default function Window({ application }) { } if (language === "JavaScript") { - await previewer.update(); + await previewer.update(true); // We have to create a new file each time // because gjs doesn't appear to use etag for module caching @@ -271,7 +271,7 @@ export default function Window({ application }) { try { exports = await import(`file://${file_javascript.get_path()}`); } catch (err) { - await previewer.update(); + await previewer.update(true); throw err; } finally { promiseTask( @@ -317,10 +317,7 @@ export default function Window({ application }) { name: "run", }); action_run.connect("activate", () => { - // Ensure code does not run if panel is not visible - if (panel_code.panel.visible) { - runCode().catch(logError); - } + runCode().catch(logError); }); window.add_action(action_run); application.set_accels_for_action("win.run", ["Return"]); @@ -400,7 +397,7 @@ export default function Window({ application }) { panel_ui.start(); await panel_ui.update(); previewer.start(); - await previewer.update(); + await previewer.update(true); } documents.forEach((document) => { From 46b1d145be902190e3e37041f40fb2e828c3eea7 Mon Sep 17 00:00:00 2001 From: kodecheff Date: Thu, 23 Mar 2023 15:07:31 +0100 Subject: [PATCH 2/6] Library: Add SpinButton Entry --- blueprint-compiler | 2 +- src/Library/demos/Spin Button/main.blp | 19 ++++++++++ src/Library/demos/Spin Button/main.js | 48 +++++++++++++++++++++++++ src/Library/demos/Spin Button/main.json | 10 ++++++ 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/Library/demos/Spin Button/main.blp create mode 100644 src/Library/demos/Spin Button/main.js create mode 100644 src/Library/demos/Spin Button/main.json diff --git a/blueprint-compiler b/blueprint-compiler index 402677f68..87a8ef8a3 160000 --- a/blueprint-compiler +++ b/blueprint-compiler @@ -1 +1 @@ -Subproject commit 402677f687ecdb78026864188bae50b9d85949de +Subproject commit 87a8ef8a3bdfeff5547dc6d6cc1ca41a303ce6fb diff --git a/src/Library/demos/Spin Button/main.blp b/src/Library/demos/Spin Button/main.blp new file mode 100644 index 000000000..6677b3fdc --- /dev/null +++ b/src/Library/demos/Spin Button/main.blp @@ -0,0 +1,19 @@ +using Gtk 4.0; + +Box welcome { + orientation: vertical; + valign: center; + halign: center; + + Label { + label: "Spin Button"; + margin-bottom: 30; + styles ["title-1"] + } + + Button open_spinbox{ + label: "Open"; + styles["pill"] + } + +} diff --git a/src/Library/demos/Spin Button/main.js b/src/Library/demos/Spin Button/main.js new file mode 100644 index 000000000..cd9e48065 --- /dev/null +++ b/src/Library/demos/Spin Button/main.js @@ -0,0 +1,48 @@ +import Gtk from "gi://Gtk?version=4.0"; +import GObject from "gi://GObject"; + +Gtk.init(); + +const open_spin_box = workbench.builder.get_object("open_spinbox"); + +// Create new Gtk instances +const spin_button = new Gtk.SpinButton(); +const adjustment = new Gtk.Adjustment({ + lower: 0, + page_increment: 1, + step_increment: 1, + upper: 100, + value: 0, +}); + +spin_button.set_adjustment(adjustment); + +const Application = GObject.registerClass( + {}, + class extends Gtk.Application { + vfunc_activate() { + const window = new Gtk.ApplicationWindow({ application: this }); + const box = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + marginTop: 36, + marginBottom: 36, + marginStart: 36, + marginEnd: 36, + spacing: 16, + }); + + box.append(spin_button); + + window.child = box; + window.set_default_size(400, 200); + window.present(); + } + }, +); + +const app = new Application(); + +open_spin_box.connect("clicked", () => { + app.vfunc_activate(); +}); + diff --git a/src/Library/demos/Spin Button/main.json b/src/Library/demos/Spin Button/main.json new file mode 100644 index 000000000..1016586b2 --- /dev/null +++ b/src/Library/demos/Spin Button/main.json @@ -0,0 +1,10 @@ +{ + "name": "Spin Button", + "category": "user_interface", + "description": "Spin Button allows users to increment or decrement the displayed value of an attribute. ", + "panels": [ + "code", + "preview" + ], + "autorun": true +} From 97f0d3addcd6704395daf394ba8853597531e3d4 Mon Sep 17 00:00:00 2001 From: Akunne Pascal <48069624+Kodecheff@users.noreply.github.com> Date: Fri, 24 Mar 2023 09:23:54 +0100 Subject: [PATCH 3/6] Update main.blp Added Adw.StatusPage --- src/Library/demos/Spin Button/main.blp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/Library/demos/Spin Button/main.blp b/src/Library/demos/Spin Button/main.blp index 6677b3fdc..4a3bed498 100644 --- a/src/Library/demos/Spin Button/main.blp +++ b/src/Library/demos/Spin Button/main.blp @@ -1,19 +1,14 @@ using Gtk 4.0; +using Adw 1; -Box welcome { +Adw.StatusPage { + title: "Spin Button"; + description: _("Display spin button count (0 - 100)"); + + Box spinbox { orientation: vertical; valign: center; halign: center; - Label { - label: "Spin Button"; - margin-bottom: 30; - styles ["title-1"] - } - - Button open_spinbox{ - label: "Open"; - styles["pill"] } - } From 9baf1ff431e545ef470eef95f0aeeb7e14de7379 Mon Sep 17 00:00:00 2001 From: Akunne Pascal <48069624+Kodecheff@users.noreply.github.com> Date: Fri, 24 Mar 2023 09:28:08 +0100 Subject: [PATCH 4/6] Update main.blp Added API reference --- src/Library/demos/Spin Button/main.blp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Library/demos/Spin Button/main.blp b/src/Library/demos/Spin Button/main.blp index 4a3bed498..fa100c62e 100644 --- a/src/Library/demos/Spin Button/main.blp +++ b/src/Library/demos/Spin Button/main.blp @@ -11,4 +11,9 @@ Adw.StatusPage { halign: center; } + + LinkButton { + label: "API Reference"; + uri: "https://docs.gtk.org/gtk4/class.SpinButton.html"; + } } From 33bf462d06dd6a1aa34d82e67328b7634a80c78d Mon Sep 17 00:00:00 2001 From: Akunne Pascal <48069624+Kodecheff@users.noreply.github.com> Date: Fri, 24 Mar 2023 10:05:42 +0100 Subject: [PATCH 5/6] Update main.blp Created spinbutton using blueprint ui --- src/Library/demos/Spin Button/main.blp | 29 +++++++++++++++++++------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/Library/demos/Spin Button/main.blp b/src/Library/demos/Spin Button/main.blp index fa100c62e..ef1504dcb 100644 --- a/src/Library/demos/Spin Button/main.blp +++ b/src/Library/demos/Spin Button/main.blp @@ -4,16 +4,29 @@ using Adw 1; Adw.StatusPage { title: "Spin Button"; description: _("Display spin button count (0 - 100)"); - - Box spinbox { + + Box { orientation: vertical; - valign: center; halign: center; + spacing: 12; + width-request: 12; + SpinButton { + value: 0; + climb-rate: 1; + adjustment: Gtk.Adjustment { + lower: 0; + page-increment: 1; + step-increment: 1; + upper: 100; + value: 0; + }; + } + + LinkButton { + label: "API Reference"; + uri: "https://docs.gtk.org/gtk4/class.SpinButton.html"; + } } - - LinkButton { - label: "API Reference"; - uri: "https://docs.gtk.org/gtk4/class.SpinButton.html"; - } + } From 158b470f18c1bb79c2a4e4b70d6e6eec53cb51ab Mon Sep 17 00:00:00 2001 From: kodecheff Date: Mon, 27 Mar 2023 14:14:32 +0100 Subject: [PATCH 6/6] SpinButton library update --- src/Library/demos/Spin Button/main.blp | 40 ++++++++++++++------ src/Library/demos/Spin Button/main.js | 49 ++----------------------- src/Library/demos/Spin Button/main.json | 4 +- 3 files changed, 35 insertions(+), 58 deletions(-) diff --git a/src/Library/demos/Spin Button/main.blp b/src/Library/demos/Spin Button/main.blp index 6677b3fdc..a86559bc1 100644 --- a/src/Library/demos/Spin Button/main.blp +++ b/src/Library/demos/Spin Button/main.blp @@ -1,19 +1,37 @@ using Gtk 4.0; +using Adw 1; -Box welcome { +Adw.StatusPage { + title: "Spin Button"; + description: _("Display spin button count (0 - 100)"); + + Box { orientation: vertical; - valign: center; - halign: center; + spacing: 12; + width-request: 12; - Label { - label: "Spin Button"; - margin-bottom: 30; - styles ["title-1"] - } + SpinButton spinbutton{ + halign: center; + value: 0; + climb-rate: 1; + adjustment: Gtk.Adjustment { + lower: 0; + page-increment: 1; + step-increment: 1; + upper: 100; + value: 0; + }; + } + + LinkButton { + label: "API Reference"; + uri: "https://docs.gtk.org/gtk4/class.SpinButton.html"; + } - Button open_spinbox{ - label: "Open"; - styles["pill"] + LinkButton { + label: "Human Interface Guidelines"; + uri: "https://developer.gnome.org/hig/patterns/controls/spin-buttons.html"; + } } } diff --git a/src/Library/demos/Spin Button/main.js b/src/Library/demos/Spin Button/main.js index cd9e48065..8ce9764d7 100644 --- a/src/Library/demos/Spin Button/main.js +++ b/src/Library/demos/Spin Button/main.js @@ -1,48 +1,7 @@ -import Gtk from "gi://Gtk?version=4.0"; -import GObject from "gi://GObject"; +const spinbutton = workbench.builder.get_object("spinbutton"); -Gtk.init(); - -const open_spin_box = workbench.builder.get_object("open_spinbox"); - -// Create new Gtk instances -const spin_button = new Gtk.SpinButton(); -const adjustment = new Gtk.Adjustment({ - lower: 0, - page_increment: 1, - step_increment: 1, - upper: 100, - value: 0, -}); - -spin_button.set_adjustment(adjustment); - -const Application = GObject.registerClass( - {}, - class extends Gtk.Application { - vfunc_activate() { - const window = new Gtk.ApplicationWindow({ application: this }); - const box = new Gtk.Box({ - orientation: Gtk.Orientation.VERTICAL, - marginTop: 36, - marginBottom: 36, - marginStart: 36, - marginEnd: 36, - spacing: 16, - }); - - box.append(spin_button); - - window.child = box; - window.set_default_size(400, 200); - window.present(); - } - }, -); - -const app = new Application(); - -open_spin_box.connect("clicked", () => { - app.vfunc_activate(); +spinbutton.connect("value-changed", (button) => { + // Log new entry to the console + console.log("New entry:", button.get_value()); }); diff --git a/src/Library/demos/Spin Button/main.json b/src/Library/demos/Spin Button/main.json index 1016586b2..9bcdb2c01 100644 --- a/src/Library/demos/Spin Button/main.json +++ b/src/Library/demos/Spin Button/main.json @@ -1,9 +1,9 @@ { "name": "Spin Button", "category": "user_interface", - "description": "Spin Button allows users to increment or decrement the displayed value of an attribute. ", + "description": "Let users choose a precise numerical value.", "panels": [ - "code", + "ui", "preview" ], "autorun": true