Skip to content
Open
Show file tree
Hide file tree
Changes from 15 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
2 changes: 2 additions & 0 deletions demo/GraniteDemo.vala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class Granite.Demo : Gtk.Application {
var controls_view = new ControlsView ();
var maps_view = new MapsView ();
var overlaybar_view = new OverlayBarView ();
var terminal_output_view = new TerminalOutputView ();
var toast_view = new ToastView ();
var settings_uris_view = new SettingsUrisView ();
var style_manager_view = new StyleManagerView ();
Expand All @@ -53,6 +54,7 @@ public class Granite.Demo : Gtk.Application {
main_stack.add_titled (video_view, "video", video_view.title);
main_stack.add_titled (overlaybar_view, "overlaybar", "OverlayBar");
main_stack.add_titled (settings_uris_view, "settings_uris", "Settings URIs");
main_stack.add_titled (terminal_output_view, "terminal_output_view", "Terminal View");
main_stack.add_titled (toast_view, "toasts", "Toast");
main_stack.add_titled (utils_view, "utils", "Utils");
main_stack.add_titled (dialogs_view, "dialogs", "Dialogs");
Expand Down
17 changes: 0 additions & 17 deletions demo/Views/CSSView.vala
Original file line number Diff line number Diff line change
Expand Up @@ -84,21 +84,6 @@ public class CSSView : DemoPage {
card_box.append (card);
card_box.append (card_checkered);

var terminal_label = new Granite.HeaderLabel ("\"terminal\" style class");

var terminal = new Gtk.Label ("[ 73%] Linking C executable granite-demo\n[100%] Built target granite-demo") {
selectable = true,
wrap = true,
xalign = 0,
yalign = 0
};

var terminal_scroll = new Gtk.ScrolledWindow () {
min_content_height = 70,
child = terminal
};
terminal_scroll.add_css_class (Granite.STYLE_CLASS_TERMINAL);

var accent_color_label = new Granite.HeaderLabel ("Colored labels and icons");

var accent_color_box = new Gtk.Box (HORIZONTAL, 6);
Expand Down Expand Up @@ -139,8 +124,6 @@ public class CSSView : DemoPage {
};
box.append (card_header);
box.append (card_box);
box.append (terminal_label);
box.append (terminal_scroll);
box.append (accent_color_label);
box.append (accent_color_box);
box.append (success_color_box);
Expand Down
33 changes: 33 additions & 0 deletions demo/Views/TerminalOutputView.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 20205 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: LGPL-3.0-or-later
*/

public class TerminalOutputView: DemoPage {
construct {
title = "Terminal Output";
var terminal = new Granite.TerminalView () {
autoscroll = true,
vexpand = true,
margin_top = 12,
margin_bottom = 12,
margin_start = 12,
margin_end = 12
};
terminal.append_text ("[ 25%] Performing optimization passes\n");
terminal.append_text ("[ 65%] Inserting nonsense functions to pad binary size\n");
terminal.append_text ("[ 73%] Linking C executable granite-demo\n");
terminal.append_text ("[100%] Built target granite-demo\n");
terminal.append_text ("Counting to one hundred…\n");

for (int i = 0; i <= 100; i++) {
var itos = i.to_string ("%i\n");
terminal.append_text (itos);
}

terminal.add_css_class (Granite.CssClass.CARD);

child = terminal;
}

}
1 change: 1 addition & 0 deletions demo/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ executable(
'Views/OverlayBarView.vala',
'Views/SettingsUrisView.vala',
'Views/StyleManagerView.vala',
'Views/TerminalOutputView.vala',
'Views/ToastView.vala',
'Views/UtilsView.vala',
'Views/VideoView.vala',
Expand Down
10 changes: 10 additions & 0 deletions lib/Constants.vala
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ namespace Granite {
* When used with {@link Gtk.Label} this style includes internal padding. When used with {@link Gtk.TextView}
* interal padding will need to be set with {@link Gtk.Container.border_width}
*/
[Version (deprecated = true, deprecated_since = "7.7.0", replacement = "Granite.TerminalView")]
public const string STYLE_CLASS_TERMINAL = "terminal";
/**
* Style class for title label text in a {@link Granite.MessageDialog}
Expand Down Expand Up @@ -285,6 +286,15 @@ namespace Granite {
* Style class for non-terminal text that uses a monospace font.
*/
public const string MONOSPACE = "monospace";

/**
* Style class for {@link Gtk.Label} or {@link Gtk.TextView} to emulate the appearance of Terminal. This includes
* text color, background color, selection highlighting, and selecting the system monospace font.
*
* When used with {@link Gtk.Label} this style includes internal padding. When used with {@link Gtk.TextView}
* interal padding will need to be set with {@link Gtk.Container.border_width}
*/
internal const string TERMINAL = "terminal";
}

/**
Expand Down
1 change: 1 addition & 0 deletions lib/Styles/Granite/Index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
@import 'MessageDialog.scss';
@import 'OverlayBar.scss';
@import 'Placeholder.scss';
@import 'TerminalView.scss';
@import 'Toast.scss';
@import 'ToolBox.scss';
19 changes: 19 additions & 0 deletions lib/Styles/Granite/TerminalView.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.terminal {
font-family: monospace;

background-color: $SLATE_900;
color: $SILVER_200;

// this is roughly 3 lines
min-height: 9ex;

& selection {
background-color: $SILVER_200;
color: $SLATE_900;

&:backdrop {
// Cancelling values set in non-terminal selection
background-color: inherit;
}
}
}
1 change: 0 additions & 1 deletion lib/Styles/Granite/_classes.scss
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,3 @@ paper {
.monospace {
font-family: monospace;
}

12 changes: 7 additions & 5 deletions lib/Widgets/MessageDialog.vala
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ public class Granite.MessageDialog : Granite.Dialog {
*/
private Gtk.Grid message_grid;

private Gtk.Label? details_view;
//private Gtk.Label? details_view;
private Granite.TerminalView? details_view;

/**
* The {@link Gtk.Expander} used to hold the error details view.
Expand Down Expand Up @@ -308,7 +309,7 @@ public class Granite.MessageDialog : Granite.Dialog {
if (details_view == null) {
secondary_label.margin_bottom = 18;

details_view = new Gtk.Label ("") {
/* details_view = new Gtk.Label ("") {
selectable = true,
wrap = true,
xalign = 0,
Expand All @@ -321,9 +322,10 @@ public class Granite.MessageDialog : Granite.Dialog {
child = details_view
};
scroll_box.add_css_class (Granite.STYLE_CLASS_TERMINAL);

*/
details_view = new Granite.TerminalView ();
expander = new Gtk.Expander (_("Details")) {
child = scroll_box
child = details_view
};

message_grid.attach (expander, 1, 2, 1, 1);
Expand All @@ -333,6 +335,6 @@ public class Granite.MessageDialog : Granite.Dialog {
}
}

details_view.label = error_message;
details_view.append_text (error_message);
}
}
81 changes: 81 additions & 0 deletions lib/Widgets/TerminalView.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* Copyright 2025 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: GPL-2.0-or-later
*/

[Version (since = "7.7.0")]
public class Granite.TerminalView : Granite.Bin {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs documentation. See some of the other widgets for an example. Just needs a simple description of what this widget is and what it's used for


public bool autoscroll { get; construct set; default=false; }

private Gtk.TextBuffer buffer;
private double prev_upper_adj = 0;
private Gtk.ScrolledWindow scrolled_window;

public TerminalView () {
Gtk.TextView view = new Gtk.TextView () {
cursor_visible = false,
editable = false,
monospace = true,
pixels_below_lines = 3,
left_margin = 9,
right_margin = 9,
top_margin = 6,
bottom_margin = 6,
wrap_mode = Gtk.WrapMode.WORD
};

buffer = view.get_buffer ();

scrolled_window = new Gtk.ScrolledWindow () {
child = view,
hexpand = true,
vexpand = true,
hscrollbar_policy = NEVER,
};

this.child = scrolled_window;
this.add_css_class (Granite.CssClass.TERMINAL);

notify["autoscroll"].connect ((s, p) => {
update_autoscroll ();
});
}

private void update_autoscroll () {
// FIXME: this disjoints the window closing and the application finishing
Idle.add (() => {
attempt_scroll ();
if (this.autoscroll) { return GLib.Source.CONTINUE; }
else {return GLib.Source.REMOVE; }
});
}

public void attempt_scroll () {
var adj = scrolled_window.vadjustment;
var units_from_end = prev_upper_adj - adj.page_size - adj.value;

if (adj.upper - prev_upper_adj <= 0) {
return;
}

if (prev_upper_adj <= adj.page_size || units_from_end <= 50) {
adj.value = adj.upper;
}

prev_upper_adj = adj.upper;
}

/* This is useful for specific feedback such as in MessageDialogs
*
* Might also be useful to have a way of enabling direct input for stdout or
* stderr
*/
public void append_text (string text) {
buffer.insert_at_cursor (text, -1);
}

public void replace_text (string text) {
buffer.set_text (text);
}
}
1 change: 1 addition & 0 deletions lib/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ libgranite_sources = files(
'Widgets/SettingsSidebar.vala',
'Widgets/Settings.vala',
'Widgets/SwitchModelButton.vala',
'Widgets/TerminalView.vala',
'Widgets/TimePicker.vala',
'Widgets/ToolBox.vala',
'Widgets/Toast.vala',
Expand Down