<?xml version="1.0" encoding="windows-1252"?>
<node id="1014074" title="wxPerl Simulated 7 Segment LCD Display" created="2013-01-18 10:38:01" updated="2013-01-18 10:38:01">
<type id="1042">
CUFP</type>
<author id="982107">
jmlynesjr</author>
<data>
<field name="doctext">
&lt;p&gt;Here's another C++ to wxPerl port from the "wxBook"(I know, it's a sickness...).   &lt;/p&gt;

&lt;p&gt;This one is a simulated 7 segment LCD display. Nice graphic, clever implementation. I don't claim to understand all of the logic yet. The port included some perlish updates so that it looks a little less C++ish and lots of comments that weren't in the original. See the code comments for the author credits. Several other wxIndustrial Controls are available, so I may go there next.&lt;/p&gt;

&lt;p&gt;I couldn't get this port working a year ago, but it was completed in a few days this attempt. So, some learning is taking place! :)&lt;/p&gt;

&lt;p&gt;James&lt;/p&gt;

&lt;readmore&gt;&lt;code&gt;#! /home/pete/CitrusPerl/perl/bin/perl
#
# LCDdisplay.pl
# This script draws a simulated seven segment LCD Display.
# Segments are drawn as 4 or 6 sided polygons
# The colon(:) is drawn as 2 ellipses
# For demo purposes the value to be displayed is stored in %wxGlobals{mValue}
#
# Written in wxPerl. Tested on Citrus Perl 5.16 with wxWidgets 2.8.x.
# Ported by: James M. Lynes. Jr.
# Last Modified Date: January 18, 2013
#
# Adapted from LCDWindow.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, &amp; Csomor
#
#
use 5.010;							# Using Given/When
use strict;
use warnings;
use Wx qw(:everything :allclasses);
use Wx::Event qw( EVT_PAINT EVT_SIZE );

my %wxGlobals = (						# Configuration Data
		 mSegmentLen         =&gt; 40,
		 mSegmentWidth       =&gt; 10,
		 mSpace              =&gt; 5,
		 mNumberDigits       =&gt; 6,
		 mValue		     =&gt; "12:45",		# Default string to be displayed
		 LCD_Number_Segments =&gt; 8,
		 mLightColour        =&gt; sub{Wx::Colour-&gt;new(0, 255, 0)},	# Bright green
		 mGrayColour         =&gt; sub{Wx::Colour-&gt;new(0, 64, 0)},		# Dim green
		 mDefaultColour      =&gt; sub{Wx::Colour-&gt;new(0, 0, 0)},		# Black
);

my %wxDigitData = (						# Actual string to be displayed
		value		     =&gt; "",
		comma		     =&gt; 0,			# 0=false, 1=true ? this feature
);

my %ctbl = (							# Map character to segments -
		0		     =&gt; 0x3F,			# Not defined in the 7-segment "abcdefg" format
		1		     =&gt; 0x14,
		2		     =&gt; 0x6D,			#    ***0***         Bit Numbers -654 3210
		3		     =&gt; 0x75,			#   *       *
		4		     =&gt; 0x56,			#   1       2
		5		     =&gt; 0x73,			#   *       *
		6		     =&gt; 0x7B,			#    ***6***
		7		     =&gt; 0x15,			#   *       *
		8		     =&gt; 0x7F,			#   3       4
		9		     =&gt; 0x77,			#   *       *
		A		     =&gt; 0x5F,			#    ***5***
		B		     =&gt; 0x7A,
		C		     =&gt; 0x2B,
		D		     =&gt; 0x7C,
		E		     =&gt; 0x6B,
		F		     =&gt; 0x4B,
		'-'		     =&gt; 0x40,
		'_'		     =&gt; 0x20,
		'^'		     =&gt; 0x47,			# code for degree symbol
		'='		     =&gt; 0x61,			# code for undefined symbol
		' '		     =&gt; 0x00,			# code for a space
);								# Other options could be added

#
# Main Application -----------------------------------------------------------------------
#
my $app = Wx::SimpleApp-&gt;new;
my $frame = Wx::Frame-&gt;new(undef, -1, "Simulated 7-segment LCD Display",
			   wxDefaultPosition, [400,150]);
