diff --git a/katrain/__main__.py b/katrain/__main__.py index 4c87a22..77d3daa 100644 --- a/katrain/__main__.py +++ b/katrain/__main__.py @@ -147,7 +147,7 @@ class KaTrainGui(Screen, KaTrainBase): self.controls.update_players() self.update_state() for player_setup_block in PlayerSetupBlock.INSTANCES: - player_setup_block.update_players(bw,self.players_info[bw]) + player_setup_block.update_players(bw, self.players_info[bw]) def set_note(self, note): self.game.current_node.note = note @@ -215,7 +215,7 @@ class KaTrainGui(Screen, KaTrainBase): def _do_new_game_popup(self): self.controls.timer.paused = True if not self.new_game_popup: - self.new_game_popup = I18NPopup(title_key="New Game title", size_hint=(0.5, 0.6), content=NewGamePopup(self)).__self__ + self.new_game_popup = I18NPopup(title_key="New Game title", size=[800, 800], content=NewGamePopup(self)).__self__ self.new_game_popup.content.popup = self.new_game_popup self.new_game_popup.open() @@ -226,6 +226,13 @@ class KaTrainGui(Screen, KaTrainBase): self.timer_settings_popup.content.popup = self.timer_settings_popup self.timer_settings_popup.open() + def _do_teacher_popup(self): + self.controls.timer.paused = True + if not self.teacher_settings_popup: + self.teacher_settings_popup = I18NPopup(title_key="teacher settings", size=[800, 800], content=ConfigTeacherPopup(self)).__self__ + self.teacher_settings_popup.content.popup = self.teacher_settings_popup + self.teacher_settings_popup.open() + # todo pop def _do_analyze_sgf_popup(self): @@ -264,13 +271,6 @@ class KaTrainGui(Screen, KaTrainBase): self.ai_settings_popup.add_widget(ConfigAIPopupContents(self, self.ai_settings_popup)) self.ai_settings_popup.open() - def _do_teacher_popup(self): - self.controls.timer.paused = True - if not self.teacher_settings_popup: - self.teacher_settings_popup = I18NPopup(title_key="Edit Teacher Settings", size_hint=(0.7, 0.8)).__self__ - self.teacher_settings_popup.add_widget(ConfigTeacherPopup(self, self.teacher_settings_popup)) - self.teacher_settings_popup.open() - def _do_output_sgf(self): for pl in Move.PLAYERS: if not self.game.root.get_property(f"P{pl}"): diff --git a/katrain/config.json b/katrain/config.json index f16db5a..0a381f2 100644 --- a/katrain/config.json +++ b/katrain/config.json @@ -12,10 +12,6 @@ "_hint_wide_root_noise": "A higher value here (typically 0.05-0.1)\nmakes the analysis explore more moves\nat the cost of some strength.", "_enable_ownership": true }, - "timer": { - "byo_length": 30, - "byo_periods": 5 - }, "general": { "sgf_load": "~/Downloads", "sgf_save": "./sgfout", @@ -23,6 +19,10 @@ "debug_level": 1, "language": "en" }, + "timer": { + "byo_length": 30, + "byo_periods": 5 + }, "game": { "size": "19", "komi": 6.5, @@ -55,6 +55,14 @@ true, true ], + "show_dots": [ + true, + true, + true, + true, + true, + true + ], "eval_off_show_last": 3, "eval_show_ai": true, "lock_ai": false diff --git a/katrain/core/base_katrain.py b/katrain/core/base_katrain.py index 45a5d87..611befb 100644 --- a/katrain/core/base_katrain.py +++ b/katrain/core/base_katrain.py @@ -90,7 +90,6 @@ class KaTrainBase: except KeyError: self.log(f"Missing configuration option {setting}", OUTPUT_ERROR) - def update_player(self, bw, **kwargs): self.players_info[bw].update(**kwargs) @@ -100,7 +99,6 @@ class KaTrainBase: for v in self.players_info.values(): v.periods_used = 0 - @property def last_player_info(self) -> Player: return self.players_info[self.game.current_node.player] @@ -108,4 +106,3 @@ class KaTrainBase: @property def next_player_info(self) -> Player: return self.players_info[self.game.current_node.next_player] - diff --git a/katrain/core/game.py b/katrain/core/game.py index b761463..8bad811 100644 --- a/katrain/core/game.py +++ b/katrain/core/game.py @@ -246,7 +246,7 @@ class Game: if eval_thresholds is None: eval_thresholds = self.katrain.config("trainer/eval_thresholds") - player_names = {bw: re.sub(r"['<>:\"/\\|?*]", "", self.root.get_property("P"+bw) or str(self.katrain.players_info[bw])) for bw in "BW" } + player_names = {bw: re.sub(r"['<>:\"/\\|?*]", "", self.root.get_property("P" + bw) or str(self.katrain.players_info[bw])) for bw in "BW"} game_name = f"katrain_{player_names['B']} vs {player_names['W']} {self.game_id}" file_name = os.path.abspath(os.path.join(path, f"{game_name}.sgf")) os.makedirs(os.path.dirname(file_name), exist_ok=True) diff --git a/katrain/gui.kv b/katrain/gui.kv index f34574a..15e9e55 100644 --- a/katrain/gui.kv +++ b/katrain/gui.kv @@ -903,13 +903,7 @@ spacing: 3*CP_SPACING padding: CP_PADDING height: (self.parent.item_height or 50) * 5 - players: {'B':black,'W':white} - PlayerSetup: - player: 'B' - id: black - PlayerSetup: - player: 'W' - id: white + : katrain: app.gui @@ -921,6 +915,7 @@ text: i18n._('menu:playersetup') PlayerSetupBlock: id: player_setup + update_global: True MenuLabel: size_hint: 1,1 MenuLabel: diff --git a/katrain/gui/badukpan.py b/katrain/gui/badukpan.py index 1f6cb4b..2e9d76a 100644 --- a/katrain/gui/badukpan.py +++ b/katrain/gui/badukpan.py @@ -1,6 +1,7 @@ import copy import math import time +from typing import List, Optional from kivy.clock import Clock from kivy.graphics.context_instructions import Color @@ -136,7 +137,7 @@ class BadukPanWidget(Widget): self.draw_hover_contents() # remove ghost # drawing functions - def redraw(self,*_args): + def redraw(self, *_args): self.draw_board() self.draw_board_contents() @@ -155,10 +156,10 @@ class BadukPanWidget(Widget): Color(*innercol) Line(circle=(self.gridpos_x[x], self.gridpos_y[y], stone_size * 0.475 / 0.85), width=0.1 * stone_size) - def eval_color(self, points_lost): - colors = EVAL_COLORS + 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"]) - return colors[i] + if show_dots_for_class is None or show_dots_for_class[i]: + return EVAL_COLORS[i] def draw_board(self, *_args): if not (self.katrain and self.katrain.game): @@ -236,8 +237,11 @@ class BadukPanWidget(Widget): has_stone[m.coords] = m.player show_dots_for = {p: self.trainer_config["eval_show_ai"] or katrain.game.players[p].human for p in Move.PLAYERS} + show_dots_for_class = self.trainer_config["show_dots"] nodes = katrain.game.current_node.nodes_from_root realized_points_lost = None + + katrain.config("teacher/show_dots") for i, node in enumerate(nodes[::-1]): # reverse order! points_lost = node.points_lost evalsize = 1 @@ -250,7 +254,7 @@ class BadukPanWidget(Widget): if has_stone.get(m.coords) and not drawn_stone.get(m.coords): # skip captures, last only for move_eval_on = show_dots_for.get(m.player) and (i < show_n_eval or full_eval_on) if move_eval_on and points_lost is not None: - evalcol = self.eval_color(points_lost) + evalcol = self.eval_color(points_lost, show_dots_for_class) else: evalcol = None inner = stone_color[m.opponent] if i == 0 else None diff --git a/katrain/gui/kivyutils.py b/katrain/gui/kivyutils.py index 07f9506..26ca850 100644 --- a/katrain/gui/kivyutils.py +++ b/katrain/gui/kivyutils.py @@ -228,18 +228,6 @@ class StyledSpinner(Spinner): item.font_name = self.font_name -class PlayerSetupBlock(MDBoxLayout): - players = ObjectProperty(None) - INSTANCES = [] - - def __init__(self, **kwargs): - super().__init__(**kwargs) - PlayerSetupBlock.INSTANCES.append(self) - - def update_players(self, bw, player_info): # update sub widget based on gui state change - self.players[bw].update_widget(player_type=player_info.player_type, player_subtype=player_info.player_subtype) - - class PlayerSetup(MDBoxLayout): player = OptionProperty("B", options=["B", "W"]) @@ -267,9 +255,30 @@ class PlayerSetup(MDBoxLayout): self.player_subtype.select_key(player_subtype) # should trigger setup options def update_global_player_info(self): - katrain = MDApp.get_running_app().gui - if katrain.game and katrain.game.current_node: - katrain.update_player(self.player, **self.player_type_dump) + if self.parent and self.parent.update_global: + katrain = MDApp.get_running_app().gui + if katrain.game and katrain.game.current_node: + katrain.update_player(self.player, **self.player_type_dump) + + +class PlayerSetupBlock(MDBoxLayout): + players = ObjectProperty(None) + black = ObjectProperty(None) + white = ObjectProperty(None) + update_global = BooleanProperty(False) + INSTANCES = [] + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.black = PlayerSetup(player="B") + self.white = PlayerSetup(player="W") + self.players = {"B": self.black, "W": self.white} + self.add_widget(self.black) + self.add_widget(self.white) + PlayerSetupBlock.INSTANCES.append(self) + + def update_players(self, bw, player_info): # update sub widget based on gui state change + self.players[bw].update_widget(player_type=player_info.player_type, player_subtype=player_info.player_subtype) class PlayerInfo(MDBoxLayout, BackgroundMixin): diff --git a/katrain/gui/popups.py b/katrain/gui/popups.py index 7618eaf..cbef7cb 100644 --- a/katrain/gui/popups.py +++ b/katrain/gui/popups.py @@ -1,22 +1,21 @@ from collections import defaultdict -from typing import Dict, List, DefaultDict, Tuple import re +from typing import Dict, Tuple, Any, Union, List from kivy.clock import Clock from kivy.properties import StringProperty, BooleanProperty +from kivy.uix.anchorlayout import AnchorLayout from kivy.uix.boxlayout import BoxLayout -from kivy.uix.gridlayout import GridLayout -from kivy.uix.label import Label from kivy.uix.popup import Popup from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.selectioncontrol import MDCheckbox from kivymd.uix.textfield import MDTextField -from katrain.core.constants import OUTPUT_ERROR, OUTPUT_DEBUG +from katrain.core.constants import OUTPUT_ERROR, OUTPUT_DEBUG, OUTPUT_INFO from katrain.core.engine import KataGoEngine -from katrain.core.game import Game, GameNode -from katrain.gui.kivyutils import StyledSpinner -from katrain.gui.style import DEFAULT_FONT +from katrain.core.utils import i18n +from katrain.gui.kivyutils import StyledSpinner, BackgroundMixin +from katrain.gui.style import DEFAULT_FONT, EVAL_COLORS class I18NPopup(Popup): @@ -98,7 +97,7 @@ class QuickConfigGui(MDBoxLayout): self.popup = None Clock.schedule_once(lambda _dt: self.set_properties(self)) - def collect_properties(self, widget): + def collect_properties(self, widget) -> Dict: if isinstance(widget, (LabelledTextInput, LabelledSpinner, LabelledCheckBox)) and getattr(widget, "input_property", None): try: ret = {widget.input_property: widget.input_value} @@ -111,17 +110,23 @@ class QuickConfigGui(MDBoxLayout): ret[k] = v return ret - def get_setting(self, key): + def get_setting(self, key) -> Tuple[Any,Union[Dict,List],str]: keys = key.split("/") config = self.katrain._config for k in keys[:-1]: if k not in config: config[k] = {} config = config[k] - if keys[-1] not in config: - config[keys[-1]] = "" - self.katrain.log(f"Configuration setting {repr(key)} was missing, created it, but this likely indicates a broken config file.", OUTPUT_ERROR) - return config[keys[-1]], config, keys[-1] + + if "::" in keys[-1]: + arraykey, ix = keys[-1].split("::") + array = config[arraykey] + return array[int(ix)], array, ix + else: + if keys[-1] not in config: + config[keys[-1]] = "" + self.katrain.log(f"Configuration setting {repr(key)} was missing, created it, but this likely indicates a broken config file.", OUTPUT_ERROR) + return config[keys[-1]], config, keys[-1] def set_properties(self, widget): if isinstance(widget, (LabelledTextInput, LabelledSpinner, LabelledCheckBox)) and getattr(widget, "input_property", None): @@ -146,7 +151,7 @@ class QuickConfigGui(MDBoxLayout): old_value, conf, key = self.get_setting(multikey) if value != old_value: self.katrain.log(f"Updating setting {multikey} = {value}", OUTPUT_DEBUG) - conf[key] = value # reference straight back to katrain._config + conf[key] = value # reference straight back to katrain._config - may be array or dict updated.add(multikey) if save_to_file: self.katrain.save_config() @@ -158,9 +163,6 @@ class QuickConfigGui(MDBoxLayout): class ConfigTimerPopup(QuickConfigGui): - def __init__(self, katrain): - super().__init__(katrain) - def update_config(self, save_to_file=True): super().update_config(save_to_file=save_to_file) for p in self.katrain.players_info.values(): @@ -176,98 +178,66 @@ class NewGamePopup(QuickConfigGui): self.rules_spinner.value_refs = [name for abbr, name in katrain.engine.RULESETS_ABBR] def update_config(self, save_to_file=True): - updated = super().update_config(save_to_file=save_to_file) + super().update_config(save_to_file=save_to_file) self.katrain.log(f"New game settings: {self.katrain.config('game')}", OUTPUT_DEBUG) if self.restart.active: self.katrain.log("Restarting Engine", OUTPUT_DEBUG) self.katrain.engine.restart() + for bw, player_setup in self.player_setup.players.items(): + self.katrain.update_player(bw, **player_setup.player_type_dump) self.katrain("new-game") - # for bw, player_widget in self.nav_drawer_contents.player_setup.players.items(): - # self.players[bw].update(**player_widget.player_def) + +def wrap_anchor(widget): + anchor = AnchorLayout() + anchor.add_widget(widget) + return anchor + + +class ConfigTeacherPopup(QuickConfigGui): + def __init__(self, katrain): + self.build() + super().__init__(katrain) + + def add_option_widgets(self, widgets): + for widget in widgets: + self.options_grid.add_widget(wrap_anchor(widget)) + + def build(self): + undos = self.katrain.config("trainer/num_undo_prompts") + thresholds = self.katrain.config("trainer/eval_thresholds") + savesgfs = self.katrain.config("trainer/save_feedback") + show_dots = self.katrain.config("trainer/show_dots") + + for i, (color, threshold, undo, show_dot, savesgf) in enumerate(zip(EVAL_COLORS, thresholds, undos, show_dots, savesgfs)): + self.add_option_widgets( + [ + BackgroundMixin(background_color=color[:3]), + LabelledFloatInput(text=str(threshold), input_property=f"trainer/eval_thresholds::{i}"), + LabelledFloatInput(text=str(undo), input_property=f"trainer/num_undo_prompts::{i}"), + LabelledCheckBox(text=str(show_dot), input_property=f"trainer/show_dots::{i}"), + LabelledCheckBox(text=str(savesgf), input_property=f"trainer/save_feedback::{i}"), + ] + ) class ConfigPopup(QuickConfigGui): - def __init__(self, katrain, popup: Popup, config: Dict, ignore_cats: Tuple = (), **kwargs): - self.config = config - self.ignore_cats = ignore_cats - self.orientation = "vertical" - super().__init__(katrain, popup, **kwargs) - Clock.schedule_once(self.build, 0) + def update_config(self, save_to_file=True): + updated = super().update_config(save_to_file=save_to_file) + self.katrain.debug_level = self.katrain.config("general/debug_level", OUTPUT_INFO) - def build(self, _): - - props_in_col = [0, 0] - cols = [BoxLayout(orientation="vertical"), BoxLayout(orientation="vertical")] - - for k1, all_d in sorted(self.config.items(), key=lambda tup: -len(tup[1])): # sort to make greedy bin packing work better - if k1 in self.ignore_cats: - continue - d = {k: v for k, v in all_d.items() if isinstance(v, (int, float, str, bool)) and not k.startswith("_")} # no lists . dict could be supported but hard to scale - cat = GridLayout(cols=2, rows=len(d) + 1, size_hint=(1, len(d) + 1)) - cat.add_widget(Label(text="")) - cat.add_widget(ScaledLightLabel(text=f"{k1} settings", bold=True)) - for k2, v in d.items(): - label = ScaledLightLabel(text=f"{k2}:") - widget = self.type_to_widget_class(v)(text=str(v), input_property=f"{k1}/{k2}") - hint = all_d.get("_hint_" + k2) - if hint: - label.tooltip_text = hint - if isinstance(widget, LabelledTextInput): - widget.hint_text = hint - cat.add_widget(label) - cat.add_widget(widget) - if props_in_col[0] <= props_in_col[1]: - cols[0].add_widget(cat) - props_in_col[0] += len(d) - else: - cols[1].add_widget(cat) - props_in_col[1] += len(d) - - col_container = BoxLayout(size_hint=(1, 0.9)) - col_container.add_widget(cols[0]) - col_container.add_widget(cols[1]) - self.add_widget(col_container) - self.info_label = Label(halign="center") - self.apply_button = StyledButton(text="Apply", on_press=lambda _: self.update_config()) - self.save_button = StyledButton(text="Apply and Save", on_press=lambda _: self.update_config(save_to_file=True)) - btn_container = BoxLayout(orientation="horizontal", size_hint=(1, 0.1), spacing=1, padding=1) - btn_container.add_widget(self.apply_button) - btn_container.add_widget(self.info_label) - btn_container.add_widget(self.save_button) - self.add_widget(btn_container) - - def update_config(self, save_to_file=False): - updated_cat = defaultdict(list) # type: DefaultDict[List[str]] - try: - for k, v in self.collect_properties(self).items(): - k1, k2 = k.split("/") - if self.config[k1][k2] != v: - self.katrain.log(f"Updating setting {k} = {v}", OUTPUT_DEBUG) - updated_cat[k1].append(k2) - self.config[k1][k2] = v - self.popup.dismiss() - except InputParseError as e: - self.info_label.text = str(e) - self.katrain.log(e, OUTPUT_ERROR) - return - - if save_to_file: - self.katrain.save_config() - - engine_updates = updated_cat["engine"] - if "visits" in engine_updates: - self.katrain.engine.visits = engine_updates["visits"] - if {key for key in engine_updates if key not in {"max_visits", "max_time", "enable_ownership", "wide_root_noise"}}: - self.katrain.log(f"Restarting Engine after {engine_updates} settings change") - self.info_label.text = "Restarting engine\nplease wait." - self.katrain.controls.set_status(f"Restarted Engine after {engine_updates} settings change.") + ignore = {"max_visits", "max_time", "enable_ownership", "wide_root_noise"} + detected_restart = [key for key in updated if "engine" in key and not any(ig in key for ig in ignore)] + if detected_restart: def restart_engine(_dt): + self.katrain.log(f"Restarting Engine after {detected_restart} settings change") + self.katrain.controls.set_status(i18n._("restarting engine")) + old_engine = self.katrain.engine # type: KataGoEngine old_proc = old_engine.katago_process if old_proc: - old_engine.shutdown(finish=True) + old_engine.shutdown(finish=False) new_engine = KataGoEngine(self.katrain, self.config["engine"]) self.katrain.engine = new_engine self.katrain.game.engines = {"B": new_engine, "W": new_engine} @@ -276,91 +246,6 @@ class ConfigPopup(QuickConfigGui): Clock.schedule_once(restart_engine, 0) - self.katrain.debug_level = self.config["debug"]["level"] - self.katrain.update_state(redraw_board=True) - class LoadSGFPopup(BoxLayout): pass - - -class ConfigTeacherPopup(QuickConfigGui): - def __init__(self, katrain, popup, **kwargs): - self.settings = katrain.config("trainer") - self.sgf_settings = katrain.config("sgf") - self.ui_settings = katrain.config("board_ui") - super().__init__(katrain, popup, self.settings, **kwargs) - self.spacing = 2 - Clock.schedule_once(self.build, 0) - - def build(self, _dt): - thresholds = self.settings["eval_thresholds"] - undos = self.settings["num_undo_prompts"] - colors = self.ui_settings["eval_colors"] - thrbox = GridLayout(spacing=1, padding=2, cols=5, rows=len(thresholds) + 1) - thrbox.add_widget(ScaledLightLabel(text="Point loss greater than", bold=True)) - thrbox.add_widget(ScaledLightLabel(text="Gives this many undos", bold=True)) - thrbox.add_widget(ScaledLightLabel(text="Color (fixed)", bold=True)) - thrbox.add_widget(ScaledLightLabel(text="Show dots", bold=True)) - thrbox.add_widget(ScaledLightLabel(text="Save in SGF", bold=True)) - for i, (thr, undos, color) in enumerate(zip(thresholds, undos, colors)): - thrbox.add_widget(LabelledFloatInput(text=str(thr), input_property=f"eval_thresholds::{i}")) - thrbox.add_widget(LabelledFloatInput(text=str(undos), input_property=f"num_undo_prompts::{i}")) - thrbox.add_widget(BackgroundMixin(background_color=color[:3])) - thrbox.add_widget(LabelledCheckBox(text=str(color[3] == 1), input_property=f"alpha::{i}")) - thrbox.add_widget(LabelledCheckBox(size_hint=(0.5, 1), text=str(self.sgf_settings["save_feedback"][i]), input_property=f"save_feedback::{i}")) - self.add_widget(thrbox) - - xsettings = BoxLayout(size_hint=(1, 0.15), spacing=2) - xsettings.add_widget(ScaledLightLabel(text="Show last dots")) - xsettings.add_widget(LabelledIntInput(size_hint=(0.5, 1), text=str(self.settings["eval_off_show_last"]), input_property="eval_off_show_last")) - self.add_widget(xsettings) - xsettings = BoxLayout(size_hint=(1, 0.15), spacing=2) - xsettings.add_widget(ScaledLightLabel(text="Show dots/SGF comments for AI players")) - xsettings.add_widget(LabelledCheckBox(size_hint=(0.5, 1), text=str(self.settings["eval_show_ai"]), input_property="eval_show_ai")) - self.add_widget(xsettings) - xsettings = BoxLayout(size_hint=(1, 0.15), spacing=2) - xsettings.add_widget(ScaledLightLabel(text="Disable analysis while in teach mode")) - xsettings.add_widget(LabelledCheckBox(size_hint=(0.5, 1), text=str(self.settings["lock_ai"]), input_property="lock_ai")) - self.add_widget(xsettings) - - bl = BoxLayout(size_hint=(1, 0.15), spacing=2) - bl.add_widget(StyledButton(text=f"Apply", on_press=lambda _: self.update_config(False))) - self.info_label = Label() - bl.add_widget(self.info_label) - bl.add_widget(StyledButton(text=f"Apply and Save", on_press=lambda _: self.update_config(True))) - self.add_widget(bl) - - def update_config(self, save_to_file=False): - try: - for k, v in self.collect_properties(self).items(): - if "::" in k: - k1, i = k.split("::") - i = int(i) - if "alpha" in k1: - v = 1.0 if v else 0.0 - if self.ui_settings["eval_colors"][i][3] != v: - self.katrain.log(f"Updating alpha {i} = {v}", OUTPUT_DEBUG) - self.ui_settings["eval_colors"][i][3] = v - elif "save_feedback" in k1: - if self.sgf_settings[k1][i] != v: - self.sgf_settings[k1][i] = v - self.katrain.log(f"Updating setting sgf/{k1}[{i}] = {v}", OUTPUT_DEBUG) - - else: - if self.settings[k1][i] != v: - self.settings[k1][i] = v - self.katrain.log(f"Updating setting trainer/{k1}[{i}] = {v}", OUTPUT_DEBUG) - else: - if self.settings[k] != v: - self.settings[k] = v - self.katrain.log(f"Updating setting {k} = {v}", OUTPUT_DEBUG) - if save_to_file: - self.katrain.save_config() - self.popup.dismiss() - except InputParseError as e: - self.info_label.text = str(e) - self.katrain.log(e, OUTPUT_ERROR) - return - self.katrain.update_state() - self.popup.dismiss() diff --git a/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo index bf632aa..db2c6e5 100644 Binary files a/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/en/LC_MESSAGES/katrain.po b/katrain/i18n/locales/en/LC_MESSAGES/katrain.po index 09c403a..5d472c5 100644 --- a/katrain/i18n/locales/en/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/en/LC_MESSAGES/katrain.po @@ -20,7 +20,7 @@ msgid "menu:load" msgstr "Load Game" msgid "menu:settings" -msgstr "General Settings" +msgstr "General & Engine Settings" msgid "menu:clocksettings" msgstr "Timer Settings" @@ -278,6 +278,46 @@ msgstr "Note that handicaps above 9 are not supported on non-square boards." msgid "new game" msgstr "Start New Game" + +# teacher settings from here +msgstr "teacher settings" +msgid "Edit Teacher Settings" + +msgid "point loss threshold" +msgstr "Point loss greater than" + +msgid "num undos" +msgstr "Number of undos" + +msgid "num undos" +msgstr "Number of undos" + +msgid "dot color" +msgstr "Colour (fixed)" + +msgid "show dots" +msgstr "Show dots" + +msgid "save dots" +msgstr "Save in SGF" + +msgid "show last n dots" +msgstr "Show dots for the last moves" + +msgid "show ai dots" +msgstr "Show dots/SGF comments for AI players" + +msgid "lock ai when teaching" +msgstr "Disable analysis while in teach mode" + +#. submit button +msgid "update teacher" +msgstr "Update Teaching Game Settings" + +#main config settings +msgid "restarting engine" +msgstr "Restarting Engine after Settings Change." + #. misc errors and info messages msgid "sgf written" msgstr "SGF with analysis written to {file_name}" diff --git a/katrain/popups.kv b/katrain/popups.kv index ce7dbcf..6010b92 100644 --- a/katrain/popups.kv +++ b/katrain/popups.kv @@ -43,7 +43,7 @@ font_size: DESC_FONT_SIZE : - background_color: [*[c*255/66 for c in BACKGROUND_COLOR[:3]], 1] + #background_color: [*[c*255/66 for c in BACKGROUND_COLOR[:3]], 1] title: i18n._(self.title_key) title_size: DESC_FONT_SIZE title_font: self.font_name @@ -65,6 +65,144 @@ font_size: DESC_FONT_SIZE * 0.66 +: + BoxLayout: + orientation: 'horizontal' + GridLayout: + cols: 2 + rows: 9 + spacing: CP_SPACING + Label: + Label: + text: 'engine' + DescriptionLabel: + text: i18n._("general:sgf_load") + AnchorLayout: + LabelledTextInput: + input_property: "general/sgf_load" # just last load dir? + DescriptionLabel: + text: i18n._("general:sgf_save") + AnchorLayout: + LabelledTextInput: + input_property: "general/sgf_save" + DescriptionLabel: + text: i18n._("general:anim_pv_time") + AnchorLayout: + LabelledFloatInput: + input_property: "general/anim_pv_time" + DescriptionLabel: + text: i18n._("general:debug_level") + AnchorLayout: + LabelledIntInput: + input_property: "general/debug_level" + BackgroundMixing: + background_color: LIGHTGREY + size_hint: None, 1 + width: 2 + GridLayout: + cols: 2 + rows: 9 + spacing: CP_SPACING + Label: + Label: + text: 'engine' + DescriptionLabel: + text: i18n._("engine:katago") + AnchorLayout: + LabelledTextInput: + input_property: "engine/katago" + DescriptionLabel: + text: i18n._("engine:model") + AnchorLayout: + LabelledTextInput: + input_property: "engine/model" + DescriptionLabel: + text: i18n._("engine:config") + AnchorLayout: + LabelledTextInput: + input_property: "engine/config" + DescriptionLabel: + text: i18n._("engine:max_visits") + AnchorLayout: + LabelledIntInput: + input_property: "engine/max_visits" + DescriptionLabel: + text: i18n._("engine:max_time") + AnchorLayout: + LabelledFloatInput: + input_property: "engine/fast_visits" + DescriptionLabel: + text: i18n._("engine:fast_visits") + AnchorLayout: + LabelledFloatInput: + input_property: "engine/max_time" + DescriptionLabel: + text: i18n._("engine:threads") + AnchorLayout: + LabelledIntInput: + input_property: "engine/threads" + DescriptionLabel: + text: i18n._("engine:wide_root_noise") + AnchorLayout: + LabelledFloatInput: + input_property: "engine/wide_root_noise" + AnchorLayout: + size_hint: 1,1 + AutoSizedRoundedRectangleButton: + padding_x: 15 + size_hint: None,0.5 + text: i18n._("update settings") + on_press: root.update_config(True) + + + options_grid: options_grid + GridLayout: + cols: 5 + rows: 7 + size_hint: 1, 7 + id: options_grid + DescriptionLabel: + text: i18n._("dot color") + DescriptionLabel: + text: i18n._("point loss threshold") + DescriptionLabel: + text: i18n._("num undos") + DescriptionLabel: + text: i18n._("show dots") + DescriptionLabel: + text: i18n._("save dots") + GridLayout: + cols: 2 + rows: 3 + size_hint: 1, 3 + DescriptionLabel: + text: i18n._("show last n dots") + AnchorLayout: + LabelledIntInput: + input_property: "trainer/eval_off_show_last" + DescriptionLabel: + text: i18n._("show ai dots") + AnchorLayout: + LabelledIntInput: + input_property: "trainer/eval_off_show_last" + DescriptionLabel: + text: i18n._("show last n dots") + AnchorLayout: + LabelledIntInput: + input_property: "trainer/eval_show_ai" + DescriptionLabel: + text: i18n._("lock ai when teaching") + AnchorLayout: + LabelledCheckBox: + input_property: "trainer/lock_ai" + AnchorLayout: + size_hint: 1,1 + AutoSizedRoundedRectangleButton: + padding_x: 15 + size_hint: None,0.5 + text: i18n._("update teacher") + on_press: root.update_config(True) + : MDGridLayout: @@ -103,6 +241,10 @@ : restart: restart rules_spinner: rules_spinner + player_setup: player_setup + PlayerSetupBlock: + size_hint: 1, 2 + id: player_setup GridLayout: rows: 6 cols: 3 @@ -199,6 +341,9 @@ on_press: root.update_config(True) +: + FileBrowser: + # old :