Merge branch '1.7' of github.com:sanderland/katrain into 1.7
This commit is contained in:
commit
587109ae27
4 files changed
+52
-24
No files matched your search
@@ -176,12 +176,12 @@ Keyboard shortcuts are shown with **[key]**.
|
|||||||
|
|
||||||
In addition to shortcuts mentioned above and those shown in the main menu:
|
In addition to shortcuts mentioned above and those shown in the main menu:
|
||||||
|
|
||||||
* **[Shift]**: Open the main menu.
|
* **[Alt]**: Open the main menu.
|
||||||
* **[~]** or **[ ` ]** or **[f12]**: Cycles through more minimalistic UI modes.
|
* **[~]** or **[ ` ]** or **[F12]**: Cycles through more minimalistic UI modes.
|
||||||
* **[p]**: Pass
|
* **[p]**: Pass
|
||||||
* **[pause]**: Pause/Resume timer
|
* **[pause]**: Pause/Resume timer
|
||||||
* **[arrow left]** or **[z]**: Undo move. Hold alt for 10 moves at a time, or ctrl to skip to the start.
|
* **[arrow left]** or **[z]**: Undo move. Hold shift for 10 moves at a time, or ctrl to skip to the start.
|
||||||
* **[arrow right]** or **[x]**: Redo move. Hold alt for 10 moves at a time, or ctrl to skip to the end.
|
* **[arrow right]** or **[x]**: Redo move. Hold shift for 10 moves at a time, or ctrl to skip to the end.
|
||||||
* **[arrow up/down]** Switch branch, as would be expected from the move tree.
|
* **[arrow up/down]** Switch branch, as would be expected from the move tree.
|
||||||
* **[home/end]** Go to the beginning/end of the game.
|
* **[home/end]** Go to the beginning/end of the game.
|
||||||
* **[pageup]** Make the currently selected node the main branch
|
* **[pageup]** Make the currently selected node the main branch
|
||||||
|
|||||||
+18
-4
@@ -537,12 +537,11 @@ class KaTrainGui(Screen, KaTrainBase):
|
|||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
ctrl_pressed = "ctrl" in modifiers
|
ctrl_pressed = "ctrl" in modifiers
|
||||||
alt_pressed = "alt" in modifiers
|
|
||||||
shift_pressed = "shift" in modifiers
|
shift_pressed = "shift" in modifiers
|
||||||
shortcuts = self.shortcuts
|
shortcuts = self.shortcuts
|
||||||
if keycode[1] == "tab":
|
if keycode[1] == "tab":
|
||||||
self.play_mode.switch_ui_mode()
|
self.play_mode.switch_ui_mode()
|
||||||
elif keycode[1] == "shift":
|
elif keycode[1] == "alt":
|
||||||
self.nav_drawer.set_state("toggle")
|
self.nav_drawer.set_state("toggle")
|
||||||
elif keycode[1] == "spacebar":
|
elif keycode[1] == "spacebar":
|
||||||
self.toggle_continuous_analysis()
|
self.toggle_continuous_analysis()
|
||||||
@@ -551,9 +550,9 @@ class KaTrainGui(Screen, KaTrainBase):
|
|||||||
elif keycode[1] in ["`", "~", "f12"]:
|
elif keycode[1] in ["`", "~", "f12"]:
|
||||||
self.zen = (self.zen + 1) % 3
|
self.zen = (self.zen + 1) % 3
|
||||||
elif keycode[1] in ["left", "z"]:
|
elif keycode[1] in ["left", "z"]:
|
||||||
self("undo", 1 + (alt_pressed or shift_pressed) * 9 + (ctrl_pressed and not alt_pressed) * 999)
|
self("undo", 1 + shift_pressed * 9 + ctrl_pressed * 999)
|
||||||
elif keycode[1] in ["right", "x"]:
|
elif keycode[1] in ["right", "x"]:
|
||||||
self("redo", 1 + (alt_pressed or shift_pressed) * 9 + (ctrl_pressed and not alt_pressed) * 999)
|
self("redo", 1 + shift_pressed * 9 + ctrl_pressed * 999)
|
||||||
elif keycode[1] == "home":
|
elif keycode[1] == "home":
|
||||||
self("undo", 999)
|
self("undo", 999)
|
||||||
elif keycode[1] == "end":
|
elif keycode[1] == "end":
|
||||||
@@ -583,6 +582,19 @@ class KaTrainGui(Screen, KaTrainBase):
|
|||||||
shortcut.trigger_action(duration=0)
|
shortcut.trigger_action(duration=0)
|
||||||
else:
|
else:
|
||||||
self(*shortcut)
|
self(*shortcut)
|
||||||
|
elif keycode[1] == "f9" and self.debug_level >= OUTPUT_EXTRA_DEBUG:
|
||||||
|
import yappi
|
||||||
|
|
||||||
|
yappi.set_clock_type("cpu")
|
||||||
|
yappi.start()
|
||||||
|
self.log("starting profiler", OUTPUT_ERROR)
|
||||||
|
elif keycode[1] == "f10" and self.debug_level >= OUTPUT_EXTRA_DEBUG:
|
||||||
|
import yappi, time
|
||||||
|
|
||||||
|
stats = yappi.get_func_stats()
|
||||||
|
filename = f"callgrind.{int(time.time())}.prof"
|
||||||
|
stats.save(filename, type="callgrind")
|
||||||
|
self.log(f"wrote profiling results to {filename}", OUTPUT_ERROR)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@@ -594,6 +606,7 @@ class KaTrainApp(MDApp):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
|
global DEFAULT_FONT
|
||||||
self.icon = ICON # how you're supposed to set an icon
|
self.icon = ICON # how you're supposed to set an icon
|
||||||
|
|
||||||
self.title = f"KaTrain v{VERSION}"
|
self.title = f"KaTrain v{VERSION}"
|
||||||
@@ -604,6 +617,7 @@ class KaTrainApp(MDApp):
|
|||||||
kv_file = find_package_resource("katrain/gui.kv")
|
kv_file = find_package_resource("katrain/gui.kv")
|
||||||
popup_kv_file = find_package_resource("katrain/popups.kv")
|
popup_kv_file = find_package_resource("katrain/popups.kv")
|
||||||
resource_add_path(PATHS["PACKAGE"])
|
resource_add_path(PATHS["PACKAGE"])
|
||||||
|
DEFAULT_FONT = resource_find(DEFAULT_FONT)
|
||||||
Builder.load_file(kv_file)
|
Builder.load_file(kv_file)
|
||||||
|
|
||||||
Window.bind(on_request_close=self.on_request_close)
|
Window.bind(on_request_close=self.on_request_close)
|
||||||
|
|||||||
+17
-16
@@ -33,7 +33,7 @@ from katrain.core.constants import (
|
|||||||
from katrain.core.game import Move
|
from katrain.core.game import Move
|
||||||
from katrain.core.lang import i18n
|
from katrain.core.lang import i18n
|
||||||
from katrain.core.utils import evaluation_class, format_visits, var_to_grid
|
from katrain.core.utils import evaluation_class, format_visits, var_to_grid
|
||||||
from katrain.gui.kivyutils import BackgroundMixin, draw_circle, draw_text
|
from katrain.gui.kivyutils import BackgroundMixin, draw_circle, draw_text, cached_texture
|
||||||
from katrain.gui.popups import I18NPopup, ReAnalyzeGamePopup
|
from katrain.gui.popups import I18NPopup, ReAnalyzeGamePopup
|
||||||
from katrain.gui.style import *
|
from katrain.gui.style import *
|
||||||
|
|
||||||
@@ -55,8 +55,9 @@ class BadukPanWidget(Widget):
|
|||||||
self.animating_pv = None
|
self.animating_pv = None
|
||||||
self.last_mouse_pos = (0, 0)
|
self.last_mouse_pos = (0, 0)
|
||||||
Window.bind(mouse_pos=self.on_mouse_pos)
|
Window.bind(mouse_pos=self.on_mouse_pos)
|
||||||
self.redraw_board_contents_trigger = Clock.create_trigger(self.draw_board_contents)
|
self.redraw_board_contents_trigger = Clock.create_trigger(self.draw_board_contents, 0.05)
|
||||||
self.redraw_trigger = Clock.create_trigger(self.redraw)
|
self.redraw_trigger = Clock.create_trigger(self.redraw, 0.05)
|
||||||
|
self.redraw_hover_contents_trigger = Clock.create_trigger(self.draw_hover_contents, 0.01)
|
||||||
self.bind(size=self.redraw_trigger, pos=self.redraw_trigger)
|
self.bind(size=self.redraw_trigger, pos=self.redraw_trigger)
|
||||||
Clock.schedule_interval(self.animate_pv, 0.1)
|
Clock.schedule_interval(self.animate_pv, 0.1)
|
||||||
|
|
||||||
@@ -81,7 +82,7 @@ class BadukPanWidget(Widget):
|
|||||||
else:
|
else:
|
||||||
self.ghost_stone = None
|
self.ghost_stone = None
|
||||||
if prev_ghost != self.ghost_stone:
|
if prev_ghost != self.ghost_stone:
|
||||||
self.draw_hover_contents()
|
self.redraw_hover_contents_trigger()
|
||||||
|
|
||||||
def update_box_selection(self, touch, second_point=True):
|
def update_box_selection(self, touch, second_point=True):
|
||||||
if not self.gridpos_x:
|
if not self.gridpos_x:
|
||||||
@@ -93,7 +94,7 @@ class BadukPanWidget(Widget):
|
|||||||
self.region_of_interest[3] = yp
|
self.region_of_interest[3] = yp
|
||||||
else:
|
else:
|
||||||
self.region_of_interest = [xp, xp, yp, yp]
|
self.region_of_interest = [xp, xp, yp, yp]
|
||||||
self.draw_hover_contents()
|
self.redraw_hover_contents_trigger()
|
||||||
|
|
||||||
def on_touch_down(self, touch):
|
def on_touch_down(self, touch):
|
||||||
self.set_animating_pv(None, None) # any click kills PV from label/move
|
self.set_animating_pv(None, None) # any click kills PV from label/move
|
||||||
@@ -186,7 +187,7 @@ class BadukPanWidget(Widget):
|
|||||||
self.set_animating_pv(nodes_here[-1].parent.candidate_moves[0]["pv"], nodes_here[-1].parent)
|
self.set_animating_pv(nodes_here[-1].parent.candidate_moves[0]["pv"], nodes_here[-1].parent)
|
||||||
|
|
||||||
self.ghost_stone = None
|
self.ghost_stone = None
|
||||||
self.draw_hover_contents() # remove ghost
|
self.redraw_hover_contents_trigger() # remove ghost
|
||||||
|
|
||||||
# drawing functions
|
# drawing functions
|
||||||
def redraw(self, *_args):
|
def redraw(self, *_args):
|
||||||
@@ -199,7 +200,7 @@ class BadukPanWidget(Widget):
|
|||||||
Rectangle(
|
Rectangle(
|
||||||
pos=(self.gridpos_x[x] - stone_size, self.gridpos_y[y] - stone_size),
|
pos=(self.gridpos_x[x] - stone_size, self.gridpos_y[y] - stone_size),
|
||||||
size=(2 * stone_size, 2 * stone_size),
|
size=(2 * stone_size, 2 * stone_size),
|
||||||
source=f"img/{player}_stone.png",
|
texture=cached_texture(f"img/{player}_stone.png"),
|
||||||
)
|
)
|
||||||
if evalcol:
|
if evalcol:
|
||||||
eval_radius = math.sqrt(evalscale) # scale area by evalscale
|
eval_radius = math.sqrt(evalscale) # scale area by evalscale
|
||||||
@@ -208,7 +209,7 @@ class BadukPanWidget(Widget):
|
|||||||
Rectangle(
|
Rectangle(
|
||||||
pos=(self.gridpos_x[x] - evalsize, self.gridpos_y[y] - evalsize),
|
pos=(self.gridpos_x[x] - evalsize, self.gridpos_y[y] - evalsize),
|
||||||
size=(2 * evalsize, 2 * evalsize),
|
size=(2 * evalsize, 2 * evalsize),
|
||||||
source=f"img/dot.png",
|
texture=cached_texture(f"img/dot.png"),
|
||||||
)
|
)
|
||||||
if innercol:
|
if innercol:
|
||||||
Color(*innercol)
|
Color(*innercol)
|
||||||
@@ -216,7 +217,7 @@ class BadukPanWidget(Widget):
|
|||||||
Rectangle(
|
Rectangle(
|
||||||
pos=(self.gridpos_x[x] - inner_size, self.gridpos_y[y] - inner_size),
|
pos=(self.gridpos_x[x] - inner_size, self.gridpos_y[y] - inner_size),
|
||||||
size=(2 * inner_size, 2 * inner_size),
|
size=(2 * inner_size, 2 * inner_size),
|
||||||
source=f"img/inner.png",
|
texture=cached_texture(f"img/inner.png"),
|
||||||
)
|
)
|
||||||
|
|
||||||
def eval_color(self, points_lost, show_dots_for_class: List[bool] = None) -> Optional[List[float]]:
|
def eval_color(self, points_lost, show_dots_for_class: List[bool] = None) -> Optional[List[float]]:
|
||||||
@@ -261,7 +262,7 @@ class BadukPanWidget(Widget):
|
|||||||
Rectangle(
|
Rectangle(
|
||||||
pos=(self.gridpos_x[0] - self.grid_size * 1.5, self.gridpos_y[0] - self.grid_size * 1.5),
|
pos=(self.gridpos_x[0] - self.grid_size * 1.5, self.gridpos_y[0] - self.grid_size * 1.5),
|
||||||
size=(self.grid_size * x_grid_spaces, self.grid_size * y_grid_spaces),
|
size=(self.grid_size * x_grid_spaces, self.grid_size * y_grid_spaces),
|
||||||
source="img/board.png",
|
texture=cached_texture("img/board.png"),
|
||||||
)
|
)
|
||||||
|
|
||||||
Color(*LINE_COLOR)
|
Color(*LINE_COLOR)
|
||||||
@@ -455,7 +456,7 @@ class BadukPanWidget(Widget):
|
|||||||
pos=center, text=text, font_size=size * 0.25, halign="center", outline_color=[0.95, 0.95, 0.95]
|
pos=center, text=text, font_size=size * 0.25, halign="center", outline_color=[0.95, 0.95, 0.95]
|
||||||
)
|
)
|
||||||
|
|
||||||
self.draw_hover_contents()
|
self.redraw_hover_contents_trigger()
|
||||||
|
|
||||||
def draw_roi_box(self, region_of_interest, width=2):
|
def draw_roi_box(self, region_of_interest, width=2):
|
||||||
xmin, xmax, ymin, ymax = region_of_interest
|
xmin, xmax, ymin, ymax = region_of_interest
|
||||||
@@ -547,9 +548,9 @@ class BadukPanWidget(Widget):
|
|||||||
Rectangle(
|
Rectangle(
|
||||||
pos=(self.gridpos_x[move.coords[0]] - evalsize, self.gridpos_y[move.coords[1]] - evalsize),
|
pos=(self.gridpos_x[move.coords[0]] - evalsize, self.gridpos_y[move.coords[1]] - evalsize),
|
||||||
size=(2 * evalsize, 2 * evalsize),
|
size=(2 * evalsize, 2 * evalsize),
|
||||||
source="img/topmove.png",
|
texture=cached_texture("img/topmove.png"),
|
||||||
)
|
)
|
||||||
if text_on and top_moves_show:
|
if text_on and top_moves_show: # TODO: faster if not sized?
|
||||||
keys = {"size": self.grid_size / 3, "smallsize": self.grid_size / 3.33}
|
keys = {"size": self.grid_size / 3, "smallsize": self.grid_size / 3.33}
|
||||||
player_sign = current_node.player_sign(current_node.next_player)
|
player_sign = current_node.player_sign(current_node.next_player)
|
||||||
if len(top_moves_show) == 1:
|
if len(top_moves_show) == 1:
|
||||||
@@ -649,7 +650,7 @@ class BadukPanWidget(Widget):
|
|||||||
|
|
||||||
def animate_pv(self, _dt):
|
def animate_pv(self, _dt):
|
||||||
if self.animating_pv:
|
if self.animating_pv:
|
||||||
self.draw_hover_contents()
|
self.redraw_hover_contents_trigger()
|
||||||
|
|
||||||
def draw_pv(self, pv, node, up_to_move):
|
def draw_pv(self, pv, node, up_to_move):
|
||||||
katrain = self.katrain
|
katrain = self.katrain
|
||||||
@@ -684,7 +685,7 @@ class BadukPanWidget(Widget):
|
|||||||
Rectangle( # not sure why the -1 here, but seems to center better
|
Rectangle( # not sure why the -1 here, but seems to center better
|
||||||
pos=(board_coords[0] - stone_size - 1, board_coords[1] - stone_size),
|
pos=(board_coords[0] - stone_size - 1, board_coords[1] - stone_size),
|
||||||
size=(2 * stone_size + 1, 2 * stone_size + 1),
|
size=(2 * stone_size + 1, 2 * stone_size + 1),
|
||||||
source=f"img/{move_player}_stone.png",
|
texture=cached_texture(f"img/{move_player}_stone.png"),
|
||||||
)
|
)
|
||||||
Color(*STONE_TEXT_COLORS[move_player])
|
Color(*STONE_TEXT_COLORS[move_player])
|
||||||
draw_text(pos=board_coords, text=str(i + 1), font_size=self.grid_size * sizefac / 1.45, font_name="Roboto")
|
draw_text(pos=board_coords, text=str(i + 1), font_size=self.grid_size * sizefac / 1.45, font_name="Roboto")
|
||||||
@@ -696,7 +697,7 @@ class BadukPanWidget(Widget):
|
|||||||
not self.animating_pv or not (self.animating_pv[0] == pv and self.animating_pv[1] == node)
|
not self.animating_pv or not (self.animating_pv[0] == pv and self.animating_pv[1] == node)
|
||||||
):
|
):
|
||||||
self.animating_pv = (pv, node, time.time(), self.last_mouse_pos)
|
self.animating_pv = (pv, node, time.time(), self.last_mouse_pos)
|
||||||
self.draw_hover_contents()
|
self.redraw_hover_contents_trigger()
|
||||||
|
|
||||||
def show_pv_from_comments(self, pv_str):
|
def show_pv_from_comments(self, pv_str):
|
||||||
self.set_animating_pv(pv_str[1:].split(" "), self.katrain.controls.active_comment_node.parent)
|
self.set_animating_pv(pv_str[1:].split(" "), self.katrain.controls.active_comment_node.parent)
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
|
import functools
|
||||||
|
|
||||||
|
from kivy.cache import Cache
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
|
from kivy.core.image import Image
|
||||||
from kivy.core.text import Label as CoreLabel
|
from kivy.core.text import Label as CoreLabel
|
||||||
from kivy.core.text.markup import MarkupLabel as CoreMarkupLabel
|
from kivy.core.text.markup import MarkupLabel as CoreMarkupLabel
|
||||||
from kivy.core.window import Window
|
from kivy.core.window import Window
|
||||||
@@ -11,6 +15,7 @@ from kivy.properties import (
|
|||||||
OptionProperty,
|
OptionProperty,
|
||||||
StringProperty,
|
StringProperty,
|
||||||
)
|
)
|
||||||
|
from kivy.resources import resource_find
|
||||||
from kivy.uix.behaviors import ButtonBehavior, FocusBehavior, ToggleButtonBehavior
|
from kivy.uix.behaviors import ButtonBehavior, FocusBehavior, ToggleButtonBehavior
|
||||||
from kivy.uix.boxlayout import BoxLayout
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
from kivy.uix.button import Button
|
from kivy.uix.button import Button
|
||||||
@@ -623,3 +628,11 @@ def draw_text(pos, text, font_name=None, markup=False, **kw):
|
|||||||
def draw_circle(pos, r, col):
|
def draw_circle(pos, r, col):
|
||||||
Color(*col)
|
Color(*col)
|
||||||
Ellipse(pos=(pos[0] - r, pos[1] - r), size=(2 * r, 2 * r))
|
Ellipse(pos=(pos[0] - r, pos[1] - r), size=(2 * r, 2 * r))
|
||||||
|
|
||||||
|
|
||||||
|
# direct cache to texture, bypassing resource_find
|
||||||
|
def cached_texture(path,_cache={}):
|
||||||
|
tex = _cache.get(path)
|
||||||
|
if not tex:
|
||||||
|
tex = _cache[path] = Image(resource_find(path)).texture
|
||||||
|
return tex
|
||||||
Reference in new issue
Block a user