| 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 | |
| 33 | const int LINE1 = 1; |
| 34 | const int LINE2 = 2; |
| 35 | const int LINE3 = 4; |
| 36 | const int LINE4 = 8; |
| 37 | const int LINE5 = 16; |
| 38 | const int LINE6 = 32; |
| 39 | const int LINE7 = 64; |
| 40 | const int DECIMALSIGN = 128; |
| 41 | |
| 42 | const int DIGIT0 = LINE1 | LINE2 | LINE3 | LINE4 | LINE5 | LINE6; |
| 43 | const int DIGIT1 = LINE2 | LINE3; |
| 44 | const int DIGIT2 = LINE1 | LINE2 | LINE4 | LINE5 | LINE7; |
| 45 | const int DIGIT3 = LINE1 | LINE2 | LINE3 | LINE4 | LINE7; |
| 46 | const int DIGIT4 = LINE2 | LINE3 | LINE6 | LINE7; |
| 47 | const int DIGIT5 = LINE1 | LINE3 | LINE4 | LINE6 | LINE7; |
| 48 | const int DIGIT6 = LINE1 | LINE3 | LINE4 | LINE5 | LINE6 | LINE7; |
| 49 | const int DIGIT7 = LINE1 | LINE2 | LINE3; |
| 50 | const int DIGIT8 = LINE1 | LINE2 | LINE3 | LINE4 | LINE5 | LINE6 | LINE7; |
| 51 | const int DIGIT9 = LINE1 | LINE2 | LINE3 | LINE6 | LINE7; |
| 52 | const int DASH = LINE7; |
| 53 | |
| 54 | const int DIGITALL = -1; |
| 55 | |
| 56 | // ============================================================================ |
| 57 | // wxLEDNumberCtrl class implementation |
| 58 | // ============================================================================ |
| 59 | |
| 60 | wxLEDNumberCtrl::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 | |
| 72 | wxLEDNumberCtrl::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 | |
| 87 | bool 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 | |
| 105 | void 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 | |
| 118 | void 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 | |
| 130 | void 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 | |
| 154 | BEGIN_EVENT_TABLE(wxLEDNumberCtrl, wxControl) |
| 155 | EVT_ERASE_BACKGROUND(wxLEDNumberCtrl::OnEraseBackground) |
| 156 | EVT_PAINT(wxLEDNumberCtrl::OnPaint) |
| 157 | EVT_SIZE(wxLEDNumberCtrl::OnSize) |
| 158 | END_EVENT_TABLE() |
| 159 | |
| 160 | |
| 161 | void wxLEDNumberCtrl::OnEraseBackground(wxEraseEvent &WXUNUSED(event)) |
| 162 | { |
| 163 | } |
| 164 | |
| 165 | |
| 166 | void 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 | |
| 249 | void 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 | |
| 320 | void 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 | |
| 387 | void wxLEDNumberCtrl::OnSize(wxSizeEvent &Event) |
| 388 | { |
| 389 | RecalcInternals(Event.GetSize()); |
| 390 | |
| 391 | Event.Skip(); |
| 392 | } |