Fixed hwpad. Handwriting recognition should now work again.
[jben2_gui.git] / python / jben / interface / gtk / widget / hwpad.py
blob1aae034033d7670daa61f754f4c06e5eeede9464
2 #!/usr/bin/env python
3 # -*- coding: utf-8 -*-
5 # Project: J-Ben, Python front-end
6 # File: widget_hwpad.py
7 # Author: Paul Goins
8 # Created on: 25 Nov 2008
10 # I think I originally wrote this to be a generic writing pad object,
11 # but currently it is linked specifically into kanji handwriting
12 # recognition.
14 import gtk, cairo
15 import os
16 from subprocess import Popen, PIPE
18 from .infomessage import show_message
19 from jben import configure
22 class Point(object):
23 def __init__(self, init_x, init_y):
24 self.x = init_x
25 self.y = init_y
26 def __str__(self):
27 """kpengine expects a very simple format."""
28 return "%s %s" % (self.x, self.y)
30 class WidgetHWPad(gtk.DrawingArea):
31 def __init__(self):
32 gtk.DrawingArea.__init__(self)
34 self.set_events(
35 gtk.gdk.EXPOSURE_MASK |
36 gtk.gdk.BUTTON1_MOTION_MASK |
37 gtk.gdk.BUTTON_PRESS_MASK |
38 gtk.gdk.BUTTON_RELEASE_MASK |
39 gtk.gdk.POINTER_MOTION_HINT_MASK
41 self.connect("expose-event", self.on_expose)
42 self.connect("motion-notify-event", self.on_motion)
43 self.connect("button-press-event", self.on_press)
44 self.connect("button-release-event", self.on_release)
46 self.current_line = None
47 self.lines = []
48 self.results = []
50 def on_expose(self, widget, event):
51 cairo_context = self.window.cairo_create()
53 # Clip update region
54 cairo_context.rectangle(
55 event.area.x, event.area.y, event.area.width, event.area.height)
56 cairo_context.clip()
58 # Set drawing style
59 cairo_context.set_line_width(5)
60 cairo_context.set_line_join(cairo.LINE_JOIN_ROUND)
61 cairo_context.set_line_cap(cairo.LINE_CAP_ROUND)
63 # Fill background to white
64 cairo_context.set_source_rgb(1, 1, 1)
65 cairo_context.paint()
67 # Create path from stored data
68 # Also, if a line is being drawn, append the partial line temporarily.
69 if self.current_line: self.lines.append(self.current_line)
70 for line in self.lines:
71 if len(line) < 2: continue
72 line_started = False
74 for point in line:
75 if not line_started:
76 cairo_context.move_to(point.x, point.y)
77 line_started = True
78 else:
79 cairo_context.line_to(point.x, point.y)
80 if self.current_line: self.lines.pop()
82 # Draw lines
83 cairo_context.set_source_rgb(0, 0, 0)
84 cairo_context.stroke()
85 return True
87 def on_motion(self, widget, event):
88 if event.state | gtk.gdk.BUTTON1_MASK:
89 if self.current_line:
90 self.current_line.append(Point(int(event.x), int(event.y)))
91 self.update_drawing_area()
93 # This was marked as non-Win32 in the C++ version. Unsure whether
94 # it's okay as it is here.
95 gtk.gdk.event_request_motions(event)
97 return True
99 def on_press(self, widget, event):
100 # On left mouse click, create a new line
101 if event.button == 1:
102 self.current_line = []
103 self.current_line.append(Point(int(event.x), int(event.y)))
105 return True
107 def on_release(self, widget, event):
108 """Returns False when the control's state has been changed by a button release, True otherwise."""
110 if event.button == 1:
111 if self.current_line:
112 self.lines.append(self.current_line)
113 self.current_line = None
114 self.update_drawing_area()
115 self.look_up_chars()
116 return False
117 # If no line was written, return true (no change in state)
118 return True
120 elif event.button == 3:
121 if self.current_line:
122 self.current_line = None
123 self.update_drawing_area()
124 # No change in search results has occurred, so return true
125 return True
126 elif (self.lines):
127 self.lines.pop()
128 self.update_drawing_area()
129 self.look_up_chars()
130 # The search -has- changed, return False so we can capture it.
131 return False
132 else:
133 return True
135 return True
137 def get_results(self):
138 """Returns an array of 5 UTF8-encoded kanji characters."""
140 print "WidgetHWPad.get_results() \n\t= %s" % (self.results,)
142 return self.results
144 def clear(self):
145 self.current_line = None
146 self.lines = []
147 self.results = []
148 self.update_drawing_area()
150 def update_drawing_area(self):
151 self.window.invalidate_rect(None, False)
153 def look_up_chars(self):
154 print "WidgetHWPad.look_up_chars()"
155 #return
157 data_dir = configure.get_system_data_dir()
158 kpdata_dir = os.path.join(data_dir, "kpdata")
160 if os.name == "nt":
161 exe_name = "jben_kpengine.exe"
162 else:
163 exe_name = "jben_kpengine"
165 if not os.path.exists(exe_name) or not os.path.isfile(exe_name):
166 show_message(
167 None, _("Could not find jben_kpengine"),
168 _("J-Ben currently requires the jben_kpengine executable from "
169 "a J-Ben 1.x.x release to perform handwriting recognition. "
170 "Since it could not be found, this feature will not work."))
171 return
173 elif not os.path.exists(data_dir) or not os.path.isdir(data_dir):
174 show_message(
175 None, _("Could not find kpengine_data"),
176 _("J-Ben currently requires the kpengine data from "
177 "a J-Ben 1.x.x release to perform handwriting recognition. "
178 "Since it could not be found, this feature will not work."))
179 return
182 # Line format:
183 # x y x y x y x y x y\n (line 1)
184 # x y x y x y x y\n (line 2)
185 # \n (end of kanji)
186 pipe_data = "\n".join(
187 [" ".join([str(point) for point in line])
188 for line in self.lines]) + "\n\n"
190 p = Popen([exe_name, "-d", kpdata_dir], stdin=PIPE, stdout=PIPE)
191 stdout, stderr = p.communicate(pipe_data)
193 klist = stdout[1:].strip().split()
194 self.results = []
195 if klist:
196 for kanji in klist:
197 self.results.append(unichr(int(kanji)))