File Coverage

WinConsole.pm
Criterion Covered Total %
statement 15 358 4.1
branch 0 100 0.0
condition 0 45 0.0
subroutine 5 41 12.2
pod n/a
total 20 544 3.6


line stmt bran cond sub pod time code
1             package WinConsole;
2              
3             require 5.005_62;
4 1     1   4337 use strict;
  1         1  
  1         25  
5 1     1   3 use warnings;
  1         1  
  1         91  
6              
7             require Exporter;
8              
9             our @ISA = qw(Exporter);
10              
11             our %EXPORT_TAGS = ( 'all' => [ qw() ] );
12              
13             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
14              
15             our @EXPORT = qw();
16              
17             our $VERSION = '0.01';
18              
19             $|++;
20              
21             ############################################################
22             ## Declarations
23             #
24              
25 1     1   4 use vars qw( @ISA $AUTOLOAD %sequences %attcode $MAXWIN $USECOLOR %borderChr);
  1         4  
  1         2392  
26              
27             $MAXWIN = 20;
28             $USECOLOR = 1;
29              
30             # %borderChr contains the different chars used to draw borders.
31             %borderChr = ( 'ul' => '/', 'ur' => '\\', 'bl' => '\\', 'br' => '/', 'hrz' => '=', 'vrt' => '|' );
32              
33             # %sequence is used to convert a command into its corresponding ANSI sequence. During runtime the '?'
34             # is replaced by a parameter.
35             #
36             # Idea taken from Term::ANSIScreen
37             #
38             %sequences = (
39             'black' => '30m', 'on_black' => '40m',
40             'red' => '31m', 'on_red' => '41m',
41             'green' => '32m', 'on_green' => '42m',
42             'yellow' => '33m', 'on_yellow' => '43m',
43             'blue' => '34m', 'on_blue' => '44m',
44             'magenta' => '35m', 'on_magenta' => '45m',
45             'cyan' => '36m', 'on_cyan' => '46m',
46             'white' => '37m', 'on_white' => '47m',
47             'clear' => '0m', 'reset' => '0m',
48             'light' => '1m', 'dark' => '2m',
49             'underline' => '4m', 'underscore' => '4m',
50             'blink' => '5m',
51             'reverse' => '7m',
52             'hidden' => '8m',
53             'up' => '?A', 'down' => '?B',
54             'right' => '?C', 'left' => '?D',
55             'savepos' => 's' , 'loadpos' => 'u',
56             'saveatt' => '7' , 'loadatt' => '8',
57             'cls' => '2J', 'cll' => '2K',
58             'locate' => '?;?H', 'setmode' => '?h',
59             'font0' => '(', 'font1' => ')',
60             'wrapon' => '7h', 'wrapoff' => '7l',
61             'fullreset' => 'c',
62             );
63              
64             # attcode is used to convert a color attribute into a bit rank thus combined attributes
65             # can give a unique integer
66             #
67             # format is :
68             # attrib back fore
69             # chrbld rgb rgb
70            
71             %attcode = (
72             'on_red' => 32,
73             'on_green' => 16,
74             'on_yellow' => 48,
75             'on_blue' => 8,
76             'on_magenta'=> 40,
77             'on_cyan' => 24,
78             'on_white' => 56,
79             'black' => 0,
80             'red' => 4,
81             'green' => 2,
82             'yellow' => 6,
83             'blue' => 1,
84             'magenta' => 5,
85             'cyan' => 3,
86             'white' => 7,
87             'light' => 64,
88             'dark' => 128,
89             'underline' => 256,
90             'blink' => 512,
91             'reverse' => 1024,
92             'hidden' => 2048,
93             'clear' => 4096,
94             );
95              
96             ############################################################
97             ## Constructor
98             #
99              
100             sub new {
101 0     0     my $class = shift;
102 0           my $title = shift;
103 0           my $colsize = shift;
104 0           my $rowsize = shift;
105 0           my $border = shift;
106 0           my $cr = shift;
107 0           my $pattern = shift;
108 0 0         my $buffered = shift; if (!defined($buffered)) {$buffered=1}
  0            
  0            
109              
110 0           my %object = (
111             "winActive" => 0, #active miniwin index
112             "miniwin" => undef, #miniwin structures reference
113             "useBuffer" => $buffered,#flag
114             "lsAtt" => undef, #last sent attribute
115             "frontTxt" => undef, #production text buffer reference
116             "frontAtt" => undef, #production attributes buffer reference
117             "zBuffer" => undef, #Z-Buffer reference
118             "winStack" => undef, #miniwins stack reference
119             "stats" => 0, #stats
120             );
121              
122             # Init the miniwin structure with a fullscreen miniwin (miniwin #0)
123 0           &setWindow(\%object,$title, 1, 1, $colsize, $rowsize, $border, $cr, $pattern);
124              
125             # Init buffers
126 0           my (@frontTxt,@frontAtt,@zBuffer);
127              
128 0           for (1..$rowsize){
129 0           push @frontTxt , $pattern x $colsize;
130 0           push @frontAtt , [(0) x $colsize];
131 0           push @zBuffer , [(0) x $colsize];
132             }
133              
134 0           $object{'frontAtt'} = \@frontAtt;
135 0           $object{'frontTxt'} = \@frontTxt;
136 0           $object{'zBuffer'} = \@zBuffer;
137              
138 0           return bless \%object , $class;
139             }
140              
141             #################################################
142             ## AUTOLOAD implementation
143             #
144              
145             # using %sequence keys as function name return/print the corresponding ANSI sequence
146             # Idea taken from Term::ANSIScreen
147              
148             sub AUTOLOAD {
149 0     0     my $sub;
150 0           ($sub = $AUTOLOAD) =~ s/^.*:://;
151 0 0         if (my $seq = $sequences{$sub}) {
152 0           shift(@_);
153 0 0         $seq =~ s/\?/defined($_[0]) ? shift(@_) : 1/eg;
  0            
154 0 0         return (defined wantarray) ? "\e[$seq" : print("\e[$seq");
155             }else{
156 0           die "Undefined subroutine &$AUTOLOAD called";
157             }
158             }
159              
160             sub DESTROY
161       0     {}
162              
163             ###########################################################################################
164             ## MISC FUNCTIONS
165             #
166              
167             # the stat counter is incremented each time a character is printed by a display function
168             # ( currently refresh and flush).
169             # this feature is given for optimisation purposes.
170              
171             sub resetStat
172             {
173 0     0     my ($self) = @_;
174 0           $self->{'stats'} = 0;
175             }
176              
177             sub getStat
178             {
179 0     0     my ($self) = @_;
180 0           return $self->{'stats'};
181             }
182              
183             ###########################################################################################
184             ## WINDOW STACK HANDLING
185             #
186              
187             # this stack is used to store windows depth level
188              
189             # add $idx on top of the stack
190             sub stackAdd
191             {
192 0     0     my ($self,$idx) = @_;
193 0           unshift(@{$self->{'winStack'}},$idx);
  0            
194             }
195              
196             # supress $idx from the stack
197             sub stackDel
198             {
199 0     0     my ($self,$idx) = @_;
200 0           my ($offset);
201            
202 0           $offset = stackFind($self,$idx);
203 0 0         if (defined $offset){
204 0           splice(@{$self->{'winStack'}},$offset,1);
  0            
205 0           return 1;
206             }else{
207 0           return undef;
208             }
209             }
210              
211             # move $idx on top of the stack
212             sub stackFocus
213             {
214 0     0     my ($self,$idx) = @_;
215 0 0         if (!defined(stackDel($self,$idx))){
216 0           stackAdd($self,$idx);
217 0           return 1;
218             }else{
219 0           return undef;
220             }
221             }
222              
223             # return the offset of $idx in the stack
224             sub stackFind
225             {
226 0     0     my ($self,$idx) = @_;
227 0           my ($offset);
228            
229 0           $offset = 0;
230 0           for (@{$self->{'winStack'}}){
  0            
231 0 0         if ($_==$idx){
232 0           return $offset;
233             }
234 0           $offset++
235             }
236 0           return undef;
237             }
238              
239             # return the index of the miniwin with $title as title
240             sub indexFind
241             {
242 0     0     my ($self,$title) = @_;
243 0           my ($idx);
244            
245 0           $idx = 0;
246 0           for (@{$self->{'miniwin'}}){
  0            
247 0 0         if ($_->{'title'} eq $title){
248 0           return $idx;
249             }
250 0           $idx++
251             }
252 0           return undef;
253             }
254              
255             # useful aliases
256             sub showWindow
257             {
258 0     0     my ($self,$idx) = @_;
259 0           my ($offset);
260              
261 0 0         if (!defined $idx){
262 0           $idx = $self->{'winActive'};
263             }
264            
265 0           $offset = stackFind($self,$idx);
266 0 0         if (!defined $offset){
267 0           &stackAdd($self,$idx);
268             }else{
269 0           &stackFocus($self,$idx);
270             }
271             }
272              
273             sub hideWindow
274             {
275 0     0     my ($self,$idx) = @_;
276 0           my ($offset);
277              
278 0 0         if (!defined $idx){
279 0           $idx = $self->{'winActive'};
280             }
281            
282 0           $offset = stackFind($self,$idx);
283 0 0         if (defined $offset){
284 0           &stackDel($self,$idx);
285             }
286             }
287              
288             ###########################################################################################
289             ## DISPLAY HANDLING
290             #
291              
292             # every drawing operations are made in a local miniwin buffer. Each time a display request is done,
293             # all the miniwins'buffer are melt into a unique 'backbuffer'.
294             #
295             # there are two methods to start a display :
296             # - refresh : simply overwrite the production buffer with the back buffer and display it.
297             # (it needs less computations but send more data to the terminal)
298             # - flush : makes a diff between the production and the back buffer and display only differences
299             # (more computations needed but less data sent to the terminal)
300              
301             sub makeFullBackBuffer
302             {
303 0     0     my ($self) = @_;
304 0           my (@backAtt,@backTxt,$screen,$current, $destCol, $destRow, $active );
305              
306 0           $screen = $self->{'miniwin'}[0];
307 0           for (1..$screen->{'height'}){
308 0           push @backTxt , ' ' x $screen->{'width'};
309 0           push @backAtt , [(0) x $screen->{'width'}];
310             }
311              
312 0           for $active (reverse @{$self->{'winStack'}})
  0            
313             {
314 0           $current=$self->{'miniwin'}[$active];
315 0           for my $row (1..$current->{'height'})
316             {
317 0           for my $col (1..$current->{'width'})
318             {
319 0           $destCol = $current->{'colTop'}+$col-2;
320 0 0         if ($destCol>$screen->{'width'}) { $destCol = $screen->{'width'} };
  0            
321 0           $destRow = $current->{'rowTop'}+$row-2;
322 0 0         if ($destRow>$screen->{'height'}) { $destRow = $screen->{'height'} };
  0            
323 0           $backAtt[$destRow][$destCol]=$current->{'backAtt'}[$row-1][$col-1];
324 0           $self->{'zBuffer'}[$destRow][$destCol]=$active;
325 0           substr($backTxt[$destRow],$destCol,1)=substr($current->{'backTxt'}[$row-1],$col-1,1);
326             }
327             }
328             }
329 0           return \(@backAtt,@backTxt);
330             }
331              
332              
333             sub flush
334             {
335 0     0     my ($self, $win) = @_;
336 0           my ($current, $curAtt, $col, $row, $gathering, $backAtt, $backTxt, $chunk, @chunk, $result );
337              
338 0 0         if (defined $win){
339 0 0         if ($win<$#{$self->{'miniwin'}}){
  0            
340 0           $win = $self->{'winActive'};
341             }else{
342 0           $win = 0;
343             }
344             }else{
345 0           $win = 0;
346             }
347              
348 0           ($backAtt,$backTxt) = &makeFullBackBuffer($self);
349 0           $current = $self->{'miniwin'}[$win];
350 0           $curAtt = $self->{'lsAtt'};
351 0           $gathering = 0;
352            
353 0           for my $row ($current->{'rowTop'}..($current->{'rowTop'}+$current->{'height'}-1))
354             {
355 0           for my $col ($current->{'colTop'}..($current->{'colTop'}+$current->{'width'}-1))
356             {
357 0 0         if (!$gathering){
358 0 0 0       if (($self->{'frontAtt'}[$row-1][$col-1]!=${$backAtt}[$row-1][$col-1])
  0   0        
      0        
359 0           ||(substr($self->{'frontTxt'}[$row-1],$col-1,1) ne substr(@{$backTxt}[$row-1],$col-1,1))
360             &&(($self->{'zBuffer'}[$row-1][$col-1]==$win)||($win==0))
361             ){
362             $chunk = {
363             "col" => $col,
364             "row" => $row,
365 0           "att" => ${$backAtt}[$row-1][$col-1],
366 0           "txt" => substr(@{$backTxt}[$row-1],$col-1,1),
  0            
367             };
368 0           $curAtt = ${$backAtt}[$row-1][$col-1];
  0            
369 0           $self->{'frontAtt'}[$row-1][$col-1]=${$backAtt}[$row-1][$col-1];
  0            
370 0           substr($self->{'frontTxt'}[$row-1],$col-1,1) = substr(@{$backTxt}[$row-1],$col-1,1);
  0            
371 0           $gathering = 1;
372             }
373             }else{
374 0 0 0       if ( ($curAtt == ${$backAtt}[$row-1][$col-1])
  0   0        
      0        
      0        
375             &&( ($self->{'frontAtt'}[$row-1][$col-1]!=${$backAtt}[$row-1][$col-1])
376             ||
377             (substr($self->{'frontTxt'}[$row-1],$col-1,1) ne substr(@{$backTxt}[$row-1],$col-1,1))
378             )
379             &&
380             (($self->{'zBuffer'}[$row-1][$col-1]!=$win)&&($win!=0))
381             ){
382 0           ${$chunk}{'txt'}.=substr(@{$backTxt}[$row-1],$col-1,1);
  0            
  0            
383 0           $self->{'frontAtt'}[$row-1][$col-1]=${$backAtt}[$row-1][$col-1];
  0            
384 0           substr($self->{'frontTxt'}[$row-1],$col-1,1) = substr(@{$backTxt}[$row-1],$col-1,1);
  0            
385             }else{
386 0           push @chunk, $chunk;
387 0           undef($chunk);
388 0           $gathering = 0;
389             # at this point we're ending the current chunk
390             # but the current char is maybe the beginning of a new chunk
391             # so we redo the current loop
392 0           redo;
393             }
394             }
395             }
396 0 0         if ($gathering){
397 0           push @chunk, $chunk;
398 0           undef($chunk);
399 0           $gathering = 0;
400             }
401             }
402            
403 0           $result = "\e[s";
404              
405 0           for(@chunk){
406              
407 0 0         if (!$_) { next; }
  0            
408              
409 0           $result.="\e[0m";
410 0           $self->{'stats'}+= length("\e[0m");
411              
412 0           $result.="\e[".${$_}{'row'}.";".${$_}{'col'}."H";
  0            
  0            
413 0           $self->{'stats'}+= length("\e[".${$_}{'row'}.";".${$_}{'col'}."H");
  0            
  0            
414              
415 0           $result.=&att2seq(${$_}{'att'});
  0            
416 0           $self->{'stats'}+= length(&att2seq(${$_}{'att'}));
  0            
417              
418 0           $result.=${$_}{'txt'};
  0            
419 0           $self->{'stats'}+= length(${$_}{'txt'});
  0            
420              
421 0           $self->{'lsAtt'} = ${$_}{'att'};
  0            
422             }
423 0           $result.="\e[u";
424 0           undef (@chunk);
425 0 0         return (defined wantarray) ? $result : print $result;
426             }
427              
428              
429             sub fullDump
430             {
431 0     0     my ($self, $win) = @_;
432 0           my ($current, $lastAtt, $backAtt, $backTxt, $result);
433              
434 0 0         if (defined $win){
435 0 0         if ($win<$#{$self->{'miniwin'}}){
  0            
436 0           $win = $self->{'winActive'};
437             }else{
438 0           $win = 0;
439             }
440             }else{
441 0           $win = 0;
442             }
443              
444 0           $lastAtt=0;
445              
446 0           $current = $self->{'miniwin'}[$win];
447              
448 0           ($backAtt,$backTxt) = &makeFullBackBuffer($self);
449              
450 0           @{$self->{'frontAtt'}} = @{$backAtt};
  0            
  0            
451 0           @{$self->{'frontTxt'}} = @{$backTxt};
  0            
  0            
452              
453 0           $result = "\e[s";
454 0           for my $row ($current->{'rowTop'}..($current->{'rowTop'}+$current->{'height'}-1))
455             {
456 0           $result.="\e[".$row.";".$current->{'colTop'}."H";
457 0           $self->{'stats'}+= length("\e[".$row.";".$current->{'colTop'}."H");
458              
459 0           for my $col ($current->{'colTop'}..($current->{'colTop'}+$current->{'width'}-1))
460             {
461 0 0 0       if (
462             ($self->{'zBuffer'}[$row-1][$col-1]==$win)
463             ||
464             ($win==0)
465             )
466             {
467 0 0         if ($self->{'frontAtt'}[$row-1][$col-1]!=$lastAtt){
468 0           $result.="\e[0m";
469 0           $self->{'stats'}+= length("\e[0m");
470            
471 0           $result.=&att2seq($self->{'frontAtt'}[$row-1][$col-1]);
472 0           $self->{'stats'}+= length(&att2seq($self->{'frontAtt'}[$row-1][$col-1]));
473            
474 0           $lastAtt = $self->{'frontAtt'}[$row-1][$col-1];
475 0           $self->{'lsAtt'} = $lastAtt;
476             }
477            
478 0           $result.=substr($self->{'frontTxt'}[$row-1],$col-1,1);
479 0           $self->{'stats'}+= length(substr($self->{'frontTxt'}[$row-1],$col-1,1));
480             }
481             }
482             }
483 0           $result.="\e[u";
484              
485 0 0         return (defined wantarray) ? $result : print $result;
486             }
487              
488             ###########################################################################################
489             ## CURSOR HANDLING
490             #
491              
492             sub gotoCR
493             {
494 0     0     my ($self, $column, $row) = @_;
495 0           my ($current, $modif);
496              
497 0           $current = $self->{'miniwin'}[$self->{'winActive'}];
498              
499 0 0         if ($current->{'border'}) {
500 0           $modif = 2;
501             }else{
502 0           $modif = 1;
503             }
504              
505             # return on bad values
506 0 0 0       return undef if ((!$column)||(!$row));
507              
508             # -1 means the last column/row
509 0 0         if ($column<0){
510 0           $column = $current->{'width'}-$modif+$column+1;
511             }
512 0 0         if ($row<0){
513 0           $row = $current->{'height'}-$modif+$row+1;
514             }
515            
516 0 0         if ($row<=($current->{'height'}-$modif)){
517 0           $current->{'cursRow'}=$row;
518             }else{
519 0 0         if ($current->{'carrRet'}){
520 0           &scrollWin($self,'up',1);
521 0           $current->{'cursRow'}=$current->{'height'}-$modif;
522 0           $current->{'curscol'}=1;
523             }else{
524 0           return undef;
525             }
526             }
527              
528 0 0         if ($column<=($current->{'width'}-$modif)){
529 0           $current->{'cursCol'}=$column;
530             }else{
531 0 0         if ($current->{'carrRet'}){
532 0           &doCR($self);
533 0           ($column, $row) = &getCR;
534             }else{
535 0           return undef;
536             }
537             }
538 0           return 1;
539             }
540              
541             sub getCR
542             {
543 0     0     my ($self) = @_;
544 0           my $current;
545              
546 0           $current = $self->{'miniwin'}[$self->{'winActive'}];
547              
548 0           return $current->{'cursCol'},$current->{'cursRow'};
549             }
550              
551             sub getAbsCR
552             {
553 0     0     my ($self) = @_;
554 0           my ($current, $col, $row);
555              
556 0           $current = $self->{'miniwin'}[$self->{'winActive'}];
557 0           ($col, $row) = &getCR;
558            
559 0 0         if ($current->{'border'}){
560 0           $col++;
561 0           $row++;
562             }
563 0           return ($col + $current->{'colTop'} - 1),($row + $current->{'rowTop'} - 1 );
564             }
565              
566             sub doCR
567             {
568 0     0     my ($self) = @_;
569 0           my ($col,$row);
570              
571 0           ($col, $row) = &getCR;
572 0           $col = 1;
573 0           $row++;
574 0           &gotoCR($self, $col, $row);
575             }
576              
577             sub readyCurs
578             {
579 0     0     my ($self, $col, $row) = @_;
580 0           my ($current);
581              
582 0           $current = $self->{'miniwin'}[$self->{'winActive'}];
583              
584 0 0         if (!$col){
585 0           $col = $current->{'cursCol'};
586             }
587              
588 0 0         if (!$row){
589 0           $row = $current->{'cursRow'};
590             }
591              
592             # correction des coordonnées par gotoCR/getAbsCR
593 0           &gotoCR($self,$col,$row);
594 0           ($col,$row) = &getAbsCR;
595 0           print "\e[0m";
596 0           print &att2seq($self->{'frontAtt'}[$row-1][$col-1]);
597 0           $self->{'lsAtt'} = $self->{'frontAtt'}[$row-1][$col-1];
598 0           print("\e[".$row.";".$col."H");
599             }
600              
601             ###########################################################################################
602             ## COLOR HANDLING
603             #
604              
605             sub setWinColor
606             {
607 0     0     my ($self, $color) = @_;
608 0           return $self->{'miniwin'}[$self->{'winActive'}]->{'winCol'} = &codeAtt($color);
609            
610             }
611              
612             sub setCurrentColor
613             {
614 0     0     my ($self, $color) = @_;
615 0           return $self->{'miniwin'}[$self->{'winActive'}]->{'curCol'} = &codeAtt($color);
616            
617             }
618              
619             sub resetColor
620             {
621 0     0     my ($self) = @_;
622 0           return $self->{'miniwin'}[$self->{'winActive'}]->{'curCol'} = $self->{'miniwin'}[$self->{'winActive'}]->{'winCol'};
623             }
624              
625             ###########################################################################################
626             ## ATTRIBUTES STRING CODING/UNCODING
627             #
628             sub codeAtt
629 0           {
630 1     1   6 no warnings;
  1         0  
  1         76  
631 0     0     my ($attStr) = @_;
632 0           my ($code);
633            
634 0           $code=0;
635 0           foreach(split ' ',$attStr){
636 0           $code |= $attcode{$_};
637             }
638 0           return $code;
639 1     1   4 use warnings;
  1         1  
  1         1368  
640             }
641              
642             sub uncodeAtt
643             {
644 0     0     my ($code) = @_;
645 0           my ($attStr, $key, $val, $idx);
646              
647             #decimal to binary conversion
648 0           $code = unpack("B32", pack("N",$code));
649              
650 0 0         if ($USECOLOR){
651             #extracting background color
652 0           $val = unpack("N", pack("B32", substr("0"x32 .substr($code, -3, 3),-32)));
653 0 0         foreach $key (keys %attcode){ if ($attcode{$key}==$val){ $attStr.=" $key"; }}
  0            
  0            
654            
655             #extracting foreground color
656 0           $val = unpack("N", pack("B32", substr("0"x32 .substr($code, -6, 3),-32)));
657 0 0         foreach $key (keys %attcode){ if ($attcode{$key}==$val){ $attStr.=" on_$key"; }}
  0            
  0            
658             }
659              
660             #extracting attributes
661 0           $val = substr($code, -13, 7);
662 0           for $idx (1..length($val)){
663 0 0         if (substr($val,-$idx,1)){
664 0           foreach (keys %attcode){
665 0 0         if ($attcode{$_}==(2**($idx+5))){
666 0           $attStr.=" $_";
667             }
668             }
669             }
670             }
671 0           return $attStr;
672             }
673              
674             sub att2seq
675             {
676 0     0     my ($code) = @_;
677 0           my ($attStr, $sequence);
678            
679 0           $attStr= &uncodeAtt($code);
680 0           foreach(split ' ',$attStr){
681 0           $sequence .= "\e[".$sequences{$_};
682             }
683 0           return $sequence;
684             }
685              
686              
687             ###########################################################################################
688             ## MINIWINS HANDLING
689             #
690              
691             sub deleteWin
692             {
693 0     0     my ($self, $winId) = @_;
694 0 0 0       if (($winId>0)&&($winId<$#{$self->{'miniwin'}})){
  0            
695 0           $self->{'miniwin'}[$winId]= undef;
696 0 0         if ($self->{'winActive'}==$winId){
697 0           $self->{'winActive'}=0;
698             }
699 0           return 1;
700             }else{
701 0           return undef;
702             }
703             }
704              
705             sub setWinBorder
706             {
707 0     0     my ($self, $flag) = @_;
708 0           return $self->{'miniwin'}[$self->{'winActive'}]->{'border'} = $flag;
709             }
710              
711             sub setWinCarret
712             {
713 0     0     my ($self, $flag) = @_;
714 0           return $self->{'miniwin'}[$self->{'winActive'}]->{'carrRet'} = $flag;
715             }
716              
717             sub setActiveWin
718             {
719 0     0     my ($self, $winId) = @_;
720 0 0 0       if ( ($winId<=$#{$self->{'miniwin'}}) && (defined ($self->{'miniwin'}[$winId])))
  0            
721             {
722 0           $self->{'winActive'} = $winId;
723             }else{
724 0           return undef;
725             }
726             }
727              
728             sub setWinPattern
729             {
730 0     0     my ($self, $pattern) = @_;
731 0           return $self->{'miniwin'}[$self->{'winActive'}]->{'pattern'} = $pattern;
732             }
733              
734             sub setWinTitle
735             {
736 0     0     my ($self, $title) = @_;
737 0           return $self->{'miniwin'}[$self->{'winActive'}]->{'title'} = $title;
738             }
739              
740             sub setWinCol
741             {
742 0     0     my ($self, $col) = @_;
743            
744 0 0 0       if (($col>0)
745             &&($col<=($self->{'miniwin'}[0]->{'width'}-$self->{'miniwin'}[$self->{'winActive'}]->{'width'}+1))
746             ){
747 0           return $self->{'miniwin'}[$self->{'winActive'}]->{'colTop'} = $col;
748             }else{
749 0           return undef;
750             }
751             }
752              
753             sub setWinRow
754             {
755 0     0     my ($self, $row) = @_;
756            
757 0 0 0       if (($row>0)
758             &&($row<=($self->{'miniwin'}[0]->{'height'}-$self->{'miniwin'}[$self->{'winActive'}]->{'height'}+1))
759             ){
760 0           return $self->{'miniwin'}[$self->{'winActive'}]->{'rowTop'} = $row;
761             }else{
762 0           return undef;
763             }
764             }
765              
766             sub setWinWidth
767             {
768 0     0     my ($self, $width) = @_;
769 0           my ($current);
770              
771 0           $current = $self->{'miniwin'}[$self->{'winActive'}];
772 0 0 0       if (($width>0)
773             &&($width<=length($current->{'backTxt'}[0]))
774             ){
775 0           return $self->{'miniwin'}[$self->{'winActive'}]->{'width'} = $width;
776             }else{
777 0           return undef;
778             }
779             }
780              
781             sub setWinHeight
782             {
783 0     0     my ($self, $height) = @_;
784 0           my ($current);
785            
786 0           $current = $self->{'miniwin'}[$self->{'winActive'}];
787 0 0 0       if (($height>0)
788 0           &&($height<=$#{$current->{'backTxt'}}+1)
789             ){
790 0           return $self->{'miniwin'}[$self->{'winActive'}]->{'height'} = $height;
791             }else{
792 0           return undef;
793             }
794             }
795              
796             sub setWindow
797             {
798             my ($self, $title, $colTop, $rowTop, $width, $height, $border, $cr, $pattern) = @_;
799             my ($screen, $newwin, @backTxt, @backAtt);
800              
801             if (!defined($title)) {$title=''}
802             if (!defined($colTop)) {$colTop=1}
803             if (!defined($rowTop)) {$rowTop=1}
804             if (!defined($width)) {$width=80}
805             if (!defined($height)) {$height=25}
806             if (!defined($border)) {$border=0}
807             if (!defined($cr)) {$cr=1}
808             if (!defined($pattern)) {$pattern=' '}
809              
810             if ($#{$self->{'miniwin'}}<$MAXWIN)
811             {
812             if (defined(@{$self->{'miniwin'}}))
813             {
814             $screen = $self->{'miniwin'}[0];
815             if ($colTop>=$screen->{'width'}){
816             $colTop = 1;
817             }
818             if ($rowTop>=$screen->{'height'}){
819             $rowTop = 1;
820             }
821             if (($colTop+$width-1)>$screen->{'width'}){
822             $width = $screen->{'width'} - $colTop +1 ;
823             }
824             if (($height+$rowTop-1)>$screen->{'height'}){
825             $height = $screen->{'height'} - $rowTop +1 ;
826             }
827             }
828              
829             for (1..$height){
830             push @backTxt , $pattern x $width;
831             push @backAtt , [(0) x $width];
832             }
833              
834             $newwin = {
835             "title" => $title,
836             "colTop" => $colTop,
837             "rowTop" => $rowTop,
838             "width" => $width,
839             "height" => $height,
840             "border" => $border,
841             "cursRow" => 1,
842             "cursCol" => 1,
843             "carrRet" => $cr,
844             "winCol" => &codeAtt("white on_black"),
845             "curCol" => &codeAtt("white on_black"),
846             "pattern" => $pattern,
847             "backTxt" => \@backTxt,
848             "backAtt" => \@backAtt
849             };
850              
851             if (!defined(@{$self->{'miniwin'}}))
852             {
853             $self->{'miniwin'} = [$newwin];
854             }else{
855             push @{$self->{'miniwin'}} , $newwin;
856             }
857            
858             &stackAdd($self, $#{$self->{'miniwin'}});
859            
860             return $#{$self->{'miniwin'}};
861             }else{
862             return undef;
863             }
864             }
865              
866             ###########################################################################################
867             ## DISPLAY HANDLING
868             #
869             sub home
870             {
871             my ($self) = @_;
872             my ($current, $row, $col);
873              
874             $current = $self->{'miniwin'}[$self->{'winActive'}];
875              
876             for my $row (1..$current->{'height'})
877             {
878             for my $col (1..$current->{'width'})
879             {
880             $current->{'backAtt'}[$row-1][$col-1] = $current->{'winCol'};
881             substr($current->{'backTxt'}[$row-1],$col-1,1)= $current->{'pattern'};
882             }
883             }
884              
885             if ($current->{'border'})
886             {
887             # 201 upperleft corner symbol
888             $col = 1;
889             $row = 1;
890             $current->{'backAtt'}[$row-1][$col-1] = $current->{'winCol'};
891             substr($current->{'backTxt'}[$row-1],$col-1,1)= $borderChr{'ul'};
892              
893             # 187 upperright corner symbol
894             $col = $current->{'width'};
895             $row = 1;
896             $current->{'backAtt'}[$row-1][$col-1] = $current->{'winCol'};
897             substr($current->{'backTxt'}[$row-1],$col-1,1)= $borderChr{'ur'};
898              
899             # 188 bottomright corner symbol
900             $col = $current->{'width'};
901             $row = $current->{'height'};
902             $current->{'backAtt'}[$row-1][$col-1] = $current->{'winCol'};
903             substr($current->{'backTxt'}[$row-1],$col-1,1)= $borderChr{'br'};
904              
905             # 200 bottomleft corner symbol
906             $col = 1;
907             $row = $current->{'height'};
908             $current->{'backAtt'}[$row-1][$col-1] = $current->{'winCol'};
909             substr($current->{'backTxt'}[$row-1],$col-1,1)= $borderChr{'bl'};
910              
911             # 205 horizontal symbol
912             for (2..$current->{'width'}-1)
913             {
914             $col = $_;
915             $row = 1;
916             $current->{'backAtt'}[$row-1][$col-1] = $current->{'winCol'};
917             substr($current->{'backTxt'}[$row-1],$col-1,1)= $borderChr{'hrz'};
918             $row = $current->{'height'};
919             $current->{'backAtt'}[$row-1][$col-1] = $current->{'winCol'};
920             substr($current->{'backTxt'}[$row-1],$col-1,1)= $borderChr{'hrz'};
921             }
922              
923             # title
924             $col = 3;
925             $row = 1;
926             my $title = $current->{'title'}.($borderChr{'hrz'} x ($current->{'width'}-1));
927             substr($current->{'backTxt'}[$row-1],$col-1,$current->{'width'}-4)= substr ($title,0,$current->{'width'}-4);
928            
929              
930             # 186 vertical symbol
931             for (2..$current->{'height'}-1)
932             {
933             $row = $_;
934             $col = 1;
935             $current->{'backAtt'}[$row-1][$col-1] = $current->{'winCol'};
936             substr($current->{'backTxt'}[$row-1],$col-1,1)= $borderChr{'vrt'};
937             $col = $current->{'width'};
938             $current->{'backAtt'}[$row-1][$col-1] = $current->{'winCol'};
939             substr($current->{'backTxt'}[$row-1],$col-1,1)= $borderChr{'vrt'};
940             }
941             }
942             &gotoCR($self,1,1);
943             }
944              
945             sub deleteCh
946             {
947             my ($self, $col, $row) = @_;
948             my ($current);
949              
950             $current = $self->{'miniwin'}[$self->{'winActive'}];
951             return &printCh($self, $current->{'pattern'}, $col, $row);
952             }
953              
954             sub printCh
955             {
956             my ($self, $char , $col, $row) = @_;
957             my ($current, $oldCol, $oldRow, $modif);
958              
959             $current = $self->{'miniwin'}[$self->{'winActive'}];
960              
961             if ($current->{'border'}) {
962             $modif = 1;
963             }else{
964             $modif = 0;
965             }
966              
967             if ($char ne "\n"){
968             ($oldCol, $oldRow) = &getCR;
969             if (&gotoCR($self, $col, $row)){
970             substr ($current->{'backTxt'}[$row-1+$modif],$col-1+$modif,1) = $char;
971             $current->{'backAtt'}[$row-1+$modif][$col-1+$modif] = $current->{'curCol'};
972             &gotoCR($self,$oldCol,$oldRow);
973             return 1;
974             }else{
975             return undef;
976             }
977             }else{
978             &doCR($self);
979             return 1;
980             }
981             }
982              
983             sub streamCh
984             {
985             my ($self, $char) = @_;
986             my ($current, $col, $row, $modif);
987              
988             $current = $self->{'miniwin'}[$self->{'winActive'}];
989              
990             if ($current->{'border'}) {
991             $modif = 1;
992             }else{
993             $modif = 0;
994             }
995              
996             if ($char ne "\n"){
997             ($col,$row) = &getCR;
998             substr ($current->{'backTxt'}[$row-1+$modif],$col-1+$modif,1) = $char;
999             $current->{'backAtt'}[$row-1+$modif][$col-1+$modif] = $current->{'curCol'};
1000             ($col,$row) = &getCR;
1001             return &gotoCR($self,$col+1,$row);;
1002             }else{
1003             &doCR($self);
1004             return 1;
1005             }
1006              
1007             }
1008              
1009             sub printSt
1010             {
1011             my ($self, $chars) = @_;
1012             for (1..length($chars))
1013             {
1014             &streamCh($self,substr($chars,$_-1,1));
1015             }
1016             }
1017              
1018             sub centerSt
1019             {
1020             my ($self, $chars) = @_;
1021             my ($current, $modif, $pos, $slice);
1022              
1023             $current = $self->{'miniwin'}[$self->{'winActive'}];
1024              
1025             if ($current->{'border'}) {
1026             $modif = 2;
1027             }
1028            
1029             foreach(split "\n",$chars){
1030             $slice = $_;
1031             if (($current->{'width'}-$modif)>length($slice)){
1032             $pos = ($current->{'width'}-length($slice))/2;
1033             }else{
1034             $pos=1;
1035             }
1036             &gotoCR($self,$pos,$current->{'cursRow'});
1037             for (1..length($slice))
1038             {
1039             &streamCh($self,substr($slice,$_-1,1));
1040             }
1041             if ($chars=~/$slice/){
1042             &doCR($self);
1043             }
1044             }
1045            
1046             }
1047              
1048             ###########################################################################################
1049             #### SCROLL HANDLING
1050             #
1051              
1052             sub scrollWin # up, down, left right
1053             {
1054             my ($self, $dir, $dist) = @_;
1055             my ($current, @saveText, @saveAtt, $modif, %src, %clip, $colDest, $rowDest);
1056              
1057             $current = $self->{'miniwin'}[$self->{'winActive'}];
1058             if (!$dist){
1059             $dist=1;
1060             }
1061              
1062             if ($current->{'border'}){
1063             $modif = 1;
1064             }
1065              
1066             if (($dir eq 'down')||($dir eq 'd'))
1067             {
1068             $colDest = 1+$modif;
1069             $rowDest = 1+$modif+$dist;
1070             $src{'left'} = 1+$modif;
1071             $src{'top'} = 1+$modif;
1072             $src{'height'} = $current->{'height'}-$modif*2-$dist;
1073             $src{'width'} = $current->{'width'}-$modif*2;
1074             $clip{'left'} = 1+$modif;
1075             $clip{'top'} = 1+$modif;
1076             $clip{'width'} = $current->{'width'}-$modif*2;
1077             $clip{'height'}= $dist;
1078             }
1079              
1080             if (($dir eq 'right')||($dir eq 'r'))
1081             {
1082             $colDest = 1+$modif+$dist;
1083             $rowDest = 1+$modif;
1084             $src{'left'} = 1+$modif;
1085             $src{'top'} = 1+$modif;
1086             $src{'height'} = $current->{'height'}-$modif*2;
1087             $src{'width'} = $current->{'width'}-$dist-$modif*2;
1088             $clip{'left'} = 1+$modif;
1089             $clip{'top'} = 1+$modif;
1090             $clip{'width'} = $dist;
1091             $clip{'height'}= $current->{'height'}-$modif*2;
1092             }
1093              
1094             if (($dir eq 'up')||($dir eq 'u'))
1095             {
1096             $colDest = 1+$modif;
1097             $rowDest = 1+$modif;
1098             $src{'left'} = 1+$modif;
1099             $src{'top'} = 1+$modif+$dist;
1100             $src{'height'} = $current->{'height'}-$modif*2-$dist;
1101             $src{'width'} = $current->{'width'}-$modif*2;
1102             $clip{'left'} = 1+$modif;
1103             $clip{'top'} = 1+$current->{'height'}-$dist-$modif;
1104             $clip{'width'} = $current->{'width'}-$modif*2;
1105             $clip{'height'}= $dist;
1106             }
1107              
1108             if (($dir eq 'left')||($dir eq 'l'))
1109             {
1110             $colDest = 1+$modif;
1111             $rowDest = 1+$modif;
1112             $src{'left'} = 1+$modif+$dist;
1113             $src{'top'} = 1+$modif;
1114             $src{'height'} = $current->{'height'}-$modif*2;
1115             $src{'width'} = $current->{'width'}-$dist-$modif*2;
1116             $clip{'left'} = 1+$current->{'width'}-$dist-$modif;
1117             $clip{'top'} = 1+$modif;
1118             $clip{'width'} = $dist;
1119             $clip{'height'}= $current->{'height'}-$modif*2;
1120             }
1121              
1122             #Backup buffers creation
1123             for (0..$src{'height'}-1){
1124             push @saveAtt , [(0) x $src{'width'}];
1125             push @saveText , '' x $src{'width'};
1126             }
1127              
1128             #Save the data
1129             for my $row (0..$src{'height'}-1)
1130             {
1131             for my $col (0..$src{'width'}-1)
1132             {
1133             $saveAtt[$row][$col]=$current->{'backAtt'}[$src{'top'}+$row-1][$src{'left'}+$col-1];
1134             substr($saveText[$row],$col,1) = substr($current->{'backTxt'}[$src{'top'}+$row-1],$src{'left'}+$col-1,1);
1135             }
1136             }
1137              
1138             for my $row (0..$src{'height'}-1)
1139             {
1140             for my $col (0..$src{'width'}-1)
1141             {
1142             $current->{'backAtt'}[$rowDest+$row-1][$colDest+$col-1]=$saveAtt[$row][$col];
1143             substr($current->{'backTxt'}[$rowDest+$row-1],$colDest+$col-1,1) = substr($saveText[$row],$col,1);
1144             }
1145             }
1146             for my $row (0..$clip{'height'}-1)
1147             {
1148             for my $col (0..$clip{'width'}-1)
1149             {
1150             $current->{'backAtt'}[$clip{'top'}+$row-1][$clip{'left'}+$col-1]= $current->{'winCol'};
1151             substr($current->{'backTxt'}[$clip{'top'}+$row-1],$clip{'left'}+$col-1,1) = $current->{'pattern'};
1152             }
1153             }
1154             }
1155              
1156             sub pasteWin # up, down, left right
1157             {
1158             my ($self, $dir, $txtref, $attref) = @_;
1159             my ($current, @saveText, @saveAtt, $modif, %src, %clip, $colDest, $rowDest, $dist);
1160              
1161             $current = $self->{'miniwin'}[$self->{'winActive'}];
1162              
1163             @saveText = @{$txtref};
1164             if (defined $attref){
1165             @saveAtt = @{$attref};
1166             }
1167              
1168             if ($current->{'border'}){
1169             $modif = 1;
1170             }
1171              
1172             if (($dir eq 'up')||($dir eq 'u')||($dir eq 'down')||($dir eq 'd'))
1173             {
1174             # test hrz validity
1175             if ((length $saveText[0]<($current->{'width'}-$modif*2))
1176             or ( (defined $attref)
1177             and ($#{@{$attref}[0]}<($current->{'width'}-1-$modif*2))
1178             )
1179             ){
1180             return undef;
1181             }else{
1182             $dist=$#saveText+1;
1183             }
1184             }
1185              
1186             if (($dir eq 'left')||($dir eq 'l')||($dir eq 'right')||($dir eq 'r'))
1187             {
1188             # test vrt validity
1189             if (($#saveText<($current->{'height'}-1-$modif*2))
1190             or ( (defined $attref)
1191             and ($#{@{$attref}}<($current->{'height'}-1-$modif*2))
1192             )
1193             ){
1194             return undef;
1195             }else{
1196             $dist=length $saveText[0];
1197             }
1198             }
1199              
1200             if (($dir eq 'up')||($dir eq 'u'))
1201             {
1202             $clip{'left'} = 1+$modif;
1203             $clip{'top'} = 1+$modif;
1204             $clip{'width'} = $current->{'width'}-$modif*2;
1205             $clip{'height'}= $dist;
1206             }
1207              
1208             if (($dir eq 'left')||($dir eq 'l'))
1209             {
1210             $clip{'left'} = 1+$modif;
1211             $clip{'top'} = 1+$modif;
1212             $clip{'width'} = $dist;
1213             $clip{'height'}= $current->{'height'}-$modif*2;
1214             }
1215              
1216             if (($dir eq 'down')||($dir eq 'd'))
1217             {
1218             $clip{'left'} = 1+$modif;
1219             $clip{'top'} = 1+$current->{'height'}-$dist-$modif;
1220             $clip{'width'} = $current->{'width'}-$modif*2;
1221             $clip{'height'}= $dist;
1222             }
1223              
1224             if (($dir eq 'right')||($dir eq 'r'))
1225             {
1226             $clip{'left'} = 1+$current->{'width'}-$dist-$modif;
1227             $clip{'top'} = 1+$modif;
1228             $clip{'width'} = $dist;
1229             $clip{'height'}= $current->{'height'}-$modif*2;
1230             }
1231              
1232             for my $row (0..$clip{'height'}-1)
1233             {
1234             for my $col (0..$clip{'width'}-1)
1235             {
1236             if (@saveAtt){
1237             $current->{'backAtt'}[$clip{'top'}+$row-1][$clip{'left'}+$col-1]= $saveAtt[$row][$col];
1238             }else{
1239             $current->{'backAtt'}[$clip{'top'}+$row-1][$clip{'left'}+$col-1] = $current->{'winCol'};
1240             }
1241             substr($current->{'backTxt'}[$clip{'top'}+$row-1],$clip{'left'}+$col-1,1) = substr($saveText[$row],$col,1);
1242             #print " $col : $row '".substr($current->{'backTxt'}[$clip{'top'}+$row-1],$clip{'left'}+$col-1,1)."' on ".$saveAtt[$row][$col]."\n";
1243             }
1244             }
1245            
1246             return $dist;
1247             }
1248              
1249              
1250             1;
1251             __END__