File Coverage

blib/lib/Tk/SevenSegmentDisplay.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             #*** SevenSegmentDisplay.pm ***#
2             # Copyright (C) 2009 by Torsten Knorr
3             # create-soft@freenet.de
4             # All rights reserved!
5             #-------------------------------------------------
6             package Tk::SevenSegmentDisplay;
7             #-------------------------------------------------
8 1     1   38765 use strict;
  1         2  
  1         55  
9 1     1   484 use Tk::Frame;
  0            
  0            
10             #-------------------------------------------------
11             use constant DIGITWIDTH => 33;
12             use constant COLONWIDTH => 6;
13             use constant POINTWIDTH => 6;
14             use constant DIGITHEIGHT => 58;
15             use constant SEGMENTSDIGIT => 7;
16             use constant SEGMENTSCOLON => 2;
17             use constant POINTSSEGMENT => 12;
18             use constant POINTSCOLON => 8;
19             use constant POINTSDOT => 8;
20             #-------------------------------------------------
21             sub _PT_SEGMENTS
22             {
23             [[9, 0, 24, 0, 28, 4, 24, 8, 9, 8, 5, 4],
24             [4, 5, 8, 9, 8, 24, 4, 28, 0, 24, 0, 9],
25             [29, 5, 33, 9, 33, 24, 29, 28, 25, 24, 25, 9],
26             [9, 25, 24, 25, 28, 29, 24, 33, 9, 33, 5, 29],
27             [4, 30, 8, 34, 8, 49, 4, 53, 0, 49, 0, 34],
28             [29, 30, 33, 34, 33, 49, 29, 53, 25, 49, 25, 34],
29             [9, 50, 24, 50, 28, 54, 24, 58, 9, 58, 5, 54]];
30             }
31             #-------------------------------------------------
32             sub _PT_COLON
33             {
34             [[3, 26, 6, 29, 3, 32, 0, 29],
35             [3, 51, 6, 54, 3, 57, 0, 54]];
36             }
37             #-------------------------------------------------
38             sub _PT_DOT
39             {
40             [0, 55, 3, 52, 6, 55, 3, 58];
41             }
42             #-------------------------------------------------
43             my @_combinations =
44             (
45             # 0
46             [1, 1, 1, 0, 1, 1, 1],
47             # 1
48             [0, 0, 1, 0, 0, 1, 0],
49             # 2
50             [1, 0, 1, 1, 1, 0, 1],
51             # 3
52             [1, 0, 1, 1, 0, 1, 1],
53             # 4
54             [0, 1, 1, 1, 0, 1, 0],
55             # 5
56             [1, 1, 0, 1, 0, 1, 1],
57             # 6
58             [1, 1, 0, 1, 1, 1, 1],
59             # 7
60             [1, 0, 1, 0, 0, 1, 0],
61             # 8
62             [1, 1, 1, 1, 1, 1, 1],
63             # 9
64             [1, 1, 1, 1, 0, 1, 1],
65             # - = 10
66             [0, 0, 0, 1, 0, 0, 0],
67             # E = 11
68             [1, 1, 0, 1, 1, 0, 1],
69             # space = 12
70             [0, 0, 0, 0, 0, 0, 0]
71             );
72             #-------------------------------------------------
73             @Tk::SevenSegmentDisplay::ISA = qw(Tk::Frame);
74             $Tk::SevenSegmentDisplay::VERSION = '0.01';
75             #-------------------------------------------------
76             Construct Tk::Widget 'SevenSegmentDisplay';
77             #-------------------------------------------------
78             sub Populate
79             {
80             require Tk::Canvas;
81             my ($self, $rh_args) = @_;
82             $self->SUPER::Populate($rh_args);
83             $self->{_seven_segment_display} = $self->Canvas()->grid();
84             $self->Advertise('SevenSegmentDisplay' => $self->{_seven_segment_display});
85             $self->Delegates(DEFAULT => $self->{_seven_segment_display});
86             $self->ConfigSpecs(
87             -digitwidth => [qw/METHOD digitwidth DigitWidth/, DIGITWIDTH],
88             -digitheight => [qw/METHOD digitheight DigitHeight/, DIGITHEIGHT],
89             -space => [qw/METHOD space Space/, 3],
90             -format => [qw/METHOD format Format/, 'dd.dd'],
91             -background => [qw/METHOD background Background/, '#00C800'],
92             -foreground => [qw/METHOD foreground Foreground/, '#006400'],
93             DEFAULT => [$self->{_seven_segment_display}]
94             );
95             }
96             #-------------------------------------------------
97             sub digitwidth { $_[0]->{_x_scale_factor} = $_[1] / DIGITWIDTH; }
98             sub digitheight { $_[0]->{_y_scale_factor} = $_[1] / DIGITHEIGHT; }
99             sub space { $_[0]->{_space} = $_[1]; }
100             sub format { $_[0]->{_format} = $_[1]; }
101             sub background { $_[0]->{_background} = $_[1]; }
102             sub foreground { $_[0]->{_foreground} = $_[1]; }
103             #-------------------------------------------------
104             sub CalculateDisplay
105             {
106             my ($self, %args) = @_;
107             my ($segment, $point);
108             $self->{_digits_count} = 0;
109             $self->{_colons_count} = 0;
110             $self->{_signs_count} = 0;
111             $self->{_dots_count} = 0;
112             my $x_offset = $self->{_space} + 2;
113             $self->{_digits} = [];
114             $self->{_colons} = [];
115             $self->{_signs} = [];
116             $self->{_dots} = [];
117             if($self->{_format} =~ m/^-/)
118             {
119             $self->{_signed} = 1;
120             }
121             else
122             {
123             $self->{_signed} = undef;
124             }
125             for(split(//, $self->{_format}))
126             {
127             SWITCH:
128             {
129             #-------------------------------------------------
130             /d|D/ && do
131             {
132             for($segment = 0; $segment < SEGMENTSDIGIT; $segment++)
133             {
134             for($point = 0; $point < POINTSSEGMENT; $point++)
135             {
136             $self->{_digits}[$self->{_digits_count}][$segment][$point] =
137             int(_PT_SEGMENTS->[$segment][$point] * $self->{_x_scale_factor}) + $x_offset;
138             $point++;
139             $self->{_digits}[$self->{_digits_count}][$segment][$point] =
140             int(_PT_SEGMENTS->[$segment][$point] * $self->{_y_scale_factor}) + $self->{_space} + 2;
141             }
142             }
143             $self->{_digits_count}++;
144             $x_offset += int(DIGITWIDTH * $self->{_x_scale_factor}) + $self->{_space} + 1;
145             last SWITCH;
146             };
147             #-------------------------------------------------
148             /-/ && do
149             {
150             for($point = 0; $point < POINTSSEGMENT; $point++)
151             {
152             $self->{_signs}[$self->{_signs_count}][$point] =
153             int(_PT_SEGMENTS->[3][$point] * $self->{_x_scale_factor}) + $x_offset;
154             $point++;
155             $self->{_signs}[$self->{_signs_count}][$point] =
156             int(_PT_SEGMENTS->[3][$point] * $self->{_y_scale_factor}) + $self->{_space} + 2;
157             }
158             $self->{_signs_count}++;
159             $x_offset += int(DIGITWIDTH * $self->{_x_scale_factor}) + $self->{_space} + 1;
160             last SWITCH;
161             };
162             #-------------------------------------------------
163             /:/ && do
164             {
165             for($segment = 0; $segment < SEGMENTSCOLON; $segment++)
166             {
167             for($point = 0; $point < POINTSCOLON; $point++)
168             {
169             $self->{_colons}[$self->{_colons_count}][$segment][$point] =
170             int(_PT_COLON->[$segment][$point] * $self->{_x_scale_factor}) + $x_offset;
171             $point++;
172             $self->{_colons}[$self->{_colons_count}][$segment][$point] =
173             int(_PT_COLON->[$segment][$point] * $self->{_y_scale_factor}) + $self->{_space} + 2;
174             }
175             }
176             $self->{_colons_count}++;
177             $x_offset += int(COLONWIDTH * $self->{_x_scale_factor}) + $self->{_space} + 1;
178             last SWITCH;
179             };
180             #-------------------------------------------------
181             /\./ && do
182             {
183             for($point = 0; $point < POINTSDOT; $point++)
184             {
185             $self->{_dots}[$self->{_dots_count}][$point] =
186             int(_PT_DOT->[$point] * $self->{_x_scale_factor}) + $x_offset;
187             $point++;
188             $self->{_dots}[$self->{_dots_count}][$point] =
189             int(_PT_DOT->[$point] * $self->{_y_scale_factor}) + $self->{_space} + 2;
190             }
191             $self->{_dots_count}++;
192             $x_offset += int(POINTWIDTH * $self->{_x_scale_factor}) + $self->{_space} + 1;
193             last SWITCH;
194             };
195             #-------------------------------------------------
196             }
197             }
198             $self->{_values}[$_] = 8 for(0..$#{$self->{_digits}});
199             $self->{_rect_bottom} = int(DIGITHEIGHT * $self->{_y_scale_factor}) + 2 * $self->{_space} + 1;
200             $self->{_rect_right} = $x_offset - 2;
201             $self->{_seven_segment_display}->configure(
202             -width => $self->{_rect_right},
203             -height => $self->{_rect_bottom},
204             -background => $self->{_background}
205             );
206             return $self->DrawNew();
207             }
208             #-------------------------------------------------
209             sub DrawNew
210             {
211             my ($self) = @_;
212             my $segment = 0;
213             $self->{_seven_segment_display}->delete('all');
214             #-------------------------------------------------
215             #draw background
216             $self->{_seven_segment_display}->createRectangle(
217             0,
218             0,
219             $self->{_rect_right},
220             $self->{_rect_bottom},
221             -fill => $self->{_background},
222             -outline => $self->{_background},
223             -tags => 'background'
224             );
225             #-------------------------------------------------
226             # draw digits
227             for(my $digit = 0; $digit < $self->{_digits_count}; $digit++)
228             {
229             for($segment = 0; $segment < SEGMENTSDIGIT; $segment++)
230             {
231             if($_combinations[$self->{_values}[$digit]][$segment])
232             {
233             $self->{_seven_segment_display}->createPolygon(
234             @{$self->{_digits}[$digit][$segment]},
235             -fill => $self->{_foreground},
236             -outline => $self->{_foreground},
237             -tags => "segment$digit$segment"
238             );
239             }
240             }
241             }
242             #-------------------------------------------------
243             # draw colons
244             for(my $colon = 0; $colon < $self->{_colons_count}; $colon++)
245             {
246             for($segment = 0; $segment < SEGMENTSCOLON; $segment++)
247             {
248             $self->{_seven_segment_display}->createPolygon(
249             @{$self->{_colons}[$colon][$segment]},
250             -fill => $self->{_foreground},
251             -outline => $self->{_foreground},
252             -tags => 'colon'
253             );
254             }
255             }
256             #-------------------------------------------------
257             # draw signs and hyphens
258             my $sign = 0;
259             if($self->{_signed})
260             {
261             $self->{_seven_segment_display}->createPolygon(
262             @{$self->{_signs}[$sign]},
263             -fill => $self->{_foreground},
264             -outline => $self->{_foreground},
265             -tags => 'sign'
266             );
267             $sign++;
268             }
269             for(; $sign < $self->{_signs_count}; $sign++)
270             {
271             $self->{_seven_segment_display}->createPolygon(
272             @{$self->{_signs}[$sign]},
273             -fill => $self->{_foreground},
274             -outline => $self->{_foreground},
275             -tags => 'hyphen'
276             );
277             }
278             #-------------------------------------------------
279             # draw dot
280             for(my $dot = 0; $dot < $self->{_dots_count}; $dot++)
281             {
282             $self->{_seven_segment_display}->createPolygon(
283             @{$self->{_dots}[$dot]},
284             -fill => $self->{_foreground},
285             -outline => $self->{_foreground},
286             -tags => 'dot'
287             );
288             }
289             #-------------------------------------------------
290             return 1;
291             }
292             #-------------------------------------------------
293             sub ChangeColor
294             {
295             my ($self) = @_;
296             my $segment;
297             #-------------------------------------------------
298             # change the colors of the digits
299             for(my $digit = 0; $digit < $self->{_digits_count}; $digit++)
300             {
301             for($segment = 0; $segment < SEGMENTSDIGIT; $segment++)
302             {
303             if($_combinations[$self->{_values}[$digit]][$segment])
304             {
305             $self->{_seven_segment_display}->itemconfigure(
306             "segment$digit$segment",
307             -fill => $self->{_foreground},
308             -outline => $self->{_foreground}
309             );
310             }
311             else
312             {
313             $self->{_seven_segment_display}->itemconfigure(
314             "segment$digit$segment",
315             -fill => $self->{_background},
316             -outline => $self->{_background}
317             );
318             }
319             }
320             }
321             #-------------------------------------------------
322             # change the color of the sign
323             if($self->{_signed})
324             {
325             if($self->{_negative})
326             {
327             $self->{_seven_segment_display}->itemconfigure(
328             'sign',
329             -fill => $self->{_foreground},
330             -outline => $self->{_foreground}
331             );
332             }
333             else
334             {
335             $self->{_seven_segment_display}->itemconfigure(
336             'sign',
337             -fill => $self->{_background},
338             -outline => $self->{_background}
339             );
340             }
341             }
342             return 1;
343             }
344             #-------------------------------------------------
345             sub ChangeSequence
346             {
347             my ($self) = @_;
348             my $segment;
349             #-------------------------------------------------
350             # change the display sequence of the digits
351             for(my $digit = 0; $digit < $self->{_digits_count}; $digit++)
352             {
353             for($segment = 0; $segment < SEGMENTSDIGIT; $segment++)
354             {
355             if($_combinations[$self->{_values}[$digit]][$segment])
356             {
357             $self->{_seven_segment_display}->raise(
358             "segment$digit$segment",
359             'background'
360             );
361             }
362             else
363             {
364             $self->{_seven_segment_display}->lower(
365             "segment$digit$segment",
366             'background'
367             );
368             }
369             }
370             }
371             #-------------------------------------------------
372             # change the display sequence of the sign
373             my $sign = 0;
374             if($self->{_signed})
375             {
376             if($self->{_negative})
377             {
378             $self->{_seven_segment_display}->raise(
379             'sign',
380             'background'
381             );
382             }
383             else
384             {
385             $self->{_seven_segment_display}->lower(
386             'sign',
387             'background'
388             );
389             }
390             }
391             return 1;
392             }
393             #-------------------------------------------------
394             sub SetValue
395             {
396             my ($self, $digit, $value) = @_;
397             return if(1 > $digit || $self->{_digits_count} < $digit);
398             return if(0 > $value || 9 < $value);
399             $digit--;
400             $self->{_values}[$digit] = int($value);
401             return 1;
402             }
403             #-------------------------------------------------
404             sub SetInt
405             {
406             my ($self, $int) = @_;
407             if(0 > $int && $self->{_signed})
408             {
409             $self->{_negative} = 1;
410             $int = abs($int);
411             }
412             else
413             {
414             $self->{_negative} = undef;
415             }
416             for(my $i = $#{$self->{_values}}, my $d = 1; $i >= 0; $i--, $d *= 10)
417             {
418             $self->{_values}[$i] = int($int / $d) % 10;
419             }
420             return 1;
421             }
422             #-------------------------------------------------
423             1;
424             #-------------------------------------------------
425             __END__