1 /********************************************************************************
2 * *
3 * 7 - S e g m e n t D i s p l a y W i d g e t *
4 * *
5 *********************************************************************************
6 * Copyright (C) 2004,2005 by Jeroen van der Zijp. All Rights Reserved. *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU Lesser General Public *
10 * License as published by the Free Software Foundation; either *
11 * version 2.1 of the License, or (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
21 *********************************************************************************
22 * $Id: FX7Segment.cpp,v 1.14 2005/01/16 16:06:06 fox Exp $ *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "FXHash.h"
28 #include "FXThread.h"
29 #include "FXStream.h"
30 #include "FXString.h"
31 #include "FXSize.h"
32 #include "FXPoint.h"
33 #include "FXRectangle.h"
34 #include "FXSettings.h"
35 #include "FXRegistry.h"
36 #include "FXApp.h"
37 #include "FXDCWindow.h"
38 #include "FXFrame.h"
39 #include "FX7Segment.h"
40
41
42 /*
43 Notes:
44 - Emulate old LED or LCD Display.
45 - Segment numbering:
46
47 01
48 -----
49 02 | | 04 ++
50 | 08 | ++
51 -----
52 10 | | 20 ++ 100
53 | | ++
54 ----- o 80
55 40
56
57 - Still to add: decimal point, a few more letters.
58 - Perhaps some control over cell spacing.
59 */
60
61
62 #define JUSTIFY_MASK (JUSTIFY_HZ_APART|JUSTIFY_VT_APART)
63 #define SEVENSEGMENT_MASK (SEVENSEGMENT_NORMAL|SEVENSEGMENT_SHADOW)
64
65
66 using namespace FX;
67
68 /*******************************************************************************/
69
70 namespace FX {
71
72
73 const FXuint segm[]={
74 0x0000, // 20 SPACE
75 0x0000, // 21 !
76 0x0000, // 22 "
77 0x0000, // 23 #
78 0x0000, // 24 $
79 0x0000, // 25 %
80 0x0000, // 26 &
81 0x0000, // 27 '
82 0x0053, // 28 (
83 0x0065, // 29 )
84 0x0000, // 2A *
85 0x0000, // 2B +
86 0x0080, // 2C ,
87 0x0008, // 2D -
88 0x0080, // 2E .
89 0x0000, // 2F /
90
91 0x0077, // 30 0
92 0x0024, // 31 1
93 0x005d, // 32 2
94 0x006d, // 33 3
95 0x002e, // 34 4
96 0x006b, // 35 5
97 0x007b, // 36 6
98 0x0025, // 37 7
99 0x007f, // 38 8
100 0x006f, // 39 9
101 0x0100, // 3A :
102 0x0100, // 3B ;
103 0x0000, // 3C <
104 0x0048, // 3D =
105 0x0000, // 3E >
106 0x0000, // 3F ?
107
108 0x0000, // 40 @
109 0x003F, // 41 A
110 0x007A, // 42 B
111 0x0058, // 43 C
112 0x007C, // 44 D
113 0x005B, // 45 E
114 0x001B, // 46 F
115 0x0073, // 47 G
116 0x003A, // 48 H
117 0x0024, // 49 I
118 0x0064, // 4A J
119 0x001A, // 4B K
120 0x0052, // 4C L
121 0x0037, // 4D M
122 0x0038, // 4E N
123 0x0078, // 4F O
124
125 0x001F, // 50 P
126 0x002F, // 51 Q
127 0x0018, // 52 R
128 0x006B, // 53 S
129 0x005A, // 54 T
130 0x0070, // 55 U
131 0x0076, // 56 V
132 0x0076, // 57 W
133 0x0049, // 58 X
134 0x006E, // 59 Y
135 0x005d, // 5A Z
136 0x0053, // 5B [
137 0x0000, // 5C
138 0x0065, // 5D ]
139 0x0000, // 5E ^
140 0x0040, // 5F _
141
142 0x0000, // 60 `
143 0x003F, // 61 a
144 0x007A, // 62 b
145 0x0058, // 63 c
146 0x007C, // 64 d
147 0x005b, // 65 e
148 0x001B, // 66 f
149 0x0073, // 67 g
150 0x003A, // 68 h
151 0x0024, // 69 i
152 0x0064, // 6A j
153 0x001A, // 6B k
154 0x0052, // 6C l
155 0x0037, // 6D m
156 0x0038, // 6E n
157 0x0078, // 6F o
158
159 0x001F, // 70 p
160 0x002F, // 71 q
161 0x0018, // 72 r
162 0x006B, // 73 s
163 0x005A, // 74 t
164 0x0070, // 75 u
165 0x0076, // 76 v
166 0x0076, // 77 w
167 0x0049, // 78 x
168 0x006E, // 79 y
169 0x005d, // 7A z
170 0x0053, // 7B {
171 0x0024, // 7C |
172 0x0065, // 7D }
173 0x0001, // 7E ~
174 };
175
176
177 // map
178 FXDEFMAP(FX7Segment) FX7SegmentMap[]={
179 FXMAPFUNC(SEL_PAINT,0,FX7Segment::onPaint),
180 FXMAPFUNC(SEL_COMMAND,FX7Segment::ID_SETVALUE,FX7Segment::onCmdSetValue),
181 FXMAPFUNC(SEL_COMMAND,FX7Segment::ID_SETINTVALUE,FX7Segment::onCmdSetIntValue),
182 FXMAPFUNC(SEL_COMMAND,FX7Segment::ID_SETREALVALUE,FX7Segment::onCmdSetRealValue),
183 FXMAPFUNC(SEL_COMMAND,FX7Segment::ID_SETSTRINGVALUE,FX7Segment::onCmdSetStringValue),
184 FXMAPFUNC(SEL_COMMAND,FX7Segment::ID_GETINTVALUE,FX7Segment::onCmdGetIntValue),
185 FXMAPFUNC(SEL_COMMAND,FX7Segment::ID_GETREALVALUE,FX7Segment::onCmdGetRealValue),
186 FXMAPFUNC(SEL_COMMAND,FX7Segment::ID_GETSTRINGVALUE,FX7Segment::onCmdGetStringValue),
187 };
188
189
FXIMPLEMENT(FX7Segment,FXFrame,FX7SegmentMap,ARRAYNUMBER (FX7SegmentMap))190 FXIMPLEMENT(FX7Segment,FXFrame,FX7SegmentMap,ARRAYNUMBER(FX7SegmentMap))
191
192
193 // For serialization
194 FX7Segment::FX7Segment(){
195 flags|=FLAG_ENABLED;
196 textColor=0;
197 thickness=3;
198 cellwidth=12;
199 cellheight=18;
200 }
201
202
203 // Construct 7 segment display
FX7Segment(FXComposite * p,const FXString & text,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb)204 FX7Segment::FX7Segment(FXComposite* p,const FXString& text,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb):FXFrame(p,opts,x,y,w,h,pl,pr,pt,pb),label(text){
205 flags|=FLAG_ENABLED;
206 textColor=getApp()->getForeColor();
207 thickness=3;
208 cellwidth=12;
209 cellheight=18;
210 }
211
212
213 // Get default width
getDefaultWidth()214 FXint FX7Segment::getDefaultWidth(){
215 register FXint w=(cellwidth+2)*label.length();
216 if(label.length()) w-=2;
217 return padleft+padright+(border<<1)+w;
218 }
219
220
221 // Get default height
getDefaultHeight()222 FXint FX7Segment::getDefaultHeight(){
223 return padtop+padbottom+(border<<1)+cellheight;
224 }
225
226
227 // Update value from a message
onCmdSetValue(FXObject *,FXSelector,void * ptr)228 long FX7Segment::onCmdSetValue(FXObject*,FXSelector,void *ptr){
229 setText((const FXchar*)ptr);
230 return 1;
231 }
232
233
234 // Get value as int
onCmdGetIntValue(FXObject *,FXSelector,void * ptr)235 long FX7Segment::onCmdGetIntValue(FXObject*,FXSelector,void* ptr){
236 *((FXint*)ptr)=FXIntVal(label);
237 return 1;
238 }
239
240
241 // Set value from int
onCmdSetIntValue(FXObject *,FXSelector,void * ptr)242 long FX7Segment::onCmdSetIntValue(FXObject*,FXSelector,void *ptr){
243 setText(FXStringVal(*((FXint*)ptr)));
244 return 1;
245 }
246
247
248 // Get value as double
onCmdGetRealValue(FXObject *,FXSelector,void * ptr)249 long FX7Segment::onCmdGetRealValue(FXObject*,FXSelector,void* ptr){
250 *((FXdouble*)ptr)=FXDoubleVal(label);
251 return 1;
252 }
253
254
255 // Set value from double
onCmdSetRealValue(FXObject *,FXSelector,void * ptr)256 long FX7Segment::onCmdSetRealValue(FXObject*,FXSelector,void* ptr){
257 setText(FXStringVal(*((FXdouble*)ptr)));
258 return 1;
259 }
260
261
262 // Get value as string
onCmdGetStringValue(FXObject *,FXSelector,void * ptr)263 long FX7Segment::onCmdGetStringValue(FXObject*,FXSelector,void* ptr){
264 *((FXint*)ptr)=FXIntVal(label);
265 return 1;
266 }
267
268
269 // Set value from string
onCmdSetStringValue(FXObject *,FXSelector,void * ptr)270 long FX7Segment::onCmdSetStringValue(FXObject*,FXSelector,void *ptr){
271 setText(*((FXString*)ptr));
272 return 1;
273 }
274
275
276 // draw/redraw object
onPaint(FXObject *,FXSelector,void * ptr)277 long FX7Segment::onPaint(FXObject*,FXSelector,void *ptr){
278 register FXEvent *event=(FXEvent*)ptr;
279 register FXint tx,ty,tw,ch,cw;
280 FXDCWindow dc(this,event);
281
282 // Draw frame
283 drawFrame(dc,0,0,width,height);
284
285 // Draw background
286 dc.setForeground(backColor);
287 dc.fillRectangle(border,border,width-(border<<1),height-(border<<1));
288
289 // Non empty
290 if(label.length()){
291
292 cw=cellwidth;
293 ch=cellheight;
294
295 tw=label.length()*(cw+2);
296 if(label.length()) tw-=2;
297
298 // Justify in x
299 if((options&JUSTIFY_LEFT) && (options&JUSTIFY_RIGHT)){ // FIXME not good yet
300 tx=border+padleft;
301 tw=width-padleft-padright-(border<<1);
302 cw=tw/label.length();
303 }
304 else if(options&JUSTIFY_LEFT){
305 tx=border+padleft;
306 }
307 else if(options&JUSTIFY_RIGHT){
308 tx=width-padright-border-tw;
309 }
310 else{
311 tx=border+padleft+(width-padleft-padright-(border<<1)-tw)/2;
312 }
313
314 // Justify in y
315 if((options&JUSTIFY_TOP) && (options&JUSTIFY_BOTTOM)){
316 ty=border+padtop;
317 ch=height-padbottom-padtop-(border<<1);
318 }
319 else if(options&JUSTIFY_TOP){
320 ty=border+padtop;
321 }
322 else if(options&JUSTIFY_BOTTOM){
323 ty=height-padbottom-border-ch;
324 }
325 else{
326 ty=border+padtop+(height-padbottom-padtop-(border<<1)-ch)/2;
327 }
328
329 // Draw cells with shadow
330 if(options&SEVENSEGMENT_SHADOW){
331 dc.setForeground(shadowColor);
332 drawCells(dc,tx+1,ty+1,cw,ch);
333 }
334
335 // Draw cells normally
336 dc.setForeground(textColor);
337 drawCells(dc,tx,ty,cw,ch);
338 }
339 return 1;
340 }
341
342
343 // Draw cells
drawCells(FXDCWindow & dc,FXint x,FXint y,FXint cw,FXint ch)344 void FX7Segment::drawCells(FXDCWindow &dc,FXint x,FXint y,FXint cw,FXint ch){
345 register FXint c,t;
346 for(c=0; c<label.length(); c++){
347 t=(FXuchar)label[c];
348 if(' '<=t && t<127){
349 //drawSegments(dc,tx+(c*tw+label.length()-1)/label.length(),ty,cw,th,segm[ch-' ']);
350 drawSegments(dc,x+c*(cellwidth+2),y,cw,ch,segm[t-' ']);
351 }
352 }
353 }
354
355
356 // Draw segments
drawSegments(FXDCWindow & dc,FXint x,FXint y,FXint w,FXint h,FXuint segments)357 void FX7Segment::drawSegments(FXDCWindow &dc,FXint x,FXint y,FXint w,FXint h,FXuint segments){
358 FXPoint points[6];
359 if(segments&0x02){ // Upper left
360 points[0].x=x;
361 points[0].y=y;
362 points[1].x=x+thickness;
363 points[1].y=y+thickness;
364 points[2].x=x+thickness;
365 points[2].y=y+(h>>1)-(thickness>>1)-1;
366 points[3].x=x;
367 points[3].y=y+(h>>1);
368 dc.fillPolygon(points,4);
369 }
370 if(segments&0x04){ // Upper right
371 points[0].x=x+w;
372 points[0].y=y;
373 points[1].x=x+w;
374 points[1].y=y+(h>>1);
375 points[2].x=x+w-thickness;
376 points[2].y=y+(h>>1)-(thickness>>1)-1;
377 points[3].x=x+w-thickness;
378 points[3].y=y+thickness;
379 dc.fillPolygon(points,4);
380 }
381 if(segments&0x10){ // Lower left
382 points[0].x=x;
383 points[0].y=y+(h>>1);
384 points[1].x=x+thickness;
385 points[1].y=y+(h>>1)-(thickness>>1)+thickness;
386 points[2].x=x+thickness;
387 points[2].y=y+h-thickness-1;
388 points[3].x=x;
389 points[3].y=y+h-1;
390 dc.fillPolygon(points,4);
391 }
392 if(segments&0x20){ // Lower right
393 points[0].x=x+w;
394 points[0].y=y+(h>>1);
395 points[1].x=x+w;
396 points[1].y=y+h-1;
397 points[2].x=x+w-thickness;
398 points[2].y=y+h-thickness-1;
399 points[3].x=x+w-thickness;
400 points[3].y=y+(h>>1)-(thickness>>1)+thickness;
401 dc.fillPolygon(points,4);
402 }
403 if(segments&0x01){ // Top
404 points[0].x=x+1;
405 points[0].y=y;
406 points[1].x=x+w-1;
407 points[1].y=y;
408 points[2].x=x+w-thickness-1;
409 points[2].y=y+thickness;
410 points[3].x=x+thickness+1;
411 points[3].y=y+thickness;
412 dc.fillPolygon(points,4);
413 }
414 if(segments&0x40){ // Bottom
415 points[0].x=x;
416 points[0].y=y+h;
417 points[1].x=x+w;
418 points[1].y=y+h;
419 points[2].x=x+w-thickness;
420 points[2].y=y+h-thickness;
421 points[3].x=x+thickness;
422 points[3].y=y+h-thickness;
423 dc.fillPolygon(points,4);
424 }
425 if(segments&0x08){ // Middle
426 points[0].x=x+1;
427 points[0].y=y+(h>>1);
428 points[1].x=x+thickness;
429 points[1].y=y+(h>>1)-(thickness>>1);
430 points[2].x=x+w-thickness;
431 points[2].y=y+(h>>1)-(thickness>>1);
432 points[3].x=x+w-1;
433 points[3].y=y+(h>>1);
434 points[4].x=x+w-thickness-2;
435 points[4].y=y+(h>>1)-(thickness>>1)+thickness;
436 points[5].x=x+thickness+1;
437 points[5].y=y+(h>>1)-(thickness>>1)+thickness;
438 dc.fillPolygon(points,6);
439 }
440 if(segments&128){ // Decimal
441 }
442 if(segments&256){ // Colon
443 dc.fillRectangle(x+(w>>1)-(thickness>>1)-1,y+(h>>1)-(thickness>>1)-thickness-1,thickness,thickness);
444 dc.fillRectangle(x+(w>>1)-(thickness>>1)-1,y+(h>>1)-(thickness>>1)+thickness+1,thickness,thickness);
445 }
446 }
447
448
449 // Change text
setText(const FXString & text)450 void FX7Segment::setText(const FXString& text){
451 if(label!=text){
452 if(label.length()!=text.length()) recalc();
453 label=text;
454 update();
455 }
456 }
457
458
459 // Set text color
setTextColor(FXColor clr)460 void FX7Segment::setTextColor(FXColor clr){
461 if(textColor!=clr){
462 textColor=clr;
463 update();
464 }
465 }
466
467
468 // Get/set cell width
setCellWidth(FXint w)469 void FX7Segment::setCellWidth(FXint w){
470 if(cellwidth!=w){
471 cellwidth=w;
472 recalc();
473 update();
474 }
475 }
476
477
478 // Get/set cell height
setCellHeight(FXint h)479 void FX7Segment::setCellHeight(FXint h){
480 if(cellheight!=h){
481 cellheight=h;
482 recalc();
483 update();
484 }
485 }
486
487
488 // set segment thickness
setThickness(FXint t)489 void FX7Segment::setThickness(FXint t){
490 if(t<1) t=1;
491 if(!(t&1)) t|=1;
492 if(thickness!=t){
493 thickness=t;
494 recalc();
495 update();
496 }
497 }
498
499
500 // Change 7 segment style
set7SegmentStyle(FXuint style)501 void FX7Segment::set7SegmentStyle(FXuint style){
502 FXuint opts=(options&~SEVENSEGMENT_MASK) | (style&SEVENSEGMENT_MASK);
503 if(options!=opts){
504 options=opts;
505 update();
506 }
507 }
508
509
510 // Get 7 segment
get7SegmentStyle() const511 FXuint FX7Segment::get7SegmentStyle() const {
512 return (options&SEVENSEGMENT_MASK);
513 }
514
515
516 // Set text justify style
setJustify(FXuint style)517 void FX7Segment::setJustify(FXuint style){
518 FXuint opts=(options&~JUSTIFY_MASK) | (style&JUSTIFY_MASK);
519 if(options!=opts){
520 options=opts;
521 update();
522 }
523 }
524
525
526 // Get text justify style
getJustify() const527 FXuint FX7Segment::getJustify() const {
528 return (options&JUSTIFY_MASK);
529 }
530
531
532 // Save object to stream
save(FXStream & store) const533 void FX7Segment::save(FXStream &store) const {
534 FXFrame::save(store);
535 store << label;
536 store << textColor;
537 store << thickness;
538 store << cellwidth;
539 store << cellheight;
540 }
541
542
543 // Load object from stream
load(FXStream & store)544 void FX7Segment::load(FXStream &store) {
545 FXFrame::load(store);
546 store >> label;
547 store >> textColor;
548 store >> thickness;
549 store >> cellwidth;
550 store >> cellheight;
551 }
552
553 }
554