1// ============================================================================ 2// headers 3// ============================================================================ 4 5#include "wx/wxprec.h" 6 7#ifdef __BORLANDC__ 8 #pragma hdrstop 9#endif //__BORLANDC__ 10 11#ifndef WX_PRECOMP 12 #include "wx/dcclient.h" 13 #include "wx/dcmemory.h" 14 #include "wx/intl.h" 15#endif 16 17#include "wx/gizmos/ledctrl.h" 18 19// ---------------------------------------------------------------------------- 20// constants 21// ---------------------------------------------------------------------------- 22 23// A LED digit is build up like this, with maximum 7 Lines : 24// 25// 111 26// 6 2 27// 777 28// 5 3 29// 444 30// 31// Each number contains combinations of the lines, and they are set up below. 32 33const int LINE1 = 1; 34const int LINE2 = 2; 35const int LINE3 = 4; 36const int LINE4 = 8; 37const int LINE5 = 16; 38const int LINE6 = 32; 39const int LINE7 = 64; 40const int DECIMALSIGN = 128; 41 42const int DIGIT0 = LINE1 | LINE2 | LINE3 | LINE4 | LINE5 | LINE6; 43const int DIGIT1 = LINE2 | LINE3; 44const int DIGIT2 = LINE1 | LINE2 | LINE4 | LINE5 | LINE7; 45const int DIGIT3 = LINE1 | LINE2 | LINE3 | LINE4 | LINE7; 46const int DIGIT4 = LINE2 | LINE3 | LINE6 | LINE7; 47const int DIGIT5 = LINE1 | LINE3 | LINE4 | LINE6 | LINE7; 48const int DIGIT6 = LINE1 | LINE3 | LINE4 | LINE5 | LINE6 | LINE7; 49const int DIGIT7 = LINE1 | LINE2 | LINE3; 50const int DIGIT8 = LINE1 | LINE2 | LINE3 | LINE4 | LINE5 | LINE6 | LINE7; 51const int DIGIT9 = LINE1 | LINE2 | LINE3 | LINE6 | LINE7; 52const int DASH = LINE7; 53 54const int DIGITALL = -1; 55 56// ============================================================================ 57// wxLEDNumberCtrl class implementation 58// ============================================================================ 59 60wxLEDNumberCtrl::wxLEDNumberCtrl() 61: m_Alignment(wxLED_ALIGN_LEFT), 62 m_LineMargin(-1), 63 m_DigitMargin(-1), 64 m_LineLength(-1), 65 m_LineWidth(-1), 66 m_DrawFaded(false), 67 m_LeftStartPos(-1) 68{ 69} 70 71 72wxLEDNumberCtrl::wxLEDNumberCtrl(wxWindow *parent, wxWindowID id, 73 const wxPoint& pos, const wxSize& size, 74 long style) 75: m_Alignment(wxLED_ALIGN_LEFT), 76 m_LineMargin(-1), 77 m_DigitMargin(-1), 78 m_LineLength(-1), 79 m_LineWidth(-1), 80 m_DrawFaded(false), 81 m_LeftStartPos(-1) 82{ 83 Create(parent, id, pos, size, style); 84} 85 86 87bool wxLEDNumberCtrl::Create(wxWindow *parent, wxWindowID id, 88 const wxPoint& pos, const wxSize& size, 89 long style) 90{ 91 bool RetVal = wxControl::Create(parent, id, pos, size, style); 92 93 if ((style & wxLED_DRAW_FADED) != 0) 94 SetDrawFaded(true); 95 if ((style & wxLED_ALIGN_MASK) != 0) 96 SetAlignment((wxLEDValueAlign)(style & wxLED_ALIGN_MASK)); 97 98 SetBackgroundColour(*wxBLACK); 99 SetForegroundColour(*wxGREEN); 100 101 return RetVal; 102} 103 104 105void wxLEDNumberCtrl::SetAlignment(wxLEDValueAlign Alignment, bool Redraw) 106{ 107 if (Alignment != m_Alignment) 108 { 109 m_Alignment = Alignment; 110 RecalcInternals(GetClientSize()); 111 112 if (Redraw) 113 Refresh(false); 114 } 115} 116 117 118void wxLEDNumberCtrl::SetDrawFaded(bool DrawFaded, bool Redraw) 119{ 120 if (DrawFaded != m_DrawFaded) 121 { 122 m_DrawFaded = DrawFaded; 123 124 if (Redraw) 125 Refresh(false); 126 } 127} 128 129 130void wxLEDNumberCtrl::SetValue(wxString const &Value, bool Redraw) 131{ 132 if (Value != m_Value) 133 { 134#ifdef __WXDEBUG__ 135 if (!Value.empty()) 136 { 137 for(size_t i=0; i<Value.Length(); i++) { 138 wxChar ch = Value[i]; 139 wxASSERT_MSG((ch>='0' && ch<='9') || ch=='-' || ch==' ' || ch=='.', 140 wxT("wxLEDNumberCtrl can only display numeric string values.")); 141 } 142 } 143#endif 144 145 m_Value = Value; 146 RecalcInternals(GetClientSize()); 147 148 if (Redraw) 149 Refresh(false); 150 } 151} 152 153 154BEGIN_EVENT_TABLE(wxLEDNumberCtrl, wxControl) 155 EVT_ERASE_BACKGROUND(wxLEDNumberCtrl::OnEraseBackground) 156 EVT_PAINT(wxLEDNumberCtrl::OnPaint) 157 EVT_SIZE(wxLEDNumberCtrl::OnSize) 158END_EVENT_TABLE() 159 160 161void wxLEDNumberCtrl::OnEraseBackground(wxEraseEvent &WXUNUSED(event)) 162{ 163} 164 165 166void wxLEDNumberCtrl::OnPaint(wxPaintEvent &WXUNUSED(event)) 167{ 168 wxPaintDC Dc(this); 169 170 int Width, Height; 171 GetClientSize(&Width, &Height); 172 173 wxBitmap *pMemoryBitmap = new wxBitmap(Width, Height); 174 wxMemoryDC MemDc; 175 176 MemDc.SelectObject(*pMemoryBitmap); 177 178 // Draw background. 179 MemDc.SetBrush(wxBrush(GetBackgroundColour(), wxSOLID)); 180 MemDc.DrawRectangle(wxRect(0, 0, Width, Height)); 181 MemDc.SetBrush(wxNullBrush); 182 183 // Iterate each digit in the value, and draw. 184 const int DigitCount = m_Value.Len(); 185 for (int offset=0, i = 0; offset < DigitCount; ++offset, ++i) 186 { 187 wxChar c = m_Value.GetChar(offset); 188 189 // Draw faded lines if wanted. 190 if (m_DrawFaded && (c != _T('.'))) 191 DrawDigit(MemDc, DIGITALL, i); 192 193 // Draw the digits. 194 switch (c) 195 { 196 case _T('0') : 197 DrawDigit(MemDc, DIGIT0, i); 198 break; 199 case _T('1') : 200 DrawDigit(MemDc, DIGIT1, i); 201 break; 202 case _T('2') : 203 DrawDigit(MemDc, DIGIT2, i); 204 break; 205 case _T('3') : 206 DrawDigit(MemDc, DIGIT3, i); 207 break; 208 case _T('4') : 209 DrawDigit(MemDc, DIGIT4, i); 210 break; 211 case _T('5') : 212 DrawDigit(MemDc, DIGIT5, i); 213 break; 214 case _T('6') : 215 DrawDigit(MemDc, DIGIT6, i); 216 break; 217 case _T('7') : 218 DrawDigit(MemDc, DIGIT7, i); 219 break; 220 case _T('8') : 221 DrawDigit(MemDc, DIGIT8, i); 222 break; 223 case _T('9') : 224 DrawDigit(MemDc, DIGIT9, i); 225 break; 226 case _T('-') : 227 DrawDigit(MemDc, DASH, i); 228 break; 229 case _T('.') : 230 // Display the decimal in the previous segment 231 i--; 232 DrawDigit(MemDc, DECIMALSIGN, i); 233 break; 234 case _T(' ') : 235 // just skip it 236 break; 237 default : 238 wxFAIL_MSG(wxT("Unknown digit value")); 239 break; 240 } 241 } 242 243 // Blit the memory dc to screen. 244 Dc.Blit(0, 0, Width, Height, &MemDc, 0, 0, wxCOPY); 245 delete pMemoryBitmap; 246} 247 248 249void wxLEDNumberCtrl::DrawDigit(wxDC &Dc, int Digit, int Column) 250{ 251 wxColour LineColor(GetForegroundColour()); 252 253 if (Digit == DIGITALL) 254 { 255 const unsigned char R = (unsigned char)(LineColor.Red() / 16); 256 const unsigned char G = (unsigned char)(LineColor.Green() / 16); 257 const unsigned char B = (unsigned char)(LineColor.Blue() / 16); 258 259 LineColor.Set(R, G, B); 260 } 261 262 int XPos = m_LeftStartPos + Column * (m_LineLength + m_DigitMargin); 263 264 // Create a pen and draw the lines. 265 wxPen Pen(LineColor, m_LineWidth, wxSOLID); 266 Dc.SetPen(Pen); 267 268 if ((Digit & LINE1)) 269 { 270 Dc.DrawLine(XPos + m_LineMargin*2, m_LineMargin, 271 XPos + m_LineLength + m_LineMargin*2, m_LineMargin); 272 } 273 274 if (Digit & LINE2) 275 { 276 Dc.DrawLine(XPos + m_LineLength + m_LineMargin*3, m_LineMargin*2, 277 XPos + m_LineLength + m_LineMargin*3, m_LineLength + (m_LineMargin*2)); 278 } 279 280 if (Digit & LINE3) 281 { 282 Dc.DrawLine(XPos + m_LineLength + m_LineMargin*3, m_LineLength + (m_LineMargin*4), 283 XPos + m_LineLength + m_LineMargin*3, m_LineLength*2 + (m_LineMargin*4)); 284 } 285 286 if (Digit & LINE4) 287 { 288 Dc.DrawLine(XPos + m_LineMargin*2, m_LineLength*2 + (m_LineMargin*5), 289 XPos + m_LineLength + m_LineMargin*2, m_LineLength*2 + (m_LineMargin*5)); 290 } 291 292 if (Digit & LINE5) 293 { 294 Dc.DrawLine(XPos + m_LineMargin, m_LineLength + (m_LineMargin*4), 295 XPos + m_LineMargin, m_LineLength*2 + (m_LineMargin*4)); 296 } 297 298 if (Digit & LINE6) 299 { 300 Dc.DrawLine(XPos + m_LineMargin, m_LineMargin*2, 301 XPos + m_LineMargin, m_LineLength + (m_LineMargin*2)); 302 } 303 304 if (Digit & LINE7) 305 { 306 Dc.DrawLine(XPos + m_LineMargin*2, m_LineLength + (m_LineMargin*3), 307 XPos + m_LineMargin*2 + m_LineLength, m_LineLength + (m_LineMargin*3)); 308 } 309 310 if (Digit & DECIMALSIGN) 311 { 312 Dc.DrawLine(XPos + m_LineLength + m_LineMargin*4, m_LineLength*2 + (m_LineMargin*5), 313 XPos + m_LineLength + m_LineMargin*4, m_LineLength*2 + (m_LineMargin*5)); 314 } 315 316 Dc.SetPen(wxNullPen); 317} 318 319 320void wxLEDNumberCtrl::RecalcInternals(const wxSize &CurrentSize) 321{ 322 // Dimensions of LED segments 323 // 324 // Size of character is based on the HEIGH of the widget, NOT the width. 325 // Segment height is calculated as follows: 326 // Each segment is m_LineLength pixels long. 327 // There is m_LineMargin pixels at the top and bottom of each line segment 328 // There is m_LineMargin pixels at the top and bottom of each digit 329 // 330 // Therefore, the heigth of each character is: 331 // m_LineMargin : Top digit boarder 332 // m_LineMargin+m_LineLength+m_LineMargin : Top half of segment 333 // m_LineMargin+m_LineLength+m_LineMargin : Bottom half of segment 334 // m_LineMargin : Bottom digit boarder 335 // ---------------------- 336 // m_LineMargin*6 + m_LineLength*2 == Total height of digit. 337 // Therefore, (m_LineMargin*6 + m_LineLength*2) must equal Height 338 // 339 // Spacing between characters can then be calculated as follows: 340 // m_LineMargin : before the digit, 341 // m_LineMargin+m_LineLength+m_LineMargin : for the digit width 342 // m_LineMargin : after the digit 343 // = m_LineMargin*4 + m_LineLength 344 const int Height = CurrentSize.GetHeight(); 345 346 if ((Height * 0.075) < 1) 347 m_LineMargin = 1; 348 else 349 m_LineMargin = (int)(Height * 0.075); 350 351 if ((Height * 0.275) < 1) 352 m_LineLength = 1; 353 else 354 m_LineLength = (int)(Height * 0.275); 355 356 m_LineWidth = m_LineMargin; 357 358 m_DigitMargin = m_LineMargin * 4; 359 360 // Count the number of characters in the string; '.' characters are not 361 // included because they do not take up space in the display 362 int count = 0; 363 for (unsigned int i = 0; i < m_Value.Len(); i++) 364 if (m_Value.GetChar(i) != '.') 365 count++; 366 const int ValueWidth = (m_LineLength + m_DigitMargin) * count; 367 const int ClientWidth = CurrentSize.GetWidth(); 368 369 switch (m_Alignment) 370 { 371 case wxLED_ALIGN_LEFT : 372 m_LeftStartPos = m_LineMargin; 373 break; 374 case wxLED_ALIGN_RIGHT : 375 m_LeftStartPos = ClientWidth - ValueWidth - m_LineMargin; 376 break; 377 case wxLED_ALIGN_CENTER : 378 m_LeftStartPos = (ClientWidth - ValueWidth) / 2; 379 break; 380 default : 381 wxFAIL_MSG(wxT("Unknown alignent value for wxLEDNumberCtrl.")); 382 break; 383 } 384} 385 386 387void wxLEDNumberCtrl::OnSize(wxSizeEvent &Event) 388{ 389 RecalcInternals(Event.GetSize()); 390 391 Event.Skip(); 392} 393