File Coverage

blib/lib/Gtk2/Ex/TiedMenuChildren.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             # Copyright 2010 Kevin Ryde
2              
3             # This file is part of Gtk2-Ex-TiedListColumn.
4             #
5             # Gtk2-Ex-TiedListColumn is free software; you can redistribute it and/or
6             # modify it under the terms of the GNU General Public License as published
7             # by the Free Software Foundation; either version 3, or (at your option) any
8             # later version.
9             #
10             # Gtk2-Ex-TiedListColumn is distributed in the hope that it will be useful,
11             # but WITHOUT ANY WARRANTY; without even the implied warranty of
12             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13             # Public License for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Gtk2-Ex-TiedListColumn. If not, see .
17              
18              
19             package Gtk2::Ex::TiedMenuChildren;
20 1     1   1039 use 5.008;
  1         3  
  1         39  
21 1     1   6 use strict;
  1         2  
  1         38  
22 1     1   5 use warnings;
  1         3  
  1         38  
23 1     1   5 use Carp;
  1         1  
  1         61  
24 1     1   545 use Gtk2::Ex::ContainerBits;
  0            
  0            
25             use List::Util qw(min max);
26              
27             # uncomment this to run the ### lines
28             #use Smart::Comments;
29              
30             our $VERSION = 5;
31              
32             sub new {
33             my ($class, $menu) = @_;
34             tie (my @array, $class, $menu);
35             return \@array;
36             }
37              
38             sub TIEARRAY {
39             my ($class, $menu) = @_;
40             return bless \$menu, $class;
41             }
42              
43             # optional, not needed
44             # sub UNTIE { }
45              
46             # tied object func
47             sub menu {
48             return ${$_[0]};
49             }
50              
51             # negative indices already normalized to >=0 by the time they get here
52             sub FETCH {
53             my ($self, $index) = @_;
54             #### TiedChildren FETCH: $index
55             return (($$self)->get_children)[$index];
56             }
57              
58             # negative indices already normalized to >=0 by the time they get here
59             sub STORE {
60             my ($self, $index, $new) = @_;
61             #### TiedChildren STORE: [ $index, $new ]
62             my $menu = $$self;
63              
64             if (my $old = $self->FETCH ($index)) {
65             if ($old == $new) {
66             return; # already what's wanted
67             }
68             $menu->remove ($old);
69             }
70              
71             if (defined $new) {
72             $menu->insert ($new, $index);
73             }
74             }
75              
76             sub FETCHSIZE {
77             my ($self) = @_;
78             ### TiedChildren FETCHSIZE
79             my @children = ($$self)->get_children;
80             return scalar(@children);
81             }
82              
83             # big negative sizes normalized to 0 by the time they get here
84             sub STORESIZE {
85             my ($self, $want_size) = @_;
86             ### TiedChildren STORESIZE: $want_size
87             ### currently: $self->FETCHSIZE
88              
89             my $menu = $$self;
90             my @children = $menu->get_children;
91             if ($want_size < @children) {
92             Gtk2::Ex::ContainerBits::remove_widgets
93             ($menu, splice (@children, $want_size));
94             }
95             }
96              
97             sub EXTEND {
98             }
99              
100             # negative indices already normalized to >=0 by the time they get here
101             sub EXISTS {
102             my ($self, $index) = @_;
103             ### TiedChildren EXISTS: $index
104             return defined((($$self)->get_children)[$index]);
105             }
106              
107             sub DELETE {
108             my ($self, $index) = @_;
109             ### TiedChildren DELETE: $index
110             my $menu = $$self;
111             my $ret;
112             if ($ret = $self->FETCH ($index)) { # if such an element
113             $menu->remove ($ret);
114             }
115             return $ret;
116             }
117              
118             sub CLEAR {
119             my ($self) = @_;
120             ### TiedChildren CLEAR
121             Gtk2::Ex::ContainerBits::remove_all ($$self);
122             }
123              
124             sub PUSH {
125             my $self = shift;
126             my $menu = $$self;
127             while (@_) {
128             $menu->append (shift @_);
129             }
130             }
131              
132             sub POP {
133             my ($self) = @_;
134             ### TiedChildren POP
135             my $menu = $$self;
136             my $ret = ($menu->get_children)[-1];
137             if (defined $ret) { # if not empty menu
138             $menu->remove ($ret);
139             }
140             return $ret;
141             }
142              
143             sub SHIFT {
144             my ($self) = @_;
145             return DELETE($self, 0);
146             }
147              
148             # don't have to return the new size here, FETCHSIZE is called separately
149             sub UNSHIFT {
150             my $self = shift;
151             ### TiedChildren UNSHIFT
152             my $menu = $$self;
153             while (@_) {
154             $menu->prepend (pop @_);
155             }
156             }
157              
158             sub SPLICE {
159             my $self = shift;
160             my $offset = shift;
161             my $length = shift;
162             my $menu = $$self;
163             my @children = $menu->get_children;
164             my $total = scalar @children;
165              
166             # carp similar to "use warnings" on ordinary arrays
167             if (! defined $offset) {
168             $offset = 0;
169             } elsif ($offset < -$total) {
170             carp "TiedChildren: offset $offset before start of array";
171             $offset = 0;
172             } elsif ($offset < 0) {
173             $offset = $total + $offset;
174             } elsif ($offset > $total) {
175             carp "TiedChildren: offset $offset past end of array";
176             $offset = $total;
177             }
178              
179             my @ret = splice (@children, $offset, $length);
180             Gtk2::Ex::ContainerBits::remove_widgets ($menu, @ret);
181              
182             while (@_) {
183             $menu->insert (pop @_, $offset);
184             }
185             ### ret: map {$_->get_name} @ret
186             return (wantarray ? @ret : $ret[-1]);
187             }
188              
189             1;
190             __END__