From d8600bba95d81f532017913b8b78fe0132c666df Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 13 Aug 2022 21:12:49 +0200 Subject: [PATCH] Working version without cursor size change --- test_kivy_draw.py | 303 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100755 test_kivy_draw.py diff --git a/test_kivy_draw.py b/test_kivy_draw.py new file mode 100755 index 0000000..53878e9 --- /dev/null +++ b/test_kivy_draw.py @@ -0,0 +1,303 @@ +#!/usr/bin/env python3 +from random import random, randint, choice +from datetime import timedelta +from kivy.app import App +from kivy.uix.widget import Widget +from kivy.uix.button import Button, ButtonBehavior +from kivy.uix.label import Label +from kivy.graphics import Color, Ellipse, Line, Rectangle +from kivy.core.window import Window +from kivy.uix.boxlayout import BoxLayout +from kivy.clock import Clock +from kivy.uix.popup import Popup +from kivy.uix.colorpicker import ColorPicker +from kivy.uix.scrollview import ScrollView +from kivy.properties import StringProperty, BooleanProperty +from kivy.lang import Builder + + +PASS_PENALTY = 4 +DRAWING_TIME = 60 + + +Builder.load_string(''' +: + Label: + size_hint_y: None + height: self.texture_size[1] + text_size: self.width, None + text: root.text + markup: root.markup +''') + +class ScrollableLabel(ScrollView): + text = StringProperty('') + markup = BooleanProperty(False) + + + +class MyPaintWidget(Label): + _game_state = {"game_started": False, + "game_paused": False, + "game_finished": False + } + _game_wordlists = {"possible_wordlist": set(), + "found_words": set(), + "unfound_words": set() + } + pen_characteristics = {"current_color": (0,0,0,1), + "current_width": 4 + } + current_word = "" + + time = timedelta(seconds=DRAWING_TIME) + _popup = None + + def __init__(self, text="", **kwargs): + super().__init__(**kwargs) + self._keyboard = Window.request_keyboard( + self._keyboard_closed, self, 'text') + if self._keyboard.widget: + # If it exists, this widget is a VKeyboard object which you can use + # to change the keyboard layout. + pass + self._keyboard.bind(on_key_down=self._on_keyboard_down) + with open("words.txt", "r") as wordfile: + self._wordlist = (word.strip() for word in wordfile.readlines()) + self._game_wordlists["possible_wordlist"] = set(self._wordlist) + self.reset_game() + + def _keyboard_closed(self): + print('My keyboard has been closed!') + self._keyboard.unbind(on_key_down=self._on_keyboard_down) + self._keyboard = None + + def _on_keyboard_down(self, keyboard, keycode, text, modifiers): + print('The key', keycode, 'have been pressed') + print(' - text is %r' % text) + print(' - modifiers are %r' % modifiers) + if not self._game_state["game_started"]: + if keycode[0] == 32: + self.start_game() + + elif keycode[1] == 'p': + self.toggle_pause() + + elif self.is_game_playing: + if keycode[0] == 32: + self.next_word() + elif keycode[0] == 13: + self.pass_word() + elif keycode[1] == 'z' and "ctrl" in modifiers: + if self.canvas.before.children: + self.canvas.before.remove(self.canvas.before.children[-1]) + self.canvas.before.remove(self.canvas.before.children[-1]) + self.canvas.before.remove(self.canvas.before.children[-1]) + elif self._game_state["game_finished"]: + if keycode[0] == 8: + self.reset_game() + + # Keycode is composed of an integer + a string + # If we hit escape, let the input through to leave the app + if keycode[1] == 'escape': + return False + + # Return True to accept the key. Otherwise, it will be used by + # the system. + return True + + def toggle_pause(self): + self._game_state["game_paused"] = not self._game_state["game_paused"] + + def start_game(self): + self.text="" + self._game_state["game_started"] = True + self._game_state["game_paused"] = False + self.next_word(True) + + def next_word(self, passed=False): + if not passed: + self._game_wordlists["found_words"].add(self.current_word) + self.current_word = choice(list(self._game_wordlists["possible_wordlist"])) + self._game_wordlists["possible_wordlist"].discard(self.current_word) + self.clear_drawing() + + def pass_word(self): + self._game_wordlists["unfound_words"].add(self.current_word) + self.next_word(True) + if self.time - timedelta(seconds=PASS_PENALTY) > timedelta(0): + self.time -= timedelta(seconds=PASS_PENALTY) + else: + self.time = timedelta(0) + + @property + def is_game_playing(self): + return (self._game_state["game_started"] + and not self._game_state["game_paused"] + and not self._game_state["game_finished"]) + + @property + def current_color(self): + return self.pen_characteristics["current_color"] + + def on_touch_down(self, touch): + if self.is_game_playing: + with self.canvas.before: + if self.collide_point(touch.x, touch.y): + Color(*self.pen_characteristics["current_color"], mode='rgba') + diameter = self.pen_characteristics["current_width"] + Ellipse(pos=(touch.x - diameter / 2, touch.y - diameter / 2), + size=(2*diameter, 2*diameter)) + touch.ud['line'] = Line(points=(touch.x, touch.y), width=diameter) + + + + def on_touch_move(self, touch): + if self.is_game_playing: + if 'line' in touch.ud: + if self.collide_point(touch.x, touch.y): + touch.ud['line'].points += [touch.x, touch.y] + elif self.collide_point(touch.ud['line'].points[-2], touch.y): + touch.ud['line'].points += [touch.ud['line'].points[-2], touch.y] + elif self.collide_point(touch.x, touch.ud['line'].points[-1]): + touch.ud['line'].points += [touch.x, touch.ud['line'].points[-1]] + + def recap(self): + found_words = self._game_wordlists['found_words'] + unfound_words =self._game_wordlists['unfound_words'] + lines = ["[b]Tour terminé ![/b]\n"+ + f"Trouvés: [color=#5BB834]{len(found_words)}[/color]", + "-"+ "\n-".join(found_words) if found_words else "", + f"Passés: [color=#FF2A40]{len(unfound_words)}[/color]", + "- "+ "\n- ".join(unfound_words) if unfound_words else ""] + self.clear_drawing() + self._popup = Popup(title='Fini !', + content=ScrollableLabel(text="[size=24]"+"\n".join(lines)+"[/size]", + markup=True), + size_hint=(0.6,0.6), + auto_dismiss=False) + self._popup.open() + + def game_finished(self): + self._game_state["game_finished"] = True + self.recap() + + def reset_game(self): + if self._popup: + self._popup.dismiss() + self.color = (0,0,0,1) + self.text = "Appuyer sur 'espace' pour commencer à jouer" + self.time = timedelta(seconds=DRAWING_TIME) + self._game_state["game_finished"] = False + self._game_state["game_started"] = False + + def clear_drawing(self): + self.canvas.before.clear() + +class SizeButton(Widget, ButtonBehavior): + def __init__(self, size=1, **kwargs): + super().__init__(**kwargs) + self.dot_size = size + with self.canvas: + Color(0,0,0, mode="rgb") + self.bg = Rectangle(pos=self.pos, size=self.size) + Color(1,1,1, mode="rgb") + self.dot = Ellipse(pos=(self.center_x-size/2, self.center_y-size/2), + size = (size*2, size*2)) + def redraw(self, args): + self.dot.pos = (self.center_x-size/2, self.center_y-size/2) + self.bg.pos = self.pos + self.bg.size = self.size + self.bind(size=redraw, pos=redraw) + + +class MyPaintApp(App): + state = False + init = True + + def build(self): + Window.clearcolor = (1, 1, 1, 1) + #self.init_keyboard() + parent = BoxLayout(orientation='vertical') + + self.painter = MyPaintWidget(size_hint=(0.9, 1)) + Clock.schedule_interval(self.update_time, 1.0/10.0) + clearbtn = Button(text='Clear') + clearbtn.bind(on_release=self.clear_canvas) + togglebtn = Button(text='Inverser la couleur du fond') + togglebtn.bind(on_release=self.toggle_background) + + self.right_row = BoxLayout(orientation="vertical", size_hint=(0.1,1)) + color_picker_button = Button(text="Couleur") + color_picker_button.background_color = self.painter.pen_characteristics["current_color"] + color_picker_button.background_normal = '' + color_picker_button.bind(on_release=self.open_color_picker) + self.right_row.add_widget(color_picker_button) + for i in range(1,6): + size_button = SizeButton(2*i) + self.right_row.add_widget(size_button) + + middle_row = BoxLayout(orientation="horizontal", size_hint=(1, 0.8)) + middle_row.add_widget(self.painter) + middle_row.add_widget(self.right_row) + + bottom_row = BoxLayout(orientation='horizontal', spacing=5, size_hint=(1, .1)) + bottom_row.add_widget(togglebtn) + bottom_row.add_widget(clearbtn) + + top_row = BoxLayout(orientation='horizontal', spacing=5, size_hint=(1, .1)) + self.word_label = Label(text="Mot:", color=[0,0,0,1], halign="left") + self.time_label = Label(text=f"{self.painter.time}", color=[0,0,0,1]) + top_row.add_widget(self.word_label) + top_row.add_widget(self.time_label) + + parent.add_widget(top_row) + parent.add_widget(middle_row) + parent.add_widget(bottom_row) + return parent + + def open_color_picker(self, _): + clr_picker = ColorPicker() + clr_picker.color = self.painter.pen_characteristics["current_color"] + def on_color_change(instance, value): + self.painter.pen_characteristics["current_color"] = value + self.right_row.children[-1].background_color = self.painter.current_color + clr_picker.bind(color=on_color_change) + popup = Popup(title="Couleur du pinceau", + content=clr_picker, + size_hint=(0.5,0.5)) + popup.open() + + def update_time(self, _): + self.word_label.text_size = (self.word_label.size[0], None) + if self.painter.is_game_playing: + if self.painter.time > timedelta(0): + self.painter.time -= timedelta(milliseconds=100) + self.word_label.text = f"Mot: {self.painter.current_word}" + else: + self.painter.game_finished() + + self.time_label.text = f"{self.painter.time}" + + def toggle_background(self, obj): + + if self.state: + Window.clearcolor = (1, 1, 1, 1) + self.painter.pen_characteristics["current_color"] = (0,0,0,1) + self.word_label.color = (0,0,0,1) + self.time_label.color = (0,0,0,1) + self.state = False + else: + Window.clearcolor = (0,0,0,1) + self.painter.pen_characteristics["current_color"] = (1,1,1,1) + self.word_label.color = (1,1,1,1) + self.time_label.color = (1,1,1,1) + self.state = True + self.clear_canvas(obj) + + def clear_canvas(self, _): + self.painter.clear_drawing() + + +if __name__ == '__main__': + MyPaintApp().run()