=pod
=head1 NAME
examples/periodic.pl - A periodic table of elements
=head1 FEATURES
Demonstrates usage of grid widget
=cut
use strict;
use warnings;
use Prima qw(Application Grids);
my $scaling = $::application->uiScaling;
my $w = Prima::MainWindow-> create(
text => "Periodic table of elements",
size => [ map { $scaling * $_ } 45 * 14 + 5, 45 * 14 + 5],
);
my @layers = ( 2, 8, 8, 10, 9, 10, 9, 10, 9, 10, 10, 0, 14, 14);
my %colors = (
2 => {
0 => cl::Blue,
10 => cl::Red,
},
8 => {
0 => cl::Blue,
1 => cl::Blue,
10 => cl::Red,
default => 0x804000
},
9 => {
0 => cl::Black,
1 => cl::Black,
10 => cl::Red,
default => 0x804000
},
10 => {
0 => cl::Blue,
1 => cl::Blue,
default => cl::Black,
},
14 => {
default => cl::Green,
}
);
my %sides = (
'9:0' => 4, '9:1' => 4, '9:2' => 4,
'7:4' => 8, '8:4' => 8, '9:4' => 12,
'7:6' => 8, '8:6' => 8, '9:6' => 12,
'7:8' => 8, '8:8' => 8, '9:8' => 12,
'7:10' => 8, '8:10' => 8, '9:10' => 12,
'10:3' => 8, '10:5' => 8, '10:7' => 8, '10:9' => 8, '10:11' => 8,
'0:11' => 8, '1:11' => 8, '2:11' => 8, '3:11' => 8, '4:11' => 8,
'5:11' => 8, '6:11' => 8,
# '11:4' => 8, '12:4' => 8, '13:4' => 12,
# '10:5' => 12, '13:5' => 4, '13:6' => 4,
# '11:7' => 8, '12:7' => 8, '13:7' => 8,
);
package Periodic;
use vars qw(@ISA);
@ISA = qw(Prima::GridViewer);
my %elem_info = (
H => { atomic_number => 1, name => "Hydrogen", weight => "1.00794(7)", },
He => { atomic_number => 2, name => "Helium", weight => "4.002602(2)", },
Li => { atomic_number => 3, name => "Lithium", weight => "6.941(2)", },
Be => { atomic_number => 4, name => "Beryllium", weight => "9.012182(3)", },
B => { atomic_number => 5, name => "Boron", weight => "10.881(7)", },
C => { atomic_number => 6, name => "Carbon", weight => "12.0107(8)", },
N => { atomic_number => 7, name => "Nitrogen", weight => "14.00674(7)", },
O => { atomic_number => 8, name => "Oxygen", weight => "15.9994(3)", },
F => { atomic_number => 9, name => "Fluorine", weight => "18.9984032(5)", },
Ne => { atomic_number => 10, name => "Neon", weight => "20.1797(6)", },
Na => { atomic_number => 11, name => "Sodium", weight => "22.989770(2)", },
Mg => { atomic_number => 12, name => "Magnesium", weight => "24.3050(6)", },
Al => { atomic_number => 13, name => "Aluminium", weight => "26.981538(2)", },
Si => { atomic_number => 14, name => "Silicon", weight => "28.0855(3)", },
P => { atomic_number => 15, name => "Phosphorus", weight => "30.973761(2)", },
S => { atomic_number => 16, name => "Sulfur", weight => "32.066(6)", },
Cl => { atomic_number => 17, name => "Chlorine", weight => "35.4527(9)", },
Ar => { atomic_number => 18, name => "Argon", weight => "39.948(1)", },
K => { atomic_number => 19, name => "Potassium", weight => "39.0983(1)", },
Ca => { atomic_number => 20, name => "Calcium", weight => "40.078(4)", },
Sc => { atomic_number => 21, name => "Scandium", weight => "44.955910(8)", },
Ti => { atomic_number => 22, name => "Titanium", weight => "47.867(1)", },
V => { atomic_number => 23, name => "Vanadium", weight => "50.9415(1)", },
Cr => { atomic_number => 24, name => "Chromium", weight => "51.9961(6)", },
Mn => { atomic_number => 25, name => "Manganese", weight => "54.938049(9)", },
Fe => { atomic_number => 26, name => "Iron", weight => "55.845(2)", },
Co => { atomic_number => 27, name => "Cobalt", weight => "58.933200(9)", },
Ni => { atomic_number => 28, name => "Nickel", weight => "58.6934(2)", },
Cu => { atomic_number => 29, name => "Copper", weight => "63.546(3)", },
Zn => { atomic_number => 30, name => "Zinc", weight => "65.39(2)", },
Ga => { atomic_number => 31, name => "Gallium", weight => "69.723(1)", },
Ge => { atomic_number => 32, name => "Germanium", weight => "72.61(2)", },
As => { atomic_number => 33, name => "Arsenic", weight => "74.92160(2)", },
Se => { atomic_number => 34, name => "Selenium", weight => "78.96(3)", },
Br => { atomic_number => 35, name => "Bromine", weight => "79.904(1)", },
Kr => { atomic_number => 36, name => "Krypton", weight => "83.80(1)", },
Rb => { atomic_number => 37, name => "Rubidium", weight => "85.4678(3)", },
Sr => { atomic_number => 38, name => "Strontium", weight => "87.62(1)", },
Y => { atomic_number => 39, name => "Yttrium", weight => "88.90585(2)", },
Zr => { atomic_number => 40, name => "Zirconium", weight => "91.224(2)", },
Nb => { atomic_number => 41, name => "Niobium", weight => "92.90638(2)", },
Mo => { atomic_number => 42, name => "Molybdenum", weight => "95.94(1)", },
Tc => { atomic_number => 43, name => "Technetium", weight => "[97.9072]", },
Ru => { atomic_number => 44, name => "Ruthenium", weight => "101.07(2)", },
Rh => { atomic_number => 45, name => "Rhodium", weight => "102.90550(2)", },
Pd => { atomic_number => 46, name => "Palladium", weight => "106.42(1)", },
Ag => { atomic_number => 47, name => "Silver", weight => "107.8682(2)", },
Cd => { atomic_number => 48, name => "Cadmium", weight => "112.411(8)", },
In => { atomic_number => 49, name => "Indium", weight => "114.818(3)", },
Sn => { atomic_number => 50, name => "Tin", weight => "118.710(7)", },
Sb => { atomic_number => 51, name => "Antimony", weight => "121.760(1)", },
Te => { atomic_number => 52, name => "Tellurium", weight => "127.60(3)", },
I => { atomic_number => 53, name => "Iodine", weight => "126.90447(3)", },
Xe => { atomic_number => 54, name => "Xenon", weight => "131.29(2)", },
Cs => { atomic_number => 55, name => "Caesium", weight => "132.90545(2)", },
Ba => { atomic_number => 56, name => "Barium", weight => "137.327(7)", },
La => { atomic_number => 57, name => "Lanthanum", weight => "138.9055(2)", },
Hf => { atomic_number => 72, name => "Hafnium", weight => "178.49(2)", },
Ta => { atomic_number => 73, name => "Tantalum", weight => "180.9479(1)", },
W => { atomic_number => 74, name => "Tungsten", weight => "183.84(1)", },
Re => { atomic_number => 75, name => "Rhenium", weight => "186.207(1)", },
Os => { atomic_number => 76, name => "Osmium", weight => "190.23(3)", },
Ir => { atomic_number => 77, name => "Iridium", weight => "192.217(3)", },
Pt => { atomic_number => 78, name => "Platinum", weight => "195.078(2)", },
Au => { atomic_number => 79, name => "Gold", weight => "196.96655(2)", },
Hg => { atomic_number => 80, name => "Mercury", weight => "200.59(2)", },
Tl => { atomic_number => 81, name => "Thallium", weight => "204.3383(2)", },
Pb => { atomic_number => 82, name => "Lead", weight => "207.2(1)", },
Bi => { atomic_number => 83, name => "Bismuth", weight => "208.98038(2)", },
Po => { atomic_number => 84, name => "Polonium", weight => "[208.9824]", },
At => { atomic_number => 85, name => "Astatine", weight => "[209.9871]", },
Rn => { atomic_number => 86, name => "Radon", weight => "[222.0176]", },
Fr => { atomic_number => 87, name => "Francium", weight => "[223.0197]", },
Ra => { atomic_number => 88, name => "Radium", weight => "[226.0254]", },
Ac => { atomic_number => 89, name => "Actinium", weight => "[227.0277]", },
Rf => { atomic_number => 104, name => "Rutherfordium", weight => "[263.1125]", },
Db => { atomic_number => 105, name => "Dubnium", weight => "[262.1144]", },
Sg => { atomic_number => 106, name => "Seaborgium", weight => "[266.1219]", },
Bh => { atomic_number => 107, name => "Bohrium", weight => "[264.1247]", },
Hs => { atomic_number => 108, name => "Hassium", weight => "[269.1341]", },
Mt => { atomic_number => 109, name => "Meitnerium", weight => "[268.1388]", },
Ds => { atomic_number => 110, name => "Darmstadtium", weight => "[272.1463]", },
Rg => { atomic_number => 111, name => "Roentgenium", weight => "[282]", },
Cn => { atomic_number => 112, name => "Copenicium", weight => "[285]", },
Nh => { atomic_number => 113, name => "Nihonium", weight => "[286]", },
Fl => { atomic_number => 114, name => "Flerovium", weight => "[289]", },
Mc => { atomic_number => 115, name => "Moscovium", weight => "[290]", },
Lv => { atomic_number => 116, name => "Livermorium", weight => "[293]", },
Ts => { atomic_number => 117, name => "Tennessine", weight => "[294]", },
Og => { atomic_number => 118, name => "Oganesson", weight => "[294]", },
Ce => { atomic_number => 58, name => "Cerium", weight => "140.116(1)", },
Pr => { atomic_number => 59, name => "Praseodymium", weight => "140.90765(2)", },
Nd => { atomic_number => 60, name => "Neodymium", weight => "144.24(3)", },
Pm => { atomic_number => 61, name => "Promethium", weight => "[144.9127]", },
Sm => { atomic_number => 62, name => "Samarium", weight => "150.36(3)", },
Eu => { atomic_number => 63, name => "Europium", weight => "151.964(1)", },
Gd => { atomic_number => 64, name => "Gadolinium", weight => "157.25(3)", },
Tb => { atomic_number => 65, name => "Terbium", weight => "158.92534(2)", },
Dy => { atomic_number => 66, name => "Dysprosium", weight => "162.50(3)", },
Ho => { atomic_number => 67, name => "Holmium", weight => "164.93032(2)", },
Er => { atomic_number => 68, name => "Erbium", weight => "167.26(3)", },
Tm => { atomic_number => 69, name => "Thulium", weight => "168.93421(2)", },
Yb => { atomic_number => 70, name => "Ytterbium", weight => "173.04(3)", },
Lu => { atomic_number => 71, name => "Lutetium", weight => "174.967(1)", },
Th => { atomic_number => 90, name => "Thorium", weight => "232.0381(1)", },
Pa => { atomic_number => 91, name => "Protactinium", weight => "231.03588(2)", },
U => { atomic_number => 92, name => "Uranium", weight => "238.0289(1)", },
Np => { atomic_number => 93, name => "Neptunium", weight => "[237.0482]", },
Pu => { atomic_number => 94, name => "Plutonium", weight => "[244.0642]", },
Am => { atomic_number => 95, name => "Americium", weight => "[243.0614]", },
Cm => { atomic_number => 96, name => "Curium", weight => "[247.0703]", },
Bk => { atomic_number => 97, name => "Berkelium", weight => "[247.0703]", },
Cf => { atomic_number => 98, name => "Californium", weight => "[251.0796]", },
Es => { atomic_number => 99, name => "Einsteinium", weight => "[252.0830]", },
Fm => { atomic_number => 100, name => "Fermium", weight => "[257.0951]", },
Md => { atomic_number => 101, name => "Mendelevium", weight => "[258.0984]", },
No => { atomic_number => 102, name => "Nobelium", weight => "[259.1011]", },
Lr => { atomic_number => 103, name => "Lawrencium", weight => "[262.110]", },
);
sub on_keydown
{
my $self = shift;
local $self->{inside_keydown} = 1;
$self->SUPER::on_keydown(@_);
}
sub focusedCell
{
return $_[0]-> SUPER::focusedCell unless $#_;
my ($self,$x,$y) = @_;
($x, $y) = @$x if !defined $y && ref($x) eq 'ARRAY';
my (@last, @dir);
if ( $self-> {inside_keydown}) {
@last = $self->SUPER::focusedCell;
@dir = ($x - $last[0], $y - $last[1]);
@dir = () unless
(abs($dir[0]) == 1 && $dir[1] == 0) ||
(abs($dir[1]) == 1 && $dir[0] == 0);
}
if ( @dir ) {
my $text = $self-> {cells}-> [$last[1]]-> [$last[0]];
if ( $dir[0] == 1 ) {
if ($text eq 'La' ) {
($x, $y) = (0, 12);
} elsif ( $text eq 'Ac') {
($x, $y) = (0, 13);
} elsif ( $text eq 'Lu') {
($x, $y) = (3, 7);
} elsif ( $text eq 'Lr') {
($x, $y) = (3, 9);
}
} elsif ( $dir[0] == -1 ) {
if ($text eq 'Hf' ) {
($x, $y) = (13, 12);
} elsif ( $text eq 'Rf') {
($x, $y) = (13, 13);
} elsif ( $text eq 'Ce') {
($x, $y) = (2, 7);
} elsif ( $text eq 'Th') {
($x, $y) = (2, 9);
}
}
}
unless ($y >= 0 && $x >= 0 && $self-> {cells}-> [$y] &&
$self-> {cells}-> [$y]-> [$x] && length $self-> {cells}-> [$y]-> [$x]
) {
return unless @dir;
my $n = 9;
my @p = ($x, $y);
my $c = $self->{cells};
while ($n-- > 0) {
$p[$_] += $dir[$_] for 0,1;
last if $p[0] < 0 || $p[1] < 0 || $p[1] >= @$c || $p[0] >= @{$c->[$p[1]]};
my $item = $c-> [$p[1]]-> [$p[0]];
next unless defined($item) and defined ($elem_info{$item}-> {name});
($x,$y) = @p;
goto SETFOC;
}
if ( $dir[0] == 1 && $y < $#$c ) {
my $item = $c-> [$y + 1]-> [0];
if ( defined($item) and defined ($elem_info{$item}-> {name})) {
$x = 0;
$y++;
goto SETFOC;
}
} elsif ( $dir[0] == -1 && $y > 0 ) {
my $n = 5;
my $nx = @{$c->[$y - 1]} - 1;
while ( $n-- > 0 ) {
my $item = $c-> [$y - 1]-> [$nx];
if ( defined($item) and defined ($elem_info{$item}-> {name})) {
$x = $nx;
$y--;
goto SETFOC;
}
$nx--;
}
}
return;
}
SETFOC:
$self-> SUPER::focusedCell( $x, $y);
}
my @small_font_metrics;
my $g = $w-> insert( Periodic =>
origin => [0,0],
size => [$w-> size],
growMode => gm::Client,
cells => [
['H', ('')x9, 'He', ('')x3],
[qw(Li Be B C N O F), ('')x3,'Ne', ('')x3],
[qw(Na Mg Al Si P S Cl), ('')x3,'Ar', ('')x3],
[qw(K Ca Sc Ti V Cr Mn Fe Co Ni), ('')x4],
[qw(Cu Zn Ga Ge As Se Br), ('')x3,'Kr', ('')x3],
[qw(Rb Sr Y Zr Nb Mo Tc Ru Rh Pd), ('')x4],
[qw(Ag Cd In Sn Sb Te I), ('')x3,'Xe', ('')x3],
[qw(Cs Ba La Hf Ta W Re Os Ir Pt), ('')x4],
[qw(Au Hg Tl Pb Bi Po At), ('')x3,'Rn', ('')x3],
[qw(Fr Ra Ac Rf Db Sg Bh Hs Mt Ds), ('')x4],
[qw(Rg Cn Nh Fl Mc Lv Ts), ('')x3,'Og', ('')x3],
[('') x 14],
[qw(Ce Pr Nd Pm Sm Eu Gd Tb Dy Ho Er Tm Yb Lu)],
[qw(Th Pa U Np Pu Am Cm Bk Cf Es Fm Md No Lr)],
],
drawHGrid => 0,
drawVGrid => 0,
constantCellWidth => int( 45 * $scaling + .5),
constantCellHeight => int( 45 * $scaling + .5),
multiSelect => 0,
onDrawCell => sub {
my ( $self, $canvas,
$column, $row, $indent,
$sx1, $sy1, $sx2, $sy2,
$cx1, $cy1, $cx2, $cy2,
$selected, $focused, $prelight) = @_;
$canvas-> clear($sx1, $sy1, $sx2, $sy2);
my $item = $self-> {cells}-> [$row]-> [$column];
my $color = $colors{$layers[$row]};
if ( length $item) {
return unless $color;
return unless defined
($color = ( exists $color-> {$column}) ?
$color-> {$column} :
$color-> {default});
$canvas-> color( cl::Black);
$canvas-> rectangle( $cx1-1, $cy1-1, $cx2, $cy2);
if ( $focused || $prelight ) {
$self-> draw_item_background($canvas, $cx1, $cy1, $cx2-1, $cy2-1, $prelight, $focused ? $self-> hiliteBackColor : cl::Back);
$canvas-> backColor( cl::Back );
$canvas-> color( $focused ? $self-> hiliteColor : cl::Fore);
} else {
$canvas-> color( $color);
}
$canvas-> text_out( $item, $cx1 + 10 * $scaling, $cy1 + 10 * $scaling);
my $f = $canvas-> font;
$canvas-> font( height => 12 * $scaling );
@small_font_metrics = ( $canvas-> get_text_width('3'), $f-> height)
unless @small_font_metrics;
my $text = $elem_info{$item}-> {atomic_number}||"";
$canvas-> text_out( $text,
$cx2 - $small_font_metrics[0] * length($text) - 4,
$cy2 - $small_font_metrics[1] - 4);
$canvas-> font($f);
$canvas-> rect_focus( $sx1, $sy1, $sx2-1, $sy2-1) if $focused;
} elsif ( exists $sides{"$column:$row"}) {
my $side = $sides{"$column:$row"};
$canvas-> color( cl::Black);
$canvas-> line( $cx1-1,$cy1-1,$cx2,$cy1-1 ) if $side & 1;
$canvas-> line( $cx1-1,$cy1-1,$cx1-1,$cy2 ) if $side & 2;
$canvas-> line( $cx2,$cy1-1,$cx2,$cy2 ) if $side & 4;
$canvas-> line( $cx1-1,$cy2,$cx2,$cy2 ) if $side & 8;
}
},
onClick => sub {
my ($self) = @_;
my @foc = $self-> focusedCell;
my $text = $self-> {cells}-> [$foc[1]]-> [$foc[0]];
return unless $text;
if ($text eq "La") {
$self-> focusedCell(0, 11);
} elsif ($text eq "Ac") {
$self-> focusedCell(0, 12);
}
},
onSelectCell => sub {
my ( $self, $col, $row) = @_;
my $item = $self-> {cells}-> [$row]-> [$col];
return unless defined($item) and defined ($elem_info{$item}-> {name});
$w-> text("Periodic table of elements - $elem_info{$item}->{name} $elem_info{$item}->{atomic_number} $elem_info{$item}->{weight}");
},
);
run Prima;