Added .gitignore info for Windows build files.
[jben.git] / panel_kanjipad.cpp
blob6678d308e079a9341e76eb82c557d82960b7b198
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"
27 BEGIN_EVENT_TABLE(PanelKanjiPad, wxPanel)
28 EVT_LEFT_DOWN(PanelKanjiPad::OnMouseDown)
29 EVT_LEFT_UP(PanelKanjiPad::OnMouseUp)
30 EVT_LEAVE_WINDOW(PanelKanjiPad::OnLeaveWindow)
31 EVT_MOTION(PanelKanjiPad::OnMouseMove)
32 EVT_RIGHT_DOWN(PanelKanjiPad::OnMouseRightDown)
33 EVT_PAINT(PanelKanjiPad::OnPaint)
34 EVT_END_PROCESS(wxID_ANY, PanelKanjiPad::AfterEngineCall)
35 END_EVENT_TABLE()
37 PanelKanjiPad::PanelKanjiPad(wxWindow *owner,
38 wxWindowID id,
39 const wxPoint& pos,
40 const wxSize& size,
41 long style,
42 const wxString& name) : wxPanel(owner, id, pos,
43 size, style, name) {
44 isDrawing=false;
45 kpengine=NULL;
46 kpStdin=NULL;
47 kpStdout=kpStderr=NULL;
48 kpPid=0;
49 for(int i=0;i<KANJIPAD_MAX_KANJI;i++) results[i]=_T('\0');
52 void PanelKanjiPad::OnMouseDown(wxMouseEvent& ev) {
53 currentStroke.push_back(ev.GetPosition());
54 #ifdef DEBUG
55 printf("MouseDown: [%d/%d]\n", currentStroke.back().x, currentStroke.back().y);
56 #endif
57 isDrawing=true;
60 void PanelKanjiPad::OnMouseUp(wxMouseEvent& ev) {
61 if(isDrawing) {
62 isDrawing=false;
63 #ifdef DEBUG
64 printf("MouseUp: [%d/%d]\n", currentStroke.back().x, currentStroke.back().y);
65 #endif
66 strokes.push_back(currentStroke);
67 currentStroke.clear();
71 void PanelKanjiPad::OnLeaveWindow(wxMouseEvent& ev) {
72 if(isDrawing) OnMouseUp(ev);
75 void PanelKanjiPad::OnMouseMove(wxMouseEvent& ev) {
76 if(isDrawing) {
77 wxPoint pCurrent = ev.GetPosition();
78 wxPoint pLast = currentStroke.back();
79 wxClientDC dc(this);
81 /* Do drawing */
82 dc.SetBrush(*wxBLACK_BRUSH);
83 dc.DrawLine(pLast.x, pLast.y, pCurrent.x, pCurrent.y);
84 dc.SetBrush(wxNullBrush);
86 /* Append point to stroke */
87 currentStroke.push_back(pCurrent);
88 #ifdef DEBUG
89 printf("MouseMove: [%d/%d]\n", currentStroke.back().x, currentStroke.back().y);
90 #endif
94 void PanelKanjiPad::Clear() {
95 currentStroke.clear();
96 strokes.clear();
99 void PanelKanjiPad::OnPaint(wxPaintEvent& ev) {
100 wxPaintDC dc(this);
101 dc.SetBackground(*wxWHITE_BRUSH);
102 dc.SetBrush(*wxBLACK_BRUSH);
104 wxPoint *pList;
105 int pCount, i;
107 dc.Clear();
108 /* Draw all strokes */
109 for(list< list<wxPoint> >::iterator li = strokes.begin();
110 li!=strokes.end(); li++) {
111 pCount = li->size();
112 pList = new wxPoint[pCount];
113 i=0;
114 for(list<wxPoint>::iterator pi = li->begin();
115 pi != li->end(); pi++) {
116 pList[i] = *pi;
117 i++;
119 dc.DrawLines(pCount, pList);
120 delete[] pList;
123 dc.SetBrush(wxNullBrush);
126 void PanelKanjiPad::OnMouseRightDown(wxMouseEvent& ev) {
127 if(isDrawing) {
128 wxPoint p = ev.GetPosition();
129 currentStroke.clear();
130 currentStroke.push_back(p);
131 } else {
132 /* For some reason, this call is slow! */
133 if(strokes.size()>0) strokes.pop_back();
135 this->Refresh();
138 list< list<wxPoint> > const* PanelKanjiPad::GetStrokes() {return &strokes;}
140 bool PanelKanjiPad::Search() {
141 /* Create string to send to back end */
142 /* kpengine takes alternating x y args for points via stdin.
143 '\n' breaks between the strokes. */
144 char buffer[30];
145 string points("");
146 size_t charsWritten;
148 if(!kpengine) {
149 if(strokes.size()<1) return false;
150 for(list< list<wxPoint> >::const_iterator li=strokes.begin();
151 li!=strokes.end(); li++) {
152 for(list<wxPoint>::const_iterator pi=li->begin();
153 pi!=li->end(); pi++) {
154 charsWritten = sprintf(buffer, "%d %d ", pi->x, pi->y);
155 buffer[charsWritten]='\0';
156 points.append(buffer);
158 points.append("\n");
160 points.append("\n");
162 /* Connect to back end */
163 kpengine = new wxProcess(this);
164 kpengine->Redirect();
165 #ifdef __MSWINDOWS__
166 wxString command = _T(".\\kpengine");
167 #else
168 wxString command = _T("./kpengine");
169 #endif
170 kpPid = wxExecute(command, wxEXEC_ASYNC, kpengine);
172 /* Grab our streams */
173 kpStdin = kpengine->GetOutputStream();
174 kpStdout = kpengine->GetInputStream();
175 kpStderr = kpengine->GetErrorStream();
177 if(!kpPid) {
178 wxMessageBox(_T("ERROR: kpengine could not start!"),
179 _T("Error!"), wxOK | wxICON_ERROR, this);
180 } else if(!kpStdin || !kpStdout || !kpStderr) {
181 wxMessageBox(_T("ERROR: Could not capture streams from kpengine!"),
182 _T("Error!"), wxOK | wxICON_ERROR, this);
183 wxKillError killres = wxProcess::Kill(kpPid, wxSIGTERM);
184 if(killres!=wxKILL_OK)
185 wxMessageBox(wxString::Format(
186 _T("ERROR: Sending SIGTERM to kpengine returned "
187 "code %d!\n"), killres),
188 _T("Error!"), wxOK | wxICON_ERROR, this);
189 kpPid = 0;
191 /* If either of the above errors occurred, then bail. */
192 if(kpPid==0) {
193 delete kpengine;
194 kpengine = NULL;
195 return false;
199 /* Write all data out to kpengine's stdin */
200 size_t len = points.length();
201 charsWritten = 0;
202 while(charsWritten<len) {
203 kpStdin->Write((const void *)(points.c_str() + charsWritten),
204 points.length());
205 charsWritten+=kpStdin->LastWrite();
207 kpStdin->Close();
209 /* Wait until the child process terminates */
210 /* However, don't wait forever! After 3 seconds, force it to close! */
211 wxLongLong stime = wxGetLocalTime();
212 while(kpengine && (wxGetLocalTime() - stime < 3000))
213 wxTheApp->Yield();
215 return (results[0] != _T('\0'));
216 } return false;
219 void PanelKanjiPad::AfterEngineCall(wxProcessEvent& ev) {
220 if(ev.GetPid()==kpPid) {
221 if(kpengine) {
222 char buffer[81];
223 size_t index, len;
225 memset((void *)buffer, 0, 81);
227 for(int i=0;i<KANJIPAD_MAX_KANJI;i++) results[i]=_T('\0');
228 if(kpStdout->CanRead()) {
229 kpStdout->Read(buffer, 80);
231 if(buffer[0]=='K') {
232 index = 1;
233 len = strlen(buffer);
234 for(int i=0;i<KANJIPAD_MAX_KANJI;i++) {
235 if(index<strlen(buffer)) {
236 results[i] = atoi(buffer+index);
237 index = strchr(buffer+index, ' ') - buffer + 1;
242 buffer[0] = '\0';
243 if(kpStderr->CanRead()) {
244 kpStderr->Read(buffer, 80);
247 if(strlen(buffer)>0) {
248 string errstr("Errors: [");
249 errstr.append(buffer);
250 while(kpStderr->CanRead()) {
251 kpStderr->Read(buffer, 80);
252 errstr.append(buffer);
254 errstr.append("]\n");
255 wxMessageBox(wxString(errstr.c_str(), wxConvUTF8),
256 _T("Error on kpengine call"),
257 wxOK | wxICON_ERROR, this);
260 delete kpengine;
261 kpengine = NULL;
262 kpPid=0;