Modernized preferences

This commit is contained in:
Nils Lück 2022-08-19 21:18:48 +00:00 committed by Michael Catanzaro
parent 543de0e371
commit f8aa4eab3d
13 changed files with 1163 additions and 1193 deletions

View file

@ -4,7 +4,7 @@
<menu id="app_menu">
<section>
<item>
<attribute name="label" translatable="yes">_New Game</attribute>
<attribute name="label" translatable="yes">_New Game</attribute>
<attribute name="action">app.new</attribute>
</item>
<item>

View file

@ -2,7 +2,8 @@
<gresources>
<gresource prefix="/org/gnome/Chess/ui">
<file preprocess="xml-stripblanks">chess-window.ui</file>
<file preprocess="xml-stripblanks">preferences.ui</file>
<file preprocess="xml-stripblanks">new-game-window.ui</file>
<file preprocess="xml-stripblanks">preferences-window.ui</file>
<file preprocess="xml-stripblanks">promotion-type-selector.ui</file>
</gresource>
<gresource prefix="/org/gnome/Chess/pieces">

158
data/new-game-window.ui Normal file
View file

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<template class="NewGameWindow" parent="AdwPreferencesWindow">
<property name="title" translatable="yes">New Game</property>
<property name="hide-on-close">true</property>
<property name="modal">true</property>
<property name="search-enabled">false</property>
<property name="default_width">400</property>
<property name="default_height">550</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="AdwHeaderBar">
<property name="show-start-title-buttons">false</property>
<property name="show-end-title-buttons">false</property>
<child type="start">
<object class="GtkButton">
<property name="label" translatable="yes">_Cancel</property>
<property name="valign">center</property>
<property name="use-underline">true</property>
<signal name="clicked" handler="gtk_window_close" object="NewGameWindow" swapped="yes"/>
</object>
</child>
<child type="end">
<object class="GtkButton">
<property name="label" translatable="yes">_Start</property>
<property name="valign">center</property>
<property name="use-underline">true</property>
<signal name="clicked" handler="start_game_cb" />
<style>
<class name="suggested-action"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesPage">
<child>
<object class="AdwPreferencesGroup">
<child>
<object class="AdwComboRow" id="opponent_combo">
<property name="title" translatable="yes">_Opposing Player</property>
<property name="use-underline">true</property>
</object>
</child>
<child>
<object class="AdwComboRow" id="play_as_combo">
<property name="title" translatable="yes">_Play As</property>
<property name="use-underline">true</property>
<property name="model">
<object class="AdwEnumListModel">
<property name="enum-type">PlayAs</property>
</object>
</property>
<property name="expression">
<closure type="gchararray" function="play_as_display_name_cb" swapped="true" />
</property>
</object>
</child>
<child>
<object class="AdwComboRow" id="difficulty_combo">
<property name="title" translatable="yes">_Difficulty</property>
<property name="use-underline">true</property>
<property name="model">
<object class="AdwEnumListModel">
<property name="enum-type">Difficulty</property>
</object>
</property>
<property name="expression">
<closure type="gchararray" function="difficulty_display_name_cb" swapped="true" />
</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<property name="title">Time Limit</property>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">_Use Time Limit</property>
<property name="use-underline">true</property>
<property name="activatable_widget">time_limit_switch</property>
<child>
<object class="GtkSwitch" id="time_limit_switch">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">_Minutes Per Side</property>
<property name="use-underline">true</property>
<property name="sensitive" bind-source="time_limit_switch" bind-property="active" bind-flags="default|sync-create" />
<property name="activatable-widget">duration_spin</property>
<child>
<object class="GtkSpinButton" id="duration_spin">
<property name="valign">center</property>
<property name="adjustment">
<object class="GtkAdjustment">
<property name="lower">1</property>
<property name="step-increment">1</property>
<property name="upper">600</property>
</object>
</property>
<property name="value">5.0</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">_Increment In Seconds</property>
<property name="use-underline">true</property>
<property name="sensitive" bind-source="time_limit_switch" bind-property="active" bind-flags="default|sync-create" />
<property name="activatable-widget">increment_spin</property>
<child>
<object class="GtkSpinButton" id="increment_spin">
<property name="valign">center</property>
<property name="adjustment">
<object class="GtkAdjustment">
<property name="lower">0</property>
<property name="step-increment">1</property>
<property name="upper">600</property>
</object>
</property>
<property name="value">0</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwComboRow" id="clock_type_combo" >
<property name="title" translatable="yes">Clock _Type</property>
<property name="use-underline">true</property>
<property name="sensitive" bind-source="time_limit_switch" bind-property="active" bind-flags="default|sync-create" />
<property name="model">
<object class="AdwEnumListModel">
<property name="enum-type">ClockType</property>
</object>
</property>
<property name="expression">
<closure type="gchararray" function="clock_type_display_name_cb" swapped="true" />
</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

View file

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<template class="PreferencesWindow" parent="AdwPreferencesWindow">
<property name="search-enabled">false</property>
<property name="hide-on-close">true</property>
<property name="default_width">400</property>
<property name="default_height">380</property>
<child>
<object class="AdwPreferencesPage">
<child>
<object class="AdwPreferencesGroup">
<child>
<object class="AdwComboRow" id="board_orientation_combo">
<property name="title" translatable="yes">_Board Orientation</property>
<property name="use-underline">true</property>
<property name="model">
<object class="AdwEnumListModel">
<property name="enum-type">BoardOrientation</property>
</object>
</property>
<property name="expression">
<closure type="gchararray" function="board_orientation_display_name_cb" swapped="true" />
</property>
</object>
</child>
<child>
<object class="AdwComboRow" id="move_format_combo">
<property name="title" translatable="yes">_Move Format</property>
<property name="use-underline">true</property>
<property name="model">
<object class="AdwEnumListModel">
<property name="enum-type">MoveFormat</property>
</object>
</property>
<property name="expression">
<closure type="gchararray" function="move_format_display_name_cb" swapped="true" />
</property>
</object>
</child>
<child>
<object class="AdwComboRow" id="piece_style_combo">
<property name="title" translatable="yes">_Piece Style</property>
<property name="use-underline">true</property>
<property name="model">
<object class="AdwEnumListModel">
<property name="enum-type">PieceStyle</property>
</object>
</property>
<property name="expression">
<closure type="gchararray" function="piece_style_display_name_cb" swapped="true" />
</property>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Board _Numbering</property>
<property name="use-underline">true</property>
<property name="activatable_widget">board_numbering_switch</property>
<child>
<object class="GtkSwitch" id="board_numbering_switch">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Move _Hints</property>
<property name="use-underline">true</property>
<property name="activatable_widget">move_hints_switch</property>
<child>
<object class="GtkSwitch" id="move_hints_switch">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

View file

