/
LinearMeter.pl
executable file
·234 lines (232 loc) · 7.58 KB
/
LinearMeter.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#! /home/pete/CitrusPerl/perl/bin/perl
#
# LinearMeter.pl
# This script draws a simulated linear panel meter.
# Meter can be configured to be verticle or horizontal
#
# Move mouse up/down to change the displayed value on verticle meter
# (or left/right if reconfigured for horizontal meter)
#
# Written in wxPerl. Tested on Citrus Perl 5.16 with wxWidgets 2.8.x.
# Ported by: James M. Lynes. Jr.
# Last Modified Date: January 21, 2013
#
# Adapted from LinearMeter.cpp by Marco Cavallini
# based in part(mostly) on the work of
# the KWIC project (http://www.koansoftware.com/kwic/index.htm).
# Referenced on pg 596 of the "Wx Book" -
# "Cross-Platform GUI Programming with wxWidgets", Smart, Hock, & Csomor
#
# Added high-limit/alarm processing- red/green color change
# Added animation
# Added label display at bottom of meter
# Set an initial value, high-limit, and tic array
#
#
use 5.010;
use strict;
use warnings;
use Wx qw(:everything :allclasses);
use Wx::Event qw( EVT_PAINT EVT_ERASE_BACKGROUND EVT_MOTION );
#
# Configuration Data ------------------------------------------------------------------
#
my $MeterHeight = 400; # Swap these for horizontal display
my $MeterWidth = 100;
my $ActiveBar = wxGREEN;
my $PassiveBar = wxWHITE;
my $ValueColour = wxBLACK;
my $BorderColour = wxBLUE;
my $LimitColour = wxBLACK;
my $AlarmLimitColour = wxRED;
my $TagsColour = wxBLACK;
my $ScaledValue = 0;
my $RealVal = 0;
my $Limit = 75; # High-Limit setpoint
my @TagsVal;
my $TagsNum = 0;
my $StartTag = 0;
my $NumTags = 10;
my $IncTag = 10;
my $Max = 100; # Span
my $Min = 0;
my $ramp = 45; # Initial value displayed
my $lastpos = 0; # Last mouse position
my $DirHorizFlag = 0; # 0-Verticle, 1-Horizontal
my $ShowCurrent = 1;
my $ShowLimits = 0;
my $ShowLabel = 1;
my $Font = Wx::Font->new(10, wxFONTFAMILY_SWISS, wxNORMAL, wxNORMAL);
my $Label = "Temp degC";
#
# Main Application -----------------------------------------------------------------------
#
my $app = Wx::SimpleApp->new;
my $frame = Wx::Frame->new(undef, -1, "",
[600,200], [$MeterWidth, $MeterHeight]);
EVT_PAINT( $frame, \&onPaint );
EVT_ERASE_BACKGROUND( $frame, \&onEraseBackground );
EVT_MOTION( $frame, \&onMotion );
$frame->Show;
$app->MainLoop;
#
# Dismiss an erase background event -----------------------------------------------------
#
sub onEraseBackground {
my($self, $event) = @_;
$event->Skip();
}
#
# Paint the simulated LCD Display ----------------------------------------------------------
#
sub onPaint {
my($self, $event) = @_;
my $dc = Wx::PaintDC->new($self);
my $memdc = Wx::MemoryDC->new();
$memdc->SelectObject(Wx::Bitmap->new($MeterWidth, $MeterHeight));
my($w, $h) = $memdc->GetSizeWH();
my $brush = Wx::Brush->new($PassiveBar, wxSOLID);
$memdc->SetBackground($brush);
$memdc->Clear();
SetUp($memdc); # Set the initial value and tic marks
my $pen = Wx::Pen->new($BorderColour, 2, wxSOLID);
$memdc->SetPen($pen);
$memdc->DrawRectangle(0, 0, $w, $h);
$pen = Wx::Pen->new($BorderColour, 2, wxSOLID);
$memdc->SetPen($pen);
$brush = Wx::Brush->new($ActiveBar, wxSOLID);
if($RealVal > $Limit) {$brush = Wx::Brush->new($AlarmLimitColour, wxSOLID)}
$memdc->SetBrush($brush);
my $yPoint;
my $rectHeight;
if($DirHorizFlag) { # Horizontal Orientation
$memdc->DrawRectangle(1, 1, $ScaledValue, $h-2);
}
else { # Verticle Orientation
$yPoint = $h - $ScaledValue;
if($ScaledValue == 0) {
$rectHeight = $ScaledValue;
}
else {
if($RealVal == $Max) {
$rectHeight = $ScaledValue;
$yPoint -= 1;
}
else {
$rectHeight = $ScaledValue - 1;
}
$memdc->DrawRectangle(1, $yPoint, $w-2, $rectHeight);
}
}
if($ShowCurrent) {DrawCurrent($memdc)}
if($ShowLimits) {DrawLimits($memdc)}
if($TagsNum > 0) {DrawTags($memdc)}
if($ShowLabel) {DrawLabel($memdc)}
$dc->Blit(0, 0, $w, $h, $memdc, 0, 0);
}
sub onMotion { # Change the setpoint value and redraw
my($self, $event) = @_;
my $y = $event->GetPosition->y; # Current mouse position, swap to (x) for horz
if($y > $lastpos) {$ramp -= 1; $lastpos = $y} # Mouse down, decrement needle, swap (x/+=)for horz
if($y < $lastpos) {$ramp += 1; $lastpos = $y} # Mouse up, increment needle, swap(x/-=) for horz
if($ramp >= $Max) {$ramp = $Max;} # Clamp to max range
if($ramp <= $Min) {$ramp = $Min;} # Clamp to min range
$self->Refresh;
$self->Update;
}
sub SetUp { # Set and update the displayed value
my($dc) = @_;
SetValue($dc, $ramp);
if($TagsNum == 0) { # Build tic marks 1st time through
for($StartTag..$NumTags) { # Quick and dirty
AddTag($_ * $IncTag);
}
}
}
sub DrawCurrent { # Draw the current value as text
my($dc) = @_;
my($w, $h) = $dc->GetSizeWH();
my $valuetext = sprintf("%d", $RealVal);
my ($tw, $th) = $dc->GetTextExtent($valuetext);
$dc->SetTextForeground($ValueColour);
$dc->DrawText($valuetext, $w/2-$tw/2, $h/2-$th/2);
}
sub DrawLimits { # Draw Min and Max as text
my($dc) = @_;
my($w, $h) = $dc->GetSizeWH();
$dc->SetFont($Font);
$dc->SetTextForeground($LimitColour);
if($DirHorizFlag) {
my $valuetext = sprintf("%d", $Min);
my ($tw, $th) = $dc->GetTextExtent($valuetext);
$dc->DrawText($valuetext, 5, $h/2-$th/2);
$valuetext = sprintf("%d", $Max);
($tw, $th) = $dc->GetTextExtent($valuetext);
$dc->DrawText($valuetext, $w-$tw-5, $h/2-$th/2);
}
else {
my $valuetext = sprintf("%d", $Min);
my ($tw, $th) = $dc->GetTextExtent($valuetext);
$dc->DrawText($valuetext, $w/2-$tw/2, $h-$th-5);
$valuetext = sprintf("%d", $Max);
($tw, $th) = $dc->GetTextExtent($valuetext);
$dc->DrawText($valuetext, $w/2-$tw/2, 5);
}
}
sub DrawTags { # Draw tic marks and labels
my($dc, $Value) = @_;
my($w, $h) = $dc->GetSizeWH();
my $tcoeff;
if($DirHorizFlag) {
$tcoeff = ($w-2)/($Max-$Min);
}
else {
$tcoeff = ($h-2)/($Max-$Min);
}
my $pen = Wx::Pen->new($TagsColour, 1, wxSOLID);
$dc->SetPen($pen);
my $brush = Wx::Brush->new($TagsColour, wxSOLID);
$dc->SetBrush($brush);
$dc->SetTextForeground($TagsColour);
my $tag = 0;
while($tag < $TagsNum) {
my $scalval = ($TagsVal[$tag]-$Min) * $tcoeff;
my $textvalue = sprintf("%d", $TagsVal[$tag]);
if($DirHorizFlag) {
$dc->DrawLine($scalval+1, $h-2, $scalval+1, $h-10);
my($tw, $th) = $dc->GetTextExtent($textvalue);
$dc->DrawText($textvalue, $scalval+1-($tw/2), $h-10-$th);
}
else {
$dc->DrawLine($w-2, $h-$scalval+1, $w-10, $h-$scalval);
my($tw, $th) = $dc->GetTextExtent($textvalue);
$dc->DrawText($textvalue, $w-10-$tw, $h-$scalval-($th/2));
}
$tag++;
}
}
sub AddTag { # Add a tic mark to array
my($val) = @_;
push(@TagsVal, $val);
$TagsNum = @TagsVal;
}
sub SetValue { # Scale the value for display
my($dc, $Value) = @_;
my($w, $h) = $dc->GetSizeWH();
my $coeff;
if($DirHorizFlag) {
$coeff = ($w-2)/($Max-$Min);
}
else {
$coeff = ($h-2)/($Max-$Min);
}
$ScaledValue = (($Value-$Min) * $coeff);
$RealVal = $Value;
}
sub DrawLabel { # Draw a label at bottom of meter
my($dc) = @_;
my($w, $h) = $dc->GetSizeWH();
my @te = $dc->GetTextExtent($Label);
my $x = ($w-$te[0])/2;
$dc->DrawText($Label, $x, $h-20);
}