File Coverage

blib/lib/Gtk2/Ex/AdjustmentBits.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, 2011, 2012 Kevin Ryde
2              
3             # This file is part of Gtk2-Ex-WidgetBits.
4             #
5             # Gtk2-Ex-WidgetBits 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-WidgetBits 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-WidgetBits. If not, see .
17              
18             package Gtk2::Ex::AdjustmentBits;
19 1     1   876 use 5.008;
  1         4  
  1         47  
20 1     1   6 use strict;
  1         2  
  1         40  
21 1     1   5 use warnings;
  1         2  
  1         33  
22 1     1   5 use Carp;
  1         2  
  1         76  
23 1     1   749 use Gtk2 1.220;
  0            
  0            
24             use List::Util 'min', 'max';
25              
26             our $VERSION = 48;
27              
28             # uncomment this to run the ### lines
29             #use Smart::Comments;
30              
31              
32             # Names a bit too generic to want to import usually.
33             # use Exporter;
34             # our @ISA = ('Exporter');
35             # our @EXPORT_OK = qw(scroll_value
36             # scroll_increment
37             # set_maybe set_empty);
38              
39             #------------------------------------------------------------------------------
40              
41             sub scroll_value {
42             my ($adj, $amount) = @_;
43             my $oldval = $adj->value;
44             $adj->value (max ($adj->lower,
45             min ($adj->upper - $adj->page_size,
46             $oldval + $amount)));
47             # re-fetch $adj->value() for comparison to allow round-off on storing if
48             # perl NV is a long double
49             if ($adj->value != $oldval) {
50             $adj->notify ('value');
51             $adj->signal_emit ('value-changed');
52             }
53             }
54              
55             # Validate $type as "page" or "step" so as not to let dubious input call an
56             # arbitrary method.
57             my %increment_method = (page => 'page_increment',
58             step => 'step_increment',
59             # page_increment => 'page_increment',
60             # step_increment => 'step_increment',
61             );
62             sub scroll_increment {
63             my ($adj, $inctype, $inverted) = @_;
64             my $method = $increment_method{$inctype}
65             || croak "Unrecognised increment type: ",$inctype;
66             scroll_value ($adj, $adj->$method * ($inverted ? -1 : 1));
67             }
68              
69             my %direction_is_inverted = (up => 1, # Gtk2::Gdk::ScrollDirection enum
70             down => 0,
71             left => 1,
72             right => 0);
73             sub scroll_event {
74             my ($adj, $event, $inverted) = @_;
75             $inverted ^= $direction_is_inverted{$event->direction};
76             Gtk2::Ex::AdjustmentBits::scroll_increment
77             ($adj,
78             ($event->state & 'control-mask' ? 'page' : 'step'),
79             $inverted);
80             return 0; # Gtk2::EVENT_PROPAGATE
81             }
82              
83             #------------------------------------------------------------------------------
84             # set_maybe()
85             #
86             # Gtk 2.0
87             # $adj->changed() emits "changed" only
88             # $adj->value_changed() emits "value-changed" only
89             # Gtk 2.6
90             # $adj->changed() emits "changed" only
91             # $adj->value_changed() emits "value-changed" and "notify::value"
92              
93             use constant _NOTIFY_EMITS_CHANGED =>
94             do {
95             my $adj = Gtk2::Adjustment->new (0,0,0,0,0,0);
96             my $result = 0;
97             $adj->signal_connect (changed => sub { $result = 1 });
98             $adj->notify ('upper');
99             $result
100             };
101             ### _NOTIFY_EMITS_CHANGED is: _NOTIFY_EMITS_CHANGED()
102              
103             if (_NOTIFY_EMITS_CHANGED) {
104             require Glib::Ex::FreezeNotify;
105             }
106              
107             sub set_maybe {
108             my ($adj, %values) = @_;
109             ### AdjustmentBits set_maybe(): "from ",caller()
110              
111             my $value = delete $values{'value'};
112             if (! defined $value) { $value = $adj->value; }
113              
114             # compare after storing to see the value converted to double perhaps
115             # from a 64-bit perl integer etc
116             foreach my $key (keys %values) {
117             my $old = $adj->$key;
118             $adj->$key ($values{$key});
119             if ($adj->$key == $old) {
120             delete $values{$key};
121             }
122             }
123             ### set_maybe change: %values
124              
125             $value = max ($adj->lower,
126             min ($adj->upper - $adj->page_size,
127             $value));
128             {
129             my $old = $adj->value;
130             $adj->value ($value);
131             if ($adj->value != $old) {
132             $values{'value'} = 1;
133             }
134             }
135              
136             if (%values) {
137             # In gtk 2.18 emitting "notify" wastefully emits "changed" too.
138             # Freezing collapses to just one of those "changed".
139             my $freezer = _NOTIFY_EMITS_CHANGED && Glib::Ex::FreezeNotify->new($adj);
140              
141             foreach my $key (keys %values) {
142             $adj->notify ($key);
143             }
144             $value = delete $values{'value'};
145              
146             if (! _NOTIFY_EMITS_CHANGED) {
147             if (%values) {
148             $adj->changed;
149             }
150             }
151             if (defined $value) {
152             # use signal_emit() since gtk_adjustment_value_changed() func varies
153             # among gtk versions as to whether it emits "notify::value" too
154             $adj->signal_emit('value-changed');
155             }
156             }
157             }
158              
159             # configure() emits notify and changed even if upper/lower etc unchanged, so
160             # no good.
161             #
162             # if (Gtk2::Adjustment->can('configure')) {
163             # # new in gtk 2.14 and Perl-Gtk 1.240
164             # eval "\n#line ".(__LINE__+1)." \"".__FILE__."\"\n" . <<'HERE' or die;
165             #
166             # sub set_maybe {
167             # my ($adj, %values) = @_;
168             # ### AdjustmentBits set_maybe(), with configure()
169             #
170             # $adj->configure (map {
171             # my $value = delete $values{$_};
172             # (defined $value ? $value : $adj->$_)
173             # } qw(value
174             # lower upper
175             # step_increment page_increment page_size));
176             # if (%values) {
177             # croak "Unrecognised adjustment field(s) ",join(',',keys %values);
178             # }
179             # }
180             # 1;
181             # HERE
182              
183             #------------------------------------------------------------------------------
184              
185             sub set_empty {
186             my ($adj) = @_;
187             Gtk2::Ex::AdjustmentBits::set_maybe ($adj,
188             upper => 0,
189             lower => 0,
190             page_size => 0,
191             page_increment => 0,
192             step_increment => 0,
193             value => 0);
194             }
195              
196             1;
197             __END__