package LinearMeter;
use strict;
use warnings;
use Wx qw(:everything);
use Data::Dumper;

sub new {
    my $self                  = {};
    $self->{METERHEIGHT}      = 400;					# Swap these for horizontal display
    $self->{METERWIDTH}       = 100;
    $self->{ACTIVEBAR}        = wxGREEN;
    $self->{PASSIVEBAR}       = wxWHITE;
    $self->{VALUECOLOUR}      = wxBLACK;
    $self->{BORDERCOLOUR}     = wxBLUE;
    $self->{LIMITCOLOUR}      = wxBLACK;
    $self->{ALARMLIMITCOLOUR} = wxRED;
    $self->{TAGSCOLOUR}       = wxBLACK;
    $self->{SCALEDVALUE}      = 0;
    $self->{REALVAL}          = 0;
    $self->{LIMIT}            = 75;					# High-Limit setpoint
    $self->{TAGSVAL}          = [];
    $self->{TAGSNUM}          = 0;
    $self->{STARTTAG}         = 0;
    $self->{NUMTAGS}          = 10;
    $self->{INCTAG}           = 10;
    $self->{MAX}              = 100;					# Span
    $self->{MIN}              = 0;
    $self->{INITIALVALUE}     = 45;					# Initial value displayed
    $self->{LASTPOS}          = 0;					# Last mouse position
    $self->{DIRHORIZFLAG}     = 0;					# 0-Verticle, 1-Horizontal
    $self->{SHOWCURRENT}      = 1;
    $self->{SHOWLIMITS}       = 0;
    $self->{SHOWLABEL}        = 1;
    $self->{FONT}             = Wx::Font->new(10, wxFONTFAMILY_SWISS, wxNORMAL, wxNORMAL);
    $self->{LABEL}            = "";
    bless($self);
    return $self;
}
#
# Draw the Linear Meter ----------------------------------------------------------
#
sub Draw {						# ****Simple testing version****
    my($class, $panel, $Meter) = @_;			# Sets all white background
    my $dc = Wx::PaintDC->new($panel);			# Draws a blue border
    my $memdc = Wx::MemoryDC->new();
    $memdc->SelectObject(Wx::Bitmap->new(100,400));
    my($w, $h) = $memdc->GetSizeWH();
    my $brush = Wx::Brush->new(wxWHITE, wxSOLID);
    $memdc->SetBackground($brush);
    $memdc->Clear();
    my $pen = Wx::Pen->new(wxBLUE, 2, wxSOLID);
    $memdc->SetPen($pen);
    $memdc->DrawRectangle(0, 0, $w, $h);
    $dc->Blit(0, 0, $w, $h, $memdc, 0, 0);
    $panel->Refresh();
    $panel->Update();
sleep(1);						# Slow things down to see what's going on
}

sub realDraw {
    my($class, $panel, $Meter) = @_;
    my $dc = Wx::PaintDC->new($panel);
    my $memdc = Wx::MemoryDC->new();
    $memdc->SelectObject(Wx::Bitmap->new($Meter->MeterWidth(), $Meter->MeterHeight()));
    my($w, $h) = $memdc->GetSizeWH();
    my $brush = Wx::Brush->new($Meter->PassiveBar(), wxSOLID);
    $memdc->SetBackground($brush);
    $memdc->Clear();
    SetUp($memdc, $Meter);						# Set the initial value and tic marks
    my $pen = Wx::Pen->new($Meter->BorderColour(), 2, wxSOLID);
    $memdc->SetPen($pen);
    $memdc->DrawRectangle(0, 0, $w, $h);
    $pen = Wx::Pen->new($Meter->BorderColour(), 2, wxSOLID);
    $memdc->SetPen($pen);
    $brush = Wx::Brush->new($Meter->ActiveBar(), wxSOLID);
    if($Meter->RealVal() > $Meter->Limit()) {$brush = Wx::Brush->new($Meter->AlarmLimitColour(), wxSOLID)}
    $memdc->SetBrush($brush);
    my $yPoint;
    my $rectHeight;
    if($Meter->DirHorizFlag()) {						# Horizontal Orientation
        $memdc->DrawRectangle(1, 1, $Meter->ScaledValue(), $h-2);
    }
    else {							# Verticle Orientation
        $yPoint = $h - $Meter->ScaledValue();
        if($Meter->ScaledValue() == 0) {
            $rectHeight = $Meter->ScaledValue();
        }
        else {
            if($Meter->RealVal() == $Meter->Max()) {
               $rectHeight = $Meter->ScaledValue();
               $yPoint -= 1;
            }
            else {
                $rectHeight = $Meter->ScaledValue() - 1;
            }
        $memdc->DrawRectangle(1, $yPoint, $w-2, $rectHeight);
       }
    }
    if($Meter->ShowCurrent()) {DrawCurrent($memdc, $Meter)}
    if($Meter->ShowLimits()) {DrawLimits($memdc, $Meter)}
#    if($Meter->TagsNum() > 0) {DrawTags($memdc, $Meter)}
    if($Meter->ShowLabel()) {DrawLabel($memdc, $Meter)}
    $dc->Blit(0, 0, $w, $h, $memdc, 0, 0);
}
sub SetUp {						# Set and update the displayed value
    my($dc, $Meter) = @_;
    SetValue($dc, $Meter->InitialValue(), $Meter);
    if($Meter->TagsNum() == 0) {					# Build tic marks 1st time through
        for($Meter->StartTag()..$Meter->NumTags()) {			# Quick and dirty
            AddTag($_ * $Meter->IncTag(), $Meter);
        }
    }
} 
sub DrawCurrent {					# Draw the current value as text
    my($dc, $Meter) = @_;
    my($w, $h) = $dc->GetSizeWH();
    my $valuetext = sprintf("%d", $Meter->RealVal());
    my ($tw, $th) = $dc->GetTextExtent($valuetext);
    $dc->SetTextForeground($Meter->ValueColour());
    $dc->DrawText($valuetext, $w/2-$tw/2, $h/2-$th/2);    
}
sub DrawLimits {					# Draw Min and Max as text
    my($dc, $Meter) = @_;
    my($w, $h) = $dc->GetSizeWH();
    $dc->SetFont($Meter->Font());
    $dc->SetTextForeground($Meter->LimitColour());
    if($Meter->DirHorizFlag()) {
        my $valuetext = sprintf("%d", $Meter->Min());
        my ($tw, $th) = $dc->GetTextExtent($valuetext);
        $dc->DrawText($valuetext, 5, $h/2-$th/2);
        $valuetext = sprintf("%d", $Meter->Max());
        ($tw, $th) = $dc->GetTextExtent($valuetext);
        $dc->DrawText($valuetext, $w-$tw-5, $h/2-$th/2);
    }
    else {
        my $valuetext = sprintf("%d", $Meter->Min());
        my ($tw, $th) = $dc->GetTextExtent($valuetext);
        $dc->DrawText($valuetext, $w/2-$tw/2, $h-$th-5);
        $valuetext = sprintf("%d", $Meter->Max());
        ($tw, $th) = $dc->GetTextExtent($valuetext);
        $dc->DrawText($valuetext, $w/2-$tw/2, 5);
    }     
}
sub DrawTags {						# Draw tic marks and labels
    my($dc, $Meter) = @_;
    my($w, $h) = $dc->GetSizeWH();
    my $tcoeff;
    if($Meter->DirHorizFlag()) {
        $tcoeff = ($w-2)/($Meter->Max()-$Meter->Min());
    }
    else {
        $tcoeff = ($h-2)/($Meter->Max()-$Meter->Min());
    }
    my $pen = Wx::Pen->new($Meter->TagsColour(), 1, wxSOLID);
    $dc->SetPen($pen);
    my $brush = Wx::Brush->new($Meter->TagsColour(), wxSOLID);
    $dc->SetBrush($brush);
    $dc->SetTextForeground($Meter->TagsColour());
    my $tag = 0;
    while($tag < $Meter->TagsNum()) {
        my $scalval = ($Meter->TagsVal([$tag])-$Meter->Min()) * $tcoeff;
        my $textvalue = sprintf("%d", $Meter->TagsVal([$tag]));
        if($Meter->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, $Meter) = @_;
    push($Meter->TagsVal(), $val);
    $Meter->TagsNum($Meter->TagsVal());    
}
sub SetValue {						# Scale the value for display
    my($dc, $Value, $Meter) = @_;
    my($w, $h) = $dc->GetSizeWH();
    my $coeff;
    if($Meter->DirHorizFlag()) {
        $coeff = ($w-2)/($Meter->Max()-$Meter->Min());
    }
    else {
        $coeff = ($h-2)/($Meter->Max()-$Meter->Min());
    }
    $Meter->ScaledValue(($Value-$Meter->Min()) * $coeff);
    $Meter->RealVal($Value);
}
sub DrawLabel {						# Draw a label at bottom of meter
    my($dc, $Meter) = @_;
    my($w, $h) = $dc->GetSizeWH();
    my @te = $dc->GetTextExtent($Meter->Label());
    my $x = ($w-$te[0])/2;
    $dc->DrawText($Meter->Label(), $x, $h-20);
}
#
# Object Accessors --------------------------------------------------------------------------
#
sub MeterHeight {
    my $self = shift;
    if(@_) { $self->{METERHEIGHT} = shift }
    return $self->{METERHEIGHT};
}
sub MeterWidth {
    my $self = shift;
    if(@_) { $self->{METERWIDTH} = shift }
    return $self->{METERWIDTH};
}
sub ActiveBar {
    my $self = shift;
    if(@_) { $self->{ACTIVEBAR} = shift }
    return $self->{ACTIVEBAR};
}
sub PassiveBar {
    my $self = shift;
    if(@_) { $self->{PASSIVEBAR} = shift }
    return $self->{PASSIVEBAR};
}
sub ValueColour {
    my $self = shift;
    if(@_) { $self->{VALUECOLOUR} = shift }
    return $self->{VALUECOLOUR};
}
sub BorderColour {
    my $self = shift;
    if(@_) { $self->{BORDERCOLOUR} = shift }
    return $self->{BORDERCOLOUR};
}
sub LimitColour {
    my $self = shift;
    if(@_) { $self->{LIMITCOLOUR} = shift }
    return $self->{LIMITCOLOUR};
}
sub AlarmLimitColour {
    my $self = shift;
    if(@_) { $self->{ALARMLIMITCOLOUR} = shift }
    return $self->{ALARMLIMITCOLOUR};
}
sub TagsColour {
    my $self = shift;
    if(@_) { $self->{TAGSCOLOUR} = shift }
    return $self->{TAGSCOLOUR};
}
sub ScaledValue {
    my $self = shift;
    if(@_) { $self->{SCALEDVALUE} = shift }
    return $self->{SCALEDVALUE};
}
sub RealVal {
    my $self = shift;
    if(@_) { $self->{REALVAL} = shift }
    return $self->{REALVAL};
}
sub Limit {
    my $self = shift;
    if(@_) { $self->{LIMIT} = shift }
    return $self->{LIMIT};
}
sub TagsVal {
    my $self = shift;
    if(@_) { $self->{TAGSVAL} = @_ }
    return $self->{TAGSVAL};
}
sub TagsNum {
    my $self = shift;
    if(@_) { $self->{TAGSNUM} = shift }
    return $self->{TAGSNUM};
}
sub StartTag {
    my $self = shift;
    if(@_) { $self->{STARTTAG} = shift }
    return $self->{STARTTAG};
}
sub NumTags {
    my $self = shift;
    if(@_) { $self->{NUMTAGS} = shift }
    return $self->{NUMTAGS};
}
sub IncTag {
    my $self = shift;
    if(@_) { $self->{INCTAG} = shift }
    return $self->{INCTAG};
}
sub Max {
    my $self = shift;
    if(@_) { $self->{MAX} = shift }
    return $self->{MAX};
}
sub Min {
    my $self = shift;
    if(@_) { $self->{MIN} = shift }
    return $self->{MIN};
}
sub InitialValue {
    my $self = shift;
    if(@_) { $self->{INITIALVALUE} = shift }
    return $self->{INITIALVALUE};
}
sub lastpos {
    my $self = shift;
    if(@_) { $self->{LASTPOS} = shift }
    return $self->{LASTPOS};
}
sub DirHorizFlag {
    my $self = shift;
    if(@_) { $self->{DIRHORIZFLAG} = shift }
    return $self->{DIRHORIZFLAG};
}
sub ShowCurrent {
    my $self = shift;
    if(@_) { $self->{SHOWCURRENT} = shift }
    return $self->{SHOWCURRENT};
}
sub ShowLimits {
    my $self = shift;
    if(@_) { $self->{SHOWLIMITS} = shift }
    return $self->{SHOWLIMITS};
}
sub ShowLabel {
    my $self = shift;
    if(@_) { $self->{SHOWLABEL} = shift }
    return $self->{SHOWLABEL};
}
sub Font {
    my $self = shift;
    if(@_) { $self->{FONT} = shift }
    return $self->{FONT};
}
sub Label {
    my $self = shift;
    if(@_) { $self->{LABEL} = shift }
    return $self->{LABEL};
}

1;



