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.
This commit is contained in:
Peter Hutterer 2018-01-24 15:12:03 +10:00
parent 3d516530c6
commit 80d214c78f
4 changed files with 118 additions and 98 deletions

View File

@ -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()

View File

@ -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)

109
tuhi/drawing.py Normal file
View File

@ -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)

View File

@ -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