Create a ChessWindow and move a bunch of logic there

This commit is contained in:
Michael Catanzaro 2020-12-25 11:16:50 -06:00
parent d5fefd3433
commit c292a01440
9 changed files with 725 additions and 655 deletions

View file

@ -1,29 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<menu id="app-menu">
<menu id="app_menu">
<section>
<item>
<attribute name="label" translatable="yes">_New Game</attribute>
<attribute name="action">win.new</attribute>
<attribute name="action">app.new</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Open Game…</attribute>
<attribute name="action">win.open</attribute>
<attribute name="action">app.open</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Save Game</attribute>
<attribute name="action">win.save</attribute>
<attribute name="action">app.save</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Save Game As…</attribute>
<attribute name="action">win.save-as</attribute>
<attribute name="action">app.save-as</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">_Resign Game</attribute>
<attribute name="action">win.resign</attribute>
<attribute name="action">app.resign</attribute>
</item>
</section>
<section>
@ -35,7 +35,7 @@
<section>
<item>
<attribute name="label" translatable="yes">_Keyboard Shortcuts</attribute>
<attribute name="action">win.show-help-overlay</attribute>
<attribute name="action">app.show-help-overlay</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Help</attribute>
@ -47,23 +47,23 @@
</item>
</section>
</menu>
<object class="GtkListStore" id="history-model">
<object class="GtkListStore" id="history_model">
<columns>
<column type="gchararray"/>
<column type="gint"/>
</columns>
</object>
<object class="GtkApplicationWindow" id="gnome_chess_app">
<template class="ChessWindow" parent="GtkApplicationWindow">
<property name="can-focus">0</property>
<property name="default-width">700</property>
<property name="title" translatable="yes">Chess</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar">
<object class="GtkHeaderBar">
<property name="can-focus">0</property>
<child>
<object class="GtkButton" id="undo-move-button">
<object class="GtkButton">
<property name="valign">center</property>
<property name="action-name">win.undo</property>
<property name="action-name">app.undo</property>
<property name="tooltip-text" translatable="yes">Undo your most recent move</property>
<style>
<class name="image-button"/>
@ -78,9 +78,9 @@
</object>
</child>
<child>
<object class="GtkButton" id="pause_button">
<object class="GtkButton" id="pause_resume_button">
<property name="valign">center</property>
<property name="action-name">win.pause-resume</property>
<property name="action-name">app.pause-resume</property>
<style>
<class name="image-button"/>
</style>
@ -94,7 +94,7 @@
<child type="end">
<object class="GtkMenuButton">
<property name="icon-name">open-menu-symbolic</property>
<property name="menu-model">app-menu</property>
<property name="menu-model">app_menu</property>
</object>
</child>
</object>
@ -144,7 +144,7 @@
</style>
<child>
<object class="GtkButton" id="first_move_button">
<property name="action-name">win.go-first</property>
<property name="action-name">app.go-first</property>
<property name="sensitive">0</property>
<property name="tooltip-text" translatable="yes" comments="Tooltip on the show first move (i.e. game start) navigation button">Rewind to the game start</property>
<style>
@ -161,7 +161,7 @@
</child>
<child>
<object class="GtkButton" id="prev_move_button">
<property name="action-name">win.go-previous</property>
<property name="action-name">app.go-previous</property>
<property name="sensitive">0</property>
<property name="tooltip-text" translatable="yes" comments="Tooltip on the show previous move navigation button">Show the previous move</property>
<style>
@ -178,7 +178,7 @@
</child>
<child>
<object class="GtkButton" id="next_move_button">
<property name="action-name">win.go-next</property>
<property name="action-name">app.go-next</property>
<property name="sensitive">0</property>
<property name="tooltip-text" translatable="yes" comments="Tooltip on the show next move navigation button">Show the next move</property>
<style>
@ -195,7 +195,7 @@
</child>
<child>
<object class="GtkButton" id="last_move_button">
<property name="action-name">win.go-last</property>
<property name="action-name">app.go-last</property>
<property name="sensitive">0</property>
<property name="tooltip-text" translatable="yes" comments="Tooltip on the show current move navigation button">Show the current move</property>
<style>
@ -216,7 +216,7 @@
<object class="GtkComboBox" id="history_combo">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="model">history-model</property>
<property name="model">history_model</property>
<signal name="changed" handler="history_combo_changed_cb" swapped="no"/>
<child>
<object class="GtkCellRendererText">
@ -253,7 +253,7 @@
</child>
</object>
</child>
</object>
</template>
<object class="GtkSizeGroup">
<property name="mode">vertical</property>
<widgets>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/Chess/ui">
<file preprocess="xml-stripblanks">gnome-chess.ui</file>
<file preprocess="xml-stripblanks">chess-window.ui</file>
<file preprocess="xml-stripblanks">preferences.ui</file>
<file preprocess="xml-stripblanks">promotion-type-selector.ui</file>
</gresource>

