From d9763f0777800e765274f52aa2a90be0b43ff29c Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Thu, 18 Jul 2024 14:42:05 +0300
Subject: [PATCH 01/30] skip Qt 5 build on macos-latest (#799)
The latest versions of MacOS do not support building with Qt 5 so skip
it.
---
.github/workflows/build.yml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f6cb74de..4229b8d8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,6 +13,9 @@ jobs:
matrix:
qt_version: [5.15.2, 6.5.2]
os: [windows-latest, ubuntu-latest, macos-latest]
+ exclude:
+ - os: macos-latest
+ qt_version: 5.15.2
steps:
- uses: actions/checkout@v3
From f842c194bcb249205d1128e7218dca426aed3357 Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Thu, 18 Jul 2024 17:01:53 +0300
Subject: [PATCH 02/30] re-enable local CodeQL queries (#798)
These local queries were developed some years ago but were disabled when
the LGTM service (predecessor to CodeQL) was deprecated.
Reference the directory where the local queries are located
with the `queries` parameter in the `codeql/init` step. Add a QL pack
configuration so that CodeQL understand this directory contains the
queries.
---
.github/workflows/codeql.yml | 1 +
.lgtm/cpp-queries/qlpack.yml | 5 +++++
2 files changed, 6 insertions(+)
create mode 100644 .lgtm/cpp-queries/qlpack.yml
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 998a6a29..1708b642 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -57,6 +57,7 @@ jobs:
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
+ queries: +./.lgtm/cpp-queries
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
diff --git a/.lgtm/cpp-queries/qlpack.yml b/.lgtm/cpp-queries/qlpack.yml
new file mode 100644
index 00000000..c8c072e8
--- /dev/null
+++ b/.lgtm/cpp-queries/qlpack.yml
@@ -0,0 +1,5 @@
+name: cutechess/cpp-queries
+version: 1.0.0
+dependencies:
+ codeql/cpp-all: "*"
+extractor: cpp
From 554fa68101c0419abcb360156ed1dac4eaf5ee2d Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 18 Jul 2024 17:24:58 +0300
Subject: [PATCH 03/30] build(deps): bump actions/checkout from 3 to 4 (#779)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)
---
updated-dependencies:
- dependency-name: actions/checkout
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/build.yml | 2 +-
.github/workflows/codeql.yml | 2 +-
.github/workflows/coverity.yml | 2 +-
.github/workflows/release.yml | 6 +++---
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4229b8d8..19c9842a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -17,7 +17,7 @@ jobs:
- os: macos-latest
qt_version: 5.15.2
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: install qt 5.x
uses: jurplel/install-qt-action@v3
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 1708b642..058826a0 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -46,7 +46,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install dependencies
run: |
diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml
index 7222c23a..126d4874 100644
--- a/.github/workflows/coverity.yml
+++ b/.github/workflows/coverity.yml
@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt install qtbase5-dev qtbase5-dev-tools libqt5svg5-dev
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 9f064e69..aec09078 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -11,7 +11,7 @@ jobs:
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: set version
run: echo "VERSION=$(cat .version)" >> $GITHUB_ENV
@@ -35,7 +35,7 @@ jobs:
qt_version: [6.5.2]
os: [ubuntu-latest]
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: install qt 6.x
uses: jurplel/install-qt-action@v3
@@ -89,7 +89,7 @@ jobs:
qt_version: [5.15.2]
os: [windows-latest]
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: install qt 5.x
uses: jurplel/install-qt-action@v3
From ca0d8451dc0b147c3e4fd92d2b71aa17457958e6 Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Thu, 18 Jul 2024 18:55:48 +0300
Subject: [PATCH 04/30] bump CodeQL Action to v3 (#800)
The v2 based actions will be deprecated at the end of 2024:
https://github.blog/changelog/2024-01-12-code-scanning-deprecation-of-codeql-action-v2/
---
.github/workflows/codeql.yml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 058826a0..eea6165b 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -54,7 +54,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +./.lgtm/cpp-queries
@@ -69,7 +69,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
- uses: github/codeql-action/autobuild@v2
+ uses: github/codeql-action/autobuild@v3
# âšī¸ Command-line programs to run using the OS shell.
# đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -82,6 +82,6 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
From 48e0297c6b02f4cb4f7ebf3fafc43114eee87e04 Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Fri, 19 Jul 2024 10:36:33 +0300
Subject: [PATCH 05/30] update changelog
---
CHANGELOG.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index af851a5a..ac644802 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,16 @@
All notable changes to Cute Chess will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+## Unreleased
+
+### Fixed
+
+- Cute Chess specific CodeQL static analysis queries have been re-enabled (#798)
+
+### Changed
+
+- Limit the CI build for the latest MacOS version to Qt 6 only (#799)
+
## [1.3.1](https://github.com/cutechess/cutechess/releases/tag/v1.3.1) - 2023-07-30
### Added
From ba889643c8e5462066c5adedf2698b5f1b21ae81 Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Fri, 19 Jul 2024 11:42:05 +0300
Subject: [PATCH 06/30] bump CI build to use the latest Qt 6 release (#801)
---
.github/workflows/build.yml | 2 +-
.github/workflows/release.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 19c9842a..0527b231 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
- qt_version: [5.15.2, 6.5.2]
+ qt_version: [5.15.2, 6.7.2]
os: [windows-latest, ubuntu-latest, macos-latest]
exclude:
- os: macos-latest
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index aec09078..d41cbff6 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -32,7 +32,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
- qt_version: [6.5.2]
+ qt_version: [6.7.2]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
From f62e186de1f76b414e87e9aac0a4634afddfad3a Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Fri, 19 Jul 2024 14:50:44 +0300
Subject: [PATCH 07/30] build Windows releases with Qt 6 (#802)
---
.github/workflows/release.yml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d41cbff6..1ee31b4a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -86,16 +86,16 @@ jobs:
ISDIR: 'C:\Program Files (x86)\Inno Setup 6'
strategy:
matrix:
- qt_version: [5.15.2]
+ qt_version: [6.7.2]
os: [windows-latest]
steps:
- uses: actions/checkout@v4
- - name: install qt 5.x
+ - name: install qt 6.x
uses: jurplel/install-qt-action@v3
- if: startsWith(matrix.qt_version, '5.')
with:
version: ${{ matrix.qt_version }}
+ modules: 'qt5compat'
- name: build cute chess
run: |
From c75a5da7c9d682696999d670b7caff4b87d86720 Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Fri, 19 Jul 2024 15:07:57 +0300
Subject: [PATCH 08/30] update changelog
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ac644802..a7898e1f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed
+- Windows releases are now built with Qt 6 (#802)
- Limit the CI build for the latest MacOS version to Qt 6 only (#799)
## [1.3.1](https://github.com/cutechess/cutechess/releases/tag/v1.3.1) - 2023-07-30
From 2708f926b3e45f2b5ca8b7c94d4c2d4e8caccfa1 Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Fri, 19 Jul 2024 15:22:59 +0300
Subject: [PATCH 09/30] version 1.3.2-beta1
---
.version | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.version b/.version
index 6261a05b..10cad164 100644
--- a/.version
+++ b/.version
@@ -1 +1 @@
-1.3.1
\ No newline at end of file
+1.3.2-beta1
\ No newline at end of file
From b1ce6b33395847118956c356b4cda32b93b5a97a Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Fri, 19 Jul 2024 17:18:50 +0300
Subject: [PATCH 10/30] install app icons to the correct directory (#803)
I *think* this is the correct location for the icons.
Also add more icon resolutions in addition to the 256x256.
---
CMakeLists.txt | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 21afca22..cfed1c58 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -322,6 +322,9 @@ endif()
install(TARGETS cli DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
install(TARGETS gui DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
install(FILES dist/linux/cutechess.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications COMPONENT Runtime)
-install(FILES projects/gui/res/icons/cutechess_256x256.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/application/256x256/apps/ RENAME cutechess.png COMPONENT Runtime)
+install(FILES projects/gui/res/icons/cutechess_64x64.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/64x64/apps/ RENAME cutechess.png COMPONENT Runtime)
+install(FILES projects/gui/res/icons/cutechess_128x128.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/128x128/apps/ RENAME cutechess.png COMPONENT Runtime)
+install(FILES projects/gui/res/icons/cutechess_256x256.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/256x256/apps/ RENAME cutechess.png COMPONENT Runtime)
+install(FILES projects/gui/res/icons/cutechess_512x512.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/512x512/apps/ RENAME cutechess.png COMPONENT Runtime)
install(FILES docs/cutechess-cli.6 DESTINATION ${CMAKE_INSTALL_MANDIR}/man6/ COMPONENT Documentation)
install(FILES docs/cutechess-engines.json.5 DESTINATION ${CMAKE_INSTALL_MANDIR}/man5/ COMPONENT Documentation)
From 34153ccbaa1f0d06ec8f55532cb8db77adc72848 Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Fri, 19 Jul 2024 17:41:54 +0300
Subject: [PATCH 11/30] fix issues related to Windows Qt6 release (#804)
---
.github/workflows/release.yml | 18 +++++++++---------
dist/windows_setup.iss | 14 +++++++-------
2 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 1ee31b4a..badc64cd 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -121,22 +121,22 @@ jobs:
cp ..\docs\cutechess-engines.json.5.html .
cp ..\docs\cutechess-engines.json.5.txt .
cp "$env:VCDIR\VC\Redist\MSVC\v143\vc_redist.x64.exe" .
- cp "$env:Qt5_Dir\bin\Qt5Core.dll" .
- cp "$env:Qt5_Dir\bin\Qt5Gui.dll" .
- cp "$env:Qt5_Dir\bin\Qt5Svg.dll" .
- cp "$env:Qt5_Dir\bin\Qt5PrintSupport.dll" .
- cp "$env:Qt5_Dir\bin\Qt5Widgets.dll" .
- cp "$env:Qt5_Dir\bin\Qt5ConCurrent.dll" .
+ cp "$env:Qt6_Dir\bin\Qt6Core.dll" .
+ cp "$env:Qt6_Dir\bin\Qt6Gui.dll" .
+ cp "$env:Qt6_Dir\bin\Qt6Svg.dll" .
+ cp "$env:Qt6_Dir\bin\Qt6PrintSupport.dll" .
+ cp "$env:Qt6_Dir\bin\Qt6Widgets.dll" .
+ cp "$env:Qt6_Dir\bin\Qt6ConCurrent.dll" .
mkdir platforms
- cp "$env:Qt5_Dir\plugins\platforms\qwindows.dll" platforms\
+ cp "$env:Qt6_Dir\plugins\platforms\qwindows.dll" platforms\
mkdir styles
- cp "$env:Qt5_Dir\plugins\styles\qwindowsvistastyle.dll" styles\
+ cp "$env:Qt6_Dir\plugins\styles\qmodernwindowsstyle.dll" styles\
cd ..
7z a cutechess-$env:VERSION-win64.zip cutechess-$env:VERSION-win64\
- name: create an installer
run: |
- & "$env:ISDIR\iscc.exe" /DMyAppVersion=$env:VERSION /DQtLibPath=$env:Qt5_Dir /DMSVCPath=$env:VCDIR /DCuteChessPath=$env:GITHUB_WORKSPACE dist\windows_setup.iss
+ & "$env:ISDIR\iscc.exe" /DMyAppVersion=$env:VERSION /DQtLibPath=$env:Qt6_Dir /DMSVCPath=$env:VCDIR /DCuteChessPath=$env:GITHUB_WORKSPACE dist\windows_setup.iss
- name: upload zip release asset
uses: actions/upload-release-asset@v1
diff --git a/dist/windows_setup.iss b/dist/windows_setup.iss
index d1a0bae7..dd6d97bb 100644
--- a/dist/windows_setup.iss
+++ b/dist/windows_setup.iss
@@ -49,14 +49,14 @@ Source: "{#CuteChessPath}\build\Release\cutechess-cli.exe"; DestDir: "{app}"; Fl
#ifdef MSVC
Source: "{#MSVCPath}\VC\Redist\MSVC\v143\vc_redist.x64.exe"; DestDir: "{app}"; Flags: ignoreversion
#endif
-Source: "{#QtLibPath}\bin\Qt5Core.dll"; DestDir: "{app}"; Flags: ignoreversion
-Source: "{#QtLibPath}\bin\Qt5Gui.dll"; DestDir: "{app}"; Flags: ignoreversion
-Source: "{#QtLibPath}\bin\Qt5Svg.dll"; DestDir: "{app}"; Flags: ignoreversion
-Source: "{#QtLibPath}\bin\Qt5PrintSupport.dll"; DestDir: "{app}"; Flags: ignoreversion
-Source: "{#QtLibPath}\bin\Qt5Widgets.dll"; DestDir: "{app}"; Flags: ignoreversion
-Source: "{#QtLibPath}\bin\Qt5Concurrent.dll"; DestDir: "{app}"; Flags: ignoreversion
+Source: "{#QtLibPath}\bin\Qt6Core.dll"; DestDir: "{app}"; Flags: ignoreversion
+Source: "{#QtLibPath}\bin\Qt6Gui.dll"; DestDir: "{app}"; Flags: ignoreversion
+Source: "{#QtLibPath}\bin\Qt6Svg.dll"; DestDir: "{app}"; Flags: ignoreversion
+Source: "{#QtLibPath}\bin\Qt6PrintSupport.dll"; DestDir: "{app}"; Flags: ignoreversion
+Source: "{#QtLibPath}\bin\Qt6Widgets.dll"; DestDir: "{app}"; Flags: ignoreversion
+Source: "{#QtLibPath}\bin\Qt6Concurrent.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#QtLibPath}\plugins\platforms\qwindows.dll"; DestDir: "{app}\platforms"; Flags: ignoreversion
-Source: "{#QtLibPath}\plugins\styles\qwindowsvistastyle.dll"; DestDir: "{app}\styles"; Flags: ignoreversion
+Source: "{#QtLibPath}\plugins\styles\qmodernwindowsstyle.dll"; DestDir: "{app}\styles"; Flags: ignoreversion
Source: "{#CuteChessPath}\COPYING"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#CuteChessPath}\docs\cutechess-cli.6.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#CuteChessPath}\docs\cutechess-cli.6.html"; DestDir: "{app}"; Flags: ignoreversion
From 4b8d618b268f6dda9cbf0e445ac118ccec434ea1 Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Fri, 19 Jul 2024 17:42:38 +0300
Subject: [PATCH 12/30] version 1.3.2-beta2
---
.version | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.version b/.version
index 10cad164..613119d7 100644
--- a/.version
+++ b/.version
@@ -1 +1 @@
-1.3.2-beta1
\ No newline at end of file
+1.3.2-beta2
\ No newline at end of file
From 853c34cc83d3dc892b6d106d40c7a58f380d7aa7 Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Fri, 19 Jul 2024 18:23:32 +0300
Subject: [PATCH 13/30] add Qt5 compatibility component to Windows release
(#805)
---
.github/workflows/release.yml | 1 +
dist/windows_setup.iss | 1 +
2 files changed, 2 insertions(+)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index badc64cd..88167d95 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -127,6 +127,7 @@ jobs:
cp "$env:Qt6_Dir\bin\Qt6PrintSupport.dll" .
cp "$env:Qt6_Dir\bin\Qt6Widgets.dll" .
cp "$env:Qt6_Dir\bin\Qt6ConCurrent.dll" .
+ cp "$env:Qt6_Dir\bin\Qt6Core5Compat.dll" .
mkdir platforms
cp "$env:Qt6_Dir\plugins\platforms\qwindows.dll" platforms\
mkdir styles
diff --git a/dist/windows_setup.iss b/dist/windows_setup.iss
index dd6d97bb..386eaa43 100644
--- a/dist/windows_setup.iss
+++ b/dist/windows_setup.iss
@@ -55,6 +55,7 @@ Source: "{#QtLibPath}\bin\Qt6Svg.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#QtLibPath}\bin\Qt6PrintSupport.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#QtLibPath}\bin\Qt6Widgets.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#QtLibPath}\bin\Qt6Concurrent.dll"; DestDir: "{app}"; Flags: ignoreversion
+Source: "{#QtLibPath}\bin\Qt6Core5Compat.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#QtLibPath}\plugins\platforms\qwindows.dll"; DestDir: "{app}\platforms"; Flags: ignoreversion
Source: "{#QtLibPath}\plugins\styles\qmodernwindowsstyle.dll"; DestDir: "{app}\styles"; Flags: ignoreversion
Source: "{#CuteChessPath}\COPYING"; DestDir: "{app}"; Flags: ignoreversion
From a882913c1106287802e564d29a62932b7724b9f1 Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Fri, 19 Jul 2024 18:24:06 +0300
Subject: [PATCH 14/30] version 1.3.2-beta3
---
.version | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.version b/.version
index 613119d7..1bde121c 100644
--- a/.version
+++ b/.version
@@ -1 +1 @@
-1.3.2-beta2
\ No newline at end of file
+1.3.2-beta3
\ No newline at end of file
From c4afd36924b070a642fa4f3545e7ae783fb04a19 Mon Sep 17 00:00:00 2001
From: Ilari Pihlajisto
Date: Sat, 20 Jul 2024 11:51:55 +0300
Subject: [PATCH 15/30] clang-format fixes to better match existing Cute Chess
style
---
.clang-format | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/.clang-format b/.clang-format
index d3c46d0f..68660242 100644
--- a/.clang-format
+++ b/.clang-format
@@ -16,18 +16,19 @@ BreakBeforeBraces: Custom
BreakBeforeBinaryOperators: None
BraceWrapping:
AfterClass: true
- AfterControlStatement: false
- AfterEnum: false
+ AfterControlStatement: true
+ AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterStruct: true
AfterUnion: false
BeforeCatch: false
- BeforeElse: false
+ BeforeElse: true
+ BeforeLambdaBody: true
IndentBraces: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, forever, Q_FOREVER, QBENCHMARK, QBENCHMARK_ONCE ]
NamespaceIndentation: None
SortIncludes: false
SpaceAfterTemplateKeyword: false
-BreakBeforeBinaryOperators: NonAssignment
+LambdaBodyIndentation: OuterScope
...
From c1eb6fa56935b43785cc4f53b33914a36f164d01 Mon Sep 17 00:00:00 2001
From: alwey
Date: Sat, 8 Aug 2020 11:59:01 +0200
Subject: [PATCH 16/30] GUI: Option to use split time controls for White and
Black in individual games
Use the new TimeControlWidget in support of TimeControlDialog.
Enable second TimeControlWidget for Black on demand.
Add timeControl2 to GameSettingsWidget, save/read settings for 2nd control.
Add extra control logic for hourglass mode.
GUI: Option to use individual time controls in tournaments
Add a context menu to the tournament players' list.
Add function to edit time controls individually.
Use a simplified time control dialog (2nd time control unused).
Add QVector of individual time controls to NewTournamentDialog.
Support multi-engine selection for time control updates.
Use an individual time control when valid else tournament controls.
At tournament creation hourglass mode is enabled or disabled uniformly
according to the tournament's common settings.
---
projects/gui/src/gamesettingswidget.cpp | 56 +++-
projects/gui/src/gamesettingswidget.h | 5 +
projects/gui/src/newgamedlg.cpp | 5 +-
projects/gui/src/newtournamentdialog.cpp | 58 +++-
projects/gui/src/newtournamentdialog.h | 2 +
projects/gui/src/settingsdlg.cpp | 1 +
projects/gui/src/timecontroldlg.cpp | 165 +++--------
projects/gui/src/timecontroldlg.h | 27 +-
projects/gui/src/timecontrolwidget.cpp | 202 +++++++++++++
projects/gui/src/timecontrolwidget.h | 78 +++++
projects/gui/ui/timecontroldlg.ui | 351 +++++++----------------
projects/gui/ui/timecontrolwidget.ui | 268 +++++++++++++++++
12 files changed, 809 insertions(+), 409 deletions(-)
create mode 100644 projects/gui/src/timecontrolwidget.cpp
create mode 100644 projects/gui/src/timecontrolwidget.h
create mode 100644 projects/gui/ui/timecontrolwidget.ui
diff --git a/projects/gui/src/gamesettingswidget.cpp b/projects/gui/src/gamesettingswidget.cpp
index 128249c1..562b7d04 100644
--- a/projects/gui/src/gamesettingswidget.cpp
+++ b/projects/gui/src/gamesettingswidget.cpp
@@ -31,6 +31,7 @@
GameSettingsWidget::GameSettingsWidget(QWidget *parent)
: QWidget(parent),
ui(new Ui::GameSettingsWidget),
+ m_splitTimeControls(false),
m_board(nullptr),
m_isValid(true)
{
@@ -46,6 +47,9 @@ GameSettingsWidget::GameSettingsWidget(QWidget *parent)
this, SLOT(showTimeControlDialog()));
m_timeControl.setMovesPerTc(40);
m_timeControl.setTimePerTc(300000);
+ m_timeControl2.setMovesPerTc(40);
+ m_timeControl2.setTimePerTc(300000);
+
ui->m_timeControlBtn->setText(m_timeControl.toVerboseString());
connect(ui->m_browseOpeningSuiteBtn, &QPushButton::clicked, this, [=]()
@@ -129,6 +133,11 @@ TimeControl GameSettingsWidget::timeControl() const
return m_timeControl;
}
+TimeControl GameSettingsWidget::timeControl2() const
+{
+ return m_timeControl2;
+}
+
bool GameSettingsWidget::pondering() const
{
return ui->m_ponderingCheck->isChecked();
@@ -231,7 +240,12 @@ void GameSettingsWidget::readSettings()
ui->m_variantCombo->setCurrentText(s.value("variant").toString());
m_timeControl.readSettings(&s);
- ui->m_timeControlBtn->setText(m_timeControl.toVerboseString());
+
+ s.beginGroup("second_time_control");
+ m_timeControl2.readSettings(&s);
+ s.endGroup(); // "second_time_control"
+
+ updateButtonText();
s.beginGroup("opening_suite");
ui->m_fenEdit->setText(s.value("fen").toString());
@@ -239,7 +253,7 @@ void GameSettingsWidget::readSettings()
ui->m_openingSuiteDepthSpin->setValue(s.value("depth", 1).toInt());
if (s.value("random_order").toBool())
ui->m_randomOrderRadio->setChecked(true);
- s.endGroup();
+ s.endGroup(); // "games"
s.beginGroup("opening_book");
ui->m_polyglotFileEdit->setText(s.value("file").toString());
@@ -283,7 +297,12 @@ void GameSettingsWidget::enableSettingsUpdates()
QSettings s;
s.beginGroup("games");
m_timeControl.writeSettings(&s);
- s.endGroup();
+
+ s.beginGroup("second_time_control");
+ m_timeControl2.writeSettings(&s);
+ s.endGroup(); // "second_time_control"
+
+ s.endGroup(); // "games"
});
connect(ui->m_tbCheck, &QCheckBox::toggled, [=](bool checked)
@@ -417,13 +436,38 @@ void GameSettingsWidget::validateFen(const QString& fen)
}
}
+void GameSettingsWidget::updateButtonText()
+{
+ QString str(m_timeControl.toVerboseString());
+
+ if (!(m_timeControl == m_timeControl2) && m_splitTimeControls)
+ str += " vs " + m_timeControl2.toVerboseString();
+
+ ui->m_timeControlBtn->setText(str);
+}
+
+void GameSettingsWidget::enableSplitTimeControls(bool enable)
+{
+ m_splitTimeControls = enable;
+ updateButtonText();
+}
+
void GameSettingsWidget::showTimeControlDialog()
{
- TimeControlDialog dlg(m_timeControl);
+ TimeControlDialog dlg(m_timeControl,
+ m_splitTimeControls ? m_timeControl2 : TimeControl());
+
if (dlg.exec() == QDialog::Accepted)
{
- m_timeControl = dlg.timeControl();
- ui->m_timeControlBtn->setText(m_timeControl.toVerboseString());
+ m_timeControl = dlg.timeControlWhite();
+ m_timeControl2 = dlg.timeControlBlack();
+ QString str(m_timeControl.toVerboseString());
+
+ if (!(m_timeControl == m_timeControl2))
+ str += " vs " + m_timeControl2.toVerboseString();
+
+ ui->m_timeControlBtn->setText(str);
+
emit timeControlChanged();
}
}
diff --git a/projects/gui/src/gamesettingswidget.h b/projects/gui/src/gamesettingswidget.h
index fe4a68e3..e8014345 100644
--- a/projects/gui/src/gamesettingswidget.h
+++ b/projects/gui/src/gamesettingswidget.h
@@ -43,6 +43,7 @@ class GameSettingsWidget : public QWidget
QString chessVariant() const;
TimeControl timeControl() const;
+ TimeControl timeControl2() const;
bool pondering() const;
GameAdjudicator adjudicator() const;
OpeningSuite* openingSuite() const;
@@ -53,6 +54,7 @@ class GameSettingsWidget : public QWidget
void applyEngineConfiguration(EngineConfiguration* config);
void enableSettingsUpdates();
+ void enableSplitTimeControls(bool enable);
public slots:
void onHumanCountChanged(int count);
@@ -68,9 +70,12 @@ class GameSettingsWidget : public QWidget
private:
void readSettings();
+ void updateButtonText();
Ui::GameSettingsWidget *ui;
+ bool m_splitTimeControls;
TimeControl m_timeControl;
+ TimeControl m_timeControl2;
Chess::Board* m_board;
QPalette m_defaultPalette;
bool m_isValid;
diff --git a/projects/gui/src/newgamedlg.cpp b/projects/gui/src/newgamedlg.cpp
index 1070ce93..edf8b3fc 100644
--- a/projects/gui/src/newgamedlg.cpp
+++ b/projects/gui/src/newgamedlg.cpp
@@ -47,6 +47,7 @@ NewGameDialog::NewGameDialog(EngineManager* engineManager, QWidget* parent)
{
Q_ASSERT(engineManager != nullptr);
ui->setupUi(this);
+ ui->m_gameSettings->enableSplitTimeControls(true);
m_engines = new EngineConfigurationModel(m_engineManager, this);
#if 0
@@ -112,7 +113,9 @@ ChessGame* NewGameDialog::createGame() const
pgn->setSite(QSettings().value("pgn/site").toString());
auto game = new ChessGame(board, pgn);
- game->setTimeControl(ui->m_gameSettings->timeControl());
+ game->setTimeControl(ui->m_gameSettings->timeControl(), Chess::Side::White);
+ game->setTimeControl(ui->m_gameSettings->timeControl2(), Chess::Side::Black);
+
game->setAdjudicator(ui->m_gameSettings->adjudicator());
auto suite = ui->m_gameSettings->openingSuite();
diff --git a/projects/gui/src/newtournamentdialog.cpp b/projects/gui/src/newtournamentdialog.cpp
index 9ac086ec..8f601d84 100644
--- a/projects/gui/src/newtournamentdialog.cpp
+++ b/projects/gui/src/newtournamentdialog.cpp
@@ -20,6 +20,7 @@
#include
#include
+#include
#include
#include
@@ -112,6 +113,10 @@ NewTournamentDialog::NewTournamentDialog(EngineManager* engineManager,
connect(ui->m_playersList, SIGNAL(doubleClicked(QModelIndex)),
this, SLOT(configureEngine(QModelIndex)));
+ ui->m_playersList->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
+ connect(ui->m_playersList, SIGNAL(customContextMenuRequested(const QPoint&)),
+ this, SLOT(onContextMenuRequest()));
+
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
connect(ui->m_gameSettings, &GameSettingsWidget::statusChanged, [=](bool ok)
{
@@ -136,6 +141,7 @@ void NewTournamentDialog::addEngineOnDblClick(const QModelIndex& index)
const QModelIndex& idx = m_proxyModel->mapToSource(index);
m_addedEnginesManager->addEngine(m_srcEngineManager->engineAt(idx.row()));
+ m_timeControls << TimeControl();
listView->selectionModel()->select(index, QItemSelectionModel::Deselect);
QPushButton* button = ui->buttonBox->button(QDialogButtonBox::Ok);
@@ -157,7 +163,10 @@ void NewTournamentDialog::addEngine()
const QModelIndexList list(dlg.selection().indexes());
for (const QModelIndex& index : list)
+ {
m_addedEnginesManager->addEngine(m_srcEngineManager->engineAt(index.row()));
+ m_timeControls << TimeControl();
+ }
QPushButton* button = ui->buttonBox->button(QDialogButtonBox::Ok);
button->setEnabled(canStart());
@@ -176,7 +185,10 @@ void NewTournamentDialog::removeEngine()
});
for (const QModelIndex& index : qAsConst(selected))
+ {
m_addedEnginesManager->removeEngineAt(index.row());
+ m_timeControls.remove(index.row());
+ }
QPushButton* button = ui->buttonBox->button(QDialogButtonBox::Ok);
button->setEnabled(canStart());
@@ -207,10 +219,14 @@ void NewTournamentDialog::moveEngine(int offset)
int row1 = index.row();
int row2 = row1 + offset;
EngineConfiguration tmp(m_addedEnginesManager->engineAt(row1));
+ TimeControl tc = m_timeControls.at(row1);
m_addedEnginesManager->updateEngineAt(row1, m_addedEnginesManager->engineAt(row2));
m_addedEnginesManager->updateEngineAt(row2, tmp);
+ m_timeControls[row1] = m_timeControls.at(row2);
+ m_timeControls[row2]= tc;
+
ui->m_playersList->setCurrentIndex(index.sibling(row2, 0));
}
@@ -264,6 +280,37 @@ void NewTournamentDialog::onPlayerSelectionChanged(const QItemSelection& selecte
ui->m_moveEngineDownBtn->setEnabled(enable && i < m_addedEnginesManager->engineCount() - 1);
}
+void NewTournamentDialog::onContextMenuRequest()
+{
+ QList selected = ui->m_playersList->selectionModel()->selectedRows();
+ if (selected.isEmpty())
+ return;
+
+ QMenu menu(ui->m_playersList);
+
+ auto editTimeControlAct = menu.addAction(tr("Edit Time Control"));
+ connect(editTimeControlAct, &QAction::triggered, this, [=]()
+ {
+ int i = selected.first().row();
+ TimeControl tc {m_timeControls.at(i)};
+ if (!tc.isValid())
+ tc = ui->m_gameSettings->timeControl();
+
+ auto dlg = new TimeControlDialog(tc);
+ QString name {m_addedEnginesManager->engines().at(i).name()};
+ if (selected.count() > 1)
+ name.append(tr(" - %0 engines").arg(selected.count()));
+ dlg->setWindowTitle(tr("Time Control - %0").arg(name));
+
+ if (dlg->exec() == QDialog::Accepted)
+ for (QModelIndex index: selected)
+ m_timeControls[index.row()] = dlg->timeControlWhite();
+ delete dlg;
+ });
+
+ menu.exec(QCursor::pos());
+}
+
Tournament* NewTournamentDialog::createTournament(GameManager* gameManager) const
{
Q_ASSERT(gameManager != nullptr);
@@ -301,12 +348,19 @@ Tournament* NewTournamentDialog::createTournament(GameManager* gameManager) cons
t->setReverseSides(ts->reversingSchedule());
t->setResultFormat(ts->resultFormat());
+ bool isHourglass = ui->m_gameSettings->timeControl().isHourglass();
+
const auto engines = m_addedEnginesManager->engines();
- for (EngineConfiguration config : engines)
+ for (int i = 0; i < engines.count(); i++)
{
+ EngineConfiguration config = engines.at(i);
ui->m_gameSettings->applyEngineConfiguration(&config);
+ TimeControl tc = m_timeControls.at(i);
+ // Hourglass mode must be the same for all players
+ tc.setHourglass(isHourglass);
+
t->addPlayer(new EngineBuilder(config),
- ui->m_gameSettings->timeControl(),
+ tc.isValid() ? tc : ui->m_gameSettings->timeControl(),
book,
bookDepth);
}
diff --git a/projects/gui/src/newtournamentdialog.h b/projects/gui/src/newtournamentdialog.h
index 9b7e45b9..30e2f334 100644
--- a/projects/gui/src/newtournamentdialog.h
+++ b/projects/gui/src/newtournamentdialog.h
@@ -53,6 +53,7 @@ class NewTournamentDialog : public QDialog
void onVariantChanged(const QString& variant);
void onPlayerSelectionChanged(const QItemSelection& selected,
const QItemSelection& deselected);
+ void onContextMenuRequest();
private:
void moveEngine(int offset);
@@ -64,6 +65,7 @@ class NewTournamentDialog : public QDialog
EngineConfigurationModel* m_srcEnginesModel;
EngineConfigurationModel* m_addedEnginesModel;
EngineConfigurationProxyModel* m_proxyModel;
+ QVector m_timeControls;
Ui::NewTournamentDialog* ui;
};
diff --git a/projects/gui/src/settingsdlg.cpp b/projects/gui/src/settingsdlg.cpp
index 4d1bf028..bcd07474 100644
--- a/projects/gui/src/settingsdlg.cpp
+++ b/projects/gui/src/settingsdlg.cpp
@@ -29,6 +29,7 @@ SettingsDialog::SettingsDialog(QWidget* parent)
ui(new Ui::SettingsDialog)
{
ui->setupUi(this);
+ ui->m_gameSettings->enableSplitTimeControls(true);
readSettings();
diff --git a/projects/gui/src/timecontroldlg.cpp b/projects/gui/src/timecontroldlg.cpp
index c3b19159..09c17e2e 100644
--- a/projects/gui/src/timecontroldlg.cpp
+++ b/projects/gui/src/timecontroldlg.cpp
@@ -19,157 +19,66 @@
#include "timecontroldlg.h"
#include "ui_timecontroldlg.h"
-
-TimeControlDialog::TimeControlDialog(const TimeControl& tc,
+TimeControlDialog::TimeControlDialog(const TimeControl& tc1,
+ const TimeControl& tc2,
QWidget *parent)
: QDialog(parent),
ui(new Ui::TimeControlDialog)
{
ui->setupUi(this);
- connect(ui->m_tournamentRadio, SIGNAL(clicked()),
- this, SLOT(onTournamentSelected()));
- connect(ui->m_timePerMoveRadio, SIGNAL(clicked()),
- this, SLOT(onTimePerMoveSelected()));
- connect(ui->m_infiniteRadio, SIGNAL(clicked()),
- this, SLOT(onInfiniteSelected()));
- connect(ui->m_hourglassRadio, SIGNAL(clicked()),
- this, SLOT(onHourglassSelected()));
-
- if (!tc.isValid())
- return;
-
- if (tc.isInfinite())
- {
- ui->m_infiniteRadio->setChecked(true);
- onInfiniteSelected();
- }
- else if (tc.isHourglass())
+ // If tc2 has default value then use a simplified dialog
+ if (tc2 == TimeControl())
{
- ui->m_hourglassRadio->setChecked(true);
- setTime(tc.timePerTc());
- onHourglassSelected();
+ ui->m_timeControlGroupBoxBlack->setEnabled(false);
+ ui->m_timeControlGroupBoxWhite->setCheckable(false);
}
- else if (tc.timePerMove() != 0)
- {
- ui->m_timePerMoveRadio->setChecked(true);
- setTime(tc.timePerMove());
- onTimePerMoveSelected();
- }
- else
+
+ ui->m_timeControlGroupBoxBlack->setVisible(false);
+ adjustSize();
+
+ connect(ui->m_timeControlGroupBoxWhite, &QGroupBox::toggled, [=](bool checked)
{
- ui->m_tournamentRadio->setChecked(true);
- ui->m_movesSpin->setValue(tc.movesPerTc());
- ui->m_incrementSpin->setValue(double(tc.timeIncrement()) / 1000.0);
- setTime(tc.timePerTc());
- onTournamentSelected();
- }
+ ui->m_timeControlWidgetWhite->setEnabled(true);
+ ui->m_timeControlGroupBoxBlack->setEnabled(!checked);
+ ui->m_timeControlGroupBoxBlack->setVisible(!checked);
+ ui->m_timeControlWidgetBlack->setEnabled(!checked);
- ui->m_nodesSpin->setValue(tc.nodeLimit());
- ui->m_pliesSpin->setValue(tc.plyLimit());
- ui->m_marginSpin->setValue(tc.expiryMargin());
-}
+ ui->m_timeControlGroupBoxWhite->setTitle(checked ? tr("Both Sides")
+ : tr("White"));
+ adjustSize();
+ });
-TimeControlDialog::~TimeControlDialog()
-{
- delete ui;
-}
+ if (!tc1.isValid())
+ return;
-void TimeControlDialog::onTournamentSelected()
-{
- ui->m_movesSpin->setEnabled(true);
- ui->m_timeSpin->setEnabled(true);
- ui->m_timeUnitCombo->setEnabled(true);
- ui->m_incrementSpin->setEnabled(true);
- ui->m_marginSpin->setEnabled(true);
-}
+ ui->m_timeControlWidgetWhite->init(tc1);
+ ui->m_timeControlWidgetBlack->init(tc2.isValid() ? tc2 : tc1);
-void TimeControlDialog::onTimePerMoveSelected()
-{
- ui->m_movesSpin->setEnabled(false);
- ui->m_timeSpin->setEnabled(true);
- ui->m_timeUnitCombo->setEnabled(true);
- ui->m_incrementSpin->setEnabled(false);
- ui->m_marginSpin->setEnabled(true);
-}
+ ui->m_timeControlGroupBoxWhite->setChecked(tc1 == tc2 || !tc2.isValid());
+ ui->m_timeControlWidgetBlack->disableHourglassRadio();
-void TimeControlDialog::onInfiniteSelected()
-{
- ui->m_movesSpin->setEnabled(false);
- ui->m_timeSpin->setEnabled(false);
- ui->m_timeUnitCombo->setEnabled(false);
- ui->m_incrementSpin->setEnabled(false);
- ui->m_marginSpin->setEnabled(false);
+ connect (ui->m_timeControlWidgetWhite, SIGNAL(hourglassToggled(bool)),
+ ui->m_timeControlWidgetBlack, SLOT(setHourglassMode(bool)));
+
+ ui->m_timeControlWidgetBlack->setHourglassMode(tc1.isHourglass());
}
-void TimeControlDialog::onHourglassSelected()
+TimeControlDialog::~TimeControlDialog()
{
- ui->m_movesSpin->setEnabled(false);
- ui->m_timeSpin->setEnabled(true);
- ui->m_timeUnitCombo->setEnabled(true);
- ui->m_incrementSpin->setEnabled(false);
- ui->m_marginSpin->setEnabled(true);
+ delete ui;
}
-int TimeControlDialog::timeToMs() const
+TimeControl TimeControlDialog::timeControlWhite() const
{
- switch (ui->m_timeUnitCombo->currentIndex())
- {
- case Seconds:
- return ui->m_timeSpin->value() * 1000.0;
- case Minutes:
- return ui->m_timeSpin->value() * 60000.0;
- case Hours:
- return ui->m_timeSpin->value() * 3600000.0;
- default:
- return 0;
- }
+ return ui->m_timeControlWidgetWhite->timeControl();
}
-void TimeControlDialog::setTime(int ms)
+TimeControl TimeControlDialog::timeControlBlack() const
{
- Q_ASSERT(ms >= 0);
-
- if (ms == 0 || ms % 60000 != 0)
- {
- ui->m_timeUnitCombo->setCurrentIndex(Seconds);
- ui->m_timeSpin->setValue(double(ms) / 1000.0);
- }
- else if (ms % 3600000 != 0)
- {
- ui->m_timeUnitCombo->setCurrentIndex(Minutes);
- ui->m_timeSpin->setValue(double(ms) / 60000.0);
- }
+ if (ui->m_timeControlWidgetBlack->isEnabled())
+ return ui->m_timeControlWidgetBlack->timeControl();
else
- {
- ui->m_timeUnitCombo->setCurrentIndex(Hours);
- ui->m_timeSpin->setValue(double(ms) / 3600000.0);
- }
+ return ui->m_timeControlWidgetWhite->timeControl();
}
-TimeControl TimeControlDialog::timeControl() const
-{
- TimeControl tc;
- if (ui->m_infiniteRadio->isChecked())
- tc.setInfinity(true);
- else if (ui->m_timePerMoveRadio->isChecked())
- tc.setTimePerMove(timeToMs());
- else if (ui->m_tournamentRadio->isChecked())
- {
- tc.setMovesPerTc(ui->m_movesSpin->value());
- tc.setTimePerTc(timeToMs());
- tc.setTimeIncrement(ui->m_incrementSpin->value() * 1000.0);
- }
- else if (ui->m_hourglassRadio->isChecked())
- {
- tc.setHourglass(true);
- tc.setTimePerTc(timeToMs());
- tc.setTimeIncrement(0);
- }
-
- tc.setNodeLimit(ui->m_nodesSpin->value());
- tc.setPlyLimit(ui->m_pliesSpin->value());
- tc.setExpiryMargin(ui->m_marginSpin->value());
-
- return tc;
-}
diff --git a/projects/gui/src/timecontroldlg.h b/projects/gui/src/timecontroldlg.h
index 153a0ec1..ff1135cb 100644
--- a/projects/gui/src/timecontroldlg.h
+++ b/projects/gui/src/timecontroldlg.h
@@ -37,33 +37,20 @@ class TimeControlDialog : public QDialog
/*!
* Creates a new time control dialog.
*
- * The dialog is initialized according to \a tc.
+ * The dialog is initialized according to \a tc1,
+ * and \a tc2
*/
- explicit TimeControlDialog(const TimeControl& tc,
- QWidget *parent = nullptr);
+ explicit TimeControlDialog(const TimeControl& tc1,
+ const TimeControl& tc2 = TimeControl(),
+ QWidget* parent = nullptr);
/*! Destroys the dialog. */
virtual ~TimeControlDialog();
/*! Returns the time control that was set in the dialog. */
- TimeControl timeControl() const;
-
- private slots:
- void onTournamentSelected();
- void onTimePerMoveSelected();
- void onInfiniteSelected();
- void onHourglassSelected();
+ TimeControl timeControlWhite() const;
+ TimeControl timeControlBlack() const;
private:
- enum TimeUnit
- {
- Seconds,
- Minutes,
- Hours
- };
-
- int timeToMs() const;
- void setTime(int ms);
-
Ui::TimeControlDialog *ui;
};
diff --git a/projects/gui/src/timecontrolwidget.cpp b/projects/gui/src/timecontrolwidget.cpp
new file mode 100644
index 00000000..a54faac8
--- /dev/null
+++ b/projects/gui/src/timecontrolwidget.cpp
@@ -0,0 +1,202 @@
+/*
+ This file is part of Cute Chess.
+ Copyright (C) 2008-2018 Cute Chess authors
+
+ Cute Chess 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.
+
+ Cute Chess is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Cute Chess. If not, see .
+*/
+
+#include "timecontrolwidget.h"
+#include "ui_timecontrolwidget.h"
+
+
+TimeControlWidget::TimeControlWidget(QWidget *parent)
+ : QWidget(parent),
+ ui(new Ui::TimeControlWidget)
+{
+ ui->setupUi(this);
+}
+
+void TimeControlWidget::init(const TimeControl& tc)
+{
+ connect(ui->m_tournamentRadio, SIGNAL(clicked()),
+ this, SLOT(onTournamentSelected()));
+ connect(ui->m_timePerMoveRadio, SIGNAL(clicked()),
+ this, SLOT(onTimePerMoveSelected()));
+ connect(ui->m_infiniteRadio, SIGNAL(clicked()),
+ this, SLOT(onInfiniteSelected()));
+ connect(ui->m_hourglassRadio, SIGNAL(clicked()),
+ this, SLOT(onHourglassSelected()));
+ connect(ui->m_hourglassRadio, SIGNAL(toggled(bool)),
+ this, SIGNAL(hourglassToggled(bool)));
+
+ if (!tc.isValid())
+ return;
+
+ if (tc.isInfinite())
+ {
+ ui->m_infiniteRadio->setChecked(true);
+ onInfiniteSelected();
+ }
+ else if (tc.isHourglass())
+ {
+ ui->m_hourglassRadio->setChecked(true);
+ setTime(tc.timePerTc());
+ onHourglassSelected();
+ }
+ else if (tc.timePerMove() != 0)
+ {
+ ui->m_timePerMoveRadio->setChecked(true);
+ setTime(tc.timePerMove());
+ onTimePerMoveSelected();
+ }
+ else
+ {
+ ui->m_tournamentRadio->setChecked(true);
+ ui->m_movesSpin->setValue(tc.movesPerTc());
+ ui->m_incrementSpin->setValue(double(tc.timeIncrement()) / 1000.0);
+ setTime(tc.timePerTc());
+ onTournamentSelected();
+ }
+
+ ui->m_nodesSpin->setValue(tc.nodeLimit());
+ ui->m_pliesSpin->setValue(tc.plyLimit());
+ ui->m_marginSpin->setValue(tc.expiryMargin());
+}
+
+TimeControlWidget::~TimeControlWidget()
+{
+ delete ui;
+}
+
+void TimeControlWidget::onTournamentSelected()
+{
+ ui->m_movesSpin->setEnabled(true);
+ ui->m_timeSpin->setEnabled(true);
+ ui->m_timeUnitCombo->setEnabled(true);
+ ui->m_incrementSpin->setEnabled(true);
+ ui->m_marginSpin->setEnabled(true);
+}
+
+void TimeControlWidget::onTimePerMoveSelected()
+{
+ ui->m_movesSpin->setEnabled(false);
+ ui->m_timeSpin->setEnabled(true);
+ ui->m_timeUnitCombo->setEnabled(true);
+ ui->m_incrementSpin->setEnabled(false);
+ ui->m_marginSpin->setEnabled(true);
+}
+
+void TimeControlWidget::onInfiniteSelected()
+{
+ ui->m_movesSpin->setEnabled(false);
+ ui->m_timeSpin->setEnabled(false);
+ ui->m_timeUnitCombo->setEnabled(false);
+ ui->m_incrementSpin->setEnabled(false);
+ ui->m_marginSpin->setEnabled(false);
+}
+
+void TimeControlWidget::onHourglassSelected()
+{
+ ui->m_movesSpin->setEnabled(false);
+ ui->m_timeSpin->setEnabled(true);
+ ui->m_timeUnitCombo->setEnabled(true);
+ ui->m_incrementSpin->setEnabled(false);
+ ui->m_marginSpin->setEnabled(true);
+}
+
+void TimeControlWidget::setHourglassMode(bool enabled)
+{
+ ui->m_groupBox->setEnabled(!enabled);
+
+ if (enabled)
+ {
+ ui->m_hourglassRadio->setChecked(true);
+ onHourglassSelected();
+ }
+ else
+ {
+ ui->m_tournamentRadio->setChecked(true);
+ onTournamentSelected();
+ }
+}
+
+void TimeControlWidget::disableHourglassRadio()
+{
+ ui->m_hourglassRadio->setEnabled(false);
+ if (ui->m_hourglassRadio->isChecked())
+ ui->m_groupBox->setEnabled(false);
+}
+
+int TimeControlWidget::timeToMs() const
+{
+ switch (ui->m_timeUnitCombo->currentIndex())
+ {
+ case Seconds:
+ return ui->m_timeSpin->value() * 1000.0;
+ case Minutes:
+ return ui->m_timeSpin->value() * 60000.0;
+ case Hours:
+ return ui->m_timeSpin->value() * 3600000.0;
+ default:
+ return 0;
+ }
+}
+
+void TimeControlWidget::setTime(int ms)
+{
+ Q_ASSERT(ms >= 0);
+
+ if (ms == 0 || ms % 60000 != 0)
+ {
+ ui->m_timeUnitCombo->setCurrentIndex(Seconds);
+ ui->m_timeSpin->setValue(double(ms) / 1000.0);
+ }
+ else if (ms % 3600000 != 0)
+ {
+ ui->m_timeUnitCombo->setCurrentIndex(Minutes);
+ ui->m_timeSpin->setValue(double(ms) / 60000.0);
+ }
+ else
+ {
+ ui->m_timeUnitCombo->setCurrentIndex(Hours);
+ ui->m_timeSpin->setValue(double(ms) / 3600000.0);
+ }
+}
+
+TimeControl TimeControlWidget::timeControl() const
+{
+ TimeControl tc;
+ if (ui->m_infiniteRadio->isChecked())
+ tc.setInfinity(true);
+ else if (ui->m_timePerMoveRadio->isChecked())
+ tc.setTimePerMove(timeToMs());
+ else if (ui->m_tournamentRadio->isChecked())
+ {
+ tc.setMovesPerTc(ui->m_movesSpin->value());
+ tc.setTimePerTc(timeToMs());
+ tc.setTimeIncrement(ui->m_incrementSpin->value() * 1000.0);
+ }
+ else if (ui->m_hourglassRadio->isChecked())
+ {
+ tc.setHourglass(true);
+ tc.setTimePerTc(timeToMs());
+ tc.setTimeIncrement(0);
+ }
+
+ tc.setNodeLimit(ui->m_nodesSpin->value());
+ tc.setPlyLimit(ui->m_pliesSpin->value());
+ tc.setExpiryMargin(ui->m_marginSpin->value());
+
+ return tc;
+}
diff --git a/projects/gui/src/timecontrolwidget.h b/projects/gui/src/timecontrolwidget.h
new file mode 100644
index 00000000..1dfa0e20
--- /dev/null
+++ b/projects/gui/src/timecontrolwidget.h
@@ -0,0 +1,78 @@
+/*
+ This file is part of Cute Chess.
+ Copyright (C) 2008-2018 Cute Chess authors
+
+ Cute Chess 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.
+
+ Cute Chess is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Cute Chess. If not, see .
+*/
+
+#ifndef TIMECONTROLWIDGET_H
+#define TIMECONTROLWIDGET_H
+
+#include
+#include
+
+namespace Ui {
+ class TimeControlWidget;
+}
+
+/*!
+ * \brief A dialog for setting a chess game's time controls
+ */
+class TimeControlWidget : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ /*!
+ * Creates a new time control widget.
+ *
+ * The widget is initialized according to \a tc.
+ */
+ explicit TimeControlWidget(QWidget *parent = nullptr);
+ /*! Destroys the dialog. */
+ virtual ~TimeControlWidget();
+
+ /*! Initialise time contol, signals and slots */
+ void init(const TimeControl& tc);
+ /*! Returns the time control that was set in the dialog. */
+ TimeControl timeControl() const;
+
+ signals:
+ void hourglassToggled(bool);
+
+ public slots: void setHourglassMode(bool enabled);
+ void disableHourglassRadio();
+
+ private slots:
+ void onTournamentSelected();
+ void onTimePerMoveSelected();
+ void onInfiniteSelected();
+ void onHourglassSelected();
+
+ private:
+ enum TimeUnit
+ {
+ Seconds,
+ Minutes,
+ Hours
+ };
+
+ int timeToMs() const;
+ void setTime(int ms);
+
+ Ui::TimeControlWidget *ui;
+ TimeControl m_tc;
+};
+
+#endif // TIMECONTROLWIDGET_H
diff --git a/projects/gui/ui/timecontroldlg.ui b/projects/gui/ui/timecontroldlg.ui
index bd7296c3..4f992dab 100644
--- a/projects/gui/ui/timecontroldlg.ui
+++ b/projects/gui/ui/timecontroldlg.ui
@@ -6,264 +6,111 @@
0
0
- 289
- 399
+ 610
+ 462
- Time Controls
+ Time Control
-
-
- QLayout::SetFixedSize
+
+
+
+ 20
+ 430
+ 281
+ 32
+
- -
-
-
- false
-
-
- Mode
-
-
- false
-
-
- false
-
-
- -
-
-
- Tournament time control
-
-
- Tournament
-
-
- true
-
-
-
- -
-
-
- Fixed time limit for each move
-
-
- Time per move
-
-
-
- -
-
-
- Infinite thinking time
-
-
- Infinite
-
-
-
- -
-
-
- Time used is added to opponent's available time
-
-
- Hourglass
-
-
-
-
-
-
- -
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
- -
-
-
- Moves:
-
-
- m_movesSpin
-
-
-
- -
-
-
- The number of moves in a time control
-
-
- Whole game
-
-
- 9999
-
-
- 0
-
-
-
- -
-
-
- Time:
-
-
- m_timeSpin
-
-
-
- -
-
- -
-
-
- Time limit for the chosen time control
-
-
- 2
-
-
- 0.010000000000000
-
-
- 10000.000000000000000
-
-
- 0.010000000000000
-
-
-
- -
-
-
- Time unit for the time limit
-
-
- 0
-
- -
-
- Seconds
-
-
- -
-
- Minutes
-
-
- -
-
- Hours
-
-
-
-
-
-
- -
-
-
- Increment:
-
-
- m_incrementSpin
-
-
-
- -
-
-
- Time increment per move in seconds
-
-
- sec
-
-
-
- -
-
-
- Maximum search depth in plies (engines only)
-
-
- 999
-
-
-
- -
-
-
- Plies:
-
-
- m_pliesSpin
-
-
-
- -
-
-
- Maximum number of nodes to search (engines only)
-
-
- 2147483647
-
-
-
- -
-
-
- Nodes:
-
-
- m_nodesSpin
-
-
-
- -
-
-
- The time limit can be exceeded by this many milliseconds
-
-
- ms
-
-
- 9999
-
-
-
- -
-
-
- Margin:
-
-
- m_marginSpin
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
-
-
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+ 20
+ 20
+ 282
+ 409
+
+
+
+ Select common or separate time controls
+
+
+ Both Sides
+
+
+ true
+
+
+ true
+
+
+
+
+ 0
+ 19
+ 281
+ 371
+
+
+
+
+
+
+ false
+
+
+
+ 310
+ 20
+ 291
+ 409
+
+
+
+ Time Control for 2nd Player
+
+
+ B&lack
+
+
+ false
+
+
+ false
+
+
+
+ false
+
+
+
+ 0
+ 20
+ 281
+ 371
+
+
+
+
+ m_timeControlGroupBoxBlack
+ buttonBox
+ m_timeControlGroupBoxWhite
+
+
+ TimeControlWidget
+ QWidget
+
+ 1
+
+
diff --git a/projects/gui/ui/timecontrolwidget.ui b/projects/gui/ui/timecontrolwidget.ui
new file mode 100644
index 00000000..5d122d44
--- /dev/null
+++ b/projects/gui/ui/timecontrolwidget.ui
@@ -0,0 +1,268 @@
+
+
+ TimeControlWidget
+
+
+
+ 0
+ 0
+ 291
+ 372
+
+
+
+ Form
+
+
+
+
+ 10
+ 10
+ 271
+ 157
+
+
+
+ false
+
+
+ Mode
+
+
+ false
+
+
+ false
+
+
+ -
+
+
+ Tournament time control
+
+
+ To&urnament
+
+
+ true
+
+
+
+ -
+
+
+ Fixed time limit for each move
+
+
+ Time &per move
+
+
+
+ -
+
+
+ Infinite thinking time
+
+
+ Infinite
+
+
+
+ -
+
+
+ Time used is added to opponent's available time
+
+
+ Hourglass
+
+
+
+
+
+
+
+
+ 10
+ 172
+ 271
+ 190
+
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+ -
+
+
+ Mo&ves:
+
+
+ m_movesSpin
+
+
+
+ -
+
+
+ The number of moves in a time control
+
+
+ Whole game
+
+
+ 9999
+
+
+ 0
+
+
+
+ -
+
+
+ Time:
+
+
+ m_timeSpin
+
+
+
+ -
+
+ -
+
+
+ Time limit for the chosen time control
+
+
+ 2
+
+
+ 0.010000000000000
+
+
+ 10000.000000000000000
+
+
+ 0.010000000000000
+
+
+
+ -
+
+
+ Time unit for the time limit
+
+
+ 0
+
+ -
+
+ Seconds
+
+
+ -
+
+ Minutes
+
+
+ -
+
+ Hours
+
+
+
+
+
+
+ -
+
+
+ In&crement:
+
+
+ m_incrementSpin
+
+
+
+ -
+
+
+ Time increment per move in seconds
+
+
+ sec
+
+
+
+ -
+
+
+ Maximum search depth in plies (engines only)
+
+
+ 999
+
+
+
+ -
+
+
+ P&lies:
+
+
+ m_pliesSpin
+
+
+
+ -
+
+
+ Maximum number of nodes to search (engines only)
+
+
+ 2147483647
+
+
+
+ -
+
+
+ Nodes:
+
+
+ m_nodesSpin
+
+
+
+ -
+
+
+ The time limit can be exceeded by this many milliseconds
+
+
+ ms
+
+
+ 9999
+
+
+
+ -
+
+
+ Mar&gin:
+
+
+ m_marginSpin
+
+
+
+
+
+
+
+
+
From ab0c9e1a2c2deac674a774e8c713ed5826f119c3 Mon Sep 17 00:00:00 2001
From: Ilari Pihlajisto
Date: Thu, 18 Jul 2024 17:28:29 +0300
Subject: [PATCH 17/30] GUI: re-design and re-factor for split time controls
---
CMakeLists.txt | 8 +-
projects/gui/res/icons/icons.qrc | 2 +
.../gui/res/icons/toolbutton/lock-closed.svg | 1 +
.../gui/res/icons/toolbutton/lock-open.svg | 1 +
projects/gui/src/gamesettingswidget.cpp | 85 ++--
projects/gui/src/gamesettingswidget.h | 9 +-
projects/gui/src/newgamedlg.cpp | 9 +-
projects/gui/src/newtournamentdialog.cpp | 4 +-
projects/gui/src/pairtimecontroldlg.cpp | 76 +++
projects/gui/src/pairtimecontroldlg.h | 63 +++
projects/gui/src/timecontroldlg.cpp | 57 +--
projects/gui/src/timecontroldlg.h | 31 +-
projects/gui/src/timecontrolwidget.cpp | 173 +++++--
projects/gui/src/timecontrolwidget.h | 40 +-
projects/gui/ui/pairtimecontroldlg.ui | 308 ++++++++++++
projects/gui/ui/timecontroldlg.ui | 110 +----
projects/gui/ui/timecontrolwidget.ui | 458 +++++++++---------
17 files changed, 950 insertions(+), 485 deletions(-)
create mode 100644 projects/gui/res/icons/toolbutton/lock-closed.svg
create mode 100644 projects/gui/res/icons/toolbutton/lock-open.svg
create mode 100644 projects/gui/src/pairtimecontroldlg.cpp
create mode 100644 projects/gui/src/pairtimecontroldlg.h
create mode 100644 projects/gui/ui/pairtimecontroldlg.ui
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cfed1c58..a20695c5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -254,12 +254,16 @@ add_executable(gui
projects/gui/src/gamedatabasemanager.cpp
projects/gui/src/pgndatabase.cpp
projects/gui/src/pathlineedit.cpp
- projects/gui/src/timecontroldlg.cpp
+ projects/gui/src/pairtimecontroldlg.cpp
+ projects/gui/src/timecontroldlg.cpp
+ projects/gui/src/timecontrolwidget.cpp
projects/gui/src/pgnimporter.cpp
projects/gui/ui/settingsdlg.ui
projects/gui/ui/engineconfigdlg.ui
- projects/gui/ui/timecontroldlg.ui
+ projects/gui/ui/pairtimecontroldlg.ui
+ projects/gui/ui/timecontroldlg.ui
+ projects/gui/ui/timecontrolwidget.ui
projects/gui/ui/engineselectiondlg.ui
projects/gui/ui/importprogressdlg.ui
projects/gui/ui/gamedatabasesearchdlg.ui
diff --git a/projects/gui/res/icons/icons.qrc b/projects/gui/res/icons/icons.qrc
index e366b615..3d59e2d5 100644
--- a/projects/gui/res/icons/icons.qrc
+++ b/projects/gui/res/icons/icons.qrc
@@ -15,5 +15,7 @@
toolbutton/next_16x16.png
toolbutton/previous_16x16.png
toolbutton/remove_16x16.png
+ toolbutton/lock-closed.svg
+ toolbutton/lock-open.svg
diff --git a/projects/gui/res/icons/toolbutton/lock-closed.svg b/projects/gui/res/icons/toolbutton/lock-closed.svg
new file mode 100644
index 00000000..a8318821
--- /dev/null
+++ b/projects/gui/res/icons/toolbutton/lock-closed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/projects/gui/res/icons/toolbutton/lock-open.svg b/projects/gui/res/icons/toolbutton/lock-open.svg
new file mode 100644
index 00000000..bcfcdf24
--- /dev/null
+++ b/projects/gui/res/icons/toolbutton/lock-open.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/projects/gui/src/gamesettingswidget.cpp b/projects/gui/src/gamesettingswidget.cpp
index 562b7d04..9a00e08c 100644
--- a/projects/gui/src/gamesettingswidget.cpp
+++ b/projects/gui/src/gamesettingswidget.cpp
@@ -27,8 +27,9 @@
#include
#include
#include "timecontroldlg.h"
+#include "pairtimecontroldlg.h"
-GameSettingsWidget::GameSettingsWidget(QWidget *parent)
+GameSettingsWidget::GameSettingsWidget(QWidget* parent)
: QWidget(parent),
ui(new Ui::GameSettingsWidget),
m_splitTimeControls(false),
@@ -45,12 +46,14 @@ GameSettingsWidget::GameSettingsWidget(QWidget *parent)
connect(ui->m_timeControlBtn, SIGNAL(clicked()),
this, SLOT(showTimeControlDialog()));
- m_timeControl.setMovesPerTc(40);
- m_timeControl.setTimePerTc(300000);
- m_timeControl2.setMovesPerTc(40);
- m_timeControl2.setTimePerTc(300000);
+ for (auto& tc : m_timeControl)
+ {
+ tc.setMovesPerTc(40);
+ tc.setTimePerTc(300000);
+ }
- ui->m_timeControlBtn->setText(m_timeControl.toVerboseString());
+ //ui->m_timeControlBtn->setText(m_timeControl.toVerboseString());
+ ui->m_timeControlBtn->setText(timeControlText());
connect(ui->m_browseOpeningSuiteBtn, &QPushButton::clicked, this, [=]()
{
@@ -128,14 +131,20 @@ QString GameSettingsWidget::chessVariant() const
return ui->m_variantCombo->currentText();
}
-TimeControl GameSettingsWidget::timeControl() const
+TimeControl GameSettingsWidget::timeControl(Chess::Side side) const
{
- return m_timeControl;
+ if (side == Chess::Side::NoSide)
+ side = Chess::Side::White;
+ return m_timeControl[side];
}
-TimeControl GameSettingsWidget::timeControl2() const
+QString GameSettingsWidget::timeControlText() const
{
- return m_timeControl2;
+ if (!m_splitTimeControls || m_timeControl[Chess::Side::White] == m_timeControl[Chess::Side::Black])
+ return m_timeControl[Chess::Side::White].toVerboseString();
+
+ return m_timeControl[Chess::Side::White].toVerboseString() + " vs " +
+ m_timeControl[Chess::Side::Black].toVerboseString();
}
bool GameSettingsWidget::pondering() const
@@ -239,10 +248,10 @@ void GameSettingsWidget::readSettings()
s.beginGroup("games");
ui->m_variantCombo->setCurrentText(s.value("variant").toString());
- m_timeControl.readSettings(&s);
+ m_timeControl[Chess::Side::White].readSettings(&s);
s.beginGroup("second_time_control");
- m_timeControl2.readSettings(&s);
+ m_timeControl[Chess::Side::Black].readSettings(&s);
s.endGroup(); // "second_time_control"
updateButtonText();
@@ -296,10 +305,10 @@ void GameSettingsWidget::enableSettingsUpdates()
{
QSettings s;
s.beginGroup("games");
- m_timeControl.writeSettings(&s);
+ m_timeControl[Chess::Side::White].writeSettings(&s);
s.beginGroup("second_time_control");
- m_timeControl2.writeSettings(&s);
+ m_timeControl[Chess::Side::Black].writeSettings(&s);
s.endGroup(); // "second_time_control"
s.endGroup(); // "games"
@@ -438,12 +447,7 @@ void GameSettingsWidget::validateFen(const QString& fen)
void GameSettingsWidget::updateButtonText()
{
- QString str(m_timeControl.toVerboseString());
-
- if (!(m_timeControl == m_timeControl2) && m_splitTimeControls)
- str += " vs " + m_timeControl2.toVerboseString();
-
- ui->m_timeControlBtn->setText(str);
+ ui->m_timeControlBtn->setText(timeControlText());
}
void GameSettingsWidget::enableSplitTimeControls(bool enable)
@@ -454,20 +458,37 @@ void GameSettingsWidget::enableSplitTimeControls(bool enable)
void GameSettingsWidget::showTimeControlDialog()
{
- TimeControlDialog dlg(m_timeControl,
- m_splitTimeControls ? m_timeControl2 : TimeControl());
+ bool accepted = false;
+
+ if (m_splitTimeControls)
+ {
+ PairTimeControlDialog dlg(m_timeControl[Chess::Side::White],
+ m_splitTimeControls ? m_timeControl[Chess::Side::Black] : TimeControl());
+ if (dlg.exec() == QDialog::Accepted)
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ auto side = Chess::Side::Type(i);
+ m_timeControl[side] = dlg.timeControl(side);
+ }
+ accepted = true;
+ }
+ } else {
+ TimeControlDialog dlg(m_timeControl[Chess::Side::White]);
+ if (dlg.exec() == QDialog::Accepted)
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ auto side = Chess::Side::Type(i);
+ m_timeControl[side] = dlg.timeControl();
+ }
+ accepted = true;
+ }
+ }
- if (dlg.exec() == QDialog::Accepted)
+ if (accepted)
{
- m_timeControl = dlg.timeControlWhite();
- m_timeControl2 = dlg.timeControlBlack();
- QString str(m_timeControl.toVerboseString());
-
- if (!(m_timeControl == m_timeControl2))
- str += " vs " + m_timeControl2.toVerboseString();
-
- ui->m_timeControlBtn->setText(str);
-
+ updateButtonText();
emit timeControlChanged();
}
}
diff --git a/projects/gui/src/gamesettingswidget.h b/projects/gui/src/gamesettingswidget.h
index e8014345..3bc0a13b 100644
--- a/projects/gui/src/gamesettingswidget.h
+++ b/projects/gui/src/gamesettingswidget.h
@@ -38,12 +38,11 @@ class GameSettingsWidget : public QWidget
Q_OBJECT
public:
- explicit GameSettingsWidget(QWidget *parent = nullptr);
+ explicit GameSettingsWidget(QWidget* parent = nullptr);
virtual ~GameSettingsWidget();
QString chessVariant() const;
- TimeControl timeControl() const;
- TimeControl timeControl2() const;
+ TimeControl timeControl(Chess::Side side = Chess::Side::NoSide) const;
bool pondering() const;
GameAdjudicator adjudicator() const;
OpeningSuite* openingSuite() const;
@@ -71,11 +70,11 @@ class GameSettingsWidget : public QWidget
private:
void readSettings();
void updateButtonText();
+ QString timeControlText() const;
Ui::GameSettingsWidget *ui;
bool m_splitTimeControls;
- TimeControl m_timeControl;
- TimeControl m_timeControl2;
+ TimeControl m_timeControl[2];
Chess::Board* m_board;
QPalette m_defaultPalette;
bool m_isValid;
diff --git a/projects/gui/src/newgamedlg.cpp b/projects/gui/src/newgamedlg.cpp
index edf8b3fc..df536cb5 100644
--- a/projects/gui/src/newgamedlg.cpp
+++ b/projects/gui/src/newgamedlg.cpp
@@ -33,7 +33,7 @@
#include "engineconfigurationmodel.h"
#include "engineconfigproxymodel.h"
#include "engineconfigurationdlg.h"
-#include "timecontroldlg.h"
+#include "pairtimecontroldlg.h"
#include "stringvalidator.h"
#if 0
@@ -113,8 +113,11 @@ ChessGame* NewGameDialog::createGame() const
pgn->setSite(QSettings().value("pgn/site").toString());
auto game = new ChessGame(board, pgn);
- game->setTimeControl(ui->m_gameSettings->timeControl(), Chess::Side::White);
- game->setTimeControl(ui->m_gameSettings->timeControl2(), Chess::Side::Black);
+ for (int i = 0; i < 2; i++)
+ {
+ auto side = Chess::Side::Type(i);
+ game->setTimeControl(ui->m_gameSettings->timeControl(side), side);
+ }
game->setAdjudicator(ui->m_gameSettings->adjudicator());
diff --git a/projects/gui/src/newtournamentdialog.cpp b/projects/gui/src/newtournamentdialog.cpp
index 8f601d84..2536c115 100644
--- a/projects/gui/src/newtournamentdialog.cpp
+++ b/projects/gui/src/newtournamentdialog.cpp
@@ -303,8 +303,8 @@ void NewTournamentDialog::onContextMenuRequest()
dlg->setWindowTitle(tr("Time Control - %0").arg(name));
if (dlg->exec() == QDialog::Accepted)
- for (QModelIndex index: selected)
- m_timeControls[index.row()] = dlg->timeControlWhite();
+ for (const QModelIndex& index: selected)
+ m_timeControls[index.row()] = dlg->timeControl();
delete dlg;
});
diff --git a/projects/gui/src/pairtimecontroldlg.cpp b/projects/gui/src/pairtimecontroldlg.cpp
new file mode 100644
index 00000000..b4a15d13
--- /dev/null
+++ b/projects/gui/src/pairtimecontroldlg.cpp
@@ -0,0 +1,76 @@
+/*
+ This file is part of Cute Chess.
+ Copyright (C) 2008-2018 Cute Chess authors
+
+ Cute Chess 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.
+
+ Cute Chess is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Cute Chess. If not, see .
+*/
+
+#include "pairtimecontroldlg.h"
+#include "ui_pairtimecontroldlg.h"
+
+PairTimeControlDialog::PairTimeControlDialog(const TimeControl& tc1, const TimeControl& tc2,
+ QWidget* parent)
+ : QDialog(parent), ui(new Ui::PairTimeControlDialog)
+{
+ ui->setupUi(this);
+
+ connect(ui->m_sameTc, &QToolButton::toggled, [=](bool checked)
+ {
+ if (checked)
+ syncTimeControls();
+ else
+ unsyncTimeControls();
+ });
+
+ if (!tc1.isValid())
+ return;
+
+ ui->m_timeControlWidgetWhite->init(tc1);
+ ui->m_timeControlWidgetBlack->init(tc2.isValid() ? tc2 : tc1);
+
+ const bool inSync = tc1 == tc2;
+ ui->m_sameTc->setChecked(inSync);
+
+ if (inSync)
+ syncTimeControls();
+}
+
+PairTimeControlDialog::~PairTimeControlDialog()
+{
+ delete ui;
+}
+
+void PairTimeControlDialog::syncTimeControls()
+{
+ // First, copy all settings from white to black
+ const auto whiteTc(ui->m_timeControlWidgetWhite->timeControl());
+ ui->m_timeControlWidgetBlack->init(whiteTc);
+
+ // Then, propagate all inputs from white to black and vice versa
+ ui->m_timeControlWidgetBlack->syncWith(ui->m_timeControlWidgetWhite);
+ ui->m_timeControlWidgetWhite->syncWith(ui->m_timeControlWidgetBlack);
+}
+
+void PairTimeControlDialog::unsyncTimeControls()
+{
+ ui->m_timeControlWidgetBlack->unsyncWith(ui->m_timeControlWidgetWhite);
+ ui->m_timeControlWidgetWhite->unsyncWith(ui->m_timeControlWidgetBlack);
+}
+
+TimeControl PairTimeControlDialog::timeControl(Chess::Side side) const
+{
+ if (side == Chess::Side::Black && ui->m_timeControlWidgetBlack->isEnabled())
+ return ui->m_timeControlWidgetBlack->timeControl();
+ return ui->m_timeControlWidgetWhite->timeControl();
+}
diff --git a/projects/gui/src/pairtimecontroldlg.h b/projects/gui/src/pairtimecontroldlg.h
new file mode 100644
index 00000000..4d41245c
--- /dev/null
+++ b/projects/gui/src/pairtimecontroldlg.h
@@ -0,0 +1,63 @@
+/*
+ This file is part of Cute Chess.
+ Copyright (C) 2008-2018 Cute Chess authors
+
+ Cute Chess 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.
+
+ Cute Chess is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Cute Chess. If not, see .
+*/
+
+#ifndef PAIRTIMECONTROLDIALOG_H
+#define PAIRTIMECONTROLDIALOG_H
+
+#include
+#include
+#include
+
+namespace Ui {
+ class PairTimeControlDialog;
+}
+
+/*!
+ * \brief A dialog for setting a chess game's time controls
+ */
+class PairTimeControlDialog : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ /*!
+ * Creates a new time control dialog for pairs (white and black)
+ *
+ * The dialog is initialized according to \a tcWhite,
+ * and \a tcBlack
+ */
+ explicit PairTimeControlDialog(const TimeControl& tcWhite,
+ const TimeControl& tcBlack = TimeControl(),
+ QWidget* parent = nullptr);
+ /*! Destroys the dialog. */
+ virtual ~PairTimeControlDialog();
+
+ /*!
+ * Returns the time control that was set in the dialog
+ * for the specified \a side.
+ */
+ TimeControl timeControl(Chess::Side side = Chess::Side::NoSide) const;
+
+ private:
+ void syncTimeControls();
+ void unsyncTimeControls();
+
+ Ui::PairTimeControlDialog *ui;
+};
+
+#endif // PAIRTIMECONTROLDIALOG_H
diff --git a/projects/gui/src/timecontroldlg.cpp b/projects/gui/src/timecontroldlg.cpp
index 09c17e2e..e82e140a 100644
--- a/projects/gui/src/timecontroldlg.cpp
+++ b/projects/gui/src/timecontroldlg.cpp
@@ -19,49 +19,17 @@
#include "timecontroldlg.h"
#include "ui_timecontroldlg.h"
-TimeControlDialog::TimeControlDialog(const TimeControl& tc1,
- const TimeControl& tc2,
- QWidget *parent)
- : QDialog(parent),
- ui(new Ui::TimeControlDialog)
+TimeControlDialog::TimeControlDialog(const TimeControl& tc,
+ QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::TimeControlDialog)
{
ui->setupUi(this);
- // If tc2 has default value then use a simplified dialog
- if (tc2 == TimeControl())
- {
- ui->m_timeControlGroupBoxBlack->setEnabled(false);
- ui->m_timeControlGroupBoxWhite->setCheckable(false);
- }
-
- ui->m_timeControlGroupBoxBlack->setVisible(false);
- adjustSize();
-
- connect(ui->m_timeControlGroupBoxWhite, &QGroupBox::toggled, [=](bool checked)
- {
- ui->m_timeControlWidgetWhite->setEnabled(true);
- ui->m_timeControlGroupBoxBlack->setEnabled(!checked);
- ui->m_timeControlGroupBoxBlack->setVisible(!checked);
- ui->m_timeControlWidgetBlack->setEnabled(!checked);
-
- ui->m_timeControlGroupBoxWhite->setTitle(checked ? tr("Both Sides")
- : tr("White"));
- adjustSize();
- });
-
- if (!tc1.isValid())
+ if (!tc.isValid())
return;
- ui->m_timeControlWidgetWhite->init(tc1);
- ui->m_timeControlWidgetBlack->init(tc2.isValid() ? tc2 : tc1);
-
- ui->m_timeControlGroupBoxWhite->setChecked(tc1 == tc2 || !tc2.isValid());
- ui->m_timeControlWidgetBlack->disableHourglassRadio();
-
- connect (ui->m_timeControlWidgetWhite, SIGNAL(hourglassToggled(bool)),
- ui->m_timeControlWidgetBlack, SLOT(setHourglassMode(bool)));
-
- ui->m_timeControlWidgetBlack->setHourglassMode(tc1.isHourglass());
+ ui->m_timeControlWidget->init(tc);
}
TimeControlDialog::~TimeControlDialog()
@@ -69,16 +37,7 @@ TimeControlDialog::~TimeControlDialog()
delete ui;
}
-TimeControl TimeControlDialog::timeControlWhite() const
+TimeControl TimeControlDialog::timeControl() const
{
- return ui->m_timeControlWidgetWhite->timeControl();
+ return ui->m_timeControlWidget->timeControl();
}
-
-TimeControl TimeControlDialog::timeControlBlack() const
-{
- if (ui->m_timeControlWidgetBlack->isEnabled())
- return ui->m_timeControlWidgetBlack->timeControl();
- else
- return ui->m_timeControlWidgetWhite->timeControl();
-}
-
diff --git a/projects/gui/src/timecontroldlg.h b/projects/gui/src/timecontroldlg.h
index ff1135cb..a92cd172 100644
--- a/projects/gui/src/timecontroldlg.h
+++ b/projects/gui/src/timecontroldlg.h
@@ -16,8 +16,8 @@
along with Cute Chess. If not, see .
*/
-#ifndef TIMECONTROLDIALOG_H
-#define TIMECONTROLDIALOG_H
+#ifndef TIMECONTROLDLG_H
+#define TIMECONTROLDLG_H
#include
#include
@@ -27,31 +27,24 @@ namespace Ui {
}
/*!
- * \brief A dialog for setting a chess game's time controls
+ * \brief A dialog for setting a chess player's, or tournament's time controls
*/
class TimeControlDialog : public QDialog
{
Q_OBJECT
public:
- /*!
- * Creates a new time control dialog.
- *
- * The dialog is initialized according to \a tc1,
- * and \a tc2
- */
- explicit TimeControlDialog(const TimeControl& tc1,
- const TimeControl& tc2 = TimeControl(),
- QWidget* parent = nullptr);
- /*! Destroys the dialog. */
- virtual ~TimeControlDialog();
-
- /*! Returns the time control that was set in the dialog. */
- TimeControl timeControlWhite() const;
- TimeControl timeControlBlack() const;
+ /*! Creates a new time control dialog */
+ explicit TimeControlDialog(const TimeControl& tc,
+ QWidget *parent = nullptr);
+ /*! Destroys the dialog */
+ ~TimeControlDialog();
+
+ /*! Returns the time control that was set in the dialog */
+ TimeControl timeControl() const;
private:
Ui::TimeControlDialog *ui;
};
-#endif // TIMECONTROLDIALOG_H
+#endif // TIMECONTROLDLG_H
diff --git a/projects/gui/src/timecontrolwidget.cpp b/projects/gui/src/timecontrolwidget.cpp
index a54faac8..fd3419c4 100644
--- a/projects/gui/src/timecontrolwidget.cpp
+++ b/projects/gui/src/timecontrolwidget.cpp
@@ -20,45 +20,56 @@
#include "ui_timecontrolwidget.h"
-TimeControlWidget::TimeControlWidget(QWidget *parent)
+TimeControlWidget::TimeControlWidget(QWidget* parent)
: QWidget(parent),
- ui(new Ui::TimeControlWidget)
+ ui(new Ui::TimeControlWidget),
+ m_tcMode(Tournament)
{
ui->setupUi(this);
+
+ connect(ui->m_tournamentRadio, &QRadioButton::toggled, [=](bool checked)
+ {
+ if (checked)
+ setTimeControlMode(Tournament);
+ });
+ connect(ui->m_timePerMoveRadio, &QRadioButton::toggled, [=](bool checked)
+ {
+ if (checked)
+ setTimeControlMode(TimePerMove);
+ });
+ connect(ui->m_infiniteRadio, &QRadioButton::toggled, [=](bool checked)
+ {
+ if (checked)
+ setTimeControlMode(Infinite);
+ });
+ connect(ui->m_hourglassRadio, &QRadioButton::toggled, [=](bool checked)
+ {
+ if (checked)
+ setTimeControlMode(Hourglass);
+ });
}
void TimeControlWidget::init(const TimeControl& tc)
{
- connect(ui->m_tournamentRadio, SIGNAL(clicked()),
- this, SLOT(onTournamentSelected()));
- connect(ui->m_timePerMoveRadio, SIGNAL(clicked()),
- this, SLOT(onTimePerMoveSelected()));
- connect(ui->m_infiniteRadio, SIGNAL(clicked()),
- this, SLOT(onInfiniteSelected()));
- connect(ui->m_hourglassRadio, SIGNAL(clicked()),
- this, SLOT(onHourglassSelected()));
- connect(ui->m_hourglassRadio, SIGNAL(toggled(bool)),
- this, SIGNAL(hourglassToggled(bool)));
-
if (!tc.isValid())
return;
if (tc.isInfinite())
{
ui->m_infiniteRadio->setChecked(true);
- onInfiniteSelected();
+ setTimeControlMode(Infinite);
}
else if (tc.isHourglass())
{
ui->m_hourglassRadio->setChecked(true);
setTime(tc.timePerTc());
- onHourglassSelected();
+ setTimeControlMode(Hourglass);
}
else if (tc.timePerMove() != 0)
{
ui->m_timePerMoveRadio->setChecked(true);
setTime(tc.timePerMove());
- onTimePerMoveSelected();
+ setTimeControlMode(TimePerMove);
}
else
{
@@ -66,7 +77,7 @@ void TimeControlWidget::init(const TimeControl& tc)
ui->m_movesSpin->setValue(tc.movesPerTc());
ui->m_incrementSpin->setValue(double(tc.timeIncrement()) / 1000.0);
setTime(tc.timePerTc());
- onTournamentSelected();
+ setTimeControlMode(Tournament);
}
ui->m_nodesSpin->setValue(tc.nodeLimit());
@@ -79,6 +90,111 @@ TimeControlWidget::~TimeControlWidget()
delete ui;
}
+void TimeControlWidget::syncWith(TimeControlWidget* other)
+{
+ disconnect(other, &TimeControlWidget::timeControlModeChanged,
+ this, &TimeControlWidget::onOtherTimeControlModeChanged);
+
+ connect(other->ui->m_tournamentRadio, &QRadioButton::toggled,
+ this->ui->m_tournamentRadio, &QRadioButton::setChecked);
+ connect(other->ui->m_timePerMoveRadio, &QRadioButton::toggled,
+ this->ui->m_timePerMoveRadio, &QRadioButton::setChecked);
+ connect(other->ui->m_infiniteRadio, &QRadioButton::toggled,
+ this->ui->m_infiniteRadio, &QRadioButton::setChecked);
+ connect(other->ui->m_hourglassRadio, &QRadioButton::toggled,
+ this->ui->m_hourglassRadio, &QRadioButton::setChecked);
+ connect(other->ui->m_movesSpin, static_cast(&QSpinBox::valueChanged),
+ this->ui->m_movesSpin, &QSpinBox::setValue);
+ connect(other->ui->m_timeSpin, static_cast(&QDoubleSpinBox::valueChanged),
+ this->ui->m_timeSpin, &QDoubleSpinBox::setValue);
+ connect(other->ui->m_timeUnitCombo, static_cast(&QComboBox::currentIndexChanged),
+ this->ui->m_timeUnitCombo, &QComboBox::setCurrentIndex);
+ connect(other->ui->m_incrementSpin, static_cast(&QDoubleSpinBox::valueChanged),
+ this->ui->m_incrementSpin, &QDoubleSpinBox::setValue);
+ connect(other->ui->m_nodesSpin, static_cast(&QSpinBox::valueChanged),
+ this->ui->m_nodesSpin, &QSpinBox::setValue);
+ connect(other->ui->m_pliesSpin, static_cast(&QSpinBox::valueChanged),
+ this->ui->m_pliesSpin, &QSpinBox::setValue);
+ connect(other->ui->m_marginSpin, static_cast(&QSpinBox::valueChanged),
+ this->ui->m_marginSpin, &QSpinBox::setValue);
+}
+
+void TimeControlWidget::unsyncWith(TimeControlWidget* other)
+{
+ disconnect(other->ui->m_tournamentRadio, &QRadioButton::toggled,
+ this->ui->m_tournamentRadio, &QRadioButton::setChecked);
+ disconnect(other->ui->m_timePerMoveRadio, &QRadioButton::toggled,
+ this->ui->m_timePerMoveRadio, &QRadioButton::setChecked);
+ disconnect(other->ui->m_infiniteRadio, &QRadioButton::toggled,
+ this->ui->m_infiniteRadio, &QRadioButton::setChecked);
+ disconnect(other->ui->m_hourglassRadio, &QRadioButton::toggled,
+ this->ui->m_hourglassRadio, &QRadioButton::setChecked);
+ disconnect(other->ui->m_movesSpin, static_cast(&QSpinBox::valueChanged),
+ this->ui->m_movesSpin, &QSpinBox::setValue);
+ disconnect(other->ui->m_timeSpin, static_cast(&QDoubleSpinBox::valueChanged),
+ this->ui->m_timeSpin, &QDoubleSpinBox::setValue);
+ disconnect(other->ui->m_timeUnitCombo, static_cast(&QComboBox::currentIndexChanged),
+ this->ui->m_timeUnitCombo, &QComboBox::setCurrentIndex);
+ disconnect(other->ui->m_incrementSpin, static_cast(&QDoubleSpinBox::valueChanged),
+ this->ui->m_incrementSpin, &QDoubleSpinBox::setValue);
+ disconnect(other->ui->m_nodesSpin, static_cast(&QSpinBox::valueChanged),
+ this->ui->m_nodesSpin, &QSpinBox::setValue);
+ disconnect(other->ui->m_pliesSpin, static_cast(&QSpinBox::valueChanged),
+ this->ui->m_pliesSpin, &QSpinBox::setValue);
+ disconnect(other->ui->m_marginSpin, static_cast(&QSpinBox::valueChanged),
+ this->ui->m_marginSpin, &QSpinBox::setValue);
+
+ connect(other, &TimeControlWidget::timeControlModeChanged,
+ this, &TimeControlWidget::onOtherTimeControlModeChanged);
+}
+
+void TimeControlWidget::onOtherTimeControlModeChanged(Mode mode)
+{
+ if (mode == Hourglass || m_tcMode == Hourglass)
+ {
+ switch (mode)
+ {
+ case Tournament:
+ ui->m_tournamentRadio->setChecked(true);
+ break;
+ case TimePerMove:
+ ui->m_timePerMoveRadio->setChecked(true);
+ break;
+ case Infinite:
+ ui->m_infiniteRadio->setChecked(true);
+ break;
+ case Hourglass:
+ ui->m_hourglassRadio->setChecked(true);
+ break;
+ }
+ }
+}
+
+void TimeControlWidget::setTimeControlMode(Mode mode)
+{
+ if (m_tcMode == mode)
+ return;
+
+ switch (mode)
+ {
+ case Tournament:
+ onTournamentSelected();
+ break;
+ case TimePerMove:
+ onTimePerMoveSelected();
+ break;
+ case Infinite:
+ onInfiniteSelected();
+ break;
+ case Hourglass:
+ onHourglassSelected();
+ break;
+ }
+
+ m_tcMode = mode;
+ emit timeControlModeChanged(mode);
+}
+
void TimeControlWidget::onTournamentSelected()
{
ui->m_movesSpin->setEnabled(true);
@@ -115,29 +231,6 @@ void TimeControlWidget::onHourglassSelected()
ui->m_marginSpin->setEnabled(true);
}
-void TimeControlWidget::setHourglassMode(bool enabled)
-{
- ui->m_groupBox->setEnabled(!enabled);
-
- if (enabled)
- {
- ui->m_hourglassRadio->setChecked(true);
- onHourglassSelected();
- }
- else
- {
- ui->m_tournamentRadio->setChecked(true);
- onTournamentSelected();
- }
-}
-
-void TimeControlWidget::disableHourglassRadio()
-{
- ui->m_hourglassRadio->setEnabled(false);
- if (ui->m_hourglassRadio->isChecked())
- ui->m_groupBox->setEnabled(false);
-}
-
int TimeControlWidget::timeToMs() const
{
switch (ui->m_timeUnitCombo->currentIndex())
diff --git a/projects/gui/src/timecontrolwidget.h b/projects/gui/src/timecontrolwidget.h
index 1dfa0e20..ec22a7b2 100644
--- a/projects/gui/src/timecontrolwidget.h
+++ b/projects/gui/src/timecontrolwidget.h
@@ -39,28 +39,55 @@ class TimeControlWidget : public QWidget
*
* The widget is initialized according to \a tc.
*/
- explicit TimeControlWidget(QWidget *parent = nullptr);
+ explicit TimeControlWidget(QWidget* parent = nullptr);
+
/*! Destroys the dialog. */
virtual ~TimeControlWidget();
+ /*! Time control mode */
+ enum Mode
+ {
+ Tournament, //!< Tournament time controls, e.g. 1h per 40 moves
+ TimePerMove, //!< Same amount of time for each move
+ Infinite, //!< Infinite thinking time
+ Hourglass //!< Player B's time left goes up as A's goes down
+ };
+ Q_ENUM(Mode)
+
/*! Initialise time contol, signals and slots */
void init(const TimeControl& tc);
+
/*! Returns the time control that was set in the dialog. */
TimeControl timeControl() const;
- signals:
- void hourglassToggled(bool);
+ /*!
+ * Starts propagating all inputs from \a other to this widget.
+ *
+ * \note The current state of \a other is NOT automatically
+ * copied to this widget.
+ */
+ void syncWith(TimeControlWidget* other);
+
+ /*! Stops propagating inputs from \a other to this widget. */
+ void unsyncWith(TimeControlWidget* other);
- public slots: void setHourglassMode(bool enabled);
- void disableHourglassRadio();
+ public slots:
+ /*! Sets the time control mode to \a mode. */
+ void setTimeControlMode(Mode mode);
+
+ signals:
+ /*! Emitted when the time control mode changes. */
+ void timeControlModeChanged(Mode mode);
private slots:
+ void onOtherTimeControlModeChanged(Mode mode);
+
+ private:
void onTournamentSelected();
void onTimePerMoveSelected();
void onInfiniteSelected();
void onHourglassSelected();
- private:
enum TimeUnit
{
Seconds,
@@ -73,6 +100,7 @@ class TimeControlWidget : public QWidget
Ui::TimeControlWidget *ui;
TimeControl m_tc;
+ Mode m_tcMode;
};
#endif // TIMECONTROLWIDGET_H
diff --git a/projects/gui/ui/pairtimecontroldlg.ui b/projects/gui/ui/pairtimecontroldlg.ui
new file mode 100644
index 00000000..cc51a82a
--- /dev/null
+++ b/projects/gui/ui/pairtimecontroldlg.ui
@@ -0,0 +1,308 @@
+
+
+ PairTimeControlDialog
+
+
+
+ 0
+ 0
+ 417
+ 343
+
+
+
+ Time Control
+
+
+ -
+
+
+ QLayout::SetDefaultConstraint
+
+ -
+
+
+ Link/unlink white's and black's time controls
+
+
+
+ :/icons/toolbutton/lock-open.svg
+ :/icons/toolbutton/lock-closed.svg :/icons/toolbutton/lock-open.svg
+
+
+
+ 24
+ 24
+
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
+ 0
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+ 0
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame {
+ border-top: 2px solid;
+ border-left: 2px solid;
+ border-right: 0px;
+ border-bottom: 0px;
+}
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Plain
+
+
+ 2
+
+
+
+
+
+
+
+ -
+
+
+ Time Control for 2nd Player
+
+
+ Black
+
+
+ false
+
+
+ false
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+
+
+ -
+
+
+ Select common or separate time controls
+
+
+ White
+
+
+ false
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+
+
+ -
+
+
+ 0
+
+ -
+
+
+ 0
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame {
+ border-top: 2px solid;
+ border-left: 0px;
+ border-right: 2px solid;
+ border-bottom: 0px;
+}
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Plain
+
+
+ 2
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+ TimeControlWidget
+ QWidget
+
+ 1
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ PairTimeControlDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ PairTimeControlDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/projects/gui/ui/timecontroldlg.ui b/projects/gui/ui/timecontroldlg.ui
index 4f992dab..ee200a5e 100644
--- a/projects/gui/ui/timecontroldlg.ui
+++ b/projects/gui/ui/timecontroldlg.ui
@@ -6,108 +6,34 @@
0
0
- 610
- 462
+ 400
+ 300
Time Control
-
-
-
- 20
- 430
- 281
- 32
-
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
-
-
-
- 20
- 20
- 282
- 409
-
-
-
- Select common or separate time controls
-
-
- Both Sides
-
-
- true
-
-
- true
-
-
-
-
- 0
- 19
- 281
- 371
-
-
-
-
-
-
- false
-
-
-
- 310
- 20
- 291
- 409
-
-
-
- Time Control for 2nd Player
-
-
- B&lack
-
-
- false
-
-
- false
-
-
-
- false
-
-
-
- 0
- 20
- 281
- 371
-
-
-
-
- m_timeControlGroupBoxBlack
- buttonBox
- m_timeControlGroupBoxWhite
+
+ -
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
TimeControlWidget
QWidget
-
+
1
diff --git a/projects/gui/ui/timecontrolwidget.ui b/projects/gui/ui/timecontrolwidget.ui
index 5d122d44..a4026858 100644
--- a/projects/gui/ui/timecontrolwidget.ui
+++ b/projects/gui/ui/timecontrolwidget.ui
@@ -6,262 +6,250 @@
0
0
- 291
- 372
+ 338
+ 429
Form
-
-
-
- 10
- 10
- 271
- 157
-
-
-
- false
-
-
- Mode
-
-
- false
-
-
- false
-
-
- -
-
-
- Tournament time control
-
-
- To&urnament
-
-
- true
-
-
-
- -
-
-
- Fixed time limit for each move
-
-
- Time &per move
-
-
-
- -
-
-
- Infinite thinking time
-
-
- Infinite
-
-
-
- -
-
-
- Time used is added to opponent's available time
-
-
- Hourglass
-
-
-
-
-
-
-
-
- 10
- 172
- 271
- 190
-
-
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
- -
-
-
- Mo&ves:
-
-
- m_movesSpin
-
-
-
- -
-
-
- The number of moves in a time control
-
-
- Whole game
-
-
- 9999
-
-
- 0
-
-
-
- -
-
-
- Time:
-
-
- m_timeSpin
-
-
-
- -
-
+
+ -
+
+
+ false
+
+
+ Mode
+
+
+ false
+
+
+ false
+
+
-
-
+
- Time limit for the chosen time control
+ Tournament time control
-
- 2
+
+ To&urnament
-
- 0.010000000000000
+
+ true
-
- 10000.000000000000000
+
+
+ -
+
+
+ Fixed time limit for each move
-
- 0.010000000000000
+
+ Time &per move
-
-
+
- Time unit for the time limit
+ Infinite thinking time
-
- 0
+
+ Infinite
+
+
+
+ -
+
+
+ Time used is added to opponent's available time
+
+
+ Hourglass
- -
-
- Seconds
-
-
- -
-
- Minutes
-
-
- -
-
- Hours
-
-
-
- -
-
-
- In&crement:
-
-
- m_incrementSpin
-
-
-
- -
-
-
- Time increment per move in seconds
-
-
- sec
-
-
-
- -
-
-
- Maximum search depth in plies (engines only)
-
-
- 999
-
-
-
- -
-
-
- P&lies:
-
-
- m_pliesSpin
-
-
-
- -
-
-
- Maximum number of nodes to search (engines only)
-
-
- 2147483647
-
-
-
- -
-
-
- Nodes:
-
-
- m_nodesSpin
-
-
-
- -
-
-
- The time limit can be exceeded by this many milliseconds
-
-
- ms
-
-
- 9999
-
-
-
- -
-
-
- Mar&gin:
-
-
- m_marginSpin
-
-
-
-
-
+
+
+ -
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+ -
+
+
+ Mo&ves:
+
+
+ m_movesSpin
+
+
+
+ -
+
+
+ The number of moves in a time control
+
+
+ Whole game
+
+
+ 9999
+
+
+ 0
+
+
+
+ -
+
+
+ Time:
+
+
+ m_timeSpin
+
+
+
+ -
+
+ -
+
+
+ Time limit for the chosen time control
+
+
+ 2
+
+
+ 0.010000000000000
+
+
+ 10000.000000000000000
+
+
+ 0.010000000000000
+
+
+
+ -
+
+
+ Time unit for the time limit
+
+
+ 0
+
+ -
+
+ Seconds
+
+
+ -
+
+ Minutes
+
+
+ -
+
+ Hours
+
+
+
+
+
+
+ -
+
+
+ In&crement:
+
+
+ m_incrementSpin
+
+
+
+ -
+
+
+ Time increment per move in seconds
+
+
+ sec
+
+
+
+ -
+
+
+ Maximum search depth in plies (engines only)
+
+
+ 999
+
+
+
+ -
+
+
+ P&lies:
+
+
+ m_pliesSpin
+
+
+
+ -
+
+
+ Maximum number of nodes to search (engines only)
+
+
+ 2147483647
+
+
+
+ -
+
+
+ Nodes:
+
+
+ m_nodesSpin
+
+
+
+ -
+
+
+ The time limit can be exceeded by this many milliseconds
+
+
+ ms
+
+
+ 9999
+
+
+
+ -
+
+
+ Mar&gin:
+
+
+ m_marginSpin
+
+
+
+
+
+
From 34893eb4291ec7baa161ab0a85a48e3c8e09ee40 Mon Sep 17 00:00:00 2001
From: Ilari Pihlajisto
Date: Sun, 21 Jul 2024 10:36:06 +0300
Subject: [PATCH 18/30] fix compiler warning about writing to a region of size
0
---
projects/gui/src/newtournamentdialog.cpp | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/projects/gui/src/newtournamentdialog.cpp b/projects/gui/src/newtournamentdialog.cpp
index 2536c115..8becb045 100644
--- a/projects/gui/src/newtournamentdialog.cpp
+++ b/projects/gui/src/newtournamentdialog.cpp
@@ -21,7 +21,6 @@
#include
#include
#include
-#include
#include
#include
@@ -215,17 +214,31 @@ void NewTournamentDialog::configureEngine(const QModelIndex& index)
void NewTournamentDialog::moveEngine(int offset)
{
+ if (offset == 0)
+ return;
+
QModelIndex index(ui->m_playersList->currentIndex());
int row1 = index.row();
int row2 = row1 + offset;
- EngineConfiguration tmp(m_addedEnginesManager->engineAt(row1));
- TimeControl tc = m_timeControls.at(row1);
+ // It should be impossible for either row to be out of bounds,
+ // but we'll check it explicitly, which makes the compiler happy.
+ if (row1 < 0 || row1 >= m_timeControls.size())
+ {
+ qWarning("row1 out of bounds");
+ return;
+ }
+ if (row2 < 0 || row2 >= m_timeControls.size())
+ {
+ qWarning("row2 out of bounds");
+ return;
+ }
+
+ EngineConfiguration tmp(m_addedEnginesManager->engineAt(row1));
m_addedEnginesManager->updateEngineAt(row1, m_addedEnginesManager->engineAt(row2));
m_addedEnginesManager->updateEngineAt(row2, tmp);
- m_timeControls[row1] = m_timeControls.at(row2);
- m_timeControls[row2]= tc;
+ m_timeControls.swapItemsAt(row1, row2);
ui->m_playersList->setCurrentIndex(index.sibling(row2, 0));
}
From 456f99f3611b14050483cd030b64d1a5de440028 Mon Sep 17 00:00:00 2001
From: Ilari Pihlajisto
Date: Sun, 21 Jul 2024 11:40:10 +0300
Subject: [PATCH 19/30] fix modal dialog issues with time control dialogs
---
projects/gui/src/gamesettingswidget.cpp | 6 ++++--
projects/gui/src/newtournamentdialog.cpp | 2 +-
projects/gui/ui/pairtimecontroldlg.ui | 5 ++++-
projects/gui/ui/timecontroldlg.ui | 3 +++
4 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/projects/gui/src/gamesettingswidget.cpp b/projects/gui/src/gamesettingswidget.cpp
index 9a00e08c..beb1f8fa 100644
--- a/projects/gui/src/gamesettingswidget.cpp
+++ b/projects/gui/src/gamesettingswidget.cpp
@@ -463,7 +463,8 @@ void GameSettingsWidget::showTimeControlDialog()
if (m_splitTimeControls)
{
PairTimeControlDialog dlg(m_timeControl[Chess::Side::White],
- m_splitTimeControls ? m_timeControl[Chess::Side::Black] : TimeControl());
+ m_splitTimeControls ? m_timeControl[Chess::Side::Black] : TimeControl(),
+ this->parentWidget());
if (dlg.exec() == QDialog::Accepted)
{
for (int i = 0; i < 2; i++)
@@ -474,7 +475,8 @@ void GameSettingsWidget::showTimeControlDialog()
accepted = true;
}
} else {
- TimeControlDialog dlg(m_timeControl[Chess::Side::White]);
+ TimeControlDialog dlg(m_timeControl[Chess::Side::White],
+ this->parentWidget());
if (dlg.exec() == QDialog::Accepted)
{
for (int i = 0; i < 2; i++)
diff --git a/projects/gui/src/newtournamentdialog.cpp b/projects/gui/src/newtournamentdialog.cpp
index 8becb045..75c2a15f 100644
--- a/projects/gui/src/newtournamentdialog.cpp
+++ b/projects/gui/src/newtournamentdialog.cpp
@@ -309,7 +309,7 @@ void NewTournamentDialog::onContextMenuRequest()
if (!tc.isValid())
tc = ui->m_gameSettings->timeControl();
- auto dlg = new TimeControlDialog(tc);
+ auto dlg = new TimeControlDialog(tc, this);
QString name {m_addedEnginesManager->engines().at(i).name()};
if (selected.count() > 1)
name.append(tr(" - %0 engines").arg(selected.count()));
diff --git a/projects/gui/ui/pairtimecontroldlg.ui b/projects/gui/ui/pairtimecontroldlg.ui
index cc51a82a..c6817ab2 100644
--- a/projects/gui/ui/pairtimecontroldlg.ui
+++ b/projects/gui/ui/pairtimecontroldlg.ui
@@ -11,9 +11,12 @@
- Time Control
+ Time Controls
+
+ QLayout::SetFixedSize
+
-
diff --git a/projects/gui/ui/timecontroldlg.ui b/projects/gui/ui/timecontroldlg.ui
index ee200a5e..eb837fd4 100644
--- a/projects/gui/ui/timecontroldlg.ui
+++ b/projects/gui/ui/timecontroldlg.ui
@@ -14,6 +14,9 @@
Time Control
+
+ QLayout::SetFixedSize
+
-
From 7af9b8542743616676211dac701d2d65a15c2342 Mon Sep 17 00:00:00 2001
From: Ilari Pihlajisto
Date: Sun, 21 Jul 2024 11:57:46 +0300
Subject: [PATCH 20/30] remove commented-out code, plus formatting fix
---
projects/gui/src/gamesettingswidget.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/projects/gui/src/gamesettingswidget.cpp b/projects/gui/src/gamesettingswidget.cpp
index beb1f8fa..c30ba499 100644
--- a/projects/gui/src/gamesettingswidget.cpp
+++ b/projects/gui/src/gamesettingswidget.cpp
@@ -52,7 +52,6 @@ GameSettingsWidget::GameSettingsWidget(QWidget* parent)
tc.setTimePerTc(300000);
}
- //ui->m_timeControlBtn->setText(m_timeControl.toVerboseString());
ui->m_timeControlBtn->setText(timeControlText());
connect(ui->m_browseOpeningSuiteBtn, &QPushButton::clicked, this, [=]()
@@ -474,7 +473,9 @@ void GameSettingsWidget::showTimeControlDialog()
}
accepted = true;
}
- } else {
+ }
+ else
+ {
TimeControlDialog dlg(m_timeControl[Chess::Side::White],
this->parentWidget());
if (dlg.exec() == QDialog::Accepted)
From 704f5d163dd0b75bd80c29c63f427ba8305f7612 Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Sun, 21 Jul 2024 12:23:06 +0300
Subject: [PATCH 21/30] update changelog
Remove the entry about MacOS CI since it has very little relevance for
end-users.
---
CHANGELOG.md | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a7898e1f..c91d6ba9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## Unreleased
+### Added
+
+- Players can have separate time controls (#806)
+
### Fixed
- Cute Chess specific CodeQL static analysis queries have been re-enabled (#798)
@@ -12,7 +16,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed
- Windows releases are now built with Qt 6 (#802)
-- Limit the CI build for the latest MacOS version to Qt 6 only (#799)
## [1.3.1](https://github.com/cutechess/cutechess/releases/tag/v1.3.1) - 2023-07-30
From 25e1aa88b0d8814459b053d920ca0d7c9dc6b14d Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Sun, 21 Jul 2024 12:32:54 +0300
Subject: [PATCH 22/30] version 1.4.0-beta1
---
.version | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.version b/.version
index 1bde121c..ee041bdc 100644
--- a/.version
+++ b/.version
@@ -1 +1 @@
-1.3.2-beta3
\ No newline at end of file
+1.4.0-beta1
\ No newline at end of file
From 53adf5be0795cfa0e4178540e5dc06e82e57a63c Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Sun, 21 Jul 2024 15:47:01 +0300
Subject: [PATCH 23/30] deploy SVG DLLs with the Windows release
---
.github/workflows/release.yml | 5 +++++
dist/windows_setup.iss | 2 ++
2 files changed, 7 insertions(+)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 88167d95..0215dac5 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -132,6 +132,11 @@ jobs:
cp "$env:Qt6_Dir\plugins\platforms\qwindows.dll" platforms\
mkdir styles
cp "$env:Qt6_Dir\plugins\styles\qmodernwindowsstyle.dll" styles\
+ mkdir plugins
+ mkdir plugins\iconengines
+ cp "$env:Qt6_Dir\plugins\iconengines\qsvgicon.dll" plugins\iconengines
+ mkdir plugins\imageformats
+ cp "$env:Qt6_Dir\plugins\imageformats\qsvg.dll" plugins\imageformats
cd ..
7z a cutechess-$env:VERSION-win64.zip cutechess-$env:VERSION-win64\
diff --git a/dist/windows_setup.iss b/dist/windows_setup.iss
index 386eaa43..f227f82e 100644
--- a/dist/windows_setup.iss
+++ b/dist/windows_setup.iss
@@ -58,6 +58,8 @@ Source: "{#QtLibPath}\bin\Qt6Concurrent.dll"; DestDir: "{app}"; Flags: ignorever
Source: "{#QtLibPath}\bin\Qt6Core5Compat.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#QtLibPath}\plugins\platforms\qwindows.dll"; DestDir: "{app}\platforms"; Flags: ignoreversion
Source: "{#QtLibPath}\plugins\styles\qmodernwindowsstyle.dll"; DestDir: "{app}\styles"; Flags: ignoreversion
+Source: "{#QtLibPath}\plugins\iconengines\qsvgicon.dll"; DestDir: "{app}\plugins\iconengines"; Flags: ignoreversion
+Source: "{#QtLibPath}\plugins\imageformats\qsvg.dll"; DestDir: "{app}\plugins\imageformats"; Flags: ignoreversion
Source: "{#CuteChessPath}\COPYING"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#CuteChessPath}\docs\cutechess-cli.6.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#CuteChessPath}\docs\cutechess-cli.6.html"; DestDir: "{app}"; Flags: ignoreversion
From 8bf6bcde94c480ffb6aa3e57c6b1f4afa7c7bfb8 Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Sun, 21 Jul 2024 15:48:06 +0300
Subject: [PATCH 24/30] version 1.4.0-beta2
---
.version | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.version b/.version
index ee041bdc..9ce2de56 100644
--- a/.version
+++ b/.version
@@ -1 +1 @@
-1.4.0-beta1
\ No newline at end of file
+1.4.0-beta2
\ No newline at end of file
From ae6c93922fe054e5bff0688293ad8e33f7684996 Mon Sep 17 00:00:00 2001
From: Ilari Pihlajisto
Date: Sun, 21 Jul 2024 16:19:41 +0300
Subject: [PATCH 25/30] fix crash when tournament game fails to start (#794)
---
projects/lib/src/tournament.cpp | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/projects/lib/src/tournament.cpp b/projects/lib/src/tournament.cpp
index 87b90207..af6a2fac 100644
--- a/projects/lib/src/tournament.cpp
+++ b/projects/lib/src/tournament.cpp
@@ -730,11 +730,18 @@ void Tournament::onGameFinished(ChessGame* game)
{
Q_ASSERT(game != nullptr);
+ if (!m_gameData.contains(game))
+ {
+ // Game failed to start, gameData was removed in onGameStartFailed.
+ // The game's PGN data is already destroyed, and tournament set to
+ // stop, so we can simply return here.
+ return;
+ }
+
PgnGame* pgn(game->pgn());
m_finishedGameCount++;
- Q_ASSERT(m_gameData.contains(game));
GameData* data = m_gameData.take(game);
int gameNumber = data->number;
Sprt::GameResult sprtResult = Sprt::NoResult;
From 2c8aa36e8303749ec2df58c1b74c8c2ed6463555 Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Sun, 21 Jul 2024 16:33:12 +0300
Subject: [PATCH 26/30] version 1.4.0-beta3
---
.version | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.version b/.version
index 9ce2de56..b95a95b0 100644
--- a/.version
+++ b/.version
@@ -1 +1 @@
-1.4.0-beta2
\ No newline at end of file
+1.4.0-beta3
\ No newline at end of file
From 4775fdd78ba8c2fde72de0e2e0e7fcd47189cb2f Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Sun, 21 Jul 2024 16:34:54 +0300
Subject: [PATCH 27/30] update changelog
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c91d6ba9..ff1d1778 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed
+- Crash when tournament game fails to start (#794)
- Cute Chess specific CodeQL static analysis queries have been re-enabled (#798)
### Changed
From 69c37797d81c1b29b1d9a8d6ea96491da8811a78 Mon Sep 17 00:00:00 2001
From: Rak Laptudirm
Date: Mon, 22 Jul 2024 15:46:26 +0530
Subject: [PATCH 28/30] chore: update sprt completion conditions to match
theory (#782)
The conditions which must be met for H0 or H1 to be accepted have been updated to use closed intervals, matching the theory found in the original paper by Abraham Wald.
---
projects/lib/src/sprt.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/projects/lib/src/sprt.cpp b/projects/lib/src/sprt.cpp
index 838c31bb..79c4e479 100644
--- a/projects/lib/src/sprt.cpp
+++ b/projects/lib/src/sprt.cpp
@@ -193,9 +193,9 @@ Sprt::Status Sprt::status() const
status.lBound = std::log(m_beta / (1.0 - m_alpha));
status.uBound = std::log((1.0 - m_beta) / m_alpha);
- if (status.llr > status.uBound)
+ if (status.llr >= status.uBound)
status.result = AcceptH1;
- else if (status.llr < status.lBound)
+ else if (status.llr <= status.lBound)
status.result = AcceptH0;
return status;
From a70c59153bcc764495c98dc9b807b64471eb81be Mon Sep 17 00:00:00 2001
From: alwey
Date: Sat, 12 Feb 2022 12:12:49 +0100
Subject: [PATCH 29/30] Add way to switch on debugging on UCI engines
Some changed to the original PR by @ilaripih
Introduce debugEnabled to EngineConfiguration. Introduce formal engine
option "debug" e.g. cutechess-cli -each ponder debug opt.op1=value.
Introduce ChessEngine::debugEnabled.
Send "debug on" in UciEngine::startGame if debugEnabled()
Add support for GUI:
Add m_debugCheck to EngineConfigDlg abdsupporting logic to
EngineConfigurationDlg.
Resolves #505
---
docs/cutechess-cli.6 | 2 ++
projects/cli/res/doc/help.txt | 1 +
projects/cli/src/main.cpp | 10 +++++++-
projects/gui/src/engineconfigurationdlg.cpp | 9 +++++++
projects/gui/ui/engineconfigdlg.ui | 14 +++++++++--
projects/lib/src/chessengine.cpp | 8 ++++++
projects/lib/src/chessengine.h | 11 ++++++++
projects/lib/src/engineconfiguration.cpp | 28 ++++++++++++++++++---
projects/lib/src/engineconfiguration.h | 9 +++++++
projects/lib/src/uciengine.cpp | 3 +++
10 files changed, 88 insertions(+), 7 deletions(-)
diff --git a/docs/cutechess-cli.6 b/docs/cutechess-cli.6
index 9a2c7bf6..450eae52 100644
--- a/docs/cutechess-cli.6
+++ b/docs/cutechess-cli.6
@@ -500,6 +500,8 @@ Set the node count limit.
Scale engine timeouts by
.Ar factor .
Only use this option if necessary.
+.It Ic debug
+Activate debug mode (per protocol, UCI only).
.El
.Sh EXAMPLES
Play ten games between two Sloppy engines with a time control of 40
diff --git a/projects/cli/res/doc/help.txt b/projects/cli/res/doc/help.txt
index 20e9f1cd..04629e4b 100644
--- a/projects/cli/res/doc/help.txt
+++ b/projects/cli/res/doc/help.txt
@@ -223,5 +223,6 @@ Engine options:
pondering is disabled.
tscale=FACTOR Scale engine timeouts by FACTOR. Only use this option
if necessary.
+ debug Activate debug mode per protocol (UCI only).
option.OPTION=VALUE Set custom option OPTION to value VALUE
diff --git a/projects/cli/src/main.cpp b/projects/cli/src/main.cpp
index ea67c929..ac20bf99 100644
--- a/projects/cli/src/main.cpp
+++ b/projects/cli/src/main.cpp
@@ -234,6 +234,10 @@ bool parseEngine(const QStringList& args, EngineData& data)
{
data.config.setPondering(true);
}
+ else if (name == "debug")
+ {
+ data.config.setDebugEnabled(true);
+ }
// Custom engine option
else if (name.startsWith("option."))
data.config.setOption(name.section('.', 1), val);
@@ -271,7 +275,7 @@ EngineMatch* parseMatch(const QStringList& args, QObject* parent)
parser.addOption("-ratinginterval", QVariant::Int, 1, 1);
parser.addOption("-outcomeinterval", QVariant::Int, 1, 1);
parser.addOption("-resultformat", QVariant::String, 1, 1);
- parser.addOption("-debug", QVariant::Bool, 0, 0);
+ parser.addOption("-debug", QVariant::String, 0, 1);
parser.addOption("-openings", QVariant::StringList);
parser.addOption("-bookmode", QVariant::String);
parser.addOption("-pgnout", QVariant::StringList, 1, 3);
@@ -479,6 +483,10 @@ EngineMatch* parseMatch(const QStringList& args, QObject* parent)
{
QLoggingCategory::defaultCategory()->setEnabled(QtDebugMsg, true);
match->setDebugMode(true);
+ if (value == "all")
+ eachOptions.append("debug");
+ else if (!value.isNull())
+ ok = false;
}
// Use an opening suite
else if (name == "-openings")
diff --git a/projects/gui/src/engineconfigurationdlg.cpp b/projects/gui/src/engineconfigurationdlg.cpp
index 668f8bb9..d8c7f814 100644
--- a/projects/gui/src/engineconfigurationdlg.cpp
+++ b/projects/gui/src/engineconfigurationdlg.cpp
@@ -94,11 +94,16 @@ EngineConfigurationDialog::EngineConfigurationDialog(
[=](const QString& text)
{
if (text == "xboard")
+ {
ui->m_whitePovCheck->setEnabled(true);
+ ui->m_debugCheck->setChecked(false);
+ ui->m_debugCheck->setEnabled(false);
+ }
else
{
ui->m_whitePovCheck->setChecked(false);
ui->m_whitePovCheck->setEnabled(false);
+ ui->m_debugCheck->setChecked(false);
}
});
@@ -138,6 +143,9 @@ void EngineConfigurationDialog::applyEngineInformation(
if (engine.whiteEvalPov())
ui->m_whitePovCheck->setCheckState(Qt::Checked);
+ if (engine.debugEnabled())
+ ui->m_debugCheck->setCheckState(Qt::Checked);
+
const auto options = engine.options();
for (const EngineOption* option : options)
m_options << option->copy();
@@ -165,6 +173,7 @@ EngineConfiguration EngineConfigurationDialog::engineConfiguration()
engine.setInitStrings(initStr.split('\n'));
engine.setWhiteEvalPov(ui->m_whitePovCheck->checkState() == Qt::Checked);
+ engine.setDebugEnabled(ui->m_debugCheck->checkState() == Qt::Checked);
QList optionCopies;
for (const EngineOption* option : qAsConst(m_options))
diff --git a/projects/gui/ui/engineconfigdlg.ui b/projects/gui/ui/engineconfigdlg.ui
index 7da316f3..8c8b7b5a 100644
--- a/projects/gui/ui/engineconfigdlg.ui
+++ b/projects/gui/ui/engineconfigdlg.ui
@@ -6,8 +6,8 @@
0
0
- 480
- 400
+ 519
+ 477
@@ -189,6 +189,16 @@
+ -
+
+
+ The engine is put into debug mode, if the engine supports it
+
+
+ Debug
+
+
+
diff --git a/projects/lib/src/chessengine.cpp b/projects/lib/src/chessengine.cpp
index 5c76186c..477ba69b 100644
--- a/projects/lib/src/chessengine.cpp
+++ b/projects/lib/src/chessengine.cpp
@@ -77,6 +77,7 @@ ChessEngine::ChessEngine(QObject* parent)
m_whiteEvalPov(false),
m_pondering(false),
m_timeoutScale(1.0),
+ m_debugEnabled(false),
m_pingTimer(new QTimer(this)),
m_quitTimer(new QTimer(this)),
m_idleTimer(new QTimer(this)),
@@ -143,6 +144,8 @@ void ChessEngine::applyConfiguration(const EngineConfiguration& configuration)
m_pondering = configuration.pondering();
m_timeoutScale = configuration.timeoutScale();
m_restartMode = configuration.restartMode();
+ m_debugEnabled = configuration.debugEnabled();
+
setClaimsValidated(configuration.areClaimsValidated());
// Read protocol timeouts from QSettings.
@@ -295,6 +298,11 @@ bool ChessEngine::pondering() const
return m_pondering;
}
+bool ChessEngine::debugEnabled() const
+{
+ return m_debugEnabled;
+}
+
void ChessEngine::endGame(const Chess::Result& result)
{
ChessPlayer::endGame(result);
diff --git a/projects/lib/src/chessengine.h b/projects/lib/src/chessengine.h
index 16a73a0d..68ab86d1 100644
--- a/projects/lib/src/chessengine.h
+++ b/projects/lib/src/chessengine.h
@@ -232,6 +232,16 @@ class LIB_EXPORT ChessEngine : public ChessPlayer
* the engine does not support pondering.
*/
bool pondering() const;
+
+ /*!
+ * Returns true if debugging is enabled for the engine;
+ * otherwise returns false.
+ *
+ * \note Even if debugging is enabled, it's still possible that
+ * the engine does not support debugging.
+ */
+ bool debugEnabled() const;
+
/*!
* Gives id number of the engine
*/
@@ -295,6 +305,7 @@ class LIB_EXPORT ChessEngine : public ChessPlayer
bool m_whiteEvalPov;
bool m_pondering;
double m_timeoutScale;
+ bool m_debugEnabled;
QTimer* m_pingTimer;
QTimer* m_quitTimer;
QTimer* m_idleTimer;
diff --git a/projects/lib/src/engineconfiguration.cpp b/projects/lib/src/engineconfiguration.cpp
index 12f9d2a7..5dc36630 100644
--- a/projects/lib/src/engineconfiguration.cpp
+++ b/projects/lib/src/engineconfiguration.cpp
@@ -28,7 +28,8 @@ EngineConfiguration::EngineConfiguration()
m_pondering(false),
m_validateClaims(true),
m_timeoutScale(1.0),
- m_restartMode(RestartAuto)
+ m_restartMode(RestartAuto),
+ m_debugEnabled(false)
{
}
@@ -43,7 +44,8 @@ EngineConfiguration::EngineConfiguration(const QString& name,
m_pondering(false),
m_validateClaims(true),
m_timeoutScale(1.0),
- m_restartMode(RestartAuto)
+ m_restartMode(RestartAuto),
+ m_debugEnabled(false)
{
}
@@ -53,7 +55,8 @@ EngineConfiguration::EngineConfiguration(const QVariant& variant)
m_pondering(false),
m_validateClaims(true),
m_timeoutScale(1.0),
- m_restartMode(RestartAuto)
+ m_restartMode(RestartAuto),
+ m_debugEnabled(false)
{
const QVariantMap map = variant.toMap();
@@ -90,6 +93,8 @@ EngineConfiguration::EngineConfiguration(const QVariant& variant)
if (map.contains("validateClaims"))
setClaimsValidated(map["validateClaims"].toBool());
+ if (map.contains("debug"))
+ setDebugEnabled(map["debug"].toBool());
if (map.contains("variants"))
setSupportedVariants(map["variants"].toStringList());
@@ -120,7 +125,8 @@ EngineConfiguration::EngineConfiguration(const EngineConfiguration& other)
m_pondering(other.m_pondering),
m_validateClaims(other.m_validateClaims),
m_timeoutScale(other.m_timeoutScale),
- m_restartMode(other.m_restartMode)
+ m_restartMode(other.m_restartMode),
+ m_debugEnabled(other.debugEnabled())
{
const auto options = other.options();
for (const EngineOption* option : options)
@@ -146,6 +152,7 @@ EngineConfiguration& EngineConfiguration::operator=(EngineConfiguration&& other)
m_validateClaims = other.m_validateClaims;
m_timeoutScale = other.m_timeoutScale;
m_restartMode = other.m_restartMode;
+ m_debugEnabled =other.m_debugEnabled;
m_options = other.m_options;
// other's destructor will cause a mess if its m_options isn't cleared
@@ -183,6 +190,8 @@ QVariant EngineConfiguration::toVariant() const
if (!m_validateClaims)
map.insert("validateClaims", false);
+ if (m_debugEnabled)
+ map.insert("debug", true);
if (m_variants.count("standard") != m_variants.count())
map.insert("variants", m_variants);
@@ -384,6 +393,16 @@ void EngineConfiguration::setTimeoutScale(double value)
m_timeoutScale = qBound(timeoutScaleMin, value, timeoutScaleMax);
}
+bool EngineConfiguration::debugEnabled() const
+{
+ return m_debugEnabled;
+}
+
+void EngineConfiguration::setDebugEnabled(bool enabled)
+{
+ m_debugEnabled = enabled;
+}
+
EngineConfiguration& EngineConfiguration::operator=(const EngineConfiguration& other)
{
if (this != &other)
@@ -401,6 +420,7 @@ EngineConfiguration& EngineConfiguration::operator=(const EngineConfiguration& o
m_pondering = other.m_pondering;
m_validateClaims = other.m_validateClaims;
m_restartMode = other.m_restartMode;
+ m_debugEnabled = other.m_debugEnabled;
qDeleteAll(m_options);
m_options.clear();
diff --git a/projects/lib/src/engineconfiguration.h b/projects/lib/src/engineconfiguration.h
index 33bcf114..ae2eadf4 100644
--- a/projects/lib/src/engineconfiguration.h
+++ b/projects/lib/src/engineconfiguration.h
@@ -227,6 +227,14 @@ class LIB_EXPORT EngineConfiguration
*/
void setTimeoutScale(double value);
+ /*!
+ * Returns true if debug mode is enabled for the engine,
+ * else false.
+ */
+ bool debugEnabled() const;
+ /*! Sets the debug mode to \a enabled */
+ void setDebugEnabled(bool enabled);
+
/*!
* Assigns \a other to this engine configuration and returns
* a reference to this object.
@@ -248,6 +256,7 @@ class LIB_EXPORT EngineConfiguration
bool m_validateClaims;
double m_timeoutScale;
RestartMode m_restartMode;
+ bool m_debugEnabled;
};
#endif // ENGINE_CONFIGURATION_H
diff --git a/projects/lib/src/uciengine.cpp b/projects/lib/src/uciengine.cpp
index b667f9d8..8c73c70b 100644
--- a/projects/lib/src/uciengine.cpp
+++ b/projects/lib/src/uciengine.cpp
@@ -148,6 +148,9 @@ void UciEngine::startGame()
m_startFen = board()->fenString(Chess::Board::XFen);
setVariant(board()->variant());
+ if (debugEnabled())
+ write("debug on");
+
write("ucinewgame");
if (m_canPonder)
From 780065637f9936bc29cc592c6f0b2007ccbf66de Mon Sep 17 00:00:00 2001
From: Arto Jonsson
Date: Mon, 22 Jul 2024 20:26:07 +0300
Subject: [PATCH 30/30] regen docs
---
docs/cutechess-cli.6.html | 138 ++++++++++++++-------------
docs/cutechess-cli.6.txt | 6 ++
docs/cutechess-engines.json.5.html | 148 ++++++++++++++---------------
3 files changed, 149 insertions(+), 143 deletions(-)
diff --git a/docs/cutechess-cli.6.html b/docs/cutechess-cli.6.html
index 0b927166..95637dcd 100644
--- a/docs/cutechess-cli.6.html
+++ b/docs/cutechess-cli.6.html
@@ -2,6 +2,7 @@
+
CUTECHESS-CLI(6)
@@ -16,8 +17,8 @@
-cutechess-cli
—
-Automate chess engine tournaments
+cutechess-cli
—
+ Automate chess engine tournaments
-The cutechess-cli
utility automates chess engine
- tournaments.
+The cutechess-cli
utility automates chess
+ engine tournaments.
Its options are as follows:
- -engine
+ -engine
engine-options
Add an engine defined by engine-options to the
tournament. See Engine
Options .
- -each
+ -each
engine-options
Apply engine-options to each engine in the
tournament. See Engine
Options .
- -variant
+ -variant
variant
Set the chess variant, where variant is one of:
@@ -206,11 +207,11 @@
- -concurrency
+ -concurrency
n
Set the maximum number of concurrent games to
n .
- -draw
+ -draw
movenumber
=number
movecount
=count
score
=score
@@ -219,7 +220,7 @@
- -ratinginterval
+ -ratinginterval
n
Set the interval for printing the ratings to n
games.
- -outcomeinterval
+ -outcomeinterval
n
Set the interval for printing outcomes to n
games.
- -debug
+ -debug
Display all engine input and output.
- -openings
+ -openings
file
=file
format
=[epd
|
pgn
]
@@ -334,49 +335,49 @@ DESCRIP
default
shifts for any new pair of players and
also when the specified number of opening repetitions is reached.
- -bookmode
+ -bookmode
mode
Set Polyglot book access mode, where mode is either
ram
(the whole book is loaded into RAM) or
disk
(the book is accessed directly on disk). The
default mode is ram
.
- -pgnout
+ -pgnout
file [min
]
[fi
]
Save the games to file in PGN format. Use the
min
argument to save in a minimal PGN format. Only
finished games will be saved if argument fi
is
given.
- -epdout
+ -epdout
file
Save the games to file in FEN format.
- -recover
+ -recover
Restart crashed engines instead of stopping the game.
- -repeat
+ -repeat
[n ]
Play each opening twice (or n times). Unless the
-noswap
option is used, the players swap sides
after each game. So they get to play the opening on both sides. Please
note that a new encounter will use a new opening.
- -noswap
+ -noswap
Do not swap sides of paired engines.
- -reverse
+ -reverse
Use schedule with reverse sides.
- -seeds
+ -seeds
n
Set the first n engines as seeds in the tournament.
The default is 0.
- -site
+ -site
arg
Set the site / location to arg .
- -srand
+ -srand
seed
Set the random seed for the book move selector.
- -wait
+ -wait
n
Wait n milliseconds between games. The default is
0.
- -resultformat
+ -resultformat
format
Specify the format of result lists.
Format can either be a comma separated list of
@@ -384,32 +385,32 @@ DESCRIP
available named formats. The default
format lists
rank, name, elo, elo error, number of games, score percentage, and draw
percentage of every player.
- -version
+ -version
Display the version information.
- -help
+ -help
Display help information.
- -engines
+ -engines
Display a list of configured engines and exit.
EXAMPLES
-Play ten games between two Sloppy engines with a time control of 40 moves in 60
- seconds:
+Play ten games between two Sloppy engines with a time control of
+ 40 moves in 60 seconds:
$ cutechess-cli -engine cmd=sloppy
-engine cmd=sloppy -each proto=xboard tc=40/60 -rounds 10
@@ -505,15 +511,15 @@ EXAMPLES <
AUTHORS
-The cutechess-cli
utility was written by
- Ilari Pihlajisto ,
-
-Arto Jonsson and contributors. See the project page for
- more details.
+The cutechess-cli
utility was written by
+ Ilari Pihlajisto ,
+
+ Arto Jonsson and contributors. See the project page
+ for more details.
RESOURCES
diff --git a/docs/cutechess-cli.6.txt b/docs/cutechess-cli.6.txt
index 8810e1ff..4c4adef9 100644
--- a/docs/cutechess-cli.6.txt
+++ b/docs/cutechess-cli.6.txt
@@ -328,6 +328,12 @@ DESCRIPTION
nodes=count
Set the node count limit.
+ tscale=factor
+ Scale engine timeouts by factor. Only use this option if
+ necessary.
+
+ debug Activate debug mode (per protocol, UCI only).
+
EXAMPLES
Play ten games between two Sloppy engines with a time control of 40 moves
in 60 seconds:
diff --git a/docs/cutechess-engines.json.5.html b/docs/cutechess-engines.json.5.html
index 15a8645d..6bd221f1 100644
--- a/docs/cutechess-engines.json.5.html
+++ b/docs/cutechess-engines.json.5.html
@@ -2,6 +2,7 @@
+
CUTECHESS-ENGINES.JSON(5)
@@ -16,159 +17,153 @@
NAME
-cutechess-engines.json
—
-Cute Chess engine configuration file
+cutechess-engines.json
—
+ Cute Chess engine configuration file
DESCRIPTION
-cutechess-engines.json
is the chess engine configuration
- file for cutechess-cli(6) . An engine configuration defines a
- name, a command, a working directory and many other options. Engine
- configurations can be used in cutechess-cli(6) with the
- conf
command-line option.
+cutechess-engines.json
is the chess engine
+ configuration file for cutechess-cli(6) . An engine
+ configuration defines a name, a command, a working directory and many other
+ options. Engine configurations can be used in
+ cutechess-cli(6) with the conf
+ command-line option.
Engine configurations are defined in JavaScript Object Notation
(JSON) format. See JSON FORMAT .
JSON
FORMAT
-JavaScript Object Notation (JSON) is a text-based format for structured data.
- JSON is a subset of ECMAScript (JavaScript).
+JavaScript Object Notation (JSON) is a text-based format for
+ structured data. JSON is a subset of ECMAScript (JavaScript).
Values
-A JSON value must be one of: object ,
- array , number ,
- string , false
,
- true
or null
.
+A JSON value must be one of: object ,
+ array , number ,
+ string , false
,
+ true
or null
.
Objects
-An object is structure of name-value
- pairs enclosed in curly brackets. A name is a string .
- Name and value are separated by a single colon. Pairs are separated by commas.
+An object is structure of
+ name-value pairs enclosed in curly brackets. A name is
+ a string . Name and value are separated by a single
+ colon. Pairs are separated by commas.
Example objects would be:
-
-
-{ "Finland" : ".fi", "Sweden" : ".se" }
+
+
{ "Finland" : ".fi", "Sweden" : ".se" }
{
"firstName" : "JC",
"lastName" : "Denton",
"age" : 28,
"languages" : [ "English", "French", "Spanish" ]
-}
-
+}
Arrays
-An array is a structure of zero or more
- values enclosed in square brackets. Values are separated
- by commas.
+An array is a structure of zero or more
+ values enclosed in square brackets. Values are
+ separated by commas.
Example arrays would be:
-
-
-[ "Cute", "Chess" ]
+
+
[ "Cute", "Chess" ]
[
[ 1, 0, 0 ],
[ 0, 1, 0 ],
[ 0, 0, 1 ]
-]
-
+]
Numbers
-A number consists of an integer part and optional
- fractional and/or exponent part. The integer part can be prefixed with a minus
- sign. Fractional part is a decimal point followed by one or more digits.
- Exponent part begins with a letter E in upper or lowercase which may be
- followed by a plus or minus sign. The E and optional sign are followed by one
- or more digits.
+A number consists of an integer part and
+ optional fractional and/or exponent part. The integer part can be prefixed
+ with a minus sign. Fractional part is a decimal point followed by one or
+ more digits. Exponent part begins with a letter E in upper or lowercase
+ which may be followed by a plus or minus sign. The E and optional sign are
+ followed by one or more digits.
Octal and hex forms are not allowed.
Example numbers would be:
-
-
-128
+
+
128
-1.04
2e32
--18E-20
-
+-18E-20
Strings
-A string is sequence of characters enclosed in quotation
- marks. All Unicode characters may be placed within the quotation marks except
- for the characters that must be escaped: quotation mark, backslash, and
- control characters.
+A string is sequence of characters enclosed
+ in quotation marks. All Unicode characters may be placed within the
+ quotation marks except for the characters that must be escaped: quotation
+ mark, backslash, and control characters.
Available two-character escape sequences are as follows:
- \\
+ \\
Backslash character.
- \/
+ \/
Forward slash character.
- \"
+ \"
Quotation mark.
- \b
+ \b
Bell character.
- \f
+ \f
Form feed character.
- \n
+ \n
Line feed character.
- \t
+ \t
Vertical tab character.
- \u
num
+ \u
num
Unicode character where num is a four hexadecimal
digits that encode the character's code point.
Example strings would be:
-
-
-"Hello, world!"
+
+
"Hello, world!"
"Please place all items \"carefully\" in bins."
-"\u03a6 is one of the letters of Greek alphabet."
-
+"\u03a6 is one of the letters of Greek alphabet."
EXAMPLES
-A minimal engine configuration file for the Sloppy chess engine:
-
-
-[
+A minimal engine configuration file for the Sloppy chess
+ engine:
+
+
[
{
"name": "Sloppy",
"command": "sloppy",
"protocol": "xboard"
}
-]
-
+]
Using the above engine configuration file with the
conf
command-line option:
@@ -206,7 +200,7 @@ EXAMPLES <