$frame-&gt;SetBackgroundColour($wxGlobals{mDefaultColour}-&gt;());
EVT_PAINT( $frame, \&amp;onPaint );
EVT_SIZE( $frame, \&amp;onSize );
$frame-&gt;Show;
$app-&gt;MainLoop;
#
# Dismiss a size event
#
sub onSize{
    my($self, $event) = @_;
    $event-&gt;Skip();
}
#
# Paint the simulated LCD Display ----------------------------------------------------------
#
sub onPaint{
    my($self, $event) = @_;
    my $disp = Wx::PaintDC-&gt;new($self);				# Create paint device context
    my( $dw, $dh) = $disp-&gt;GetSizeWH();				# Calculate display scaling
    my $bw = GetBitmapWidth();
    my $bh = GetBitmapHeight();
    my $xs = $dw/$bw;
    my $ys = $dh/$bh;
    my $as = $xs &gt; $ys ? $ys : $xs;
    $disp-&gt;SetUserScale($as, $as);
    $disp-&gt;SetDeviceOrigin((($dw-$bw*$as)/2), (($dh-$bh*$as)/2));
    DoDrawing($disp);						# Paint the display
}
sub DoDrawing{
    my($dc) = @_;
    my @cbuf = reverse(split(//,$wxGlobals{mValue}));		# Process one character at a time
    my $cbuflen = @cbuf;
    if($cbuflen &gt; $wxGlobals{mNumberDigits}) {			# Truncate string to max display width
        $cbuflen = $wxGlobals{mNumberDigits};
    }
    my $ctr = 0;
    while($ctr &lt; $cbuflen) {
        $wxDigitData{value} = $cbuf[$ctr];
        $wxDigitData{comma} = 0;				# ? not clear on comma feature yet
        DrawDigit($dc, $ctr);
        $ctr++
    }
}
sub DrawDigit{
    my($dc, $digit) = @_;
    my $value = $wxDigitData{value};
    my $dec = Decode($value);
    if($value eq ':') {						# Draw a colon(:)
        DrawTwoDots($dc, $digit);
    }
    else{
        my $ctr = 0;
        while($ctr &lt; $wxGlobals{LCD_Number_Segments}-1) {
            DrawSegment($dc, $digit, $ctr, ($dec&gt;&gt;$ctr)&amp;1);
            $ctr++;
        }
        DrawSegment($dc, $digit, 7, $wxDigitData{comma});	# ? not clear on digit 7 yet
    }
}
sub DrawTwoDots{						# Draws a colon(:)
    my($dc, $digit) = @_;
    my $sl = $wxGlobals{mSegmentLen};
    my $sw = $wxGlobals{mSegmentWidth};
    my $sp = $wxGlobals{mSpace};
    my $x = DigitX($digit);
    my $y = DigitY($digit);
    $x += ($sl/2)-$sw;
    $y += ($sl/2)-$sw;
    my $brushOn = Wx::Brush-&gt;new($wxGlobals{mLightColour}-&gt;(), wxSOLID);
    $dc-&gt;SetBrush($brushOn);
    $dc-&gt;SetPen(Wx::Pen-&gt;new($frame-&gt;GetBackgroundColour(), 1, wxSOLID));
    $dc-&gt;DrawEllipse($x, $y, $sw*2, $sw*2);
    $y += $sl;
    $dc-&gt;DrawEllipse($x, $y, $sw*2, $sw*2);
}
sub DrawSegment{
    my($dc, $digit, $segment, $state) = @_;
    my $sl = $wxGlobals{mSegmentLen};
    my $sw = $wxGlobals{mSegmentWidth};
    my $x = DigitX($digit);
    my $y = DigitY($digit);
    my $brushOn = Wx::Brush-&gt;new($wxGlobals{mLightColour}-&gt;(), wxSOLID);
    my $brushOff = Wx::Brush-&gt;new($wxGlobals{mGrayColour}-&gt;(), wxSOLID);
    if($state) {						# bit set for On segment
        $dc-&gt;SetBrush($brushOn);				# Bright color for On segment
    }
    else {							# bit cleared for Off segment
        $dc-&gt;SetBrush($brushOff);				# Dim color for Off segment
    }
    $dc-&gt;SetPen(Wx::Pen-&gt;new($frame-&gt;GetBackgroundColour(), 1, wxSOLID));
    my @points;							# Verticies for 4 sided segments
    my @p6;							# Verticies for the 6 sided segment
    given($segment) {
        when(0) {
                  $points[0] = Wx::Point-&gt;new($x, $y);
                  $points[1] = Wx::Point-&gt;new($x+$sl, $y);
                  $points[2] = Wx::Point-&gt;new($x+$sl-$sw, $y+$sw);
                  $points[3] = Wx::Point-&gt;new($x+$sw, $y+$sw);
         }
        when(1) {
                  $points[0] = Wx::Point-&gt;new($x, $y);
                  $points[1] = Wx::Point-&gt;new($x, $y+$sl);
                  $points[2] = Wx::Point-&gt;new($x+$sw, $y+$sl-$sw/2);
                  $points[3] = Wx::Point-&gt;new($x+$sw, $y+$sw);
         }
        when(2) {
                  $x += $sl-$sw;
                  $points[0] = Wx::Point-&gt;new($x,$y+$sw);
                  $points[1] = Wx::Point-&gt;new($x+$sw, $y);
                  $points[2] = Wx::Point-&gt;new($x+$sw, $y+$sl);
                  $points[3] = Wx::Point-&gt;new($x, $y+$sl-$sw/2);
         }
        when(3) {
                  $y += $sl;
                  $points[0] = Wx::Point-&gt;new($x, $y);
                  $points[1] = Wx::Point-&gt;new($x, $y+$sl);
                  $points[2] = Wx::Point-&gt;new($x+$sw, $y+$sl-$sw);
                  $points[3] = Wx::Point-&gt;new($x+$sw, $y+$sw-$sw/2);
         }
        when(4) {
                  $x += $sl-$sw;
                  $y += $sl;
                  $points[0] = Wx::Point-&gt;new($x, $y+$sw/2);
                  $points[1] = Wx::Point-&gt;new($x+$sw, $y);
                  $points[2] = Wx::Point-&gt;new($x+$sw, $y+$sl);
                  $points[3] = Wx::Point-&gt;new($x, $y+$sl-$sw);
         }
        when(5) {
                  $y += 2*$sl-$sw;
                  $points[0] = Wx::Point-&gt;new($x+$sw, $y);
                  $points[1] = Wx::Point-&gt;new($x+$sl-$sw, $y);
                  $points[2] = Wx::Point-&gt;new($x+$sl, $y+$sw);
                  $points[3] = Wx::Point-&gt;new($x, $y+$sw);
         }
        when(6) {
                  $y += $sl-$sw/2;
                  $p6[0] = Wx::Point-&gt;new($x, $y+$sw/2);
                  $p6[1] = Wx::Point-&gt;new($x+$sw, $y);
                  $p6[2] = Wx::Point-&gt;new($x+$sl-$sw, $y);
                  $p6[3] = Wx::Point-&gt;new($x+$sl, $y+$sw/2);
                  $p6[4] = Wx::Point-&gt;new($x+$sl-$sw, $y+$sw);
                  $p6[5] = Wx::Point-&gt;new($x+$sw, $y+$sw);
        }
        default {}
    }
    if($segment &lt; 6) {						# Draw the 4 sided segments(0-5)
       $dc-&gt;DrawPolygon(\@points, 0, 0);
    }
    elsif($segment = 6) {					# Draw the 6 sided segment(6)
        $dc-&gt;DrawPolygon(\@p6, 0, 0);
    }
    else {							# ? not clear on this feature yet(7)
        $y += 2*$sl;
        $x += $sl;
        $dc-&gt;DrawEllipse($x+1, $y-$sw, $sw, $sw);
    }
}
sub Decode {							# Table lookup for character to
    my($char) = @_;						# Segment translation
    my $return;
    if(defined($ctbl{$char})) {
        $return = $ctbl{$char};
    }
    else {
         $return = $ctbl{'='};					# Triple bar for undefined character
    }   
}
#
# Support subs ----------------------------------------------------------------------------
#
sub GetDigitWidth{
    my $return = $wxGlobals{mSegmentLen} + $wxGlobals{mSegmentWidth} + $wxGlobals{mSpace};
}
sub GetDigitHeight{
    my $return = ($wxGlobals{mSegmentLen}*2) + ($wxGlobals{mSpace}*2);
}
sub GetBitmapWidth{
    my $return = ($wxGlobals{mNumberDigits}*GetDigitWidth()) + $wxGlobals{mSpace};
}
sub GetBitmapHeight{
    my $return = GetDigitHeight();
}
sub DigitX{
    my($digit) = @_;
    my $return = GetBitmapWidth()-(($digit+1)*GetDigitWidth());
}
sub DigitY{
    my($digit) = @_;
    my $return = $wxGlobals{mSpace};
}
sub SetNumberDigits{
    my $ndigits = @_;
    $wxGlobals{mNumberDigits} = $ndigits;
}
sub SetValue{
    my $value = @_;
    $wxGlobals{mValue} = $value;
}
sub GetValue{
    my $return = $wxGlobals{mValue};
}
sub GetNumberDigits{
    my $return = $wxGlobals{mNumberDigits};
}
sub SetLightColour{
    my($ref) = @_;
    $wxGlobals{mLightColour} = $ref;
}
sub SetGrayColour{
    my($ref) = @_;
    $wxGlobals{mGrayColour} = $ref;
}
sub GetLightColour{
    my $ref = $wxGlobals{mLightColour};
}
sub GetGrayColour{
    my $ref = $wxGlobals{mGrayColour};
}
sub GetDigitsNeeded{
    my($string) = @_;
    $string =~ s/\.//;
    my $return = strlen($string);
}&lt;/code&gt;&lt;/readmore&gt;

&lt;div class="pmsig"&gt;&lt;div class="pmsig-982107"&gt;
&lt;p&gt;There's never enough time to do it right, but always enough time to do it over...&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;</field>
</data>
</node>
