diff --git a/LICENSE b/LICENSE index ba01b65..538b16c 100644 --- a/LICENSE +++ b/LICENSE @@ -4,10 +4,8 @@ This repository includes: For on related licenses for these binaries and libraries see https://github.com/lightvector/KataGo 2. Icons from www.flaticon.com, used with permission with the following attributions: -- New game/Load game/Config/Config clock icons: made by Freepik from www.flaticon.com -- Flag icons: made by Freepik from www.flaticon.com -- Save icon, Pause Icon: made by Pixel perfect from www.flaticon.com -- Next/Previous icons: made by/derived from ones made by RoundIcons from www.flaticon.com +- New game/Save game/Load game/Configure icons/Flag icons: made by or derived from work by Freepik from www.flaticon.com +- Next/Previous icons: derived from work by RoundIcons from www.flaticon.com 3. The True Type Font DIGITAL-7 version 1.02 by Sizenko Alexander, which is free for non-commercial use. diff --git a/katrain/__main__.py b/katrain/__main__.py index 70d82aa..ada642b 100644 --- a/katrain/__main__.py +++ b/katrain/__main__.py @@ -22,7 +22,7 @@ from kivy.storage.jsonstore import JsonStore from kivy.uix.popup import Popup from kivy.uix.screenmanager import Screen from kivymd.app import MDApp - +from katrain.core.constants import * from katrain.core.ai import ai_move from katrain.core.utils import ( DEFAULT_LANGUAGE, @@ -36,6 +36,8 @@ from katrain.core.utils import ( MODE_PLAY, switch_lang, ) +from katrain.gui.popups import ConfigTeacherPopup, ConfigTimerPopup +from katrain.gui.ai_settings import ConfigAIPopupContents from katrain.core.engine import KataGoEngine from katrain.core.game import Game, IllegalMoveException, KaTrainSGF from katrain.core.sgf_parser import Move, ParseError @@ -60,9 +62,14 @@ class KaTrainGui(Screen): self.debug_level = 0 self.engine = None self.game = None + self.new_game_popup = None self.fileselect_popup = None self.config_popup = None + self.ai_settings_popup = None + self.teacher_settings_popup = None + self.timer_settings_popup = None + self.logger = lambda message, level=OUTPUT_INFO: self.log(message, level) self.config_file = self._load_config() @@ -114,9 +121,14 @@ class KaTrainGui(Screen): except KeyError: self.log(f"Missing configuration option {setting}", OUTPUT_ERROR) + @property def play_analyze_mode(self): return self.play_mode.play_analyze_mode + @property + def ai_strategies(self): + return list(self.config("ai").keys()) + def start(self): if self.engine: return @@ -262,6 +274,7 @@ class KaTrainGui(Screen): self.fileselect_popup.open() def _do_new_game_popup(self): + self.controls.timer.paused = True if not self.new_game_popup: self.new_game_popup = Popup(title="New Game", size_hint=(0.5, 0.6)).__self__ popup_contents = NewGamePopup(self, self.new_game_popup, {k: v[0] for k, v in self.game.root.properties.items() if len(v) == 1}) @@ -269,12 +282,34 @@ class KaTrainGui(Screen): self.new_game_popup.open() def _do_config_popup(self): + self.controls.timer.paused = True if not self.config_popup: self.config_popup = Popup(title=f"Edit Settings - {self.config_file}", size_hint=(0.9, 0.9)).__self__ popup_contents = ConfigPopup(self, self.config_popup, dict(self._config), ignore_cats=("trainer", "ai")) self.config_popup.add_widget(popup_contents) self.config_popup.open() + def _do_ai_popup(self): + self.controls.timer.paused = True + if not self.ai_settings_popup: # persist state of popup etc + self.ai_settings_popup = Popup(title="Edit AI Settings", size_hint=(0.7, 0.8)).__self__ + 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 = Popup(title="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_timer_popup(self): + self.controls.timer.paused = True + if not self.timer_settings_popup: + self.timer_settings_popup = Popup(title="Edit Timer Settings", size_hint=(0.4, 0.4)).__self__ + self.timer_settings_popup.add_widget(ConfigTimerPopup(self, self.timer_settings_popup)) + self.timer_settings_popup.open() + def _do_output_sgf(self): for pl in Move.PLAYERS: if not self.game.root.get_property(f"P{pl}"): @@ -329,6 +364,10 @@ class KaTrainGui(Screen): "p": ("play", None), "right": ("switch-branch", 1), "left": ("switch-branch", -1), + "f5": ("timer-popup",), + "f6": ("teacher-popup",), + "f7": ("ai-popup",), + "f8": ("config-popup",), } def _on_keyboard_down(self, _keyboard, keycode, _text, modifiers): diff --git a/katrain/core/constants.py b/katrain/core/constants.py new file mode 100644 index 0000000..f55fdf2 --- /dev/null +++ b/katrain/core/constants.py @@ -0,0 +1,7 @@ +PLAYER_HUMAN, PLAYER_AI = "player:human", "player:ai" +PLAYER_TYPES = [PLAYER_HUMAN, PLAYER_AI] + +PLAYING_NORMAL, PLAYING_TEACHING = "game:normal", "game:teach" +GAME_TYPES = [PLAYING_NORMAL, PLAYING_TEACHING] + +AI_DEFAULT = "default" diff --git a/katrain/core/game.py b/katrain/core/game.py index 4f6d4aa..33ff723 100644 --- a/katrain/core/game.py +++ b/katrain/core/game.py @@ -9,6 +9,7 @@ from katrain.core.utils import var_to_grid, OUTPUT_INFO, OUTPUT_DEBUG, i18n from katrain.core.engine import KataGoEngine from katrain.core.game_node import GameNode from katrain.core.sgf_parser import SGF, Move +from katrain.core.constants import * class IllegalMoveException(Exception): @@ -19,11 +20,6 @@ class KaTrainSGF(SGF): _NODE_CLASS = GameNode -PLAYER_HUMAN, PLAYER_AI = "Player", "AI" -PLAYING_NORMAL, PLAYING_TEACHING = "Normal game", "Teaching game" -AI_DEFAULT = "default" - - class Player: def __init__(self, player="B", player_type=PLAYER_HUMAN, player_subtype=PLAYING_NORMAL, periods_used=0): self.player = player diff --git a/katrain/core/utils.py b/katrain/core/utils.py index 187608d..95d3884 100644 --- a/katrain/core/utils.py +++ b/katrain/core/utils.py @@ -57,8 +57,6 @@ def find_package_resource(path): return path # absolute path - - class Lang(Observable): observers = [] callbacks = [] @@ -69,8 +67,8 @@ class Lang(Observable): self.switch_lang(lang) def _(self, text): - if text=='': - return '' # just for font change + if text == "": + return "" # just for font change return self.ugettext(text) def fbind(self, name, func, *args): @@ -90,9 +88,8 @@ class Lang(Observable): else: return super(Lang, self).funbind(name, func, *args) - def add_callback(self,callback_fn: Callable): + def add_callback(self, callback_fn: Callable): self.callbacks.append(callback_fn) - print("ADDING CB") def switch_lang(self, lang): # get the right locales directory, and instantiate a gettext @@ -113,9 +110,8 @@ class Lang(Observable): for cb in self.callbacks: try: cb(self) - print("CALLING CB") except Exception as e: - print(f"Failed callback on language change: {e}",file=sys.stderr) + print(f"Failed callback on language change: {e}", file=sys.stderr) DEFAULT_LANGUAGE = "en" diff --git a/katrain/gui.kv b/katrain/gui.kv index 38295e6..1bc2ec9 100644 --- a/katrain/gui.kv +++ b/katrain/gui.kv @@ -9,6 +9,7 @@ #:set GRAPH_DOT_COLOR [0.85, 0.3, 0.3,1] #-- NEW +#:import PLAYER_TYPES __main__.PLAYER_TYPES #:import RED __main__.RED #:import WHITE __main__.WHITE @@ -124,8 +125,7 @@ : background_radius: self.height/3.5 - -: +: background_color: BOX_BACKGROUND_COLOR : @@ -140,14 +140,35 @@ mipmap: True +: + background_color: BACKGROUND_COLOR + background_normal: '' + lang_change_tracking: i18n._('') # for font + color: WHITE + canvas.after: + Color: + rgba: LIGHTGREY + Line + points: self.pos[0],self.pos[1],self.pos[0]+self.width,self.pos[1] + width: 1 + +: + text: self.values[0] if self.values else '' + font_size: self.height * 0.5 + sync_height_frac: 1.0 + background_color: [*[c*255/88 for c in BACKGROUND_COLOR[:3]], 1] # compensate for texture + option_cls: 'StyledSpinnerOption' + + + # -- old widgets : color: WHITE - font_size: self.size[1] * 0.45 - radius: (self.size[1]/7,) + font_size: self.height * 0.45 + radius: (self.height/7,) button_color: BUTTON_COLOR button_color_down: [0.105, 0.14, 0.155, 1] button_color_highlight: [(a+b)/2 for a,b in zip(self.button_color,self.button_color_down)] @@ -157,27 +178,10 @@ Color: rgba: self.button_color if root.state=='normal' else self.button_color_down RoundedRectangle: - size: self.size[0],self.size[1] + size: self.size[0],self.height pos: (self.pos[0],self.pos[1]) radius: root.radius -: - background_color: BUTTON_COLOR - background_normal: '' - color: WHITE - canvas.after: - Color: - rgba: WHITE - Line - points: self.pos[0],self.pos[1],self.pos[0]+self.width,self.pos[1] - width: 1 - -: - text: self.values[0] if self.values else '' - font_size: self.size[1] * 0.33 - sync_height_frac: 0.7 - background_color: [*[c*255/88 for c in BUTTON_COLOR[:3]], 1] # compensate for texture - option_cls: 'StyledSpinnerOption' : max_lines: 1 @@ -185,19 +189,19 @@ : : - padding: 3, 0.27*self.size[1] - font_size: 0.4*self.size[1] + padding: 3, 0.27*self.height + font_size: 0.4*self.height : - font_size: 0.5*self.size[1] - padding: 7, 0.2*self.size[1] + font_size: 0.5*self.height + padding: 7, 0.2*self.height : - font_size: 0.5*self.size[1] - padding: 7, 0.2*self.size[1] + font_size: 0.5*self.height + padding: 7, 0.2*self.height - font_size: 0.2*self.size[1] + font_size: 0.2*self.height : color: BLACK @@ -211,7 +215,7 @@ button_color_down: ICON_BUTTON_COLOR_DOWN icon_margin: 0.15 * self.size[0] icon: '' - icon_size: min(self.size[0]-2*self.icon_margin,self.size[1]-2*self.icon_margin) + icon_size: min(self.size[0]-2*self.icon_margin,self.height-2*self.icon_margin) Image: size: (root.icon_size or 0,root.icon_size or 0) # square pos: [root.pos[i] + (root.size[i] - root.icon_size)/2 for i in [0,1]] if root.icon_size else [0,0] @@ -228,10 +232,10 @@ : # popups color: TEXT_COLOR - font_size: 0.45*self.size[1]/self.num_lines + font_size: 0.45*self.height/self.num_lines : - font_size: self.size[1]/10 + font_size: self.height/10 halign: 'center' valign: 'middle' multiline: True @@ -249,7 +253,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=='White' else 'img/black.png' + source: 'img/white.png' if root.player=='W' else 'img/black.png' mipmap: True Label: id: lbl @@ -257,7 +261,7 @@ text_size: None, root.min_size bold: True valign: 'center' - color: BLACK if root.player=='White' else WHITE + color: BLACK if root.player=='W' else WHITE pos: (image.x, image.y) size: image.size font_size: root.min_size * 1.2 / (1 + 1 * len(self.text)) @@ -271,7 +275,7 @@ : size_hint: 0.06, 0.4 - icon_size: [min(self.size[0],self.size[1]),min(self.size[0],self.size[1])] + icon_size: [min(self.size[0],self.height),min(self.size[0],self.height)] pos_hint: {'center_y': 0.5} : @@ -308,13 +312,13 @@ size_hint: 5/8, 1 pos_hint: {'center_x': 0.5-3/16} id: black_circle - player: 'Black' + player: 'B' text: '' CircleWithText: size_hint: 5/8, 1 pos_hint: {'center_x': 0.5+3/16} id: white_circle - player: 'White' + player: 'W' text: '' NavIconButton: icon: 'img/flaticon/next.png' @@ -326,7 +330,7 @@ icon: 'img/flaticon/next999.png' on_press: root.katrain('redo',999) NavIconButton: - icon: 'img/flaticon/route.png' + icon: 'img/forward_-_child.png' on_press: root.katrain('switch-branch',1) ClickableLabel: pos_hint: {'center_x': 0.85,'center_y':0.5} @@ -349,13 +353,13 @@ : icon: 'img/hamburger.png' width: self.height - icon_size: [self.height * 0.8, self.height * 0.8] + icon_size: [self.height * 0.6, self.height * 0.6] # ---------- components of right pane ------- : captures: 0 - player: 'Black' + player: 'B' player_type: 'Player' player_subtype: 'Normal game' background_color: BOX_BACKGROUND_COLOR if self.active else BACKGROUND_COLOR @@ -420,23 +424,38 @@ color: GREEN markup: True multiline: False - font_name: 'fonts/digital-7.ttf' + font_name: 'fonts/digital-7 (mono).ttf' -: - state: (30,5,1) +: spacing: CP_SPACING padding: CP_PADDING * 4, CP_PADDING * 2 paused: True MDBoxLayout: size_hint: 0.7,1 - TimerLabel: + MDFloatLayout: + canvas.before: + Color: + rgba: GREEN + Line: + rectangle: (*self.pos,*self.size) + width: 1 size_hint: 0.4,1 - id: timer - text_size: self.size - halign: 'right' - valign: 'middle' - font_size: 0.85*self.size[1] - text: f"{root.state[0]//60}:{int(root.state[0] % 60):02d}" + TimerLabel: + color: BACKGROUND_COLOR + text: '8:88' + text_size: self.size + font_size: 0.85*self.height + pos_hint: {'right':1,'center_y':0.5} + halign: 'right' + valign: 'middle' + TimerLabel: + id: timer + text: "{:01d}:{:02d}".format(int(root.state[0])//60,int(root.state[0] % 60) ) + text_size: self.size + font_size: 0.85*self.height + pos_hint: {'right':1,'center_y':0.5} + halign: 'right' + valign: 'middle' TimerLabel: size_hint: 0.05,1 text: "x" @@ -552,7 +571,7 @@ size_hint: 0.6,1 id: desc text: root.label if not root.hidden else '' - font_size: self.size[1] * 0.7 + font_size: self.height * 0.7 font_name: root.font_name text_size: self.size valign: 'middle' @@ -658,10 +677,10 @@ height: root.player_box_height PlayerInfo: id: B_player - player: 'Black' + player: 'B' PlayerInfo: id: W_player - player: 'White' + player: 'W' BoxLayout: size_hint_y: None height: root.timer_box_height @@ -867,22 +886,54 @@ size_hint: 1,None -: +: orientation: 'horizontal' - CircleWithText: - text: root.player[0] - player: root.player - Label: - text: 'type' - Label: - text: 'subtype' + spacing: CP_SPACING + padding: 0, CP_PADDING + player_type: player_type + player_subtype: player_subtype + player_subtype_label: player_subtype_label + MDBoxLayout: + size_hint: 0.25, 1 + CircleWithText: + size_hint: 0.8, 0.8 + pos_hint: {'center_x':0.5,'center_y':0.5} + text: root.player[0] + player: root.player + MDBoxLayout: + size_hint: 0.5, 1 + orientation: 'vertical' + spacing: CP_SPACING + Label: + text: i18n._('player:type') + font_size: self.height * 0.5 + StyledSpinner: + id: player_type + value_refs: PLAYER_TYPES + on_text: root.setup_options(*args) + MDBoxLayout: + size_hint: 0.5, 1 + orientation: 'vertical' + spacing: CP_SPACING + Label: + text: 'Player Type' + id: player_subtype_label + font_size: self.height * 0.5 + StyledSpinner: + id: player_subtype + value_refs: [] + on_text: root.set_player() : orientation: 'vertical' + size_hint_y: None + spacing: 3*CP_SPACING + padding: CP_PADDING + height: (self.parent.item_height or 50) * 5 PlayerSetup: - player: 'Black' + player: 'B' PlayerSetup: - player: 'White' + player: 'W' : katrain: app.gui @@ -892,6 +943,8 @@ MenuLabel: text: i18n._('menu:playersetup') PlayerSetupBlock: + MenuLabel: + size_hint: 1,1 MenuLabel: MDBoxLayout: orientation: 'vertical' @@ -906,17 +959,33 @@ height: root.item_height MainMenuItem: text: i18n._('menu:save') - icon: 'img/flaticon/savegame.png' + icon: 'img/flaticon/floppy-disk.png' shortcut: 'Ctrl-S' on_action: root.katrain("analyze-sgf-popup") MainMenuItem: text: i18n._('menu:load') - icon: 'img/flaticon/loadgame.png' + icon: 'img/flaticon/folder.png' shortcut: 'Ctrl-L' on_action: root.katrain("analyze-sgf-popup") + MainMenuItem: + text: i18n._('menu:clocksettings') + icon: 'img/flaticon/cogwheel.png' + shortcut: 'F5' + on_action: root.katrain('timer-popup') + MainMenuItem: + text: i18n._('menu:teachsettings') + icon: 'img/flaticon/graduate.png' + shortcut: 'F6' + on_action: root.katrain('teacher-popup') + MainMenuItem: + text: i18n._('menu:aisettings') + icon: 'img/flaticon/ai.png' + shortcut: 'F7' + on_action: root.katrain('ai-popup') MainMenuItem: text: i18n._('menu:settings') icon: 'img/flaticon/settings.png' + shortcut: 'F8' on_action: root.katrain('config-popup') MenuLabel: text: i18n._('menu:lang') @@ -949,6 +1018,8 @@ allow_no_selection: False : + play: play + analyze: analyze OutlineBox: outline_color: WHITE size_hint: 0.7,0.7 @@ -1072,8 +1143,8 @@ text: "Size" LabelledTextInput: text: '19' - font_size: 0.5*self.size[1] - padding: 7, 0.2*self.size[1] + font_size: 0.5*self.height + padding: 7, 0.2*self.height input_property: 'SZ' BoxLayout: spacing: 1 @@ -1125,21 +1196,21 @@ color: WHITE id: restart ScaledLightLabel: - font_size: 0.35*self.size[1] + font_size: 0.35*self.height text: 'avoids replaying\nidentical games' LightHelpLabel: text: "Use x:y (e.g. 19:9) to play on a non-square board." size_hint: 1,2 text_size: self.width-6, None - font_size: self.size[1]/6 + font_size: self.height/6 id: info LightHelpLabel: text: "Note that handicaps above 9 are not supported on non-square boards." - font_size: self.size[1]/6 + font_size: self.height/6 text_size: self.width-6, None id: info StyledButton: halign: 'center' text: 'Start\nGame' - font_size: 0.3 * self.size[1] + font_size: 0.3 * self.height on_left_press: if not self.last_touch or self.last_touch.button=="left": root.new_game() diff --git a/katrain/gui/controlspanel.py b/katrain/gui/controlspanel.py index 4dbb780..9ca2af0 100644 --- a/katrain/gui/controlspanel.py +++ b/katrain/gui/controlspanel.py @@ -7,9 +7,7 @@ from kivy.uix.popup import Popup from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.floatlayout import MDFloatLayout -from katrain.core.utils import MODE_PLAY, MODE_ANALYZE -from katrain.gui.popups import ConfigTeacherPopup, ConfigTimerPopup -from katrain.gui.ai_settings import ConfigAIPopupContents +from katrain.core.utils import MODE_PLAY, MODE_ANALYZE, i18n class PlayAnalyzeSelect(MDFloatLayout): @@ -18,13 +16,13 @@ class PlayAnalyzeSelect(MDFloatLayout): @property def play_analyze_mode(self): - return MODE_PLAY if self.play_mode.play.status == "down" else MODE_ANALYZE + return MODE_PLAY if self.play.active else MODE_ANALYZE def switch_mode(self): # TODO: load settings if self.play_analyze_mode == MODE_PLAY: - self.play.trigger_action(duration=0) - else: self.analyze.trigger_action(duration=0) + else: + self.play.trigger_action(duration=0) class ControlsPanel(BoxLayout): @@ -35,15 +33,14 @@ class ControlsPanel(BoxLayout): super(ControlsPanel, self).__init__(**kwargs) self.status_msg = None self.status_node = None - self.ai_settings_popup = None - self.teacher_settings_popup = None self.active_comment_node = None - self.timer_settings_popup = None self.last_timer_update = (None, 0) Clock.schedule_interval(self.update_timer, 0.07) - def check_hide_show(self, *_args): - pass + def update_players(self, *_args): + for player, info in self.katrain.game.players.items(): + self.players[player].player_type = i18n._(info.player_type) + self.players[player].player_subtype = i18n._(info.player_subtype) def set_status(self, msg, at_node=None): self.status_msg = msg @@ -62,7 +59,6 @@ class ControlsPanel(BoxLayout): self.status.text = "" self.status_node = None - both_players_are_robots = all(p.ai for p in game.players.values()) last_player_was_ai_playing_human = game.last_player.ai and game.next_player.human self.active_comment_node = current_node @@ -92,18 +88,6 @@ class ControlsPanel(BoxLayout): self.note.text = current_node.note self.info.text = info - def configure_ais(self): - if not self.ai_settings_popup: # persist state of popup etc - self.ai_settings_popup = Popup(title="Edit AI Settings", size_hint=(0.7, 0.8)).__self__ - self.ai_settings_popup.add_widget(ConfigAIPopupContents(self.katrain, self.ai_settings_popup, self.katrain.config("ai"))) - self.ai_settings_popup.open() - - def configure_teacher(self): - if not self.teacher_settings_popup: - self.teacher_settings_popup = Popup(title="Edit Teacher Settings", size_hint=(0.7, 0.8)).__self__ - self.teacher_settings_popup.add_widget(ConfigTeacherPopup(self.katrain, self.teacher_settings_popup)) - self.teacher_settings_popup.open() - def update_timer(self, _dt): current_node = self.katrain and self.katrain.game and self.katrain.game.current_node if current_node: @@ -127,10 +111,3 @@ class ControlsPanel(BoxLayout): time_remaining = byo_len - current_node.time_used periods_rem = byo_num - player.periods_used self.timer.state = (time_remaining, periods_rem, ai) - - def configure_timer(self): - self.pause.state = "down" - if not self.timer_settings_popup: - self.timer_settings_popup = Popup(title="Edit Timer Settings", size_hint=(0.4, 0.4)).__self__ - self.timer_settings_popup.add_widget(ConfigTimerPopup(self.katrain, self.timer_settings_popup)) - self.timer_settings_popup.open() diff --git a/katrain/gui/kivyutils.py b/katrain/gui/kivyutils.py index 023651c..a78b6ca 100644 --- a/katrain/gui/kivyutils.py +++ b/katrain/gui/kivyutils.py @@ -13,7 +13,7 @@ from kivy.uix.filechooser import FileChooserLayout, FileChooserListLayout from kivy.uix.gridlayout import GridLayout from kivy.uix.label import Label from kivy.uix.scrollview import ScrollView -from kivy.uix.spinner import Spinner +from kivy.uix.spinner import Spinner, SpinnerOption from kivy.uix.textinput import TextInput from kivy.uix.widget import Widget @@ -25,6 +25,8 @@ from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.button import BasePressedButton, BaseFlatButton from kivymd.uix.navigationdrawer import MDNavigationDrawer from kivy.core.text import Label as CoreLabel + +from katrain.core.constants import GAME_TYPES from katrain.core.utils import i18n # @@ -97,6 +99,10 @@ class ToggleButtonMixin(ToggleButtonBehavior): inactive_background_color = ListProperty([0.5, 0.5, 0.5, 1]) active_background_color = ListProperty([1, 1, 1, 1]) + @property + def active(self): + return self.state == "down" + class SizedToggleButton(ToggleButtonMixin, SizedButton): pass @@ -156,24 +162,101 @@ class MyNavigationDrawer(MDNavigationDrawer): # in PR - closes NavDrawer on any class CircleWithText(Widget): text = StringProperty("0") - player = OptionProperty("Black", options=["Black", "White"]) + player = OptionProperty("B", options=["B", "W"]) min_size = NumericProperty(50) +class BGMDBoxLayout(MDBoxLayout, BackgroundMixin): + pass + + # -- new gui elements + +class StyledSpinner(Spinner): + sync_height_frac = NumericProperty(1.0) + value_refs = ListProperty() + font_name = StringProperty(DEFAULT_FONT) + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.bind(size=self.update_dropdown_props, pos=self.update_dropdown_props, value_refs=self.i18n_values) + self.i18n_values() + + @property + def selected(self): + try: + selected = self.values.index(self.text) + return selected, self.value_refs[selected], self.values[selected] + except (ValueError, IndexError): + return 0, "", "" + + def i18n_values(self, *_args): + if self.value_refs: + selected = self.selected[0] + self.values = [i18n._(ref) for ref in self.value_refs] + print(self.selected, self.values, self.value_refs) + self.text = self.values[selected] + self.font_name = i18n.font_name + self.update_dropdown_props() + + def update_dropdown_props(self, *largs): + if not self.sync_height_frac: + return + dp = self._dropdown + if not dp: + return + container = dp.container + if not container: + return + h = self.height + fsz = self.font_size + for item in container.children[:]: + item.height = h * self.sync_height_frac + item.font_size = fsz + item.font_name = self.font_name + + class PlayerSetup(MDBoxLayout): - player = OptionProperty("Black", options=["Black", "White"]) + player = OptionProperty("B", options=["B", "W"]) + + def __init__(self, **kwargs): + super().__init__(**kwargs) + Clock.schedule_once(self.setup_options, 0) + + def setup_options(self, *_args): + self.player_subtype.clear_widgets() + if self.player_type.selected[0] == 0: # human + self.player_subtype_label.text = i18n._("gametype") + self.player_subtype.value_refs = GAME_TYPES + else: + self.player_subtype_label.text = i18n._("aistrategy") + self.player_subtype.value_refs = MDApp.get_running_app().gui.ai_strategies # TODO: + self.player_subtype.text = self.player_subtype.values[0] + self.set_player() + + def set_player(self): + katrain = MDApp.get_running_app().gui + game = katrain and katrain.game + if game: + game.players[self.player].player_type = self.player_type.selected[1] + game.players[self.player].player_subtype = self.player_subtype.selected[1] + katrain.controls.update_players() + katrain.update_state() class PlayerInfo(MDBoxLayout, BackgroundMixin): captures = NumericProperty(0) - player = OptionProperty("Black", options=["Black", "White"]) + player = OptionProperty("B", options=["B", "W"]) player_type = StringProperty("Player") player_subtype = StringProperty("") active = BooleanProperty(True) +class Timer(BGMDBoxLayout): + state = ListProperty([30, 5, 1]) + + class AnalysisToggle(MDBoxLayout): text = StringProperty("") default_active = BooleanProperty(False) @@ -398,29 +481,6 @@ class StyledToggleButton(StyledButton, ToggleButtonBehavior, ToolTipBehavior): self.state = "normal" if self.state == "down" else "down" -class StyledSpinner(Spinner): - sync_height_frac = NumericProperty(1.0) - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.bind(size=self._update_dropdown_size_frac, pos=self._update_dropdown_size_frac) - - def _update_dropdown_size_frac(self, *largs): - if not self.sync_height_frac: - return - dp = self._dropdown - if not dp: - return - container = dp.container - if not container: - return - h = self.height - fsz = self.font_size - for item in container.children[:]: - item.height = h * self.sync_height_frac - item.font_size = fsz - - class ToggleButtonContainer(GridLayout): __events__ = ("on_selection",) @@ -544,7 +604,7 @@ class LabelledIntInput(LabelledTextInput): def draw_text(pos, text, font_name=None, **kw): - label = CoreLabel(text=text, bold=True, font_name=font_name or i18n.font, **kw) # + label = CoreLabel(text=text, bold=True, font_name=font_name or i18n.font_name, **kw) # label.refresh() Rectangle(texture=label.texture, pos=(pos[0] - label.texture.size[0] / 2, pos[1] - label.texture.size[1] / 2), size=label.texture.size) diff --git a/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo index 0b2bff2..010e4e9 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 fdae16e..9c9cb3e 100644 --- a/katrain/i18n/locales/en/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/en/LC_MESSAGES/katrain.po @@ -22,12 +22,43 @@ msgstr "Load Game" msgid "menu:settings" msgstr "General Settings" +msgid "menu:clocksettings" +msgstr "Timer Settings" + +msgid "menu:teachsettings" +msgstr "Teaching Game Settings" + +msgid "menu:aisettings" +msgstr "AI Settings" + msgid "menu:lang" msgstr "Language" msgid "menu:support" msgstr "Support or Contribute" +#. player options in the setup and on the right +msgid "player:type" +msgstr "Player" + +msgid "player:human" +msgstr "Human" + +msgid "player:ai" +msgstr "AI" + +msgid "aistrategy" +msgstr "AI Strategy" + +msgid "gametype" +msgstr "Game Type" + +msgid "game:normal" +msgstr "Normal Game" + +msgid "game:teach" +msgstr "Teaching Game" + #. buttons at the top - should all include a line break msgid "analysis:nextmoves" msgstr "" diff --git a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo index bf733fe..032bb26 100644 Binary files a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.po b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.po index 8edc4ee..99a620b 100644 --- a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.po @@ -227,3 +227,47 @@ msgstr "Support or Contribute" #. TODO msgid "wait-before-equalize" msgstr "Wait for initial analysis to complete before requesting a refinement." + +#. TODO +msgid "game:teaching" +msgstr "Teaching Game" + +#. TODO +msgid "aistrategy" +msgstr "AI Strategy" + +#. TODO +msgid "game:normal" +msgstr "Normal Game" + +#. TODO +msgid "player:human" +msgstr "AI" + +#. TODO +msgid "player:type" +msgstr "Player" + +#. TODO +msgid "gametype" +msgstr "Game Type" + +#. TODO +msgid "player:ai" +msgstr "AI" + +#. TODO +msgid "game:teach" +msgstr "Teaching Game" + +#. TODO +msgid "menu:clocksettings" +msgstr "Timer Settings" + +#. TODO +msgid "menu:teachsettings" +msgstr "Teaching Game Settings" + +#. TODO +msgid "menu:aisettings" +msgstr "AI Settings" diff --git a/katrain/i18n/locales/nl/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/nl/LC_MESSAGES/katrain.mo index b762a7b..58dd771 100644 Binary files a/katrain/i18n/locales/nl/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/nl/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/nl/LC_MESSAGES/katrain.po b/katrain/i18n/locales/nl/LC_MESSAGES/katrain.po index 3bc9f57..88bda5b 100644 --- a/katrain/i18n/locales/nl/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/nl/LC_MESSAGES/katrain.po @@ -259,3 +259,47 @@ msgstr "Support or Contribute" #. TODO msgid "wait-before-equalize" msgstr "Wait for initial analysis to complete before requesting a refinement." + +#. TODO +msgid "game:teaching" +msgstr "Teaching Game" + +#. TODO +msgid "aistrategy" +msgstr "AI Strategy" + +#. TODO +msgid "game:normal" +msgstr "Normal Game" + +#. TODO +msgid "player:human" +msgstr "AI" + +#. TODO +msgid "player:type" +msgstr "Player" + +#. TODO +msgid "gametype" +msgstr "Game Type" + +#. TODO +msgid "player:ai" +msgstr "AI" + +#. TODO +msgid "game:teach" +msgstr "Teaching Game" + +#. TODO +msgid "menu:clocksettings" +msgstr "Timer Settings" + +#. TODO +msgid "menu:teachsettings" +msgstr "Teaching Game Settings" + +#. TODO +msgid "menu:aisettings" +msgstr "AI Settings" diff --git a/katrain/img/back_-_parentpng.png b/katrain/img/back_-_parentpng.png new file mode 100644 index 0000000..2f7f697 Binary files /dev/null and b/katrain/img/back_-_parentpng.png differ diff --git a/katrain/img/flaticon/ai.png b/katrain/img/flaticon/ai.png new file mode 100644 index 0000000..3d832db Binary files /dev/null and b/katrain/img/flaticon/ai.png differ diff --git a/katrain/img/flaticon/cogwheel.png b/katrain/img/flaticon/cogwheel.png index 332f832..6fee5b5 100644 Binary files a/katrain/img/flaticon/cogwheel.png and b/katrain/img/flaticon/cogwheel.png differ diff --git a/katrain/img/flaticon/floppy-disk.png b/katrain/img/flaticon/floppy-disk.png new file mode 100644 index 0000000..841b76d Binary files /dev/null and b/katrain/img/flaticon/floppy-disk.png differ diff --git a/katrain/img/flaticon/folder.png b/katrain/img/flaticon/folder.png new file mode 100644 index 0000000..bb9f45d Binary files /dev/null and b/katrain/img/flaticon/folder.png differ diff --git a/katrain/img/flaticon/graduate.png b/katrain/img/flaticon/graduate.png new file mode 100644 index 0000000..4b896b6 Binary files /dev/null and b/katrain/img/flaticon/graduate.png differ diff --git a/katrain/img/flaticon/newgame - Copy.png b/katrain/img/flaticon/newgame - Copy.png new file mode 100644 index 0000000..5cafc67 Binary files /dev/null and b/katrain/img/flaticon/newgame - Copy.png differ diff --git a/katrain/img/flaticon/newgame.png b/katrain/img/flaticon/newgame.png index 5cafc67..e797736 100644 Binary files a/katrain/img/flaticon/newgame.png and b/katrain/img/flaticon/newgame.png differ diff --git a/katrain/img/flaticon/route.png b/katrain/img/flaticon/route.png deleted file mode 100644 index 157a05c..0000000 Binary files a/katrain/img/flaticon/route.png and /dev/null differ diff --git a/katrain/img/flaticon/settings.png b/katrain/img/flaticon/settings.png index 3d45e9a..0dc8f11 100644 Binary files a/katrain/img/flaticon/settings.png and b/katrain/img/flaticon/settings.png differ diff --git a/katrain/img/forward_-_child.png b/katrain/img/forward_-_child.png new file mode 100644 index 0000000..0ad8638 Binary files /dev/null and b/katrain/img/forward_-_child.png differ diff --git a/katrain/img/hamburger.png b/katrain/img/hamburger.png index 0877347..f337350 100644 Binary files a/katrain/img/hamburger.png and b/katrain/img/hamburger.png differ