diff --git a/Userland/Games/Chess/Chess.gml b/Userland/Games/Chess/Chess.gml index 70fe7db793e..d71821e7d5f 100644 --- a/Userland/Games/Chess/Chess.gml +++ b/Userland/Games/Chess/Chess.gml @@ -2,7 +2,34 @@ fill_with_background_color: true layout: @GUI::VerticalBoxLayout {} - @Chess::ChessWidget { - name: "chess_widget" + @GUI::HorizontalSplitter { + @GUI::Frame { + name: "chess_widget_frame" + min_width: 508 + min_height: 508 + layout: @GUI::HorizontalBoxLayout {} + + @Chess::ChessWidget { + name: "chess_widget" + } + } + + @GUI::Frame { + layout: @GUI::VerticalBoxLayout {} + + @GUI::Label { + text: "Moves" + text_alignment: "Center" + font_weight: "Bold" + fixed_height: 24 + name: "moves_display_widget_label" + } + + @GUI::TextEditor { + name: "move_display_widget" + mode: "DisplayOnly" + focus_policy: "NoFocus" + } + } } } diff --git a/Userland/Games/Chess/ChessWidget.cpp b/Userland/Games/Chess/ChessWidget.cpp index 179994c1ec0..374a4046d99 100644 --- a/Userland/Games/Chess/ChessWidget.cpp +++ b/Userland/Games/Chess/ChessWidget.cpp @@ -9,6 +9,7 @@ #include "ChessWidget.h" #include "PromotionDialog.h" +#include #include #include #include @@ -37,7 +38,6 @@ ErrorOr> ChessWidget::try_create() void ChessWidget::paint_event(GUI::PaintEvent& event) { int const min_size = min(width(), height()); - int const widget_offset_x = (window()->width() - min_size) / 2; int const widget_offset_y = (window()->height() - min_size) / 2; GUI::Frame::paint_event(event); @@ -47,7 +47,7 @@ void ChessWidget::paint_event(GUI::PaintEvent& event) painter.fill_rect(frame_inner_rect(), Gfx::Color::Black); - painter.translate(frame_thickness() + widget_offset_x, frame_thickness() + widget_offset_y); + painter.translate(frame_thickness(), frame_thickness() + widget_offset_y); auto square_width = min_size / 8; auto square_height = min_size / 8; @@ -211,7 +211,6 @@ void ChessWidget::paint_event(GUI::PaintEvent& event) void ChessWidget::mousedown_event(GUI::MouseEvent& event) { int const min_size = min(width(), height()); - int const widget_offset_x = (window()->width() - min_size) / 2; int const widget_offset_y = (window()->height() - min_size) / 2; if (!frame_inner_rect().contains(event.position())) @@ -237,7 +236,7 @@ void ChessWidget::mousedown_event(GUI::MouseEvent& event) if (drag_enabled() && piece.color == board().turn() && !m_playback) { m_dragging_piece = true; set_override_cursor(Gfx::StandardCursor::Drag); - m_drag_point = { event.position().x() - widget_offset_x, event.position().y() - widget_offset_y }; + m_drag_point = { event.position().x(), event.position().y() - widget_offset_y }; m_moving_square = square.value(); m_board.generate_moves([&](Chess::Move move) { @@ -295,6 +294,7 @@ void ChessWidget::mouseup_event(GUI::MouseEvent& event) } if (board().apply_move(move)) { + update_move_display_widget(m_board); m_playback_move_number = board().moves().size(); m_playback = false; m_board_playback = m_board; @@ -310,7 +310,6 @@ void ChessWidget::mouseup_event(GUI::MouseEvent& event) void ChessWidget::mousemove_event(GUI::MouseEvent& event) { int const min_size = min(width(), height()); - int const widget_offset_x = (window()->width() - min_size) / 2; int const widget_offset_y = (window()->height() - min_size) / 2; if (!frame_inner_rect().contains(event.position())) @@ -334,7 +333,7 @@ void ChessWidget::mousemove_event(GUI::MouseEvent& event) return; } - m_drag_point = { event.position().x() - widget_offset_x, event.position().y() - widget_offset_y }; + m_drag_point = { event.position().x(), event.position().y() - widget_offset_y }; update(); } @@ -399,10 +398,9 @@ void ChessWidget::set_piece_set(StringView set) Optional ChessWidget::mouse_to_square(GUI::MouseEvent& event) const { int const min_size = min(width(), height()); - int const widget_offset_x = (window()->width() - min_size) / 2; int const widget_offset_y = (window()->height() - min_size) / 2; - auto x = event.x() - widget_offset_x; + auto x = event.x(); auto y = event.y() - widget_offset_y; if (x < 0 || y < 0 || x > min_size || y > min_size) return {}; @@ -433,6 +431,7 @@ void ChessWidget::reset() m_playback_move_number = 0; m_board_playback = Chess::Board(); m_board = Chess::Board(); + update_move_display_widget(m_board); m_side = (get_random() % 2) ? Chess::Color::White : Chess::Color::Black; m_drag_enabled = true; if (m_engine) @@ -483,10 +482,10 @@ void ChessWidget::input_engine_move() set_drag_enabled(drag_was_enabled); if (!move.is_error()) { VERIFY(board().apply_move(move.release_value())); + update_move_display_widget(board()); if (check_game_over(ClaimDrawBehavior::Prompt)) return; } - m_playback_move_number = m_board.moves().size(); m_playback = false; m_board_markings.clear(); @@ -509,6 +508,7 @@ void ChessWidget::playback_move(PlaybackDirection direction) m_board_playback = Chess::Board(); for (size_t i = 0; i < m_playback_move_number - 1; i++) m_board_playback.apply_move(m_board.moves().at(i)); + update_move_display_widget(m_board_playback); m_playback_move_number--; break; case PlaybackDirection::Forward: @@ -517,6 +517,7 @@ void ChessWidget::playback_move(PlaybackDirection direction) return; } m_board_playback.apply_move(m_board.moves().at(m_playback_move_number++)); + update_move_display_widget(m_board_playback); if (m_playback_move_number == m_board.moves().size()) m_playback = false; break; @@ -535,6 +536,21 @@ void ChessWidget::playback_move(PlaybackDirection direction) update(); } +void ChessWidget::update_move_display_widget(Chess::Board& board) +{ + size_t turn = 1; + StringBuilder sb; + for (auto [i, move] : enumerate(board.moves())) { + if (i % 2 == 0) { + sb.append(MUST(String::formatted("{}. {}", turn, MUST(move.to_algebraic())))); + } else { + sb.append(MUST(String::formatted(" {}\n", MUST(move.to_algebraic())))); + turn++; + } + } + m_move_display_widget->set_text(sb.string_view()); +} + ErrorOr ChessWidget::get_fen() const { return TRY(m_playback ? m_board_playback.to_fen() : m_board.to_fen()); @@ -740,6 +756,7 @@ ErrorOr ChessWidget::import_pgn(Core::File& file) m_board_playback = m_board; m_playback_move_number = m_board_playback.moves().size(); m_playback = true; + update_move_display_widget(m_board_playback); update(); return {}; diff --git a/Userland/Games/Chess/ChessWidget.h b/Userland/Games/Chess/ChessWidget.h index a952a8f2e47..53a85f4a78b 100644 --- a/Userland/Games/Chess/ChessWidget.h +++ b/Userland/Games/Chess/ChessWidget.h @@ -16,6 +16,7 @@ #include #include #include +#include #include namespace Chess { @@ -81,6 +82,7 @@ public: ErrorOr get_fen() const; ErrorOr import_pgn(Core::File&); ErrorOr export_pgn(Core::File&) const; + void update_move_display_widget(Chess::Board&); int resign(); void flip_board(); @@ -106,6 +108,7 @@ public: void playback_move(PlaybackDirection); void set_engine(RefPtr engine) { m_engine = engine; } + void set_move_display_widget(RefPtr move_display_widget) { m_move_display_widget = move_display_widget; } void input_engine_move(); bool want_engine_move(); @@ -174,6 +177,7 @@ private: RefPtr m_engine; bool m_coordinates { true }; bool m_highlight_checks { true }; + RefPtr m_move_display_widget; }; } diff --git a/Userland/Games/Chess/main.cpp b/Userland/Games/Chess/main.cpp index b1883cd7071..c61ac30722e 100644 --- a/Userland/Games/Chess/main.cpp +++ b/Userland/Games/Chess/main.cpp @@ -66,7 +66,10 @@ ErrorOr serenity_main(Main::Arguments arguments) auto window = GUI::Window::construct(); auto main_widget = TRY(Chess::MainWidget::try_create()); + auto& chess_widget = *main_widget->find_descendant_of_type_named("chess_widget"); + auto& move_display_widget = *main_widget->find_descendant_of_type_named("move_display_widget"); + chess_widget.set_move_display_widget(move(move_display_widget)); window->set_main_widget(main_widget); window->set_focused_widget(&chess_widget); @@ -85,7 +88,7 @@ ErrorOr serenity_main(Main::Arguments arguments) window->set_title("Chess"); window->set_base_size({ 4, 4 }); window->set_size_increment({ 8, 8 }); - window->resize(508, 508); + window->resize(668, 508); window->set_icon(app_icon.bitmap_for_size(16));