View file

@ -15,5 +15,6 @@ lib/chess-game.vala
lib/chess-pgn.vala
src/chess-scene.vala
src/chess-view.vala
src/chess-window.vala
src/gnome-chess.vala
src/preferences-dialog.vala

View file

@ -6,5 +6,6 @@ lib/chess-game.c
lib/chess-pgn.c
src/chess-scene.c
src/chess-view.c
src/chess-window.c
src/gnome-chess.c
src/preferences-dialog.c

View file

@ -41,15 +41,13 @@ public class ChessView : Gtk.DrawingArea
public ChessView (ChessScene scene)
{
Object (scene: scene);
}
construct
{
init_mouse ();
set_draw_func (draw);
hexpand = true;
vexpand = true;
set_size_request (100, 100);
}
public override void resize (int width, int height)

580
src/chess-window.vala Normal file
View file

@ -0,0 +1,580 @@
/* -*- 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/chess-window.ui")]
public class ChessWindow : Gtk.ApplicationWindow
{
public enum LayoutMode {
NORMAL,
NARROW
}
private LayoutMode _layout_mode = LayoutMode.NORMAL;
public LayoutMode layout_mode
{
get { return _layout_mode; }
private set
{
if (_layout_mode == value)
return;
_layout_mode = value;
Idle.add(() => {
navigation_box.set_orientation (value == LayoutMode.NORMAL ? Gtk.Orientation.HORIZONTAL : Gtk.Orientation.VERTICAL);
return Source.REMOVE;
});
}
}
public ChessView view
{
get; private set;
}
public ChessScene scene
{
get { return view.scene; }
}
public ChessGame? game
{
get { return scene.game; }
}
private ChessApplication app;
private ulong clock_tick_signal_id = 0;
[GtkChild]
private unowned Gtk.Box main_box;
[GtkChild]
private unowned Gtk.InfoBar info_bar;
[GtkChild]
private unowned Gtk.Label info_bar_label;
[GtkChild]
private unowned Gtk.Button pause_resume_button;
[GtkChild]
private unowned Gtk.Box navigation_box;
[GtkChild]
private unowned Gtk.ComboBox history_combo;
[GtkChild]
private unowned Gtk.Box clock_box;
[GtkChild]
private unowned Gtk.DrawingArea white_time_label;
[GtkChild]
private unowned Gtk.DrawingArea black_time_label;
public ChessWindow (ChessApplication app)
{
this.app = app;
var scene = new ChessScene ();
scene.changed.connect (() => update_history_panel ());
view = new ChessView (scene);
main_box.insert_child_after (view, info_bar);
update_pause_resume_button ();
white_time_label.set_draw_func (draw_white_time_label);
black_time_label.set_draw_func (draw_black_time_label);
notify["default-height"].connect (window_state_changed_cb);
notify["default-width"].connect (window_state_changed_cb);
}
private void window_state_changed_cb ()
{
if (fullscreened || maximized)
return;
if (default_width == 0 || default_height == 0)
return;
if (default_width <= 500 && layout_mode == LayoutMode.NORMAL)
layout_mode = LayoutMode.NARROW;
else if (default_width > 500 && layout_mode == LayoutMode.NARROW)
layout_mode = LayoutMode.NORMAL;
}
public void update_game_status (string? title = null, string? info = null)
{
this.title = title != null ? title : app.compute_current_title ();
info_bar_label.label = info != null ? info : app.compute_status_info ();
/* Setting the label to null actually just sets it to an empty string. */
info_bar.visible = info_bar_label.label != "";
}
public void update_pause_resume_button ()
{
var game = scene.game;
if (game != null && game.clock == null)
pause_resume_button.hide ();
else
pause_resume_button.show ();
if (game != null && game.is_paused)
{
pause_resume_button.icon_name = "media-playback-start-symbolic";
pause_resume_button.tooltip_text = _("Unpause the game");
}
else
{
pause_resume_button.icon_name = "media-playback-pause-symbolic";
pause_resume_button.tooltip_text = _("Pause the game");
}
}
public void update_history_panel ()
{
if (game == null)
return;
var move_number = scene.move_number;
var n_moves = (int) game.n_moves;
if (move_number < 0)
move_number += 1 + n_moves;
if (n_moves > 0 && move_number != 0 && !game.is_paused)
app.enable_action (HISTORY_GO_FIRST_ACTION_NAME);
else
app.disable_action (HISTORY_GO_FIRST_ACTION_NAME);
if (move_number > 0 && !game.is_paused)
app.enable_action (HISTORY_GO_PREVIOUS_ACTION_NAME);
else
app.disable_action (HISTORY_GO_PREVIOUS_ACTION_NAME);
if (move_number < n_moves && !game.is_paused)
app.enable_action (HISTORY_GO_NEXT_ACTION_NAME);
else
app.disable_action (HISTORY_GO_NEXT_ACTION_NAME);
if (n_moves > 0 && move_number != n_moves && !game.is_paused)
app.enable_action (HISTORY_GO_LAST_ACTION_NAME);
else
app.disable_action (HISTORY_GO_LAST_ACTION_NAME);
history_combo.sensitive = !game.is_paused;
/* Set move text for all moves (it may have changed format) */
int i = n_moves;
foreach (var state in game.move_stack)
{
if (state.last_move != null)
{
Gtk.TreeIter iter;
if (history_combo.model.iter_nth_child (out iter, null, i))
set_move_text (iter, state.last_move);
}
i--;
}
history_combo.set_active (move_number);
}
public void set_clock_visible (bool visible)
{
clock_box.visible = visible;
}
/* Compute the largest possible size the timer label might ever want to take.
* The size of the characters may vary by font, but one digit will always
* be the largest.
*/
private int compute_time_label_width_request (Cairo.Context c)
ensures (result > 0)
{
Cairo.TextExtents extents;
double max = 0;
c.text_extents ("00000", out extents);
max = (max > extents.width ? max : extents.width);
c.text_extents ("11111", out extents);
max = (max > extents.width ? max : extents.width);
c.text_extents ("22222", out extents);
max = (max > extents.width ? max : extents.width);
c.text_extents ("33333", out extents);
max = (max > extents.width ? max : extents.width);
c.text_extents ("44444", out extents);
max = (max > extents.width ? max : extents.width);
c.text_extents ("55555", out extents);
max = (max > extents.width ? max : extents.width);
c.text_extents ("66666", out extents);
max = (max > extents.width ? max : extents.width);
c.text_extents ("77777", out extents);
max = (max > extents.width ? max : extents.width);
c.text_extents ("88888", out extents);
max = (max > extents.width ? max : extents.width);
c.text_extents ("99999", out extents);
max = (max > extents.width ? max : extents.width);
/* Leave a little bit of room to the sides. */
return (int) Math.ceil (max) + 6;
}
private void draw_time (Gtk.Widget widget, Cairo.Context c, int width, int height, string text, double[] fg, double[] bg)
{
/* We need to draw text on our cairo context to properly compute our
* required size. But the only place we are able to access the cairo
* context is here, the draw function. And we are not allowed to set our
* size inside the draw function. So the best we can do is schedule the
* size computation and queue draw again when that's done.
*/
if (widget.width_request == -1)
{
Idle.add(() => {
widget.set_size_request (compute_time_label_width_request (c), -1);
widget.queue_draw ();
return Source.REMOVE;
});
return;
}
double alpha = 1.0;
if ((widget.get_state_flags () & Gtk.StateFlags.INSENSITIVE) != 0)
alpha = 0.5;
c.set_source_rgba (bg[0], bg[1], bg[2], alpha);
c.paint ();
c.set_source_rgba (fg[0], fg[1], fg[2], alpha);
c.select_font_face ("fixed", Cairo.FontSlant.NORMAL, Cairo.FontWeight.BOLD);
c.set_font_size (0.6 * widget.get_allocated_height ());
Cairo.TextExtents extents;
c.text_extents (text, out extents);
c.move_to ((widget.get_allocated_width () - extents.width) / 2 - extents.x_bearing,
(widget.get_allocated_height () - extents.height) / 2 - extents.y_bearing);
c.show_text (text);
}
private string make_clock_text (ChessClock? clock, Color color)
requires (clock != null)
{
int time;
if (color == Color.WHITE)
time = clock.white_remaining_seconds;
else
time = clock.black_remaining_seconds;
if (time >= 60)
return "%d\xE2\x80\x8E%02d".printf (time / 60, time % 60);
else
return "\xE2\x80\x8E%02d".printf (time);
}
private void draw_white_time_label (Gtk.DrawingArea drawing_area, Cairo.Context c, int width, int height)
{
draw_time (drawing_area, c, width, height, make_clock_text (scene.game.clock, Color.WHITE), { 0.0, 0.0, 0.0 }, { 1.0, 1.0, 1.0 });
}
private void draw_black_time_label (Gtk.DrawingArea drawing_area, Cairo.Context c, int width, int height)
{
draw_time (drawing_area, c, width, height, make_clock_text (scene.game.clock, Color.BLACK), { 1.0, 1.0, 1.0 }, { 0.0, 0.0, 0.0 });
}
[GtkCallback]
private void history_combo_changed_cb (Gtk.ComboBox combo)
{
Gtk.TreeIter iter;
if (!combo.get_active_iter (out iter))
return;
int move_number;
combo.model.get (iter, 1, out move_number, -1);
if (game == null || move_number == game.n_moves)
move_number = -1;
scene.move_number = move_number;
}
public void set_move_text (Gtk.TreeIter iter, ChessMove move)
{
/* Note there are no move formats for pieces taking kings and this is not allowed in Chess rules */
const string human_descriptions[] = {/* Human Move String: Description of a white pawn moving from %1$s to %2s, e.g. 'c2 to c4' */
N_("White pawn moves from %1$s to %2$s"),
/* Human Move String: Description of a white pawn at %1$s capturing a pawn at %2$s */
N_("White pawn at %1$s takes the black pawn at %2$s"),
/* Human Move String: Description of a white pawn at %1$s capturing a rook at %2$s */
N_("White pawn at %1$s takes the black rook at %2$s"),
/* Human Move String: Description of a white pawn at %1$s capturing a knight at %2$s */
N_("White pawn at %1$s takes the black knight at %2$s"),
/* Human Move String: Description of a white pawn at %1$s capturing a bishop at %2$s */
N_("White pawn at %1$s takes the black bishop at %2$s"),
/* Human Move String: Description of a white pawn at %1$s capturing a queen at %2$s */
N_("White pawn at %1$s takes the black queen at %2$s"),
/* Human Move String: Description of a white rook moving from %1$s to %2$s, e.g. 'a1 to a5' */
N_("White rook moves from %1$s to %2$s"),
/* Human Move String: Description of a white rook at %1$s capturing a pawn at %2$s */
N_("White rook at %1$s takes the black pawn at %2$s"),
/* Human Move String: Description of a white rook at %1$s capturing a rook at %2$s */
N_("White rook at %1$s takes the black rook at %2$s"),
/* Human Move String: Description of a white rook at %1$s capturing a knight at %2$s */
N_("White rook at %1$s takes the black knight at %2$s"),
/* Human Move String: Description of a white rook at %1$s capturing a bishop at %2$s */
N_("White rook at %1$s takes the black bishop at %2$s"),
/* Human Move String: Description of a white rook at %1$s capturing a queen at %2$s" */
N_("White rook at %1$s takes the black queen at %2$s"),
/* Human Move String: Description of a white knight moving from %1$s to %2$s, e.g. 'b1 to c3' */
N_("White knight moves from %1$s to %2$s"),
/* Human Move String: Description of a white knight at %1$s capturing a pawn at %2$s */
N_("White knight at %1$s takes the black pawn at %2$s"),
/* Human Move String: Description of a white knight at %1$s capturing a rook at %2$s */
N_("White knight at %1$s takes the black rook at %2$s"),
/* Human Move String: Description of a white knight at %1$s capturing a knight at %2$s */
N_("White knight at %1$s takes the black knight at %2$s"),
/* Human Move String: Description of a white knight at %1$s capturing a bishop at %2$s */
N_("White knight at %1$s takes the black bishop at %2$s"),
/* Human Move String: Description of a white knight at %1$s capturing a queen at %2$s */
N_("White knight at %1$s takes the black queen at %2$s"),
/* Human Move String: Description of a white bishop moving from %1$s to %2$s, e.g. 'f1 to b5' */
N_("White bishop moves from %1$s to %2$s"),
/* Human Move String: Description of a white bishop at %1$s capturing a pawn at %2$s */
N_("White bishop at %1$s takes the black pawn at %2$s"),
/* Human Move String: Description of a white bishop at %1$s capturing a rook at %2$s */
N_("White bishop at %1$s takes the black rook at %2$s"),
/* Human Move String: Description of a white bishop at %1$s capturing a knight at %2$s */
N_("White bishop at %1$s takes the black knight at %2$s"),
/* Human Move String: Description of a white bishop at %1$s capturing a bishop at %2$s */
N_("White bishop at %1$s takes the black bishop at %2$s"),
/* Human Move String: Description of a white bishop at %1$s capturing a queen at %2$s */
N_("White bishop at %1$s takes the black queen at %2$s"),
/* Human Move String: Description of a white queen moving from %1$s to %2$s, e.g. 'd1 to d4' */
N_("White queen moves from %1$s to %2$s"),
/* Human Move String: Description of a white queen at %1$s capturing a pawn at %2$s */
N_("White queen at %1$s takes the black pawn at %2$s"),
/* Human Move String: Description of a white queen at %1$s capturing a rook at %2$s */
N_("White queen at %1$s takes the black rook at %2$s"),
/* Human Move String: Description of a white queen at %1$s capturing a knight at %2$s */
N_("White queen at %1$s takes the black knight at %2$s"),
/* Human Move String: Description of a white queen at %1$s capturing a bishop at %2$s */
N_("White queen at %1$s takes the black bishop at %2$s"),
/* Human Move String: Description of a white queen at %1$s capturing a queen at %2$s */
N_("White queen at %1$s takes the black queen at %2$s"),
/* Human Move String: Description of a white king moving from %1$s to %2$s, e.g. 'e1 to f1' */
N_("White king moves from %1$s to %2$s"),
/* Human Move String: Description of a white king at %1$s capturing a pawn at %2$s */
N_("White king at %1$s takes the black pawn at %2$s"),
/* Human Move String: Description of a white king at %1$s capturing a rook at %2$s */
N_("White king at %1$s takes the black rook at %2$s"),
/* Human Move String: Description of a white king at %1$s capturing a knight at %2$s */
N_("White king at %1$s takes the black knight at %2$s"),
/* Human Move String: Description of a white king at %1$s capturing a bishop at %2$s */
N_("White king at %1$s takes the black bishop at %2$s"),
/* Human Move String: Description of a white king at %1$s capturing a queen at %2$s */
N_("White king at %1$s takes the black queen at %2$s"),
/* Human Move String: Description of a black pawn moving from %1$s to %2$s, e.g. 'c8 to c6' */
N_("Black pawn moves from %1$s to %2$s"),
/* Human Move String: Description of a black pawn at %1$s capturing a pawn at %2$s */
N_("Black pawn at %1$s takes the white pawn at %2$s"),
/* Human Move String: Description of a black pawn at %1$s capturing a rook at %2$s */
N_("Black pawn at %1$s takes the white rook at %2$s"),
/* Human Move String: Description of a black pawn at %1$s capturing a knight at %2$s */
N_("Black pawn at %1$s takes the white knight at %2$s"),
/* Human Move String: Description of a black pawn at %1$s capturing a bishop at %2$s */
N_("Black pawn at %1$s takes the white bishop at %2$s"),
/* Human Move String: Description of a black pawn at %1$s capturing a queen at %2$s */
N_("Black pawn at %1$s takes the white queen at %2$s"),
/* Human Move String: Description of a black rook moving from %1$s to %2$s, e.g. 'a8 to a4' */
N_("Black rook moves from %1$s to %2$s"),
/* Human Move String: Description of a black rook at %1$s capturing a pawn at %2$s */
N_("Black rook at %1$s takes the white pawn at %2$s"),
/* Human Move String: Description of a black rook at %1$s capturing a rook at %2$s */
N_("Black rook at %1$s takes the white rook at %2$s"),
/* Human Move String: Description of a black rook at %1$s capturing a knight at %2$s */
N_("Black rook at %1$s takes the white knight at %2$s"),
/* Human Move String: Description of a black rook at %1$s capturing a bishop at %2$s */
N_("Black rook at %1$s takes the white bishop at %2$s"),
/* Human Move String: Description of a black rook at %1$s capturing a queen at %2$s */
N_("Black rook at %1$s takes the white queen at %2$s"),
/* Human Move String: Description of a black knight moving from %1$s to %2$s, e.g. 'b8 to c6' */
N_("Black knight moves from %1$s to %2$s"),
/* Human Move String: Description of a black knight at %1$s capturing a pawn at %2$s */
N_("Black knight at %1$s takes the white pawn at %2$s"),
/* Human Move String: Description of a black knight at %1$s capturing a rook at %2$s */
N_("Black knight at %1$s takes the white rook at %2$s"),
/* Human Move String: Description of a black knight at %1$s capturing a knight at %2$s */
N_("Black knight at %1$s takes the white knight at %2$s"),
/* Human Move String: Description of a black knight at %1$s capturing a bishop at %2$s */
N_("Black knight at %1$s takes the white bishop at %2$s"),
/* Human Move String: Description of a black knight at %1$s capturing a queen at %2$s */
N_("Black knight at %1$s takes the white queen at %2$s"),
/* Human Move String: Description of a black bishop moving from %1$s to %2$s, e.g. 'f8 to b3' */
N_("Black bishop moves from %1$s to %2$s"),
/* Human Move String: Description of a black bishop at %1$s capturing a pawn at %2$s */
N_("Black bishop at %1$s takes the white pawn at %2$s"),
/* Human Move String: Description of a black bishop at %1$s capturing a rook at %2$s */
N_("Black bishop at %1$s takes the white rook at %2$s"),
/* Human Move String: Description of a black bishop at %1$s capturing a knight at %2$s */
N_("Black bishop at %1$s takes the white knight at %2$s"),
/* Human Move String: Description of a black bishop at %1$s capturing a bishop at %2$s */
N_("Black bishop at %1$s takes the white bishop at %2$s"),
/* Human Move String: Description of a black bishop at %1$s capturing a queen at %2$s */
N_("Black bishop at %1$s takes the white queen at %2$s"),
/* Human Move String: Description of a black queen moving from %1$s to %2$s, e.g. 'd8 to d5' */
N_("Black queen moves from %1$s to %2$s"),
/* Human Move String: Description of a black queen at %1$s capturing a pawn at %2$s */
N_("Black queen at %1$s takes the white pawn at %2$s"),
/* Human Move String: Description of a black queen at %1$s capturing a rook at %2$s */
N_("Black queen at %1$s takes the white rook at %2$s"),
/* Human Move String: Description of a black queen at %1$s capturing a knight at %2$s */
N_("Black queen at %1$s takes the white knight at %2$s"),
/* Human Move String: Description of a black queen at %1$s capturing a bishop at %2$s */
N_("Black queen at %1$s takes the white bishop at %2$s"),
/* Human Move String: Description of a black queen at %1$s capturing a queen at %2$s */
N_("Black queen at %1$s takes the white queen at %2$s"),
/* Human Move String: Description of a black king moving from %1$s to %2$s, e.g. 'e8 to f8' */
N_("Black king moves from %1$s to %2$s"),
/* Human Move String: Description of a black king at %1$s capturing a pawn at %2$s */
N_("Black king at %1$s takes the white pawn at %2$s"),
/* Human Move String: Description of a black king at %1$s capturing a rook at %2$s */
N_("Black king at %1$s takes the white rook at %2$s"),
/* Human Move String: Description of a black king at %1$s capturing a knight at %2$s */
N_("Black king at %1$s takes the white knight at %2$s"),
/* Human Move String: Description of a black king at %1$s capturing a bishop at %2$s */
N_("Black king at %1$s takes the white bishop at %2$s"),
/* Human Move String: Description of a black king at %1$s capturing a queen at %2$s" */
N_("Black king at %1$s takes the white queen at %2$s")};
var move_text = "";
switch (scene.move_format)
{
case "human":
if (move.castling_rook != null)
{
if (move.f0 < move.f1 && move.r0 == 0)
move_text = _("White castles kingside");
else if (move.f1 < move.f0 && move.r0 == 0)
move_text = _("White castles queenside");
else if (move.f0 < move.f1 && move.r0 == 7)
move_text = _("Black castles kingside");
else if (move.f1 < move.f0 && move.r0 == 7)
move_text = _("Black castles queenside");
else
assert_not_reached ();
}
else
{
int index;
if (move.victim == null)
index = 0;
else
index = move.victim.type + 1;
index += move.piece.type * 6;
if (move.piece.player.color == Color.BLACK)
index += 36;
var start = "%c%d".printf ('a' + move.f0, move.r0 + 1);
var end = "%c%d".printf ('a' + move.f1, move.r1 + 1);
var template = _(human_descriptions[index]);
if (move.en_passant)
{
if (move.r0 < move.r1)
{ /* Human Move String: Description of a white pawn at %1$s capturing a pawn at %2$s en passant */
template = _("White pawn at %1$s takes the black pawn at %2$s en passant");
}
else
{ /* Human Move String: Description of a black pawn at %1$s capturing a pawn at %2$s en passant */
template = _("Black pawn at %1$s takes white pawn at %2$s en passant");
}
}
move_text = template.printf (start, end);
}
break;
case "san":
move_text = move.get_san ();
break;
case "fan":
move_text = move.get_fan ();
break;
default:
case "lan":
move_text = move.get_lan ();
break;
}
var model = (Gtk.ListStore) history_combo.model;
var label = "%u%c. %s".printf ((move.number + 1) / 2, move.number % 2 == 0 ? 'b' : 'a', move_text);
model.set (iter, 0, label, -1);
}
public void start_game ()
{
var model = (Gtk.ListStore) history_combo.model;
model.clear ();
Gtk.TreeIter iter;
model.append (out iter);
model.set (iter, 0,
/* Move History Combo: Go to the start of the game */
_("Game Start"), 1, 0, -1);
history_combo.set_active_iter (iter);
white_time_label.queue_draw ();
black_time_label.queue_draw ();
if (clock_tick_signal_id != 0)
{
disconnect (clock_tick_signal_id);
clock_tick_signal_id = 0;
}
if (game.clock != null)
{
clock_tick_signal_id = game.clock.tick.connect (() => {
white_time_label.queue_draw ();
black_time_label.queue_draw ();
});
}
}
public void move (ChessMove m)
{
/* Automatically return view to the present */
scene.move_number = -1;
var model = (Gtk.ListStore) history_combo.model;
Gtk.TreeIter iter;
model.append (out iter);
model.set (iter, 1, m.number, -1);
set_move_text (iter, m);
/* Follow the latest move */
if (m.number == game.n_moves)
history_combo.set_active_iter (iter);
}
public void undo ()
{
/* Remove from the history */
var model = (Gtk.ListStore) history_combo.model;
Gtk.TreeIter iter;
model.iter_nth_child (out iter, null, model.iter_n_children (null) - 1);
model.remove (ref iter);
/* Always undo from the most recent move */
scene.move_number = -1;
/* Go back one */
model.iter_nth_child (out iter, null, model.iter_n_children (null) - 1);
history_combo.set_active_iter (iter);
view.queue_draw ();
}
public void end_game ()
{
white_time_label.queue_draw ();
black_time_label.queue_draw ();
}
}

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,7 @@ chess_sources = [
resources,
'chess-scene.vala',
'chess-view.vala',
'chess-window.vala',
'gnome-chess.vala',
'preferences-dialog.vala',
'promotion-type-selector-dialog.vala',

View file

@ -32,12 +32,12 @@ public class PromotionTypeSelectorDialog : Gtk.Dialog
[GtkChild]
private unowned Gtk.Image bishop_image;
public PromotionTypeSelectorDialog (Gtk.Window window, Color color, string theme, ChessApplication.LayoutMode layout_mode)
public PromotionTypeSelectorDialog (Gtk.Window window, Color color, string theme, ChessWindow.LayoutMode layout_mode)
{
transient_for = window;
modal = true;
if (layout_mode == ChessApplication.LayoutMode.NARROW)
if (layout_mode == ChessWindow.LayoutMode.NARROW)
button_box.orientation = Gtk.Orientation.VERTICAL;
var color_string = color == Color.WHITE ? "white" : "black";