Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 58 additions & 2 deletions demo/Views/DialogsView.vala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ public class DialogsView : DemoPage {
construct {
var dialog_button = new Gtk.Button.with_label ("Show Dialog");

var alert_button = new Gtk.Button.with_label ("AlertDialog");

var alert_button_pro = new Gtk.Button.with_label ("AlertDialog+ Pro Ultra Max");

var message_button = new Gtk.Button.with_label ("Show MessageDialog");

toast = new Granite.Toast ("Did something");
Expand All @@ -25,8 +29,10 @@ public class DialogsView : DemoPage {
valign = Gtk.Align.CENTER,
row_spacing = 12
};
grid.attach (dialog_button, 0, 1);
grid.attach (message_button, 0, 2);
grid.attach (dialog_button, 0, 0);
grid.attach (alert_button, 0, 1);
grid.attach (alert_button_pro, 0, 2);
grid.attach (message_button, 0, 3);

var overlay = new Gtk.Overlay () {
child = grid
Expand All @@ -36,6 +42,8 @@ public class DialogsView : DemoPage {
child = overlay;

dialog_button.clicked.connect (show_dialog);
alert_button.clicked.connect (show_alert_dialog);
alert_button_pro.clicked.connect (show_alert_dialog_pro);
message_button.clicked.connect (show_message_dialog);
}

Expand Down Expand Up @@ -76,6 +84,54 @@ public class DialogsView : DemoPage {
dialog.show ();
}

private void show_alert_dialog () {
var dialog = new Granite.AlertDialog (
"Say what happened",
"Provide reassurance. Explain why it happened. Provide a suggestion. Additional help info or links."
) {
transient_for = (Gtk.Window) get_root ()
};

dialog.add_button ("_Cancel", "cancel");

dialog.response.connect (() => {
dialog.destroy ();
});

dialog.present ();
}

private void show_alert_dialog_pro () {
var dialog = new Granite.AlertDialog (
"Say what happened",
"Provide reassurance. Explain why it happened. Provide a suggestion. Additional help info or links."
) {
primary_icon = new ThemedIcon ("applications-development"),
secondary_icon = new ThemedIcon ("dialog-information"),
content = new Gtk.CheckButton.with_label ("Optional choices or content"),
transient_for = (Gtk.Window) get_root ()
};

dialog.add_button ("_Cancel", "cancel");
dialog.add_button ("_Take Action", "accept", SUGGESTED);

dialog.set_response_enabled ("accept", false);

dialog.response.connect ((response_id) => {
if (response_id == "accept") {
toast.send_notification ();
}

dialog.destroy ();
});

dialog.present ();

Timeout.add_once (3000, () => {
dialog.set_response_enabled ("accept", true);
});
}

private void show_message_dialog () {
var message_dialog = new Granite.MessageDialog (
"Basic information and a suggestion",
Expand Down
21 changes: 21 additions & 0 deletions lib/Styles/Granite/AlertDialog.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
window.granite-alert.dialog {
toolbox box.top,
toolbox box.bottom {
padding: 1rem;
}

toolbox box.top {
overlay {
min-width: calc((48px * 2) - 1em);
}

.large-icons {
-gtk-icon-size: 48px;
}
}

toolbox box.bottom button {
min-width: 5em;
}
}

1 change: 1 addition & 0 deletions lib/Styles/Granite/Index.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import '_classes.scss';
@import 'AlertDialog.scss';
@import 'Box.scss';
@import 'Button.scss';
@import 'Dialog.scss';
Expand Down
166 changes: 166 additions & 0 deletions lib/Widgets/AlertDialog.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* SPDX-FileCopyrightText: 2026 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: GPL-2.0-or-later
*/

/**
* A dialog presenting a message or a question
*/
[Version (since = "9.0.0")]
public class Granite.AlertDialog : Gtk.Window {
public signal void response (string response_id);

/**
* Describes the possible styles of {@link Granite.AlertDialog} response buttons
*/
public enum ButtonStyle {
// Default button appearance.
DEFAULT,
// The primary suggested affirmative action/
SUGGESTED,
// Used to draw attention to the potentially damaging consequences. This appearance acts as a warning.
DESTRUCTIVE;

public string to_string () {
switch (this) {
case DESTRUCTIVE:
return Granite.CssClass.DESTRUCTIVE;
case SUGGESTED:
return Granite.CssClass.SUGGESTED;
default:
return "";
}
}
}

/**
* The secondary text, body of the dialog.
*/
public string secondary_text { get; construct set; }

/**
* The {@link GLib.Icon} that is used to display the primary_icon representing the app making the request
*/
public GLib.Icon primary_icon { get; set; }

/**
* The {@link GLib.Icon} that is used to display a secondary_icon representing the action to be performed
*/
public GLib.Icon secondary_icon { get; set; }

/**
* The child widget for the content area
*/
public Gtk.Widget content { get; set; }

private Granite.Box button_box;
private SimpleActionGroup action_group;

/**
* Constructs a new {@link Granite.AlertDialog}.
* See {@link Granite.AlertDialog} for more details.
*
* @param title the title of the dialog
* @param secondary_text the body of the dialog
*/
public AlertDialog (string title, string secondary_text) {
Object (
title: title,
secondary_text: secondary_text
);
}

static construct {
Granite.init ();
}

construct {
var primary_icon = new Gtk.Image.from_icon_name ("") {
halign = START,
icon_size = LARGE
};

var secondary_icon = new Gtk.Image.from_icon_name ("") {
halign = END,
icon_size = LARGE
};

var overlay = new Gtk.Overlay () {
child = secondary_icon,
halign = CENTER
};
overlay.add_overlay (primary_icon);

var header_label = new Granite.HeaderLabel ("") {
size = H3
};

var header = new Granite.Box (VERTICAL);
header.append (overlay);
header.append (header_label);

button_box = new Granite.Box (HORIZONTAL, HALF) {
homogeneous = true
};

var toolbarview = new Granite.ToolBox () {
vexpand = true
};
toolbarview.add_bottom_bar (button_box);
toolbarview.add_top_bar (header);

child = toolbarview;
default_width = 325;
modal = true;

// We need to hide the title area
titlebar = new Gtk.Grid () {
visible = false
};

add_css_class ("dialog");
add_css_class ("granite-alert");

bind_property ("primary-icon", primary_icon, "gicon");
bind_property ("secondary-icon", secondary_icon, "gicon");
bind_property ("content", toolbarview, "content");
bind_property ("title", header_label, "label", SYNC_CREATE);
bind_property ("secondary-text", header_label, "secondary-text", SYNC_CREATE);

action_group = new SimpleActionGroup ();

insert_action_group ("dialog", action_group);

// close_request.connect (() => { response (DELETE_EVENT); });
}

public void add_button (string label, string response_id, ButtonStyle button_style = DEFAULT) {
var response_action = new SimpleAction (response_id, null);
response_action.activate.connect (() => {
response (response_id);
});

action_group.add_action (response_action);

var button = new Gtk.Button.with_label (label) {
action_name = "dialog." + response_id,
use_underline = true
};

if (button_style != DEFAULT) {
button.add_css_class (button_style.to_string ());
}

button_box.append (button);
}

/**
* Set whether a response is enabled. The corresponding button will have {@link Gtk.Widget.sensitive} set accordingly.
*
* Responses are enabled by default
*/
public void set_response_enabled (string response_id, bool enabled) {
var action = (SimpleAction) action_group.lookup_action (response_id);
action.set_enabled (enabled);
}
}
1 change: 1 addition & 0 deletions lib/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ libgranite_sources = files(
'Widgets/AbstractSettingsPage.vala',
'Widgets/AbstractSimpleSettingsPage.vala',
'Widgets/AccelLabel.vala',
'Widgets' / 'AlertDialog.vala',
'Widgets/BackButton.vala',
'Widgets/Bin.vala',
'Widgets/Box.vala',
Expand Down
1 change: 1 addition & 0 deletions po/POTFILES
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ lib/Services/System.vala

lib/Widgets/AbstractSettingsPage.vala
lib/Widgets/AbstractSimpleSettingsPage.vala
lib/Widgets/AlertDialog.vala
lib/Widgets/DatePicker.vala
lib/Widgets/HeaderLabel.vala
lib/Widgets/MessageDialog.vala
Expand Down