1 /***************************************************************
2 * Name: wxledpanel.cpp
3 * Purpose: Code for Class wxLEDPanel
4 * Author: Christian Gr�fe (info@mcs-soft.de)
5 * Created: 2007-02-28
6 * Copyright: Christian Gr�fe (www.mcs-soft.de)
7 * License: wxWindows licence
8 **************************************************************/
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #ifdef __BORLANDC__
14 #pragma hdrstop
15 #endif
16
17 #ifndef WX_PRECOMP
18 #include <wx/wx.h>
19 #endif
20
21 #include <wx/dcbuffer.h>
22 #include "wx/wxledpanel.h"
23
24 #define TIMER_SCROLL_ID 1000
25
BEGIN_EVENT_TABLE(wxLEDPanel,wxControl)26 BEGIN_EVENT_TABLE(wxLEDPanel, wxControl)
27 EVT_PAINT(wxLEDPanel::OnPaint)
28 EVT_ERASE_BACKGROUND(wxLEDPanel::OnEraseBackground)
29 EVT_TIMER(TIMER_SCROLL_ID,wxLEDPanel::OnScrollTimer)
30 END_EVENT_TABLE()
31
32 wxLEDPanel::wxLEDPanel() :
33 m_align(wxALIGN_LEFT|wxALIGN_TOP),
34 m_padLeft(1),
35 m_padRight(1),
36 m_invert(false),
37 m_show_inactivs(true),
38 m_scrollspeed(0),
39 m_scrolldirection(wxALL),
40 m_aniFrameNr(-1)
41 {
42 }
43
wxLEDPanel(wxWindow * parent,wxWindowID id,const wxSize & ledsize,const wxSize & fieldsize,int padding,const wxPoint & pos,long style,const wxValidator & validator)44 wxLEDPanel::wxLEDPanel(wxWindow* parent, wxWindowID id, const wxSize& ledsize,
45 const wxSize& fieldsize, int padding, const wxPoint& pos,
46 long style, const wxValidator& validator) :
47 m_align(wxALIGN_LEFT|wxALIGN_TOP),
48 m_padLeft(1),
49 m_padRight(1),
50 m_invert(false),
51 m_show_inactivs(true),
52 m_scrollspeed(0),
53 m_scrolldirection(wxALL),
54 m_aniFrameNr(-1)
55 {
56 Create(parent,id,ledsize,fieldsize,padding,pos,style,validator);
57 }
58
~wxLEDPanel()59 wxLEDPanel::~wxLEDPanel()
60 {
61 }
62
Create(wxWindow * parent,wxWindowID id,const wxSize & ledsize,const wxSize & fieldsize,int padding,const wxPoint & pos,long style,const wxValidator & validator)63 bool wxLEDPanel::Create(wxWindow* parent, wxWindowID id, const wxSize& ledsize,
64 const wxSize& fieldsize, int padding, const wxPoint& pos,
65 long style, const wxValidator& validator)
66 {
67 // save in member
68 m_ledsize=ledsize;
69 m_padding=padding;
70 wxSize size;
71 size.SetWidth((ledsize.GetWidth()+padding)*fieldsize.GetWidth()+padding);
72 size.SetHeight((ledsize.GetHeight()+padding)*fieldsize.GetHeight()+padding);
73
74 // create the control
75 if(!wxControl::Create(parent,id,pos,size,style,validator))
76 return false;
77
78 // initialise MatrixObjekt
79 m_field.Init(0,fieldsize.GetWidth(),fieldsize.GetHeight());
80
81 // default backgroundcolor is black (call parent, to prevent the call of PrepareBackground)
82 wxWindow::SetBackgroundColour(*wxBLACK);
83
84 // default led-color is red
85 this->SetLEDColour(wxLED_COLOUR_RED);
86
87 // no Input Events
88 this->Enable(false);
89
90 // bind timer
91 m_scrollTimer.SetOwner(this,TIMER_SCROLL_ID);
92
93 return true;
94 }
95
DoGetBestSize() const96 wxSize wxLEDPanel::DoGetBestSize() const
97 {
98 wxSize size;
99 size.SetWidth((m_ledsize.GetWidth()+m_padding)*m_field.GetWidth()+m_padding);
100 size.SetHeight((m_ledsize.GetHeight()+m_padding)*m_field.GetHeight()+m_padding);
101 return size;
102 }
103
Clear()104 void wxLEDPanel::Clear()
105 {
106 m_field.Clear();
107 }
108
Reset()109 void wxLEDPanel::Reset()
110 {
111 SetText(m_text);
112 }
113
114 /** @return the size of the field in points */
GetFieldsize() const115 wxSize wxLEDPanel::GetFieldsize() const
116 {
117 return m_field.GetSize();
118 }
119
120 /** @return the size of one LED on the field */
GetLEDSize() const121 wxSize wxLEDPanel::GetLEDSize() const
122 {
123 return m_ledsize;
124 }
125
126 /**
127 * Sets the colour of the LEDs
128 * @param colourID the ID of the new colour
129 */
SetLEDColour(wxLEDColour colourID)130 void wxLEDPanel::SetLEDColour(wxLEDColour colourID)
131 {
132 // for drawing
133 wxBrush brush;
134 wxPen pen;
135
136 // colourID speichern
137 m_activ_colour_id=colourID;
138
139 int w=m_ledsize.GetWidth()+m_padding;
140 int h=m_ledsize.GetHeight()+m_padding;
141
142 // create Bitmaps for "LED on" und "LED off"
143 wxBitmap led_on(w,h);
144 wxBitmap led_off(w,h);
145 wxBitmap led_none(w,h);
146
147 // draw "LED on"
148 m_mdc_led_on.SelectObject(led_on);
149
150 // Clear Background
151 m_mdc_led_on.SetBackground(this->GetBackgroundColour());
152 m_mdc_led_on.Clear();
153
154 // complete point
155 pen.SetColour(s_colour_dark[colourID-1]);
156 brush.SetColour(s_colour[colourID-1]);
157 m_mdc_led_on.SetPen(pen);
158 m_mdc_led_on.SetBrush(brush);
159 m_mdc_led_on.DrawEllipse(wxPoint(0,0),m_ledsize);
160
161 // left top corner in lighter colour
162 pen.SetColour(s_colour_light[colourID-1]);
163 m_mdc_led_on.SetPen(pen);
164 m_mdc_led_on.DrawEllipticArc(0,0,m_ledsize.GetWidth(),m_ledsize.GetHeight(),75.0,195.0);
165
166
167 // draw "LED off"
168 m_mdc_led_off.SelectObject(led_off);
169
170 // cleare Background
171 m_mdc_led_off.SetBackground(this->GetBackgroundColour());
172 m_mdc_led_off.Clear();
173
174 // complete point
175 pen.SetColour(s_colour_dark[colourID-1]);
176 brush.SetColour(s_colour_verydark[colourID-1]);
177 m_mdc_led_off.SetPen(pen);
178 m_mdc_led_off.SetBrush(brush);
179 m_mdc_led_off.DrawEllipse(wxPoint(0,0),m_ledsize);
180
181
182 // draw "no LED"
183 m_mdc_led_none.SelectObject(led_none);
184 m_mdc_led_none.SetBackground(this->GetBackgroundColour());
185 m_mdc_led_none.Clear();
186
187
188 PrepareBackground();
189 }
190
191 /** @return the real colour of a LED */
GetLEDColour() const192 const wxColour& wxLEDPanel::GetLEDColour() const
193 {
194 return s_colour[m_activ_colour_id];
195 }
196
197 /** Overwritten to prepare the background with the new backgroundcolour
198 * @param colour the new backroundcolour
199 */
SetBackgroundColour(const wxColour & colour)200 bool wxLEDPanel::SetBackgroundColour(const wxColour& colour)
201 {
202 if (wxWindow::SetBackgroundColour(colour))
203 {
204 PrepareBackground();
205 return true;
206 }
207
208 return false;
209 }
210
211 /** Sets the speed for the scrolling
212 * @param speed the speed in ms (optimal range between 80-120)
213 */
SetScrollSpeed(int speed)214 void wxLEDPanel::SetScrollSpeed(int speed)
215 {
216 // the save way
217 m_scrollTimer.Stop();
218
219 // save speed
220 m_scrollspeed=speed;
221
222 // start timer
223 if(m_scrollspeed>0 && m_scrolldirection!=wxALL)
224 m_scrollTimer.Start(speed,true);
225 }
226
227 /** @return the speed of the scrolling */
GetScrollSpeed() const228 int wxLEDPanel::GetScrollSpeed() const
229 {
230 return m_scrollspeed;
231 }
232
233 /** Sets the direction to scroll
234 * @param d the direction (wxALL for no scrolling)
235 */
SetScrollDirection(wxDirection d)236 void wxLEDPanel::SetScrollDirection(wxDirection d)
237 {
238 // the save way
239 m_scrollTimer.Stop();
240
241 // save direction
242 m_scrolldirection=d;
243
244 if(m_scrollspeed>0 && m_scrolldirection!=wxALL)
245 m_scrollTimer.Start(m_scrollspeed,true);
246 }
247
248 /** @return the current direction of the scrolling (wxALL for no scrolling)*/
GetScrollDirection() const249 wxDirection wxLEDPanel::GetScrollDirection() const
250 {
251 return m_scrolldirection;
252 }
253
254 /** Swaps the LED states
255 * @param invert if true, all active LEDs are drawn as inactiv and all inactiv drawn as activ
256 */
ShowInvertet(bool invert)257 void wxLEDPanel::ShowInvertet(bool invert)
258 {
259 if(m_invert==invert) return;
260
261 m_invert=invert;
262 PrepareBackground();
263 }
264
265 /** Should the inactive LEDs be drawn */
ShowInactivLEDs(bool show_inactivs)266 void wxLEDPanel::ShowInactivLEDs(bool show_inactivs)
267 {
268 if(m_show_inactivs==show_inactivs) return;
269
270 m_show_inactivs=show_inactivs;
271 PrepareBackground();
272 }
273
SetContentAlign(int a)274 void wxLEDPanel::SetContentAlign(int a)
275 {
276 // save value
277 m_align=a;
278
279 // Reset the Horizontal position
280 ResetPos();
281
282 // Reinit the field
283 m_field.Clear();
284 m_field.SetDatesAt(m_pos,m_content_mo);
285 }
286
GetContentAlign() const287 int wxLEDPanel::GetContentAlign() const
288 {
289 return m_align;
290 }
291
SetText(const wxString & text,int align)292 void wxLEDPanel::SetText(const wxString& text, int align)
293 {
294 // String emtpy
295 if(text.IsEmpty()) return;
296
297 // the MO for the Text
298 MatrixObject* tmp=NULL;
299
300 // save the align
301 if(align!=-1) m_align=align;
302
303 // save the string
304 m_text=text;
305 m_aniFrameNr=-1;
306
307 // get the MO for the text
308 if(m_align&wxALIGN_CENTER_HORIZONTAL)
309 tmp=m_font.GetMOForText(text,wxALIGN_CENTER_HORIZONTAL);
310 else if(m_align&wxALIGN_RIGHT)
311 tmp=m_font.GetMOForText(text,wxALIGN_RIGHT);
312 else tmp=m_font.GetMOForText(text); // wxALIGN_LEFT
313
314 // save the MO, and delete the tmp
315 m_content_mo.Init(*tmp);
316 delete tmp;
317
318 // Find the place for the text
319 ResetPos();
320
321 // Set in field
322 m_field.Clear();
323 m_field.SetDatesAt(m_pos,m_content_mo);
324 }
325
326 /** @return the current text */
GetText() const327 wxString wxLEDPanel::GetText() const
328 {
329 return m_text;
330 }
331
SetImage(const wxImage img)332 void wxLEDPanel::SetImage(const wxImage img)
333 {
334 if(!img.IsOk()) return;
335 m_text.Empty();
336
337 m_content_mo.Init(img);
338 m_aniFrameNr=-1;
339
340 // Find the place for the bitmap
341 ResetPos();
342
343 // Set in field
344 m_field.Clear();
345 m_field.SetDatesAt(m_pos,m_content_mo);
346 }
347
GetContentAsImage() const348 wxImage wxLEDPanel::GetContentAsImage() const
349 {
350 return m_content_mo.GetAsImage();
351 }
352
SetAnimation(const wxAnimation ani)353 void wxLEDPanel::SetAnimation(const wxAnimation ani)
354 {
355 if(!ani.IsOk() || ani.GetFrameCount()==0) return;
356
357 m_ani = ani;
358 m_text.Empty();
359 m_aniFrameNr = 0;
360
361 m_content_mo.Init(ani.GetFrame(0));
362
363 // Find the place for the bitmap
364 ResetPos();
365
366 // Set in field
367 m_field.Clear();
368 m_field.SetDatesAt(m_pos,m_content_mo);
369
370 // start timer
371 m_scrollTimer.Stop();
372 m_scrollspeed = m_ani.GetDelay(0);
373 m_scrollTimer.Start(m_scrollspeed,true);
374 }
375
GetAnimation() const376 const wxAnimation wxLEDPanel::GetAnimation() const
377 {
378 return m_ani;
379 }
380
SetContentPaddingLeft(int padLeft)381 void wxLEDPanel::SetContentPaddingLeft(int padLeft)
382 {
383 // Save value
384 m_padLeft=padLeft;
385
386 // Reset the text position
387 ResetPos();
388
389 // Reinit the field
390 m_field.Clear();
391 m_field.SetDatesAt(m_pos,m_content_mo);
392 }
393
GetContentPaddingLeft() const394 int wxLEDPanel::GetContentPaddingLeft() const
395 {
396 return m_padLeft;
397 }
398
SetContentPaddingRight(int padRight)399 void wxLEDPanel::SetContentPaddingRight(int padRight)
400 {
401 // Save the Value
402 m_padRight=padRight;
403
404 // Reset the text position
405 ResetPos();
406
407 // Reinit the field
408 m_field.Clear();
409 m_field.SetDatesAt(m_pos,m_content_mo);
410 }
411
GetContentPaddingRight() const412 int wxLEDPanel::GetContentPaddingRight() const
413 {
414 return m_padRight;
415 }
416
417 /** Sets the space between two letters
418 * @param leterSpace the space in points (one point = one LED)
419 */
SetLetterSpace(int letterSpace)420 void wxLEDPanel::SetLetterSpace(int letterSpace)
421 {
422 // is already this size?
423 if(m_font.GetLetterSpace()==letterSpace) return;
424
425 m_font.SetLetterSpace(letterSpace);
426 Reset();
427 }
428
429 /** @return the space between two letters in points */
GetLetterSpace() const430 int wxLEDPanel::GetLetterSpace() const
431 {
432 return m_font.GetLetterSpace();
433 }
434
SetFontType(wxLEDFontType t)435 void wxLEDPanel::SetFontType(wxLEDFontType t)
436 {
437 if(m_font.GetFontType()==t) return;
438
439 m_font.SetFontType(t);
440 Reset();
441 }
442
GetFontType() const443 wxLEDFontType wxLEDPanel::GetFontType() const
444 {
445 return m_font.GetFontType();
446 }
447
448 /** this draws the data on the Control */
DrawField(wxDC & dc,bool backgroundMode)449 void wxLEDPanel::DrawField(wxDC& dc, bool backgroundMode)
450 {
451 wxPoint point;
452 int w=m_ledsize.GetWidth()+m_padding;
453 int h=m_ledsize.GetHeight()+m_padding;
454
455 // Z�hler f�r Zeile und Spalte
456 int x=0,y=0;
457
458 // Pointer to avoid unnesecerie if blocks in the for block
459 wxMemoryDC* p_mdc_data=((m_invert)?((m_show_inactivs)?(&m_mdc_led_off):(&m_mdc_led_none)):(&m_mdc_led_on));
460 wxMemoryDC* p_mdc_nodata=((m_invert)?(&m_mdc_led_on):((m_show_inactivs)?(&m_mdc_led_off):(&m_mdc_led_none)));
461
462 int l = m_field.GetLength();
463 int fw = m_field.GetWidth();
464 const char* field = m_field.GetData();
465 for(int i=0;i<l;++i)
466 {
467 // Koordinaten
468 point.x=x*w+m_padding;
469 point.y=y*h+m_padding;
470
471 // zeichnen
472 if(field[i] && !backgroundMode)
473 {
474 dc.Blit(point.x,point.y,w,h,p_mdc_data,0,0);
475 }
476 else if(backgroundMode)
477 {
478 dc.Blit(point.x,point.y,w,h,p_mdc_nodata,0,0);
479 }
480
481 // hochz�hlen
482 ++x;
483 if(x==fw) {++y; x=0;}
484 }
485 }
486
487 /** Do nothing to avoid flicker */
OnEraseBackground(wxEraseEvent & event)488 void wxLEDPanel::OnEraseBackground(wxEraseEvent& event)
489 {
490 (void)event;
491 }
492
OnPaint(wxPaintEvent & event)493 void wxLEDPanel::OnPaint(wxPaintEvent &event)
494 {
495 (void)event;
496 wxBufferedPaintDC dc(this);
497 //dc.SetBackground(this->GetBackgroundColour());
498 //dc.Clear();
499
500 // background
501 dc.Blit(0,0,m_mdc_background.GetSize().GetWidth(),m_mdc_background.GetSize().GetHeight(),&m_mdc_background,0,0);
502 // field
503 DrawField(dc);
504 }
505
ShiftLeft()506 void wxLEDPanel::ShiftLeft()
507 {
508 // new text Pos
509 m_pos.x--;
510
511 // out of bound
512 if(m_pos.x+m_content_mo.GetWidth()<=0)
513 {
514 m_pos.x=m_field.GetWidth();
515 return;
516 }
517
518 // Shift
519 m_field.ShiftLeft();
520
521 // TODO check bounds!
522 // data for the new line
523 for(int i=0;i<m_content_mo.GetHeight();++i)
524 {
525 char d=m_content_mo.GetDataFrom(abs(m_pos.x-m_field.GetWidth()+1),i);
526 if(d>0) m_field.SetDataAt(m_field.GetWidth()-1,m_pos.y+i,d);
527 }
528 }
529
ShiftRight()530 void wxLEDPanel::ShiftRight()
531 {
532 // new text Pos
533 m_pos.x++;
534 // out of bound
535 if(m_pos.x>=m_field.GetWidth())
536 {
537 m_pos.x=-m_content_mo.GetWidth(); // TODO without +1 error (in SetDatesAt??)
538 return;
539 }
540
541 // Shift
542 m_field.ShiftRight();
543
544 // TODO check bounds!
545 // TODO at first run -> false y-pos!
546 // data for the new line
547 for(int i=0;i<m_content_mo.GetHeight();++i)
548 {
549 char d=m_content_mo.GetDataFrom(abs(m_pos.x-m_field.GetWidth()+1),i);
550 if(d>0) m_field.SetDataAt(0,m_pos.y+i,d);
551 }
552 }
553
ShiftUp()554 void wxLEDPanel::ShiftUp()
555 {
556 // new text Pos
557 m_pos.y--;
558 // out of bound
559 if(m_pos.y+m_content_mo.GetHeight()<=0)
560 m_pos.y=m_field.GetHeight();
561
562 // TODO optimize with shift
563 m_field.Clear();
564 m_field.SetDatesAt(m_pos,m_content_mo);
565 }
566
ShiftDown()567 void wxLEDPanel::ShiftDown()
568 {
569 // new text Pos
570 m_pos.y++;
571 // out of bound
572 if(m_pos.y>=m_field.GetHeight())
573 m_pos.y=-m_content_mo.GetHeight();
574
575 // TODO optimize with shift
576 m_field.Clear();
577 m_field.SetDatesAt(m_pos,m_content_mo);
578
579 }
580
OnScrollTimer(wxTimerEvent & event)581 void wxLEDPanel::OnScrollTimer(wxTimerEvent& event)
582 {
583 (void)event;
584 if(m_scrollspeed==0||m_content_mo.IsEmpty()) return;
585
586 // the save way
587 m_scrollTimer.Stop();
588
589 if(m_aniFrameNr < 0)
590 {
591
592 // Scroll
593 switch(m_scrolldirection)
594 {
595 case wxALL: return;
596 case wxLEFT: this->ShiftLeft(); break;
597 case wxRIGHT: this->ShiftRight(); break;
598 case wxDOWN: this->ShiftDown(); break;
599 case wxUP: this->ShiftUp(); break;
600 default: return;
601 }
602 }
603 else
604 {
605 m_aniFrameNr++;
606 if(m_aniFrameNr >= m_ani.GetFrameCount())
607 m_aniFrameNr=0;
608
609 m_content_mo.Init(m_ani.GetFrame(m_aniFrameNr));
610 m_field.Clear();
611 m_field.SetDatesAt(m_pos,m_content_mo);
612 m_scrollspeed = m_ani.GetDelay(m_aniFrameNr);
613 }
614
615 // Repaint
616 this->Refresh();
617
618 // start timer again
619 m_scrollTimer.Start(m_scrollspeed,true);
620 }
621
622 /** Resets the position of the content after scrolling */
ResetPos()623 void wxLEDPanel::ResetPos()
624 {
625 // has a text?
626 if(m_content_mo.GetData()==NULL) return;
627
628 // horizontal text pos
629 if(m_scrolldirection!=wxLEFT && m_scrolldirection!=wxRIGHT)
630 {
631 if(m_align & wxALIGN_RIGHT)
632 m_pos.x=m_field.GetWidth()-m_content_mo.GetWidth()-m_padRight;
633 else if(m_align & wxALIGN_CENTER_HORIZONTAL)
634 m_pos.x=(m_field.GetWidth()-m_content_mo.GetWidth())/2;
635 else // wxALING_LEFT
636 m_pos.x=m_padLeft;
637 }
638 else if(m_scrolldirection==wxLEFT)
639 m_pos.x=m_field.GetWidth();
640 else if(m_scrolldirection==wxRIGHT)
641 m_pos.x=-m_content_mo.GetWidth();
642
643 // vertical text pos
644 if(m_scrolldirection!=wxUP && m_scrolldirection!=wxDOWN)
645 {
646 if(m_align & wxALIGN_BOTTOM)
647 m_pos.y=m_field.GetHeight()-m_content_mo.GetHeight();
648 else if(m_align & wxALIGN_CENTER_VERTICAL)
649 m_pos.y=(m_field.GetHeight()-m_content_mo.GetHeight())/2;
650 else // wxALIGN TOP
651 m_pos.y=0;
652 }
653 else if(m_scrolldirection==wxUP)
654 m_pos.y=m_field.GetHeight();
655 else if(m_scrolldirection==wxDOWN)
656 m_pos.y=-m_content_mo.GetHeight();
657 }
658
659 /** Prepares the backgroundimage, to optimze speed */
PrepareBackground()660 void wxLEDPanel::PrepareBackground()
661 {
662 wxSize s=DoGetBestSize();
663 wxBitmap bmpBG(s.GetWidth(),s.GetHeight());
664
665 m_mdc_background.SelectObject(bmpBG);
666
667 // clear the background
668 m_mdc_background.SetBackground(this->GetBackgroundColour());
669 m_mdc_background.Clear();
670
671 if(m_invert || m_show_inactivs)
672 DrawField(m_mdc_background, true);
673 }
674
675 // Red, Green, Blue, Yellow, Magenta, Cyan, Grey
676 const wxColour wxLEDPanel::s_colour[7]=
677 { wxColour(255,0,0), wxColour(0,255,0), wxColour(0,0,255),
678 wxColour(255,255,0), wxColour(255,0,255), wxColour(0,255,255),
679 wxColour(128,128,128) };
680
681 const wxColour wxLEDPanel::s_colour_dark[7]=
682 { wxColour(128,0,0), wxColour(0,128,0), wxColour(0,0,128),
683 wxColour(128,128,0), wxColour(128,0,128), wxColour(0,128,128),
684 wxColour(64,64,64) };
685
686 const wxColour wxLEDPanel::s_colour_verydark[7]=
687 { wxColour(64,0,0), wxColour(0,64,0), wxColour(0,0,64),
688 wxColour(64,64,0), wxColour(64,0,64), wxColour(0,64,64),
689 wxColour(32,32,32) };
690
691 const wxColour wxLEDPanel::s_colour_light[7]=
692 { wxColour(255,128,128), wxColour(128,255,128), wxColour(128,128,255),
693 wxColour(255,255,128), wxColour(255,128,255), wxColour(128,255,255),
694 wxColour(192,192,192) };
695