From 80d214c78f05803902c818ef5a549bcbe96115ff Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 24 Jan 2018 15:12:03 +1000 Subject: [PATCH] Split the Drawing class out into a separate module No point having multiple implementations of what a drawing is. Let's have it in one module. --- tuhi/base.py | 71 +---------------------------- tuhi/dbusserver.py | 2 +- tuhi/drawing.py | 109 +++++++++++++++++++++++++++++++++++++++++++++ tuhi/wacom.py | 34 +++----------- 4 files changed, 118 insertions(+), 98 deletions(-) create mode 100644 tuhi/drawing.py diff --git a/tuhi/base.py b/tuhi/base.py index 2cec947..b5bb836 100644 --- a/tuhi/base.py +++ b/tuhi/base.py @@ -12,14 +12,13 @@ # import argparse -import json import logging import sys from gi.repository import GObject from tuhi.dbusserver import TuhiDBusServer from tuhi.ble import BlueZDeviceManager -from tuhi.wacom import WacomDevice, Stroke +from tuhi.wacom import WacomDevice from tuhi.config import TuhiConfig logging.basicConfig(format='%(levelname)s: %(name)s: %(message)s', @@ -29,47 +28,6 @@ logger = logging.getLogger('tuhi') WACOM_COMPANY_ID = 0x4755 -class TuhiDrawing(object): - class Stroke(object): - def __init__(self): - self.points = [] - - def to_dict(self): - d = {} - d['points'] = [p.to_dict() for p in self.points] - return d - - class Point(object): - def __init__(self): - pass - - def to_dict(self): - d = {} - for key in ['toffset', 'position', 'pressure']: - val = getattr(self, key, None) - if val is not None: - d[key] = val - return d - - def __init__(self, name, dimensions, timestamp): - self.name = name - self.dimensions = dimensions - self.timestamp = timestamp - self.strokes = [] - - def json(self): - JSON_FILE_FORMAT_VERSION = 1 - - json_data = { - 'version': JSON_FILE_FORMAT_VERSION, - 'devicename': self.name, - 'dimensions': list(self.dimensions), - 'timestamp': self.timestamp, - 'strokes': [s.to_dict() for s in self.strokes] - } - return json.dumps(json_data) - - class TuhiDevice(GObject.Object): """ Glue object to combine the backend bluez DBus object (that talks to the @@ -156,32 +114,7 @@ class TuhiDevice(GObject.Object): def _on_drawing_received(self, device, drawing): logger.debug('Drawing received') - d = TuhiDrawing(device.name, (0, 0), drawing.timestamp) - for s in drawing: - stroke = TuhiDrawing.Stroke() - lastx, lasty, lastp = None, None, None - for type, x, y, p in s.points: - if x is not None: - if type == Stroke.RELATIVE: - x += lastx - lastx = x - if y is not None: - if type == Stroke.RELATIVE: - y += lasty - lasty = y - if p is not None: - if type == Stroke.RELATIVE: - p += lastp - lastp = p - - lastx, lasty, lastp = x, y, p - point = TuhiDrawing.Point() - point.position = (lastx, lasty) - point.pressure = lastp - stroke.points.append(point) - d.strokes.append(stroke) - - self._tuhi_dbus_device.add_drawing(d) + self._tuhi_dbus_device.add_drawing(drawing) def _on_fetching_finished(self, device, exception, bluez_device): bluez_device.disconnect_device() diff --git a/tuhi/dbusserver.py b/tuhi/dbusserver.py index fe767ce..d3d665d 100755 --- a/tuhi/dbusserver.py +++ b/tuhi/dbusserver.py @@ -294,7 +294,7 @@ class TuhiDBusDevice(_TuhiDBus): except IndexError: return '' else: - return drawing.json() + return drawing.to_json() def add_drawing(self, drawing): self.drawings.append(drawing) diff --git a/tuhi/drawing.py b/tuhi/drawing.py new file mode 100644 index 0000000..f4fcd84 --- /dev/null +++ b/tuhi/drawing.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +from gi.repository import GObject +import json + + +class Point(GObject.Object): + def __init__(self, stroke): + GObject.Object.__init__(self) + self.stroke = stroke + self.position = None + self.pressure = None + + def to_dict(self): + d = {} + for key in ['position', 'pressure']: + val = getattr(self, key, None) + if val is not None: + d[key] = val + return d + + +class Stroke(GObject.Object): + def __init__(self, drawing): + GObject.Object.__init__(self) + self.drawing = drawing + self.points = [] + self._position = (0, 0) + self._pressure = 0 + + def new_rel(self, position=None, pressure=None): + p = Point(self) + if position is not None: + x, y = self._position + self._position = (x + position[0], y + position[1]) + p.position = self._position + if pressure is not None: + self._pressure += pressure + p.pressure = self._pressure + + self.points.append(p) + + def new_abs(self, position=None, pressure=None): + p = Point(self) + if position is not None: + self._position = position + p.position = position + if pressure is not None: + self._pressure = pressure + p.pressure = pressure + + self.points.append(p) + + def to_dict(self): + d = {} + d['points'] = [p.to_dict() for p in self.points] + return d + + +class Drawing(GObject.Object): + """ + Abstracts a drawing. The drawing is composed Strokes, each of which has + Points. + """ + def __init__(self, name, dimensions, timestamp): + GObject.Object.__init__(self) + self.name = name + self.dimensions = dimensions + self.timestamp = timestamp # unix seconds + self.strokes = [] + self._current_stroke = -1 + + # The way we're building drawings, we don't need to change the current + # stroke at runtime, so this is read-ony + @property + def current_stroke(self): + return self.strokes[self._current_stroke] + + def new_stroke(self): + """ + Create a new stroke and make it the current stroke + """ + l = Stroke(self) + self.strokes.append(l) + self._current_stroke += 1 + return l + + def to_json(self): + JSON_FILE_FORMAT_VERSION = 1 + + json_data = { + 'version': JSON_FILE_FORMAT_VERSION, + 'devicename': self.name, + 'dimensions': list(self.dimensions), + 'timestamp': self.timestamp, + 'strokes': [s.to_dict() for s in self.strokes] + } + return json.dumps(json_data) diff --git a/tuhi/wacom.py b/tuhi/wacom.py index 1443980..d52d530 100644 --- a/tuhi/wacom.py +++ b/tuhi/wacom.py @@ -19,6 +19,7 @@ import time import uuid import errno from gi.repository import GObject +from .drawing import Drawing logger = logging.getLogger('tuhi.wacom') @@ -65,27 +66,6 @@ class NordicData(list): self.length = bs[1] -class Stroke(object): - RELATIVE = 1 - ABSOLUTE = 2 - - def __init__(self): - self.points = [] - - def add_pos(self, x, y, p=None): - self.points.append((Stroke.ABSOLUTE, x, y, p)) - - def add_rel(self, x, y, p=None): - self.points.append((Stroke.RELATIVE, x, y, p)) - - -class Drawing(list): - def __init__(self, size, timestamp): - super().__init__() - self.timestamp = timestamp - self.size = size - - class WacomException(Exception): errno = errno.ENOSYS @@ -491,15 +471,14 @@ class WacomDevice(GObject.Object): bitmask, opcode, raw_args, args, offset = self.next_pen_data(data, offset) if opcode == 0x3800: logger.info(f'beginning of sequence') - drawing = Drawing((self.width, self.height), timestamp) + drawing = Drawing(self.name, (self.width, self.height), timestamp) drawings.append(drawing) continue elif opcode == 0xeeff: # some sort of headers time_offset = int.from_bytes(raw_args[4:], byteorder='little') logger.info(f'time offset since boot: {time_offset * 0.005} secs') - stroke = Stroke() - drawing.append(stroke) + stroke = drawing.new_stroke() continue if bytes(args) == b'\xff\xff\xff\xff\xff\xff\xff\xff': logger.info(f'end of sequence') @@ -510,8 +489,7 @@ class WacomDevice(GObject.Object): continue if stroke is None: - stroke = Stroke() - drawing.append(stroke) + stroke = drawing.new_stroke() x, dx, xrel = self.get_coordinate(bitmask, 0, args, x, dx) y, dy, yrel = self.get_coordinate(bitmask, 1, args, y, dy) @@ -526,9 +504,9 @@ class WacomDevice(GObject.Object): if bitmask & 0b00111100 == 0: continue if xrel or yrel or prel: - stroke.add_rel(dx, dy, dp) + stroke.new_rel((dx, dy), dp) else: - stroke.add_pos(x, y, p) + stroke.new_abs((x, y), p) return drawings