diff --git a/kivy_garden/__init__.py b/kivy_garden/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kivy_garden/matplotlib/backend_kivy.py b/kivy_garden/matplotlib/backend_kivy.py index d84496d..71f1ff5 100644 --- a/kivy_garden/matplotlib/backend_kivy.py +++ b/kivy_garden/matplotlib/backend_kivy.py @@ -232,7 +232,6 @@ def close(event): import six import os import matplotlib -import matplotlib.transforms as transforms from matplotlib._pylab_helpers import Gcf from matplotlib.backend_bases import ( RendererBase, @@ -243,12 +242,15 @@ def close(event): TimerBase, ) from matplotlib.figure import Figure -from matplotlib.transforms import Bbox, Affine2D -from matplotlib.backend_bases import ShowBase, Event +from matplotlib.transforms import Affine2D +from matplotlib.backend_bases import (ShowBase, + Event, + ResizeEvent, + MouseEvent, + KeyEvent) from matplotlib.backends.backend_agg import FigureCanvasAgg from matplotlib.mathtext import MathTextParser from matplotlib import rcParams -from hashlib import md5 from matplotlib import _path try: @@ -260,7 +262,6 @@ def close(event): from kivy.graphics.texture import Texture from kivy.graphics import Rectangle from kivy.uix.widget import Widget -from kivy.uix.label import Label from kivy.uix.floatlayout import FloatLayout from kivy.uix.behaviors import FocusBehavior from kivy.uix.actionbar import ( @@ -286,12 +287,8 @@ def close(event): from kivy.resources import resource_find from kivy.uix.stencilview import StencilView from kivy.core.window import Window -from kivy.uix.button import Button -from kivy.uix.boxlayout import BoxLayout -from kivy.uix.relativelayout import RelativeLayout from kivy.uix.popup import Popup from kivy.properties import ObjectProperty -from kivy.uix.textinput import TextInput from kivy.lang import Builder from kivy.clock import Clock from distutils.version import LooseVersion @@ -300,12 +297,9 @@ def close(event): _mpl_ge_2_0 = LooseVersion(matplotlib.__version__) >= LooseVersion("2.0.0") import numpy as np -import io import textwrap import uuid import numbers -from functools import partial -from math import cos, sin, pi kivy.require("1.9.1") @@ -340,7 +334,7 @@ def build(self): def draw_if_interactive(): - """Handle whether or not the backend is in interactive mode or not.""" + """Handle whether the backend is in interactive mode or not.""" if matplotlib.is_interactive(): figManager = Gcf.get_active() if figManager: @@ -989,13 +983,14 @@ def __init__(self, canvas, **kwargs): ) def _init_toolbar(self): - """A Toolbar is created with an ActionBar widget in which buttons are - added with a specific behavior given by a callback. The buttons - properties are given by matplotlib. + """A Toolbar is created with an ActionBar widget in which buttons + are added with a specific behavior given by a callback. + The buttons properties are given by matplotlib. """ basedir = os.path.join(rcParams["datapath"], "images") actionview = ActionView() - actionprevious = ActionPrevious(title="Navigation", with_previous=False) + actionprevious = ActionPrevious(title="Navigation", + with_previous=False) actionoverflow = ActionOverflow() actionview.add_widget(actionprevious) actionview.add_widget(actionoverflow) @@ -1217,31 +1212,21 @@ def on_touch_down(self, touch): newcoord = self.to_widget(touch.x, touch.y, relative=True) x = newcoord[0] y = newcoord[1] - if super(FigureCanvasKivy, self).on_touch_down(touch): return True if self.collide_point(*touch.pos): - self.motion_notify_event(x, y, guiEvent=None) - + self.motion_notify_event(x, y) touch.grab(self) - if "button" in touch.profile and touch.button in ( - "scrollup", - "scrolldown", - ): - self.scroll_event(x, y, 5, guiEvent=None) + if 'button' in touch.profile and touch.button in ("scrollup", + "scrolldown"): + self.scroll_event(x, y, 5) else: - self.button_press_event( - x, - y, - self.get_mouse_button(touch), - dblclick=False, - guiEvent=None, - ) + self.button_press_event(x, y, self.get_mouse_button(touch)) if self.entered_figure: - self.enter_notify_event(guiEvent=None, xy=None) + self.enter_notify_event() else: if not self.entered_figure: - self.leave_notify_event(guiEvent=None) + self.leave_notify_event() return False def on_touch_move(self, touch): @@ -1253,12 +1238,12 @@ def on_touch_move(self, touch): y = newcoord[1] inside = self.collide_point(touch.x, touch.y) if inside: - self.motion_notify_event(x, y, guiEvent=None) + self.motion_notify_event(x, y) if not inside and not self.entered_figure: - self.leave_notify_event(guiEvent=None) + self.leave_notify_event() self.entered_figure = True elif inside and self.entered_figure: - self.enter_notify_event(guiEvent=None, xy=(x, y)) + self.enter_notify_event() self.entered_figure = False return False @@ -1284,15 +1269,11 @@ def on_touch_up(self, touch): x = newcoord[0] y = newcoord[1] if touch.grab_current is self: - if "button" in touch.profile and touch.button in ( - "scrollup", - "scrolldown", - ): - self.scroll_event(x, y, 5, guiEvent=None) + if 'button' in touch.profile and touch.button in ("scrollup", + "scrolldown"): + self.scroll_event(x, y, 5) else: - self.button_release_event( - x, y, self.get_mouse_button(touch), guiEvent=None - ) + self.button_release_event(x, y, self.get_mouse_button(touch)) touch.ungrab(self) else: return super(FigureCanvasKivy, self).on_touch_up(touch) @@ -1300,15 +1281,15 @@ def on_touch_up(self, touch): def keyboard_on_key_down(self, window, keycode, text, modifiers): """Kivy event to trigger matplotlib `key_press_event`.""" - self.key_press_event(keycode[1], guiEvent=None) + self.key_press_event(key=keycode[1]) return super(FigureCanvasKivy, self).keyboard_on_key_down( - window, keycode, text, modifiers - ) + window, keycode, text, modifiers) def keyboard_on_key_up(self, window, keycode): """Kivy event to trigger matplotlib `key_release_event`.""" - self.key_release_event(keycode[1], guiEvent=None) - return super(FigureCanvasKivy, self).keyboard_on_key_up(window, keycode) + self.key_release_event(key=keycode[1]) + return super(FigureCanvasKivy, self).keyboard_on_key_up( + window, keycode) def _on_mouse_pos(self, *args): """Kivy Event to trigger the following matplotlib events: @@ -1321,22 +1302,85 @@ def _on_mouse_pos(self, *args): y = newcoord[1] inside = self.collide_point(*pos) if inside: - self.motion_notify_event(x, y, guiEvent=None) + self.motion_notify_event(x, y) if not inside and not self.entered_figure: - self.leave_notify_event(guiEvent=None) + self.leave_notify_event() self.entered_figure = True elif inside and self.entered_figure: - self.enter_notify_event(guiEvent=None, xy=(pos[0], pos[1])) + self.enter_notify_event() self.entered_figure = False - def enter_notify_event(self, guiEvent=None, xy=None): - event = Event("figure_enter_event", self, guiEvent) + def enter_notify_event(self, gui_event=None): + event = Event("figure_enter_event", self, gui_event) self.callbacks.process("figure_enter_event", event) - def leave_notify_event(self, guiEvent=None): - event = Event("figure_leave_event", self, guiEvent) + def leave_notify_event(self, gui_event=None): + event = Event("figure_leave_event", self, gui_event) self.callbacks.process("figure_leave_event", event) + def resize_event(self): + event = ResizeEvent('resize_event', self) + self.callbacks.process('resize_event', event) + + def motion_notify_event(self, x, y, gui_event=None): + event = MouseEvent( + 'motion_notify_event', + canvas=self, + x=x, + y=y, + guiEvent=gui_event) + self.callbacks.process('motion_notify_event', event) + + def button_press_event(self, x, y, button, + dblclick=False, gui_event=None): + event = MouseEvent( + 'button_press_event', + canvas=self, + x=x, + y=y, + button=button, + dblclick=dblclick, + guiEvent=gui_event) + self.callbacks.process('button_press_event', event) + + def button_release_event(self, x, y, button, + dblclick=False, gui_event=None): + event = MouseEvent( + 'button_release_event', + canvas=self, + x=x, + y=y, + button=button, + dblclick=dblclick, + guiEvent=gui_event) + self.callbacks.process('button_release_event', event) + + def scroll_event(self, x, y, step, gui_event=None): + event = MouseEvent( + 'scroll_event', + canvas=self, + x=x, + y=y, + step=step, + guiEvent=gui_event) + self.callbacks.process('scroll_event', event) + + def key_press_event(self, key, gui_event=None): + event = KeyEvent( + 'key_press_event', + canvas=self, + key=key, + guiEvent=gui_event) + self.callbacks.process('key_press_event', event) + + def key_release_event(self, key, gui_event=None): + event = KeyEvent( + 'key_release_event', + canvas=self, + key=key, + guiEvent=gui_event) + self.callbacks.process('key_release_event', event) + def _on_pos_changed(self, *args): self.draw() @@ -1346,6 +1390,8 @@ def _on_size_changed(self, *args): size. """ w, h = self.size + if w <= 0 or h <= 0: + return dpival = self.figure.dpi winch = float(w) / dpival hinch = float(h) / dpival diff --git a/kivy_garden/matplotlib/backend_kivyagg.py b/kivy_garden/matplotlib/backend_kivyagg.py index cce9dc2..8253908 100644 --- a/kivy_garden/matplotlib/backend_kivyagg.py +++ b/kivy_garden/matplotlib/backend_kivyagg.py @@ -73,18 +73,7 @@ def my_callback(event): __all__ = "FigureCanvasKivyAgg" -import six - -import matplotlib -from matplotlib._pylab_helpers import Gcf -from matplotlib.backend_bases import ( - RendererBase, - GraphicsContextBase, - FigureManagerBase, - FigureCanvasBase, -) from matplotlib.figure import Figure -from matplotlib.transforms import Bbox from matplotlib.backends.backend_agg import FigureCanvasAgg from matplotlib.backend_bases import register_backend, ShowBase @@ -96,7 +85,6 @@ def my_callback(event): from kivy.app import App from kivy.graphics.texture import Texture from kivy.graphics import Rectangle, Color -from kivy.uix.widget import Widget from kivy.properties import ObjectProperty from kivy.base import EventLoop from kivy.uix.floatlayout import FloatLayout diff --git a/kivy_garden/matplotlib/tests/__init__.py b/kivy_garden/matplotlib/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kivy_garden/matplotlib/tests/test_backend_kivy.py b/kivy_garden/matplotlib/tests/test_backend_kivy.py index f18a00a..02d1b9f 100644 --- a/kivy_garden/matplotlib/tests/test_backend_kivy.py +++ b/kivy_garden/matplotlib/tests/test_backend_kivy.py @@ -2,6 +2,7 @@ def test_matplotlib_use_backend(): import matplotlib import matplotlib.pyplot as plt + plt.close('all') matplotlib.use("module://kivy_garden.matplotlib.backend_kivy") plt.plot([1, 2, 3, 4]) diff --git a/kivy_garden/matplotlib/tests/test_backend_kivyagg.py b/kivy_garden/matplotlib/tests/test_backend_kivyagg.py index 619b35b..6a501a3 100644 --- a/kivy_garden/matplotlib/tests/test_backend_kivyagg.py +++ b/kivy_garden/matplotlib/tests/test_backend_kivyagg.py @@ -2,6 +2,7 @@ def test_matplotlib_use_backend(): import matplotlib import matplotlib.pyplot as plt + plt.close('all') matplotlib.use("module://kivy_garden.matplotlib.backend_kivyagg") plt.plot([1, 2, 3, 4]) diff --git a/kivy_garden/matplotlib/tests/test_events.py b/kivy_garden/matplotlib/tests/test_events.py new file mode 100644 index 0000000..f41ea76 --- /dev/null +++ b/kivy_garden/matplotlib/tests/test_events.py @@ -0,0 +1,86 @@ +from kivy.tests import GraphicUnitTest, UnitTestTouch + + +class TestEvents(GraphicUnitTest): + + @classmethod + def setUpClass(cls): + from matplotlib.figure import Figure + from kivy_garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg + + fig = Figure() + ax = fig.add_subplot(111) + ax.plot([1, 2, 3, 4]) + cls.figure_canvas = FigureCanvasKivyAgg(figure=fig) + + def test_resize_screen(self): + self.render(self.figure_canvas) + + def test_touch_down(self): + self.render(self.figure_canvas) + UnitTestTouch(x=0.5, y=0.5).touch_down() + + def test_touch_down_scrolldown(self): + self.render(self.figure_canvas) + touch = UnitTestTouch(x=0, y=0) + touch.profile = 'button' + touch.button = 'scrolldown' + touch.touch_down() + + def test_touch_down_scrolluo(self): + self.render(self.figure_canvas) + touch = UnitTestTouch(x=0, y=0) + touch.profile = 'button' + touch.button = 'scrollup' + touch.touch_down() + + def test_touch_up(self): + self.render(self.figure_canvas) + touch = UnitTestTouch(x=0.5, y=0.5) + touch.touch_down() + touch.touch_up() + + def test_touch_up_scrolldown(self): + self.render(self.figure_canvas) + touch = UnitTestTouch(x=0, y=0) + touch.profile = 'button' + touch.button = 'scrolldown' + touch.touch_down() + touch.touch_up() + + def test_touch_up_scrolluo(self): + self.render(self.figure_canvas) + touch = UnitTestTouch(x=0, y=0) + touch.profile = 'button' + touch.button = 'scrollup' + touch.touch_down() + touch.touch_up() + + def test_touch_move(self): + self.render(self.figure_canvas) + UnitTestTouch(x=0.5, y=0.5).touch_move(x=0.5, y=0.5) + + def test_on_key_down(self): + from kivy.base import EventLoop + from kivy.core.window import Keyboard + + EventLoop.ensure_window() + window = EventLoop.window + key = 'tab' + key_code = (key, Keyboard.keycodes[key]) + print(Keyboard.keycodes) + + self.figure_canvas.keyboard_on_key_down( + window, key_code, text='tab', modifiers=[]) + + def test_on_key_up(self): + from kivy.base import EventLoop + from kivy.core.window import Keyboard + + EventLoop.ensure_window() + window = EventLoop.window + key = 'tab' + key_code = (key, Keyboard.keycodes[key]) + print(Keyboard.keycodes) + self.figure_canvas.keyboard_on_key_up( + window, key_code) diff --git a/setup.py b/setup.py index 0f2c9d7..54db180 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ keywords='Kivy kivy-garden', packages=find_namespace_packages(include=['kivy_garden.*']), - install_requires=['matplotlib==3.7.2', 'kivy>=2.1.0'], + install_requires=['matplotlib>=3.7.2', 'kivy>=2.1.0'], extras_require={ 'dev': ['pytest>=3.6', 'pytest-cov', 'pytest-asyncio', 'sphinx_rtd_theme'],