@ -1,661 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<object class="GtkListStore" id="custom_duration_units_model">
<columns>
<column type="gchararray"/>
<column type="gint"/>
</columns>
<data>
<row>
<col id="0" translatable="yes" context="custom_duration_units" comments="Preferences dialog: Combo box entry for time limit">minutes</col>
<col id="1">60</col>
</row>
<row>
<col id="0" translatable="yes" context="custom_duration_units" comments="Preferences dialog: Combo box entry for time limit">hours</col>
<col id="1">3600</col>
</row>
</data>
</object>
<object class="GtkListStore" id="timer_increment_units_model">
<columns>
<column type="gchararray"/>
<column type="gint"/>
</columns>
<data>
<row>
<col id="0" translatable="yes" context="custom_duration_units" comments="Preferences dialog: Combo box entry for timer increment">seconds</col>
<col id="1">1</col>
</row>
<row>
<col id="0" translatable="yes" context="custom_duration_units" comments="Preferences dialog: Combo box entry for timer increment">minutes</col>
<col id="1">60</col>
</row>
</data>
</object>
<object class="GtkListStore" id="clock_type_model">
<columns>
<column type="gchararray"/>
<column type="gint"/>
</columns>
<data>
<row>
<col id="0" translatable="yes" context="custom_duration_units" comments="Preferences dialog: Combo box entry for clock type">Simple</col>
<col id="1">0</col>
</row>
<row>
<col id="0" translatable="yes" context="custom_duration_units" comments="Preferences dialog: Combo box entry for time limit. Fischer is a proper name.">Fischer</col>
<col id="1">1</col>
</row>
<row>
<col id="0" translatable="yes" context="custom_duration_units" comments="Preferences dialog: Combo box entry for time limit. Bronstein is a proper name.">Bronstein</col>
<col id="1">2</col>
</row>
</data>
</object>
<object class="GtkListStore" id="difficulty_model">
<columns>
<column type="gchararray"/>
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes" context="difficulty" comments="Preferences Dialog: Combo box entry for easy game difficulty">Easy</col>
<col id="1">easy</col>
</row>
<row>
<col id="0" translatable="yes" context="difficulty" comments="Preferences Dialog: Combo box entry for normal game difficulty">Normal</col>
<col id="1">normal</col>
</row>
<row>
<col id="0" translatable="yes" context="difficulty" comments="Preferences Dialog: Combo box entry for hard game difficulty">Hard</col>
<col id="1">hard</col>
</row>
</data>
</object>
<object class="GtkAdjustment" id="timer_increment_adjustment">
<property name="lower">1</property>
<property name="upper">59</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<signal name="value-changed" handler="timer_increment_units_changed_cb" swapped="no"/>
</object>
<object class="GtkAdjustment" id="duration_adjustment">
<property name="lower">1</property>
<property name="upper">10</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<signal name="value-changed" handler="duration_changed_cb" swapped="no"/>
</object>
<object class="GtkListStore" id="duration_model">
<columns>
<column type="gchararray"/>
<column type="gint"/>
</columns>
<data>
<row>
<col id="0" translatable="yes" comments="Preferences Dialog: Combo box entry for no game timer">No limit</col>
<col id="1">0</col>
</row>
<row>
<col id="0" translatable="yes" comments="Preferences Dialog: Combo box entry for game timer of five minutes">Five minutes</col>
<col id="1">300</col>
</row>
<row>
<col id="0" translatable="yes" comments="Preferences Dialog: Combo box entry for game timer of ten minutes">Ten minutes</col>
<col id="1">600</col>
</row>
<row>
<col id="0" translatable="yes" comments="Preferences Dialog: Combo box entry for game timer of thirty minutes">Thirty minutes</col>
<col id="1">1800</col>
</row>
<row>
<col id="0" translatable="yes" comments="Preferences Dialog: Combo box entry for game timer of one hour">One hour</col>
<col id="1">3600</col>
</row>
<row>
<col id="0" translatable="yes" comments="Preferences Dialog: Combo box entry for game timer of two hours">Two hours</col>
<col id="1">7200</col>
</row>
<row>
<col id="0" translatable="yes" comments="Preferences Dialog: Combo box entry for game timer of three hours">Three hours</col>
<col id="1">10800</col>
</row>
<row>
<col id="0" translatable="yes" comments="Preferences Dialog: Combo box entry for custom game timer">Custom</col>
<col id="1">-1</col>
</row>
</data>
</object>
<object class="GtkListStore" id="move_format_model">
<columns>
<column type="gchararray"/>
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes" context="chess-move-format" comments="Preferences Dialog: Combo box entry for setting the notation type to human readable descriptions">Human</col>
<col id="1">human</col>
</row>
<row>
<col id="0" translatable="yes" context="chess-move-format" comments="Preferences Dialog: Combo box entry for setting the notation type to standard algebraic (SAN)">Standard Algebraic</col>
<col id="1">san</col>
</row>
<row>
<col id="0" translatable="yes" context="chess-move-format" comments="Preferences Dialog: Combo box entry for setting the notation type to long figurine notation (FAN)">Figurine</col>
<col id="1">fan</col>
</row>
<row>
<col id="0" translatable="yes" context="chess-move-format" comments="Preferences Dialog: Combo box entry for setting the notation type to long algebraic (LAN)">Long Algebraic</col>
<col id="1">lan</col>
</row>
</data>
</object>
<object class="GtkListStore" id="opponent_model">
<columns>
<column type="gchararray"/>
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes" context="chess-opponent" comments="Preferences Dialog: Combo box entry for human opponent">Human</col>
<col id="1">human</col>
</row>
</data>
</object>
<object class="GtkListStore" id="orientation_model">
<columns>
<column type="gchararray"/>
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes" context="chess-side" comments="Preferences Dialog: Combo box entry for setting the board orientation to the white side">White Side</col>
<col id="1">white</col>
</row>
<row>
<col id="0" translatable="yes" context="chess-side" comments="Preferences Dialog: Combo box entry for setting the board orientation to the black side">Black Side</col>
<col id="1">black</col>
</row>
<row>
<col id="0" translatable="yes" context="chess-side" comments="Preferences Dialog: Combo box entry for setting the board orientation to the side the human player is on">Human Side</col>
<col id="1">human</col>
</row>
<row>
<col id="0" translatable="yes" context="chess-side" comments="Preferences Dialog: Combo box entry for setting the board orientation to the side the current active player is on">Current Player</col>
<col id="1">current</col>
</row>
</data>
</object>
<object class="GtkListStore" id="piece_style_model">
<columns>
<column type="gchararray"/>
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes" comments="Preferences Dialog: Combo box entry for simple theme">Simple</col>
<col id="1">simple</col>
</row>
<row>
<col id="0" translatable="yes" comments="Preferences Dialog: Combo box entry for fancy theme">Fancy</col>
<col id="1">fancy</col>
</row>
</data>
</object>
<object class="GtkListStore" id="side_model">
<columns>
<column type="gchararray"/>
<column type="gint"/>
</columns>
<data>
<row>
<col id="0" translatable="yes" context="chess-player" comments="Preferences Dialog: Combo box entry for playing as white">White</col>
<col id="1">0</col>
</row>
<row>
<col id="0" translatable="yes" context="chess-player" comments="Preferences Dialog: Combo box entry for playing as black">Black</col>
<col id="1">1</col>
</row>
<row>
<col id="0" translatable="yes" context="chess-player" comments="Preferences Dialog: Combo box entry for alterning between black and white">Alternate</col>
<col id="1">2</col>
</row>
</data>
</object>
<template class="PreferencesDialog" parent="GtkDialog">
<property name="can-focus">0</property>
<property name="title" translatable="yes" comments="Title for preferences dialog">Preferences</property>
<property name="resizable">0</property>
<property name="destroy-with-parent">1</property>
<property name="use-header-bar">1</property>
<child>
<object class="GtkBox">
<property name="can-focus">0</property>
<child>
<object class="GtkNotebook">
<child>
<object class="GtkNotebookPage">
<property name="child">
<object class="GtkGrid">
<property name="can-focus">0</property>
<property name="column-spacing">6</property>
<property name="row-spacing">6</property>
<property name="margin-start">18</property>
<property name="margin-end">18</property>
<property name="margin-top">18</property>
<property name="margin-bottom">18</property>
<child>
<object class="GtkLabel">
<property name="can-focus">0</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Preferences Dialog: Label before clock type (Fischer/Bronstein) combo box">_Clock type:</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">clock_type_combo</property>
<layout>
<property name="row">5</property>
<property name="column">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="timer_increment_label">
<property name="can-focus">0</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Preferences Dialog: Label before timer increment combo box">Timer _increment:</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">timer_increment_spin</property>
<layout>
<property name="row">6</property>
<property name="column">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBox" id="clock_type_combo">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="model">clock_type_model</property>
<signal name="changed" handler="clock_type_changed_cb" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
<layout>
<property name="row">5</property>
<property name="column">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="can-focus">0</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Preferences Dialog: Label before player side (white/black) combo box">_Play as:</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">side_combo</property>
<layout>
<property name="row">1</property>
<property name="column">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="can-focus">0</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Preferences Dialog: Label before opposing player combo box">_Opposing player:</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">opponent_combo</property>
<layout>
<property name="row">0</property>
<property name="column">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="can-focus">0</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Preferences Dialog: Label before difficulty level combo box">_Difficulty:</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">difficulty_combo</property>
<layout>
<property name="row">2</property>
<property name="column">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkBox" id="timer_increment_box">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="spacing">6</property>
<child>
<object class="GtkSpinButton" id="timer_increment_spin">
<property name="hexpand">1</property>
<property name="adjustment">timer_increment_adjustment</property>
<property name="climb-rate">1</property>
<property name="numeric">1</property>
</object>
</child>
<child>
<object class="GtkComboBox" id="timer_increment_units_combo">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="model">timer_increment_units_model</property>
<signal name="changed" handler="timer_increment_units_changed_cb" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<layout>
<property name="row">6</property>
<property name="column">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBox" id="side_combo">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="model">side_model</property>
<signal name="changed" handler="side_combo_changed_cb" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
<layout>
<property name="row">1</property>
<property name="column">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBox" id="opponent_combo">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="model">opponent_model</property>
<signal name="changed" handler="opponent_combo_changed_cb" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
<layout>
<property name="row">0</property>
<property name="column">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBox" id="difficulty_combo">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="model">difficulty_model</property>
<signal name="changed" handler="difficulty_combo_changed_cb" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
<layout>
<property name="row">2</property>
<property name="column">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkBox" id="custom_duration_box">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="spacing">6</property>
<child>
<object class="GtkSpinButton">
<property name="hexpand">1</property>
<property name="adjustment">duration_adjustment</property>
<property name="climb-rate">1</property>
<property name="numeric">1</property>
</object>
</child>
<child>
<object class="GtkComboBox" id="custom_duration_units_combo">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="model">custom_duration_units_model</property>
<signal name="changed" handler="duration_units_changed_cb" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<layout>
<property name="row">4</property>
<property name="column">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="can-focus">0</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Preferences Dialog: Label before game timer settings">_Time limit:</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">duration_combo</property>
<layout>
<property name="row">3</property>
<property name="column">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBox" id="duration_combo">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="model">duration_model</property>
<signal name="changed" handler="duration_combo_changed_cb" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
<layout>
<property name="row">3</property>
<property name="column">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkBox">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="spacing">5</property>
<child>
<object class="GtkImage">
<property name="can-focus">0</property>
<property name="icon-name">dialog-information-symbolic</property>
<property name="icon-size">large</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Preferences dialog: Label to notify user that the settings are applied for the next game">Changes will take effect for the next game.</property>
</object>
</child>
<layout>
<property name="row">7</property>
<property name="column">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
</object>
</property>
<property name="tab">
<object class="GtkLabel">
<property name="can-focus">0</property>
<property name="label" translatable="yes" comments="Preferences Dialog: Tab title for game preferences">_Game</property>
<property name="use-underline">1</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkNotebookPage">
<property name="child">
<object class="GtkGrid">
<property name="can-focus">0</property>
<property name="column-spacing">6</property>
<property name="row-spacing">6</property>
<property name="margin-start">18</property>
<property name="margin-end">18</property>
<property name="margin-top">18</property>
<property name="margin-bottom">18</property>
<child>
<object class="GtkLabel">
<property name="can-focus">0</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Preferences Dialog: Label before board orientation combo box">Board _orientation:</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">orientation_combo</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="can-focus">0</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Preferences Dialog: Label before move format combo box">Move _format:</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">move_format_combo</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="can-focus">0</property>
<property name="halign">start</property>
<property name="label" translatable="yes" comments="Preferences Dialog: Label before piece style combo box">_Piece style:</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">piece_style_combo</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBox" id="orientation_combo">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="model">orientation_model</property>
<signal name="changed" handler="orientation_combo_changed_cb" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
<layout>
<property name="column">1</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBox" id="move_format_combo">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="model">move_format_model</property>
<signal name="changed" handler="move_format_combo_changed_cb" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
<layout>
<property name="column">1</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBox" id="piece_style_combo">
<property name="hexpand">1</property>
<property name="model">piece_style_model</property>
<signal name="changed" handler="piece_style_combo_changed_cb" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
<layout>
<property name="column">1</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkCheckButton" id="show_numbering_check">
<property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if board numbering is visible">_Board numbering</property>
<property name="use-underline">1</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkCheckButton" id="show_move_hints_check">
<property name="label" translatable="yes" comments="Preferences Dialog: Check box for selecting if move hints are visible">_Move hints</property>
<property name="use-underline">1</property>
<layout>
<property name="column">0</property>
<property name="row">4</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
</object>
</property>
<property name="tab">
<object class="GtkLabel">
<property name="can-focus">0</property>
<property name="label" translatable="yes" comments="Preferences Dialog: Title of appearance options tab">_Appearance</property>
<property name="use-underline">1</property>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

