The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl -w
package WidgetView;

use Qt 2.0;
import Qt::app;
use lib '../aclock', '../dclock';
use AnalogClock;
use DigitalClock;

use Qt::slots 'button1Clicked()',
	      'checkBoxClicked(int)',
	      'radioButtonClicked(int)',
	      'sliderValueChanged(int)',
	      'listBoxItemSelected(int)',
	      'comboBoxItemActivated(int)',
	      'edComboBoxItemActivated(cstring)',
              'lineEditTextChanged(cstring)',
	      'movieStatus(int)',
	      'movieUpdate(const \QRect)',
	      'spinBoxValueChanged(cstring)';

sub MOVIEFILENAME () { "perlqt.gif" }

@ISA = qw(Qt::Widget);

sub new {
    my $self = shift->SUPER::new(@_);
    my $col = Qt::Color->new;

    # Set the window caption/title

    $self->setCaption("PerlQt Widget Demo Application");

    # Install an application-global event filter

    $app->installEventFilter($self);

    # Create a layout to position the widgets

    my $topLayout = Qt::VBoxLayout->new($self, 10);

    # Create a grid layout to hold most of the widgets

    my $grid = Qt::GridLayout->new(6, 3);
    # This layout will get all of the stretch
    $topLayout->addLayout($grid, 10);

    # Create a menubar
    my $menubar = Qt::MenuBar->new($self);
    $menubar->setSeparator(Qt::MenuBar::InWindowsStyle);
    # Create an easter egg
    Qt::ToolTip::add($menubar, Qt::Rect->new(0, 0, 2, 2), "easter egg");

    my $popup;
    $popup = Qt::PopupMenu->new;
    my $id;
    $id = $popup->insertItem("&New");
    $popup->setItemEnabled($id, 0);
    $id = $popup->insertItem("&Open");
    $popup->setItemEnabled($id, 0);
    $popup->insertSeparator();
    $popup->insertItem("&Quit", $app, 'quit()', Qt::CTRL+Qt::Key_Q);

    $menubar->insertItem("&File", $popup);

    # Must tell the layout about a menubar in a widget
    $topLayout->setMenuBar($menubar);

    # Create an analog and a digital clock

    my $aclock = AnalogClock->new($self);
    my $dclock = DigitalClock->new($self);
    $dclock->setMaximumWidth(200);
    $grid->addWidget($aclock, 0, 2);
    $grid->addWidget($dclock, 1, 2);

    # Give the dclock widget a blue palette

    $col->setRgb(0xaa, 0xbe, 0xff);
    $dclock->setPalette(Qt::Palette->new($col));

    # make tool tips for both of them

    Qt::ToolTip::add($aclock, "custom widget: analog clock");
    Qt::ToolTip::add($dclock, "custom widget: digital clock");

    # Create a push button.

    my $pb;
    $pb = Qt::PushButton->new($self, "button1");
    $pb->setText("Push button 1");
    $pb->setFixedHeight($pb->sizeHint()->height());
    $grid->addWidget($pb, 0, 0, $Qt::AlignVCenter);
    $self->connect($pb, 'clicked()', 'button1Clicked()');
    Qt::ToolTip::add($pb, "push button 1");
    my $pm = Qt::Pixmap->new;
    my $pix = $pm->load("perlqt.bmp");
    if(!$pix) {
#        Qt::MessageBox::information(0,
#	    "PerlQt Widgets Example",
#            "Could not load the file \"perlqt.bmp\", which\n" .
#            "contains an icon used...\n\n" .
#	    "The text \"line 42\" will be substituted.",
#	    Qt::MessageBox::Ok + Qt::MessageBox::Default );
    }

    # Create a label containing a QMovie

    my $movielabel = $self->{'movielabel'} = Qt::Label->new($self, "label0");
    my $movie = $self->{'movie'} = Qt::Movie->new(MOVIEFILENAME);
    $movie->connectStatus($self, 'movieStatus(int)');
    $movie->connectUpdate($self, 'movieUpdate(const \QRect)');
    $movielabel->setFrameStyle(Qt::Frame::Box | Qt::Frame::Plain);
    $movielabel->setMovie($movie);
    $movielabel->setMargin(0);
    $movielabel->setFixedSize(128+$movielabel->frameWidth()*2,
			      64 +$movielabel->frameWidth()*2);
    $grid->addWidget($movielabel, 0, 1, Qt::AlignCenter);
    Qt::ToolTip::add($movielabel, "movie");

    # Create a group of check boxes

    my $bg = Qt::ButtonGroup->new($self, "checkGroup");
    $bg->setTitle("Check Boxes");
    $grid->addWidget($bg, 1, 0);

    # Create a layout for the check boxes
    my $vbox = Qt::VBoxLayout->new($bg, 10);

    $vbox->addSpacing($bg->fontMetrics()->height());

    my @cb;
    $cb[0] = Qt::CheckBox->new($bg);
    $cb[0]->setText("Read");
    $vbox->addWidget($cb[0]);
    $cb[0]->setMinimumSize($cb[0]->sizeHint());
    $cb[1] = Qt::CheckBox->new($bg);
    $cb[1]->setText("Write");
    $vbox->addWidget($cb[1]);
    $cb[1]->setMinimumSize($cb[1]->sizeHint());
    $cb[2] = Qt::CheckBox->new($bg);
    $cb[2]->setText("Execute");
    $cb[2]->setMinimumSize($cb[2]->sizeHint());
    $vbox->addWidget($cb[2]);
    $bg->setMinimumSize($bg->childrenRect()->size());
    $vbox->activate();
    $self->{'cb'} = \@cb;

    $self->connect($bg, 'clicked(int)', 'checkBoxClicked(int)');

    Qt::ToolTip::add($cb[0], "check box 1");
    Qt::ToolTip::add($cb[1], "check box 2");
    Qt::ToolTip::add($cb[2], "check box 3");

    # Create a group of radio buttons

    my $rb;
    $bg = Qt::ButtonGroup->new($self, "radioGroup");
    $bg->setTitle("Radio buttons");

    $grid->addWidget($bg, 1, 1);

    # Create a layout for the radio buttons
    $vbox = Qt::VBoxLayout->new($bg, 10);

    $vbox->addSpacing($bg->fontMetrics()->height());
    $rb = Qt::RadioButton->new($bg);
    $rb->setText("&AM");
    $rb->setChecked(1);
    $vbox->addWidget($rb);
    $rb->setMinimumSize($rb->sizeHint());
    Qt::ToolTip::add($rb, "radio button 1");
    $rb = Qt::RadioButton->new($bg);
    $rb->setText("&FM");
    $vbox->addWidget($rb);
    $rb->setMinimumSize($rb->sizeHint());
    Qt::ToolTip::add($rb, "radio button 2");
    $rb = Qt::RadioButton->new($bg);
    $rb->setText("&Short Wave");
    $vbox->addWidget($rb);
    $rb->setMinimumSize($rb->sizeHint());
    $vbox->activate();

    $self->connect($bg, 'clicked(int)', 'radioButtonClicked(int)');
    Qt::ToolTip::add($rb, "radio button 3");

    # Create a list box

    my $lb = Qt::ListBox->new($self, 'listBox');
    for(my $i = 0; $i < 100; $i++) {
	$lb->insertItem(($i == 42 && $pix) ? $pm : "line $i");
    }
    $grid->addMultiCellWidget($lb, 2, 4, 0, 0);
    $self->connect($lb, 'selected(int)', 'listBoxItemSelected(int)');
    Qt::ToolTip::add($lb, "list box");

    $vbox = Qt::VBoxLayout->new(8);
    $grid->addLayout($vbox, 2, 1);

    # Create a slider

    my $sb = Qt::Slider->new(0, 300, 1, 100, Qt::Slider::Horizontal,
			     $self, "Slider");
    $sb->setTickmarks(Qt::Slider::Below);
    $sb->setTickInterval(10);
    $sb->setFocusPolicy(Qt::Widget::TabFocus);
    $sb->setFixedHeight($sb->sizeHint()->height());
    $vbox->addWidget($sb);

    $self->connect($sb, 'valueChanged(int)', 'sliderValueChanged(int)');
    Qt::ToolTip::add($sb, "slider");

    # Create a combo box

    my $combo = Qt::ComboBox->new(0, $self, "comboBox");
    $combo->insertItem("darkBlue");
    $combo->insertItem("darkRed");
    $combo->insertItem("darkGreen");
    $combo->insertItem("blue");
    $combo->insertItem("red");
    $combo->setFixedHeight($combo->sizeHint()->height());
    $vbox->addWidget($combo);
    $self->connect($combo, 'activated(int)', 'comboBoxItemActivated(int)');
    Qt::ToolTip::add($combo, "read-only combo box");

    # Create an editable combo box

    my $edCombo = Qt::ComboBox->new(1, $self, "edComboBox");
    $edCombo->insertItem("Permutable");
    $edCombo->insertItem("Malleable");
    $edCombo->insertItem("Adaptable");
    $edCombo->insertItem("Alterable");
    $edCombo->insertItem("Inconstant");
    $edCombo->setFixedHeight($edCombo->sizeHint()->height());
    $vbox->addWidget($edCombo);
    $self->connect($edCombo, 'activated(cstring)', 'edComboBoxItemActivated(cstring)');
    Qt::ToolTip::add($edCombo, "editable combo box");

    $edCombo->setAutoCompletion(1);

    $vbox->addStretch(1);

    $vbox = Qt::VBoxLayout->new(8);
    $grid->addLayout($vbox, 2, 2);

    # Create a spin box

    my $spin = Qt::SpinBox->new(0, 10, 1, $self, "spin");
    $spin->setSuffix(" mm");
    $spin->setSpecialValueText("Auto");
    $spin->setMinimumSize($spin->sizeHint());
    $self->connect($spin, 'valueChanged(cstring)', 'spinBoxValueChanged(cstring)');
    Qt::ToolTip::add($spin, "spin box");
    $vbox->addWidget($spin);

    $vbox->addStretch(1);

    # Create a multi line edit

    my $mle = Qt::MultiLineEdit->new($self, "multiLineEdit");

    $grid->addMultiCellWidget($mle, 3, 3, 1, 2);
    $mle->setMinimumHeight($mle->fontMetrics()->height()*3);
    $mle->setText("This is a QMultiLineEdit widget,\n" .
		  "useful for small multi-line\n" .
		  "input fields.");
    Qt::ToolTip::add($mle, "multi line editor");

    # Create a single line edit

    my $le = Qt::LineEdit->new($self, "lineEdit");
    $grid->addMultiCellWidget($le, 4, 4, 1, 2);
    $le->setFixedHeight($le->sizeHint()->height());
    $self->connect($le, 'textChanged(cstring)', 'lineEditTextChanged(cstring)');
    Qt::ToolTip::add($le, "single line editor");

    # Create a horizontal line (sort of QFrame) above the message line

    my $separator = Qt::Frame->new($self, "separatorLine");
    $separator->setFrameStyle(Qt::Frame::HLine | Qt::Frame::Sunken);
    $separator->setFixedHeight($separator->sizeHint()->height());
    $grid->addMultiCellWidget($separator, 5, 5, 0, 2);
    Qt::ToolTip::add($separator, "tool tips on a separator! wow!");

    $grid->setRowStretch(0,0);
    $grid->setRowStretch(1,0);
    $grid->setRowStretch(2,0);
    $grid->setRowStretch(3,1);
    $grid->setRowStretch(4,1);
    $grid->setRowStretch(5,0);

    $grid->setColStretch(0,1);
    $grid->setColStretch(1,1);
    $grid->setColStretch(2,1);


    # Create an label and a message in a plain widget
    # The message is updated when buttons are clicked etc.

    my $hbox = Qt::HBoxLayout->new();
    $topLayout->addLayout($hbox);
    my $msgLabel = Qt::Label->new($self, "msgLabel");
    $msgLabel->setText("Message:");
    $msgLabel->setAlignment(Qt::AlignCenter);
    $msgLabel->setFixedSize($msgLabel->sizeHint());
    $hbox->addWidget($msgLabel);
    Qt::ToolTip::add($msgLabel, "label 1");

    my $msg = $self->{'msg'} = Qt::Label->new($self, "message");
    $msg->setFrameStyle(Qt::Frame::Panel | Qt::Frame::Sunken);
    $msg->setAlignment(Qt::AlignCenter);
    $msg->setFont(Qt::Font->new("times",12,Qt::Font::Bold));
    $msg->setText("Message");
    $msg->setFixedHeight($msg->sizeHint()->height());
    $msg->setText("");
    $hbox->addWidget($msg, 5);
    Qt::ToolTip::add($msg, "label 2");

    $topLayout->activate();

    return $self;
}

