From dc62d212ad510078bbc83abaecee12ac842ca559 Mon Sep 17 00:00:00 2001 From: AkshayWarrier <58233418+AkshayWarrier@users.noreply.github.com> Date: Fri, 11 Aug 2023 14:36:55 +0530 Subject: [PATCH 1/8] library: Add Navigation Split View entry (#479) * library: Add Navigation Split View entry * Navigation Split View: Replicate Adw Demo * Navigation Split View: Changes from code review * Navigation Split View: Update main.json --- .../demos/Navigation Split View/main.blp | 66 +++++++++++++++++++ .../demos/Navigation Split View/main.json | 6 ++ 2 files changed, 72 insertions(+) create mode 100644 src/Library/demos/Navigation Split View/main.blp create mode 100644 src/Library/demos/Navigation Split View/main.json diff --git a/src/Library/demos/Navigation Split View/main.blp b/src/Library/demos/Navigation Split View/main.blp new file mode 100644 index 000000000..3c307ffd9 --- /dev/null +++ b/src/Library/demos/Navigation Split View/main.blp @@ -0,0 +1,66 @@ +using Gtk 4.0; +using Adw 1; + +Adw.Window { + width-request: 360; + height-request: 200; + default-width: 640; + default-height: 480; + + Adw.Breakpoint { + condition ("max-width: 400sp") + setters { + split_view.collapsed: true; + button.visible: true; + } + } + + content: Adw.NavigationSplitView split_view { + sidebar: Adw.NavigationPage { + title: "Sidebar"; + tag: "sidebar"; + child: Adw.ToolbarView { + + [top] + Adw.HeaderBar { + show-title: false; + } + + content: Adw.StatusPage { + title: _("Sidebar"); + + Button button { + visible: false; + halign: center; + can-shrink: true; + label: _("Open Content"); + action-name: "navigation.push"; + action-target: "'content'"; + styles ["pill"] + } + }; + }; + }; + + content: Adw.NavigationPage { + title: "Content"; + tag: "content"; + child: Adw.ToolbarView { + + [top] + Adw.HeaderBar { + show-title: false; + } + + content: Adw.StatusPage { + title: _("Content"); + + LinkButton { + label: "API Reference"; + uri: "https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.NavigationSplitView.html"; + } + }; + }; + }; + }; +} diff --git a/src/Library/demos/Navigation Split View/main.json b/src/Library/demos/Navigation Split View/main.json new file mode 100644 index 000000000..30555a9a0 --- /dev/null +++ b/src/Library/demos/Navigation Split View/main.json @@ -0,0 +1,6 @@ +{ + "category": "navigation", + "description": "A widget presenting sidebar and content side by side or as a navigation view.", + "panels": ["ui", "preview"], + "autorun": true +} From 9b725a62315c2feb63941e745a33729c20c29b1e Mon Sep 17 00:00:00 2001 From: AkshayWarrier Date: Wed, 19 Jul 2023 10:26:20 +0530 Subject: [PATCH 2/8] library: Add Scrolled Window entry --- src/Library/demos/Scrolled Window/main.blp | 76 +++++++++++++++++ src/Library/demos/Scrolled Window/main.js | 91 +++++++++++++++++++++ src/Library/demos/Scrolled Window/main.json | 10 +++ 3 files changed, 177 insertions(+) create mode 100644 src/Library/demos/Scrolled Window/main.blp create mode 100644 src/Library/demos/Scrolled Window/main.js create mode 100644 src/Library/demos/Scrolled Window/main.json diff --git a/src/Library/demos/Scrolled Window/main.blp b/src/Library/demos/Scrolled Window/main.blp new file mode 100644 index 000000000..f25b6ee7e --- /dev/null +++ b/src/Library/demos/Scrolled Window/main.blp @@ -0,0 +1,76 @@ +using Gtk 4.0; +using Adw 1; + +Adw.StatusPage { + title: _("Scrolled Window"); + description: _("A container that makes its child scrollable"); + + Adw.Clamp { + Box{ + hexpand: true; + vexpand: true; + spacing: 12; + orientation: vertical; + + Box{ + halign: center; + spacing: 18; + + Label { + label: _("Orientation"); + } + + Box { + margin-start: 6; + homogeneous: true; + halign: center; + styles ["linked"] + + ToggleButton toggle_orientation { + label: _("Horizontal"); + active: true; + } + ToggleButton { + label: _("Vertical"); + group: toggle_orientation; + } + } + + Label { + label: _("Go To"); + } + + Box{ + + Button button_start { + label: _("Start"); + } + + Button button_end { + label: _("End"); + } + styles ["linked"] + } + } + + + + ScrolledWindow scrolled_window { + margin-bottom: 24; + margin-top: 24; + has-frame: true; + propagate-natural-height: true; + max-content-height: 300; + + Box container { + homogeneous: true; + } + } + + LinkButton { + label: "Documentation"; + uri: "https://docs.gtk.org/gtk4/class.ScrolledWindow.html"; + } + } + } +} diff --git a/src/Library/demos/Scrolled Window/main.js b/src/Library/demos/Scrolled Window/main.js new file mode 100644 index 000000000..69cc52a3d --- /dev/null +++ b/src/Library/demos/Scrolled Window/main.js @@ -0,0 +1,91 @@ +import Gtk from "gi://Gtk"; +import Adw from "gi://Adw"; + +const scrolled_window = workbench.builder.get_object("scrolled_window"); +const container = workbench.builder.get_object("container"); +const toggle_orientation = workbench.builder.get_object("toggle_orientation"); +const button_start = workbench.builder.get_object("button_start"); +const button_end = workbench.builder.get_object("button_end"); + +const scrollbars = [ + scrolled_window.get_hscrollbar(), + scrolled_window.get_vscrollbar(), +]; +let orientation = 0; +toggle_orientation.connect("toggled", () => { + if (toggle_orientation.active) { + container.orientation = Gtk.Orientation.HORIZONTAL; + orientation = 0; + } else { + container.orientation = Gtk.Orientation.VERTICAL; + orientation = 1; + } +}); + +const num_items = 20; +for (let i = 0; i < num_items; i++) { + populateContainer(container, `Item ${i + 1}`); +} + +scrolled_window.connect("edge-reached", () => { + console.log("Edge Reached"); +}); + +button_start.connect("clicked", () => { + disableButtons(); + const scrollbar = scrollbars[orientation]; + const anim = createScrollbarAnim(scrollbar, 0); + anim.play(); +}); + +button_end.connect("clicked", () => { + disableButtons(); + const scrollbar = scrollbars[orientation]; + const anim = createScrollbarAnim(scrollbar, 1); + anim.play(); +}); + +function populateContainer(container, label) { + const item = new Adw.Bin({ + margin_top: 6, + margin_bottom: 6, + margin_start: 6, + margin_end: 6, + child: new Gtk.Label({ + label: label, + width_request: 100, + height_request: 100, + }), + css_classes: ["card"], + }); + container.append(item); +} + +function disableButtons() { + button_end.sensitive = false; + button_start.sensitive = false; +} + +function enableButtons() { + button_end.sensitive = true; + button_start.sensitive = true; +} + +function createScrollbarAnim(scrollbar, direction) { + // direction = 0 -> Animates to Start + // direction = 1 -> Animates to End + const adjustment = scrollbar.adjustment; + const target = Adw.PropertyAnimationTarget.new(adjustment, "value"); + const animation = new Adw.TimedAnimation({ + widget: scrollbar, + value_from: adjustment.value, + value_to: direction ? adjustment.upper : 0, + duration: 3000, + easing: Adw.Easing["LINEAR"], + target: target, + }); + animation.connect("done", () => { + enableButtons(); + }); + return animation; +} diff --git a/src/Library/demos/Scrolled Window/main.json b/src/Library/demos/Scrolled Window/main.json new file mode 100644 index 000000000..c422c2ec0 --- /dev/null +++ b/src/Library/demos/Scrolled Window/main.json @@ -0,0 +1,10 @@ +{ + "name": "Scrolled Window", + "category": "layout", + "description": "A container that makes its child scrollable", + "panels": [ + "ui", + "preview" + ], + "autorun": true +} From e90d3d2b23d5b67319b476f2c691d96bf8414dde Mon Sep 17 00:00:00 2001 From: AkshayWarrier Date: Thu, 20 Jul 2023 02:49:08 +0530 Subject: [PATCH 3/8] Scrolled Window: Minor change --- src/Library/demos/Scrolled Window/main.blp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Library/demos/Scrolled Window/main.blp b/src/Library/demos/Scrolled Window/main.blp index f25b6ee7e..57f16b258 100644 --- a/src/Library/demos/Scrolled Window/main.blp +++ b/src/Library/demos/Scrolled Window/main.blp @@ -68,7 +68,7 @@ Adw.StatusPage { } LinkButton { - label: "Documentation"; + label: "API Reference"; uri: "https://docs.gtk.org/gtk4/class.ScrolledWindow.html"; } } From 75c07263e85318ee9aa8561c33f56bb3b11603fc Mon Sep 17 00:00:00 2001 From: AkshayWarrier Date: Mon, 7 Aug 2023 22:20:17 +0530 Subject: [PATCH 4/8] Scrolled Window: Enable/disable start and end buttons properly --- src/Library/demos/Scrolled Window/main.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Library/demos/Scrolled Window/main.js b/src/Library/demos/Scrolled Window/main.js index 69cc52a3d..ff265869e 100644 --- a/src/Library/demos/Scrolled Window/main.js +++ b/src/Library/demos/Scrolled Window/main.js @@ -7,6 +7,8 @@ const toggle_orientation = workbench.builder.get_object("toggle_orientation"); const button_start = workbench.builder.get_object("button_start"); const button_end = workbench.builder.get_object("button_end"); +button_start.sensitive = false; + const scrollbars = [ scrolled_window.get_hscrollbar(), scrolled_window.get_vscrollbar(), @@ -28,6 +30,11 @@ for (let i = 0; i < num_items; i++) { } scrolled_window.connect("edge-reached", () => { + const scrollbar = scrollbars[orientation]; + const adj = scrollbar.adjustment; + // Enable end button if scrollbar is at the start + button_end.sensitive = adj.value === adj.lower; + button_start.sensitive = !button_end.sensitive; console.log("Edge Reached"); }); @@ -62,13 +69,8 @@ function populateContainer(container, label) { } function disableButtons() { - button_end.sensitive = false; button_start.sensitive = false; -} - -function enableButtons() { - button_end.sensitive = true; - button_start.sensitive = true; + button_end.sensitive = false; } function createScrollbarAnim(scrollbar, direction) { @@ -79,13 +81,10 @@ function createScrollbarAnim(scrollbar, direction) { const animation = new Adw.TimedAnimation({ widget: scrollbar, value_from: adjustment.value, - value_to: direction ? adjustment.upper : 0, - duration: 3000, + value_to: direction ? adjustment.upper - adjustment.page_size : 0, + duration: 1000, easing: Adw.Easing["LINEAR"], target: target, }); - animation.connect("done", () => { - enableButtons(); - }); return animation; } From 0d1a0bb2f4493840bf397820315fd640b465c4d7 Mon Sep 17 00:00:00 2001 From: AkshayWarrier Date: Thu, 10 Aug 2023 13:53:07 +0530 Subject: [PATCH 5/8] Scrolled Window: Better behaviour --- src/Library/demos/Scrolled Window/main.js | 52 ++++++++++++++--------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/Library/demos/Scrolled Window/main.js b/src/Library/demos/Scrolled Window/main.js index ff265869e..f77f60108 100644 --- a/src/Library/demos/Scrolled Window/main.js +++ b/src/Library/demos/Scrolled Window/main.js @@ -6,21 +6,20 @@ const container = workbench.builder.get_object("container"); const toggle_orientation = workbench.builder.get_object("toggle_orientation"); const button_start = workbench.builder.get_object("button_start"); const button_end = workbench.builder.get_object("button_end"); +let auto_scrolling = false; button_start.sensitive = false; -const scrollbars = [ - scrolled_window.get_hscrollbar(), - scrolled_window.get_vscrollbar(), -]; -let orientation = 0; +const scrollbars = { + [Gtk.Orientation.HORIZONTAL]: scrolled_window.get_hscrollbar(), + [Gtk.Orientation.VERTICAL]: scrolled_window.get_vscrollbar(), +}; + toggle_orientation.connect("toggled", () => { if (toggle_orientation.active) { container.orientation = Gtk.Orientation.HORIZONTAL; - orientation = 0; } else { container.orientation = Gtk.Orientation.VERTICAL; - orientation = 1; } }); @@ -29,25 +28,39 @@ for (let i = 0; i < num_items; i++) { populateContainer(container, `Item ${i + 1}`); } -scrolled_window.connect("edge-reached", () => { +for (const orientation in scrollbars) { const scrollbar = scrollbars[orientation]; const adj = scrollbar.adjustment; - // Enable end button if scrollbar is at the start - button_end.sensitive = adj.value === adj.lower; - button_start.sensitive = !button_end.sensitive; + adj.connect("value-changed", () => { + if (adj.value === adj.lower) { + button_end.sensitive = true; + button_start.sensitive = false; + } else if (adj.value === adj.upper - adj.page_size) { + button_end.sensitive = false; + button_start.sensitive = true; + } else { + // Disable buttons if scrollbar is auto-scrolling + button_end.sensitive = !auto_scrolling; + button_start.sensitive = !auto_scrolling; + } + }); +} + +scrolled_window.connect("edge-reached", () => { + const scrollbar = scrollbars[container.orientation]; console.log("Edge Reached"); }); button_start.connect("clicked", () => { - disableButtons(); - const scrollbar = scrollbars[orientation]; + auto_scrolling = true; + const scrollbar = scrollbars[container.orientation]; const anim = createScrollbarAnim(scrollbar, 0); anim.play(); }); button_end.connect("clicked", () => { - disableButtons(); - const scrollbar = scrollbars[orientation]; + auto_scrolling = true; + const scrollbar = scrollbars[container.orientation]; const anim = createScrollbarAnim(scrollbar, 1); anim.play(); }); @@ -68,11 +81,6 @@ function populateContainer(container, label) { container.append(item); } -function disableButtons() { - button_start.sensitive = false; - button_end.sensitive = false; -} - function createScrollbarAnim(scrollbar, direction) { // direction = 0 -> Animates to Start // direction = 1 -> Animates to End @@ -86,5 +94,9 @@ function createScrollbarAnim(scrollbar, direction) { easing: Adw.Easing["LINEAR"], target: target, }); + + animation.connect("done", () => { + auto_scrolling = false; + }); return animation; } From 520c09ae0de98c8b320d718f8b07c3b408424c27 Mon Sep 17 00:00:00 2001 From: halfmexican <103920890+halfmexican@users.noreply.github.com> Date: Fri, 11 Aug 2023 08:13:58 -0500 Subject: [PATCH 6/8] library: add Overlay Split View entry (#463) --- src/Library/demos/Overlay Split View/main.blp | 85 +++++++++++++++++++ src/Library/demos/Overlay Split View/main.js | 13 +++ .../demos/Overlay Split View/main.json | 7 ++ 3 files changed, 105 insertions(+) create mode 100644 src/Library/demos/Overlay Split View/main.blp create mode 100644 src/Library/demos/Overlay Split View/main.js create mode 100644 src/Library/demos/Overlay Split View/main.json diff --git a/src/Library/demos/Overlay Split View/main.blp b/src/Library/demos/Overlay Split View/main.blp new file mode 100644 index 000000000..1e6502b5d --- /dev/null +++ b/src/Library/demos/Overlay Split View/main.blp @@ -0,0 +1,85 @@ +using Gtk 4.0; +using Adw 1; + +Adw.Window { + width-request: 360; + height-request: 200; + default-width: 640; + default-height: 480; + title: _("Overlay Split view"); + + Adw.Breakpoint { + condition ("max-width: 400sp") + setters { + split_view.collapsed: true; + } + } + + content: Adw.ToolbarView { + top-bar-style: raised; + + [top] + Adw.HeaderBar { + + [start] + ToggleButton show_sidebar_button { + icon-name: "dock-left"; + tooltip-text: _("Toggle Sidebar"); + active: bind split_view.show-sidebar; + visible: bind start_toggle.active; + } + + [end] + ToggleButton { + icon-name: "dock-right"; + tooltip-text: _("Toggle Sidebar"); + active: bind show_sidebar_button.active; + visible: bind end_toggle.active; + } + } + + content: Adw.OverlaySplitView split_view { + show-sidebar: bind show_sidebar_button.active; + + sidebar: Adw.StatusPage { + title: _("Sidebar"); + + child: Box { + orientation: vertical; + halign: center; + spacing: 18; + + ToggleButton start_toggle { + label: _("Start"); + can-shrink: true; + active: true; + styles ["pill"] + } + + ToggleButton end_toggle { + label: _("End"); + can-shrink: true; + group: start_toggle; + styles ["pill"] + } + }; + }; + + content: Adw.StatusPage { + title: _("Content"); + + Box { + orientation: vertical; + valign: center; + spacing: 18; + + LinkButton { + label: "API Reference"; + uri: "https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.OverlaySplitView.html"; + margin-top: 24; + } + } + }; + }; + }; +} diff --git a/src/Library/demos/Overlay Split View/main.js b/src/Library/demos/Overlay Split View/main.js new file mode 100644 index 000000000..44ae37e2c --- /dev/null +++ b/src/Library/demos/Overlay Split View/main.js @@ -0,0 +1,13 @@ +import Gtk from "gi://Gtk"; + +const split_view = workbench.builder.get_object("split_view"); +const start_toggle = workbench.builder.get_object("start_toggle"); +const end_toggle = workbench.builder.get_object("end_toggle"); + +start_toggle.connect("toggled", () => { + split_view.sidebar_position = Gtk.PackType.START; +}); + +end_toggle.connect("toggled", () => { + split_view.sidebar_position = Gtk.PackType.END; +}); diff --git a/src/Library/demos/Overlay Split View/main.json b/src/Library/demos/Overlay Split View/main.json new file mode 100644 index 000000000..3e9dee673 --- /dev/null +++ b/src/Library/demos/Overlay Split View/main.json @@ -0,0 +1,7 @@ +{ + "name": "Overlay Split View", + "category": "navigation", + "description": "A content and sidebar view", + "panels": ["ui", "preview"], + "autorun": true +} From 07ed8db2b58880f26abd24155f24cbb6fe816d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20Iv=C3=A1n=20M=2EE?= <76420970+Diego-Ivan@users.noreply.github.com> Date: Fri, 11 Aug 2023 07:21:04 -0600 Subject: [PATCH 7/8] library: Port system APIs demos to Vala (#483) * library: Port Wallpaper and Screenshot demos to Vala * library: Port Account and Color Picker demos to Vala * library: Port Email demo to Vala * library: Port Location demo to Vala --- src/Library/demos/Account/main.vala | 54 ++++++++++ src/Library/demos/Color Picker/main.vala | 36 +++++++ src/Library/demos/Email/main.vala | 40 ++++++++ src/Library/demos/Location/main.vala | 125 +++++++++++++++++++++++ src/Library/demos/Screenshot/main.vala | 37 +++++++ src/Library/demos/Wallpaper/main.vala | 33 ++++++ 6 files changed, 325 insertions(+) create mode 100644 src/Library/demos/Account/main.vala create mode 100644 src/Library/demos/Color Picker/main.vala create mode 100644 src/Library/demos/Email/main.vala create mode 100644 src/Library/demos/Location/main.vala create mode 100644 src/Library/demos/Screenshot/main.vala create mode 100644 src/Library/demos/Wallpaper/main.vala diff --git a/src/Library/demos/Account/main.vala b/src/Library/demos/Account/main.vala new file mode 100644 index 000000000..b1e1cfcf8 --- /dev/null +++ b/src/Library/demos/Account/main.vala @@ -0,0 +1,54 @@ +#!/usr/bin/env -S vala workbench.vala --pkg libadwaita-1 --pkg libportal-gtk4 + +private Gtk.Revealer revealer; +private Adw.EntryRow entry; +private Adw.Avatar avatar; +private Gtk.Label username; +private Gtk.Label display; +private Xdp.Portal portal; +private Xdp.Parent parent; + +public void main () { + portal = new Xdp.Portal (); + parent = Xdp.parent_new_gtk (workbench.window); + + revealer = (Gtk.Revealer) workbench.builder.get_object ("revealer"); + entry = (Adw.EntryRow) workbench.builder.get_object ("entry"); + avatar = (Adw.Avatar) workbench.builder.get_object ("avatar"); + username = (Gtk.Label) workbench.builder.get_object ("username"); + display = (Gtk.Label) workbench.builder.get_object ("name"); + + var button = (Gtk.Button) workbench.builder.get_object ("button"); + button.clicked.connect (on_button_clicked); +} + +private async void on_button_clicked () { + try { + string reason = entry.text; + Variant result = yield portal.get_user_information (parent, reason, NONE, null); + + /* + * result is a Variant dictionary containing the following fields: + * id (s): the user id + * name (s): the users real name + * image (s): the uri of an image file for the users avatar picture + */ + + var id = (string) result.lookup_value ("id", VariantType.STRING); + var name = (string) result.lookup_value ("name", VariantType.STRING); + var uri = (string) result.lookup_value ("image", VariantType.STRING); + + var file = File.new_for_uri (uri); + var texture = Gdk.Texture.from_file (file); + + username.label = id; + display.label = name; + avatar.custom_image = texture; + revealer.reveal_child = true; + + entry.text = ""; + message ("Information Retrieved"); + } catch (Error e) { + critical (e.message); + } +} diff --git a/src/Library/demos/Color Picker/main.vala b/src/Library/demos/Color Picker/main.vala new file mode 100644 index 000000000..7663a5174 --- /dev/null +++ b/src/Library/demos/Color Picker/main.vala @@ -0,0 +1,36 @@ +#!/usr/bin/env -S vala workbench.vala --pkg libadwaita-1 --pkg libportal-gtk4 + +private Xdp.Portal portal; +private Xdp.Parent parent; + +public void main () { + portal = new Xdp.Portal (); + parent = Xdp.parent_new_gtk (workbench.window); + + var button = (Gtk.Button) workbench.builder.get_object ("button"); + button.clicked.connect (on_button_clicked); +} + +private async void on_button_clicked () { + try { + // result is a variant of the form (ddd), containing red green and blue components in the range [0,1] + Variant result = yield portal.pick_color (parent, null); + + double r, g, b; + VariantIter iter = result.iterator (); // Iterate over the array in the variant + iter.next ("d", out r); + iter.next ("d", out g); + iter.next ("d", out b); + + var color = Gdk.RGBA () { + red = (float) r, + green = (float) g, + blue = (float) b, + alpha = 1.0f + }; + + message (@"Selected color is $color"); + } catch (Error e) { + critical (e.message); + } +} diff --git a/src/Library/demos/Email/main.vala b/src/Library/demos/Email/main.vala new file mode 100644 index 000000000..a4624c526 --- /dev/null +++ b/src/Library/demos/Email/main.vala @@ -0,0 +1,40 @@ +#!/usr/bin/env -S vala workbench.vala --pkg libadwaita-1 --pkg libportal-gtk4 + +private Xdp.Portal portal; +private Xdp.Parent parent; +private Gtk.Entry entry; + +public void main () { + portal = new Xdp.Portal (); + parent = Xdp.parent_new_gtk (workbench.window); + + entry = (Gtk.Entry) workbench.builder.get_object ("entry"); + var button = (Gtk.Button) workbench.builder.get_object ("button"); + button.clicked.connect (on_button_clicked); +} + +private async void on_button_clicked () { + string email_address = entry.text; + + try { + bool success = yield portal.compose_email ( + parent, + { email_address }, // addresses + null, // cc + null, // bcc + "Email from Workbench", // subject + "Hello World!", // body + null, + NONE, + null + ); + + if (success) { + message ("Success"); + return; + } + message ("Failure: verify that you have an email application."); + } catch (Error e) { + critical (e.message); + } +} diff --git a/src/Library/demos/Location/main.vala b/src/Library/demos/Location/main.vala new file mode 100644 index 000000000..34a0ebe32 --- /dev/null +++ b/src/Library/demos/Location/main.vala @@ -0,0 +1,125 @@ +#!/usr/bin/env -S vala workbench.vala --pkg libadwaita-1 --pkg libportal-gtk4 + +private Xdp.Portal portal; +private Xdp.Parent parent; + +private Gtk.Revealer revealer; +private Gtk.Button start_button; +private Gtk.Button close_button; +private Gtk.SpinButton distance_threshold; +private Gtk.SpinButton time_threshold; +private Adw.ComboRow accuracy_button; + +private Gtk.Label latitude_label; +private Gtk.Label longitude_label; +private Gtk.Label accuracy_label; +private Gtk.Label altitude_label; +private Gtk.Label speed_label; +private Gtk.Label heading_label; +private Gtk.Label description_label; +private Gtk.Label timestamp_label; + +public void main () { + portal = new Xdp.Portal (); + parent = Xdp.parent_new_gtk (workbench.window); + + revealer = (Gtk.Revealer) workbench.builder.get_object ("revealer"); + start_button = (Gtk.Button) workbench.builder.get_object ("start"); + close_button = (Gtk.Button) workbench.builder.get_object ("close"); + distance_threshold = (Gtk.SpinButton) workbench.builder.get_object ("distance_threshold"); + time_threshold = (Gtk.SpinButton) workbench.builder.get_object ("time_threshold"); + accuracy_button = (Adw.ComboRow) workbench.builder.get_object ("accuracy_button"); + + latitude_label = (Gtk.Label) workbench.builder.get_object ("latitude"); + longitude_label = (Gtk.Label) workbench.builder.get_object ("longitude"); + accuracy_label = (Gtk.Label) workbench.builder.get_object ("accuracy"); + altitude_label = (Gtk.Label) workbench.builder.get_object ("altitude"); + speed_label = (Gtk.Label) workbench.builder.get_object ("speed"); + heading_label = (Gtk.Label) workbench.builder.get_object ("heading"); + description_label = (Gtk.Label) workbench.builder.get_object ("description"); + timestamp_label = (Gtk.Label) workbench.builder.get_object ("timestamp"); + + start_button.clicked.connect (start_session); + close_button.clicked.connect (close_session); + + time_threshold.value_changed.connect (() => { + message ("Time threshold changed"); + restart_session (); + }); + + distance_threshold.value_changed.connect (() => { + message ("Distance threshold changed"); + restart_session (); + }); + + accuracy_button.notify["selected-item"].connect (() => { + message ("Accuracy changed"); + restart_session (); + }); + + portal.location_updated.connect (on_location_updated); +} + +private void on_location_updated ( + double latitude, + double longitude, + double altitude, + double accuracy, + double speed, + double heading, + string description, + int64 timestamp_seconds, + int64 timestamp_ms +) { + message ("Location updated"); + latitude_label.label = latitude.to_string (); + longitude_label.label = longitude.to_string (); + accuracy_label.label = accuracy.to_string (); + altitude_label.label = altitude.to_string (); + speed_label.label = speed.to_string (); + heading_label.label = heading.to_string (); + description_label.label = description; + + // Convert UNIX timestamp to local date and time string + var timestamp = new DateTime.from_unix_local (timestamp_ms); + timestamp_label.label = timestamp.to_string (); +} + +private void restart_session () { + portal.location_monitor_stop (); + revealer.reveal_child = false; + start_session.begin (); +} + +private async void start_session () { + start_button.sensitive = false; + close_button.sensitive = true; + + try { + bool result = yield portal.location_monitor_start ( + parent, + (uint) distance_threshold.value, + (uint) time_threshold.value, + (Xdp.LocationAccuracy) accuracy_button.selected, + NONE, + null + ); + + if (result) { + message ("Location access granted"); + revealer.reveal_child = true; + return; + } + message ("Error retrieving location"); + } catch (Error e) { + critical (e.message); + } +} + +private void close_session () { + start_button.sensitive = false; + close_button.sensitive = false; + portal.location_monitor_stop (); + revealer.reveal_child = false; + message ("Session Closed"); +} diff --git a/src/Library/demos/Screenshot/main.vala b/src/Library/demos/Screenshot/main.vala new file mode 100644 index 000000000..6cb7d6c4e --- /dev/null +++ b/src/Library/demos/Screenshot/main.vala @@ -0,0 +1,37 @@ +#!/usr/bin/env -S vala workbench.vala --pkg libadwaita-1 --pkg libportal-gtk4 + +private Xdp.Portal portal; +private Xdp.Parent parent; +private Gtk.Picture picture; + +public void main () { + portal = new Xdp.Portal (); + parent = Xdp.parent_new_gtk (workbench.window); + picture = (Gtk.Picture) workbench.builder.get_object ("picture"); + + var button = (Gtk.Button) workbench.builder.get_object ("button"); + button.clicked.connect (on_button_clicked); +} + +private async void on_button_clicked () { + try { + string uri = yield portal.take_screenshot (parent, NONE, null); + picture.file = File.new_for_uri (uri); + } catch (Error e) { + show_permission_error (); + } +} + +private void show_permission_error () { + var dialog = new Adw.MessageDialog ( + workbench.window, + "Permission Error", + "Ensure Screenshot permission is enabled in\nSettings → Apps → Workbench" + ) { + close_response = "ok", + modal = true, + }; + + dialog.add_response ("ok", "OK"); + dialog.present (); +} diff --git a/src/Library/demos/Wallpaper/main.vala b/src/Library/demos/Wallpaper/main.vala new file mode 100644 index 000000000..dd7e610cf --- /dev/null +++ b/src/Library/demos/Wallpaper/main.vala @@ -0,0 +1,33 @@ +#!/usr/bin/env -S vala workbench.vala --pkg libadwaita-1 --pkg libportal-gtk4 + +private Xdp.Portal portal; +private Xdp.Parent parent; +private string image_uri; + +public void main () { + portal = new Xdp.Portal (); + parent = Xdp.parent_new_gtk (workbench.window); + image_uri = workbench.resolve ("./wallpaper.png"); + + var button = (Gtk.Button) workbench.builder.get_object ("button"); + button.clicked.connect (on_button_clicked); +} + +private async void on_button_clicked () { + try { + bool success = yield portal.set_wallpaper ( + parent, + image_uri, + PREVIEW | BACKGROUND | LOCKSCREEN, + null + ); + + if (success) { + message ("Wallpaper set successfully"); + return; + } + message ("Could not set wallpaper"); + } catch (Error e) { + critical (e.message); + } +} From 20bf5c4338bc4527a21d4cc6503f2d330060debe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20Iv=C3=A1n=20M=2EE?= <76420970+Diego-Ivan@users.noreply.github.com> Date: Sat, 12 Aug 2023 05:03:07 -0600 Subject: [PATCH 8/8] library: Port Event Controllers demo to Vala (#486) * library: Port Event Controllers demo to Vala * library: Cast workbench.window when add_controller is called --- src/Library/demos/Event Controllers/main.vala | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/Library/demos/Event Controllers/main.vala diff --git a/src/Library/demos/Event Controllers/main.vala b/src/Library/demos/Event Controllers/main.vala new file mode 100644 index 000000000..e2328c497 --- /dev/null +++ b/src/Library/demos/Event Controllers/main.vala @@ -0,0 +1,90 @@ +#!/usr/bin/env -S vala workbench.vala --pkg libadwaita-1 + +private bool ctrl_pressed = false; + +public void main () { + Gtk.Window window = workbench.window; + + var pic1 = (Gtk.Picture) workbench.builder.get_object ("pic1"); + var pic2 = (Gtk.Picture) workbench.builder.get_object ("pic2"); + + pic1.file = File.new_for_uri (workbench.resolve ("image1.png")); + pic2.file = File.new_for_uri (workbench.resolve ("image2.png")); + + var stack = (Gtk.Stack) workbench.builder.get_object ("stack"); + var primary_button = (Gtk.Button) workbench.builder.get_object ("primary_button"); + var middle_button = (Gtk.Button) workbench.builder.get_object ("middle_button"); + var secondary_button = (Gtk.Button) workbench.builder.get_object ("secondary_button"); + var ctrl_button = (Gtk.Button) workbench.builder.get_object ("ctrl_button"); + + var key_controller = new Gtk.EventControllerKey (); + // Gtk.Window hides Gtk.Widget's add_controller method, thus we need to cast it + ((Gtk.Widget) window).add_controller (key_controller); + + key_controller.key_pressed.connect ((keyval, keycode, state) => { + if (keyval == Gdk.Key.Control_L || keyval == Gdk.Key.Control_R) { + ctrl_pressed = true; + } + return true; + }); + + key_controller.key_released.connect ((keyval, keycode, state) => { + if (keyval == Gdk.Key.Control_L || keyval == Gdk.Key.Control_R) { + ctrl_pressed = false; + } + }); + + ctrl_button.clicked.connect (() => { + if (ctrl_pressed) { + ctrl_button.label = "Click to Deactivate"; + ctrl_button.add_css_class ("suggested-action"); + } else { + ctrl_button.label = "Ctrl + Click to Activate"; + ctrl_button.remove_css_class ("suggested-action"); + } + }); + + var gesture_click = new Gtk.GestureClick () { + button = 0 + }; + ((Gtk.Widget) window).add_controller (gesture_click); + + gesture_click.pressed.connect ((gesture, n_press, x, y) => { + switch (gesture.get_current_button ()) { + case Gdk.BUTTON_PRIMARY: + primary_button.add_css_class ("suggested-action"); + break; + case Gdk.BUTTON_MIDDLE: + middle_button.add_css_class ("suggested-action"); + break; + case Gdk.BUTTON_SECONDARY: + secondary_button.add_css_class ("suggested-action"); + break; + } + }); + + gesture_click.released.connect ((gesture, n_press, x, y) => { + switch (gesture.get_current_button ()) { + case Gdk.BUTTON_PRIMARY: + primary_button.remove_css_class ("suggested-action"); + break; + case Gdk.BUTTON_MIDDLE: + middle_button.remove_css_class ("suggested-action"); + break; + case Gdk.BUTTON_SECONDARY: + secondary_button.remove_css_class ("suggested-action"); + break; + } + }); + + var gesture_swipe = new Gtk.GestureSwipe (); + stack.add_controller (gesture_swipe); + + gesture_swipe.swipe.connect ((vel_x, vel_y) => { + if (vel_x > 0) { + stack.visible_child_name = "pic1"; + } else { + stack.visible_child_name = "pic2"; + } + }); +}