View file

@ -11,7 +11,7 @@
* license.
*/
public enum ClockType
public enum ChessClockType
{
SIMPLE,
FISCHER,
@ -33,7 +33,7 @@ public enum ClockType
}
}
public static ClockType string_to_enum (string s)
public static ChessClockType string_to_enum (string s)
{
switch (s)
{
@ -75,7 +75,7 @@ public class ChessClock : Object
get { return black_initial_seconds + black_extra_seconds - black_seconds_used; }
}
public ClockType clock_type { get; set; default = ClockType.SIMPLE; }
public ChessClockType clock_type { get; set; default = ChessClockType.SIMPLE; }
private Color _active_color = Color.WHITE;
public Color active_color
@ -206,13 +206,13 @@ public class ChessClock : Object
int white_move_used = 0, black_move_used = 0;
switch (clock_type)
{
case ClockType.FISCHER:
case ChessClockType.FISCHER:
if (active_color == Color.WHITE)
white_extra_seconds += extra_seconds;
else
black_extra_seconds += extra_seconds;
break;
case ClockType.BRONSTEIN:
case ChessClockType.BRONSTEIN:
white_move_used = white_seconds_used - white_prev_move_seconds;
black_move_used = black_seconds_used - black_prev_move_seconds;
if (active_color != Color.WHITE)

View file

@ -262,7 +262,7 @@ public class PGN : Object
game.tags.insert ("X-GNOME-BlackTimeLeft", tag_value);
break;
case "X-GNOME-ClockType":
if (ClockType.string_to_enum (tag_value) == ClockType.INVALID)
if (ChessClockType.string_to_enum (tag_value) == ChessClockType.INVALID)
{
warning (_("Invalid clock type in PGN: %s, using a simple clock."), tag_value);
game.tags.insert ("X-GNOME-ClockType", "simple");

View file

@ -30,6 +30,7 @@ public const string QUIT_ACTION_NAME = "quit";
public class ChessApplication : Adw.Application
{
private GLib.Settings settings;
private Preferences preferences;
public unowned ChessWindow window
{
@ -46,7 +47,8 @@ public class ChessApplication : Adw.Application
get { return view.scene; }
}
private PreferencesDialog? preferences_dialog = null;
private NewGameWindow? new_game_window = null;
private PreferencesWindow? preferences_window = null;
private Gtk.AboutDialog? about_dialog = null;
private Gtk.FileChooserNative? open_dialog = null;
private Gtk.FileChooserNative? save_dialog = null;
@ -119,6 +121,7 @@ Copyright © 20152016 Sahil Sareen""";
base.startup ();
settings = new Settings ("org.gnome.Chess");
preferences = new Preferences (settings);
add_action_entries (action_entries, this);
set_accels_for_action ("app." + NEW_GAME_ACTION_NAME, { "<Control>n" });
@ -137,16 +140,16 @@ Copyright © 20152016 Sahil Sareen""";
"<Control>w" });
window = new ChessWindow (this);
window.set_default_size (settings.get_int ("width"), settings.get_int ("height"));
if (settings.get_boolean ("maximized"))
window.set_default_size (settings.get_int (WIDTH_SETTINGS_KEY), settings.get_int (HEIGHT_SETTINGS_KEY));
if (settings.get_boolean (MAXIMIZED_SETTINGS_KEY))
window.maximize ();
add_window (window);
settings.bind ("show-move-hints", scene, "show-move-hints", SettingsBindFlags.GET);
settings.bind ("show-numbering", scene, "show-numbering", SettingsBindFlags.GET);
settings.bind ("piece-theme", scene, "theme-name", SettingsBindFlags.GET);
settings.bind ("move-format", scene, "move-format", SettingsBindFlags.GET);
settings.bind ("board-side", scene, "board-side", SettingsBindFlags.GET);
settings.bind (SHOW_MOVE_HINTS_SETTINGS_KEY, scene, "show-move-hints", SettingsBindFlags.GET);
settings.bind (SHOW_BOARD_NUMBERING_SETTINGS_KEY, scene, "show-numbering", SettingsBindFlags.GET);
settings.bind (PIECE_STYLE_SETTINGS_KEY, scene, "theme-name", SettingsBindFlags.GET);
settings.bind (MOVE_FORMAT_SETTINGS_KEY, scene, "move-format", SettingsBindFlags.GET);
settings.bind (BOARD_ORIENTATION_SETTINGS_KEY, scene, "board-side", SettingsBindFlags.GET);
scene.is_human.connect ((p) => { return p == human_player; });
scene.choose_promotion_type.connect (show_promotion_type_selector);
@ -207,9 +210,9 @@ Copyright © 20152016 Sahil Sareen""";
/* Save window state */
settings.delay ();
settings.set_int ("width", window.default_width);
settings.set_int ("height", window.default_height);
settings.set_boolean ("maximized", window.maximized);
settings.set_int (WIDTH_SETTINGS_KEY, window.default_width);
settings.set_int (HEIGHT_SETTINGS_KEY, window.default_height);
settings.set_boolean (MAXIMIZED_SETTINGS_KEY, window.maximized);
settings.apply ();
base.shutdown ();
@ -275,7 +278,7 @@ Copyright © 20152016 Sahil Sareen""";
catch (Error e)
{
show_invalid_move_dialog (e.message);
start_new_game ();
configure_new_game ();
return;
}
@ -396,16 +399,16 @@ Copyright © 20152016 Sahil Sareen""";
timer_increment_adj_value = int.parse (pgn_game.timer_increment);
else
{
timer_increment_adj_value = settings.get_int ("timer-increment");
timer_increment_adj_value = settings.get_int (INCREMENT_SETTINGS_KEY);
pgn_game.timer_increment = timer_increment_adj_value.to_string ();
}
ClockType clock_type = ClockType.SIMPLE;
ChessClockType clock_type = ChessClockType.SIMPLE;
if (pgn_game.clock_type != null)
clock_type = ClockType.string_to_enum (pgn_game.clock_type);
clock_type = ChessClockType.string_to_enum (pgn_game.clock_type);
else
{
clock_type = ClockType.string_to_enum (settings.get_string ("clock-type"));
clock_type = ChessClockType.string_to_enum (settings.get_string (CLOCK_TYPE_SETTINGS_KEY));
pgn_game.clock_type = clock_type.to_string ();
}
@ -689,8 +692,6 @@ Copyright © 20152016 Sahil Sareen""";
{
/* Warning: this callback is invoked several times when loading a game. */
enable_action (NEW_GAME_ACTION_NAME);
/* Need to save after each move */
game_needs_saving = true;
@ -755,7 +756,6 @@ Copyright © 20152016 Sahil Sareen""";
else
{
game_needs_saving = false;
disable_action (NEW_GAME_ACTION_NAME);
disable_action (SAVE_GAME_ACTION_NAME);
disable_action (SAVE_GAME_AS_ACTION_NAME);
}
@ -838,9 +838,6 @@ Copyright © 20152016 Sahil Sareen""";
disable_action (RESIGN_ACTION_NAME);
disable_action (PAUSE_RESUME_ACTION_NAME);
/* In case of engine desync before the first move, or after undo */
enable_action (NEW_GAME_ACTION_NAME);
game_needs_saving = false;
string what = "";
@ -1060,7 +1057,7 @@ Copyright © 20152016 Sahil Sareen""";
{
prompt_save_game (_("Save this game before starting a new one?"), (cancelled) => {
if (!cancelled)
start_new_game ();
configure_new_game ();
});
}
@ -1162,17 +1159,29 @@ Copyright © 20152016 Sahil Sareen""";
scene.move_number = -1;
}
private void preferences_cb ()
private void configure_new_game ()
{
if (preferences_dialog != null)
if (new_game_window != null)
{
preferences_dialog.show ();
new_game_window.show ();
return;
}
preferences_dialog = new PreferencesDialog (window, settings, ai_profiles);
preferences_dialog.response.connect (() => preferences_dialog.hide ());
preferences_dialog.show ();
new_game_window = new NewGameWindow (window, preferences, ai_profiles);
new_game_window.new_game_requested.connect (() => start_new_game ());
new_game_window.show ();
}
private void preferences_cb ()
{
if (preferences_window != null)
{
preferences_window.show ();
return;
}
preferences_window = new PreferencesWindow (window, preferences);
preferences_window.show ();
}
public void help_cb ()
@ -1463,21 +1472,20 @@ Copyright © 20152016 Sahil Sareen""";
{
game_file = null;
disable_action (NEW_GAME_ACTION_NAME);
disable_action (SAVE_GAME_AS_ACTION_NAME);
pgn_game = new PGNGame ();
var now = new DateTime.now_local ();
pgn_game.date = now.format ("%Y.%m.%d");
pgn_game.time = now.format ("%H:%M:%S");
var duration = settings.get_int ("duration");
var duration = settings.get_int (DURATION_SETTINGS_KEY);
if (duration > 0)
{
pgn_game.time_control = duration.to_string ();
pgn_game.white_time_left = duration.to_string ();
pgn_game.black_time_left = duration.to_string ();
}
var engine_name = settings.get_string ("opponent");
var engine_name = settings.get_string (OPPONENT_SETTINGS_KEY);
if (engine_name == "")
{
if (ai_profiles != null)
@ -1485,14 +1493,14 @@ Copyright © 20152016 Sahil Sareen""";
else
engine_name = "human";
}
var engine_level = settings.get_string ("difficulty");
var engine_level = settings.get_string (DIFFICULTY_SETTINGS_KEY);
if (engine_name != null && engine_name != "human")
{
var play_as = settings.get_string ("play-as");
var play_as = settings.get_string (PLAY_AS_SETTINGS_KEY);
if (play_as == "alternate")
{
var last_side = settings.get_string ("last-played-as");
var last_side = settings.get_string (LAST_PLAYED_AS_SETTINGS_KEY);
play_as = (last_side == "white" ? "black" : "white");
}
@ -1511,7 +1519,7 @@ Copyright © 20152016 Sahil Sareen""";
assert_not_reached ();
}
settings.set_string ("last-played-as", play_as);
settings.set_string (LAST_PLAYED_AS_SETTINGS_KEY, play_as);
}
start_game ();
@ -1519,8 +1527,6 @@ Copyright © 20152016 Sahil Sareen""";
private void load_game (File file)
{
enable_action (NEW_GAME_ACTION_NAME);
try
{
var pgn = new PGN.from_file (file);

View file

@ -5,7 +5,9 @@ chess_sources = [
'chess-view.vala',
'chess-window.vala',
'gnome-chess.vala',
'preferences-dialog.vala',
'new-game-window.vala',
'preferences-window.vala',
'preferences.vala',
'promotion-type-selector-dialog.vala',
]

198
src/new-game-window.vala Normal file
View file

@ -0,0 +1,198 @@
/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Nils Lück
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
* license.
*/
[GtkTemplate (ui = "/org/gnome/Chess/ui/new-game-window.ui")]
public class NewGameWindow : Adw.PreferencesWindow
{
private bool syncing_time_limit = false;
private Preferences preferences;
private unowned List<AIProfile> ai_profiles;
private List<Opponent> opponents = new List<Opponent> ();
public signal void new_game_requested ();
[GtkChild]
private unowned Adw.ComboRow play_as_combo;
[GtkChild]
private unowned Adw.ComboRow difficulty_combo;
[GtkChild]
private unowned Adw.ComboRow opponent_combo;
[GtkChild]
private unowned Adw.ComboRow clock_type_combo;
[GtkChild]
private unowned Gtk.SpinButton duration_spin;
[GtkChild]
private unowned Gtk.SpinButton increment_spin;
[GtkChild]
private unowned Gtk.Switch time_limit_switch;
public NewGameWindow (Gtk.Window window, Preferences preferences, List<AIProfile> ai_profiles)
{
transient_for = window;
this.preferences = preferences;
this.ai_profiles = ai_profiles;
initialize_opponents (ai_profiles);
preferences.bind_property ("play-as", play_as_combo, "selected", BindingFlags.BIDIRECTIONAL | BindingFlags.SYNC_CREATE, null, null);
preferences.bind_property ("difficulty", difficulty_combo, "selected", BindingFlags.BIDIRECTIONAL | BindingFlags.SYNC_CREATE, null, null);
preferences.bind_property (
"opponent",
opponent_combo,
"selected",
BindingFlags.BIDIRECTIONAL | BindingFlags.SYNC_CREATE,
(binding, from_value, ref to_value) =>
{
var opponent = (Opponent) from_value.get_object ();
var position = get_opponent_index (opponent.display_name);
to_value.set_uint (position);
return true;
},
(binding, from_value, ref to_value) =>
{
var position = from_value.get_uint ();
to_value.set_object (opponents.nth_data (position));
return true;
});
time_limit_settings_changed_cb ();
time_limit_switch.notify["active"].connect (time_limit_controls_changed_cb);
clock_type_combo.notify["selected"].connect (time_limit_controls_changed_cb);
duration_spin.value_changed.connect (time_limit_controls_changed_cb);
increment_spin.value_changed.connect (time_limit_controls_changed_cb);
preferences.notify["time-limit"].connect (time_limit_settings_changed_cb);
opponent_combo.bind_property (
"selected",
difficulty_combo,
"sensitive",
BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE,
(binding, from_value, ref to_value) =>
{
var opponent = opponents.nth_data (from_value.get_uint ());
to_value.set_boolean (!opponent.is_human);
return true;
},
null);
opponent_combo.bind_property (
"selected",
play_as_combo,
"sensitive",
BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE,
(binding, from_value, ref to_value) =>
{
var opponent = opponents.nth_data (from_value.get_uint ());
to_value.set_boolean (!opponent.is_human);
return true;
},
null);
}
[GtkCallback]
private void start_game_cb ()
{
close ();
new_game_requested ();
}
[GtkCallback]
private string play_as_display_name_cb (Adw.EnumListItem item)
{
var value = (PlayAs) item.value;
return value.display_name ();
}
[GtkCallback]
private string difficulty_display_name_cb (Adw.EnumListItem item)
{
var value = (Difficulty) item.value;
return value.display_name ();
}
[GtkCallback]
private string clock_type_display_name_cb (Adw.EnumListItem item)
{
var value = (ClockType) item.value;
return value.display_name ();
}
private void time_limit_settings_changed_cb ()
{
if (syncing_time_limit)
return;
syncing_time_limit = true;
if (preferences.time_limit == null)
{
time_limit_switch.active = false;
duration_spin.value = 5;
increment_spin.value = 0;
clock_type_combo.selected = (int) ClockType.FISCHER;
}
else
{
time_limit_switch.active = true;
duration_spin.value = preferences.time_limit.duration_in_seconds / 60.0;
increment_spin.value = preferences.time_limit.increment_in_seconds;
clock_type_combo.selected = (int) preferences.time_limit.clock_type;
}
syncing_time_limit = false;
}
private void time_limit_controls_changed_cb ()
{
if (syncing_time_limit)
return;
syncing_time_limit = true;
if (time_limit_switch.active)
{
var duration_in_seconds = (int) duration_spin.value * 60;
var increment_in_seconds = (int) increment_spin.value;
var clock_type = (ClockType) clock_type_combo.selected;
preferences.time_limit = new TimeLimit (duration_in_seconds, increment_in_seconds, clock_type);
}
else
preferences.time_limit = null;
syncing_time_limit = false;
}
private void initialize_opponents (List<AIProfile> ai_profiles)
{
opponents.append (Opponent.human);
foreach (var ai_profile in ai_profiles)
{
opponents.append (Opponent.from_ai_profile (ai_profile));
}
var opponents_model = new Gtk.StringList (null);
foreach (var opponent in opponents)
{
opponents_model.append(opponent.display_name);
}
opponent_combo.model = opponents_model;
}
private uint get_opponent_index (string display_name)
{
var i = 0;
foreach (var opponent in opponents)
{
if (opponent.display_name == display_name)
return i;
i++;
}
return 0;
}
}

View file

@ -1,485 +0,0 @@
/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2010-2013 Robert Ancell
* Copyright (C) 2013-2020 Michael Catanzaro
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
* license.
*/
[GtkTemplate (ui = "/org/gnome/Chess/ui/preferences.ui")]
public class PreferencesDialog : Gtk.Dialog
{
private Settings settings;
private unowned List<AIProfile> ai_profiles;
private uint save_duration_timeout = 0;
[GtkChild]
private unowned Gtk.CheckButton show_numbering_check;
[GtkChild]
private unowned Gtk.CheckButton show_move_hints_check;
[GtkChild]
private unowned Gtk.ComboBox side_combo;
[GtkChild]
private unowned Gtk.ComboBox difficulty_combo;
[GtkChild]
private unowned Gtk.ComboBox opponent_combo;
[GtkChild]
private unowned Gtk.ListStore opponent_model;
[GtkChild]
private unowned Gtk.Adjustment duration_adjustment;
[GtkChild]
private unowned Gtk.Adjustment timer_increment_adjustment;
[GtkChild]
private unowned Gtk.Box custom_duration_box;
[GtkChild]
private unowned Gtk.Box timer_increment_box;
[GtkChild]
private unowned Gtk.ComboBox custom_duration_units_combo;
[GtkChild]
private unowned Gtk.Label timer_increment_label;
[GtkChild]
private unowned Gtk.ComboBox timer_increment_units_combo;
[GtkChild]
private unowned Gtk.ComboBox clock_type_combo;
[GtkChild]
private unowned Gtk.ComboBox duration_combo;
[GtkChild]
private unowned Gtk.ComboBox orientation_combo;
[GtkChild]
private unowned Gtk.ComboBox move_format_combo;
[GtkChild]
private unowned Gtk.ComboBox piece_style_combo;
public PreferencesDialog (Gtk.Window window, Settings settings, List<AIProfile> ai_profiles)
{
transient_for = window;
modal = true;
this.settings = settings;
this.ai_profiles = ai_profiles;
settings.bind ("show-numbering", show_numbering_check,
"active", SettingsBindFlags.DEFAULT);
settings.bind ("show-move-hints", show_move_hints_check,
"active", SettingsBindFlags.DEFAULT);
side_combo.set_active (settings.get_enum ("play-as"));
set_combo (difficulty_combo, 1, settings.get_string ("difficulty"));
var opponent_name = settings.get_string ("opponent");
if (opponent_name == "human")
opponent_combo.set_active (0);
foreach (var p in ai_profiles)
{
Gtk.TreeIter iter;
opponent_model.append (out iter);
opponent_model.set (iter, 0, p.name, 1, p.name, -1);
if (p.name == opponent_name || (opponent_name == "" && opponent_combo.active == -1))
opponent_combo.set_active_iter (iter);
}
if (opponent_combo.active == -1)
{
opponent_combo.active = 0;
settings.set_string ("opponent", "human");
}
set_duration (settings.get_int ("duration"));
set_clock_type ((int) ClockType.string_to_enum (settings.get_string ("clock-type")));
set_timer_increment (settings.get_int ("timer-increment"));
set_combo (orientation_combo, 1, settings.get_string ("board-side"));
set_combo (move_format_combo, 1, settings.get_string ("move-format"));
set_combo (piece_style_combo, 1, settings.get_string ("piece-theme"));
/* Human vs. human */
if (opponent_combo.get_active () == 0)
{
side_combo.sensitive = false;
difficulty_combo.sensitive = false;
}
}
~PreferencesDialog ()
{
if (save_duration_timeout != 0)
{
Source.remove (save_duration_timeout);
save_duration_cb ();
}
}
private void set_combo (Gtk.ComboBox combo, int value_index, string value)
{
Gtk.TreeIter iter;
var model = combo.model;
if (!model.get_iter_first (out iter))
return;
do
{
string v;
model.@get (iter, value_index, out v, -1);
if (v == value)
{
combo.set_active_iter (iter);
return;
}
} while (model.iter_next (ref iter));
}
private string? get_combo (Gtk.ComboBox combo, int value_index)
{
string value;
Gtk.TreeIter iter;
if (!combo.get_active_iter (out iter))
return null;
combo.model.@get (iter, value_index, out value, -1);
return value;
}
[GtkCallback]
private void side_combo_changed_cb (Gtk.ComboBox combo)
{
Gtk.TreeIter iter;
if (!combo.get_active_iter (out iter))
return;
int player;
combo.model.@get (iter, 1, out player, -1);
settings.set_enum ("play-as", player);
}
[GtkCallback]
private void opponent_combo_changed_cb (Gtk.ComboBox combo)
{
Gtk.TreeIter iter;
if (!combo.get_active_iter (out iter))
return;
string opponent;
combo.model.@get (iter, 1, out opponent, -1);
settings.set_string ("opponent", opponent);
bool vs_human = (combo.get_active () == 0);
side_combo.sensitive = !vs_human;
difficulty_combo.sensitive = !vs_human;
}
[GtkCallback]
private void difficulty_combo_changed_cb (Gtk.ComboBox combo)
{
Gtk.TreeIter iter;
if (!combo.get_active_iter (out iter))
return;
string difficulty;
combo.model.@get (iter, 1, out difficulty, -1);
settings.set_string ("difficulty", difficulty);
}
private void set_clock_type (int clock_type)
{
var model = clock_type_combo.model;
Gtk.TreeIter iter, active_iter_clock_type = {};
/* Find the largest units that can be used for this value */
if (model.get_iter_first (out iter))
{
do
{
int type;
model.@get (iter, 1, out type, -1);
if (type == clock_type)
{
active_iter_clock_type = iter;
}
} while (model.iter_next (ref iter));
}
clock_type_combo.set_active_iter (active_iter_clock_type);
clock_type_changed_cb (clock_type_combo);
}
private void set_timer_increment (int timer_increment)
{
int timer_increment_multiplier = 1;
if (timer_increment >= 60)
{
timer_increment_adjustment.value = timer_increment / 60;
timer_increment_multiplier = 60;
} else
timer_increment_adjustment.value = timer_increment;
var model = timer_increment_units_combo.model;
Gtk.TreeIter iter, reqd_iter = {};
/* Find the largest units that can be used for this value */
if (model.get_iter_first (out iter))
{
do
{
int multiplier;
model.@get (iter, 1, out multiplier, -1);
if (multiplier == timer_increment_multiplier)
{
reqd_iter = iter;
}
} while (model.iter_next (ref iter));
}
timer_increment_units_combo.set_active_iter (reqd_iter);
timer_increment_units_changed_cb (timer_increment_units_combo);
}
private void set_duration (int duration, bool simplify = true)
{
var model = custom_duration_units_combo.model;
Gtk.TreeIter iter, max_iter = {};
/* Find the largest units that can be used for this value */
int max_multiplier = 0;
if (model.get_iter_first (out iter))
{
do
{
int multiplier;
model.@get (iter, 1, out multiplier, -1);
if (multiplier > max_multiplier && duration % multiplier == 0)
{
max_multiplier = multiplier;
max_iter = iter;
}
} while (model.iter_next (ref iter));
}
/* Set the spin button to the value with the chosen units */
var value = 0;
if (max_multiplier > 0)
{
value = duration / max_multiplier;
duration_adjustment.value = value;
custom_duration_units_combo.set_active_iter (max_iter);
}
if (!simplify)
return;
model = duration_combo.model;
if (!model.get_iter_first (out iter))
return;
do
{
int v;
model.@get (iter, 1, out v, -1);
if (v == duration || v == -1)
{
duration_combo.set_active_iter (iter);
custom_duration_box.visible = v == -1;
return;
}
} while (model.iter_next (ref iter));
}
private int get_duration ()
{
Gtk.TreeIter iter;
if (duration_combo.get_active_iter (out iter))
{
int duration;
duration_combo.model.@get (iter, 1, out duration, -1);
if (duration >= 0)
return duration;
}
var magnitude = (int) duration_adjustment.value;
int multiplier = 1;
if (custom_duration_units_combo.get_active_iter (out iter))
custom_duration_units_combo.model.@get (iter, 1, out multiplier, -1);
switch (multiplier)
{
case 60:
if (duration_adjustment.get_upper () != 600)
duration_adjustment.set_upper (600);
break;
case 3600:
if (duration_adjustment.get_upper () != 10)
{
duration_adjustment.set_upper (10);
if (duration_adjustment.value > 10)
{
duration_adjustment.value = 10;
magnitude = 10;
}
}
break;
default:
assert_not_reached ();
}
return magnitude * multiplier;
}
[GtkCallback]
private void duration_changed_cb (Gtk.Adjustment adjustment)
{
var model = (Gtk.ListStore) custom_duration_units_combo.model;
Gtk.TreeIter iter;
/* Set the unit labels to the correct plural form */
if (model.get_iter_first (out iter))
{
do
{
int multiplier;
model.@get (iter, 1, out multiplier, -1);
switch (multiplier)
{
case 60:
model.set (iter, 0, ngettext (/* Preferences Dialog: Combo box entry for a custom game timer set in minutes */
"minute", "minutes", (ulong) adjustment.value), -1);
break;
case 3600:
model.set (iter, 0, ngettext (/* Preferences Dialog: Combo box entry for a custom game timer set in hours */
"hour", "hours", (ulong) adjustment.value), -1);
break;
default:
assert_not_reached ();
}
} while (model.iter_next (ref iter));
}
save_duration ();
}
[GtkCallback]
private void duration_units_changed_cb (Gtk.Widget widget)
{
save_duration ();
}
[GtkCallback]
private void timer_increment_units_changed_cb (Gtk.Widget widget)
{
var model = (Gtk.ListStore) timer_increment_units_combo.model;
Gtk.TreeIter iter;
int multiplier = 0;
/* Set the unit labels to the correct plural form */
if (model.get_iter_first (out iter))
{
do
{
model.@get (iter, 1, out multiplier, -1);
switch (multiplier)
{
case 1:
model.set (iter, 0, ngettext (/* Preferences Dialog: Combo box entry for a custom clock type set in seconds */
"second", "seconds", (ulong) timer_increment_adjustment.value), -1);
break;
case 60:
model.set (iter, 0, ngettext (/* Preferences Dialog: Combo box entry for a custom clock type set in minutes */
"minute", "minutes", (ulong) timer_increment_adjustment.value), -1);
break;
default:
assert_not_reached ();
}
} while (model.iter_next (ref iter));
}
if (timer_increment_units_combo.get_active_iter (out iter))
timer_increment_units_combo.model.@get (iter, 1, out multiplier, -1);
switch (multiplier)
{
case 1:
if (timer_increment_adjustment.get_upper () != 59)
timer_increment_adjustment.set_upper (59);
break;
case 60:
if (timer_increment_adjustment.get_upper () != 10)
{
timer_increment_adjustment.set_upper (10);
if (timer_increment_adjustment.value > 10)
timer_increment_adjustment.value = 10;
}
break;
default:
assert_not_reached ();
}
settings.set_int ("timer-increment", (int) timer_increment_adjustment.value * multiplier);
}
private bool save_duration_cb ()
{
settings.set_int ("duration", get_duration ());
save_duration_timeout = 0;
return Source.REMOVE;
}
private void save_duration ()
{
if (save_duration_timeout != 0)
Source.remove (save_duration_timeout);
/* Delay writing the value as this event will be generated a lot spinning through the value */
save_duration_timeout = Timeout.add (100, save_duration_cb);
}
[GtkCallback]
private void duration_combo_changed_cb (Gtk.ComboBox combo)
{
Gtk.TreeIter iter;
if (!combo.get_active_iter (out iter))
return;
int duration;
combo.model.@get (iter, 1, out duration, -1);
custom_duration_box.visible = duration < 0;
clock_type_combo.sensitive = duration != 0;
if (duration == 0)
set_clock_type (ClockType.SIMPLE);
if (duration >= 0)
set_duration (duration, false);
/* Default to one hour (30 minutes/player) when setting custom duration */
else if (get_duration () <= 0)
set_duration (60 * 60, false);
save_duration ();
}
[GtkCallback]
private void clock_type_changed_cb (Gtk.ComboBox combo)
{
Gtk.TreeIter iter;
if (!combo.get_active_iter (out iter))
return;
ClockType clock_type;
combo.model.@get (iter, 1, out clock_type, -1);
timer_increment_box.visible = clock_type > 0;
timer_increment_label.visible = clock_type > 0;
settings.set_string ("clock-type", clock_type.to_string ());
}
[GtkCallback]
private void piece_style_combo_changed_cb (Gtk.ComboBox combo)
{
settings.set_string ("piece-theme", get_combo (combo, 1));
}
[GtkCallback]
private void move_format_combo_changed_cb (Gtk.ComboBox combo)
{
settings.set_string ("move-format", get_combo (combo, 1));
}
[GtkCallback]
private void orientation_combo_changed_cb (Gtk.ComboBox combo)
{
settings.set_string ("board-side", get_combo (combo, 1));
}
}

View file

@ -0,0 +1,60 @@
/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Nils Lück
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
* license.
*/
[GtkTemplate (ui = "/org/gnome/Chess/ui/preferences-window.ui")]
public class PreferencesWindow : Adw.PreferencesWindow
{
private Preferences preferences;
[GtkChild]
private unowned Adw.ComboRow board_orientation_combo;
[GtkChild]
private unowned Adw.ComboRow move_format_combo;
[GtkChild]
private unowned Adw.ComboRow piece_style_combo;
[GtkChild]
private unowned Gtk.Switch board_numbering_switch;
[GtkChild]
private unowned Gtk.Switch move_hints_switch;
public PreferencesWindow (Gtk.Window window, Preferences preferences)
{
transient_for = window;
this.preferences = preferences;
preferences.bind_property ("show-board-numbering", board_numbering_switch, "active", BindingFlags.BIDIRECTIONAL | BindingFlags.SYNC_CREATE, null, null);
preferences.bind_property ("show-move-hints", move_hints_switch, "active", BindingFlags.BIDIRECTIONAL | BindingFlags.SYNC_CREATE, null, null);
preferences.bind_property ("piece-style", piece_style_combo, "selected", BindingFlags.BIDIRECTIONAL | BindingFlags.SYNC_CREATE, null, null);
preferences.bind_property ("move-format", move_format_combo, "selected", BindingFlags.BIDIRECTIONAL | BindingFlags.SYNC_CREATE, null, null);
preferences.bind_property ("board-orientation", board_orientation_combo, "selected", BindingFlags.BIDIRECTIONAL | BindingFlags.SYNC_CREATE, null, null);
}
[GtkCallback]
private string board_orientation_display_name_cb (Adw.EnumListItem item)
{
var value = (BoardOrientation) item.value;
return value.display_name ();
}
[GtkCallback]
private string move_format_display_name_cb (Adw.EnumListItem item)
{
var value = (MoveFormat) item.value;
return value.display_name ();
}
[GtkCallback]
private string piece_style_display_name_cb (Adw.EnumListItem item)
{
var value = (PieceStyle) item.value;
return value.display_name ();
}
}

607
src/preferences.vala Normal file
View file

@ -0,0 +1,607 @@
/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Nils Lück
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
* license.
*/
public const string WIDTH_SETTINGS_KEY = "width";
public const string HEIGHT_SETTINGS_KEY = "height";
public const string MAXIMIZED_SETTINGS_KEY = "maximized";
public const string PIECE_STYLE_SETTINGS_KEY = "piece-theme";
public const string SHOW_MOVE_HINTS_SETTINGS_KEY = "show-move-hints";
public const string SHOW_BOARD_NUMBERING_SETTINGS_KEY = "show-numbering";
public const string MOVE_FORMAT_SETTINGS_KEY = "move-format";
public const string BOARD_ORIENTATION_SETTINGS_KEY = "board-side";
public const string DURATION_SETTINGS_KEY = "duration";
public const string CLOCK_TYPE_SETTINGS_KEY = "clock-type";
public const string INCREMENT_SETTINGS_KEY = "timer-increment";
public const string PLAY_AS_SETTINGS_KEY = "play-as";
public const string LAST_PLAYED_AS_SETTINGS_KEY = "last-played-as";
public const string OPPONENT_SETTINGS_KEY = "opponent";
public const string DIFFICULTY_SETTINGS_KEY = "difficulty";
public class Preferences : Object
{
private Settings settings;
public BoardOrientation board_orientation { get; set; }
public MoveFormat move_format { get; set; }
public PieceStyle piece_style { get; set; }
public bool show_board_numbering { get; set; }
public bool show_move_hints { get; set; }
public Opponent opponent { get; set; }
public PlayAs play_as { get; set; }
public Difficulty difficulty { get; set; }
private bool syncing_time_limit = false;
public TimeLimit? time_limit { get; set; }
public Preferences(Settings settings)
{
this.settings = settings;
settings.bind (SHOW_BOARD_NUMBERING_SETTINGS_KEY, this, "show-board-numbering", SettingsBindFlags.DEFAULT);
settings.bind (SHOW_MOVE_HINTS_SETTINGS_KEY, this, "show-move-hints", SettingsBindFlags.DEFAULT);
settings.bind_with_mapping (
BOARD_ORIENTATION_SETTINGS_KEY,
this,
"board-orientation",
SettingsBindFlags.DEFAULT,
(to_value, from_value, user_data) =>
{
var value = BoardOrientation.from_setting (from_value.get_string ()) ?? BoardOrientation.HUMAN_SIDE;
to_value.set_enum (value);
return true;
},
(from_value, expected_type, user_data) =>
{
var value = (BoardOrientation) from_value.get_enum ();
return new Variant.string (value.to_setting ());
},
null,
null);
settings.bind_with_mapping (
MOVE_FORMAT_SETTINGS_KEY,
this,
"move-format",
SettingsBindFlags.DEFAULT,
(to_value, from_value, user_data) =>
{
var value = MoveFormat.from_setting (from_value.get_string ()) ?? MoveFormat.HUMAN;
to_value.set_enum (value);
return true;
},
(from_value, expected_type, user_data) =>
{
var value = (MoveFormat) from_value.get_enum ();
return new Variant.string (value.to_setting ());
},
null,
null);
settings.bind_with_mapping (
PIECE_STYLE_SETTINGS_KEY,
this,
"piece-style",
SettingsBindFlags.DEFAULT,
(to_value, from_value, user_data) =>
{
var value = PieceStyle.from_setting (from_value.get_string ()) ?? PieceStyle.SIMPLE;
to_value.set_enum (value);
return true;
},
(from_value, expected_type, user_data) =>
{
var value = (PieceStyle) from_value.get_enum ();
return new Variant.string (value.to_setting ());
},
null,
null);
settings.bind_with_mapping (
PLAY_AS_SETTINGS_KEY,
this,
"play-as",
SettingsBindFlags.DEFAULT,
(to_value, from_value, user_data) =>
{
var value = PlayAs.from_setting (from_value.get_string ()) ?? PlayAs.WHITE;
to_value.set_enum (value);
return true;
},
(from_value, expected_type, user_data) =>
{
var value = (PlayAs) from_value.get_enum ();
return new Variant.string (value.to_setting ());
},
null,
null);
settings.bind_with_mapping (
DIFFICULTY_SETTINGS_KEY,
this,
"difficulty",
SettingsBindFlags.DEFAULT,
(to_value, from_value, user_data) =>
{
var value = Difficulty.from_setting (from_value.get_string ()) ?? Difficulty.EASY;
to_value.set_enum (value);
return true;
},
(from_value, expected_type, user_data) =>
{
var value = (Difficulty) from_value.get_enum ();
return new Variant.string (value.to_setting ());
},
null,
null);
settings.bind_with_mapping (
OPPONENT_SETTINGS_KEY,
this,
"opponent",
SettingsBindFlags.DEFAULT,
(to_value, from_value, user_data) =>
{
var value = Opponent.from_setting (from_value.get_string ()) ?? Opponent.human;
to_value.set_object (value);
return true;
},
(from_value, expected_type, user_data) =>
{
var value = (Opponent) from_value.get_object ();
return new Variant.string (value.to_setting ());
},
null,
null);
time_limit_settings_changed_cb ();
settings.changed[DURATION_SETTINGS_KEY].connect(time_limit_settings_changed_cb);
settings.changed[INCREMENT_SETTINGS_KEY].connect(time_limit_settings_changed_cb);
settings.changed[CLOCK_TYPE_SETTINGS_KEY].connect(time_limit_settings_changed_cb);
notify["time-limit"].connect(time_limit_preferences_changed_cb);
}
private void time_limit_settings_changed_cb ()
{
if (syncing_time_limit)
return;
syncing_time_limit = true;
var duration = settings.get_int (DURATION_SETTINGS_KEY);
var increment = settings.get_int (INCREMENT_SETTINGS_KEY);
var clock_type = settings.get_string (CLOCK_TYPE_SETTINGS_KEY);
time_limit = TimeLimit.from_settings (duration, increment, clock_type);
syncing_time_limit = false;
}
private void time_limit_preferences_changed_cb ()
{
if (syncing_time_limit)
return;
syncing_time_limit = true;
int duration;
int increment;
string clock_type;
TimeLimit.to_settings (time_limit, out duration, out increment, out clock_type);
settings.set_int (DURATION_SETTINGS_KEY, duration);
settings.set_int (INCREMENT_SETTINGS_KEY, increment);
settings.set_string (CLOCK_TYPE_SETTINGS_KEY, clock_type);
syncing_time_limit = false;
}
}
public enum BoardOrientation
{
HUMAN_SIDE,
WHITE_SIDE,
BLACK_SIDE,
CURRENT_PLAYER;
public string display_name ()
{
switch (this)
{
case WHITE_SIDE:
return C_("chess-side", "White Side");
case BLACK_SIDE:
return C_("chess-side", "Black Side");
case HUMAN_SIDE:
return C_("chess-side", "Human Side");
case CURRENT_PLAYER:
return C_("chess-side", "Current Player");
default:
assert_not_reached ();
}
}
public string to_setting ()
{
switch (this)
{
case WHITE_SIDE:
return "white";
case BLACK_SIDE:
return "black";
case HUMAN_SIDE:
return "human";
case CURRENT_PLAYER:
return "current";
default:
assert_not_reached ();
}
}
public static BoardOrientation? from_setting (string s)
{
switch (s)
{
case "white":
return WHITE_SIDE;
case "black":
return BLACK_SIDE;
case "human":
return HUMAN_SIDE;
case "current":
return CURRENT_PLAYER;
default:
return null;
}
}
}
public enum MoveFormat
{
HUMAN,
STANDARD_ALGEBRAIC,
LONG_ALGEBRAIC,
FIGURINE;
public string display_name ()
{
switch (this)
{
case HUMAN:
return C_("chess-move-format", "Human");
case STANDARD_ALGEBRAIC:
return C_("chess-move-format", "Standard Algebraic");
case LONG_ALGEBRAIC:
return C_("chess-move-format", "Long Algebraic");
case FIGURINE:
return C_("chess-move-format", "Figurine");
default:
assert_not_reached ();
}
}
public string to_setting ()
{
switch (this)
{
case HUMAN:
return "human";
case STANDARD_ALGEBRAIC:
return "san";
case LONG_ALGEBRAIC:
return "lan";
case FIGURINE:
return "fan";
default:
assert_not_reached ();
}
}
public static MoveFormat? from_setting (string s)
{
switch (s)
{
case "human":
return HUMAN;
case "san":
return STANDARD_ALGEBRAIC;
case "lan":
return LONG_ALGEBRAIC;
case "fan":
return FIGURINE;
default:
return null;
}
}
}
public enum PieceStyle
{
SIMPLE,
FANCY;
public string display_name ()
{
switch (this)
{
case SIMPLE:
return C_("chess-piece-style", "Simple");
case FANCY:
return C_("chess-piece-style", "Fancy");
default:
assert_not_reached ();
}
}
public string to_setting ()
{
switch (this)
{
case SIMPLE:
return "simple";
case FANCY:
return "fancy";
default:
assert_not_reached ();
}
}
public static PieceStyle? from_setting (string s)
{
switch (s)
{
case "simple":
return SIMPLE;
case "fancy":
return FANCY;
default:
return null;
}
}
}
public enum PlayAs
{
WHITE,
BLACK,
ALTERNATE;
public string display_name ()
{
switch (this)
{
case WHITE:
return C_("chess-player", "White");
case BLACK:
return C_("chess-player", "Black");
case ALTERNATE:
return C_("chess-player", "Alternate");
default:
assert_not_reached ();
}
}
public string to_setting ()
{
switch (this)
{
case WHITE:
return "white";
case BLACK:
return "black";
case ALTERNATE:
return "alternate";
default:
assert_not_reached ();
}
}
public static PlayAs? from_setting (string s)
{
switch (s)
{
case "white":
return WHITE;
case "black":
return BLACK;
case "alternate":
return ALTERNATE;
default:
return null;
}
}
}
public enum Difficulty
{
EASY,
NORMAL,
HARD;
public string display_name ()
{
switch (this)
{
case EASY:
return C_("difficulty", "Easy");
case NORMAL:
return C_("difficulty", "Normal");
case HARD:
return C_("difficulty", "Hard");
default:
assert_not_reached ();
}
}
public string to_setting ()
{
switch (this)
{
case EASY:
return "easy";
case NORMAL:
return "normal";
case HARD:
return "hard";
default:
assert_not_reached ();
}
}
public static Difficulty? from_setting (string s)
{
switch (s)
{
case "easy":
return EASY;
case "normal":
return NORMAL;
case "hard":
return HARD;
default:
return null;
}
}
}
public enum ClockType
{
FISCHER,
BRONSTEIN;
public string display_name ()
{
switch (this)
{
case FISCHER:
return C_("clock-type", "Fischer");
case BRONSTEIN:
return C_("clock-type", "Bronstein");
default:
assert_not_reached ();
}
}
public string to_setting ()
{
switch (this)
{
case FISCHER:
return "fischer";
case BRONSTEIN:
return "bronstein";
default:
assert_not_reached ();
}
}
public static ClockType? from_setting (string s)
{
switch (s)
{
case "fischer":
return FISCHER;
case "bronstein":
return BRONSTEIN;
default:
return null;
}
}
}
public class Opponent : Object
{
private const string HUMAN_NAME = "human";
private static Opponent _human;
public static Opponent human
{
get
{
if (_human == null)
_human = new Opponent (HUMAN_NAME, C_("chess-opponent", "Human"));
return _human;
}
}
public string name { get; private set; }
public string display_name { get; private set; }
public bool is_human { get { return name == HUMAN_NAME; } }
public Opponent (string name, string display_name)
{
this.name = name;
this.display_name = display_name;
}
public string to_setting ()
{
return name;
}
public static Opponent? from_setting (string s)
{
if (s == HUMAN_NAME)
return human;
else if (s == null || s.length == 0)
return null;
return new Opponent (s, s);
}
public static Opponent from_ai_profile (AIProfile ai_profile)
{
return new Opponent (ai_profile.name, ai_profile.name);
}
}
public class TimeLimit
{
public int duration_in_seconds { get; private set; }
public int increment_in_seconds { get; private set; }
public ClockType clock_type { get; private set; }
public TimeLimit (int duration_in_seconds, int increment_in_seconds, ClockType clock_type)
{
assert_cmpint (duration_in_seconds, CompareOperator.GT, 0);
assert_cmpint (increment_in_seconds, CompareOperator.GE, 0);
this.duration_in_seconds = duration_in_seconds;
this.increment_in_seconds = increment_in_seconds;
this.clock_type = clock_type;
}
public static void to_settings (TimeLimit? time_limit, out int duration, out int increment, out string clock_type)
{
if (time_limit == null)
{
duration = 0;
increment = 0;
clock_type = "simple";
return;
}
duration = time_limit.duration_in_seconds;
increment = time_limit.increment_in_seconds;
if (increment == 0)
clock_type = "simple";
else
clock_type = time_limit.clock_type.to_setting ();
}
public static TimeLimit? from_settings (int duration_setting, int increment_setting, string clock_type_setting)
{
if (duration_setting <= 0)
return null;
var clock_type = ClockType.from_setting (clock_type_setting);
if (clock_type == null || increment_setting <= 0)
return new TimeLimit (duration_setting, 0, ClockType.FISCHER);
return new TimeLimit (duration_setting, increment_setting, clock_type);
}
}