diff --git a/katrain/__main__.py b/katrain/__main__.py index de8e706..44b0bde 100644 --- a/katrain/__main__.py +++ b/katrain/__main__.py @@ -400,21 +400,24 @@ class KaTrainGui(Screen, KaTrainBase): def _do_save_game(self, filename=None): filename = filename or self.game.sgf_filename if not filename: - return self("save-game-as") - msg = self.game.write_sgf(self.config("general/sgf_save")) - self.log(msg, OUTPUT_INFO) - self.controls.set_status(msg, STATUS_INFO) + return self("save-game-as-popup") + try: + msg = self.game.write_sgf(filename) + self.log(msg, OUTPUT_INFO) + self.controls.set_status(msg, STATUS_INFO) + except Exception as e: + self.log(f"Failed to save SGF to {filename}: {e}", OUTPUT_ERROR) def _do_save_game_as_popup(self): - popup_contents = SaveSGFPopup() + popup_contents = SaveSGFPopup(suggested_filename=self.game.generate_filename()) save_game_popup = I18NPopup( title_key="save sgf title", size=[dp(1200), dp(800)], content=popup_contents ).__self__ def readfile(*_args): filename = popup_contents.filesel.filename - if not filename.lower().endswith('.sgf'): - filename += '.sgf' + if not filename.lower().endswith(".sgf"): + filename += ".sgf" save_game_popup.dismiss() path, file = os.path.split(filename) if path != self.config("general/sgf_save"): @@ -426,9 +429,6 @@ class KaTrainGui(Screen, KaTrainBase): popup_contents.filesel.on_success = readfile popup_contents.filesel.on_submit = readfile save_game_popup.open() - popup_contents.filesel.ids.file_text = self.game.generate_filename() # TODO: ??? - popup_contents.filesel.path = os.path.abspath(os.path.expanduser(self.config("general/sgf_save", "."))) - # save_game_popup.content.filesel.ids.list_view._trigger_update() def load_sgf_from_clipboard(self): clipboard = Clipboard.paste() @@ -510,6 +510,11 @@ class KaTrainGui(Screen, KaTrainBase): if keycode[1] in ["f5", "f6", "f7", "f8"]: # switch between popups popup.dismiss() return + elif keycode[1] in ["enter", "numpadenter"]: + fn = getattr(popup.content, "on_submit", None) + if fn: + fn() + return else: return ctrl_pressed = "ctrl" in modifiers diff --git a/katrain/core/game.py b/katrain/core/game.py index 4c2c945..2d5c8f4 100644 --- a/katrain/core/game.py +++ b/katrain/core/game.py @@ -296,19 +296,6 @@ class Game: ) def generate_filename(self): - player_names = {bw: re.sub(r"['<>:\"/\\|?*]", "", self.root.get_property("P" + bw, bw)) for bw in "BW"} - base_game_name = f"katrain_{player_names['B']} vs {player_names['W']}" - return f"{base_game_name} {self.game_id}" - - def write_sgf( - self, file_name: str=None, trainer_config: Optional[Dict] = None, - ): - if trainer_config is None: - trainer_config = self.katrain.config("trainer", {}) - save_feedback = trainer_config.get("save_feedback", False) - eval_thresholds = trainer_config["eval_thresholds"] - save_analysis = trainer_config.get("save_analysis", False) - def player_name(player_info): if player_info.name and player_info.player_type == PLAYER_HUMAN: return player_info.name @@ -317,7 +304,7 @@ class Game: root_properties = self.root.properties x_properties = {} - if "KaTrain" in self.root.get_property("AP", ""): + if PROGRAM_NAME in self.root.get_property("AP", ""): for bw in "BW": x_properties["P" + bw] = player_name(self.katrain.players_info[bw]) player_info = self.katrain.players_info[bw] @@ -325,9 +312,20 @@ class Game: x_properties[bw + "R"] = rank_label(player_info.calculated_rank) if "+" in str(self.end_result): x_properties["RE"] = self.end_result - if save_analysis: - x_properties["KTV"] = ANALYSIS_FORMAT_VERSION + x_properties["KTV"] = ANALYSIS_FORMAT_VERSION self.root.properties = {**root_properties, **{k: [v] for k, v in x_properties.items()}} + player_names = {bw: re.sub(r"['<>:\"/\\|?*]", "", self.root.get_property("P" + bw, bw)) for bw in "BW"} + base_game_name = f"{PROGRAM_NAME}_{player_names['B']} vs {player_names['W']}" + return f"{base_game_name} {self.game_id}.sgf" + + def write_sgf( + self, filename: str = None, trainer_config: Optional[Dict] = None, + ): + if trainer_config is None: + trainer_config = self.katrain.config("trainer", {}) + save_feedback = trainer_config.get("save_feedback", False) + eval_thresholds = trainer_config["eval_thresholds"] + save_analysis = trainer_config.get("save_analysis", False) show_dots_for = { bw: trainer_config.get("eval_show_ai", True) or self.katrain.players_info[bw].human for bw in "BW" @@ -338,12 +336,11 @@ class Game: eval_thresholds=eval_thresholds, save_analysis=save_analysis, ) - file_name = file_name or self.generate_filename() - os.makedirs(os.path.dirname(file_name), exist_ok=True) - with open(file_name, "w", encoding="utf-8") as f: + self.sgf_filename = filename + os.makedirs(os.path.dirname(filename), exist_ok=True) + with open(filename, "w", encoding="utf-8") as f: f.write(sgf) - self.root.properties = root_properties - return i18n._("sgf written").format(file_name=file_name) + return i18n._("sgf written").format(file_name=filename) def analyze_extra(self, mode, **kwargs): stones = {s.coords for s in self.stones} diff --git a/katrain/gui/badukpan.py b/katrain/gui/badukpan.py index 2ddc50e..26a08a1 100644 --- a/katrain/gui/badukpan.py +++ b/katrain/gui/badukpan.py @@ -440,7 +440,6 @@ class BadukPanWidget(Widget): with self.canvas.after: self.canvas.after.clear() self.active_pv_moves = [] - # hints or PV hint_moves = [] if ( @@ -479,12 +478,21 @@ class BadukPanWidget(Widget): scale = UNCERTAIN_HINT_SCALE text_on = False alpha = HINTS_LO_ALPHA + if "pv" in move_dict: self.active_pv_moves.append((move.coords, move_dict["pv"], current_node)) else: katrain.log(f"PV missing for move_dict {move_dict}", OUTPUT_DEBUG) 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], + ) + Color(*evalcol[:3], alpha) Rectangle( pos=(self.gridpos_x[move.coords[0]] - evalsize, self.gridpos_y[move.coords[1]] - evalsize), diff --git a/katrain/gui/popups.py b/katrain/gui/popups.py index 96d2978..d9947fb 100644 --- a/katrain/gui/popups.py +++ b/katrain/gui/popups.py @@ -677,16 +677,26 @@ class LoadSGFPopup(BoxLayout): class SaveSGFPopup(BoxLayout): - def __init__(self, **kwargs): + def __init__(self, suggested_filename, **kwargs): super().__init__(**kwargs) + self.suggested_filename = suggested_filename app = MDApp.get_running_app() self.filesel.favorites = [ (os.path.abspath(app.gui.config("general/sgf_load")), "Last Load Dir"), (os.path.abspath(app.gui.config("general/sgf_save")), "Last Save Dir"), ] - self.filesel.path = os.path.abspath(os.path.expanduser(MDApp.get_running_app().gui.config("general/sgf_save"))) + save_path = os.path.expanduser(MDApp.get_running_app().gui.config("general/sgf_save") or ".") + + def set_suggested(_widget, path): + self.filesel.ids.file_text.text = os.path.join(path, self.suggested_filename) + + self.filesel.ids.list_view.bind(path=set_suggested) + self.filesel.path = os.path.abspath(save_path) self.filesel.select_string = i18n._("Save File") + def on_submit(self): + self.filesel.dispatch("on_success") + class ReAnalyzeGamePopup(BoxLayout): katrain = ObjectProperty(None) diff --git a/katrain/gui/style.py b/katrain/gui/style.py index c38edcf..7c300df 100644 --- a/katrain/gui/style.py +++ b/katrain/gui/style.py @@ -69,7 +69,7 @@ POLICY_ALPHA = 0.6 TOP_POLICY_ALPHA = 0.3 TOP_MOVE_BORDER_COLOR = [10 / 255, 200 / 255, 250 / 255, 1.0] CHILD_SCALE = 0.95 -HINT_SCALE = 0.975 +HINT_SCALE = 0.98 UNCERTAIN_HINT_SCALE = 0.7 diff --git a/katrain/gui/widgets/filebrowser.py b/katrain/gui/widgets/filebrowser.py index 404b2b9..64891dd 100644 --- a/katrain/gui/widgets/filebrowser.py +++ b/katrain/gui/widgets/filebrowser.py @@ -225,7 +225,7 @@ Builder.load_string( spacing: [5] TextInput: id: file_text - text: (root.selection and (root._shorten_filenames(root.selection) if root.multiselect else root.selection[0])) or '' + text: (root.selection and (root._shorten_filenames(root.selection) if root.multiselect else root.selection[0])) or self.text hint_text: i18n._('Filename') multiline: False height: '40dp' diff --git a/katrain/img/Save-Game - As.png b/katrain/img/Save-Game - As.png deleted file mode 100644 index 4b0af4e..0000000 Binary files a/katrain/img/Save-Game - As.png and /dev/null differ