File Coverage

lib/Curses/UI/Grid/Cell.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             ###############################################################################
2             # subclass of Curses::UI::Cell is a widget that can be used to display
3             # and manipulate cell in grid model
4             #
5             # (c) 2004 by Adrian Witas. All rights reserved.
6             #
7             # This program is free software; you can redistribute it and/or modify it
8             # under the same terms as perl itself.
9             ###############################################################################
10              
11              
12             package Curses::UI::Grid::Cell;
13              
14              
15 3     3   23799 use strict;
  3         8  
  3         165  
16 3     3   17 use warnings;
  3         7  
  3         102  
17              
18 3     3   2610 use Curses;
  0            
  0            
19             use Curses::UI::Common;
20             use Curses::UI::Grid;
21              
22             use vars qw(
23             $VERSION
24             @ISA
25             );
26              
27             $VERSION = '0.14';
28             @ISA = qw(Curses::UI::Grid);
29            
30              
31             sub new () {
32             my $class = shift;
33              
34             my %userargs = @_;
35             keys_to_lowercase(\%userargs);
36             my %args = (
37             # Parent info
38             -parent => undef # the parent object
39             ,-row => undef # row object
40             # Position and size
41             ,-x => 0 # horizontal position (rel. to -window)
42             ,-current_width => undef
43             ,-width => undef # default width 10
44             ,-align => 'L' # align L - left, R - right
45             # Initial state
46             ,-xpos => 0 # cursor position
47              
48             # General options
49             ,-maxlength => 0 # the maximum length. 0 = infinite
50             ,-overwrite => 1 # immdiately overwrite cell unless function char
51             ,-overwritetext => 1 # contol overwrite and function char (internally set)
52              
53             # Grid model
54             ,-text => '' # text
55             ,-fldname => '' # field name for data bididngs
56             ,-frozen => 0 # field name for data bididngs
57             ,-focusable => 1 # internally set
58             ,-readonly => 0 # readonly ?
59             ,%userargs
60             # Init values
61             ,-focus => 0
62             ,-bg_ => undef # user defined background color
63             ,-fg_ => undef # user defined font color
64             );
65            
66              
67             # Create the Widget.
68             my $this = {%args};
69             bless $this;
70              
71             $this->{-xoffset} = 0; #
72             $this->{-xpos} = 0; # X position for cursor in the document
73             $this->parent->layout_content;
74             $this;
75             }
76              
77             # set layout
78             sub set_position {
79             my ($this, $x, $current_width) = @_;
80             $this->x($x);
81             $this->current_width($current_width);
82             if($current_width > 0) {
83             $this->show
84             } else {
85             $this->hide;
86             }
87              
88             $current_width;
89             }
90              
91              
92             sub layout_text {
93             my $this = shift;
94             my $row= $this->row;
95             my $grid = $this->parent;
96             my $current_width = $this->current_width
97             or return;
98             my $width = $this->width;
99             my $alignlign = $this->align;
100             my $text = $this->text;
101            
102             # backward event compatibility
103             if ($grid->is_event_defined('-oncelllayout') && $row->type ne 'head') {
104             my $text_layouted = $grid->run_event('-oncelllayout', $this, $text);
105             $text = ref($text_layouted)
106             ? $text
107             : $text_layouted;
108             }
109            
110             my $text_length = length(($text || ''));
111            
112             if($alignlign eq 'R' && $text_length > $current_width) {
113             $text = substr(
114             $text,
115             ($text_length - $current_width - $this->xoffset),
116             $current_width
117             );
118             }
119            
120             if($alignlign eq 'L' && abs($this->xoffset)) {
121             $text = substr($text, -$this->xoffset, $current_width);
122             }
123              
124             $text = sprintf("%".(($alignlign || '') eq 'L' ? "-":"") . $width . "s", ($text ||''));
125             $text = $alignlign eq 'L'
126             ? substr($text, 0, $current_width)
127             : substr($text, (length($text) - $current_width), $current_width);
128             $text .= ' '
129             if(ref($this->row) && $this->row->type ne 'data');
130            
131             $text;
132             }
133              
134              
135             sub draw($;) {
136             my $this = shift;
137             my $no_doupdate = shift || 0;
138              
139             # Return immediately if this object is hidden.
140             return $this if $this->hidden;
141             return $this if $Curses::UI::screen_too_small;
142             my $grid =$this->parent;
143             my $row=$this->row(1);
144              
145             if( $#{$grid->{_rows}} > 1 ) {
146             $this->{-nocursor}=0;
147             } else {
148             $this->{-nocursor}=1;
149             }
150              
151             $row->canvasscr->attron(A_BOLD) if($row->{-focus});
152             $this->draw_cell(1,$row);
153             $row->canvasscr->attroff(A_BOLD) if($row->{-focus});
154             doupdate() if ! $no_doupdate && ! $grid->test_more;
155             $row->canvasscr->move($row->y,$this->xabs_pos);
156             $row->canvasscr->noutrefresh;
157              
158              
159             return $this;
160             }
161              
162              
163             sub draw_cell($$$) {
164             my $this = shift;
165             my $no_doupdate = shift || 0;
166             my $row = shift;
167             $row = $this->row($row);
168             return $this
169             if $this->hidden;
170             my $grid = $this->parent;
171            
172             $grid->run_event('-oncelldraw', $this)
173             if ($row->type ne 'head');
174            
175             my $fg=$row->type ne 'head' ? $this->fg : $grid->{-fg};
176             my $bg=$row->type ne 'head' ? $this->bg : $grid->{-bg};
177             my $pair=$grid->set_color($fg,$bg,$row->canvasscr);
178             my $x = $this->x;
179             my $text = $this->layout_text || '';
180             $text = substr($text, 0, $grid->canvaswidth - $x)
181             if (length($text) + $x >= $grid->canvaswidth);
182             $row->canvasscr->addstr($row->y, $x, $text);
183             $grid->color_off($pair, $row->canvasscr);
184             $this;
185             }
186              
187             sub text($$) {
188             my $this = shift;
189             my $text = shift;
190             my $result='';
191             my $row=$this->row;
192             my $grid =$this->parent;
193             my $type= $row->type || '';
194             my $id=$this->id;
195             #if row type is head return or set label attribute otherwise cell value
196             if(defined $text) {
197             if($type eq 'head') {
198             $this->{-label}=$text;
199             } else {
200             $row->{-cells}{$id}=$text;
201             }
202             }
203            
204             $result = $type eq 'head' ? $this->{-label} : exists $row->{-cells}{$id} ? $row->{-cells}{$id} :'' if($type) ;
205             return $result;
206             }
207              
208             sub cursor_right($) {
209             my $this = shift;
210             $this->overwriteoff;
211             $this->xoffset($this->xoffset-1) if($this->xpos() == ($this->current_width -1) );
212             $this->xpos($this->xpos+1);
213             $this->draw(1);
214            
215             return $this; return $this;
216             }
217              
218             sub cursor_left($) {
219             my $this = shift;
220             $this->overwriteoff;
221             $this->xoffset($this->xoffset+1) unless($this->xpos($this->xpos));
222             $this->xpos($this->xpos-1);
223             $this->draw(1);
224             return $this;
225             }
226              
227             sub cursor_to_home($) {
228             my $this = shift;
229             $this->overwriteoff;
230             my $text = $this->text;
231             my $current_width = $this->current_width;
232             my $align = $this->align;
233            
234             $this->xoffset($align eq 'L'
235             ? $current_width
236             : (length($text) - $current_width > 0
237             ? length($text) - $current_width
238             : 0 )
239             );
240              
241             $this->xpos($align eq 'L'
242             ? 0
243             : $current_width - length($text)
244             );
245             $this->draw(1);
246             }
247              
248              
249             sub cursor_to_end($) {
250             my $this = shift;
251             $this->overwriteoff;
252             my $text_lenght = length $this->text;
253             my $current_width = $this->current_width;
254             my $align = $this->align;
255             $current_width = $current_width > $text_lenght && $align eq 'L'
256             ? $text_lenght + 1
257             : $current_width;
258             $this->xoffset(
259             $align eq 'R'
260             ? 0
261             : $current_width - $text_lenght - 1)
262             if ($text_lenght >= $current_width);
263            
264             $this->xpos($align eq 'L'
265             ? $current_width - 1
266             : $current_width-1);
267            
268             $this->draw(1);
269             }
270              
271             sub delete_character($) {
272             my $this = shift;
273             return if $this->readonly;
274             my $ch = shift;
275             my $grid = $this->parent;
276             $grid->run_event('-oncellkeypress', $this, $ch)
277             or return;
278             $this->overwriteoff;
279             my $text=$this->text;
280             my $xo = $this->xoffset;
281             my $pos = $this->text_xpos;
282             my $len = $this->current_width+abs($this->xoffset);
283             my $align = $this->align;
284             my $current_width = $this->current_width;
285              
286             return if($align eq 'R' && $pos <= 0);
287             $this->xoffset($this->xoffset-1) if($align eq 'R' && $xo && length($text) - $xo >= $current_width);
288             $this->xoffset($this->xoffset-1) if($align eq 'L' && length($text) > $len);
289             $pos-- if($align eq 'R');
290             substr($text, $pos, 1, '') if(abs($pos) <= length($text));
291             $this->text($text);
292             $this->draw(1);
293             }
294              
295             sub backspace($) {
296             my $this = shift;
297             my $ch = shift;
298             return if $this->readonly;
299             my $grid =$this->parent;
300             $grid->run_event('-oncellkeypress', $this, $ch)
301             or return;
302             $this->overwriteoff;
303             my ($align,$xo)=($this->align,$this->xoffset);
304             $this->cursor_left;
305             $this->delete_character();
306             $this->cursor_right if($align eq 'R' );
307             }
308              
309             sub add_string($$;) {
310             my $this = shift;
311             my $ch = shift;
312             return if $this->readonly;
313             my $grid = $this->parent;
314              
315             my $ret= $grid->run_event('-oncellkeypress', $this, $ch)
316             or return;
317              
318             my @ch = split //, $ch;
319             $ch = '';
320             foreach (@ch) {
321             $ch .= $this->key_to_ascii($_);
322             }
323              
324              
325             $this->text('') if( $this->overwritetext );
326              
327             my ($xo,$pos,$len,$align)= ($this->xoffset ,$this->text_xpos, length($this->text),$this->align);
328             my $text=$this->text;
329              
330             substr($text, abs($pos) , 0) = $ch if($pos <= $len );
331             $this->text($text);
332             $this->cursor_right if($align eq 'L');
333             $this->draw();
334             $grid->run_event('-onaftercellkeypress', $this, $ch);
335             }
336              
337              
338              
339             # x of cell
340             sub x($;) {
341             my $this=shift;
342             my $x=shift;
343             $this->{-x}=$x if(defined $x);
344             return $this->{-x};
345             }
346              
347             # absolute x position to row
348             sub xabs_pos($;) {
349             my $this=shift;
350             my $result="";
351             my $xpos=( $this->xpos > ($this->current_width-1) ? $this->current_width-1 : $this->xpos );
352             $xpos =0 if($xpos < 0);
353             return $this->{-x} + $xpos;
354             }
355              
356              
357             # cursor relative x pos
358             sub xpos($;) {
359             my $this=shift;
360             my $x=shift;
361             if(defined $x){
362             $x = 0 if($x < 0);
363             $x= $this->width-1 if($x > $this->width-1 );
364             $this->{-xpos}=$x;
365             }
366             return $this->{-xpos};
367             }
368              
369              
370             # cursor position in text
371             sub text_xpos($;) {
372             my $this=shift;
373             my ($w,$x,$xo,$align,$l)=($this->current_width-1,$this->xpos,$this->xoffset,$this->align,length($this->text));
374             return $align eq 'R' ? $l-($w-$x+abs($xo)) : $x-$xo;
375             }
376              
377              
378             # offset to x pos
379             sub xoffset($;) {
380             my $this=shift;
381             my $xo=shift;
382             my ($align,$l,$w)=($this->align,length(($this->text || '')),$this->current_width);
383              
384             if( defined($xo) ) {
385             if($align eq 'L' ) {
386             $xo=0 if($xo > 0);
387             #$xo=$this->w-1 if($xo < 0);
388             } else {
389             $xo=$l-$w if($xo > ($l-$w) && $xo);
390             $xo=0 if($xo < 0);
391             }
392              
393              
394             $this->{-xoffset}=$xo;
395             }
396             return $this->{-xoffset};
397             }
398              
399              
400             # event of focus
401             sub event_onfocus()
402             {
403             my $this = shift;
404             my $grid =$this->parent;
405             $this->overwriteon;
406             $grid->{-cell_idx}=$grid->{-cellid2idx}{ $this->{-id} };
407              
408             # Store value of cell in case of data change
409             if(ref($this->row) && $this->row->type ne 'head' ) {
410             $this->row->set_undo_value($this->id,$this->text);
411             }
412             # Let the parent find another cell to focus
413             # if this widget is not focusable.
414             $this->{-focus} = 1;
415             if ($this->width != ($this->current_width ||0) || $this->hidden ) {
416             my $vs = $grid->get_x_offset_to_obj($this);
417             $grid->x_offset($vs);
418             }
419              
420             $this->xpos($this->align eq 'L' ? 0 : $this->current_width - 1);
421             $this->xoffset(0);
422             $grid->run_event('-oncellfocus', $this);
423             $this->draw(1);
424             return $this;
425             }
426              
427              
428             sub event_onblur() {
429             my $this = shift;
430             my $grid =$this->parent;
431             $this->xpos($this->align eq 'L' ? 0 : $this->current_width - 1);
432             $this->xoffset(0);
433             $grid->run_event('-oncellblur',$this)
434             or return;
435            
436             if (ref($this->row) && $this->row->type ne 'head' ) {
437             my $undo = $this->row->get_undo_value($this->id);
438             my $text = $this->text;
439            
440             # if data was changed
441              
442             $grid->run_event('-oncellchange', $this)
443             or return
444             if ($undo || '') ne ($text || '');
445             }
446            
447             $grid->{-cell_idx_prev} = $grid->{-cellid2idx}{$this->{-id}};
448             $this->{-focus} = 0;
449              
450             $this->draw;
451             $this;
452             }
453              
454             sub overwriteoff() { shift()->{-overwritetext}=0 }
455             sub overwriteon() { shift()->{-overwritetext}=1 }
456              
457              
458             sub overwritetext($;) {
459             my $this=shift;
460             my $result=!$this->{-overwrite} ? $this->{-overwrite} : $this->{-overwritetext};
461             $this->overwriteoff();
462             return $result;
463             }
464              
465             sub has_focus() {
466             my $this=shift;
467             my $grid =$this->parent;
468             my $result=0;
469             $result=1 if($this->{-focus});
470             return $result;
471             }
472              
473              
474             sub focus($;) {
475             my $this=shift;
476             # Let the parent focus this object.
477             my $parent = $this->parent;
478             $parent->focus($this) if defined $parent;
479             $this->draw(1);
480             return $this;
481             }
482              
483              
484             sub bg() {
485             my $this = shift;
486             my $bg=shift;
487             $this->{-bg_}=$bg if(defined $bg);
488             return $this->{-bg_} ? $this->{-bg_} : exists( $this->{-bg} ) && $this->{-bg} ? $this->{-bg} : $this->row->bg;
489             }
490              
491             sub fg() {
492             my $this = shift;
493             my $fg=shift;
494             $this->{-fg_}=$fg if(defined $fg);
495             return $this->{-fg_} ? $this->{-fg_} : exists( $this->{-fg} ) && $this->{-bg} ? $this->{-fg} : $this->row->fg;
496             }
497              
498             sub row() {
499             my ($this, $row) = @_;
500             $this->{-row} = $row
501             if defined $row;
502             $this->{-row} = $this->parent->get_foused_row
503             if(!ref($this->{-row}) || ref($this->{-row}) ne 'Curses::UI::Grid::Row');
504             return $this->{-row};
505             }
506              
507              
508              
509             sub align() { uc(shift()->{-align}) }
510             sub frozen() { shift->{-frozen} }
511             # defined width
512             sub width() {
513             my ($self, $width) = @_;
514             $self->{-width} = $width if(defined $width);
515             $self->{-width};
516             }
517              
518             #current width
519             sub current_width {
520             my ($this, $current_width) = @_;
521             $this->{-current_width} = $current_width
522             if (defined $current_width);
523             return $this->{-current_width};
524             }
525              
526             sub cleanup {
527             my $this = shift;
528             my $grid = $this->parent;
529             if ($grid) {
530             delete $this->{-cellid2idx}{$this->id};
531             delete $this->{-id2cell}{$this->id};
532             $grid->{-columns}--;
533             $this->{$_} = ''
534             for (qw(-canvasscr -parent -row));
535             }
536             }
537              
538             sub label {
539             my ($this, $label) = @_;
540             $this->{-label} = $label
541             if defined $label;
542             $this->{-label};
543             }
544              
545              
546             sub DESTROY {
547             my $this = shift;
548             $this->cleanup;
549             }
550              
551             __END__