1# contains:
2#   CheckList
3
4package Prima::ExtLists;
5use strict;
6use warnings;
7use Prima::Const;
8use Prima::Classes;
9use Prima::Lists;
10use Prima::StdBitmap;
11
12package Prima::CheckList;
13use vars qw(@ISA);
14@ISA = qw(Prima::ListBox);
15
16my (@images, @imgSize);
17
18Prima::Application::add_startup_notification( sub {
19	@images = (
20		Prima::StdBitmap::image(sbmp::CheckBoxUnchecked),
21		Prima::StdBitmap::image(sbmp::CheckBoxChecked),
22	);
23	@imgSize = (0,0);
24	@imgSize = $images[0]-> size if $images[0];
25});
26
27sub profile_default
28{
29	my $def = $_[ 0]-> SUPER::profile_default;
30	my %prf = (
31		vector => '',
32	);
33	@$def{keys %prf} = values %prf;
34	return $def;
35}
36
37
38sub init
39{
40	my $self = shift;
41	$self-> {vector} = 0;
42	my %profile = $self-> SUPER::init(@_);
43	$self-> {fontHeight} = $self-> font-> height;
44	$self-> recalc_icons;
45	$self-> vector( $profile{vector});
46	return %profile;
47}
48
49sub on_measureitem
50{
51	my ( $self, $index, $sref) = @_;
52	$$sref = $self-> get_text_width( $self-> {items}-> [$index]) + $imgSize[0] + 4;
53}
54
55sub recalc_icons
56{
57	return unless $imgSize[0];
58	my $self = $_[0];
59	my $hei = $self-> font-> height + 2;
60	$hei = $imgSize[1] + 2 if $hei < $imgSize[1] + 2;
61	$self-> itemHeight( $hei);
62}
63
64sub on_fontchanged
65{
66	my $self = shift;
67	$self-> recalc_icons;
68	$self-> {fontHeight} = $self-> font-> height;
69	$self-> SUPER::on_fontchanged(@_);
70}
71
72
73sub draw_items
74{
75	shift-> std_draw_text_items( @_);
76}
77
78sub draw_text_items
79{
80	my ( $self, $canvas, $first, $last, $step, $x, $y, $textShift, $clipRect) = @_;
81	my ( $i, $j);
82	for ( $i = $first, $j = 1; $i <= $last; $i += $step, $j++) {
83		next if $self-> {widths}-> [$i] + $self-> {offset} + $x + 1 < $clipRect-> [0];
84		$canvas-> text_shape_out( $self-> {items}-> [$i], $x + 2 + $imgSize[0],
85			$y + $textShift - $j * $self-> {itemHeight} + 1);
86		$canvas-> put_image( $x + 1,
87			$y + int(( $self-> {itemHeight} - $imgSize[1]) / 2) -
88				$j * $self-> {itemHeight} + 1,
89			$images[ vec($self-> {vector}, $i, 1)],
90		);
91	}
92}
93
94sub on_mouseclick
95{
96	my ( $self, $btn, $mod, $x, $y, $dbl) = @_;
97	$self-> SUPER::on_mouseclick( $btn, $mod, $x, $y);
98	return if $btn != mb::Left;
99	my $foc = $self-> focusedItem;
100	return if $foc < 0;
101	my $f = vec( $self-> {vector}, $foc, 1) ? 0 : 1;
102	vec( $self-> {vector}, $foc, 1) = $f;
103	$self-> notify(q(Change), $foc, $f);
104	$self-> invalidate_rect( $self-> item2rect( $foc));
105}
106
107sub on_click
108{
109	my $self = $_[0];
110	my $foc = $self-> focusedItem;
111	return if $foc < 0;
112	my $f = vec( $self-> {vector}, $foc, 1) ? 0 : 1;
113	vec( $self-> {vector}, $foc, 1) = $f;
114	$self-> notify(q(Change), $foc, $f);
115	$self-> invalidate_rect( $self-> item2rect( $foc));
116}
117
118
119sub vector
120{
121	my $self = $_[0];
122	return $self-> {vector} unless $#_;
123	$self-> {vector} = $_[1];
124	$self-> repaint;
125}
126
127sub clear_all_buttons
128{
129	my $self = $_[0];
130	my $c = int($self-> {count} / 32) + (($self-> {count} % 32) ? 1 : 0);
131	vec( $self-> {vector}, $c, 32) = 0 while $c--;
132	$self-> notify(q(Change), -1, 1);
133	$self-> repaint;
134};
135
136sub set_all_buttons
137{
138	my $self = $_[0];
139	my $c = int($self-> {count} / 32) + (($self-> {count} % 32) ? 1 : 0);
140	vec( $self-> {vector}, $c, 32) = 0xffffffff while $c--;
141	$self-> notify(q(Change), -1, 0);
142	$self-> repaint;
143};
144
145sub button
146{
147	my ( $self, $index, $state) = @_;
148	return 0 if $index < 0 || $index >= $self-> {count};
149	my $current = vec( $self-> {vector}, $index, 1);
150	return $current unless defined $state;
151	$state = ( $state < 0) ? !$current : ( $state ? 1 : 0);
152	return $current if $current == $state;
153	vec( $self-> {vector}, $index, 1) = $state;
154	$self-> notify(q(Change), $index, $state);
155	$self-> redraw_items( $index);
156	return $state;
157}
158
159#sub on_change
160#{
161#	my ( $self, $index, $state) = @_;
162#}
163
1641;
165
166=pod
167
168=head1 NAME
169
170Prima::ExtLists - extended functionality for list boxes
171
172=head1 SYNOPSIS
173
174	use Prima qw(ExtLists Application);
175
176	my $vec = '';
177	vec( $vec, 0, 8) = 0x55;
178	Prima::CheckList-> new(
179		items  => [1..10],
180		vector => $vec,
181	);
182	run Prima;
183
184=for podview <img src="extlist.gif">
185
186=for html <p><img src="https://raw.githubusercontent.com/dk/Prima/master/pod/Prima/extlist.gif">
187
188=head1 DESCRIPTION
189
190The module is intended to be a collection of list boxes with
191particular enhancements. Currently the only package is contained
192is C<Prima::CheckList> class.
193
194=head1 Prima::CheckList
195
196Provides a list box, where each item is equipped with a check box.
197The check box state can interactively be toggled by the enter key;
198also the list box reacts differently by click and double click.
199
200=head2 Properties
201
202=over
203
204=item button INDEX, STATE
205
206Runtime only. Sets INDEXth button STATE to 0 or 1.
207If STATE is -1, the button state is toggled.
208
209Returns the new state of the button.
210
211=item vector VEC
212
213VEC is a vector scalar, where each bit corresponds to the check state
214of each list box item.
215
216See also: L<perlfunc/vec>.
217
218=back
219
220=head2 Methods
221
222=over
223
224=item clear_all_buttons
225
226Sets all buttons to state 0
227
228=item set_all_buttons
229
230Sets all buttons to state 1
231
232=back
233
234=head1 AUTHOR
235
236Dmitry Karasik, E<lt>dmitry@karasik.eu.orgE<gt>.
237
238=head1 SEE ALSO
239
240L<Prima>, L<Prima::Lists>, F<examples/extlist.pl>
241
242=cut
243
244