This commit is contained in:
Sander Land committed 2020-12-11 20:34:38 +01:00
1 parent 3d43bf660f
commit bfa673d4b6
22 files changed
+477 -404

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
[flake8]
ignore = E501, E203, W503, E402 # line length, space before binary op, line break before binary op, import not at top
exclude = .git,__pycache__,build,dist
+39 -15
View File
@@ -1,7 +1,11 @@
"""isort:skip_file"""
# first, logging level lower
import json
import os
from kivy.core.window import Window
from kivy.uix.widget import Widget
os.environ["KCFG_KIVY_LOG_LEVEL"] = os.environ.get("KCFG_KIVY_LOG_LEVEL", "warning")
if "KIVY_AUDIO" not in os.environ:
os.environ["KIVY_AUDIO"] = "sdl2" # some backends hard crash / this seems to be most stable
@@ -46,9 +50,11 @@ from kivy.lang import Builder
from kivy.resources import resource_add_path
from kivy.uix.popup import Popup
from kivy.uix.screenmanager import Screen
from katrain.core.ai import generate_ai_move
from kivy.core.window import Window
from kivy.resources import resource_find
from kivy.properties import NumericProperty, ObjectProperty, StringProperty
from kivy.clock import Clock
from kivy.metrics import dp
from katrain.core.ai import generate_ai_move
from katrain.core.lang import DEFAULT_LANGUAGE, i18n
from katrain.core.constants import (
@@ -57,7 +63,6 @@ from katrain.core.constants import (
OUTPUT_INFO,
OUTPUT_DEBUG,
OUTPUT_EXTRA_DEBUG,
MODE_PLAY,
MODE_ANALYZE,
HOMEPAGE,
VERSION,
@@ -66,18 +71,23 @@ from katrain.core.constants import (
PLAYING_NORMAL,
PLAYER_HUMAN,
SGF_INTERNAL_COMMENTS_MARKER,
MODE_PLAY,
DATA_FOLDER,
)
from katrain.gui.popups import ConfigTeacherPopup, ConfigTimerPopup, I18NPopup, SaveSGFPopup
from katrain.core.base_katrain import KaTrainBase
from katrain.core.engine import KataGoEngine
from katrain.core.game import Game, IllegalMoveException, KaTrainSGF
from katrain.core.sgf_parser import Move, ParseError
from katrain.gui.kivyutils import *
from katrain.gui.popups import ConfigPopup, LoadSGFPopup, NewGamePopup, ConfigAIPopup
from katrain.gui.style import ENGINE_BUSY_COL, ENGINE_DOWN_COL, ENGINE_READY_COL
from katrain.gui.widgets import *
from katrain.gui.badukpan import AnalysisControls, BadukPanControls, BadukPanWidget
from katrain.gui.controlspanel import ControlsPanel
from katrain.gui.theme import Theme
from kivymd.app import MDApp
# used in kv
from katrain.gui.kivyutils import *
from katrain.gui.widgets import MoveTree, I18NFileBrowser, SelectionSlider, ScoreGraph # noqa F401
from katrain.gui.badukpan import AnalysisControls, BadukPanControls, BadukPanWidget # noqa F401
from katrain.gui.controlspanel import ControlsPanel # noqa F401
class KaTrainGui(Screen, KaTrainBase):
@@ -165,11 +175,11 @@ class KaTrainGui(Screen, KaTrainBase):
# update engine status dot
if not self.engine or not self.engine.katago_process or self.engine.katago_process.poll() is not None:
self.board_controls.engine_status_col = ENGINE_DOWN_COL
self.board_controls.engine_status_col = Theme.ENGINE_DOWN_COLOR
elif len(self.engine.queries) == 0:
self.board_controls.engine_status_col = ENGINE_READY_COL
self.board_controls.engine_status_col = Theme.ENGINE_READY_COLOR
else:
self.board_controls.engine_status_col = ENGINE_BUSY_COL
self.board_controls.engine_status_col = Theme.ENGINE_BUSY_COLOR
self.board_controls.queries_remaining = len(self.engine.queries)
# redraw board/stones
@@ -590,7 +600,8 @@ class KaTrainGui(Screen, KaTrainBase):
yappi.start()
self.log("starting profiler", OUTPUT_ERROR)
elif keycode[1] == "f10" and self.debug_level >= OUTPUT_EXTRA_DEBUG:
import yappi, time
import time
import yappi
stats = yappi.get_func_stats()
filename = f"callgrind.{int(time.time())}.prof"
@@ -607,7 +618,6 @@ class KaTrainApp(MDApp):
super().__init__()
def build(self):
global DEFAULT_FONT
self.icon = ICON # how you're supposed to set an icon
self.title = f"KaTrain v{VERSION}"
@@ -617,8 +627,22 @@ class KaTrainApp(MDApp):
kv_file = find_package_resource("katrain/gui.kv")
popup_kv_file = find_package_resource("katrain/popups.kv")
resource_add_path(PATHS["PACKAGE"])
DEFAULT_FONT = resource_find(DEFAULT_FONT)
resource_add_path(PATHS["PACKAGE"] + "/sounds")
resource_add_path(PATHS["PACKAGE"] + "/img")
resource_add_path(os.path.abspath(os.path.expanduser(DATA_FOLDER))) # prefer resources in .katrain
theme_file = resource_find("theme.json")
if theme_file:
try:
with open(theme_file) as f:
theme_overrides = json.load(f)
for k, v in theme_overrides.items():
setattr(Theme, k, v)
print(f"[{theme_file}] Found theme override {k} = {v}")
except Exception as e: # noqa E722
print(f"Failed to load theme file {theme_file}: {e}")
Theme.DEFAULT_FONT = resource_find(Theme.DEFAULT_FONT)
Builder.load_file(kv_file)
Window.bind(on_request_close=self.on_request_close)
+3 -3
View File
@@ -125,11 +125,11 @@ def policy_weighted_move(policy_moves, lower_bound, weaken_fac):
def generate_influence_territory_weights(ai_mode, ai_settings, policy_grid, size):
thr_line = ai_settings["threshold"] - 1 # zero-based
if ai_mode == AI_INFLUENCE:
weight = lambda x, y: (1 / ai_settings["line_weight"]) ** (
weight = lambda x, y: (1 / ai_settings["line_weight"]) ** ( # noqa E731
max(0, thr_line - min(size[0] - 1 - x, x)) + max(0, thr_line - min(size[1] - 1 - y, y))
)
) # noqa E731
else:
weight = lambda x, y: (1 / ai_settings["line_weight"]) ** (
weight = lambda x, y: (1 / ai_settings["line_weight"]) ** ( # noqa E731
max(0, min(size[0] - 1 - x, x, size[1] - 1 - y, y) - thr_line)
)
weighted_coords = [
+14 -3
View File
@@ -6,7 +6,18 @@ from kivy import Config
from kivy.storage.jsonstore import JsonStore
from katrain.core.ai import ai_rank_estimation
from katrain.core.constants import *
from katrain.core.constants import (
PLAYER_HUMAN,
PLAYER_AI,
PLAYING_NORMAL,
PLAYING_TEACHING,
OUTPUT_INFO,
OUTPUT_ERROR,
OUTPUT_DEBUG,
AI_DEFAULT,
CONFIG_MIN_VERSION,
DATA_FOLDER,
)
from katrain.core.utils import find_package_resource
@@ -44,7 +55,7 @@ class Player:
class KaTrainBase:
USER_CONFIG_FILE = os.path.expanduser("~/.katrain/config.json")
USER_CONFIG_FILE = os.path.expanduser(os.path.join(DATA_FOLDER, "config.json"))
PACKAGE_CONFIG_FILE = "katrain/config.json"
"""Settings, logging, and players functionality, so other classes like bots who need a katrain instance can be used without a GUI"""
@@ -91,7 +102,7 @@ class KaTrainBase:
else: # user file exists
try:
version = JsonStore(user_config_file).get("general")["version"]
except Exception: # broken file etc
except Exception: # noqa E722 broken file etc
version = "0.0.0"
if version < CONFIG_MIN_VERSION:
backup = user_config_file + f".{version}.backup"
+1
View File
@@ -3,6 +3,7 @@ VERSION = "1.7.0"
HOMEPAGE = "https://github.com/sanderland/katrain"
CONFIG_MIN_VERSION = "1.7.0" # keep config files from this version
ANALYSIS_FORMAT_VERSION = "1.0"
DATA_FOLDER = "~/.katrain"
OUTPUT_ERROR = -1
OUTPUT_KATAGO_STDERR = -0.5
+1 -1
View File
@@ -215,7 +215,7 @@ class Game:
if not copy_from_node.children:
break
copy_from_node = copy_from_node.ordered_children[0]
except:
except IllegalMoveException:
pass # illegal move = stop
self._calculate_groups() # recalculate groups
self.katrain.controls.set_status(
+2 -2
View File
@@ -15,7 +15,7 @@ from katrain.core.constants import (
from katrain.core.lang import i18n
from katrain.core.sgf_parser import Move, SGFNode
from katrain.core.utils import evaluation_class, pack_floats, unpack_floats, var_to_grid
from katrain.gui.style import INFO_PV_COLOR
from katrain.gui.theme import Theme
def analysis_dumps(analysis):
@@ -287,7 +287,7 @@ class GameNode(SGFNode):
def make_pv(self, player, pv, interactive):
pvtext = f"{player}{' '.join(pv)}"
if interactive:
pvtext = f"[u][ref={pvtext}][color={INFO_PV_COLOR}]{pvtext}[/color][/ref][/u]"
pvtext = f"[u][ref={pvtext}][color={Theme.INFO_PV_COLOR}]{pvtext}[/color][/ref][/u]"
return pvtext
def comment(self, sgf=False, teach=False, details=False, interactive=True):
+2 -2
View File
@@ -5,7 +5,7 @@ import sys
from kivy._event import Observable
from katrain.core.utils import find_package_resource
from katrain.gui.style import DEFAULT_FONT
from katrain.gui.theme import Theme
class Lang(Observable):
@@ -53,7 +53,7 @@ class Lang(Observable):
return
# get the right locales directory, and instantiate a gettext
self.lang = lang
self.font_name = self.FONTS.get(lang) or DEFAULT_FONT
self.font_name = self.FONTS.get(lang) or Theme.DEFAULT_FONT
i18n_dir, _ = os.path.split(find_package_resource("katrain/i18n/__init__.py"))
locale_dir = os.path.join(i18n_dir, "locales")
locales = gettext.translation("katrain", locale_dir, languages=[lang, DEFAULT_LANGUAGE])
+6 -6
View File
@@ -439,7 +439,7 @@ class SGF:
re = "W+"
elif "lack win" in lines[10]:
re = "B+"
except:
except IndexError:
pass
if handicap < 0 or handicap > 9:
@@ -527,7 +527,7 @@ class SGF:
try:
grlt = int(re.search(grlt_regex, line).group(1))
zipsu = int(re.search(zipsu_regex, line).group(1))
except:
except: # noqa E722
return ""
return gib_make_result(grlt, zipsu)
@@ -561,7 +561,7 @@ class SGF:
komi = int(re.search(r"GONGJE:(\d+),", line).group(1)) / 10
if komi:
root.set_property("KM", komi)
except:
except: # noqa E722
pass
if line.startswith("\\[GAMETAG="):
@@ -570,7 +570,7 @@ class SGF:
match = re.search(r"C(\d\d\d\d):(\d\d):(\d\d)", line)
date = "{}-{}-{}".format(match.group(1), match.group(2), match.group(3))
root.set_property("DT", date)
except:
except: # noqa E722
pass
if "RE" not in root.properties:
@@ -583,7 +583,7 @@ class SGF:
komi = int(re.search(r",G(\d+),", line).group(1)) / 10
if komi:
root.set_property("KM", komi)
except:
except: # noqa E722
pass
if line[0:3] == "INI":
@@ -592,7 +592,7 @@ class SGF:
setup = line.split()
try:
handicap = int(setup[3])
except IndexError:
except ParseError:
continue
if handicap < 0 or handicap > 9:
+100 -122
View File
@@ -10,30 +10,14 @@
#:import MODE_ANALYZE katrain.core.constants.MODE_ANALYZE
#:import STATUS_INFO katrain.core.constants.STATUS_INFO
#:import Theme katrain.gui.theme.Theme
#:import BLACK katrain.gui.theme.BLACK
#:import LIGHTER_GREY katrain.gui.theme.LIGHTER_GREY
#:import WHITE katrain.gui.style.WHITE
#:import BLACK katrain.gui.style.BLACK
#:import LIGHTGREY katrain.gui.style.LIGHTGREY
#:import LIGHTERGREY katrain.gui.style.LIGHTERGREY
#:import GREEN katrain.gui.style.GREEN
#:import YELLOW katrain.gui.style.YELLOW
#:import RED katrain.gui.style.RED
#:import DARKRED katrain.gui.style.DARKRED
#:import ORANGE katrain.gui.style.ORANGE
#:import BACKGROUND_COLOR katrain.gui.style.BACKGROUND_COLOR
#:import BOX_BACKGROUND_COLOR katrain.gui.style.BOX_BACKGROUND_COLOR
#:import LIGHTER_BACKGROUND_COLOR katrain.gui.style.LIGHTER_BACKGROUND_COLOR
#:import TEXT_COLOR katrain.gui.style.TEXT_COLOR
#:import SCORE_COLOR katrain.gui.style.SCORE_COLOR
#:import WINRATE_COLOR katrain.gui.style.WINRATE_COLOR
#:import POINTLOSS_COLOR katrain.gui.style.POINTLOSS_COLOR
#:set BUTTON_INACTIVE_COLOR LIGHTGREY
#:set CP_SPACING dp(6)
#:set CP_SMALL_SPACING dp(3)
#:set CP_PADDING dp(6)
#:set NOTES_FONT_SIZE sp(18)
#:set CP_SPACING Theme.CP_SPACING
#:set CP_SMALL_SPACING Theme.CP_SMALL_SPACING
#:set CP_PADDING Theme.CP_PADDING
#:set EPSILON 1e-9
@@ -68,8 +52,8 @@
<SizedButton>:
ripple_duration_in_slow: 0.6
text_color: TEXT_COLOR
background_color: BOX_BACKGROUND_COLOR
text_color: Theme.TEXT_COLOR
background_color: Theme.BOX_BACKGROUND_COLOR
label: label
text_size: root.size
Label:
@@ -85,27 +69,27 @@
width: root.label.texture_size[0]
<ToggleButtonMixin>:
inactive_background_color: BACKGROUND_COLOR
active_background_color: BOX_BACKGROUND_COLOR
inactive_background_color: Theme.BACKGROUND_COLOR
active_background_color: Theme.BOX_BACKGROUND_COLOR
background_color: self.active_background_color if self.state=='down' else self.inactive_background_color
outline_color: self.active_outline_color if self.state=='down' else self.inactive_outline_color
<SizedRectangleButton>:
outline_color: WHITE
outline_color: Theme.BUTTON_BORDER_COLOR
text_color: self.outline_color
<AutoSizedRectangleButton>:
outline_color: WHITE
outline_color: Theme.BUTTON_BORDER_COLOR
text_color: self.outline_color
<SizedRectangleToggleButton>:
inactive_outline_color: BUTTON_INACTIVE_COLOR
active_outline_color: WHITE
inactive_outline_color: Theme.BUTTON_INACTIVE_COLOR
active_outline_color: Theme.BUTTON_BORDER_COLOR
text_color: self.outline_color
<AutoSizedRectangleToggleButton>:
inactive_outline_color: BUTTON_INACTIVE_COLOR
active_outline_color: WHITE
inactive_outline_color: Theme.BUTTON_INACTIVE_COLOR
active_outline_color: Theme.BUTTON_BORDER_COLOR
text_color: self.outline_color
<SizedRoundedRectangleButton@SizedRectangleButton>:
@@ -115,7 +99,7 @@
background_radius: self.height/3.5
<BGBoxLayout>:
background_color: BOX_BACKGROUND_COLOR
background_color: Theme.BOX_BACKGROUND_COLOR
<TransparentIconButton>:
background_normal: ''
@@ -131,20 +115,20 @@
<I18NSpinnerOption@SpinnerOption>:
background_color: LIGHTER_BACKGROUND_COLOR
background_color: Theme.LIGHTER_BACKGROUND_COLOR
background_normal: ''
lang_change_tracking: i18n._('') # for font
color: WHITE
color: Theme.INPUT_FONT_COLOR
canvas.after:
Color:
rgba: LIGHTGREY
rgba: LIGHT_GREY
Line
points: self.x,self.y,self.x+self.width,self.y
width: 1
<Spinner>:
-font_size: self.height * 0.5
background_color: [*[c*255/88 for c in BACKGROUND_COLOR[:3]], 1] # compensate for texture
background_color: [*[c*255/88 for c in Theme.BACKGROUND_COLOR[:3]], 1] # compensate for texture
option_cls: 'I18NSpinnerOption'
<Button>:
@@ -159,7 +143,7 @@
id: image
pos: (root.pos[0] + (root.width - root.min_size)/2,root.pos[1] + (root.height - root.min_size)/2)
size: (root.min_size,root.min_size)
source: 'img/white.png' if root.player=='W' else 'img/black.png'
source: 'white_circle.png' if root.player=='W' else 'black_circle.png'
mipmap: True
Label:
id: lbl
@@ -167,7 +151,7 @@
text_size: None, root.min_size
bold: True
valign: 'center'
color: BLACK if root.player=='W' else WHITE
color: Theme.CIRCLE_TEXT_COLORS[root.player]
pos: (image.x, image.y)
size: image.size
font_size: root.min_size * 1.2 / (1 + 1 * len(self.text))
@@ -203,13 +187,13 @@
Label:
size_hint: 0.075, 0.5
NavIconButton:
icon: 'img/Previous-End.png'
icon: 'Previous-End.png'
on_press: root.katrain('undo',999)
NavIconButton:
icon: 'img/Previous-5.png'
icon: 'Previous-5.png'
on_press: root.katrain('undo',10)
NavIconButton:
icon: 'img/Previous.png'
icon: 'Previous.png'
on_press: root.katrain('undo')
MDFloatLayout:
size_hint: 0.05, 1
@@ -227,16 +211,16 @@
player: 'W'
text: ''
NavIconButton:
icon: 'img/Next.png'
icon: 'Next.png'
on_press: root.katrain('redo')
NavIconButton:
icon: 'img/Next-5.png'
icon: 'Next-5.png'
on_press: root.katrain('redo',10)
NavIconButton:
icon: 'img/Next-End.png'
icon: 'Next-End.png'
on_press: root.katrain('redo',999)
NavIconButton:
icon: 'img/Next-Mistake.png'
icon: 'Next-Mistake.png'
color: [0.79,0.06,0.06,1]
on_press: root.katrain('next-mistake')
ClickableLabel:
@@ -245,7 +229,7 @@
width: self.height
canvas.before:
Color:
rgba: YELLOW
rgba: Theme.ENGINE_PONDERING_COLOR
Ellipse:
pos: self.pos[0] + self.width/2 - self.width/6, self.pos[1] + self.height/2 - self.width/6
size: self.width/3, self.width/3
@@ -268,7 +252,7 @@
<HamburgerButton@TransparentIconButton>:
icon: 'img/hamburger.png'
icon: 'hamburger.png'
width: self.height
icon_size: [self.height * 0.5, self.height * 0.5]
@@ -279,8 +263,8 @@
player: 'B'
player_type: 'player:human'
player_subtype: 'game:normal'
background_color: BOX_BACKGROUND_COLOR if self.active else BACKGROUND_COLOR
outline_color: BOX_BACKGROUND_COLOR
background_color: Theme.BOX_BACKGROUND_COLOR if self.active else Theme.BACKGROUND_COLOR
outline_color: Theme.BOX_BACKGROUND_COLOR
outline_width: 2
padding: [2*CP_PADDING,CP_PADDING,CP_PADDING,CP_PADDING]
CircleWithText:
@@ -314,9 +298,9 @@
height: self.width
size_hint: 1, None
min_size: min(self.height,self.width)
inactive_line_color: WHITE
inactive_line_color: Theme.BUTTON_BORDER_COLOR
inactive_fill_color: [1,1,1,0]
active_line_color: ORANGE
active_line_color: Theme.PAUSE_ACTIVE_COLOR
active_fill_color: [1,1,1,0]
line_width: max(1.1,self.min_size/20)
line_color: root.active_line_color if self.active else root.inactive_line_color
@@ -345,10 +329,9 @@
cap: 'square'
<TimerLabel@Label>
timeout: False
color: ORANGE if self.timeout else GREEN
color: Theme.TIMER_TEXT_TIMEOUT_COLOR if self.timeout else Theme.TIMER_TEXT_COLOR
markup: True
max_lines: 1
font_name: 'fonts/digital-7 (mono).ttf'
@@ -363,7 +346,7 @@
MDFloatLayout:
size_hint: 0.4,1
TimerLabel:
color: BACKGROUND_COLOR
color: Theme.BACKGROUND_COLOR
text: '{}:88'.format('188' if root.state[0] >= 6000 else '88')
font_size: 0.85*self.height
pos_hint: {'right':1,'center_y':0.5}
@@ -441,30 +424,30 @@
<StatsBox>
orientation: 'vertical'
background_color: BOX_BACKGROUND_COLOR
background_color: Theme.BOX_BACKGROUND_COLOR
labels: {'score':score_label,'winrate':winrate_label,'points':pointloss_label}
StatsLabel:
id: winrate_label
label: i18n._('stats:winrate')
text: root.winrate
color: WINRATE_COLOR
color: Theme.WINRATE_COLOR
StatsLabel:
id: score_label
label: i18n._('stats:score')
text: root.score
color: SCORE_COLOR
color: Theme.SCORE_COLOR
StatsLabel:
id: pointloss_label
label: i18n._('stats:pointslost') if root.points_lost is None or root.points_lost > 0 else i18n._('stats:pointsgained')
text: '{}: {:.1f}'.format(root.player,abs(root.points_lost)) if root.points_lost is not None else '...'
color: POINTLOSS_COLOR
color: Theme.POINTLOSS_COLOR
<ScrollableLabel>:
background_color: BOX_BACKGROUND_COLOR
background_color: Theme.BOX_BACKGROUND_COLOR
do_scroll_x: False
scroll_type: ['bars']
bar_width: 5
bar_color: LIGHTGREY
bar_color: Theme.SCROLLBAR_COLOR
label: label
canvas.before:
Color:
@@ -477,9 +460,9 @@
lang_change_tracking: i18n._('')
markup: root.markup
padding: 5, 5
font_size: NOTES_FONT_SIZE
font_size: Theme.NOTES_FONT_SIZE
line_height: root.line_height
color: TEXT_COLOR
color: Theme.TEXT_COLOR
size_hint_y: None
height: self.texture_size[1]
text_size: self.width, None
@@ -497,7 +480,7 @@
<CollapsablePanelHeader>:
canvas.after:
Color:
rgba: BOX_BACKGROUND_COLOR
rgba: Theme.BOX_BACKGROUND_COLOR
Line:
width: 1
points: (self.x,self.y+1,self.x+self.width,self.y+1)
@@ -567,7 +550,7 @@
options_height: root.tab_option_height
closed_label: 'closedlabel:scoregraph'
options: ['score','winrate']
option_colors: [SCORE_COLOR,WINRATE_COLOR]
option_colors: [Theme.SCORE_COLOR,Theme.WINRATE_COLOR]
option_active: [True,False,False]
on_option_state:
graph.show_graphs(args[1])
@@ -584,7 +567,7 @@
options_height: root.tab_option_height
closed_label: 'closedlabel:movestats'
options: ['score','winrate','points']
option_colors: [SCORE_COLOR,WINRATE_COLOR,POINTLOSS_COLOR]
option_colors: [Theme.SCORE_COLOR,Theme.WINRATE_COLOR,Theme.POINTLOSS_COLOR]
option_active: [True,True,True]
on_option_state:
for k, v in args[1].items(): stats.labels[k].hidden = not v
@@ -596,26 +579,26 @@
size_hint_y_open: 1
closed_label: 'closedlabel:info&notes'
options: ['info','info-details','notes']
option_colors: [WHITE,WHITE,YELLOW]
option_colors: [Theme.INFO_TAB_FONT_COLOR,Theme.INFO_TAB_FONT_COLOR,Theme.NOTES_TAB_FONT_COLOR]
option_active: [True,False,False]
on_option_state:
info.detailed = args[1]['info-details']
info.size_hint_y = int(args[1]['info'] or info.detailed)+1e-9
info.size_hint_y = int(args[1]['info'] or info.detailed)+EPSILON
info.opacity = int(args[1]['info'] or info.detailed)
notebox.size_hint_y = int(args[1]['notes'])*0.66+1e-9
notebox.size_hint_y = int(args[1]['notes'])*0.66+EPSILON
notebox.opacity = int(args[1]['notes'])
app.gui.update_state()
options_height: root.tab_option_height
BGBoxLayout:
background_color: BOX_BACKGROUND_COLOR
background_color: Theme.BOX_BACKGROUND_COLOR
orientation: 'vertical'
ScrollableLabel:
id: status
error: False
size_hint: 1, None
height: min(self.parent.height*0.66,self.label.texture_size[1])
outline_color: RED if self.error else WHITE
background_color: LIGHTER_BACKGROUND_COLOR
outline_color: Theme.ERROR_BORDER_COLOR if self.error else Theme.INFO_TAB_FONT_COLOR
background_color: Theme.LIGHTER_BACKGROUND_COLOR
ScrollableLabel:
id: info
detailed: False
@@ -630,28 +613,28 @@
size_hint: 1,0
LabelledTextInput:
id: note
font_size: NOTES_FONT_SIZE
font_size: Theme.NOTES_FONT_SIZE
multiline: True
on_text: root.katrain.set_note(self.text)
hint_text: i18n._('SGF Notes Hint')
color_mode: 'custom'
line_color_focus: TEXT_COLOR
line_color_focus: Theme.TEXT_COLOR
size_hint: 1, 1
canvas.before:
Color:
rgba: LIGHTERGREY
rgba: LIGHTER_GREY
Line:
points: self.x, self.y+self.height, self.x+self.width, self.y+self.height
width: 1
Label:
size_hint_y: 1e-9 # takes up remaining space if info is closed
size_hint_y: EPSILON # takes up remaining space if info is closed
<MenuItem>
font_size: self.height * 0.5
size_hint_y: None
height: dp(50)
background_color: BOX_BACKGROUND_COLOR
background_color: Theme.BOX_BACKGROUND_COLOR
width_margin: 1.33
content_width: icon.width + label.texture_size[0] * self.width_margin
MDFloatLayout:
@@ -674,7 +657,7 @@
size_hint: None, None
font_size: root.font_size
font_name: root.font_name
color: WHITE
color: Theme.MENU_ITEM_FONT_COLOR
Label:
text: root.shortcut
halign: 'left'
@@ -682,7 +665,7 @@
size_hint_x: 1/3
font_size: root.font_size
font_name: root.font_name
color: LIGHTGREY
color: Theme.MENU_ITEM_SHORTCUT_COLOR
@@ -716,15 +699,15 @@
<AnalysisMenuItem@MenuItem>:
on_close: app.gui.analysis_controls.close_dropdown()
background_color: LIGHTER_BACKGROUND_COLOR
background_color: Theme.LIGHTER_BACKGROUND_COLOR
height: dp(45)
canvas.before:
Color:
rgba: WHITE
rgba: Theme.MENU_ITEM_FONT_COLOR
Line:
points: self.x,self.y, self.x,self.y+self.height
Color:
rgba: LIGHTGREY
rgba: Theme.MENU_ITEM_SHORTCUT_COLOR
Line
points: self.x,self.y,self.x+self.width,self.y
width: 1
@@ -735,52 +718,52 @@
katrain: app.gui
AnalysisMenuItem:
text: i18n._("analysis:extra")
icon: 'img/Extra.png'
icon: 'Extra.png'
shortcut: 'a'
on_action: root.katrain("analyze-extra", "extra")
AnalysisMenuItem:
text: i18n._("analysis:equalize")
icon: 'img/Equalize.png'
icon: 'Equalize.png'
shortcut: 's'
on_action: root.katrain("analyze-extra", "equalize")
AnalysisMenuItem:
text: i18n._("analysis:sweep")
icon: 'img/Sweep.png'
icon: 'Sweep.png'
shortcut: 'd'
on_action: root.katrain("analyze-extra", "sweep")
AnalysisMenuItem:
text: i18n._("analysis:alternatives")
icon: 'img/Alternative.png'
icon: 'Alternative.png'
shortcut: 'f'
on_action: root.katrain("analyze-extra", "alternative")
AnalysisMenuItem:
text: i18n._("analysis:region")
icon: 'img/local.png'
icon: 'local.png'
shortcut: 'g'
on_action: root.katrain("select-box",)
AnalysisMenuItem:
text: i18n._("analysis:insert")
icon: 'img/Insert-Move.png'
icon: 'Insert-Move.png'
shortcut: 'i'
on_action: root.katrain("insert-mode")
AnalysisMenuItem:
text: i18n._("analysis:playtoend")
icon: 'img/Finish.png'
icon: 'Finish.png'
shortcut: 'l'
on_action: root.katrain("play-to-end")
AnalysisMenuItem:
text: i18n._("analysis:game")
icon: 'img/analysis.png'
icon: 'analysis.png'
shortcut: ''
on_action: root.open_game_analysis_popup()
AnalysisMenuItem:
text: i18n._("analysis:continuous")
icon: 'img/play.png'
icon: 'play.png'
shortcut: 'space'
on_action: root.katrain.toggle_continuous_analysis()
AnalysisMenuItem:
text: i18n._("analysis:aimove")
icon: 'img/ai.png'
icon: 'ai.png'
shortcut: 'enter'
on_action: root.katrain("ai-move")
@@ -827,7 +810,7 @@
width: analysis_button.width
size_hint: None, 1
AutoSizedRectangleButton:
background_color: BOX_BACKGROUND_COLOR
background_color: Theme.BOX_BACKGROUND_COLOR
size_hint_y: 0.5
pos_hint: {'center_y': 0.5, 'x': 0}
id: analysis_button
@@ -838,7 +821,7 @@
x: self.parent.x + 2
size_hint: None, 0.4
width: self.height/2
source: 'img/menu.png'
source: 'menu.png'
mipmap: True
@@ -854,7 +837,7 @@
<MenuLabel@BackgroundMixin+Label>:
background_color: BACKGROUND_COLOR
background_color: Theme.BACKGROUND_COLOR
font_size: self.height * 0.5
height: self.parent.item_height or 50
size_hint: 1,None
@@ -934,7 +917,7 @@
<HamburgerMenuContents@MDBoxLayout+BackgroundMixin>:
katrain: app.gui
player_setup: player_setup
background_color: BOX_BACKGROUND_COLOR
background_color: Theme.BOX_BACKGROUND_COLOR
orientation: 'vertical'
item_height: self.height/20
MenuLabel:
@@ -952,43 +935,43 @@
item_height: root.item_height
MainMenuItem:
text: i18n._('menu:newgame')
icon: 'img/New-Game.png'
icon: 'New-Game.png'
shortcut: 'Ctrl-N'
on_action: root.katrain("new-game-popup")
height: root.item_height
MainMenuItem:
text: i18n._('menu:save')
icon: 'img/Save-Game.png'
icon: 'Save-Game.png'
shortcut: 'Ctrl-S'
on_action: root.katrain("save-game")
MainMenuItem:
text: i18n._('menu:save-as')
icon: 'img/Save-Game-As.png'
icon: 'Save-Game-As.png'
shortcut: 'Ctrl-D'
on_action: root.katrain("save-game-as-popup")
MainMenuItem:
text: i18n._('menu:load')
icon: 'img/Load-Game.png'
icon: 'Load-Game.png'
shortcut: 'Ctrl-L'
on_action: root.katrain("analyze-sgf-popup")
MainMenuItem:
text: i18n._('menu:clocksettings')
icon: 'img/Time-Settings.png'
icon: 'Time-Settings.png'
shortcut: 'F5'
on_action: root.katrain('timer-popup')
MainMenuItem:
text: i18n._('menu:teachsettings')
icon: 'img/Teaching-Settings.png'
icon: 'Teaching-Settings.png'
shortcut: 'F6'
on_action: root.katrain('teacher-popup')
MainMenuItem:
text: i18n._('menu:aisettings')
icon: 'img/AI-Settings.png'
icon: 'AI-Settings.png'
shortcut: 'F7'
on_action: root.katrain('ai-popup')
MainMenuItem:
text: i18n._('menu:settings')
icon: 'img/General-Settings.png'
icon: 'General-Settings.png'
shortcut: 'F8'
on_action: root.katrain('config-popup')
MenuLabel:
@@ -998,28 +981,28 @@
height: 1.5 * root.item_height
padding: CP_PADDING, 0
LangButton:
icon: 'img/flags/flag-uk.png'
icon: 'flags/flag-uk.png'
on_press: app.language = 'en'
LangButton:
icon: 'img/flags/flag-de.png'
icon: 'flags/flag-de.png'
on_press: app.language = 'de'
LangButton:
icon: 'img/flags/flag-fr.png'
icon: 'flags/flag-fr.png'
on_press: app.language = 'fr'
# LangButton:
# icon: 'img/flags/flag-es.png'
# icon: 'flags/flag-es.png'
# on_press: app.language = 'es'
LangButton:
icon: 'img/flags/flag-ru.png'
icon: 'flags/flag-ru.png'
on_press: app.language = 'ru'
LangButton:
icon: 'img/flags/flag-cn.png'
icon: 'flags/flag-cn.png'
on_press: app.language = 'cn'
LangButton:
icon: 'img/flags/flag-ko.png'
icon: 'flags/flag-ko.png'
on_press: app.language = 'ko'
LangButton:
icon: 'img/flags/flag-jp.png'
icon: 'flags/flag-jp.png'
on_press: app.language = 'jp'
BoxLayout:
size_hint: 1,None
@@ -1037,10 +1020,10 @@
<PlayAnalyzeButton@SizedToggleButton>:
inactive_background_color: BOX_BACKGROUND_COLOR
active_background_color: YELLOW
ripple_color: BACKGROUND_COLOR
text_color: self.inactive_background_color if self.state=='down' else self.active_background_color
inactive_background_color: Theme.BOX_BACKGROUND_COLOR
active_background_color: Theme.PLAY_ANALYZE_TAB_COLOR
ripple_color: Theme.BACKGROUND_COLOR
text_color: self.inactive_background_color if self.state=='down' else self.active_background_color
size_hint: 0.5,1
_font_size: self.height * 0.5
group: 'play_analyze'
@@ -1051,7 +1034,6 @@
play: play
analyze: analyze
OutlineBox:
outline_color: WHITE
size_hint: 0.7,0.7
pos_hint: {'center_x':0.5,'center_y':0.45}
PlayAnalyzeButton:
@@ -1079,7 +1061,7 @@
Screen:
name: 'gui'
BGBoxLayout:
background_color: BACKGROUND_COLOR
background_color: Theme.BACKGROUND_COLOR
MDBoxLayout:
orientation: 'vertical'
AnalysisControls:
@@ -1116,7 +1098,3 @@
on_state: if self.state=='close': root.update_state() # ai move etc on nav drawer close
HamburgerMenuContents:
id: nav_drawer_contents
+67 -67
View File
@@ -34,13 +34,13 @@ from katrain.core.lang import i18n
from katrain.core.utils import evaluation_class, format_visits, var_to_grid
from katrain.gui.kivyutils import draw_circle, draw_text, cached_texture
from katrain.gui.popups import I18NPopup, ReAnalyzeGamePopup
from katrain.gui.style import *
from katrain.gui.theme import Theme
class BadukPanWidget(Widget):
def __init__(self, **kwargs):
super(BadukPanWidget, self).__init__(**kwargs)
self.stones_sounds = [SoundLoader.load(f"sounds/stone{i}.wav") for i in [1, 2, 3, 4, 5]]
self.stones_sounds = [SoundLoader.load(file) for file in Theme.STONE_SOUNDS]
self.trainer_config = {}
self.ghost_stone = []
self.gridpos_x = []
@@ -208,16 +208,18 @@ class BadukPanWidget(Widget):
Rectangle(
pos=(self.gridpos_x[x] - stone_size, self.gridpos_y[y] - stone_size),
size=(2 * stone_size, 2 * stone_size),
texture=cached_texture(f"img/{player}_stone.png"),
texture=cached_texture(Theme.STONE_TEXTURE[player]),
)
if evalcol:
eval_radius = math.sqrt(evalscale) # scale area by evalscale
evalsize = self.stone_size * (EVAL_DOT_MIN_SIZE + eval_radius * (EVAL_DOT_MAX_SIZE - EVAL_DOT_MIN_SIZE))
evalsize = self.stone_size * (
Theme.EVAL_DOT_MIN_SIZE + eval_radius * (Theme.EVAL_DOT_MAX_SIZE - Theme.EVAL_DOT_MIN_SIZE)
)
Color(*evalcol)
Rectangle(
pos=(self.gridpos_x[x] - evalsize, self.gridpos_y[y] - evalsize),
size=(2 * evalsize, 2 * evalsize),
texture=cached_texture("img/dot.png"),
texture=cached_texture(Theme.EVAL_DOT_TEXTURE),
)
if innercol:
Color(*innercol)
@@ -225,12 +227,12 @@ class BadukPanWidget(Widget):
Rectangle(
pos=(self.gridpos_x[x] - inner_size, self.gridpos_y[y] - inner_size),
size=(2 * inner_size, 2 * inner_size),
texture=cached_texture("img/inner.png"),
texture=cached_texture(Theme.LAST_MOVE_TEXTURE),
)
def eval_color(self, points_lost, show_dots_for_class: List[bool] = None) -> Optional[List[float]]:
i = evaluation_class(points_lost, self.trainer_config["eval_thresholds"])
colors = EVAL_COLORS[self.trainer_config["theme"]]
colors = Theme.EVAL_COLORS[self.trainer_config["theme"]]
if show_dots_for_class is None or show_dots_for_class[i]:
return colors[i]
@@ -256,7 +258,7 @@ class BadukPanWidget(Widget):
board_height_with_margins = y_grid_spaces * self.grid_size
extra_px_margin_x = (self.width - board_width_with_margins) / 2
extra_px_margin_y = (self.height - board_height_with_margins) / 2
self.stone_size = self.grid_size * STONE_SIZE
self.stone_size = self.grid_size * Theme.STONE_SIZE
self.gridpos_x = [
self.pos[0] + extra_px_margin_x + math.floor((grid_spaces_margin_x[0] + i) * self.grid_size + 0.5)
@@ -268,19 +270,19 @@ class BadukPanWidget(Widget):
]
if katrain.game.insert_mode:
Color(1, 1, 1, 0.75) # dreamy
Color(*Theme.INSERT_BOARD_COLOR_TINT) # dreamy
else:
Color(1, 0.95, 0.8, 1) # image is a bit too light
Color(*Theme.BOARD_COLOR_TINT) # image is a bit too light
Rectangle(
pos=(
self.gridpos_x[0] - self.grid_size * grid_spaces_margin_x[0],
self.gridpos_y[0] - self.grid_size * grid_spaces_margin_y[0],
),
size=(self.grid_size * x_grid_spaces, self.grid_size * y_grid_spaces),
texture=cached_texture("img/board.png"),
texture=cached_texture(Theme.BOARD_TEXTURE),
)
Color(*LINE_COLOR)
Color(*Theme.LINE_COLOR)
for i in range(board_size_x):
Line(points=[(self.gridpos_x[i], self.gridpos_y[0]), (self.gridpos_x[i], self.gridpos_y[-1])])
for i in range(board_size_y):
@@ -295,10 +297,10 @@ class BadukPanWidget(Widget):
[int(size / 2)] if size % 2 == 1 and size > 7 else []
)
starpt_size = self.grid_size * STARPOINT_SIZE
starpt_size = self.grid_size * Theme.STARPOINT_SIZE
for x in star_point_coords(board_size_x):
for y in star_point_coords(board_size_y):
draw_circle((self.gridpos_x[x], self.gridpos_y[y]), starpt_size, LINE_COLOR)
draw_circle((self.gridpos_x[x], self.gridpos_y[y]), starpt_size, Theme.LINE_COLOR)
# coordinates
if self.draw_coords_enabled:
@@ -365,7 +367,7 @@ class BadukPanWidget(Widget):
evalcol = self.eval_color(points_lost, show_dots_for_class)
else:
evalcol = None
inner = STONE_COLORS[m.opponent] if i == 0 and not m in placements else None
inner = Theme.STONE_COLORS[m.opponent] if i == 0 and m not in placements else None
drawn_stone[m.coords] = m.player
self.draw_stone(
x=m.coords[0],
@@ -381,9 +383,9 @@ class BadukPanWidget(Widget):
for y in range(0, board_size_y):
evalcol = self.eval_color(16 * y / board_size_y)
self.draw_stone(0, y, "B", evalcol=evalcol, evalscale=y / (board_size_y - 1))
self.draw_stone(1, y, "B", innercol=STONE_COLORS["W"], evalcol=evalcol)
self.draw_stone(1, y, "B", innercol=Theme.STONE_COLORS["W"], evalcol=evalcol)
self.draw_stone(2, y, "W", evalcol=evalcol, evalscale=y / (board_size_y - 1))
self.draw_stone(3, y, "W", innercol=STONE_COLORS["B"], evalcol=evalcol)
self.draw_stone(3, y, "W", innercol=Theme.STONE_COLORS["B"], evalcol=evalcol)
# ownership - allow one move out of date for smooth animation
ownership = current_node.ownership or (current_node.parent and current_node.parent.ownership)
@@ -404,7 +406,7 @@ class BadukPanWidget(Widget):
for x in range(board_size_x):
loss = max(0, (-1 if current_node.children[-1].move.player == "B" else 1) * loss_grid[y][x])
if loss > 0:
Color(*EVAL_COLORS[self.trainer_config["theme"]][1][:3], loss)
Color(*Theme.EVAL_COLORS[self.trainer_config["theme"]][1][:3], loss)
Rectangle(
pos=(self.gridpos_x[x] - rsz / 2, self.gridpos_y[y] - rsz / 2), size=(rsz, rsz)
)
@@ -414,7 +416,7 @@ class BadukPanWidget(Widget):
for x in range(board_size_x):
ix_owner = "B" if ownership_grid[y][x] > 0 else "W"
if ix_owner != (has_stone.get((x, y), -1)):
Color(*STONE_COLORS[ix_owner][:3], abs(ownership_grid[y][x]))
Color(*Theme.STONE_COLORS[ix_owner][:3], abs(ownership_grid[y][x]))
Rectangle(
pos=(self.gridpos_x[x] - rsz / 2, self.gridpos_y[y] - rsz / 2), size=(rsz, rsz)
)
@@ -436,42 +438,41 @@ class BadukPanWidget(Widget):
if katrain.analysis_controls.policy.active and policy:
policy_grid = var_to_grid(policy, (board_size_x, board_size_y))
best_move_policy = max(*policy)
colors = EVAL_COLORS[self.trainer_config["theme"]]
colors = Theme.EVAL_COLORS[self.trainer_config["theme"]]
text_lb = 0.01 * 0.01
for y in range(board_size_y - 1, -1, -1):
for x in range(board_size_x):
move_policy = policy_grid[y][x]
pol_order = 5 - int(-math.log10(max(1e-9, move_policy - 1e-9)))
if pol_order >= 0:
if move_policy > text_lb:
Color(0.95, 0.75, 0.47, 1)
draw_circle(
(self.gridpos_x[x], self.gridpos_y[y]),
self.stone_size * HINT_SCALE * 0.98,
[0.95, 0.75, 0.47, 1],
)
scale = 0.95
else:
scale = 0.5
if move_policy < 0:
continue
pol_order = max(0, 5 + int(math.log10(max(1e-9, move_policy - 1e-9))))
if move_policy > text_lb:
draw_circle(
(self.gridpos_x[x], self.gridpos_y[y]),
HINT_SCALE * self.stone_size * scale,
(*colors[pol_order][:3], POLICY_ALPHA),
self.stone_size * Theme.HINT_SCALE * 0.98,
Theme.APPROX_BOARD_COLOR,
)
scale = 0.95
else:
scale = 0.5
draw_circle(
(self.gridpos_x[x], self.gridpos_y[y]),
Theme.HINT_SCALE * self.stone_size * scale,
(*colors[pol_order][:3], Theme.POLICY_ALPHA),
)
if move_policy > text_lb:
Color(*Theme.HINT_TEXT_COLOR)
draw_text(
pos=(self.gridpos_x[x], self.gridpos_y[y]),
text=f"{100 * move_policy :.2f}"[:4] + "%",
font_name="Roboto",
halign="center",
)
if move_policy == best_move_policy:
Color(*Theme.TOP_MOVE_BORDER_COLOR[:3], Theme.POLICY_ALPHA)
Line(
circle=(self.gridpos_x[x], self.gridpos_y[y], self.stone_size - dp(1.2),), width=dp(2),
)
if move_policy > text_lb:
Color(*BLACK)
draw_text(
pos=(self.gridpos_x[x], self.gridpos_y[y]),
text=f"{100 * move_policy :.2f}"[:4] + "%",
font_name="Roboto",
halign="center",
)
if move_policy == best_move_policy:
Color(*TOP_MOVE_BORDER_COLOR[:3], POLICY_ALPHA)
Line(
circle=(self.gridpos_x[x], self.gridpos_y[y], self.stone_size - dp(1.2),),
width=dp(2),
)
with pass_btn.canvas.after:
move_policy = policy[-1]
@@ -480,7 +481,7 @@ class BadukPanWidget(Widget):
draw_circle(
(pass_btn.pos[0] + pass_btn.width / 2, pass_btn.pos[1] + pass_btn.height / 2),
pass_btn.height / 2,
(*colors[pol_order][:3], GHOST_ALPHA),
(*colors[pol_order][:3], Theme.GHOST_ALPHA),
)
# pass circle
@@ -491,18 +492,18 @@ class BadukPanWidget(Widget):
katrain.controls.timer.paused = True
else:
text = i18n._("board-pass")
Color(0.45, 0.05, 0.45, 0.7)
Color(*Theme.PASS_CIRCLE_COLOR)
center = (self.gridpos_x[int(board_size_x / 2)], self.gridpos_y[int(board_size_y / 2)])
size = min(self.width, self.height) * 0.227
Ellipse(pos=(center[0] - size / 2, center[1] - size / 2), size=(size, size))
Color(0.85, 0.85, 0.85)
Color(*Theme.PASS_CIRCLE_TEXT_COLOR)
draw_text(pos=center, text=text, font_size=size * 0.25, halign="center")
self.redraw_hover_contents_trigger()
def draw_roi_box(self, region_of_interest, width=2):
xmin, xmax, ymin, ymax = region_of_interest
Color(*LIGHTER_BACKGROUND_COLOR)
Color(*Theme.REGION_BORDER_COLOR)
Line(
rectangle=(
self.gridpos_x[xmin] - self.grid_size / 3,
@@ -514,7 +515,7 @@ class BadukPanWidget(Widget):
)
def draw_hover_contents(self, *_args):
ghost_alpha = GHOST_ALPHA
ghost_alpha = Theme.GHOST_ALPHA
katrain = self.katrain
game_ended = katrain.game.end_result
current_node = katrain.game.current_node
@@ -560,17 +561,17 @@ class BadukPanWidget(Widget):
move = Move.from_gtp(move_dict["move"])
if move.coords is not None:
engine_best_move = move_dict.get("order", 99) == 0
scale = HINT_SCALE
scale = Theme.HINT_SCALE
text_on = True
alpha = HINTS_ALPHA
alpha = Theme.HINTS_ALPHA
if (
move_dict["visits"] < low_visits_threshold
and not engine_best_move
and not move_dict["move"] in child_moves
):
scale = UNCERTAIN_HINT_SCALE
scale = Theme.UNCERTAIN_HINT_SCALE
text_on = False
alpha = HINTS_LO_ALPHA
alpha = Theme.HINTS_LO_ALPHA
if "pv" in move_dict:
self.active_pv_moves.append((move.coords, move_dict["pv"], current_node))
@@ -579,18 +580,17 @@ class BadukPanWidget(Widget):
evalsize = self.stone_size * scale
evalcol = self.eval_color(move_dict["pointsLost"])
if text_on and top_moves_show: # remove grid lines using a board colored circle
Color(0.95, 0.75, 0.47, 1)
draw_circle(
(self.gridpos_x[move.coords[0]], self.gridpos_y[move.coords[1]]),
self.stone_size * scale * 0.98,
[0.95, 0.75, 0.47, 1],
Theme.APPROX_BOARD_COLOR,
)
Color(*evalcol[:3], alpha)
Rectangle(
pos=(self.gridpos_x[move.coords[0]] - evalsize, self.gridpos_y[move.coords[1]] - evalsize),
size=(2 * evalsize, 2 * evalsize),
texture=cached_texture("img/topmove.png"),
texture=cached_texture(Theme.TOP_MOVE_TEXTURE),
)
if text_on and top_moves_show: # TODO: faster if not sized?
keys = {"size": self.grid_size / 3, "smallsize": self.grid_size / 3.33}
@@ -614,7 +614,7 @@ class BadukPanWidget(Widget):
keys[TOP_MOVE_WINRATE] = f"{winrate*100:.1f}"
keys[TOP_MOVE_DELTA_WINRATE] = f"{-move_dict['winrateLost']:+.1%}"
keys[TOP_MOVE_VISITS] = format_visits(move_dict["visits"])
Color(*BLACK)
Color(*Theme.HINT_TEXT_COLOR)
draw_text(
pos=(self.gridpos_x[move.coords[0]], self.gridpos_y[move.coords[1]]),
text=fmt.format(**keys),
@@ -626,7 +626,7 @@ class BadukPanWidget(Widget):
if engine_best_move:
top_move_coords = move.coords
Color(*TOP_MOVE_BORDER_COLOR)
Color(*Theme.TOP_MOVE_BORDER_COLOR)
Line(
circle=(
self.gridpos_x[move.coords[0]],
@@ -648,7 +648,7 @@ class BadukPanWidget(Widget):
if move.coords != top_move_coords: # for contrast
dashed_width = 18
Color(*STONE_CONTRAST_COLORS[child_node.player])
Color(*Theme.NEXT_MOVE_DASH_CONTRAST_COLORS[child_node.player])
Line(
circle=(
self.gridpos_x[move.coords[0]],
@@ -659,7 +659,7 @@ class BadukPanWidget(Widget):
)
else:
dashed_width = 10
Color(*STONE_COLORS[child_node.player])
Color(*Theme.STONE_COLORS[child_node.player])
for s in range(0, 360, 30):
Line(
circle=(
@@ -727,9 +727,9 @@ class BadukPanWidget(Widget):
Rectangle( # not sure why the -1 here, but seems to center better
pos=(board_coords[0] - stone_size - 1, board_coords[1] - stone_size),
size=(2 * stone_size + 1, 2 * stone_size + 1),
texture=cached_texture(f"img/{move_player}_stone.png"),
texture=cached_texture(Theme.STONE_TEXTURE[move_player]),
)
Color(*STONE_TEXT_COLORS[move_player])
Color(*Theme.PV_TEXT_COLORS[move_player])
draw_text(pos=board_coords, text=str(i + 1), font_size=self.grid_size * sizefac / 1.45, font_name="Roboto")
def set_animating_pv(self, pv, node):
@@ -781,6 +781,6 @@ class AnalysisControls(MDBoxLayout):
class BadukPanControls(MDFloatLayout):
engine_status_col = ListProperty(ENGINE_DOWN_COL)
engine_status_col = ListProperty(Theme.ENGINE_DOWN_COLOR)
engine_status_pondering = NumericProperty(-1)
queries_remaining = NumericProperty(0)
+1 -1
View File
@@ -2,7 +2,7 @@ import time
from kivy.clock import Clock
from kivy.core.audio import SoundLoader
from kivy.properties import NumericProperty, ObjectProperty, OptionProperty
from kivy.properties import ObjectProperty, OptionProperty
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.floatlayout import MDFloatLayout
+11 -11
View File
@@ -3,7 +3,7 @@ from kivy.core.image import Image
from kivy.core.text import Label as CoreLabel
from kivy.core.text.markup import MarkupLabel as CoreMarkupLabel
from kivy.core.window import Window
from kivy.graphics import *
from kivy.graphics import Color, Ellipse, Rectangle
from kivy.properties import (
BooleanProperty,
ListProperty,
@@ -30,7 +30,7 @@ from kivymd.uix.textfield import MDTextField
from katrain.core.constants import AI_STRATEGIES_RECOMMENDED_ORDER, GAME_TYPES, MODE_PLAY, PLAYER_AI
from katrain.core.lang import i18n
from katrain.gui.style import DEFAULT_FONT, WHITE
from katrain.gui.theme import Theme
class BackgroundMixin(Widget): # -- mixins
@@ -69,14 +69,14 @@ class LeftButtonBehavior(ButtonBehavior): # stops buttons etc activating on rig
# -- resizeable buttons / avoid baserectangular for sizing
class SizedButton(LeftButtonBehavior, RectangularRippleBehavior, BasePressedButton, BaseFlatButton, BackgroundMixin):
text = StringProperty("")
text_color = ListProperty(WHITE)
text_color = ListProperty(Theme.BUTTON_TEXT_COLOR)
text_size = ListProperty([100, 100])
halign = OptionProperty("center", options=["left", "center", "right", "justify", "auto"])
label = ObjectProperty(None)
padding_x = NumericProperty(6)
padding_y = NumericProperty(0)
_font_size = NumericProperty(None)
font_name = StringProperty(DEFAULT_FONT)
font_name = StringProperty(Theme.DEFAULT_FONT)
class AutoSizedButton(SizedButton):
@@ -143,7 +143,7 @@ class StatsLabel(MDBoxLayout):
label = StringProperty("")
color = ListProperty([1, 1, 1, 1])
hidden = BooleanProperty(False)
font_name = StringProperty(DEFAULT_FONT)
font_name = StringProperty(Theme.DEFAULT_FONT)
class MyNavigationDrawer(MDNavigationDrawer):
@@ -214,7 +214,7 @@ class KeyValueSpinner(Spinner):
sync_height_frac = NumericProperty(1.0)
value_refs = ListProperty()
selected_index = NumericProperty(0)
font_name = StringProperty(DEFAULT_FONT)
font_name = StringProperty(Theme.DEFAULT_FONT)
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -283,7 +283,7 @@ class I18NSpinner(KeyValueSpinner):
sync_height_frac = NumericProperty(1.0)
value_refs = ListProperty()
selected_index = NumericProperty(0)
font_name = StringProperty(DEFAULT_FONT)
font_name = StringProperty(Theme.DEFAULT_FONT)
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -406,7 +406,7 @@ class TriStateMDCheckbox(MDCheckbox):
class AnalysisToggle(MDBoxLayout):
text = StringProperty("")
default_active = BooleanProperty(False)
font_name = StringProperty(DEFAULT_FONT)
font_name = StringProperty(Theme.DEFAULT_FONT)
disabled = BooleanProperty(False)
tri_state = BooleanProperty(False)
@@ -426,7 +426,7 @@ class MenuItem(RectangularRippleBehavior, LeftButtonBehavior, MDBoxLayout, Backg
icon = StringProperty("")
text = StringProperty("")
shortcut = StringProperty("")
font_name = StringProperty(DEFAULT_FONT)
font_name = StringProperty(Theme.DEFAULT_FONT)
content_width = NumericProperty(100)
def on_left_release(self):
@@ -466,8 +466,8 @@ class CollapsablePanel(MDBoxLayout):
closed_label = StringProperty("Closed Panel")
state = OptionProperty("open", options=["open", "close"])
close_icon = "img/Previous-5.png"
open_icon = "img/Next-5.png"
close_icon = "Previous-5.png"
open_icon = "Next-5.png"
def __init__(self, **kwargs):
self.open_close_button, self.header = None, None
+10 -9
View File
@@ -29,18 +29,19 @@ from katrain.core.constants import (
OUTPUT_ERROR,
OUTPUT_INFO,
STATUS_INFO,
DATA_FOLDER,
)
from katrain.core.engine import KataGoEngine
from katrain.core.lang import i18n, rank_label
from katrain.core.utils import PATHS, find_package_resource
from katrain.gui.kivyutils import BackgroundMixin, I18NSpinner
from katrain.gui.style import DEFAULT_FONT, EVAL_COLORS
from katrain.gui.theme import Theme
from katrain.gui.widgets.progress_loader import ProgressLoader
class I18NPopup(Popup):
title_key = StringProperty("")
font_name = StringProperty(DEFAULT_FONT)
font_name = StringProperty(Theme.DEFAULT_FONT)
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -326,14 +327,14 @@ class ConfigTeacherPopup(QuickConfigGui):
savesgfs = self.katrain.config("trainer/save_feedback")
show_dots = self.katrain.config("trainer/show_dots")
self.themes_spinner.value_refs = list(EVAL_COLORS.keys())
self.themes_spinner.value_refs = list(Theme.EVAL_COLORS.keys())
self.options_grid.clear_widgets()
for k in ["dot color", "point loss threshold", "num undos", "show dots", "save dots"]:
self.options_grid.add_widget(DescriptionLabel(text=i18n._(k), font_name=i18n.font_name, font_size=dp(17)))
for i, (color, threshold, undo, show_dot, savesgf) in enumerate(
zip(EVAL_COLORS[theme], thresholds, undos, show_dots, savesgfs)
zip(Theme.EVAL_COLORS[theme], thresholds, undos, show_dots, savesgfs)
):
self.add_option_widgets(
[
@@ -420,8 +421,8 @@ class ConfigAIPopup(QuickConfigGui):
class ConfigPopup(QuickConfigGui):
def __init__(self, katrain):
super().__init__(katrain)
self.paths = [self.katrain.config("engine/model"), "katrain/models", "~/.katrain"]
self.katago_paths = [self.katrain.config("engine/katago"), "~/.katrain"]
self.paths = [self.katrain.config("engine/model"), "katrain/models", DATA_FOLDER]
self.katago_paths = [self.katrain.config("engine/katago"), DATA_FOLDER]
Clock.schedule_once(self.check_katas)
MDApp.get_running_app().bind(language=self.check_models)
MDApp.get_running_app().bind(language=self.check_katas)
@@ -560,7 +561,7 @@ class ConfigPopup(QuickConfigGui):
for name, url in self.MODELS.items():
filename = os.path.split(url)[1]
if not any(os.path.split(f)[1] == filename for f in self.model_files.values):
savepath = os.path.expanduser(os.path.join("~/.katrain", filename))
savepath = os.path.expanduser(os.path.join(DATA_FOLDER, filename))
savepath_tmp = savepath + ".part"
self.katrain.log(f"Downloading {name} model from {url} to {savepath_tmp}", OUTPUT_INFO)
progress = ProgressLoader(
@@ -627,8 +628,8 @@ class ConfigPopup(QuickConfigGui):
filename = os.path.split(url)[1]
exe_name = unzipped_name(filename)
if not any(os.path.split(f)[1] == exe_name for f in self.katago_files.values):
savepath_tmp = os.path.expanduser(os.path.join("~/.katrain", filename))
exe_path_name = os.path.expanduser(os.path.join("~/.katrain", exe_name))
savepath_tmp = os.path.expanduser(os.path.join(DATA_FOLDER, filename))
exe_path_name = os.path.expanduser(os.path.join(DATA_FOLDER, exe_name))
self.katrain.log(f"Downloading binary {name} from {url} to {savepath_tmp}", OUTPUT_INFO)
progress = ProgressLoader(
download_url=url,
-82
View File
@@ -1,82 +0,0 @@
def to_hexcol(kivycol):
return "#" + "".join(f"{round(c * 255):02x}" for c in kivycol[:3])
DEFAULT_FONT = "fonts/NotoSansCJKsc-Regular.otf"
# basic color definitions
WHITE = [0.95, 0.95, 0.95, 1]
BLACK = [0.05, 0.05, 0.05, 1]
LIGHTGREY = [0.7, 0.7, 0.7, 1]
GREY = [0.5, 0.5, 0.5, 1]
LIGHTERGREY = [0.85, 0.85, 0.85, 1]
RED = [0.8, 0.1, 0.1, 1]
GREEN = [0.1, 0.8, 0.1, 1]
YELLOW = [0.8, 0.8, 0.1, 1]
DARKRED = [0.3, 0.1, 0.1, 1]
ORANGE = [242 / 255, 96 / 255, 34 / 255, 1]
LIGHT_ORANGE = [1, 0.5, 0.25, 1]
# gui colors
BACKGROUND_COLOR = [36 / 255, 48 / 255, 62 / 255, 1]
BOX_BACKGROUND_COLOR = [46 / 255, 65 / 255, 88 / 255, 1]
LIGHTER_BACKGROUND_COLOR = [64 / 255, 85 / 255, 110 / 255, 1]
TEXT_COLOR = WHITE
SCORE_COLOR = [0.3, 0.7, 0.9, 1]
WINRATE_COLOR = GREEN
POINTLOSS_COLOR = YELLOW
# eval dots
EVAL_COLORS = {
"theme:normal": [
[0.447, 0.129, 0.42, 1],
[0.8, 0, 0, 1],
[0.9, 0.4, 0.1, 1],
[0.95, 0.95, 0, 1],
[0.67, 0.9, 0.18, 1],
[0.117, 0.588, 0, 1],
],
"theme:red-green-colourblind": [
[1, 0, 1, 1],
[1, 0, 0, 1],
[1, 0.5, 0, 1],
[1, 1, 0, 1],
[0, 1, 1, 1],
[0, 0, 1, 1],
],
}
EVAL_DOT_MAX_SIZE = 0.5
EVAL_DOT_MIN_SIZE = 0.25
STONE_COLORS = {"B": BLACK, "W": WHITE}
STONE_CONTRAST_COLORS = {"B": LIGHTERGREY, "W": GREY}
OUTLINE_COLORS = {"B": [0.3, 0.3, 0.3, 0.5], "W": [0.7, 0.7, 0.7, 0.5]}
STONE_TEXT_COLORS = {"W": BLACK, "B": WHITE}
# board
LINE_COLOR = [0, 0, 0]
STARPOINT_SIZE = 0.1
BOARD_COLOR = [0.85, 0.68, 0.40, 1]
STONE_SIZE = 0.505 # texture edge is transparent
GHOST_ALPHA = 0.6
POLICY_ALPHA = 0.5
HINTS_LO_ALPHA = 0.6
HINTS_ALPHA = 0.8
TOP_MOVE_BORDER_COLOR = [10 / 255, 200 / 255, 250 / 255, 1.0]
CHILD_SCALE = 0.95
HINT_SCALE = 0.98
UNCERTAIN_HINT_SCALE = 0.7
# ponder light
ENGINE_DOWN_COL = EVAL_COLORS["theme:normal"][1]
ENGINE_BUSY_COL = EVAL_COLORS["theme:normal"][2]
ENGINE_READY_COL = EVAL_COLORS["theme:normal"][-1]
# info
INFO_PV_COLOR = to_hexcol(YELLOW)
+145
View File
@@ -0,0 +1,145 @@
from kivy.metrics import sp
def to_hexcol(kivycol):
return "#" + "".join(f"{round(c * 255):02x}" for c in kivycol[:3])
# basic colors
WHITE = [0.95, 0.95, 0.95, 1]
BLACK = [0.05, 0.05, 0.05, 1]
LIGHT_GREY = [0.7, 0.7, 0.7, 1]
GREY = [0.5, 0.5, 0.5, 1]
LIGHTER_GREY = [0.85, 0.85, 0.85, 1]
RED = [0.8, 0.1, 0.1, 1]
GREEN = [0.1, 0.8, 0.1, 1]
YELLOW = [0.8, 0.8, 0.1, 1]
ORANGE = [242 / 255, 96 / 255, 34 / 255, 1]
LIGHT_ORANGE = [1, 0.5, 0.25, 1]
BLUE = [0.3, 0.7, 0.9, 1]
class Theme:
# font
DEFAULT_FONT = "fonts/NotoSansCJKsc-Regular.otf"
INPUT_FONT_SIZE = sp(25)
DESC_FONT_SIZE = sp(20)
NOTES_FONT_SIZE = sp(18)
# gui colors
BACKGROUND_COLOR = [36 / 255, 48 / 255, 62 / 255, 1]
BOX_BACKGROUND_COLOR = [46 / 255, 65 / 255, 88 / 255, 1]
LIGHTER_BACKGROUND_COLOR = [64 / 255, 85 / 255, 110 / 255, 1]
SCROLLBAR_COLOR = LIGHT_GREY
TEXT_COLOR = WHITE
SCORE_COLOR = BLUE # blue
WINRATE_COLOR = GREEN # green
POINTLOSS_COLOR = YELLOW # yellow
BUTTON_INACTIVE_COLOR = LIGHT_GREY
BUTTON_BORDER_COLOR = WHITE
BUTTON_TEXT_COLOR = WHITE
PAUSE_ACTIVE_COLOR = ORANGE
TIMER_TEXT_COLOR = GREEN
TIMER_TEXT_TIMEOUT_COLOR = ORANGE
CIRCLE_TEXT_COLORS = {"W": BLACK, "B": WHITE}
NOTES_TAB_FONT_COLOR = YELLOW
INFO_TAB_FONT_COLOR = WHITE
ERROR_BORDER_COLOR = RED
MENU_ITEM_FONT_COLOR = WHITE
MENU_ITEM_SHORTCUT_COLOR = LIGHT_GREY
PLAY_ANALYZE_TAB_COLOR = YELLOW
INPUT_FONT_COLOR = WHITE
# gui spacing
CP_SPACING = 6
CP_SMALL_SPACING = 3
CP_PADDING = 6
# textures
STONE_TEXTURE = {"B": "B_stone.png", "W": "W_stone.png"}
EVAL_DOT_TEXTURE = "dot.png"
LAST_MOVE_TEXTURE = "inner.png"
TOP_MOVE_TEXTURE = "topmove.png"
BOARD_TEXTURE = "board.png"
GRAPH_TEXTURE = "graph_bg.png"
# sounds
STONE_SOUNDS = [f"stone{i}.wav" for i in [1, 2, 3, 4, 5]]
# eval dots
EVAL_COLORS = {
"theme:normal": [
[0.447, 0.129, 0.42, 1],
[0.8, 0, 0, 1],
[0.9, 0.4, 0.1, 1],
[0.95, 0.95, 0, 1],
[0.67, 0.9, 0.18, 1],
[0.117, 0.588, 0, 1],
],
"theme:red-green-colourblind": [
[1, 0, 1, 1],
[1, 0, 0, 1],
[1, 0.5, 0, 1],
[1, 1, 0, 1],
[0, 1, 1, 1],
[0, 0, 1, 1],
],
}
EVAL_DOT_MAX_SIZE = 0.5
EVAL_DOT_MIN_SIZE = 0.25
# board theme
APPROX_BOARD_COLOR = [0.95, 0.75, 0.47, 1] # for drawing on top of / hiding what's under it
BOARD_COLOR_TINT = [1, 0.95, 0.8, 1] # multiplied by texture
HINT_TEXT_COLOR = BLACK
REGION_BORDER_COLOR = LIGHTER_BACKGROUND_COLOR
INSERT_BOARD_COLOR_TINT = [1, 1, 1, 0.75]
PASS_CIRCLE_COLOR = [0.45, 0.05, 0.45, 0.7]
PASS_CIRCLE_TEXT_COLOR = [0.85, 0.85, 0.85]
STONE_COLORS = {"B": BLACK, "W": WHITE}
NEXT_MOVE_DASH_CONTRAST_COLORS = {"B": LIGHTER_GREY, "W": GREY}
OUTLINE_COLORS = {"B": [0.3, 0.3, 0.3, 0.5], "W": [0.7, 0.7, 0.7, 0.5]}
PV_TEXT_COLORS = {"W": BLACK, "B": WHITE} # numbers in PV
# board
LINE_COLOR = [0, 0, 0]
STARPOINT_SIZE = 0.1
BOARD_COLOR = [0.85, 0.68, 0.40, 1]
STONE_SIZE = 0.505 # texture edge is transparent
GHOST_ALPHA = 0.6
POLICY_ALPHA = 0.5
HINTS_LO_ALPHA = 0.6
HINTS_ALPHA = 0.8
TOP_MOVE_BORDER_COLOR = [10 / 255, 200 / 255, 250 / 255, 1.0]
CHILD_SCALE = 0.95
HINT_SCALE = 0.98
UNCERTAIN_HINT_SCALE = 0.7
# ponder light
ENGINE_DOWN_COLOR = EVAL_COLORS["theme:normal"][1]
ENGINE_BUSY_COLOR = EVAL_COLORS["theme:normal"][2]
ENGINE_READY_COLOR = EVAL_COLORS["theme:normal"][-1]
ENGINE_PONDERING_COLOR = YELLOW
# info PV link
INFO_PV_COLOR = to_hexcol(YELLOW)
# graph
GRAPH_DOT_COLOR = [0.85, 0.3, 0.3, 1]
WINRATE_MARKER_COLOR = [0.05, 0.7, 0.05, 1]
SCORE_MARKER_COLOR = [0.2, 0.6, 0.8, 1]
# move tree
MOVE_TREE_LINE = LIGHT_GREY
MOVE_TREE_CURRENT = YELLOW
MOVE_TREE_SELECTED = RED
MOVE_TREE_INSERT_NODE_PARENT = GREEN
MOVE_TREE_INSERT_CURRENT = ORANGE
MOVE_TREE_INSERT_OTHER = LIGHT_ORANGE
MOVE_TREE_COLLAPSED = LIGHT_GREY
MOVE_TREE_STONE_OUTLINE_COLORS = {"W": BLACK, "B": WHITE}
+2 -2
View File
@@ -51,7 +51,7 @@ from kivy.uix.filechooser import FileChooserListLayout, FileChooserListView
from kivy.uix.treeview import TreeView, TreeViewLabel
from kivy.utils import platform
from katrain.gui.style import DEFAULT_FONT
from katrain.gui.theme import Theme
if platform == "win":
from ctypes import windll, create_unicode_buffer
@@ -106,7 +106,7 @@ def get_drives():
class I18NFileChooserListView(FileChooserListView):
font_name = StringProperty(DEFAULT_FONT)
font_name = StringProperty(Theme.DEFAULT_FONT)
show_hidden = BooleanProperty(True) # avoid errors
+14 -23
View File
@@ -7,10 +7,12 @@ from kivy.properties import BooleanProperty, Clock, ListProperty, NumericPropert
from kivy.uix.widget import Widget
from kivymd.app import MDApp
from katrain.gui.theme import Theme
class Graph(Widget):
marker_font_size = NumericProperty(0)
background_image = StringProperty("img/graph_bg.png")
background_image = StringProperty(Theme.GRAPH_TEXTURE)
background_color = ListProperty([1, 1, 1, 1])
highlighted_index = NumericProperty(0)
nodes = ListProperty([])
@@ -157,21 +159,10 @@ class ScoreGraph(Graph):
Builder.load_string(
"""
#:set GRAPH_CENTER_COLOR [0.5,0.5,0.5]
#:set GRAPH_DOT_COLOR [0.85,0.3,0.3,1]
#:set WINRATE_MARKER_COLOR [0.05, 0.7, 0.05, 1]
#:set SCORE_MARKER_COLOR [0.2, 0.6, 0.8, 1]
#:import LIGHTER_BACKGROUND_COLOR katrain.gui.style.LIGHTER_BACKGROUND_COLOR
#:import BOX_BACKGROUND_COLOR katrain.gui.style.BOX_BACKGROUND_COLOR
#:import SCORE_COLOR katrain.gui.style.SCORE_COLOR
#:import WINRATE_COLOR katrain.gui.style.WINRATE_COLOR
#:import BLACK katrain.gui.style.BLACK
#:import WHITE katrain.gui.style.WHITE
#:import YELLOW katrain.gui.style.YELLOW
#:import Theme katrain.gui.theme.Theme
<Graph>:
background_color: BOX_BACKGROUND_COLOR
background_color: Theme.BOX_BACKGROUND_COLOR
marker_font_size: 0.1 * self.height
canvas.before:
Color:
@@ -189,12 +180,12 @@ Builder.load_string(
<ScoreGraph>:
canvas:
Color:
rgba: SCORE_COLOR
rgba: Theme.SCORE_COLOR
Line:
points: root.score_points if root.show_score else []
width: dp(1.1)
Color:
rgba: WINRATE_COLOR
rgba: Theme.WINRATE_COLOR
Line:
points: root.winrate_points if root.show_winrate else []
width: dp(1.1)
@@ -204,13 +195,13 @@ Builder.load_string(
points: root.navigate_move[1], root.y, root.navigate_move[1], root.y+root.height
width: 1
Color:
rgba: GRAPH_DOT_COLOR
rgba: Theme.GRAPH_DOT_COLOR
Ellipse:
id: score_dot
pos: [c - self.highlight_size / 2 for c in (self.score_dot_pos if not self.navigate_move[0] else [self.navigate_move[1],self.navigate_move[2]] ) ]
size: (self.highlight_size,self.highlight_size) if root.show_score else (0.0001,0.0001)
Color:
rgba: GRAPH_DOT_COLOR
rgba: Theme.GRAPH_DOT_COLOR
Ellipse:
id: winrate_dot
pos: [c - self.highlight_size / 2 for c in (self.winrate_dot_pos if not self.navigate_move[0] else [self.navigate_move[1],self.navigate_move[3]] ) ]
@@ -218,32 +209,32 @@ Builder.load_string(
# score ticks
GraphMarkerLabel:
font_size: root.marker_font_size
color: SCORE_MARKER_COLOR
color: Theme.SCORE_MARKER_COLOR
pos: root.x + root.width - self.width-1, root.pos[1]+root.height - self.font_size - 1
text: 'B+{}'.format(root.score_scale)
opacity: int(root.show_score)
GraphMarkerLabel:
font_size: root.marker_font_size
color: SCORE_MARKER_COLOR
color: Theme.SCORE_MARKER_COLOR
pos: root.x + root.width - self.width-1, root.y + root.height*0.5 - self.height/2 + 2
text: i18n._('Jigo')
opacity: int(root.show_score)
GraphMarkerLabel:
font_size: root.marker_font_size
color: SCORE_MARKER_COLOR
color: Theme.SCORE_MARKER_COLOR
pos: root.x + root.width - self.width-1, root.pos[1]
text: 'W+' + str(int(root.score_scale))
opacity: int(root.show_score)
# wr ticks
GraphMarkerLabel:
font_size: root.marker_font_size
color: WINRATE_MARKER_COLOR
color: Theme.WINRATE_MARKER_COLOR
pos: root.pos[0]+1, root.pos[1] + root.height - self.font_size - 1
text: "{}%".format(50 + root.winrate_scale)
opacity: int(root.show_winrate)
GraphMarkerLabel:
font_size: root.marker_font_size
color: WINRATE_MARKER_COLOR
color: Theme.WINRATE_MARKER_COLOR
pos:root.pos[0]+1, root.pos[1]
text: "{}%".format(50 - root.winrate_scale)
opacity: int(root.show_winrate)
+23 -18
View File
@@ -11,7 +11,7 @@ from kivy.uix.widget import Widget
from kivymd.app import MDApp
from katrain.gui.kivyutils import BackgroundMixin, draw_circle, draw_text
from katrain.gui.style import GREEN, LIGHT_ORANGE, LIGHTGREY, ORANGE, RED, STONE_COLORS, STONE_TEXT_COLORS, YELLOW
from katrain.gui.theme import Theme
class MoveTreeDropdown(DropDown):
@@ -155,8 +155,8 @@ class MoveTreeCanvas(Widget):
stack += children[move][::-1] # stack, so push top child last to process first
def draw_stone(pos, player, special_color=None):
draw_circle(pos, self.move_size / 2 - 0.5, (special_color or STONE_COLORS[player]))
Color(*STONE_TEXT_COLORS[player])
draw_circle(pos, self.move_size / 2 - 0.5, (special_color or Theme.STONE_COLORS[player]))
Color(*Theme.MOVE_TREE_STONE_OUTLINE_COLORS[player])
Line(circle=(*pos, self.move_size / 2), width=1)
def coord_pos(coord):
@@ -170,18 +170,20 @@ class MoveTreeCanvas(Widget):
self.move_xy_pos = {n: xy_pos(x, y) for n, (x, y) in self.move_pos.items()}
special_nodes = {current_node: YELLOW, self.menu_selected_node: RED}
special_nodes = {current_node: Theme.MOVE_TREE_CURRENT, self.menu_selected_node: Theme.MOVE_TREE_SELECTED}
if insert_node:
special_nodes[insert_node.parent] = GREEN
special_nodes[insert_node.parent] = Theme.MOVE_TREE_INSERT_NODE_PARENT
insert_path = current_node
while insert_path != insert_node.parent and insert_path.parent:
special_nodes[insert_path] = ORANGE if insert_path == current_node else LIGHT_ORANGE
special_nodes[insert_path] = (
Theme.MOVE_TREE_INSERT_CURRENT if insert_path == current_node else Theme.MOVE_TREE_INSERT_OTHER
)
insert_path = insert_path.parent
with self.canvas:
self.canvas.clear()
Color(*LIGHTGREY)
Color(*Theme.MOVE_TREE_LINE)
for node, (x, y) in self.move_xy_pos.items():
for ci, c in enumerate(children[node]):
cx, cy = self.move_xy_pos[c]
@@ -194,10 +196,10 @@ class MoveTreeCanvas(Widget):
pos=[c - self.move_size / 2 - spacing / 2 for c in self.move_xy_pos[node]],
size=(self.move_size + spacing, self.move_size + spacing),
)
collapsed_color = LIGHTGREY if node.shortcut_from else None
collapsed_color = Theme.MOVE_TREE_COLLAPSED if node.shortcut_from else None
draw_stone(pos, node.player, collapsed_color)
text = str(node.depth)
Color(*STONE_COLORS["W" if node.player == "B" and not node.shortcut_from else "B"])
Color(*Theme.STONE_COLORS["W" if node.player == "B" and not node.shortcut_from else "B"])
draw_text(pos=pos, text=text, font_size=self.move_size * 1.75 / (1 + 1 * len(text)), font_name="Roboto")
if current_node in self.move_xy_pos:
@@ -245,8 +247,11 @@ class MoveTree(ScrollView, BackgroundMixin):
Builder.load_string(
"""
#:import Theme katrain.gui.theme.Theme
#:import WHITE katrain.gui.theme.WHITE
#:import LIGHT_GREY katrain.gui.theme.LIGHT_GREY
<MoveTree>:
background_color: BOX_BACKGROUND_COLOR
background_color: Theme.BOX_BACKGROUND_COLOR
move_tree_canvas: move_tree_canvas
scroll_distance: 0 # scroll wheel is for forward/backward
MoveTreeCanvas:
@@ -261,7 +266,7 @@ Builder.load_string(
Line:
points: self.x, self.y, self.x, self.y+self.height
Color:
rgba: LIGHTGREY
rgba: LIGHT_GREY
Line
points: self.x,self.y,self.x+self.width,self.y
width: 1
@@ -270,27 +275,27 @@ Builder.load_string(
katrain: app.gui
MoveTreeDropdownItem:
text: i18n._("Delete Node")
icon: 'img/delete.png'
icon: 'delete.png'
shortcut: 'Ctrl+Del'
on_action: root.katrain.controls.move_tree.delete_selected_node()
-background_color: LIGHTER_BACKGROUND_COLOR
-background_color: Theme.LIGHTER_BACKGROUND_COLOR
-height: dp(45)
-width_margin: 1.6
MoveTreeDropdownItem:
text: i18n._("Make Main Branch")
icon: 'img/Branch.png'
icon: 'Branch.png'
shortcut: 'PgUp'
on_action: root.katrain.controls.move_tree.make_selected_node_main_branch()
-background_color: LIGHTER_BACKGROUND_COLOR
-background_color: Theme.LIGHTER_BACKGROUND_COLOR
-height: dp(45)
-width_margin: 1.6
MoveTreeDropdownItem:
text: i18n._("Toggle Collapse Branch")
icon: 'img/Collapse.png'
icon: 'Collapse.png'
shortcut: 'c'
on_action: root.katrain.controls.move_tree.toggle_selected_node_collapse()
-background_color: LIGHTER_BACKGROUND_COLOR
-background_color: Theme.LIGHTER_BACKGROUND_COLOR
-height: dp(45)
-width_margin: 1.6
"""
"""
)
File renamed without changes.
File renamed without changes.
+33 -37
View File
@@ -4,16 +4,12 @@
#:import abspath os.path.abspath
#:import kivy_version kivy.__version__
#:set CP_SPACING 6
#:set CP_SMALL_SPACING 3
#:set CP_PADDING 6
#:import Theme katrain.gui.theme.Theme
#:import LIGHT_GREY katrain.gui.theme.LIGHT_GREY
#:set INPUT_FONT_SIZE sp(25)
#:set DESC_FONT_SIZE sp(20)
#:import BACKGROUND_COLOR katrain.gui.style.BACKGROUND_COLOR
#:import LIGHTGREY katrain.gui.style.LIGHTGREY
#:import TEXT_COLOR katrain.gui.style.TEXT_COLOR
#:set CP_SPACING Theme.CP_SPACING
#:set CP_SMALL_SPACING Theme.CP_SMALL_SPACING
#:set CP_PADDING Theme.CP_PADDING
#:import TOP_MOVE_OPTIONS katrain.core.constants.TOP_MOVE_OPTIONS
@@ -22,15 +18,15 @@
# hint_text: "Helper text on focus"
# helper_text: "This will disappear when you click off"
# helper_text_mode: "on_focus"
# font_size: INPUT_FONT_SIZE
# font_size: Theme.INPUT_FONT_SIZE
<LabelledTextInput>:
font_size: INPUT_FONT_SIZE
font_size: Theme.INPUT_FONT_SIZE
helper_text_mode: "none"
hint_text: ""
helper_text: ""
color_mode: 'custom'
line_color_focus: TEXT_COLOR
line_color_focus: Theme.TEXT_COLOR
<LabelledPathInput>:
font_size: sp(16)
@@ -39,27 +35,27 @@
helper_text: i18n._("file not found")
<LabelledIntInput>:
font_size: INPUT_FONT_SIZE
font_size: Theme.INPUT_FONT_SIZE
size_hint: 0.5, None
<LabelledFloatInput>:
font_size: INPUT_FONT_SIZE
font_size: Theme.INPUT_FONT_SIZE
size_hint: 0.5, None
<LabelledCheckBox>:
size: DESC_FONT_SIZE*2,DESC_FONT_SIZE*2
size: Theme.DESC_FONT_SIZE*2,Theme.DESC_FONT_SIZE*2
size_hint: None,None
<QuickInputButton@SizedRectangleButton>
on_left_press: if self.target: self.target.text = self.text
size: DESC_FONT_SIZE * 2, DESC_FONT_SIZE * 2
font_size: DESC_FONT_SIZE
size: Theme.DESC_FONT_SIZE * 2, Theme.DESC_FONT_SIZE * 2
font_size: Theme.DESC_FONT_SIZE
<I18NPopup>:
background_color: BACKGROUND_COLOR
background_color: Theme.BACKGROUND_COLOR
background: self.background if kivy_version < '2.0' else ''
title: i18n._(self.title_key)
title_size: DESC_FONT_SIZE
title_size: Theme.DESC_FONT_SIZE
title_font: self.font_name
size_hint: None, None
@@ -69,14 +65,14 @@
padding: 4*CP_PADDING,CP_PADDING, 4*CP_PADDING, CP_PADDING
<DescriptionLabel>:
font_size: DESC_FONT_SIZE
font_size: Theme.DESC_FONT_SIZE
multiline: True
text_size: self.width, None
halign: 'center'
valign: 'center'
<SmallDescriptionLabel@DescriptionLabel>
font_size: DESC_FONT_SIZE * 0.66
font_size: Theme.DESC_FONT_SIZE * 0.66
<ConfigPopup>:
configfile: configfile
@@ -88,7 +84,7 @@
katago_download_progress_box: katago_download_progress_box
DescriptionLabel:
text: i18n._('katago settings')
font_size: DESC_FONT_SIZE * 1.5
font_size: Theme.DESC_FONT_SIZE * 1.5
GridLayout:
cols: 2
rows: 6
@@ -123,7 +119,7 @@
size_hint_y: 0.7
sync_height_frac: 1.0
-font_size: self.height * 0.5
-background_color: [*[c*255/88 for c in BOX_BACKGROUND_COLOR[:3]], 1] # compensate for texture
-background_color: [*[c*255/88 for c in Theme.BOX_BACKGROUND_COLOR[:3]], 1] # compensate for texture
DescriptionLabel:
text: i18n._("engine:config")
size_hint: 0.33, 1
@@ -158,7 +154,7 @@
size_hint_y: 0.7
sync_height_frac: 1.0
-font_size: self.height * 0.5
-background_color: [*[c*255/88 for c in BOX_BACKGROUND_COLOR[:3]], 1] # compensate for texture
-background_color: [*[c*255/88 for c in Theme.BOX_BACKGROUND_COLOR[:3]], 1] # compensate for texture
DescriptionLabel:
text: i18n._("engine:altcommand")
size_hint: 0.33, 1
@@ -171,9 +167,9 @@
orientation: 'horizontal'
DescriptionLabel:
text: i18n._('general settings')
font_size: DESC_FONT_SIZE * 1.5
font_size: Theme.DESC_FONT_SIZE * 1.5
DescriptionLabel:
font_size: DESC_FONT_SIZE * 1.5
font_size: Theme.DESC_FONT_SIZE * 1.5
text: i18n._('engine settings')
BoxLayout:
size_hint: 1,5
@@ -206,7 +202,7 @@
id: configfile
text: app.gui.config_file
BackgroundMixin:
background_color: LIGHTGREY
background_color: LIGHT_GREY
size_hint: None, 1
width: 2
GridLayout:
@@ -281,7 +277,7 @@
padding: 4
size_hint: 0.95, 1
DescriptionLabel:
font_size: DESC_FONT_SIZE * 0.8
font_size: Theme.DESC_FONT_SIZE * 0.8
text: i18n._("theme")
AnchorLayout:
LabelledSpinner:
@@ -289,7 +285,7 @@
input_property: 'trainer/theme'
id: themes_spinner
DescriptionLabel:
font_size: DESC_FONT_SIZE * 0.8
font_size: Theme.DESC_FONT_SIZE * 0.8
text: i18n._("stats on top move")
AnchorLayout:
BoxLayout:
@@ -307,19 +303,19 @@
value_refs: TOP_MOVE_OPTIONS
input_property: "trainer/top_moves_show_secondary"
DescriptionLabel:
font_size: DESC_FONT_SIZE * 0.8
font_size: Theme.DESC_FONT_SIZE * 0.8
text: i18n._("show stats if")
AnchorLayout:
LabelledIntInput:
input_property: "trainer/low_visits"
DescriptionLabel:
font_size: DESC_FONT_SIZE * 0.8
font_size: Theme.DESC_FONT_SIZE * 0.8
text: i18n._("show ai dots")
AnchorLayout:
LabelledCheckBox:
input_property: "trainer/eval_show_ai"
DescriptionLabel:
font_size: DESC_FONT_SIZE * 0.8
font_size: Theme.DESC_FONT_SIZE * 0.8
text: i18n._("cache analysis to sgf")
AnchorLayout:
LabelledCheckBox:
@@ -472,7 +468,7 @@
LabelledSpinner:
size_hint: 0.8,0.8
input_property: 'game/rules'
font_size: DESC_FONT_SIZE
font_size: Theme.DESC_FONT_SIZE
id: rules_spinner
Label:
DescriptionLabel:
@@ -509,7 +505,7 @@
size_hint: 2.25,1
values: root.values
on_change: textbox.text = str(slider.value)
track_color: LIGHTGREY
track_color: LIGHT_GREY
thumb_color: (0.6, 0.7, 0.9, 1) if root.key_option else (0.3, 0.4, 0.6, 1)
LabelledFloatInput:
id: textbox
@@ -522,7 +518,7 @@
BoxLayout:
size_hint: 1,1
DescriptionLabel:
font_size: DESC_FONT_SIZE
font_size: Theme.DESC_FONT_SIZE
text: i18n._('Select AI')
AnchorLayout:
I18NSpinner:
@@ -531,12 +527,12 @@
BoxLayout:
size_hint: 1,1
DescriptionLabel:
font_size: DESC_FONT_SIZE
font_size: Theme.DESC_FONT_SIZE
size_hint: 1, 1
text: i18n._('estimated strength')
DescriptionLabel:
size_hint: 0.8, 1
font_size: DESC_FONT_SIZE
font_size: Theme.DESC_FONT_SIZE
id: estimated_rank_label
text: '?' + i18n._('strength:kyu')
SmallDescriptionLabel: