head 1.29; access; symbols AS_CUI_0_5_0:1.28 AS_AFTER_RESTRUCTURING:1.4; locks; strict; comment @# @; 1.29 date 2002.12.18.11.18.20; author rse; state dead; branches; next 1.28; 1.28 date 2002.12.17.13.47.50; author thl; state Exp; branches; next 1.27; 1.27 date 2002.12.17.13.39.18; author thl; state Exp; branches; next 1.26; 1.26 date 2002.12.17.10.50.00; author thl; state Exp; branches; next 1.25; 1.25 date 2002.12.11.14.02.08; author thl; state Exp; branches; next 1.24; 1.24 date 2002.12.11.13.31.50; author thl; state Exp; branches; next 1.23; 1.23 date 2002.12.11.11.12.30; author thl; state Exp; branches; next 1.22; 1.22 date 2002.12.11.10.21.43; author thl; state Exp; branches; next 1.21; 1.21 date 2002.12.10.15.09.55; author thl; state Exp; branches; next 1.20; 1.20 date 2002.12.10.14.17.31; author thl; state Exp; branches; next 1.19; 1.19 date 2002.12.10.13.37.43; author thl; state Exp; branches; next 1.18; 1.18 date 2002.12.10.10.26.36; author thl; state Exp; branches; next 1.17; 1.17 date 2002.12.05.15.00.05; author thl; state Exp; branches; next 1.16; 1.16 date 2002.12.05.14.45.59; author thl; state Exp; branches; next 1.15; 1.15 date 2002.12.05.14.04.57; author thl; state Exp; branches; next 1.14; 1.14 date 2002.12.04.14.59.08; author thl; state Exp; branches; next 1.13; 1.13 date 2002.12.04.13.42.02; author thl; state Exp; branches; next 1.12; 1.12 date 2002.12.04.09.56.42; author thl; state Exp; branches; next 1.11; 1.11 date 2002.12.03.19.21.11; author thl; state Exp; branches; next 1.10; 1.10 date 2002.12.03.12.09.19; author thl; state Exp; branches; next 1.9; 1.9 date 2002.12.03.10.33.50; author thl; state Exp; branches; next 1.8; 1.8 date 2002.12.03.09.41.16; author thl; state Exp; branches; next 1.7; 1.7 date 2002.12.03.08.30.20; author thl; state Exp; branches; next 1.6; 1.6 date 2002.12.02.13.58.33; author thl; state Exp; branches; next 1.5; 1.5 date 2002.12.02.13.46.27; author thl; state Exp; branches; next 1.4; 1.4 date 2002.11.27.15.53.11; author thl; state Exp; branches; next 1.3; 1.3 date 2002.11.27.14.34.04; author thl; state Exp; branches; next 1.2; 1.2 date 2002.11.27.13.02.41; author thl; state Exp; branches; next 1.1; 1.1 date 2002.11.26.15.44.21; author thl; state Exp; branches; next ; desc @@ 1.29 log @polish for initial release @ text @## ## Spreadsheet ## package matrix; #this is a direct descendant from basic research at /u/thl/research/SAVE-cuiA.pl use strict; use Curses; #OpenPKG perl-curses use Curses::UI; #OpenPKG perl-curses my $matrixdata = {}; my $verbose = 0; my $breakout = 0; #flag to break out from inner loop my $vcscroll = 0; #callback tells inner loop to scroll wholly view n steps horizontally (neg = left, pos = right) my $vrscroll = 0; #callback tells inner loop to scroll wholly view n steps vertically (neg = up, pos = down) my $datacoll = 0; #callback tells inner loop to redraw wholly view while trying to reuse widgets if size permits my $vcpos = 0; #callback tells inner loop to scroll wholly view horizontally (neg = left, pos = right) my $vrpos = 0; #callback tells inner loop to scroll wholly view vertically (neg = up, pos = down) my $editcell = 0; my $widget = {}; my $matrixwidget = {}; my $matrixwidgetvisualcell = {}; my $matrixwidgetdatacell = {}; my $cui = undef; my @@keys_move = ( #FIXME now we catch all chars not only keys_move. So this remains for documenation only. "h", KEY_LEFT(), "j", KEY_DOWN(), "k", KEY_UP(), "l", KEY_RIGHT(), KEY_NPAGE(), KEY_PPAGE(), KEY_HOME(), KEY_END(), KEY_ENTER(), #same as F2 KEY_F(1), #help KEY_F(2), #edit "o", KEY_F(3), #on a new line "O", KEY_F(4), #On a new line "d", KEY_F(5), #delete line #KEY_F(6), #copy line KEY_F(7), #column show/hide KEY_F(8), #column sorting KEY_F(9), #column shrink to min KEY_F(10), #column shrink KEY_F(11), #column grow KEY_F(12), #column grow to max "1", #scroll screen up to the top and place cursor on the first line "G", #scroll screen down to the bottom and place cursor on the last line "\cU", #scroll screen up, cursor stays at current position KEY_DC(), #scroll screen down, cursor stays at current position "^", #scroll screen left to the border and place cursor on the first cell "\$", #scroll screen right to the border and place cursor on the last cell "y", #yank "p", #paste "P" #Paste ); sub rightmostvisiblefit { my $c; my $lastc; my $wremain; my $realw; my $visualc; # find leftmost column for the rightmost visible fit $visualc = 0; $lastc = $matrixdata->{"Columns"} - 1; $wremain = $matrixwidget->{"Width"}; #printf STDERR "rightmostvisiblefit lastc=%d\n", (defined $lastc) ? $lastc : "undef"; #printf STDERR "rightmostvisiblefit wremain=%d\n", (defined $wremain) ? $wremain : "undef"; for ($c = -1; $c >= -1; $c = $c == -1 ? $lastc: --$c) { if (not $matrixdata->{"CH.$c"}->{"Colhide"}) { my $w = $matrixdata->{"CH.$c"}->{"Width"}; $realw = $w + $matrixdata->{"CH.$c"}->{"Colgap"}; $wremain -= $realw; $visualc++ if ($c >= 0 and $wremain >= 0); } last if ($wremain < 0); } $c++; #printf STDERR "rightmostvisiblefit c=%d, visualc=%d\n", $c, $visualc; return ($c, $visualc); } sub bottommostvisiblefit { my $r; my $lastr; my $hremain; my $realh; my $visualr; # find topmost column for the bottommost visible fit $visualr = 0; $lastr = $matrixdata->{"Rows"} - 1; $hremain = $matrixwidget->{"Height"}; #printf STDERR "bottommostvisiblefit lastr=%d\n", (defined $lastr) ? $lastr : "undef"; #printf STDERR "bottommostvisiblefit hremain=%d\n", (defined $hremain) ? $hremain : "undef"; for ($r = -1; $r >= -1; $r = $r == -1 ? $lastr: --$r) { if (not $matrixdata->{"RH.$r"}->{"Rowhide"}) { my $h = $matrixdata->{"RH.$r"}->{"Height"}; $realh = $h + $matrixdata->{"RH.$r"}->{"Rowgap"}; $hremain -= $realh; $visualr++ if ($r >= 0 and $hremain >= 0); } last if ($hremain < 0); } $r++; #printf STDERR "bottommostvisiblefit r=%d, visualr=%d\n", $r, $visualr; return ($r, $visualr); } sub optimalcolwidth { my $x; my $c; my $cols; my $lastc; my $visualc; # column heading, sizing, counting and cachetag creation $cols = $matrixdata->{"Columns"}; $x = $matrixwidget->{"XOffset"}; $visualc = 0; my $wremain = $matrixwidget->{"Width"}; my $wweight = 0; for ($c = -1; $c < $cols; $c = $c >= 0 ? ++$c : $matrixwidget->{"FirstVisualCol"}) { next if ($matrixdata->{"CH.$c"}->{"Colhide"}); my $w = $matrixdata->{"CH.$c"}->{"Width"}; my $realw = $w + $matrixdata->{"CH.$c"}->{"Colgap"}; last if ($wremain < $realw); if ($c >= 0) { $visualc++; } $x += $realw; $wremain -= $realw; if ($matrixdata->{"CH.$c"}->{"Widthmin"} == $matrixdata->{"CH.$c"}->{"Widthmax"}) { $matrixdata->{"CH.$c"}->{"Widthweight"} = 0; } $matrixdata->{"CH.$c"}->{"Widthweight"} = 1 unless (defined $matrixdata->{"CH.$c"}->{"Widthweight"}); $wweight += $matrixdata->{"CH.$c"}->{"Widthweight"} } $wweight = 1 if ($wweight == 0); #if no weight was given at all, treat all equal and avoid div by zero $lastc = $c; if ($wremain >= 1) { my $wfraction = $wremain / $wweight; my $wfractrem = 0; $x = $matrixwidget->{"XOffset"}; my $wremain = $matrixwidget->{"Width"}; my $wweight = 0; for ($c = -1; $c < $cols; $c = $c >= 0 ? ++$c : $matrixwidget->{"FirstVisualCol"}) { next if ($matrixdata->{"CH.$c"}->{"Colhide"}); my $w = $matrixdata->{"CH.$c"}->{"Width"}; my $fadditional = $matrixdata->{"CH.$c"}->{"Widthweight"} * $wfraction + $wfractrem; my $iadditional = int($fadditional); $wfractrem = $fadditional - $iadditional; $w += $iadditional; my $realw = $w + $matrixdata->{"CH.$c"}->{"Colgap"}; $matrixdata->{"CH.$c"}->{"Width"} = $w; last if ($wremain < $realw); if ($c >= 0) { $visualc++; } $x += $realw; $wremain -= $realw; } } $matrixwidget->{"NumVisualCol"} = $visualc; return; } sub optimalrowheight { my $y; my $r; my $rows; my $lastr; my $visualr; # row heading, sizing, counting and cachetag creation $rows = $matrixdata->{"Rows"}; $y = $matrixwidget->{"YOffset"}; $visualr = 0; my $hremain = $matrixwidget->{"Height"}; my $hweight = 0; for ($r = -1; $r < $rows; $r = $r >= 0 ? ++$r : $matrixwidget->{"FirstVisualRow"}) { next if ($matrixdata->{"RH.$r"}->{"Rowhide"}); my $h = $matrixdata->{"RH.$r"}->{"Height"}; my $realh = $h + $matrixdata->{"RH.$r"}->{"Rowgap"}; last if ($hremain < $realh); if ($r >= 0) { $visualr++; } $y += $realh; $hremain -= $realh; if ($matrixdata->{"RH.$r"}->{"Heightmin"} == $matrixdata->{"RH.$r"}->{"Heightmax"}) { $matrixdata->{"RH.$r"}->{"Heightweight"} = 0; } $matrixdata->{"RH.$r"}->{"Heightweight"} = 1 unless (defined $matrixdata->{"RH.$r"}->{"Heightweight"}); $hweight += $matrixdata->{"RH.$r"}->{"Heightweight"} } $hweight = 1 if ($hweight == 0); #if no weight was given at all, treat all equal and avoid div by zero $lastr = $r; if ($hremain >= 1) { my $hfraction = $hremain / $hweight; my $hfractrem = 0; $y = $matrixwidget->{"YOffset"}; my $hremain = $matrixwidget->{"Height"}; my $hweight = 0; for ($r = -1; $r < $rows; $r = $r >= 0 ? ++$r : $matrixwidget->{"FirstVisualRow"}) { next if ($matrixdata->{"RH.$r"}->{"Rowhide"}); my $h = $matrixdata->{"RH.$r"}->{"Height"}; my $fadditional = $matrixdata->{"RH.$r"}->{"Heightweight"} * $hfraction + $hfractrem; my $iadditional = int($fadditional); $hfractrem = $fadditional - $iadditional; $h += $iadditional; my $realh = $h + $matrixdata->{"RH.$r"}->{"Rowgap"}; $matrixdata->{"RH.$r"}->{"Height"} = $h; last if ($hremain < $realh); if ($r >= 0) { $visualr++; } $y += $realh; $hremain -= $realh; } } $matrixwidget->{"NumVisualRow"} = $visualr; return; } sub colheading { my ($doit) = @@_; my $x; my $y; my $c; my $cols; my $dataxoffset; my $lastc; my $visualc; my $colcachetag; # column heading, sizing, counting and cachetag creation $cols = $matrixdata->{"Columns"}; $dataxoffset = 0; $x = $matrixwidget->{"XOffset"}; $y = $matrixwidget->{"YOffset"}; $colcachetag = ''; $visualc = 0; my $wremain = $matrixwidget->{"Width"}; for ($c = -1; $c < $cols; $c = $c >= 0 ? ++$c : $matrixwidget->{"FirstVisualCol"}) { next if ($matrixdata->{"CH.$c"}->{"Colhide"}); my $w = $matrixdata->{"CH.$c"}->{"Width"}; my $realw = $w + $matrixdata->{"CH.$c"}->{"Colgap"}; my $realh = $matrixdata->{"RH.-1"}->{"Heigth"}; last if ($wremain < $realw); if ($c >= 0) { $dataxoffset = $x if ($dataxoffset == 0); $matrixwidget->{"CH.$visualc"} = $widget->{'container'}->add("CH.$visualc", 'Label', -x => $x, -y => $y, -text => $matrixdata->{"CH.$c"}->{"Labelhide"} ? " " : $matrixdata->{"CH.$c"}->{"Label"}, -width => $realw, -height => $realh ) if ($doit); $visualc++; $colcachetag .= ".$realw"; } $x += $realw; $wremain -= $realw; } $lastc = $c; if ($wremain >= 1) { $matrixwidget->{"CH.fillright"} = $widget->{'container'}->add("CH.fillright", 'Label', -x => $x, -y => $y, -text => '#'x$wremain, -width => $wremain, -heigth => 1 ) if ($doit); } return ($dataxoffset, $lastc, $colcachetag); } sub rowheading { my ($doit) = @@_; my $x; my $y; my $r; my $rows; my $datayoffset; my $lastr; my $visualr; my $rowcachetag; # row heading, sizing, counting and cachetag creation $rows = $matrixdata->{"Rows"}; $datayoffset = 0; $x = $matrixwidget->{"XOffset"}; $y = $matrixwidget->{"YOffset"}; $rowcachetag = ''; $visualr = 0; my $hremain = $matrixwidget->{"Height"}; for ($r = -1; $r < $rows; $r = $r >= 0 ? ++$r : $matrixwidget->{"FirstVisualRow"}) { next if ($matrixdata->{"RH.$r"}->{"Rowhide"}); my $h = $matrixdata->{"RH.$r"}->{"Height"}; my $realw = $matrixdata->{"CH.-1"}->{"Width"}; my $realh = $h + $matrixdata->{"RH.$r"}->{"Rowgap"}; last if ($hremain < $realh); if ($r >= 0) { $datayoffset = $y if ($datayoffset == 0); $matrixwidget->{"RH.$visualr"} = $widget->{'container'}->add("RH.$visualr", 'Label', -x => $x, -y => $y, -text => $matrixdata->{"RH.$r"}->{"Labelhide"} ? " " : $matrixdata->{"RH.$r"}->{"Label"}, -width => $realw, -height => $realh ) if ($doit); $visualr++; $rowcachetag .= ".$realh"; } $y += $realh; $hremain -= $realh; } $lastr = $r; if ($hremain >= 1) { $matrixwidget->{"RH.fillbottom"} = $widget->{'container'}->add("RH.fillbottom", 'Label', -x => $x, -y => $y, -text => '#'x$hremain, -width => 1, -height => $hremain ) if($doit); } return ($datayoffset, $lastr, $rowcachetag); } sub updatecolheading { my $c; my $n; my $visualc; # update column heading label $visualc = 0; $c = $matrixwidget->{"FirstVisualCol"}; $n = $matrixwidget->{"NumVisualCol"}; for (; $n > 0; $c++) { next if ($matrixdata->{"CH.$c"}->{"Colhide"}); $n--; die "col Baeh!" if (not defined $matrixwidget->{"CH.$visualc"}); $matrixwidget->{"CH.$visualc"}->{-text} = $matrixdata->{"CH.$c"}->{"Labelhide"} ? " " : $matrixdata->{"CH.$c"}->{"Label"}; $matrixwidget->{"CH.$visualc"}->draw; #$matrixwidget->{"CH.$visualc"}->focus; $visualc++; } } sub updaterowheading { my $r; my $n; my $visualr; # update row heading label $visualr = 0; $r = $matrixwidget->{"FirstVisualRow"}; $n = $matrixwidget->{"NumVisualRow"}; for (; $n > 0; $r++) { next if ($matrixdata->{"RH.$r"}->{"Rowhide"}); $n--; die "row Baeh!" if (not defined $matrixwidget->{"RH.$visualr"}); $matrixwidget->{"RH.$visualr"}->{-text} = $matrixdata->{"RH.$r"}->{"Labelhide"} ? " " : $matrixdata->{"RH.$r"}->{"Label"}; $matrixwidget->{"RH.$visualr"}->draw; #$matrixwidget->{"RH.$visualr"}->focus; $visualr++; } } sub newmatrixwidget { my ($dc, $dr, $vc, $vr) = @@_; $matrixwidget->{"XOffset"} = 0; #horizontal position relative to screen $matrixwidget->{"YOffset"} = 0; #vertical position relative to screen $matrixwidget->{"Width"} = $widget->{'container'}->width - $matrixwidget->{"XOffset"}; $matrixwidget->{"Height"} = $widget->{'container'}->height - $matrixwidget->{"YOffset"}; $matrixwidget->{"FirstVisualCol"} = $dc || 0; #leftmost data column presented on screen $matrixwidget->{"FirstVisualRow"} = $dr || 0; #topmost data row presented on screen $matrixwidget->{"Cursorcol"} = $vc || 0; #cursor column $matrixwidget->{"Cursorcol"} = $vr || 0; #cursor row $matrixwidget->{"NumVisualCol"} = undef; #number of visible column (calculated later) $matrixwidget->{"NumVisualRow"} = undef; #number of visible row (calculated later) $matrixwidget->{"Cachetag"} = undef; #tracks if widgets can be reused (must start undefined) } sub layoutmatrixwidget { my ($dc, $dr, $vc, $vr) = @@_; $matrixwidget->{"FirstVisualCol"} = $dc if (defined $dc); #leftmost data column presented on screen $matrixwidget->{"FirstVisualRow"} = $dr if (defined $dr); #topmost data row presented on screen $matrixwidget->{"Cursorcol"} = $vc if (defined $vc); #cursor column $matrixwidget->{"Cursorrow"} = $vr if (defined $vr); #cursor row my $c; my $r; my $x; my $y; my $lastc; my $lastr; my $dataxoffset; my $datayoffset; my $colcachetag; my $rowcachetag; my $cachetag; my $cachehit; $cachehit = 0; if (defined $matrixwidget->{"Cachetag"}) { ($dataxoffset, $lastc, $colcachetag) = &colheading(0); ($datayoffset, $lastr, $rowcachetag) = &rowheading(0); $cachetag = $colcachetag . '\\' . $rowcachetag; if ($cachetag eq $matrixwidget->{"Cachetag"}) { $cachehit = 1; } else { &destroymatrixwidgetcells(); } } else { &optimalcolwidth(); &optimalrowheight(); } if (not $cachehit) { ($dataxoffset, $lastc, $colcachetag) = &colheading(1); ($datayoffset, $lastr, $rowcachetag) = &rowheading(1); $cachetag = $colcachetag . '\\' . $rowcachetag; $matrixwidget->{"Cachetag"} = $cachetag; } # now do the matrix content my $visualr; my $visualc; $y = $datayoffset; $visualr = 0; for ($r = $matrixwidget->{"FirstVisualRow"}; $r < $lastr; ++$r) { next if ($matrixdata->{"RH.$r"}->{"Rowhide"}); my $h = $matrixdata->{"RH.$r"}->{"Height"}; my $realh = $h + $matrixdata->{"RH.$r"}->{"Rowgap"}; $x = $dataxoffset; $visualc = 0; for ($c = $matrixwidget->{"FirstVisualCol"}; $c < $lastc; ++$c) { next if ($matrixdata->{"CH.$c"}->{"Colhide"}); my $w = $matrixdata->{"CH.$c"}->{"Width"}; my $realw = $w + $matrixdata->{"CH.$c"}->{"Colgap"}; if (not $cachehit) { $matrixwidget->{"VC.$visualc.$visualr"} = $widget->{'container'}->add("VC.$visualc.$visualr", 'TextEntry', -x => $x, -y => $y, -text => (defined $matrixdata->{"CD.$c.$r"}->{"Data"}) ? $matrixdata->{"CD.$c.$r"}->{"Data"} : "", -width => $realw, #FIXME -height => $realh, -maxlength => $matrixdata->{"CH.$c"}->{"Widthmax"} #-maxdown => $matrixdata->{"RH.$r"}->{"Heightmax"} ); $matrixwidgetvisualcell->{$matrixwidget->{"VC.$visualc.$visualr"}} = [ $visualc, $visualr ]; } else { $matrixwidget->{"VC.$visualc.$visualr"}->{-text} = (defined $matrixdata->{"CD.$c.$r"}->{"Data"}) ? $matrixdata->{"CD.$c.$r"}->{"Data"} : ""; } $matrixwidgetdatacell->{$matrixwidget->{"VC.$visualc.$visualr"}} = [ $c, $r ]; $visualc++; $x += $realw; } $visualr++; $y += $realh; } $matrixwidget->{"NumVisualCol"} = $visualc; $matrixwidget->{"NumVisualRow"} = $visualr; &updatecolheading(); &updaterowheading(); # key bindings and event handling if (not $cachehit) { for ($c = 0; $c < $visualc; $c++) { for ($r = 0; $r < $visualr; $r++) { $matrixwidget->{"VC.$c.$r"}->set_binding(\&tabbinder, "\cI", KEY_ENTER(), KEY_F(2)); $matrixwidget->{"VC.$c.$r"}->set_event("-onfocus", sub { my $this = shift; my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; $matrixwidget->{"VC.$vc.$vr"}->{-canvasscr}->standout unless($editcell); if (defined $matrixdata->{"CD.$dc.$dr"}->{"Focuscallback"}) { &{$matrixdata->{"CD.$dc.$dr"}->{"Focuscallback"}}($matrixwidget, $dc, $dr, $vc, $vr); } } ); $matrixwidget->{"VC.$c.$r"}->set_event("-onblur", sub { my $this = shift; my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; $matrixwidget->{"VC.$vc.$vr"}->{-canvasscr}->standend; if ($editcell) { if (defined $matrixdata->{"CD.$dc.$dr"}->{"Blurcallback"}) { $datacoll = &{$matrixdata->{"CD.$dc.$dr"}->{"Blurcallback"}}($matrixwidget, $dc, $dr, $vc, $vr); } } $editcell = 0; } ); } } } } sub tabbinder { my $this = shift; my $key = shift; $key = "\cD" if ($key == KEY_DC()); #make CTRL-D a normal key my $nvc = $matrixwidget->{"NumVisualCol"} - 1; my $nvr = $matrixwidget->{"NumVisualRow"} - 1; if ((not $editcell) or (not defined $matrixwidgetvisualcell->{$this})) { return 'DELEGATE'; } my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; if ($editcell and $key eq "\cI") { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; my $datacollabel = $matrixdata->{"CH.$dc"}->{"Keyname"}; if ($datacollabel =~ m/^(date)$/) { $this->{-text} = &{$matrixdata->{"completedate"}}($matrixwidget, $dc, $dr, $vc, $vr, $this->{-text}); $this->{-pos} = length($this->{-text}); } elsif ($datacollabel =~ m/^(begin|end|amount)$/) { $this->{-text} = &{$matrixdata->{"completetime"}}($matrixwidget, $dc, $dr, $vc, $vr, $this->{-text}); $this->{-pos} = length($this->{-text}); } elsif ($datacollabel eq "account") { my $accounts = []; my $values = []; my $labels = {}; if (defined $matrixdata->{"completeaccount"}) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; $accounts = &{$matrixdata->{"completeaccount"}}($matrixwidget, $dc, $dr, $vc, $vr, $this->{-text}); } my $count = @@{$accounts}; if ($count == 0) { #FIXME error } elsif ($count == 1) { if (defined $matrixdata->{"CD.$dc.$dr"}->{"Blurcallback"}) { $matrixwidget->{"VC.$vc.$vr"}->{-text} = $accounts->[0]; &{$matrixdata->{"CD.$dc.$dr"}->{"Blurcallback"}}($matrixwidget, $dc, $dr, $vc, $vr); } $editcell = 0; $datacoll = 1; } else { my $i = 0; foreach my $a (@@{$accounts}) { $values->[$i] = $i; $labels->{$i} = $a; $i++; } my $w = $this->parent->add("accountselection", 'Listbox', -x => $matrixwidget->{"XOffset"}, -y => $matrixwidget->{"YOffset"}, -values => $values, -labels => $labels, -width => $matrixwidget->{"Width"}, -height => $matrixwidget->{"Height"}, -border => 1, #-multi => 1, -title => $matrixdata->{"CH.$dc"}->{"Label"}, -vscrollbar => 1, #-onchange => \&listbox_callback, ); $w->set_binding( sub { my $this = shift; my $key = shift; $this->{-has_modal_focus} = 0; }, KEY_ENTER()); $w->draw; $w->modalfocus; $this->parent->delete("accountselection"); if (defined $w->{-selected}) { if (defined $matrixdata->{"CD.$dc.$dr"}->{"Blurcallback"}) { $matrixwidget->{"VC.$vc.$vr"}->{-text} = $accounts->[$w->{-selected}]; &{$matrixdata->{"CD.$dc.$dr"}->{"Blurcallback"}}($matrixwidget, $dc, $dr, $vc, $vr); } } $editcell = 0; $datacoll = 1; } } } elsif ($key == KEY_F(2) or $key == KEY_ENTER) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; if ($editcell) { if (defined $matrixdata->{"CD.$dc.$dr"}->{"Blurcallback"}) { $datacoll = &{$matrixdata->{"CD.$dc.$dr"}->{"Blurcallback"}}($matrixwidget, $dc, $dr, $vc, $vr); } } $matrixwidget->{"VC.$vc.$vr"}->{-canvasscr}->standout; $matrixwidget->{"VC.$vc.$vr"}->draw; $editcell = 0; return; } else { return 'DELEGATE'; } } sub keybinder { my $this = shift; my $key = shift; $key = "\cD" if ($key == KEY_DC()); #make CTRL-D a normal key my $nvc = $matrixwidget->{"NumVisualCol"} - 1; my $nvr = $matrixwidget->{"NumVisualRow"} - 1; if ($editcell) { return 'DELEGATE'; } # special handling when table is empty (dummy is focused) if (not defined $matrixwidgetvisualcell->{$this->getfocusobj}) { if ($key eq "o") { if (defined $matrixdata->{"onanewline"}) { &{$matrixdata->{"onanewline"}}($matrixwidget, 0, 0, 0, 0); $datacoll = 1; } $this->root->feedkey(KEY_F(2)); #enter edit mode after datacoll was handled } elsif ($key eq "p" and defined $matrixdata->{"paste"} and $matrixdata->{"clipboardtype"} eq "line") { if (defined $matrixdata->{"paste"}) { &{$matrixdata->{"paste"}}($matrixwidget, 0, 0, 0, 0); $datacoll = 1; } } if ($datacoll) { #$matrixwidget->{"Cursorcol"} = 0; #$matrixwidget->{"Cursorrow"} = 0; return; } return 'DELEGATE'; } my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; if ($key == KEY_UP() or (not $editcell and $key eq "k")) { $vr--; if ($vr < 0) { $vrscroll = -1; $vr = 0; } } elsif ($key == KEY_PPAGE()) { my $j; $j = int($matrixwidget->{"NumVisualRow"} / 3 * 1); $j = 10 if ( $j < 10 ); $vr-=$j; if ($vr < 0) { $vrscroll = $vr; $vr = 0; } } elsif ($key == KEY_DOWN() or (not $editcell and $key eq "j")) { $vr++; if ($vr > $nvr) { $vrscroll = 1; $vr = $nvr; } } elsif ($key == KEY_NPAGE()) { my $j; $j = int($matrixwidget->{"NumVisualRow"} / 3 * 1); $j = 10 if ( $j < 10); $vr+=$j; if ($vr > $nvr) { $vrscroll = $vr - $nvr; $vr = $nvr; } } elsif (not $editcell and ($key == KEY_LEFT() or $key eq "h")) { $vc--; if ($vc < 0) { $vcscroll = -1; $vc = 0; } } elsif (not $editcell and ($key == KEY_RIGHT() or $key eq "l")) { $vc++; if ($vc > $nvc) { $vcscroll = 1; $vc = $nvc } } elsif ($key == KEY_HOME() && not $editcell) { $vr = 0; $vc = 0; } elsif ($key == KEY_END() && not $editcell) { $vr = $nvr; $vc = $nvc; } elsif (not $editcell and ($key eq "^" or $key eq "0")) { $vc = 0; $vcpos = -1; } elsif (not $editcell and $key eq "\$") { $vc = $nvc; $vcpos = +1; } elsif (not $editcell and $key eq "1") { $vr = 0; $vrpos = -1; } elsif (not $editcell and $key eq "G") { $vr = $nvr; $vrpos = +1; } elsif (not $editcell and $key eq "\cU") { my $j; $j = int($matrixwidget->{"NumVisualRow"} / 3 * 1); $j = 10 if ( $j < 10 ); $vrscroll = -$j; } elsif (not $editcell and $key eq "\cD") { my $j; $j = int($matrixwidget->{"NumVisualRow"} / 3 * 1); $j = 10 if ( $j < 10 ); $vrscroll = +$j; } elsif (not $editcell and $key eq "\cB") { $vrscroll = -$matrixwidget->{"NumVisualRow"}; } elsif (not $editcell and $key eq "\cF") { $vrscroll = +$matrixwidget->{"NumVisualRow"}; } elsif ($key == KEY_F(1)) { $this->root->dialog( "\n ==== action ====\n" . " CTRL-X - menu\n" . " CTRL-Q - save and quit\n" . " F1 - help\n" . " RET/F2 - edit existing line\n" . " o/F3 - edit on new next line\n" . " O/F4 - edit on new this line\n" . " d/F5 - mark line for deletion\n" . "\n ==== control column view ====\n" . " F7 - show/hide\n" . " F8 - sort\n" . " F9 - shrink to min\n" . " F10 - shrink\n" . " F11 - grow\n" . " F12 - grow to max\n" . "\n ==== movement ====\n" . " hjkl/CURSOR - left, down, up, right\n" . "PAGE UP/DOWN - move 10 line\n" . " TAB - next cell\n" . " HOME/END - jump to first/last cell\n" ); return; #do not change focus } elsif (not $editcell and ($key eq " ")) { $matrixwidget->{"VC.$vc.$vr"}->{-text} = ''; $matrixwidget->{"VC.$vc.$vr"}->{-pos} = 0; $matrixwidget->{"VC.$vc.$vr"}->{-canvasscr}->standend; $matrixwidget->{"VC.$vc.$vr"}->draw; $editcell = 1; return; #do not change focus } elsif (not $editcell and ($key == KEY_F(2) or $key == KEY_ENTER)) { $matrixwidget->{"VC.$vc.$vr"}->{-canvasscr}->standend; $matrixwidget->{"VC.$vc.$vr"}->draw; $editcell = 1; return; #do not change focus } elsif (not $editcell and ($key == KEY_F(3) or $key eq "o")) { if (defined $matrixdata->{"onanewline"}) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; &{$matrixdata->{"onanewline"}}($matrixwidget, $dc, $dr, $vc, $vr); $datacoll = 1; } $this->root->feedkey(KEY_F(2)); #enter edit mode after datacoll was handled # implicit immediate KEY_DOWN $vr++; if ($vr > $nvr) { $vrscroll = 1; $vr = $nvr; } } elsif (not $editcell and ($key == KEY_F(4) or $key eq "O")) { if (defined $matrixdata->{"Onanewline"}) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; &{$matrixdata->{"Onanewline"}}($matrixwidget, $dc, $dr, $vc, $vr); $datacoll = 1; } $this->root->feedkey(KEY_F(2)); #enter edit mode after datacoll was handled return; #do not change focus } elsif (not $editcell and ($key == KEY_F(5) or $key eq "d")) { if (defined $matrixdata->{"deletedelete"}) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; if (&{$matrixdata->{"deletedelete"}}($matrixwidget, $dc, $dr, $vc, $vr)) { # implicit immediate KEY_UP when trailing line was deleted $vr--; if ($vr < 0) { $vrscroll = -1; $vr = 0; } } $datacoll = 1; } return; #do not change focus } elsif (not $editcell and $key eq "u") { if (defined $matrixdata->{"undo"}) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; return unless &{$matrixdata->{"undo"}}($matrixwidget, $dc, $dr, $vc, $vr); $datacoll = 1; } } elsif ($key == KEY_F(7)) { my $c; my $values = []; my $labels = {}; my $select = {}; for ($c = 0; $c < $matrixdata->{"Columns"}; $c++) { push @@{$values}, "$c"; $labels->{"$c"} = $matrixdata->{"CH.$c"}->{"Label"}; $select->{"$c"} = $matrixdata->{"CH.$c"}->{"Colhide"} ? 0 : 1; } my $w = $this->add("hideandseek", 'Listbox', -x => $matrixwidget->{"XOffset"}, -y => $matrixwidget->{"YOffset"}, -values => $values, -labels => $labels, -selected => $select, -width => 20, -height => 20, -border => 1, -multi => 1, -title => 'Show', -vscrollbar => 1, #-onchange => \&listbox_callback, ); $w->set_binding( sub { my $this = shift; my $key = shift; $this->{-has_modal_focus} = 0; }, KEY_ENTER()); $w->draw; $w->modalfocus; #foreach my $key (keys %{$w}) { printf STDERR " key=$key, value=$w->{$key}\n" }; #foreach my $sel (keys %{$select}) { printf STDERR "select sel=$sel, value=$select->{$sel}\n" }; for ($c = 0; $c < $matrixdata->{"Columns"}; $c++) { $matrixdata->{"CH.$c"}->{"Colhide"} = $select->{"$c"} ? 0 : 1; } $this->delete("hideandseek"); $this->root->focus(undef, 1); $datacoll = 1; return; #do not change focus } elsif ($key == KEY_F(8)) { my $c; my $i; my $values = []; my $labels = {}; my $select = {}; my $trackc = {}; $i = 0; foreach $c (@@{$matrixdata->{"Sortorder"}}) { $values->[$i] = "$c"; $labels->{$c} = $matrixdata->{"CH.$c"}->{"Label"}; $select->{$i} = 1; $trackc->{$c} = 1; $i++; } for ($c = 0; $c < $matrixdata->{"Columns"}; $c++) { if (not $trackc->{$c}) { $values->[$i] = "$c"; $labels->{$c} = $matrixdata->{"CH.$c"}->{"Label"}; $select->{$i} = 0; $i++; } } my $w = $this->add("sortselection", 'Listbox', -x => $matrixwidget->{"XOffset"}, -y => $matrixwidget->{"YOffset"}, -values => $values, -selected => $select, -labels => $labels, #-values => ["b", "a", "c"], #-selected => {0 => 1, 2 => 1}, #means 0 (b/bar) and 2 (c/quux) is selected #-labels => {"a" => "foo", "b" => "bar", "c" => "quux"}, -width => 20, -height => 20, -border => 1, -multi => 1, -title => 'Sort', -vscrollbar => 1, #-onchange => \&listbox_callback, ); $w->set_binding( sub { my $this = shift; my $key = shift; $this->{-has_modal_focus} = 0; }, KEY_ENTER()); $w->draw; $w->modalfocus; #foreach my $key (sort keys %{$w}) { printf STDERR "key=$key, value=$w->{$key}\n" }; #printf STDERR "values[] = @@{$w->{-values}}\n"; #foreach my $key (sort keys %{$w->{-selected}}) { printf STDERR "key=$key, value=$w->{-selected}->{$key} indirect value $w->{-values}->[$key]\n" }; #foreach my $key (keys %{$w->{-selected}}) { printf STDERR "$w->{-values}->[$key]\n" if ($w->{-selected}->{$key}); }; #die "buh3"; $matrixdata->{"Sortorder"} = []; for ($i = 0; $i <= $#{$values}; $i++) { $c = $w->{-values}->[$i]; #printf STDERR "$c (at index $i) = $w->{-selected}->{$i}\n"; push @@{$matrixdata->{"Sortorder"}}, $c if ($w->{-selected}->{$i}); } $this->delete("sortselection"); $this->root->focus(undef, 1); if (defined $matrixdata->{"sort"}) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; &{$matrixdata->{"sort"}}($matrixwidget, $dc, $dr, $vc, $vr); $datacoll = 1; } return; #do not change focus } elsif (not $editcell and $key eq "y") { if (defined $matrixdata->{"yankcell"}) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; &{$matrixdata->{"yankcell"}}($matrixwidget, $dc, $dr, $vc, $vr); $datacoll = 1; } } elsif (not $editcell and $key eq "Y") { if (defined $matrixdata->{"Yankline"}) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; &{$matrixdata->{"Yankline"}}($matrixwidget, $dc, $dr, $vc, $vr); $datacoll = 1; } } elsif (not $editcell and $key eq "p") { if (defined $matrixdata->{"paste"} and $matrixdata->{"clipboardtype"} eq "cell") { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; return unless &{$matrixdata->{"paste"}}($matrixwidget, $dc, $dr, $vc, $vr); $datacoll = 1; } elsif (defined $matrixdata->{"paste"} and $matrixdata->{"clipboardtype"} eq "line") { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; return unless &{$matrixdata->{"paste"}}($matrixwidget, $dc, $dr, $vc, $vr); $datacoll = 1; $vr++; if ($vr > $nvr) { $vrscroll = 1; $vr = $nvr; } } } elsif (not $editcell and $key eq "P") { if (defined $matrixdata->{"Paste"}) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; return unless &{$matrixdata->{"Paste"}}($matrixwidget, $dc, $dr, $vc, $vr); $datacoll = 1; } #$this->root->feedkey(KEY_F(2)); #enter edit mode after datacoll was handled return; #do not change focus } elsif (not $editcell and $key eq ".") { if (defined $matrixdata->{"currentdatetime"}) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; return unless &{$matrixdata->{"currentdatetime"}}($matrixwidget, $dc, $dr, $vc, $vr); $datacoll = 1; } } elsif ($key == KEY_F(9)) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; my $width = $matrixdata->{"CH.$dc"}->{"Width"}; if ($width != $matrixdata->{"CH.$dc"}->{"Widthmin"}) { $matrixdata->{"CH.$dc"}->{"Width"} = $matrixdata->{"CH.$dc"}->{"Widthmin"}; $datacoll = 1; } return; #do not change focus } elsif ($key == KEY_F(10)) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; my $width = $matrixdata->{"CH.$dc"}->{"Width"}; $width--; if ($width >= $matrixdata->{"CH.$dc"}->{"Widthmin"}) { $matrixdata->{"CH.$dc"}->{"Width"} = $width; $datacoll = 1; } return; #do not change focus } elsif ($key == KEY_F(11)) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; my $width = $matrixdata->{"CH.$dc"}->{"Width"}; $width++; if ($width <= $matrixdata->{"CH.$dc"}->{"Widthmax"}) { $matrixdata->{"CH.$dc"}->{"Width"} = $width; $datacoll = 1; } return; #do not change focus } elsif ($key == KEY_F(12)) { my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this->getfocusobj}}; my $width = $matrixdata->{"CH.$dc"}->{"Width"}; if ($width != $matrixdata->{"CH.$dc"}->{"Widthmax"}) { $matrixdata->{"CH.$dc"}->{"Width"} = $matrixdata->{"CH.$dc"}->{"Widthmax"}; $datacoll = 1; } return; #do not change focus } $matrixwidget->{"Cursorcol"} = $vc; $matrixwidget->{"Cursorrow"} = $vr; if ($vcscroll == 0 && $vrscroll == 0) { $matrixwidget->{"VC.$vc.$vr"}->focus; } else { $widget->{"dummy"}->focus; } } sub destroymatrixwidgetcells { foreach my $i (sort keys %{$matrixwidget}) { if ($i =~ m/^VC\.\d+\.\d+/ || $i =~ m/^(CH|RH)\.(\d+|fill.*)/) { $matrixwidget->{$i}->parent->delete($i); delete $matrixwidget->{$i}; } } } sub destroymatrixwidget { &destroymatrixwidgetcells(); undef $matrixwidget; } sub drawallmatrixwidgets { $widget->{'container'}->draw; return; foreach my $i (sort keys %{$matrixwidget}) { if ($i =~ m/^VC\.\d+\.\d+/ || $i =~ m/^(CH|RH)\.(\d+|fill.*)/) { #printf STDERR "DRAW: $i\n"; $matrixwidget->{$i}->draw; } } } sub drawfocusmatrixwidget { my $c; my $r; my $lastc; my $lastr; &drawallmatrixwidgets(); $c = defined $matrixwidget->{"Cursorcol"} ? $matrixwidget->{"Cursorcol"} : 0; $r = defined $matrixwidget->{"Cursorrow"} ? $matrixwidget->{"Cursorrow"} : 0; $lastc = $matrixwidget->{"NumVisualCol"} - 1; #Col0=heading, Col1...n=cursor area $lastr = $matrixwidget->{"NumVisualRow"} - 1; #Row0=heading, Row1...n=cursor area $widget->{"dummy"}->focus; if ($lastc >= 0 and $lastr >= 0) { $c = $lastc if ($c > $lastc); $r = $lastr if ($r > $lastr); $matrixwidget->{"VC.$c.$r"}->{-canvasscr}->standout; $matrixwidget->{"VC.$c.$r"}->draw; $matrixwidget->{"VC.$c.$r"}->focus; } } sub ascui { ($matrixdata, $verbose) = (@@_); # in CUI mode we do not want STDERR to clutter our screen. ($verbose && open STDERR, ">>2.log") || (open STDERR, ">/dev/null"); # create the root object $cui = new Curses::UI ( -clear_on_exit => 0, # -debug => $debug, ); $cui->overlapping(0); #activates rse performance enhancement patch for non-overlapping layouts # die handler $SIG{__DIE__} = sub { my ($err) = @@_; $err =~ s|\s+at\s+.*||s if (not $verbose); my $txt = "$err ". ($! ? "($!)" : ""); ($verbose || open STDERR, ">>2.log") || (open STDERR, ">>$ENV{HOME}/2.log") || (open STDERR, ">>/tmp/2.log"); print STDERR "ERROR: $txt\n"; $cui->error("$txt") if (defined $cui); exit(1); }; # create menu widget my $menu_file = [ { -label => 'Quit program', -value => sub {exit(0)} }, ]; my $menu_as = [ { -label => 'Testerli 1', -value => sub {exit(0)} }, { -label => 'Testerli 2', -value => sub {exit(0)} }, ]; my $menu = [ { -label => 'File', -submenu => $menu_file }, { -label => 'Accounting', -submenu => $menu_as }, ]; $widget->{'menu'} = $cui->add('menu', 'Menubar', -menu => $menu ); # add main window $widget->{'main'} = $cui->add('main', 'Window', -padtop => 1, #leave space for menu on the top -padbottom => 1, #leave space for status on the bottom -border => 0 ); # add status window $widget->{'stat'} = $cui->add('stat', 'Window', -height => 1, -y => -1, -border => 0 ); # add a status line my $wstat = $widget->{'stat'}->width; my $textl = "Accounting System (AS)"; my $textr = "CTRL+X: menu CTRL+Q: quit"; my $textf = " " x ($wstat -2 -length($textl) -1 -1 -length($textr) - 2); my $text = sprintf(" %s %s %s ", $textl, $textf, $textr); $widget->{'status'}->{-text} = $text; $widget->{'info'} = $widget->{'stat'}->add('info', 'Label', -text => $text, -reverse => 1, ); # add a container $widget->{'container'} = $widget->{'main'}->add(undef, 'Container'); # add dummy to focus and to indirectly force blur $widget->{'dummy'} = $widget->{'container'}->add(undef, 'TextEntry', -x => 0, -y => 0, -text => "", -width => 3, -height => 1 ); $cui->set_binding(sub{ $breakout = 1 }, "\cQ"); $cui->set_binding(sub{ shift()->root->focus('menu') }, "\cX"); $widget->{'container'}->set_binding(\&keybinder, ''); #now we catch all chars not just @@keys_move $cui->draw; &newmatrixwidget(); my ($upperleftcol, $cursorcol) = ($matrixdata->{"CK.date"}, 0); #&rightmostvisiblefit(); my ($upperleftrow, $cursorrow) = &bottommostvisiblefit(); &layoutmatrixwidget($upperleftcol, $upperleftrow, $cursorcol, $cursorrow); &drawfocusmatrixwidget(); $breakout = 0; do { $vcscroll = 0; $vrscroll = 0; $datacoll = 0; $vcpos = 0; $vrpos = 0; $cui->root->do_one_event; if ($vcscroll < 0) { $upperleftcol += $vcscroll; $upperleftcol = 0 if ($upperleftcol < 0); } elsif ($vcscroll > 0) { $upperleftcol += $vcscroll; my ($upperleftcolfit, $dummy) = &rightmostvisiblefit(); $upperleftcol = $upperleftcolfit if ($upperleftcol > $upperleftcolfit); } if ($vrscroll < 0) { $upperleftrow += $vrscroll; $upperleftrow = 0 if ($upperleftrow < 0); } elsif ($vrscroll > 0) { $upperleftrow += $vrscroll; my ($upperleftrowfit, $dummy) = &bottommostvisiblefit(); $upperleftrow = $upperleftrowfit if ($upperleftrow > $upperleftrowfit); } if ($vcpos < 0) { $upperleftcol = 0; } elsif ($vcpos > 0) { ($upperleftcol, my $dummy) = &rightmostvisiblefit(); } if ($vrpos < 0) { $upperleftrow = 0; } elsif ($vrpos > 0) { ($upperleftrow, my $dummy) = &bottommostvisiblefit(); } if ($vcscroll != 0 or $vrscroll != 0 or $datacoll != 0 or $vcpos != 0 or $vrpos != 0) { &layoutmatrixwidget($upperleftcol, $upperleftrow); &drawfocusmatrixwidget(); } } until ($breakout); &destroymatrixwidget(); $cui->dialog("Bye bye!"); } 1; @ 1.28 log @Remove lots of debugging stuff. @ text @@ 1.27 log @cosmetic changes only - replace tabs with spaces - align blocks on four char boundaries - make sure all functions are executed with & prefix @ text @a198 1 #printf STDERR "DEBUG: matrixdata->{RH.%d}->Heightweight=%d\n", $r, $matrixdata->{"RH.$r"}->{"Heightweight"}; a269 1 #printf STDERR "DEBUG: colcachetag=$colcachetag\n"; a270 1 #printf STDERR "DEBUG: lastc=$lastc, dataxoffset=$dataxoffset, wremain=$wremain\n"; a322 1 #printf STDERR "DEBUG: rowcachetag=$rowcachetag\n"; a323 1 #printf STDERR "DEBUG: lastr=$lastr, datayoffset=$datayoffset, hremain=$hremain\n"; a341 1 #printf STDERR "DEBUG: col von start\n"; a344 1 #printf STDERR "DEBUG: col von $c, num=$n, visualc=$visualc\n"; a345 1 #printf STDERR "DEBUG: von $c, num=$n, visualc=$visualc\n"; a348 1 #$matrixwidget->{"CH.$visualc"}->{-text} = "$visualc $c"; #DEBUG a353 1 #printf STDERR "DEBUG: col bis end\n"; a361 1 #printf STDERR "DEBUG: row von start\n"; a364 1 #printf STDERR "DEBUG: von $r, num=$n, visualr=$visualr\n"; a365 1 #printf STDERR "DEBUG: row von $r, num=$n, visualc=$visualr\n"; a368 1 #$matrixwidget->{"RH.$visualr"}->{-text} = "$visualr $r"; #DEBUG a373 1 #printf STDERR "DEBUG: row bis end\n"; a475 1 #printf STDERR "DEBUG: visualc=$visualc, visualr=$visualr\n"; a521 1 #printf STDERR "DEBUG: key was (%d) \"%s\"\n", ord($key), $key; a527 1 #printf STDERR "DEBUG: start with vc,vr=%d,%d\n", $vc, $vr; a552 1 #printf STDERR "DEBUG: count=$count\n"; die; a566 1 #printf STDERR "DEBUG: a=\"$a\"\n"; a596 1 #printf STDERR "DEBUG: text=$accounts->[$w->{-selected}]\n"; a607 1 #printf STDERR "DEBUG: captured F2/ENTER in tabbinder\n"; a631 1 #printf STDERR "DEBUG: key was (%d) \"%s\"\n", ord($key), $key; die; a660 1 #printf STDERR "DEBUG: start with vc,vr=%d,%d\n", $vc, $vr; a785 1 #printf STDERR "DEBUG: captured F2/ENTER in keybinder\n"; a1014 1 #printf STDERR "DEBUG: width=$width\n"; a1025 1 #printf STDERR "DEBUG: width=$width\n"; a1036 1 #printf STDERR "DEBUG: width=$width\n"; a1046 1 #printf STDERR "DEBUG: width=$width\n"; a1055 1 #printf STDERR "DEBUG: end up with vc,vr=%d,%d and set focus to this\n", $vc, $vr; a1058 1 #printf STDERR "DEBUG: end up with vc,vr=%d,%d and set focus to dummy\n", $vc, $vr; a1062 6 #foreach my $i (sort keys %{$matrixwidget}) { #DEBUG # if ($i =~ m/^VC\.\d+\.\d+/ || $i =~ m/^(CH|RH)\.(\d+|fill.*)/) { #DEBUG # $matrixwidget->{$i}->{-canvasscr}->standout; #DEBUG # $matrixwidget->{$i}->draw; #DEBUG # } #DEBUG #} #DEBUG a1064 3 #printf STDERR "DEBUG: destroying $i\n"; #DEBUG $matrixwidget->{$i}->{-canvasscr}->standend; #DEBUG $matrixwidget->{$i}->draw; #DEBUG a1067 3 #else { #DEBUG # printf STDERR "DEBUG: saved \"$i\"\n"; #DEBUG #} #DEBUG a1097 1 #printf STDERR "DEBUG: c=$c, r=$r, lastc=$lastc, lastr=$lastr\n"; @ 1.26 log @lots of work to unify internal processing of cli and cui properly distinguish naming between single event and all events add &isvalid(user|uuid|crc32|revision|date|begin|end|amount|account|remark) check functions &completeaccount now escapes special characters using quotemeta &readevents rewritten to use new cli/cui-unified functions "e used more consequently; does no longer escape dots; handels empty strings &bydateline no longer compares (sorts) by "end" &calccrc32 runs a loop but hardcoded fields; single event makes uuid no longer special &cuinewevent properly supports fractional pasting with fallback to default for each key Blurcallbacks rewritten to support single event fixed name/column lookup problem providing and using Keyname and CK.Label lookups status now kept in event and events; supported by &matrixrowstatus error supports multiple annotations &event2ln and &ln2event convert from single event to plain text lines &getevent and &setevent convert from single event to events &matrixrow2event converts a matrix row to single event &matrix2events rewritten to use new cli/cui-unified functions added &dumpevent for debugging "onanewline" and "Onanewline" now prefills date @ text @d501 1 a501 1 $matrixwidget->{"VC.$c.$r"}->set_event("-onfocus", d503 7 a509 7 my $this = shift; my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; $matrixwidget->{"VC.$vc.$vr"}->{-canvasscr}->standout unless($editcell); if (defined $matrixdata->{"CD.$dc.$dr"}->{"Focuscallback"}) { &{$matrixdata->{"CD.$dc.$dr"}->{"Focuscallback"}}($matrixwidget, $dc, $dr, $vc, $vr); } d512 1 a512 1 $matrixwidget->{"VC.$c.$r"}->set_event("-onblur", d514 10 a523 10 my $this = shift; my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; $matrixwidget->{"VC.$vc.$vr"}->{-canvasscr}->standend; if ($editcell) { if (defined $matrixdata->{"CD.$dc.$dr"}->{"Blurcallback"}) { $datacoll = &{$matrixdata->{"CD.$dc.$dr"}->{"Blurcallback"}}($matrixwidget, $dc, $dr, $vc, $vr); } } $editcell = 0; d687 5 a691 5 $vr--; if ($vr < 0) { $vrscroll = -1; $vr = 0; } d694 8 a701 8 my $j; $j = int($matrixwidget->{"NumVisualRow"} / 3 * 1); $j = 10 if ( $j < 10 ); $vr-=$j; if ($vr < 0) { $vrscroll = $vr; $vr = 0; } d704 5 a708 5 $vr++; if ($vr > $nvr) { $vrscroll = 1; $vr = $nvr; } d711 8 a718 8 my $j; $j = int($matrixwidget->{"NumVisualRow"} / 3 * 1); $j = 10 if ( $j < 10); $vr+=$j; if ($vr > $nvr) { $vrscroll = $vr - $nvr; $vr = $nvr; } d721 5 a725 5 $vc--; if ($vc < 0) { $vcscroll = -1; $vc = 0; } d728 5 a732 5 $vc++; if ($vc > $nvc) { $vcscroll = 1; $vc = $nvc } d735 2 a736 2 $vr = 0; $vc = 0; d739 2 a740 2 $vr = $nvr; $vc = $nvc; d743 2 a744 2 $vc = 0; $vcpos = -1; d747 2 a748 2 $vc = $nvc; $vcpos = +1; d751 2 a752 2 $vr = 0; $vrpos = -1; d755 2 a756 2 $vr = $nvr; $vrpos = +1; d759 4 a762 4 my $j; $j = int($matrixwidget->{"NumVisualRow"} / 3 * 1); $j = 10 if ( $j < 10 ); $vrscroll = -$j; d765 4 a768 4 my $j; $j = int($matrixwidget->{"NumVisualRow"} / 3 * 1); $j = 10 if ( $j < 10 ); $vrscroll = +$j; d771 1 a771 1 $vrscroll = -$matrixwidget->{"NumVisualRow"}; d774 1 a774 1 $vrscroll = +$matrixwidget->{"NumVisualRow"}; d1158 2 a1159 2 $cui = new Curses::UI ( -clear_on_exit => 0, d1187 1 a1187 1 $widget->{'menu'} = $cui->add('menu', 'Menubar', d1192 1 a1192 1 $widget->{'main'} = $cui->add('main', 'Window', d1195 1 a1195 1 -border => 0 d1199 1 a1199 1 $widget->{'stat'} = $cui->add('stat', 'Window', d1202 1 a1202 1 -border => 0 d1212 1 a1212 1 $widget->{'info'} = $widget->{'stat'}->add('info', 'Label', d1225 1 a1225 1 -width => 1, @ 1.25 log @delete/undo with unlimited history stack @ text @d538 1 a538 1 #printf STDERR "DEBUG: key was (%d) \"%s\"\n", ord($key), $key; die; d550 1 a550 1 my $datacollabel = $matrixdata->{"CH.$dc"}->{"Label"}; #FIXME name/position lookup problem d555 1 a555 1 elsif ($datacollabel =~ m/^(begin|end|amnt\.)$/) { d567 1 a567 1 $accounts = &{$matrixdata->{"completeaccount"}}($matrixwidget, $dc, $dr, $vc, $vr, quotemeta($this->{-text})); d1235 1 a1235 1 my ($upperleftcol, $cursorcol) = (4, 0); #&rightmostvisiblefit(); @ 1.24 log @handling case where no entries currently exist moved from main to matrixwidget fixed bug where yank a line does only work on entries that were read in not newly created ones support for row deletion through matrixdeleterow() support for shrinking matrix by one row through matrixshrinkrow() improve initial screen drawing by calling draw method on wholly cui object d deletes the line visibly, no more mark for deletion @ text @d857 8 @ 1.23 log @die() handler with log to a file and popup @ text @d261 1 a261 1 -text => "", d316 1 a316 1 -text => "", d358 1 a358 1 $matrixwidget->{"CH.$visualc"}->{-text} = $matrixdata->{"CH.$c"}->{"Labelhide"} ? "" : $matrixdata->{"CH.$c"}->{"Label"}; d383 1 a383 1 $matrixwidget->{"RH.$visualr"}->{-text} = $matrixdata->{"RH.$r"}->{"Labelhide"} ? "" : $matrixdata->{"RH.$r"}->{"Label"}; d534 2 a543 1 $key = "\cD" if ($key == KEY_DC()); #make CTRL-D a normal key d650 2 d656 24 a679 1 if ($editcell or (not defined $matrixwidgetvisualcell->{$this->getfocusobj})) { a682 1 $key = "\cD" if ($key == KEY_DC()); #make CTRL-D a normal key d845 8 a852 1 &{$matrixdata->{"deletedelete"}}($matrixwidget, $dc, $dr, $vc, $vr); a1131 2 $c = $lastc if ($c > $lastc); $r = $lastr if ($r > $lastr); d1133 8 a1140 3 $matrixwidget->{"VC.$c.$r"}->{-canvasscr}->standout; $matrixwidget->{"VC.$c.$r"}->draw; $matrixwidget->{"VC.$c.$r"}->focus; a1207 1 $widget->{'info'}->draw; d1224 1 @ 1.22 log @status line at the bottom @ text @d25 1 d393 2 a394 2 $matrixwidget->{"XOffset"} = $verbose ? 10 : 0; #horizontal position relative to screen $matrixwidget->{"YOffset"} = $verbose ? 10 : 0; #vertical position relative to screen d1111 2 a1112 1 $verbose = 0; #this is useful for development at max d1115 1 a1115 1 my $cui = new Curses::UI ( d1121 11 a1185 14 if ($verbose) { $widget->{'colruler'} = $widget->{'container'}->add(undef, 'Label', -x => 10, -y => 7, -text => "0 1 2 3 4 5 6 7 \n" . "|123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789" ); $widget->{'rowruler'} = $widget->{'container'}->add(undef, 'Label', -x => 7, -y => 10, -text => "0-\n 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n1-\n 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n2-\n 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n", ); } @ 1.21 log @borderless window @ text @d1110 2 d1131 1 a1131 2 $widget->{'menu'} = $cui->add( 'menu', 'Menubar', d1135 24 a1158 15 # add main screen $widget->{'main'} = $cui->add( 'main', 'Window', -title => "Accounting Data", -border => 0, -titlereverse => 0, -padtop => 1, -padbottom => 1, -ipad => 0, ); # add status line $widget->{'status'} = $cui->add( 'status', 'Window', -border => 0, -x => 0, -y => -1, -height => 1, -width => -1, d1160 1 d1163 1 a1163 2 $widget->{'container'} = $widget->{'main'}->add(undef, 'Container', ); a1173 11 my $wstat = $widget->{'status'}->width; my $text1 = "Accounting System (AS)"; my $text2 = "CTRL+X: menu CTRL+Q: quit"; my $n = $wstat - 2 - length($text1) - 1 - 2; my $text = sprintf(" %s %*s ", $text1, $n, $text2); $widget->{'status'}->add( 'explain', 'Label', -text => $text, -reverse => 1, -paddingspaces => 1, -width => -1, ); a1189 1 a1190 2 $widget->{'container'}->draw; $widget->{'container'}->focus; @ 1.20 log @SPACE should clear the field and enter edit mode like ENTER @ text @d1138 1 a1138 1 -border => 1, @ 1.19 log @start at the bottom @ text @d775 9 a783 1 elsif ($key == KEY_F(2) or $key == KEY_ENTER) { @ 1.18 log @align date/time syntax checking and completion between readevents() and CUI syntax checking now uses svalidyyyymmdd() and isvalidhhmm() completion now uses anydate2yyyymmdd() and anytimetohhmm() add time calculation when one of begin/end/amount is missing handle preseletable current "dot" time in day() and now() use user supplyable current date/time in readevents() remove outdated createsamplematrixdata() ignore missing blur callbacks (can't handle error, so don't check for it) wipe out some debug code handle KEY_ENTER when entering a edit mode and when leaving edit mode control focus/ cursor movement when leaving edit mode remove obsolete CDK research nicedate(), nicetime(), today(), now() two points off 00TODO @ text @a59 1 my ($doit) = @@_; d64 1 d67 1 d70 2 d77 1 d82 2 a83 1 return ($c); a86 1 my ($doit) = @@_; d91 1 d94 1 d97 2 d104 1 d109 2 a110 1 return ($r); d142 1 d167 60 d390 2 a391 4 # create a matrix widget sub creatematrixwidget { # fill in global matrix widget information d396 4 a399 2 $matrixwidget->{"FirstVisualCol"} = shift; #leftmost data column presented on screen $matrixwidget->{"FirstVisualRow"} = shift; #topmost data row presented on screen d402 9 a410 1 #matrixwidget->{"Cachetag"} #tracks if widgets can be reused d439 1 a1183 8 #$widget->{'note'} = $widget->{'main'}->add(undef, 'Label', # -x => 3, # -y => 3, # -text => "note Row 7 and Col 4 are hidden" #); #$matrixdata->{"RH.7"}->{"Rowhide"} = 1; #$matrixdata->{"CH.4"}->{"Colhide"} = 1; d1188 4 a1191 3 my $upperleftcol = 4; my $upperleftrow = 0; &creatematrixwidget($upperleftcol, $upperleftrow); d1209 1 a1209 1 my $upperleftcolfit = &rightmostvisiblefit(); d1218 1 a1218 1 my $upperleftrowfit = &bottommostvisiblefit(); d1226 1 a1226 1 $upperleftcol = &rightmostvisiblefit(); d1233 1 a1233 1 $upperleftrow = &bottommostvisiblefit(); d1237 1 a1237 1 &creatematrixwidget($upperleftcol, $upperleftrow); @ 1.17 log @remove unused var; default for undefined Widthweight @ text @d26 1 a26 1 my @@keys_move = ( a58 57 # create a big data matrix sub createsamplematrixdata { # fill in global matrix data information $matrixdata->{"Columns"} = 10; $matrixdata->{"Rows"} = 100; my $cols = $matrixdata->{"Columns"}; my $rows = $matrixdata->{"Rows"}; my $c; my $r; # fill in information about column headers (top) for ($c = -1; $c < $cols; $c++) { $matrixdata->{"CH.$c"} = { "Label" => "CH.$c", "Labelhide" => 0, "Widthmin" => 3, "Widthmax" => 15, "Width" => 9, "Colgap" => 1, "Colhide" => 0, "Colsort" => 0 }; } # fill in information about row headers (left) for ($r = -1; $r < $rows; $r++) { $matrixdata->{"RH.$r"} = { "Label" => "RH.$r", "Labelhide" => 0, "Heigthmin" => 1, "Heigthmax" => 1, "Height" => 1, "Rowgap" => 0, "Rowhide" => 0 }; } # fill in cell data for (my $c = 0; $c < $cols; $c++) { for (my $r = 0; $r < $rows; $r++) { $matrixdata->{"CD.$c.$r"} = { "Data" => "CD.$c.$r", "Focuscallback" => sub { my ($dc, $dr, $vc, $vr) = (@@_); #print STDERR "DEBUG: CD-Focuscallback got vc/vr=$vc/$vr, dc/dr=$dc/$dr\n"; }, "Blurcallback" => sub { my ($dc, $dr, $vc, $vr) = (@@_); #print STDERR "DEBUG: CD-Blurcallback got vc/vr=$vc/$vr, dc/dr=$dc/$dr\n"; $matrixdata->{"CD.$dc.$dr"}->{"Data"} = $matrixwidget->{"VC.$vc.$vr"}->{-text}; } }; } } }; d419 1 a419 2 #$matrixwidget->{"VC.$c.$r"}->set_binding(\&keybinder, @@keys_move); $matrixwidget->{"VC.$c.$r"}->set_binding(\&tabbinder, "\cI"); a422 1 #printf STDERR "DEBUG: focus this=$this\n"; a424 1 #printf STDERR "DEBUG: focus vc/vr=$vc/$vr, dc/dr=$dc/$dr\n"; a428 2 else { die "no Focuscallback"; } #FIXME #$matrixwidget->{"VC.$vc.$vr"}->{-text} = $matrixdata->{"CD.$dc.$dr"}->{"Data"}; a433 1 #printf STDERR "DEBUG: blur this=$this\n"; a435 1 #printf STDERR "DEBUG: blur vc/vr=$vc/$vr, dc/dr=$dc/$dr\n"; d437 4 a440 2 if (defined $matrixdata->{"CD.$dc.$dr"}->{"Blurcallback"}) { &{$matrixdata->{"CD.$dc.$dr"}->{"Blurcallback"}}($matrixwidget, $dc, $dr, $vc, $vr); a441 2 else { die "no Blurcallback"; } #FIXME #$matrixdata->{"CD.$dc.$dr"}->{"Data"} = $matrixwidget->{"VC.$vc.$vr"}->{-text}; a454 1 my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; d456 5 d462 2 d465 1 a465 37 #$this->{-text} = "/nasenbaer"; #$this->{-reverse} = 1; $this->draw; sleep(1); #$this->{-reverse} = 0; $this->draw; sleep(1); #if ($editcell and $key eq "\cI") { # $this->root->dialog("Foo"); #} #$this->{-text} = "/eins"; #$this->{-reverse} = 1; $this->draw; sleep(1); #$this->{-reverse} = 0; $this->draw; sleep(1); #return; #if ($editcell and $key eq ".") { # my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; # my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; # my $datacollabel = $matrixdata->{"CH.$dc"}->{"Label"}; # my $text = undef; # if ($datacollabel eq "date") { # $text = &today(); # } # elsif ($datacollabel eq "begin") { # $text = &now(); # } # elsif ($datacollabel eq "end") { # $text = &now(); # } # elsif ($datacollabel eq "amnt.") { # $text = &now(); # } # else { # return 'DELEGATE'; # } # if (defined $text) { # $this->{-text} = $text; # $this->{-pos} = length($text); # } #} els if ($editcell and $key eq "\cI") { d468 4 a471 3 my $datacollabel = $matrixdata->{"CH.$dc"}->{"Label"}; if ($datacollabel eq "date") { $this->{-text} = &nicedate($this->{-text}); d473 1 a473 7 elsif ($datacollabel eq "begin") { $this->{-text} = &{$matrixdata->{"completetime"}}($matrixwidget, $dc, $dr, $vc, $vr, $this->{-text}); } elsif ($datacollabel eq "end") { $this->{-text} = &{$matrixdata->{"completetime"}}($matrixwidget, $dc, $dr, $vc, $vr, $this->{-text}); } elsif ($datacollabel eq "amnt.") { d475 1 a497 2 else { die "no Blurcallback"; } #FIXME #$matrixdata->{"CD.$dc.$dr"}->{"Data"} = $matrixwidget->{"VC.$vc.$vr"}->{-text}; d535 1 a535 1 print STDERR "DEBUG: text=$accounts->[$w->{-selected}]\n"; a539 2 else { die "no Blurcallback"; } #FIXME #$matrixdata->{"CD.$dc.$dr"}->{"Data"} = $matrixwidget->{"VC.$vc.$vr"}->{-text}; d546 14 d572 1 a572 1 if (($editcell == 1) or (not defined $matrixwidgetvisualcell->{$this->getfocusobj})) { d578 1 d696 1 a696 1 $editcell = 1; d699 1 d898 8 d911 1 a911 1 #print STDERR "DEBUG: width=$width\n"; d923 1 a923 1 #print STDERR "DEBUG: width=$width\n"; d935 1 a935 1 #print STDERR "DEBUG: width=$width\n"; d946 1 a946 1 #print STDERR "DEBUG: width=$width\n"; d956 1 d960 1 a1170 48 } sub nicedate { my ($value) = (@@_); my $rv; my ($day, $month, $year); if (defined $value && $value =~ m/^(\d{1,4})(\d{1,2})(\d{1,2})$/) { ($day, $month, $year) = ($3, $2, $1); } else { ($day, $month, $year) = (localtime(time))[3,4,5]; $month++; $year += 1900; } $year += 2000 if ($year < 100); $rv = sprintf("%04d%02d%02d", $year, $month, $day); return $rv; } sub nicetime { my ($value) = (@@_); my $rv; my ($hour, $minute); if (defined $value && $value =~ m/^(\d{0,2}):?(\d{0,2})$/) { ($hour, $minute) = ($1, $2); $hour = 0 if ($hour eq ""); $minute = 0 if ($minute eq ""); $rv = sprintf("%02d:%02d", $hour, $minute); #&calcamount(); } return $rv; } sub today { my $rv; my ($day, $month, $year) = (localtime(time))[3,4,5]; $month++; $year += 1900; $rv = sprintf("%04d%02d%02d", $year, $month, $day); return $rv; } sub now { my $rv; my ($sec, $min, $hour) = (localtime(time))[0,1,2]; $rv = sprintf("%02d:%02d", $hour, $min); #&calcamount(); return $rv; @ 1.16 log @avoid crash when callback runs for non-data cells @ text @a161 1 my $y; d186 1 @ 1.15 log @yank cell, Yank line, paste cell or paste/Paste line @ text @a657 1 my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this->getfocusobj}}; a658 1 $key = "\cD" if ($key == KEY_DC()); #make CTRL-D a normal key d660 1 a660 1 if ($editcell == 1) { d663 3 @ 1.14 log @remove obsolete CDK code @ text @d939 1 a939 1 if (defined $matrixdata->{"yank"}) { d942 9 a950 1 &{$matrixdata->{"yank"}}($matrixwidget, $dc, $dr, $vc, $vr); d955 1 a955 1 if (defined $matrixdata->{"paste"}) { d961 10 a970 6 #$this->root->feedkey(KEY_F(2)); #enter edit mode after datacoll was handled # implicit immediate KEY_DOWN $vr++; if ($vr > $nvr) { $vrscroll = 1; $vr = $nvr; @ 1.13 log @calculate optimal column width and cursor movement based on screen size @ text @a1283 23 sub calcamount { my ($begin, $end) = (@@_); my $rv = undef; my $beginsec = defined $begin ? hhmm2sec($begin) : -1; my $endsec = defined $end ? hhmm2sec($end) : -1; if ($beginsec >= 0 && $endsec >= 0 && $endsec >= $beginsec) { my $amountmin = int(($endsec - $beginsec) / 60); my $hour = int($amountmin / 60); my $min = int($amountmin % 60); $rv = sprintf("%02d:%02d", $hour, $min); } return $rv; } sub hhmm2sec { my ($hhmm) = (@@_); my $rv = undef; if ($hhmm =~ m/^([0-1]?[0-9]|2[0-4]):([0-5]?[0-9])$/) { $rv = $1 * 3600 + $2 * 60; } return $rv; } @ 1.12 log @added tab completion for time fields importing code from CDK research @ text @d160 56 d382 2 a383 2 $matrixwidget->{"Width"} = 76; #width in screen dimensions $matrixwidget->{"Height"} = 20; #heigth in screen dimensions d415 3 d674 4 a677 1 $vr-=10; d691 4 a694 1 $vr+=10; d739 4 a742 1 $vrscroll = -10; d745 4 a748 1 $vrscroll = +10; @ 1.11 log @added tab completion/list box for accounts @ text @d475 25 d504 13 a516 1 if ($datacollabel eq "account") { d1163 71 @ 1.10 log @add 0, CTRL-F, CTRL-B moves; capture all keys @ text @d418 1 d426 1 a426 1 $matrixwidget->{"VC.$vc.$vr"}->{-canvasscr}->standout; d455 102 d563 1 a563 1 #printf STDERR "DEBUG: key was \"%s\" (%)d)\n", $key, ord($key); die; @ 1.9 log @add yank/paste/Paste support @ text @d517 1 a517 1 elsif (not $editcell and $key eq "^") { d536 1 a536 1 elsif (not $editcell and $key eq "\cD") { #CTRL-D d539 6 d964 1 a964 1 $widget->{'container'}->set_binding(\&keybinder, @@keys_move); @ 1.8 log @add 1, G, CTRL-U, CTRL-D, TILDE, DOLLAR moves @ text @d53 4 a56 1 "\$" #scroll screen right to the border and place cursor on the last cell d719 33 @ 1.7 log @keybinding through additional container; vi cursor movement @ text @d14 6 a19 4 my $breakout = 0; my $vrscroll = 0; my $vcscroll = 0; my $datacoll = 0; d48 6 d457 2 d514 22 a925 1 #&creatematrixwidget(0, 0); d932 1 a933 1 $vcscroll = 0; d935 3 d939 1 d958 16 a973 1 if ($vrscroll != 0 or $vcscroll != 0 or $datacoll != 0) { @ 1.6 log @"on a new line" needs implicit KEY_DOWN @ text @d24 22 a45 20 my @@keys_move = ( KEY_UP(), #"k", KEY_DOWN(), #"j", KEY_LEFT(), #"h", KEY_RIGHT(), #"l", KEY_NPAGE(), KEY_PPAGE(), KEY_HOME(), KEY_END(), KEY_F(1), #help KEY_F(2), #edit KEY_F(3), #on a new line KEY_F(4), #On a new line KEY_F(5), #delete line #KEY_F(6), #copy line KEY_F(7), #column show/hide KEY_F(8), #column sorting KEY_F(9), #column shrink to min KEY_F(10), #column shrink KEY_F(11), #column grow KEY_F(12), #column grow to max d176 1 a176 1 $matrixwidget->{"CH.$visualc"} = $widget->{'main'}->add("CH.$visualc", 'Label', d193 1 a193 1 $matrixwidget->{"CH.fillright"} = $widget->{'main'}->add("CH.fillright", 'Label', d231 1 a231 1 $matrixwidget->{"RH.$visualr"} = $widget->{'main'}->add("RH.$visualr", 'Label', d248 1 a248 1 $matrixwidget->{"RH.fillbottom"} = $widget->{'main'}->add("RH.fillbottom", 'Label', d374 1 a374 1 $matrixwidget->{"VC.$visualc.$visualr"} = $widget->{'main'}->add("VC.$visualc.$visualr", 'TextEntry', d406 1 a406 1 $matrixwidget->{"VC.$c.$r"}->set_binding(\&keybinder, @@keys_move); d448 6 a453 1 my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; d506 20 a525 15 "F1 - Help\n" . "F2 - Edit\n" . "F3 - Insert on next line\n" . "F4 - Insert on this line\n" . "\n" . "F5 - Mark line for deletion\n" . "\n" . "F9 - shrink column to minimum size\n" . "F10 - shrink column\n" . "F11 - grow column\n" . "F12 - grow column to maximum size\n" . "\n" . "Cursor movement through CURSOR, PAGE, HOME, END\n" . "\n" . "CTRL-Q save and quit" d529 1 a529 1 elsif ($key == KEY_F(2)) { d531 2 d535 1 a535 1 elsif ($key == KEY_F(3)) { d537 2 a538 2 my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; d542 2 a543 1 # implicit KEY_DOWN d550 1 a550 1 elsif ($key == KEY_F(4)) { d552 2 a553 2 my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; d557 1 d560 1 a560 1 elsif ($key == KEY_F(5)) { d562 2 a563 2 my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; d579 1 a579 1 my $w = $this->parent->add("hideandseek", 'Listbox', d607 1 a607 1 $this->parent->delete("hideandseek"); d636 1 a636 1 my $w = $this->parent->add("sortselection", 'Listbox', d676 1 a676 1 $this->parent->delete("sortselection"); d679 2 a680 2 my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; d687 2 a688 2 my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; d698 2 a699 2 my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; d710 2 a711 2 my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; d722 2 a723 2 my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; my ($dc, $dr) = @@{$matrixwidgetdatacell->{$this}}; d769 1 a769 1 $widget->{'main'}->draw; return; d841 4 d846 1 a846 1 $widget->{'dummy'} = $widget->{'main'}->add(undef, 'TextEntry', d866 1 a866 1 $widget->{'colruler'} = $widget->{'main'}->add(undef, 'Label', d872 1 a872 1 $widget->{'rowruler'} = $widget->{'main'}->add(undef, 'Label', d890 3 a892 2 $widget->{'main'}->draw; $widget->{'main'}->focus; @ 1.5 log @support for F7 column show/hide and F8 column sort with primitive dialog @ text @d528 6 a533 1 return; #do not change focus @ 1.4 log @F1 help; F9-F12 column resizing @ text @d8 2 a9 2 use Curses; use Curses::UI; d37 7 a43 4 KEY_F(9), #shrink col size to min KEY_F(10), #shrink col size KEY_F(11), #grow col size KEY_F(12), #grow col size to max d64 1 a64 1 "Width" => 9, #+int(10 * (rand()+.5)), d66 2 a67 1 "Colhide" => 0 d78 1 a78 1 "Height" => 1, #+int(rand()+.5), d544 117 @ 1.3 log @support for F5, mark for deletion; show status info for each line @ text @d32 2 a33 1 KEY_F(2), #EDIT d37 4 d493 20 d544 46 d706 1 a706 3 ); #&creatematrixdata(); @ 1.2 log @support for F3/F4; work like vi-o/On a new line @ text @d33 3 a35 2 KEY_F(3), #INS line KEY_F(4), #DEL line d510 9 d679 1 a679 1 my $upperleftcol = 3; @ 1.1 log @cui matrix editor @ text @d17 1 d24 13 d390 1 a390 1 # key bindings for navigation d394 1 a394 79 $matrixwidget->{"VC.$c.$r"}->set_binding( sub { my $this = shift; my $key = shift; my $nvc = $matrixwidget->{"NumVisualCol"} - 1; my $nvr = $matrixwidget->{"NumVisualRow"} - 1; my ($vc, $vr) = @@{$matrixwidgetvisualcell->{$this}}; if ($key == KEY_UP() or (not $editcell and $key eq "k")) { $vr--; if ($vr < 0) { $vrscroll = -1; $vr = 0; } } elsif ($key == KEY_PPAGE()) { $vr-=10; if ($vr < 0) { $vrscroll = $vr; $vr = 0; } } elsif ($key == KEY_DOWN() or (not $editcell and $key eq "j")) { $vr++; if ($vr > $nvr) { $vrscroll = 1; $vr = $nvr; } } elsif ($key == KEY_NPAGE()) { $vr+=10; if ($vr > $nvr) { $vrscroll = $vr - $nvr; $vr = $nvr; } } elsif (not $editcell and ($key == KEY_LEFT() or $key eq "h")) { $vc--; if ($vc < 0) { $vcscroll = -1; $vc = 0; } } elsif (not $editcell and ($key == KEY_RIGHT() or $key eq "l")) { $vc++; if ($vc > $nvc) { $vcscroll = 1; $vc = $nvc } } elsif ($key == KEY_HOME() && not $editcell) { $vr = 0; $vc = 0; } elsif ($key == KEY_END() && not $editcell) { $vr = $nvr; $vc = $nvc; } elsif ($key == KEY_F(2)) { $editcell = 1; } $matrixwidget->{"Cursorcol"} = $vc; $matrixwidget->{"Cursorrow"} = $vr; if ($vcscroll == 0 && $vrscroll == 0) { $matrixwidget->{"VC.$vc.$vr"}->focus; } else { $widget->{"dummy"}->focus; } }, KEY_UP(), "k", KEY_DOWN(), "j", KEY_LEFT(), "h", KEY_RIGHT(), "l", KEY_NPAGE(), KEY_PPAGE(), KEY_HOME(), KEY_END(), KEY_F(2), ); d431 88 d520 6 a525 6 foreach my $i (sort keys %{$matrixwidget}) { #DEBUG if ($i =~ m/^VC\.\d+\.\d+/ || $i =~ m/^(CH|RH)\.(\d+|fill.*)/) { #DEBUG $matrixwidget->{$i}->{-canvasscr}->standout; #DEBUG $matrixwidget->{$i}->draw; #DEBUG } #DEBUG } #DEBUG d528 1 a528 1 printf STDERR "DEBUG: destroying $i\n"; #DEBUG d534 3 a536 3 else { printf STDERR "DEBUG: saved \"$i\"\n"; } d677 1 d697 1 a697 1 if ($vrscroll != 0 or $vcscroll != 0) { @