Various changes to preferences object, file loading, and error logging.
[jben.git] / panel_kanjipad.cpp
blob55bce15f477896eb6e3d40852b059b28c25e3906
1 /*
2 Project: wxKanjiPad
3 Author: Paul Goins
4 Website: http://www.vultaire.net/software/wxkanjipad/files/
5 License: GNU General Public License (GPL) version 2
6 (http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt)
8 File: panel_kanjipad.cpp
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License along
21 with this program; if not, write to the Free Software Foundation, Inc.,
22 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "panel_kanjipad.h"
26 #include "string_utils.h"
27 #ifndef JB_DATADIR
28 #define JB_DATADIR "."
29 #endif
30 #ifndef KPENGINE_DATADIR
31 #ifdef __WXMSW__
32 #define KPENGINE_DATADIR JB_DATADIR "\\kpengine_data"
33 #else
34 #define KPENGINE_DATADIR JB_DATADIR "/kpengine_data"
35 #endif
36 #endif
38 BEGIN_EVENT_TABLE(PanelKanjiPad, wxPanel)
39 EVT_LEFT_DOWN(PanelKanjiPad::OnMouseDown)
40 EVT_LEFT_UP(PanelKanjiPad::OnMouseUp)
41 EVT_LEAVE_WINDOW(PanelKanjiPad::OnLeaveWindow)
42 EVT_MOTION(PanelKanjiPad::OnMouseMove)
43 EVT_RIGHT_DOWN(PanelKanjiPad::OnMouseRightDown)
44 EVT_PAINT(PanelKanjiPad::OnPaint)
45 EVT_END_PROCESS(wxID_ANY, PanelKanjiPad::AfterEngineCall)
46 END_EVENT_TABLE()
48 PanelKanjiPad::PanelKanjiPad(wxWindow *owner,
49 wxWindowID id,
50 const wxPoint& pos,
51 const wxSize& size,
52 long style,
53 const wxString& name) : wxPanel(owner, id, pos,
54 size, style, name) {
55 isDrawing=false;
56 kpengine=NULL;
57 kpStdin=NULL;
58 kpStdout=kpStderr=NULL;
59 kpPid=0;
60 for(int i=0;i<KANJIPAD_MAX_KANJI;i++) results[i]=_T('\0');
63 void PanelKanjiPad::OnMouseDown(wxMouseEvent& ev) {
64 currentStroke.push_back(ev.GetPosition());
65 #ifdef DEBUG
66 printf("MouseDown: [%d/%d]\n", currentStroke.back().x, currentStroke.back().y);
67 #endif
68 isDrawing=true;
71 void PanelKanjiPad::OnMouseUp(wxMouseEvent& ev) {
72 if(isDrawing) {
73 isDrawing=false;
74 #ifdef DEBUG
75 printf("MouseUp: [%d/%d]\n", currentStroke.back().x, currentStroke.back().y);
76 #endif
77 strokes.push_back(currentStroke);
78 currentStroke.clear();
82 void PanelKanjiPad::OnLeaveWindow(wxMouseEvent& ev) {
83 if(isDrawing) OnMouseUp(ev);
86 void PanelKanjiPad::OnMouseMove(wxMouseEvent& ev) {
87 if(isDrawing) {
88 wxPoint pCurrent = ev.GetPosition();
89 wxPoint pLast = currentStroke.back();
90 wxClientDC dc(this);
92 /* Do drawing */
93 dc.SetBrush(*wxBLACK_BRUSH);
94 dc.DrawLine(pLast.x, pLast.y, pCurrent.x, pCurrent.y);
95 dc.SetBrush(wxNullBrush);
97 /* Append point to stroke */
98 currentStroke.push_back(pCurrent);
99 #ifdef DEBUG
100 printf("MouseMove: [%d/%d]\n", currentStroke.back().x, currentStroke.back().y);
101 #endif
105 void PanelKanjiPad::Clear() {
106 currentStroke.clear();
107 strokes.clear();
110 void PanelKanjiPad::OnPaint(wxPaintEvent& ev) {
111 wxPaintDC dc(this);
112 dc.SetBackground(*wxWHITE_BRUSH);
113 dc.SetBrush(*wxBLACK_BRUSH);
115 wxPoint *pList;
116 int pCount, i;
118 dc.Clear();
119 /* Draw all strokes */
120 for(list< list<wxPoint> >::iterator li = strokes.begin();
121 li!=strokes.end(); li++) {
122 pCount = li->size();
123 pList = new wxPoint[pCount];
124 i=0;
125 for(list<wxPoint>::iterator pi = li->begin();
126 pi != li->end(); pi++) {
127 pList[i] = *pi;
128 i++;
130 dc.DrawLines(pCount, pList);
131 delete[] pList;
134 dc.SetBrush(wxNullBrush);
137 void PanelKanjiPad::OnMouseRightDown(wxMouseEvent& ev) {
138 if(isDrawing) {
139 wxPoint p = ev.GetPosition();
140 currentStroke.clear();
141 currentStroke.push_back(p);
142 } else {
143 /* For some reason, this call is slow! */
144 if(strokes.size()>0) strokes.pop_back();
146 this->Refresh();
149 list< list<wxPoint> > const* PanelKanjiPad::GetStrokes() {return &strokes;}
151 bool PanelKanjiPad::Search() {
152 /* Create string to send to back end */
153 /* kpengine takes alternating x y args for points via stdin.
154 '\n' breaks between the strokes. */
155 char buffer[30];
156 string points("");
157 size_t charsWritten;
159 if(!kpengine) {
160 if(strokes.size()<1) return false;
161 for(list< list<wxPoint> >::const_iterator li=strokes.begin();
162 li!=strokes.end(); li++) {
163 for(list<wxPoint>::const_iterator pi=li->begin();
164 pi!=li->end(); pi++) {
165 charsWritten = sprintf(buffer, "%d %d ", pi->x, pi->y);
166 buffer[charsWritten]='\0';
167 points.append(buffer);
169 points.append("\n");
171 points.append("\n");
173 /* Connect to back end */
174 kpengine = new wxProcess(this);
175 kpengine->Redirect();
176 wxString command = _T("jben_kpengine -d " KPENGINE_DATADIR);
177 kpPid = wxExecute(command, wxEXEC_ASYNC, kpengine);
179 /* Grab our streams */
180 kpStdin = kpengine->GetOutputStream();
181 kpStdout = kpengine->GetInputStream();
182 kpStderr = kpengine->GetErrorStream();
184 if(!kpPid) {
185 wxMessageBox(_T("ERROR: kpengine could not start!"),
186 _T("Error!"), wxOK | wxICON_ERROR, this);
187 } else if(!kpStdin || !kpStdout || !kpStderr) {
188 wxMessageBox(_T("ERROR: Could not capture streams from kpengine!"),
189 _T("Error!"), wxOK | wxICON_ERROR, this);
190 wxKillError killres = wxProcess::Kill(kpPid, wxSIGTERM);
191 if(killres!=wxKILL_OK)
192 wxMessageBox(wxString::Format(
193 _T("ERROR: Sending SIGTERM to kpengine returned "
194 "code %d!\n"), killres),
195 _T("Error!"), wxOK | wxICON_ERROR, this);
196 kpPid = 0;
198 /* If either of the above errors occurred, then bail. */
199 if(kpPid==0) {
200 delete kpengine;
201 kpengine = NULL;
202 return false;
206 /* Write all data out to kpengine's stdin */
207 size_t len = points.length();
208 charsWritten = 0;
209 while(charsWritten<len) {
210 kpStdin->Write((const void *)(points.c_str() + charsWritten),
211 points.length());
212 charsWritten+=kpStdin->LastWrite();
214 kpStdin->Close();
216 /* Wait until the child process terminates */
217 /* However, don't wait forever! After 3 seconds, force it to close! */
218 wxLongLong stime = wxGetLocalTime();
219 while(kpengine && (wxGetLocalTime() - stime < 3000))
220 wxTheApp->Yield();
222 return (results[0] != _T('\0'));
223 } return false;
226 void PanelKanjiPad::AfterEngineCall(wxProcessEvent& ev) {
227 if(ev.GetPid()==kpPid) {
228 if(kpengine) {
229 char buffer[81];
230 size_t index, len;
232 memset((void *)buffer, 0, 81);
234 for(int i=0;i<KANJIPAD_MAX_KANJI;i++) results[i]=_T('\0');
235 if(kpStdout->CanRead()) {
236 kpStdout->Read(buffer, 80);
238 if(buffer[0]=='K') {
239 index = 1;
240 len = strlen(buffer);
241 for(int i=0;i<KANJIPAD_MAX_KANJI;i++) {
242 if(index<strlen(buffer)) {
243 results[i] = atoi(buffer+index);
244 index = strchr(buffer+index, ' ') - buffer + 1;
249 buffer[0] = '\0';
250 if(kpStderr->CanRead()) {
251 kpStderr->Read(buffer, 80);
254 if(strlen(buffer)>0) {
255 string errstr;
256 errstr.append(buffer);
257 while(kpStderr->CanRead()) {
258 kpStderr->Read(buffer, 80);
259 errstr.append(buffer);
261 errstr = string("Errors: [").append(Trim(errstr)).append("]");
262 wxMessageBox(wxString(errstr.c_str(), wxConvUTF8).Trim(true).Trim(false),
263 _T("Error on kpengine call"),
264 wxOK | wxICON_ERROR, this);
267 delete kpengine;
268 kpengine = NULL;
269 kpPid=0;