1 /***************************************************************************
2 * wx.cpp is part of Math Graphic Library *
3 * Copyright (C) 2007-2016 Alexey Balakin <mathgl.abalakin@gmail.ru> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU Lesser General Public License as *
7 * published by the Free Software Foundation; either version 3 of the *
8 * License, or (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU Lesser General Public *
16 * License along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 //-----------------------------------------------------------------------------
21 #include <wx/dcclient.h>
22 #include <wx/msgdlg.h>
23 #include <wx/clipbrd.h>
24 #include <wx/dataobj.h>
25 #include <wx/menu.h>
26 #include <wx/scrolwin.h>
27
28 #undef _
29
30 #include "mgl2/canvas_wnd.h"
31 #include "mgl2/wx.h"
32 //-----------------------------------------------------------------------------
33 class MGL_EXPORT mglCanvasWX : public mglCanvasWnd
34 {
35 friend class wxMathGL;
36 public:
37 int sshow; ///< Current state of animation switch (toggle button)
38 wxMathGL *WMGL; ///< Control which draw graphics
39 wxWindow *Wnd; ///< Pointer to window
40
41 mglCanvasWX();
42 virtual ~mglCanvasWX();
43
44 /// Create a window for plotting. Now implemeted only for GLUT.
45 void Window(int argc, char **argv, int (*draw)(mglBase *gr, void *p), const char *title,
46 void *par=NULL, void (*reload)(void *p)=NULL, bool maximize=false);
47 /// Switch on/off transparency (do not overwrite switches in user drawing function)
48 void ToggleAlpha();
49 /// Switch on/off lighting (do not overwrite switches in user drawing function)
50 void ToggleLight();
51 void ToggleRotate(); ///< Switch on/off rotation by mouse
52 void ToggleZoom(); ///< Switch on/off zooming by mouse
53 void ToggleNo(); ///< Switch off all zooming and rotation
54 void Update(); ///< Update picture by calling user drawing function
55 void Adjust(); ///< Adjust size of bitmap to window size
56 void GotoFrame(int d); ///< Show arbitrary frame (use relative step)
57 void Animation(); ///< Run animation (I'm too lasy to change it)
58
59 protected:
60 wxScrolledWindow *scroll; ///< Scrolling area
61 wxMenu *popup; ///< Popup menu
62 // wxSpinCtrl *tet, *phi; ///< Spin box for angles // TODO
63
64 void MakeMenu(); ///< Create menu, toolbar and popup menu
65 };
66 //-----------------------------------------------------------------------------
67 const wxString ScriptName(L"default");
68 enum
69 {
70 TIMER_ID=1000,
71 LAST_ID
72 };
BEGIN_EVENT_TABLE(wxMathGL,wxWindow)73 BEGIN_EVENT_TABLE(wxMathGL, wxWindow)
74 EVT_TIMER (TIMER_ID, wxMathGL::OnNextSlide)
75 EVT_PAINT (wxMathGL::OnPaint)
76 EVT_SIZE (wxMathGL::OnSize)
77 EVT_LEFT_DOWN (wxMathGL::OnMouseLeftDown)
78 EVT_RIGHT_DOWN (wxMathGL::OnMouseDown)
79 EVT_MIDDLE_DOWN (wxMathGL::OnMouseDown)
80 EVT_LEFT_UP (wxMathGL::OnMouseLeftUp)
81 EVT_RIGHT_UP (wxMathGL::OnMouseRightUp)
82 EVT_MOTION (wxMathGL::OnMouseMove)
83 END_EVENT_TABLE()
84 //-----------------------------------------------------------------------------
85 //
86 // class wxMathGL
87 //
88 //-----------------------------------------------------------------------------
89 wxMathGL::wxMathGL(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name) : wxWindow(parent,id,pos,size,style,name)
90 {
91 AutoResize = false; draw_par = 0; draw_func = 0;
92 gr = new mglCanvas; popup = 0; draw_cl = 0;
93 phi = tet = per = 0; x0=y0=xe=ye=0;
94 x1 = y1 = 0; x2 = y2 = 1;
95 alpha = light = zoom = rotate = false;
96 // SetSize(600, 400);
97 timer = new wxTimer(this,TIMER_ID);
98 }
99 //-----------------------------------------------------------------------------
~wxMathGL()100 wxMathGL::~wxMathGL() { if(mgl_use_graph(gr,-1)<1) mgl_delete_graph(gr); }
101 //-----------------------------------------------------------------------------
GetRatio()102 double wxMathGL::GetRatio() { return double(mgl_get_width(gr))/mgl_get_height(gr); }
103 //-----------------------------------------------------------------------------
SetGraph(HMGL GR)104 void wxMathGL::SetGraph(HMGL GR)
105 {
106 mglCanvas *gg = dynamic_cast<mglCanvas *>(GR);
107 if(!gg) return;
108 if(mgl_use_graph(gr,-1)<1) mgl_delete_graph(gr);
109 gr=gg; mgl_use_graph(gg,1);
110 }
111 //-----------------------------------------------------------------------------
OnPaint(wxPaintEvent &)112 void wxMathGL::OnPaint(wxPaintEvent& )
113 {
114 wxPaintDC dc(this);
115 dc.DrawBitmap(pic,0,0);
116 // if(zoom) dc.DrawRectangle(x0,y0,xe-x0,ye-y0);
117 if(mgl_get_flag(gr,MGL_SHOW_POS) && !MousePos.IsEmpty())
118 dc.DrawText(MousePos,0,12);
119 // TODO: add grid drawing here (from Qt)
120 // TODO: add active points drawing here (from Qt)
121 }
122 //-----------------------------------------------------------------------------
OnSize(wxSizeEvent & event)123 void wxMathGL::OnSize(wxSizeEvent& event)
124 {
125 wxSize ev = event.GetSize();
126 if(mgl_get_width(gr)==ev.GetWidth() && mgl_get_height(gr)==ev.GetHeight())
127 return;
128 if(AutoResize && ev.GetWidth()>0 && ev.GetHeight()>0)
129 { mgl_set_size(gr, ev.GetWidth(), ev.GetHeight()); Update(); }
130 else SetSize(mgl_get_width(gr), mgl_get_height(gr));
131 }
132 //-----------------------------------------------------------------------------
OnNextSlide(wxTimerEvent &)133 void wxMathGL::OnNextSlide(wxTimerEvent& ) { NextSlide(); }
134 //-----------------------------------------------------------------------------
SetPer(int p)135 void wxMathGL::SetPer(int p)
136 { if(100*per!=p && p>=0 && p<100) { per = 0.01*p; Repaint(); } }
137 //-----------------------------------------------------------------------------
SetPhi(int p)138 void wxMathGL::SetPhi(int p)
139 { if(phi!=p) { phi = p; Repaint(); } }
140 //-----------------------------------------------------------------------------
SetTet(int t)141 void wxMathGL::SetTet(int t)
142 { if(tet!=t) { tet = t; Repaint(); } }
143 //-----------------------------------------------------------------------------
SetAlpha(bool a)144 void wxMathGL::SetAlpha(bool a)
145 { if(alpha!=a) { alpha = a; Update(); } }
146 //-----------------------------------------------------------------------------
SetLight(bool l)147 void wxMathGL::SetLight(bool l)
148 { if(light!=l) { light = l; Update(); } }
149 //-----------------------------------------------------------------------------
SetZoom(bool z)150 void wxMathGL::SetZoom(bool z)
151 { if(zoom!=z) { zoom=z; rotate=false; Repaint(); } }
152 //-----------------------------------------------------------------------------
SetRotate(bool r)153 void wxMathGL::SetRotate(bool r)
154 { if(rotate!=r) { zoom=false; rotate=r; Repaint(); } }
155 //-----------------------------------------------------------------------------
ShiftDown()156 void wxMathGL::ShiftDown()
157 { mreal d=(y2-y1)/3; y1+=d; y2+=d; Repaint(); }
158 //-----------------------------------------------------------------------------
ShiftUp()159 void wxMathGL::ShiftUp()
160 { mreal d=(y2-y1)/3; y1-=d; y2-=d; Repaint(); }
161 //-----------------------------------------------------------------------------
ShiftRight()162 void wxMathGL::ShiftRight()
163 { mreal d=(x2-x1)/3; x1-=d; x2-=d; Repaint(); }
164 //-----------------------------------------------------------------------------
ShiftLeft()165 void wxMathGL::ShiftLeft()
166 { mreal d=(x2-x1)/3; x1+=d; x2+=d; Repaint(); }
167 //-----------------------------------------------------------------------------
Restore()168 void wxMathGL::Restore()
169 {
170 SetPhi(0); SetTet(0); SetPer(0);
171 x1=y1=0; x2=y2=1; zoom=rotate=false;
172 Repaint();
173 }
174 //-----------------------------------------------------------------------------
ZoomIn()175 void wxMathGL::ZoomIn()
176 {
177 mreal d;
178 d = (y2-y1)/4; y1 += d; y2 -= d;
179 d = (x2-x1)/4; x1 += d; x2 -= d;
180 Repaint();
181 }
182 //-----------------------------------------------------------------------------
ZoomOut()183 void wxMathGL::ZoomOut()
184 {
185 mreal d;
186 d = (y2-y1)/2; y1 -= d; y2 += d;
187 d = (x2-x1)/2; x1 -= d; x2 += d;
188 Repaint();
189 }
190 //-----------------------------------------------------------------------------
Update()191 void wxMathGL::Update()
192 {
193 if(draw_func || draw_cl)
194 {
195 if(mgl_get_flag(gr,MGL_CLF_ON_UPD)) mgl_set_def_param(gr);
196 mgl_set_def_param(gr); mgl_reset_frames(gr);
197 mgl_set_alpha(gr,alpha); mgl_set_light(gr,light);
198 if(draw_func) draw_func(gr, draw_par); // drawing itself
199 else if(draw_cl) { mglGraph g(gr); draw_cl->Draw(&g); }
200 const char *buf = mgl_get_mess(gr);
201 if(*buf)
202 {
203 wxMessageDialog dlg(this, wxString(buf,wxConvLocal), appName, wxOK);
204 dlg.ShowModal();
205 }
206 }
207 else if(mgl_get_num_frame(gr)>0)
208 {
209 mgl_set_alpha(gr,alpha); mgl_set_light(gr,light);
210 // mgl_zoom(gr,x1,y1,x2,y2); mgl_view(gr,-phi,-tet,0);
211 mgl_get_frame(gr,0);
212 }
213 MousePos.Empty(); Repaint();
214 }
215 //-----------------------------------------------------------------------------
ConvertFromGraph(HMGL gr)216 wxBitmap MGL_EXPORT ConvertFromGraph(HMGL gr)
217 {
218 const unsigned char *bb = mgl_get_rgb(gr);
219 int w=mgl_get_width(gr), h=mgl_get_height(gr);
220 unsigned char *tmp = (unsigned char *)malloc(3*w*h);
221 memcpy(tmp,bb,3*w*h);
222 wxImage img(w, h); img.SetData(tmp);
223 return wxBitmap(img);
224 }
225 //-----------------------------------------------------------------------------
Repaint()226 void wxMathGL::Repaint()
227 {
228 mgl_zoom(gr,x1,y1,x2,y2); mgl_view(gr,-phi,-tet,0); mgl_ask_perspective(gr, per);
229 pic = ConvertFromGraph(gr);
230 wxSize sz=GetSize();
231 if(pic.GetWidth()!=sz.GetWidth() || pic.GetHeight()!=sz.GetHeight())
232 SetSize(pic.GetWidth(), pic.GetHeight());
233 Refresh();
234 }
235 //-----------------------------------------------------------------------------
OnMouseLeftDown(wxMouseEvent & ev)236 void wxMathGL::OnMouseLeftDown(wxMouseEvent &ev)
237 {
238 long x=ev.GetX(), y=ev.GetY();
239 if(!zoom && !rotate)
240 {
241 mglPoint p = gr->CalcXYZ(x, y);
242 MousePos.Printf(wxT("x=%g, y=%g, z=%g"),p.x,p.y,p.z);
243 Refresh();
244 // emit mouseClick(p.x,p.y,p.z);
245 }
246 xe=x0=x; ye=y0=y; ev.Skip();
247 }
248 //-----------------------------------------------------------------------------
OnMouseDown(wxMouseEvent & ev)249 void wxMathGL::OnMouseDown(wxMouseEvent &ev)
250 { xe=x0=ev.GetX(); ye=y0=ev.GetY(); ev.Skip(); }
251 //-----------------------------------------------------------------------------
OnMouseLeftUp(wxMouseEvent &)252 void wxMathGL::OnMouseLeftUp(wxMouseEvent &)
253 {
254 if(zoom)
255 {
256 int w1=GetSize().GetWidth(),h1=GetSize().GetHeight();
257 mreal _x1,_x2,_y1,_y2;
258 _x1 = x1+(x2-x1)*(x0-GetPosition().x)/mreal(w1);
259 _y1 = y2-(y2-y1)*(ye-GetPosition().y)/mreal(h1);
260 _x2 = x1+(x2-x1)*(xe-GetPosition().x)/mreal(w1);
261 _y2 = y2-(y2-y1)*(y0-GetPosition().y)/mreal(h1);
262 x1=_x1; x2=_x2; y1=_y1; y2=_y2;
263 if(x1>x2) { _x1=x1; x1=x2; x2=_x1; }
264 if(y1>y2) { _x1=y1; y1=y2; y2=_x1; }
265 x0 = xe; y0 = ye;
266 Update();
267 }
268 }
269 //-----------------------------------------------------------------------------
OnMouseRightUp(wxMouseEvent & ev)270 void wxMathGL::OnMouseRightUp(wxMouseEvent &ev)
271 { if(popup && !rotate) PopupMenu(popup, ev.GetPosition()); }
272 //-----------------------------------------------------------------------------
OnMouseMove(wxMouseEvent & ev)273 void wxMathGL::OnMouseMove(wxMouseEvent &ev)
274 {
275 long w=GetSize().GetWidth(), h=GetSize().GetHeight();
276 xe=ev.GetX(); ye=ev.GetY();
277 if(rotate)
278 {
279 if(ev.ButtonDown(wxMOUSE_BTN_LEFT)) // rotate
280 {
281 mreal ff = 240/sqrt(mreal(w*h));
282 phi += int((x0-xe)*ff);
283 tet += int((y0-ye)*ff);
284 if(phi>180) phi-=360;
285 if(phi<-180) phi+=360;
286 if(tet>180) tet-=360;
287 if(tet<-180) tet+=360;
288 // Update();
289 }
290 if(ev.ButtonDown(wxMOUSE_BTN_RIGHT)) // zoom and perspective
291 {
292 mreal ff = 2.*(y0-ye)/w, gg = 0.5*(xe-x0)/h;
293 mreal cx = (x1+x2)/2, cy = (y1+y2)/2;
294 x1 = cx+(x1-cx)*exp(-ff); x2 = cx+(x2-cx)*exp(-ff);
295 y1 = cy+(y1-cy)*exp(-ff); y2 = cy+(y2-cy)*exp(-ff);
296 per = per + gg;
297 if(per<0) per = 0;
298 if(per>=1) per = 0.9999;
299 // Update();
300 }
301 if(ev.ButtonDown(wxMOUSE_BTN_MIDDLE)) // shift
302 {
303 mreal ff = 1./sqrt(mreal(w*h));
304 mreal dx = (x0-xe)*ff*(x2-x1), dy = (y0-ye)*ff*(y2-y1);
305 x1 += dx; x2 += dx; y1 -= dy; y2 -= dy;
306 }
307 x0 = xe; y0 = ye;
308 Update();
309 }
310 // if(zoom) Update();
311 if(zoom) Refresh(0);
312 }
313 //-----------------------------------------------------------------------------
mglSetExtension(wxString & fname,const char * ext)314 wxString mglSetExtension(wxString &fname, const char *ext)
315 {
316 wxString oname;
317 if(fname.Right(4)!=wxChar('.')+wxString(ext,*wxConvCurrent))
318 oname = fname+wxChar('.')+wxString(ext,*wxConvCurrent);
319 return oname;
320 }
321 //-----------------------------------------------------------------------------
322 // NOTE: this is replacement for wxString::char_str() which is for v.2.8 or later
mglw_str(const wxString & str)323 const char *mglw_str(const wxString &str)
324 {
325 static char *buf=0;
326 if(buf) delete []buf;
327 size_t i, n=str.Len();
328 buf = new char[n+1]; buf[n]=0;
329 for(i=0;i<n;i++) buf[i] = str.GetChar(i);
330 return buf;
331 }
332 //-----------------------------------------------------------------------------
ExportPNG(wxString fname)333 void wxMathGL::ExportPNG(wxString fname)
334 {
335 if(fname.IsEmpty()) fname = ScriptName;
336 if(fname.IsEmpty()) wxMessageBox(appName, wxT("No filename."),wxOK|wxICON_ERROR ,this);
337 else mgl_write_png(gr,mglw_str(mglSetExtension(fname,"png")), mglw_str(appName));
338 }
339 //-----------------------------------------------------------------------------
ExportPNGs(wxString fname)340 void wxMathGL::ExportPNGs(wxString fname)
341 {
342 if(fname.IsEmpty()) fname = ScriptName;
343 if(fname.IsEmpty()) wxMessageBox(appName, wxT("No filename."),wxOK|wxICON_ERROR ,this);
344 else mgl_write_png_solid(gr,mglw_str(mglSetExtension(fname,"png")), mglw_str(appName));
345 }
346 //-----------------------------------------------------------------------------
ExportJPG(wxString fname)347 void wxMathGL::ExportJPG(wxString fname)
348 {
349 if(fname.IsEmpty()) fname = ScriptName;
350 if(fname.IsEmpty()) wxMessageBox(appName, wxT("No filename."),wxOK|wxICON_ERROR ,this);
351 else mgl_write_jpg(gr,mglw_str(mglSetExtension(fname,"jpg")), mglw_str(appName));
352 }
353 //-----------------------------------------------------------------------------
ExportBPS(wxString fname)354 void wxMathGL::ExportBPS(wxString fname)
355 {
356 if(fname.IsEmpty()) fname = ScriptName;
357 if(fname.IsEmpty()) wxMessageBox(appName, wxT("No filename."),wxOK|wxICON_ERROR ,this);
358 else
359 mgl_write_bps(gr,mglw_str(mglSetExtension(fname,"eps")), mglw_str(appName));
360 }
361 //-----------------------------------------------------------------------------
ExportEPS(wxString fname)362 void wxMathGL::ExportEPS(wxString fname)
363 {
364 if(fname.IsEmpty()) fname = ScriptName;
365 if(fname.IsEmpty()) wxMessageBox(appName, wxT("No filename."),wxOK|wxICON_ERROR ,this);
366 else
367 mgl_write_eps(gr,mglw_str(mglSetExtension(fname,"eps")), mglw_str(appName));
368 }
369 //-----------------------------------------------------------------------------
ExportSVG(wxString fname)370 void wxMathGL::ExportSVG(wxString fname)
371 {
372 if(fname.IsEmpty()) fname = ScriptName;
373 if(fname.IsEmpty()) wxMessageBox(appName, wxT("No filename."),wxOK|wxICON_ERROR ,this);
374 else
375 mgl_write_svg(gr,mglw_str(mglSetExtension(fname,"eps")), mglw_str(appName));
376 }
377 //-----------------------------------------------------------------------------
Copy()378 void wxMathGL::Copy()
379 {
380 if (wxTheClipboard->Open())
381 {
382 wxTheClipboard->SetData( new wxBitmapDataObject(pic) );
383 wxTheClipboard->Close();
384 }
385 }
386 //-----------------------------------------------------------------------------
SetSize(int w,int h)387 void wxMathGL::SetSize(int w, int h)
388 { mgl_set_size(gr,w,h); wxWindow::SetSize(w, h); Update(); }
389 //-----------------------------------------------------------------------------
Adjust()390 void wxMathGL::Adjust()
391 {
392 wxSize sz=GetSize();
393 mgl_set_size(gr,sz.GetWidth(),sz.GetHeight());
394 Repaint();
395 }
396 //-----------------------------------------------------------------------------
NextSlide()397 void wxMathGL::NextSlide()
398 {
399 mglCanvasWnd *g = dynamic_cast<mglCanvasWnd *>(gr);
400 if(g && g->GetNumFig()>1) g->NextFrame();
401 }
402 //-----------------------------------------------------------------------------
PrevSlide()403 void wxMathGL::PrevSlide()
404 {
405 mglCanvasWnd *g = dynamic_cast<mglCanvasWnd *>(gr);
406 if(g && g->GetNumFig()>1) g->PrevFrame();
407 }
408 //-----------------------------------------------------------------------------
Animation(bool st)409 void wxMathGL::Animation(bool st)
410 {
411 if(st) timer->Start(int(mgl_wnd_get_delay(gr)*1000));
412 else timer->Stop();
413 }
414 //-----------------------------------------------------------------------------
About()415 void wxMathGL::About()
416 {
417 wxString s = wxT("MathGL v. 2.") + wxString::Format(wxT("%g"),MGL_VER2) +
418 wxT("\n(c) Alexey Balakin, 2007\nhttp://mathgl.sourceforge.net/");
419 wxMessageBox(s, wxT("MathGL - about"), wxOK|wxICON_INFORMATION, this);
420 }
421 //-----------------------------------------------------------------------------
422