sub setStatus {
    shift->{'msg'}->setText(shift);
}

sub button1Clicked {
    shift->{'msg'}->setText("The first push button was clicked");
}

sub movieUpdate {
    # Uncomment this to test animated icons on your window manager
    # $self->setIcon($movie->framePixmap());
}

sub movieStatus {
    my $self = shift;
    my $s = shift;
    my $movielabel = $self->{'movielabel'};

    if($s == Qt::Movie::SourceEmpty) {
	$movielabel->setText("Could not load\n" . MOVIEFILENAME);
	$movielabel->setAlignment(Qt::AlignCenter);
	$movielabel->setBackgroundColor($self->backgroundColor);
    } elsif($movielabel->movie()) {
	$movielabel->setBackgroundMode(Qt::Widget::NoBackground);
    }
}

sub checkBoxClicked {
    my $self = shift;
    my $id = shift;
    my($msg, $cb) = @$self->{'msg', 'cb'};
    my $chk = "";
    $chk .= $cb->[0]->isChecked() ? "r" : "-";
    $chk .= $cb->[1]->isChecked() ? "w" : "-";
    $chk .= $cb->[2]->isChecked() ? "x" : "-";
    $msg->setText("Check box $id clicked : $chk");
}

sub edComboBoxItemActivated {
    shift->{'msg'}->setText("Editable Combo Box set to " . shift);
}

