This commit is contained in:
Sander Land committed 2020-12-01 23:09:02 +01:00
1 parent 957cdceea2
commit 93841e9b35
23 files changed
+196 -43

No files matched your search

+2 -3
View File
@@ -4,7 +4,7 @@
[![License:MIT](https://img.shields.io/pypi/l/katrain)](https://en.wikipedia.org/wiki/MIT_License) [![License:MIT](https://img.shields.io/pypi/l/katrain)](https://en.wikipedia.org/wiki/MIT_License)
[![GitHub Downloads](https://img.shields.io/github/downloads/sanderland/katrain/total?color=%23336699&label=github%20downloads)](https://github.com/sanderland/katrain/releases) [![GitHub Downloads](https://img.shields.io/github/downloads/sanderland/katrain/total?color=%23336699&label=github%20downloads)](https://github.com/sanderland/katrain/releases)
[![PyPI Downloads](https://pepy.tech/badge/katrain)](https://pepy.tech/project/katrain) [![PyPI Downloads](https://pepy.tech/badge/katrain)](https://pepy.tech/project/katrain)
[![Github sponsors](https://img.shields.io/static/v1?label=sponsor&message=7&logo=GitHub&color=dcb424&link=https://github.com/sponsors/sanderland/)](https://github.com/sponsors/sanderland) [![Github sponsors](https://img.shields.io/static/v1?label=sponsor&message=6&logo=GitHub&color=dcb424&link=https://github.com/sponsors/sanderland/)](https://github.com/sponsors/sanderland)
[![Discord](https://img.shields.io/discord/417022162348802048?logo=discord)](https://discord.com/channels/417022162348802048/629446365688365067) [![Discord](https://img.shields.io/discord/417022162348802048?logo=discord)](https://discord.com/channels/417022162348802048/629446365688365067)
<table> <table>
@@ -27,9 +27,8 @@
<a href="https://github.com/sanderland/katrain/blob/master/README.md"><img alt="English" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-uk.png" width=50></a> <a href="https://github.com/sanderland/katrain/blob/master/README.md"><img alt="English" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-uk.png" width=50></a>
<a href="https://translate.google.com/translate?sl=en&tl=de&u=https%3A%2F%2Fgithub.com%2Fsanderland%2Fkatrain%2Fblob%2Fmaster%2FREADME.md"><img alt="German" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-de.png" width=50></a> <a href="https://translate.google.com/translate?sl=en&tl=de&u=https%3A%2F%2Fgithub.com%2Fsanderland%2Fkatrain%2Fblob%2Fmaster%2FREADME.md"><img alt="German" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-de.png" width=50></a>
<a href="https://translate.google.com/translate?sl=en&tl=fr&u=https%3A%2F%2Fgithub.com%2Fsanderland%2Fkatrain%2Fblob%2Fmaster%2FREADME.md"><img alt="French" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-fr.png" width=50></a> <a href="https://translate.google.com/translate?sl=en&tl=fr&u=https%3A%2F%2Fgithub.com%2Fsanderland%2Fkatrain%2Fblob%2Fmaster%2FREADME.md"><img alt="French" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-fr.png" width=50></a>
<a href="https://translate.google.com/translate?sl=en&tl=es&u=https%3A%2F%2Fgithub.com%2Fsanderland%2Fkatrain%2Fblob%2Fmaster%2FREADME.md"><img alt="Spanish" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-es.png" width=50></a>
<br/>
<a href="https://translate.google.com/translate?sl=en&tl=ru&u=https%3A%2F%2Fgithub.com%2Fsanderland%2Fkatrain%2Fblob%2Fmaster%2FREADME.md"><img alt="Russian" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-ru.png" width=50></a> <a href="https://translate.google.com/translate?sl=en&tl=ru&u=https%3A%2F%2Fgithub.com%2Fsanderland%2Fkatrain%2Fblob%2Fmaster%2FREADME.md"><img alt="Russian" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-ru.png" width=50></a>
<br/>
<a href="https://translate.google.com/translate?sl=en&tl=zh-CN&u=https%3A%2F%2Fgithub.com%2Fsanderland%2Fkatrain%2Fblob%2Fmaster%2FREADME.md"><img alt="Chinese" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-cn.png" width=50></a> <a href="https://translate.google.com/translate?sl=en&tl=zh-CN&u=https%3A%2F%2Fgithub.com%2Fsanderland%2Fkatrain%2Fblob%2Fmaster%2FREADME.md"><img alt="Chinese" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-cn.png" width=50></a>
<a href="https://translate.google.com/translate?sl=en&tl=ko&u=https%3A%2F%2Fgithub.com%2Fsanderland%2Fkatrain%2Fblob%2Fmaster%2FREADME.md"><img alt="Korean" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-ko.png" width=50></a> <a href="https://translate.google.com/translate?sl=en&tl=ko&u=https%3A%2F%2Fgithub.com%2Fsanderland%2Fkatrain%2Fblob%2Fmaster%2FREADME.md"><img alt="Korean" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-ko.png" width=50></a>
<a href="https://translate.google.com/translate?sl=en&tl=ja&u=https%3A%2F%2Fgithub.com%2Fsanderland%2Fkatrain%2Fblob%2Fmaster%2FREADME.md"><img alt="Japanese" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-jp.png" width=50></a> <a href="https://translate.google.com/translate?sl=en&tl=ja&u=https%3A%2F%2Fgithub.com%2Fsanderland%2Fkatrain%2Fblob%2Fmaster%2FREADME.md"><img alt="Japanese" src="https://github.com/sanderland/katrain/blob/master/katrain/img/flags/flag-jp.png" width=50></a>
+39 -11
View File
@@ -66,7 +66,7 @@ from katrain.core.constants import (
PLAYING_NORMAL, PLAYING_NORMAL,
PLAYER_HUMAN, PLAYER_HUMAN,
) )
from katrain.gui.popups import ConfigTeacherPopup, ConfigTimerPopup, I18NPopup from katrain.gui.popups import ConfigTeacherPopup, ConfigTimerPopup, I18NPopup, SaveSGFPopup
from katrain.core.base_katrain import KaTrainBase from katrain.core.base_katrain import KaTrainBase
from katrain.core.engine import KataGoEngine from katrain.core.engine import KataGoEngine
from katrain.core.game import Game, IllegalMoveException, KaTrainSGF from katrain.core.game import Game, IllegalMoveException, KaTrainSGF
@@ -227,6 +227,7 @@ class KaTrainGui(Screen, KaTrainBase):
def set_note(self, note): def set_note(self, note):
self.game.current_node.note = note self.game.current_node.note = note
# The message loop is here to make sure moves happen in the right order, and slow operations don't hang the GUI
def _message_loop_thread(self): def _message_loop_thread(self):
while True: while True:
game, msg, args, kwargs = self.message_queue.get() game, msg, args, kwargs = self.message_queue.get()
@@ -253,16 +254,14 @@ class KaTrainGui(Screen, KaTrainBase):
else: # game related actions else: # game related actions
self.message_queue.put([self.game.game_id, message, args, kwargs]) self.message_queue.put([self.game.game_id, message, args, kwargs])
def _do_new_game(self, move_tree=None, analyze_fast=False, loaded_from_file=None): def _do_new_game(self, move_tree=None, analyze_fast=False, sgf_filename=None):
self.idle_analysis = False self.idle_analysis = False
mode = self.play_analyze_mode mode = self.play_analyze_mode
if (move_tree is not None and mode == MODE_PLAY) or (move_tree is None and mode == MODE_ANALYZE): if (move_tree is not None and mode == MODE_PLAY) or (move_tree is None and mode == MODE_ANALYZE):
self.play_mode.switch_ui_mode() # for new game, go to play, for loaded, analyze self.play_mode.switch_ui_mode() # for new game, go to play, for loaded, analyze
self.board_gui.animating_pv = None self.board_gui.animating_pv = None
self.engine.on_new_game() # clear queries self.engine.on_new_game() # clear queries
self.game = Game( self.game = Game(self, self.engine, move_tree=move_tree, analyze_fast=analyze_fast, sgf_filename=sgf_filename)
self, self.engine, move_tree=move_tree, analyze_fast=analyze_fast, loaded_from_file=loaded_from_file
)
if move_tree: if move_tree:
for bw, player_info in self.players_info.items(): for bw, player_info in self.players_info.items():
player_info.player_type = PLAYER_HUMAN player_info.player_type = PLAYER_HUMAN
@@ -371,7 +370,7 @@ class KaTrainGui(Screen, KaTrainBase):
except ParseError as e: except ParseError as e:
self.log(i18n._("Failed to load SGF").format(error=e), OUTPUT_ERROR) self.log(i18n._("Failed to load SGF").format(error=e), OUTPUT_ERROR)
return return
self._do_new_game(move_tree=move_tree, analyze_fast=fast, loaded_from_file=file) self._do_new_game(move_tree=move_tree, analyze_fast=fast, sgf_filename=file)
if not rewind: if not rewind:
self.game.redo(999) self.game.redo(999)
@@ -387,9 +386,8 @@ class KaTrainGui(Screen, KaTrainBase):
filename = popup_contents.filesel.filename filename = popup_contents.filesel.filename
self.fileselect_popup.dismiss() self.fileselect_popup.dismiss()
path, file = os.path.split(filename) path, file = os.path.split(filename)
settings_path = self.config("general/sgf_load") if path != self.config("general/sgf_load"):
if path != settings_path: self.log(f"Updating sgf load path default to {path}", OUTPUT_DEBUG)
self.log(f"Updating sgf load path default to {path}", OUTPUT_INFO)
self._config["general"]["sgf_load"] = path self._config["general"]["sgf_load"] = path
self.save_config("general") self.save_config("general")
self.load_sgf_file(filename, popup_contents.fast.active, popup_contents.rewind.active) self.load_sgf_file(filename, popup_contents.fast.active, popup_contents.rewind.active)
@@ -399,11 +397,39 @@ class KaTrainGui(Screen, KaTrainBase):
self.fileselect_popup.open() self.fileselect_popup.open()
self.fileselect_popup.content.filesel.ids.list_view._trigger_update() self.fileselect_popup.content.filesel.ids.list_view._trigger_update()
def _do_output_sgf(self): 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")) msg = self.game.write_sgf(self.config("general/sgf_save"))
self.log(msg, OUTPUT_INFO) self.log(msg, OUTPUT_INFO)
self.controls.set_status(msg, STATUS_INFO) self.controls.set_status(msg, STATUS_INFO)
def _do_save_game_as_popup(self):
popup_contents = SaveSGFPopup()
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'
save_game_popup.dismiss()
path, file = os.path.split(filename)
if path != self.config("general/sgf_save"):
self.log(f"Updating sgf save path default to {path}", OUTPUT_DEBUG)
self._config["general"]["sgf_save"] = path
self.save_config("general")
self._do_save_game(filename)
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): def load_sgf_from_clipboard(self):
clipboard = Clipboard.paste() clipboard = Clipboard.paste()
if not clipboard: if not clipboard:
@@ -513,7 +539,9 @@ class KaTrainGui(Screen, KaTrainBase):
elif keycode[1] == "l" and ctrl_pressed: elif keycode[1] == "l" and ctrl_pressed:
self("analyze-sgf-popup") self("analyze-sgf-popup")
elif keycode[1] == "s" and ctrl_pressed: elif keycode[1] == "s" and ctrl_pressed:
self("output-sgf") self("save-game")
elif keycode[1] == "d" and ctrl_pressed:
self("save-game-as-popup")
elif keycode[1] == "c" and ctrl_pressed: elif keycode[1] == "c" and ctrl_pressed:
Clipboard.copy(self.game.root.sgf()) Clipboard.copy(self.game.root.sgf())
self.controls.set_status(i18n._("Copied SGF to clipboard."), STATUS_INFO) self.controls.set_status(i18n._("Copied SGF to clipboard."), STATUS_INFO)
+10 -18
View File
@@ -47,7 +47,7 @@ class Game:
move_tree: GameNode = None, move_tree: GameNode = None,
analyze_fast=False, analyze_fast=False,
game_properties: Optional[Dict] = None, game_properties: Optional[Dict] = None,
loaded_from_file=None, sgf_filename=None,
): ):
self.katrain = katrain self.katrain = katrain
self._lock = threading.Lock() self._lock = threading.Lock()
@@ -55,7 +55,7 @@ class Game:
engine = {"B": engine, "W": engine} engine = {"B": engine, "W": engine}
self.engines = engine self.engines = engine
self.game_id = datetime.strftime(datetime.now(), "%Y-%m-%d %H %M %S") self.game_id = datetime.strftime(datetime.now(), "%Y-%m-%d %H %M %S")
self.loaded_from_file = loaded_from_file self.sgf_filename = sgf_filename
if move_tree: if move_tree:
self.root = move_tree self.root = move_tree
@@ -295,14 +295,18 @@ class Game:
+ f"\ncaptures: {self.prisoner_count}" + f"\ncaptures: {self.prisoner_count}"
) )
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( def write_sgf(
self, path: str, trainer_config: Optional[Dict] = None, self, file_name: str=None, trainer_config: Optional[Dict] = None,
): ):
if trainer_config is None: if trainer_config is None:
trainer_config = self.katrain.config("trainer", {}) trainer_config = self.katrain.config("trainer", {})
save_feedback = trainer_config.get("save_feedback", False) save_feedback = trainer_config.get("save_feedback", False)
eval_thresholds = trainer_config["eval_thresholds"] eval_thresholds = trainer_config["eval_thresholds"]
print(trainer_config)
save_analysis = trainer_config.get("save_analysis", False) save_analysis = trainer_config.get("save_analysis", False)
def player_name(player_info): def player_name(player_info):
@@ -324,20 +328,6 @@ class Game:
if save_analysis: 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()}} 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"katrain_{player_names['B']} vs {player_names['W']}"
game_name = f"{base_game_name} {self.game_id}"
if (
self.loaded_from_file
and base_game_name in self.loaded_from_file
and PROGRAM_NAME in self.root.get_property("AP", "")
and self.loaded_from_file.endswith("sgf")
):
file_name = self.loaded_from_file
else:
file_name = os.path.abspath(os.path.join(path, f"{game_name}.sgf"))
os.makedirs(os.path.dirname(file_name), exist_ok=True)
show_dots_for = { show_dots_for = {
bw: trainer_config.get("eval_show_ai", True) or self.katrain.players_info[bw].human for bw in "BW" bw: trainer_config.get("eval_show_ai", True) or self.katrain.players_info[bw].human for bw in "BW"
@@ -348,6 +338,8 @@ class Game:
eval_thresholds=eval_thresholds, eval_thresholds=eval_thresholds,
save_analysis=save_analysis, 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: with open(file_name, "w", encoding="utf-8") as f:
f.write(sgf) f.write(sgf)
self.root.properties = root_properties self.root.properties = root_properties
+3 -3
View File
@@ -950,9 +950,9 @@
on_action: root.katrain("save-game") on_action: root.katrain("save-game")
MainMenuItem: MainMenuItem:
text: i18n._('menu:save-as') text: i18n._('menu:save-as')
icon: 'img/Save-Game.png' icon: 'img/Save-Game-As.png'
shortcut: 'Ctrl-Shift-S' shortcut: 'Ctrl-D'
on_action: root.katrain("save-game-as") on_action: root.katrain("save-game-as-popup")
MainMenuItem: MainMenuItem:
text: i18n._('menu:load') text: i18n._('menu:load')
icon: 'img/Load-Game.png' icon: 'img/Load-Game.png'
+14 -2
View File
@@ -669,13 +669,25 @@ class LoadSGFPopup(BoxLayout):
super().__init__(**kwargs) super().__init__(**kwargs)
app = MDApp.get_running_app() app = MDApp.get_running_app()
self.filesel.favorites = [ self.filesel.favorites = [
(os.path.abspath(app.gui.config("general/sgf_load")), "Last Used Dir"), (os.path.abspath(app.gui.config("general/sgf_load")), "Last Load Dir"),
(os.path.abspath(app.gui.config("general/sgf_save")), "SGF Save Dir"), (os.path.abspath(app.gui.config("general/sgf_save")), "Last Save Dir"),
] ]
self.filesel.path = os.path.abspath(os.path.expanduser(app.gui.config("general/sgf_load"))) self.filesel.path = os.path.abspath(os.path.expanduser(app.gui.config("general/sgf_load")))
self.filesel.select_string = i18n._("Load File") self.filesel.select_string = i18n._("Load File")
class SaveSGFPopup(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
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")))
self.filesel.select_string = i18n._("Save File")
class ReAnalyzeGamePopup(BoxLayout): class ReAnalyzeGamePopup(BoxLayout):
katrain = ObjectProperty(None) katrain = ObjectProperty(None)
popup = ObjectProperty(None) popup = ObjectProperty(None)
Binary file not shown.
@@ -727,3 +727,18 @@ msgstr "Cache analysis in SGF"
#. TODO #. TODO
msgid "menu:save-as" msgid "menu:save-as"
msgstr "Save Game As..." msgstr "Save Game As..."
#. TODO
# sgf load button
msgid "Load File"
msgstr "Load File"
#. TODO
# sgf save popup
msgid "save sgf title"
msgstr "Save SGF File"
#. TODO
# sgf save as button
msgid "Save File"
msgstr "Save File"
Binary file not shown.
@@ -774,3 +774,18 @@ msgstr ""
#. TODO #. TODO
msgid "menu:save-as" msgid "menu:save-as"
msgstr "Save Game As..." msgstr "Save Game As..."
#. TODO
# sgf load button
msgid "Load File"
msgstr "Load File"
#. TODO
# sgf save popup
msgid "save sgf title"
msgstr "Save SGF File"
#. TODO
# sgf save as button
msgid "Save File"
msgstr "Save File"
Binary file not shown.
@@ -293,6 +293,18 @@ msgstr "Your SGF notes for this position here."
msgid "load sgf title" msgid "load sgf title"
msgstr "Load SGF File to Analyze" msgstr "Load SGF File to Analyze"
# sgf load button
msgid "Load File"
msgstr "Load File"
# sgf save as button
msgid "Save File"
msgstr "Save File"
# sgf save popup
msgid "save sgf title"
msgstr "Save SGF File"
msgid "load sgf fast analysis" msgid "load sgf fast analysis"
msgstr "Use fast analysis" msgstr "Use fast analysis"
Binary file not shown.
@@ -787,3 +787,18 @@ msgstr "Cache analysis in SGF"
#. TODO #. TODO
msgid "menu:save-as" msgid "menu:save-as"
msgstr "Save Game As..." msgstr "Save Game As..."
#. TODO
# sgf load button
msgid "Load File"
msgstr "Load File"
#. TODO
# sgf save popup
msgid "save sgf title"
msgstr "Save SGF File"
#. TODO
# sgf save as button
msgid "Save File"
msgstr "Save File"
Binary file not shown.
@@ -813,3 +813,18 @@ msgstr "Cache analysis in SGF"
#. TODO #. TODO
msgid "menu:save-as" msgid "menu:save-as"
msgstr "Save Game As..." msgstr "Save Game As..."
#. TODO
# sgf load button
msgid "Load File"
msgstr "Load File"
#. TODO
# sgf save popup
msgid "save sgf title"
msgstr "Save SGF File"
#. TODO
# sgf save as button
msgid "Save File"
msgstr "Save File"
Binary file not shown.
@@ -766,3 +766,18 @@ msgstr "Cache analysis in SGF"
#. TODO #. TODO
msgid "menu:save-as" msgid "menu:save-as"
msgstr "Save Game As..." msgstr "Save Game As..."
#. TODO
# sgf load button
msgid "Load File"
msgstr "Load File"
#. TODO
# sgf save popup
msgid "save sgf title"
msgstr "Save SGF File"
#. TODO
# sgf save as button
msgid "Save File"
msgstr "Save File"
Binary file not shown.
@@ -741,3 +741,18 @@ msgstr "ache analysis in SGF"
#. TODO #. TODO
msgid "menu:save-as" msgid "menu:save-as"
msgstr "Save Game As..." msgstr "Save Game As..."
#. TODO
# sgf load button
msgid "Load File"
msgstr "Load File"
#. TODO
# sgf save popup
msgid "save sgf title"
msgstr "Save SGF File"
#. TODO
# sgf save as button
msgid "Save File"
msgstr "Save File"
Binary file not shown.
@@ -775,3 +775,18 @@ msgstr "Cache analysis in SGF"
#. TODO #. TODO
msgid "menu:save-as" msgid "menu:save-as"
msgstr "Save Game As..." msgstr "Save Game As..."
#. TODO
# sgf load button
msgid "Load File"
msgstr "Load File"
#. TODO
# sgf save popup
msgid "save sgf title"
msgstr "Save SGF File"
#. TODO
# sgf save as button
msgid "Save File"
msgstr "Save File"
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

+11 -6
View File
@@ -181,13 +181,8 @@
orientation: 'horizontal' orientation: 'horizontal'
GridLayout: GridLayout:
cols: 2 cols: 2
rows: 5 rows: 4
spacing: CP_SPACING spacing: CP_SPACING
DescriptionLabel:
text: i18n._("general:sgf_save")
AnchorLayout:
LabelledPathInput:
input_property: "general/sgf_save"
DescriptionLabel: DescriptionLabel:
text: i18n._('count down sound') text: i18n._('count down sound')
AnchorLayout: AnchorLayout:
@@ -622,3 +617,13 @@
filters: ["*.sgf","*.gib","*.ngf"] filters: ["*.sgf","*.gib","*.ngf"]
path: "." path: "."
size_hint: 1,7 size_hint: 1,7
<SaveSGFPopup>:
filesel: filesel
orientation: 'vertical'
I18NFileBrowser:
id: filesel
multiselect: False
filters: ["*.sgf","*.gib","*.ngf"]
path: "."
size_hint: 1,7