[gnome-games] ui: Add the SavestatesList widget
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games] ui: Add the SavestatesList widget
- Date: Fri, 9 Aug 2019 13:40:19 +0000 (UTC)
commit 2816850f56b745d6e57bfe2d7a387bd0529e1c79
Author: Yetizone <andreii lisita gmail com>
Date: Wed Aug 7 18:44:24 2019 +0300
ui: Add the SavestatesList widget
data/gtk-style.css | 10 +++
data/org.gnome.Games.gresource.xml | 1 +
data/ui/savestates-list.ui | 76 +++++++++++++++++
src/meson.build | 2 +
src/ui/savestates-list-state.vala | 6 ++
src/ui/savestates-list.vala | 171 +++++++++++++++++++++++++++++++++++++
6 files changed, 266 insertions(+)
---
diff --git a/data/gtk-style.css b/data/gtk-style.css
index e1e66c52..410a5f59 100644
--- a/data/gtk-style.css
+++ b/data/gtk-style.css
@@ -12,6 +12,16 @@
padding: 0px;
}
+.savestate-thumbnail {
+ min-width: 64px;
+ min-height: 64px;
+ color: rgba(255, 255, 255, 0.5);
+ background: rgba (0, 0, 0, .5);
+ border: 1px solid rgba (0, 0, 0, .5);
+ margin: 6px;
+ border-radius: 5px;
+}
+
gamesgamethumbnail {
background-color: mix (@theme_base_color, @theme_bg_color, 0.5);
border-width: 1px;
diff --git a/data/org.gnome.Games.gresource.xml b/data/org.gnome.Games.gresource.xml
index 91fef297..d157b0a0 100644
--- a/data/org.gnome.Games.gresource.xml
+++ b/data/org.gnome.Games.gresource.xml
@@ -49,6 +49,7 @@
<file preprocess="xml-stripblanks">ui/resume-dialog.ui</file>
<file preprocess="xml-stripblanks">ui/resume-failed-dialog.ui</file>
<file preprocess="xml-stripblanks">ui/savestate-listbox-row.ui</file>
+ <file preprocess="xml-stripblanks">ui/savestates-list.ui</file>
<file preprocess="xml-stripblanks">ui/search-bar.ui</file>
<file preprocess="xml-stripblanks">ui/shortcuts-window.ui</file>
</gresource>
diff --git a/data/ui/savestates-list.ui b/data/ui/savestates-list.ui
new file mode 100644
index 00000000..4fca186f
--- /dev/null
+++ b/data/ui/savestates-list.ui
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.24"/>
+ <template class="GamesSavestatesList" parent="GtkBox">
+ <child>
+ <object class="GtkRevealer" id="revealer">
+ <property name="visible">True</property>
+ <property name="reveal-child">False</property>
+ <property name="transition-type">slide-left</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkSeparator">
+ <property name="visible">True</property>
+ <style>
+ <class name="sidebar"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolled_window">
+ <property name="visible">True</property>
+ <property name="vexpand">True</property>
+ <property name="width-request">350</property>
+ <child>
+ <object class="GtkListBox" id="list_box">
+ <property name="visible">True</property>
+ <signal name="row-activated" after="yes" handler="on_row_activated"/>
+ <style>
+ <class name="sidebar"/>
+ </style>
+ <child>
+ <object class="GtkListBoxRow" id="new_savestate_row">
+ <property name="visible">True</property>
+ <style>
+ <class name="savestate-row"/>
+ </style>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon-name">list-add-symbolic</property>
+ <property name="pixel-size">32</property>
+ <style>
+ <class name="savestate-thumbnail"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="margin">12</property>
+ <property name="label">Create new savestate</property>
+ <attributes>
+ <!-- "1.2" is the value of "large" -->
+ <attribute name="scale" value="1.2"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/meson.build b/src/meson.build
index 021e7427..467fb9e4 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -181,6 +181,8 @@ vala_sources = [
'ui/resume-dialog.vala',
'ui/resume-failed-dialog.vala',
'ui/savestate-listbox-row.vala',
+ 'ui/savestates-list.vala',
+ 'ui/savestates-list-state.vala',
'ui/search-bar.vala',
'ui/shortcuts-window.vala',
'ui/ui-view.vala',
diff --git a/src/ui/savestates-list-state.vala b/src/ui/savestates-list-state.vala
new file mode 100644
index 00000000..0915d300
--- /dev/null
+++ b/src/ui/savestates-list-state.vala
@@ -0,0 +1,6 @@
+private class Games.SavestatesListState : Object {
+ public signal void load_clicked ();
+ public signal void delete_clicked ();
+
+ public bool is_revealed { get; set; }
+}
diff --git a/src/ui/savestates-list.vala b/src/ui/savestates-list.vala
new file mode 100644
index 00000000..22429fed
--- /dev/null
+++ b/src/ui/savestates-list.vala
@@ -0,0 +1,171 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+[GtkTemplate (ui = "/org/gnome/Games/ui/savestates-list.ui")]
+private class Games.SavestatesList : Gtk.Box {
+ [GtkChild]
+ private Gtk.Revealer revealer;
+ [GtkChild]
+ private Gtk.ListBox list_box;
+ [GtkChild]
+ private Gtk.ListBoxRow new_savestate_row;
+
+ public bool is_revealed {
+ get { return revealer.reveal_child; }
+ set { revealer.reveal_child = value; }
+ }
+
+ private SavestatesListState _state;
+ public SavestatesListState state {
+ get { return _state; }
+ set {
+ if (_state != null)
+ _state.notify["is-revealed"].disconnect (on_state_changed);
+
+ _state = value;
+
+ if (value != null) {
+ value.notify["is-revealed"].connect (on_state_changed);
+ value.load_clicked.connect (on_load_clicked);
+ value.delete_clicked.connect (on_delete_clicked);
+ }
+ }
+ }
+
+ private Runner _runner;
+ public Runner runner {
+ get { return _runner; }
+ set {
+ _runner = value;
+
+ // Remove current savestate rows
+ var list_rows = list_box.get_children ();
+ foreach (var row in list_rows) {
+ if (row != new_savestate_row)
+ list_box.remove (row);
+ }
+
+ if (value == null)
+ return;
+
+ // value != null
+ var savestates = _runner.get_savestates ();
+ foreach (var savestate in savestates) {
+ var list_row = new SavestateListBoxRow (savestate);
+
+ list_box.add (list_row);
+ }
+ }
+ }
+
+ construct {
+ list_box.set_header_func (update_header);
+ }
+
+ [GtkCallback]
+ private void on_row_activated (Gtk.ListBoxRow activated_row) {
+ if (activated_row == new_savestate_row) {
+ var savestate = runner.try_create_savestate (false);
+
+ if (savestate != null) {
+ var savestate_row = new SavestateListBoxRow (savestate);
+
+ list_box.insert (savestate_row, 1);
+ select_and_preview_row (savestate_row);
+ }
+ else {
+ // Savestate creation failed
+ list_box.select_row (list_box.get_row_at_index (1));
+
+ // TODO: Perhaps we should warn the user that the creation of
+ // the savestate failed via an in-app notification ?
+ }
+ } else {
+ var savestate_row = activated_row as SavestateListBoxRow;
+ var savestate = savestate_row.savestate;
+
+ runner.preview_savestate (savestate);
+ }
+ }
+
+ private void on_load_clicked () {
+ if (!try_runner_load_previewed_savestate ()) {
+ // TODO: Here we could show a dialog with one button like
+ // "Failed to load savestate [Ok]"
+ }
+
+ state.is_revealed = false;
+ }
+
+ private bool try_runner_load_previewed_savestate () {
+ try {
+ _runner.load_previewed_savestate ();
+ }
+ catch (Error e) {
+ critical ("Failed to load savestate: %s", e.message);
+
+ return false;
+ }
+
+ // Nothing went wrong
+ return true;
+ }
+
+ private void on_state_changed () {
+ revealer.reveal_child = state.is_revealed;
+
+ if (state.is_revealed) {
+ list_box.select_row (null);
+ runner.capture_current_state_pixbuf ();
+ runner.pause ();
+ }
+ else
+ runner.resume ();
+ }
+
+ private void on_delete_clicked () {
+ var selected_row = list_box.get_selected_row ();
+ var selected_row_index = selected_row.get_index ();
+ var savestate_row = selected_row as SavestateListBoxRow;
+ var savestate = savestate_row.savestate;
+
+ runner.delete_savestate (savestate);
+ list_box.remove (selected_row);
+
+ // Select and preview a new row
+ var next_row = list_box.get_row_at_index (selected_row_index);
+
+ if (next_row == null) { // The last row in the list has been deleted
+ var nr_rows = list_box.get_children ().length ();
+
+ if (nr_rows == 1) {
+ // The only remaining row in the list is the create savestate one
+ runner.preview_current_state ();
+ }
+ else {
+ // The last row of the list has been deleted but there are still
+ // rows remaining in the list
+ var last_row = list_box.get_row_at_index (selected_row_index - 1);
+ select_and_preview_row (last_row);
+ }
+
+ return;
+ }
+
+ select_and_preview_row (next_row);
+ }
+
+ private void update_header (Gtk.ListBoxRow row, Gtk.ListBoxRow? before) {
+ if (before != null && row.get_header () == null) {
+ var separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL);
+ row.set_header (separator);
+ }
+ }
+
+ private void select_and_preview_row (Gtk.ListBoxRow row) {
+ var savestate_row = row as SavestateListBoxRow;
+ var savestate = savestate_row.savestate;
+
+ list_box.select_row (row);
+ runner.preview_savestate (savestate);
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]