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