icons, timers, menus, player setup
No files matched your search
@@ -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.
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 @@
|
||||
<AutoSizedRoundedRectangleButton@AutoSizedRectangleButton>:
|
||||
background_radius: self.height/3.5
|
||||
|
||||
|
||||
<BGMDBoxLayout@MDBoxLayout+BackgroundMixin>:
|
||||
<BGMDBoxLayout>:
|
||||
background_color: BOX_BACKGROUND_COLOR
|
||||
|
||||
<TransparentIconButton>:
|
||||
@@ -140,14 +140,35 @@
|
||||
mipmap: True
|
||||
|
||||
|
||||
<StyledSpinnerOption@SpinnerOption>:
|
||||
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
|
||||
|
||||
<StyledSpinner>:
|
||||
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
|
||||
|
||||
|
||||
|
||||
<StyledButton>:
|
||||
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
|
||||
|
||||
<StyledSpinnerOption@SpinnerOption>:
|
||||
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
|
||||
|
||||
<StyledSpinner>:
|
||||
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'
|
||||
|
||||
<StyledToggleButton>:
|
||||
max_lines: 1
|
||||
@@ -185,19 +189,19 @@
|
||||
<ToggleButtonContainer>:
|
||||
|
||||
<LabelledTextInput>:
|
||||
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
|
||||
|
||||
<LabelledIntInput>:
|
||||
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
|
||||
|
||||
<LabelledFloatInput>:
|
||||
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
|
||||
|
||||
<LabelledTextArea>
|
||||
font_size: 0.2*self.size[1]
|
||||
font_size: 0.2*self.height
|
||||
|
||||
<CheckBox>:
|
||||
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 @@
|
||||
|
||||
<ScaledLightLabel>: # popups
|
||||
color: TEXT_COLOR
|
||||
font_size: 0.45*self.size[1]/self.num_lines
|
||||
font_size: 0.45*self.height/self.num_lines
|
||||
|
||||
<LightHelpLabel>:
|
||||
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 @@
|
||||
|
||||
<NavIconButton@TransparentIconButton>:
|
||||
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}
|
||||
|
||||
<BadukPanControls>:
|
||||
@@ -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 @@
|
||||
<HamburgerButton@TransparentIconButton>:
|
||||
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 -------
|
||||
|
||||
<PlayerInfo>:
|
||||
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'
|
||||
|
||||
<Timer@BGMDBoxLayout>:
|
||||
state: (30,5,1)
|
||||
<Timer>:
|
||||
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
|
||||
|
||||
|
||||
<PlayerSetup@MDBoxLayout>:
|
||||
<PlayerSetup>:
|
||||
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()
|
||||
|
||||
<PlayerSetupBlock@MDBoxLayout>:
|
||||
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'
|
||||
|
||||
<ContentNavigationDrawer@MDBoxLayout+BackgroundMixin>:
|
||||
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
|
||||
|
||||
<PlayAnalyzeSelect>:
|
||||
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()
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.7 KiB |