sub radioButtonClicked {
    shift->{'msg'}->setText("Radio button #" . shift . " clicked");
}

sub listBoxItemSelected {
    shift->{'msg'}->setText("List box item " . shift . " selected");
}

sub sliderValueChanged {
    my $self = shift;
    my $value = shift;
    my $msg = $self->{'msg'};

    $msg->setText("Movie set to $value% of normal speed");
    $self->{'movie'}->setSpeed($value);
}

sub comboBoxItemActivated {
    my $self = shift;
    my $index = shift;
    my $msg = $self->{'msg'};

    $msg->setText("Combo box item $index activated");

    my(@coloridx) = (Qt::darkBlue, Qt::darkRed, Qt::darkGreen,
		     Qt::blue, Qt::red);

    Qt::Application::setWinStyleHighlightColor($coloridx[$index]);
}

sub lineEditTextChanged {
    shift->{'msg'}->setText("Line edit text: " . shift);
}

sub spinBoxValueChanged {
    shift->{'msg'}->setText("Spin box value: " . shift);
}

#
# All application events are passed throught this event filter.
# We're using it to display some information about a clicked
# widget (right mouse button + CTRL).
#


#{
#    my $identify_now = 1;
#    sub eventFilter {
#	my $self = shift;
#	my($obj, $event) = @_;
#
#	if($event->type() == Qt::Event_MouseButtonPress && $identify_now) {
#	    my $e = Qt::MouseEvent->cast($event);
#	    if($e->button() == Qt::RightButton &&
#	      ($e->state() & Qt::ControlButton) != 0) {
#		my $str = "The clicked widget is a\n";
#		$str .= $obj->className();
#		$str .= "\nThe widget's name is\n";
#		$str .= $obj->name() || "<no name>";
#		$identify_now = 0;
#	        Qt::MessageBox::message("Identify Widget", $str, 0, Qt::Widget->cast($obj));
#    }


package main;

use Qt 2.0;
import Qt::app;

$w = WidgetView->new;
$app->setMainWidget($w);
$w->show();
exit $app->exec();