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:
parent
3d516530c6
commit
80d214c78f
71
tuhi/base.py
71
tuhi/base.py
|
@ -12,14 +12,13 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
from gi.repository import GObject
|
from gi.repository import GObject
|
||||||
|
|
||||||
from tuhi.dbusserver import TuhiDBusServer
|
from tuhi.dbusserver import TuhiDBusServer
|
||||||
from tuhi.ble import BlueZDeviceManager
|
from tuhi.ble import BlueZDeviceManager
|
||||||
from tuhi.wacom import WacomDevice, Stroke
|
from tuhi.wacom import WacomDevice
|
||||||
from tuhi.config import TuhiConfig
|
from tuhi.config import TuhiConfig
|
||||||
|
|
||||||
logging.basicConfig(format='%(levelname)s: %(name)s: %(message)s',
|
logging.basicConfig(format='%(levelname)s: %(name)s: %(message)s',
|
||||||
|
@ -29,47 +28,6 @@ logger = logging.getLogger('tuhi')
|
||||||
WACOM_COMPANY_ID = 0x4755
|
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):
|
class TuhiDevice(GObject.Object):
|
||||||
"""
|
"""
|
||||||
Glue object to combine the backend bluez DBus object (that talks to the
|
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):
|
def _on_drawing_received(self, device, drawing):
|
||||||
logger.debug('Drawing received')
|
logger.debug('Drawing received')
|
||||||
d = TuhiDrawing(device.name, (0, 0), drawing.timestamp)
|
self._tuhi_dbus_device.add_drawing(drawing)
|
||||||
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)
|
|
||||||
|
|
||||||
def _on_fetching_finished(self, device, exception, bluez_device):
|
def _on_fetching_finished(self, device, exception, bluez_device):
|
||||||
bluez_device.disconnect_device()
|
bluez_device.disconnect_device()
|
||||||
|
|
|
@ -294,7 +294,7 @@ class TuhiDBusDevice(_TuhiDBus):
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return ''
|
return ''
|
||||||
else:
|
else:
|
||||||
return drawing.json()
|
return drawing.to_json()
|
||||||
|
|
||||||
def add_drawing(self, drawing):
|
def add_drawing(self, drawing):
|
||||||
self.drawings.append(drawing)
|
self.drawings.append(drawing)
|
||||||
|
|
|
@ -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)
|
|
@ -19,6 +19,7 @@ import time
|
||||||
import uuid
|
import uuid
|
||||||
import errno
|
import errno
|
||||||
from gi.repository import GObject
|
from gi.repository import GObject
|
||||||
|
from .drawing import Drawing
|
||||||
|
|
||||||
logger = logging.getLogger('tuhi.wacom')
|
logger = logging.getLogger('tuhi.wacom')
|
||||||
|
|
||||||
|
@ -65,27 +66,6 @@ class NordicData(list):
|
||||||
self.length = bs[1]
|
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):
|
class WacomException(Exception):
|
||||||
errno = errno.ENOSYS
|
errno = errno.ENOSYS
|
||||||
|
|
||||||
|
@ -491,15 +471,14 @@ class WacomDevice(GObject.Object):
|
||||||
bitmask, opcode, raw_args, args, offset = self.next_pen_data(data, offset)
|
bitmask, opcode, raw_args, args, offset = self.next_pen_data(data, offset)
|
||||||
if opcode == 0x3800:
|
if opcode == 0x3800:
|
||||||
logger.info(f'beginning of sequence')
|
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)
|
drawings.append(drawing)
|
||||||
continue
|
continue
|
||||||
elif opcode == 0xeeff:
|
elif opcode == 0xeeff:
|
||||||
# some sort of headers
|
# some sort of headers
|
||||||
time_offset = int.from_bytes(raw_args[4:], byteorder='little')
|
time_offset = int.from_bytes(raw_args[4:], byteorder='little')
|
||||||
logger.info(f'time offset since boot: {time_offset * 0.005} secs')
|
logger.info(f'time offset since boot: {time_offset * 0.005} secs')
|
||||||
stroke = Stroke()
|
stroke = drawing.new_stroke()
|
||||||
drawing.append(stroke)
|
|
||||||
continue
|
continue
|
||||||
if bytes(args) == b'\xff\xff\xff\xff\xff\xff\xff\xff':
|
if bytes(args) == b'\xff\xff\xff\xff\xff\xff\xff\xff':
|
||||||
logger.info(f'end of sequence')
|
logger.info(f'end of sequence')
|
||||||
|
@ -510,8 +489,7 @@ class WacomDevice(GObject.Object):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if stroke is None:
|
if stroke is None:
|
||||||
stroke = Stroke()
|
stroke = drawing.new_stroke()
|
||||||
drawing.append(stroke)
|
|
||||||
|
|
||||||
x, dx, xrel = self.get_coordinate(bitmask, 0, args, x, dx)
|
x, dx, xrel = self.get_coordinate(bitmask, 0, args, x, dx)
|
||||||
y, dy, yrel = self.get_coordinate(bitmask, 1, args, y, dy)
|
y, dy, yrel = self.get_coordinate(bitmask, 1, args, y, dy)
|
||||||
|
@ -526,9 +504,9 @@ class WacomDevice(GObject.Object):
|
||||||
if bitmask & 0b00111100 == 0:
|
if bitmask & 0b00111100 == 0:
|
||||||
continue
|
continue
|
||||||
if xrel or yrel or prel:
|
if xrel or yrel or prel:
|
||||||
stroke.add_rel(dx, dy, dp)
|
stroke.new_rel((dx, dy), dp)
|
||||||
else:
|
else:
|
||||||
stroke.add_pos(x, y, p)
|
stroke.new_abs((x, y), p)
|
||||||
|
|
||||||
return drawings
|
return drawings
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue