here's an attempt at fixing some of the problems listed above. I moved most of the Math into the buffer, in an attept to divorce the Display from the logic, and I used Math::BigFloat to represent the digits, but I still need to play around with the precision on divides.
#!/usr/bin/perl -w
use strict;
use utf8;
package Buffer;
use Math::BigFloat;
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {
LEFT => undef,
RIGHT => undef,
MEMORY => undef,
OP => undef,
RESET => 0
};
bless( $self, $class );
return $self;
}
sub left {
my $self = shift;
if (@_) {
$self->{LEFT} = shift;
}
return $self->{LEFT};
}
sub right {
my $self = shift;
if (@_) {
$self->{RIGHT} = shift;
}
return $self->{RIGHT};
}
sub op {
my $self = shift;
if (@_) {
my $op = shift;
if ( $op =~ /^[+-\/*]$/ ) {
$self->{OP} = $op;
}
}
return $self->{OP};
}
sub reset_display {
my $self = shift;
if (@_) {
$self->{RESET} = shift;
}
return $self->{RESET};
}
sub clear_all {
my $self = shift;
$self->{LEFT} = undef;
$self->{RIGHT} = undef;
$self->{OP} = undef;
$self->{MEMORY} = undef;
$self->reset_display(0);
}
sub add{
my $self = shift;
my $left = new Math::BigFloat($self->left);
$left->badd($self->right);
return $left->bstr;
}
sub subtract{
my $self = shift;
my $left = new Math::BigFloat($self->left);
$left->bsub($self->right);
return $left->bstr;
}
sub divide{
my $self = shift;
return "Error" unless $self->right;
my $left = new Math::BigFloat($self->left);
$left->bdiv($self->right);
my $precision = 10 - $left->copy()->blog(10);
$left->precision( - $precision->bfloor );
return $left->bstr;
}
sub multiply{
my $self = shift;
my $left = new Math::BigFloat($self->left);
$left->bmul($self->right);
return $left->bstr;
}
1;
package PerlCalc;
use Qt;
use Qt::isa qw(Qt::Dialog);
use Qt::slots
Key_0_clicked => [],
Key_1_clicked => [],
Key_2_clicked => [],
Key_3_clicked => [],
Key_4_clicked => [],
Key_5_clicked => [],
Key_6_clicked => [],
Key_7_clicked => [],
Key_8_clicked => [],
Key_9_clicked => [],
Key_Clear_clicked => [],
Key_Plus_clicked => [],
Key_Minus_clicked => [],
Key_Divide_clicked => [],
Key_Times_clicked => [],
Key_Equals_clicked => [],
Key_Decimal_clicked => [];
use Qt::attributes qw(
Key_Divide Key_Clear Key_Decimal Key_Minus Key_Plus
Key_1 Key_2 Key_3 Key_4 Key_5 Key_6 Key_7 Key_8
Key_9 Key_0 Key_Times Display Display_font Key_Equals
);
our ($buffer) = Buffer->new();
sub NEW {
shift->SUPER::NEW( @_[ 0 .. 3 ] );
if ( name() eq "unnamed" ) {
setName("PerlCalc");
}
Key_Divide = Qt::PushButton( this, "Key_Divide" );
Key_Divide->setGeometry( Qt::Rect( 90, 100, 51, 41 ) );
Key_Clear = Qt::PushButton( this, "Key_Clear" );
Key_Clear->setGeometry( Qt::Rect( 30, 100, 51, 41 ) );
Key_Decimal = Qt::PushButton( this, "Key_Decimal" );
Key_Decimal->setGeometry( Qt::Rect( 150, 300, 51, 41 ) );
Key_Minus = Qt::PushButton( this, "Key_Minus" );
Key_Minus->setGeometry( Qt::Rect( 210, 100, 51, 41 ) );
Key_Plus = Qt::PushButton( this, "Key_Plus" );
Key_Plus->setGeometry( Qt::Rect( 210, 151, 51, 90 ) );
Key_Times = Qt::PushButton( this, "Key_Times" );
Key_Times->setGeometry( Qt::Rect( 150, 100, 51, 41 ) );
Key_Equals = Qt::PushButton( this, "Key_Equals" );
Key_Equals->setGeometry( Qt::Rect( 210, 250, 51, 90 ) );
Key_0 = Qt::PushButton( this, "Key_0" );
Key_0->setGeometry( Qt::Rect( 30, 300, 110, 41 ) );
Key_1 = Qt::PushButton( this, "Key_1" );
Key_1->setGeometry( Qt::Rect( 30, 250, 51, 41 ) );
Key_2 = Qt::PushButton( this, "Key_2" );
Key_2->setGeometry( Qt::Rect( 90, 250, 51, 41 ) );
Key_3 = Qt::PushButton( this, "Key_3" );
Key_3->setGeometry( Qt::Rect( 150, 250, 51, 41 ) );
Key_4 = Qt::PushButton( this, "Key_4" );
Key_4->setGeometry( Qt::Rect( 30, 200, 51, 41 ) );
Key_5 = Qt::PushButton( this, "Key_5" );
Key_5->setGeometry( Qt::Rect( 90, 200, 51, 41 ) );
Key_6 = Qt::PushButton( this, "Key_6" );
Key_6->setGeometry( Qt::Rect( 150, 200, 51, 41 ) );
Key_7 = Qt::PushButton( this, "Key_7" );
Key_7->setGeometry( Qt::Rect( 30, 150, 51, 41 ) );
Key_8 = Qt::PushButton( this, "Key_8" );
Key_8->setGeometry( Qt::Rect( 90, 150, 51, 41 ) );
Key_9 = Qt::PushButton( this, "Key_9" );
Key_9->setGeometry( Qt::Rect( 150, 150, 51, 41 ) );
Display = Qt::Label( this, "Display" );
Display->setGeometry( Qt::Rect( 30, 20, 280, 51 ) );
Display->setBackgroundMode( &Qt::Label::PaletteBrightText() );
Display->setPaletteForegroundColor( Qt::Color( 255, 0, 0 ) );
Display->setPaletteBackgroundColor( Qt::Color( 0, 0, 0 ) );
my $Display_font = Qt::Font( Display->font );
$Display_font->setFamily("Monospace");
$Display_font->setPointSize(20);
Display->setFont($Display_font);
Display->setFrameShape( &Qt::Label::WinPanel() );
Display->setFrameShadow( &Qt::Label::Sunken() );
Display->setLineWidth( int(1) );
Display->setAlignment(
int( &Qt::Label::AlignVCenter | &Qt::Label::AlignRight ) );
languageChange();
my $resize = Qt::Size( 327, 391 );
$resize = $resize->expandedTo( minimumSizeHint() );
resize($resize);
clearWState(&Qt::WState_Polished);
Qt::Object::connect( Key_0, SIGNAL "clicked()",
this, SLOT "Key_0_clicked()" );
Qt::Object::connect( Key_1, SIGNAL "clicked()",
this, SLOT "Key_1_clicked()" );
Qt::Object::connect( Key_2, SIGNAL "clicked()",
this, SLOT "Key_2_clicked()" );
Qt::Object::connect( Key_3, SIGNAL "clicked()",
this, SLOT "Key_3_clicked()" );
Qt::Object::connect( Key_4, SIGNAL "clicked()",
this, SLOT "Key_4_clicked()" );
Qt::Object::connect( Key_5, SIGNAL "clicked()",
this, SLOT "Key_5_clicked()" );
Qt::Object::connect( Key_6, SIGNAL "clicked()",
this, SLOT "Key_6_clicked()" );
Qt::Object::connect( Key_7, SIGNAL "clicked()",
this, SLOT "Key_7_clicked()" );
Qt::Object::connect( Key_8, SIGNAL "clicked()",
this, SLOT "Key_8_clicked()" );
Qt::Object::connect( Key_9, SIGNAL "clicked()",
this, SLOT "Key_9_clicked()" );
Qt::Object::connect( Key_Clear, SIGNAL "clicked()",
this, SLOT "Key_Clear_clicked()" );
Qt::Object::connect( Key_Plus, SIGNAL "clicked()",
this, SLOT "Key_Plus_clicked()" );
Qt::Object::connect( Key_Minus, SIGNAL "clicked()",
this, SLOT "Key_Minus_clicked()" );
Qt::Object::connect( Key_Divide, SIGNAL "clicked()",
this, SLOT "Key_Divide_clicked()" );
Qt::Object::connect( Key_Times, SIGNAL "clicked()",
this, SLOT "Key_Times_clicked()" );
Qt::Object::connect( Key_Equals, SIGNAL "clicked()",
this, SLOT "Key_Equals_clicked()" );
Qt::Object::connect( Key_Decimal, SIGNAL "clicked()",
this, SLOT "Key_Decimal_clicked()" );
}
# Sets the strings of the subwidgets using the current
# language.
sub languageChange {
setCaption( trUtf8("PerlCalc") );
Key_Divide->setText( trUtf8("/") );
Key_Clear->setText( trUtf8("C") );
Key_Decimal->setText( trUtf8(".") );
Key_Minus->setText( trUtf8("-") );
Key_Plus->setText( trUtf8("+") );
Key_6->setText( trUtf8("6") );
Key_9->setText( trUtf8("9") );
Key_8->setText( trUtf8("8") );
Key_4->setText( trUtf8("4") );
Key_7->setText( trUtf8("7") );
Key_5->setText( trUtf8("5") );
Key_Times->setText( trUtf8("X") );
Key_1->setText( trUtf8("1") );
Display->setText( trUtf8("0") );
Key_Equals->setText( trUtf8("=") );
Key_0->setText( trUtf8("0") );
Key_2->setText( trUtf8("2") );
Key_3->setText( trUtf8("3") );
}
sub Key_0_clicked {AppendDisplay(0);}
sub Key_1_clicked {AppendDisplay(1);}
sub Key_2_clicked {AppendDisplay(2);}
sub Key_3_clicked {AppendDisplay(3);}
sub Key_4_clicked {AppendDisplay(4);}
sub Key_5_clicked {AppendDisplay(5);}
sub Key_6_clicked {AppendDisplay(6);}
sub Key_7_clicked {AppendDisplay(7);}
sub Key_8_clicked {AppendDisplay(8);}
sub Key_9_clicked {AppendDisplay(9);}
sub Key_Divide_clicked {
SetOp("/");
}
sub Key_Minus_clicked {
SetOp("-");
}
sub Key_Times_clicked {
SetOp("*");
}
sub Key_Plus_clicked {
SetOp("+");
}
sub Key_Decimal_clicked {
AppendDisplay(".");
}
sub Key_Clear_clicked {
$buffer->clear_all;
Display->setText("0");
}
sub Key_Equals_clicked {
my $result;
SWITCH: for ( $buffer->op ) {
/^[+]$/ && do { $result = $buffer->add; last; };
/^[-]$/ && do { $result = $buffer->subtract; last; };
/^[*]$/ && do { $result = $buffer->multiply; last; };
/^[\/]$/ && do {$result = $buffer->divide; last;};
}
if ( $result =~ /^-?\d+\.?\d*?$/ ) {
$buffer->left($result);
$buffer->reset_display(1);
Display->setText($result);
}elsif($result eq 'Error'){
$buffer->reset_display(1);
Display->setText($result);
}
print STDERR "buffer left =" . $buffer->left . "\n";
print STDERR "buffer right =" . $buffer->right . "\n";
}
sub AppendDisplay {
my $character = shift;
my $text = Display->text;
if ( $character eq '.' ) {
return if $text =~ /\./;
}
Display->setText(
$text && !$buffer->reset_display
? $text . $character
: $character
);
$buffer->reset_display(0);
if ( !defined $buffer->op ) {
$buffer->left( Display->text );
print STDERR "buffer left =" . $buffer->left . "\n";
}
else {
$buffer->right( Display->text );
print STDERR "buffer right =" . $buffer->right . "\n";
}
}
sub SetOp {
my $op = shift;
$buffer->op($op);
$buffer->reset_display(1);
}
1;
package main;
use Qt;
use PerlCalc;
my $a = Qt::Application( \@ARGV );
my $w = PerlCalc;
$a->setMainWidget($w);
$w->show;
exit $a->exec;