sub
CORE_METHODS {
qw(profile_default profile_check_in init skin)
}
sub
profile_default
{
my
(
$orig
,
$self
) =
@_
;
my
$def
=
$orig
->(
$self
);
my
$new
= {
autoHScroll
=> 1,
autoVScroll
=> 1,
borderWidth
=>
undef
,
hScroll
=> 0,
hScrollBarProfile
=> {},
scrollBarClass
=>
'Prima::ScrollBar'
,
vScroll
=> 0,
vScrollBarProfile
=> {},
%$def
,
};
return
$new
;
}
sub
profile_check_in
{
my
(
$orig
,
$self
,
$p
,
$default
) =
@_
;
$orig
->(
$self
,
$p
,
$default
);
$p
-> {autoHScroll} = 0
if
exists
$p
-> {hScroll};
$p
-> {autoVScroll} = 0
if
exists
$p
-> {vScroll};
if
( !
defined
$p
->{borderWidth} && !
defined
$default
->{borderWidth}) {
my
$skin
=
$p
->{skin} //
$default
->{skin} // (
$p
->{owner} ?
$p
->{owner}->skin :
''
);
$p
->{borderWidth} = (
$skin
eq
'flat'
) ? 1 : 2;
}
}
sub
init
{
my
(
$orig
,
$self
) = (
shift
,
shift
);
$self
->{
$_
} = 0
for
qw(autoVScroll autoHScroll hScroll vScroll borderWidth GS_extra_border)
;
my
%profile
=
$orig
->(
$self
,
@_
);
$self
->{
$_
} =
$profile
{
$_
}
for
qw(scrollBarClass hScrollBarProfile vScrollBarProfile)
;
$self
->
$_
(
$profile
{
$_
})
for
qw(borderWidth autoHScroll autoVScroll hScroll vScroll)
;
return
%profile
;
}
sub
skin
{
my
$orig
=
shift
;
return
$orig
->(
@_
)
unless
$#_
;
my
$self
=
shift
;
$orig
->(
$self
,
$_
[0]);
$self
->{GS_extra_border} = (
$orig
->(
$self
) eq
'flat'
) ? 1 : 0;
$self
->repaint;
}
sub
setup_indents
{
my
(
$self
) =
@_
;
$self
-> {indents} = [ 0,0,0,0];
my
$bw
=
$self
-> {borderWidth};
my
$ebw
=
$self
->{GS_extra_border} - 1;
$self
-> {indents}-> [
$_
] +=
$bw
for
0..3;
$self
-> {indents}-> [1] +=
$self
-> {hScrollBar}-> height +
$ebw
if
$self
-> {hScroll};
$self
-> {indents}-> [2] +=
$self
-> {vScrollBar}-> width +
$ebw
if
$self
-> {vScroll};
}
sub
set_border_width
{
my
(
$self
,
$bw
) =
@_
;
my
@size
=
$self
-> size;
$bw
= 0
if
$bw
< 0;
$bw
= 1
if
$bw
>
$size
[1] / 2;
$bw
= 1
if
$bw
>
$size
[0] / 2;
return
if
$bw
==
$self
-> {borderWidth};
my
$obw
=
$self
-> {borderWidth};
$self
-> {borderWidth} =
$bw
;
my
$ebw
=
$self
->{GS_extra_border} - 1;
$self
-> {hScrollBar}-> set(
left
=>
$bw
+
$ebw
,
bottom
=>
$bw
+
$ebw
,
width
=>
$size
[0] -
2 *
$bw
-
(
$self
-> {vScroll} ?
$self
-> {vScrollBar}-> width +
$ebw
* 3:
-
$ebw
* 2),
)
if
$self
-> {hScroll};
$self
-> {vScrollBar}-> set(
right
=>
$size
[0] -
$bw
-
$ebw
,
top
=>
$size
[1] -
$bw
-
$ebw
,
bottom
=>
$bw
-
$ebw
+ (
$self
-> {hScroll} ?
$self
-> {hScrollBar}-> height + 3 *
$ebw
: 0),
)
if
$self
-> {vScroll};
$self
-> insert_bone
if
defined
$self
-> {bone};
$self
-> setup_indents;
$self
-> reset_indents;
}
sub
reset_indents {}
sub
insert_bone
{
my
$self
=
$_
[0];
my
$bw
=
$self
-> {borderWidth};
$self
-> {bone}-> destroy
if
defined
$self
-> {bone};
my
$ebw
=
$self
->{GS_extra_border} - 1;
$self
-> {bone} = Prima::Widget-> new(
owner
=>
$self
,
name
=>
q(Bone)
,
pointerType
=> cr::Arrow,
origin
=> [
$self
-> width -
$self
-> {vScrollBar}-> width -
$ebw
* 2 -
$bw
,
$bw
+
$ebw
],
size
=> [
$self
-> {vScrollBar}-> width +
$ebw
,
$self
-> {hScrollBar}-> height +
$ebw
],
growMode
=> gm::GrowLoX,
widgetClass
=> wc::ScrollBar,
designScale
=>
undef
,
onPaint
=>
sub
{
my
(
$self
,
$canvas
,
$owner
,
$w
,
$h
) =
(
$_
[0],
$_
[1],
$_
[0]-> owner,
$_
[0]-> size);
return
$canvas
->clear
if
$owner
->skin eq
'flat'
;
$canvas
-> color(
$self
-> backColor);
$canvas
-> bar( 0, 1,
$w
- 2,
$h
- 1);
$canvas
-> color(
$owner
-> light3DColor);
$canvas
-> line( 0, 0,
$w
- 1, 0);
$canvas
-> line(
$w
- 1, 0,
$w
- 1,
$h
- 1);
},
);
}
sub
set_h_scroll
{
my
(
$self
,
$hs
) =
@_
;
return
if
(
$hs
? 1 : 0) ==
$self
-> {hScroll};
my
$bw
=
$self
-> {borderWidth} || 0;
my
$ebw
=
$self
->{GS_extra_border} - 1;
if
(
$hs
) {
$self
-> {hScrollBar} =
$self
->{scrollBarClass}-> new(
owner
=>
$self
,
name
=>
q(HScroll)
,
vertical
=> 0,
origin
=> [
$bw
+
$ebw
,
$bw
+
$ebw
],
growMode
=> gm::GrowHiX,
pointerType
=> cr::Arrow,
width
=>
$self
-> width -
2 *
$bw
-
(
$self
-> {vScroll} ?
$self
-> {vScrollBar}-> width +
$ebw
* 3:
-
$ebw
* 2),
delegations
=> [
'Change'
],
designScale
=>
undef
,
%{
$self
->{hScrollBarProfile} || {} },
);
$self
-> {hScroll} = 1;
$self
-> setup_indents;
if
(
$self
-> {vScroll}) {
my
$h
=
$self
-> {hScrollBar}-> height;
$self
-> {vScrollBar}-> set(
bottom
=>
$self
-> {vScrollBar}-> bottom +
$h
+
$ebw
,
top
=>
$self
-> {vScrollBar}-> top,
);
$self
-> insert_bone;
}
}
else
{
$self
-> {hScroll} = 0;
$self
-> setup_indents;
$self
-> {hScrollBar}-> destroy;
if
(
$self
-> {vScroll})
{
$self
-> {vScrollBar}-> set(
bottom
=>
$bw
+
$ebw
,
height
=>
$self
-> height -
$bw
* 2 -
$ebw
* 2,
);
$self
-> {bone}-> destroy;
delete
$self
-> {bone};
}
}
$self
-> reset_indents;
}
sub
set_v_scroll
{
my
(
$self
,
$vs
) =
@_
;
return
if
(
$vs
? 1 : 0) ==
$self
-> {vScroll};
my
$bw
=
$self
-> {borderWidth} || 0;
my
@size
=
$self
-> size;
my
$ebw
=
$self
->{GS_extra_border} - 1;
if
(
$vs
) {
my
$width
=
exists
(
$self
->{vScrollBarProfile}->{width} ) ?
$self
->{vScrollBarProfile}->{width} :
$Prima::ScrollBar::stdMetrics
[0];
$self
-> {vScrollBar} =
$self
->{scrollBarClass}-> new(
owner
=>
$self
,
name
=>
q(VScroll)
,
vertical
=> 1,
left
=>
$size
[0] -
$bw
-
$width
-
$ebw
,
top
=>
$size
[1] -
$bw
-
$ebw
,
bottom
=>
$bw
-
$ebw
+ (
$self
-> {hScroll} ?
$self
-> {hScrollBar}-> height + 3 *
$ebw
: 0),
growMode
=> gm::GrowLoX | gm::GrowHiY,
pointerType
=> cr::Arrow,
delegations
=> [
'Change'
],
designScale
=>
undef
,
%{
$self
->{vScrollBarProfile} || {} },
);
$self
-> {vScroll} = 1;
$self
-> setup_indents;
if
(
$self
-> {hScroll}) {
$self
-> {hScrollBar}-> width(
$size
[0] - 2 *
$bw
-
$ebw
* 2 -
$self
->{vScrollBar}->width -
$ebw
,
);
$self
-> insert_bone;
}
}
else
{
$self
-> {vScroll} = 0;
$self
-> setup_indents;
$self
-> {vScrollBar}-> destroy;
if
(
$self
-> {hScroll})
{
$self
-> {hScrollBar}-> width(
$size
[0] - 2 *
$bw
-
$ebw
* 2);
$self
-> {bone}-> destroy;
delete
$self
-> {bone};
}
}
$self
-> reset_indents;
}
sub
autoHScroll
{
return
$_
[0]-> {autoHScroll}
unless
$#_
;
my
$v
= (
$_
[1] ? 1 : 0);
return
unless
$v
!=
$_
[0]-> {autoHScroll};
$_
[0]-> {autoHScroll} =
$v
;
}
sub
autoVScroll
{
return
$_
[0]-> {autoVScroll}
unless
$#_
;
my
$v
= (
$_
[1] ? 1 : 0);
return
unless
$v
!=
$_
[0]-> {autoVScroll};
$_
[0]-> {autoVScroll} =
$v
;
}
sub
borderWidth {(
$#_
)?(
$_
[0]-> set_border_width(
$_
[1])):
return
$_
[0]-> {borderWidth}}
sub
hScroll {(
$#_
)?
$_
[0]-> set_h_scroll (
$_
[1]):
return
$_
[0]-> {hScroll}}
sub
vScroll {(
$#_
)?
$_
[0]-> set_v_scroll (
$_
[1]):
return
$_
[0]-> {vScroll}}
sub
draw_border
{
my
(
$self
,
$canvas
,
$backColor
,
@size
) =
@_
;
@size
=
$self
-> size
unless
@size
;
@size
= Prima::rect->new(
@size
)->inclusive;
if
(
$self
-> skin eq
'flat'
) {
if
(
defined
$backColor
) {
$canvas
-> rect_fill(
@size
,
$self
->{borderWidth},
$self
-> dark3DColor,
$backColor
);
}
else
{
$canvas
-> rect_solid(
@size
,
$self
->{borderWidth},
$self
-> dark3DColor,
);
}
}
else
{
$self
-> rect_bevel(
$canvas
,
@size
,
width
=>
$self
-> {borderWidth},
panel
=> 1,
fill
=>
$backColor
,
);
}
}
1;
=pod
=head1 NAME
Prima::Widget::GroupScroller - optional automatic scroll bars
=head1 DESCRIPTION
The class is used
for
widgets that contain optional scroll bars and provides means
for
their management. The class is the descendant of L<Prima::IntIndents> and adjusts
its L<indents> property
when
scrollbars are shown, hidden, or L<borderWidth> is changed.
The class does not provide range selection
for
the scrollbars; the descendant classes
must implement that.
The descendant classes must follow the following guidelines:
=over
=item *
A class may provide C<borderWidth>, C<hScroll>, C<vScroll>, C<autoHScroll>, and
C<autoVScroll> property
keys
in profile_default() .
=item *
A class' init() method must call the C<setup_indents> method
If a class overrides the C<autoHScroll> and C<autoVScroll> properties, these must be set to
0
before
the initialization.
=item *
If a class needs to overload one of the C<borderWidth>, C<hScroll>, C<vScroll>,
C<autoHScroll>, and C<autoVScroll> properties,
it is mandatory to call the inherited properties.
=item *
A class must implement the scroll bar notification callbacks: C<HScroll_Change> and C<VScroll_Change>.
=item *
A class must not
use
the reserved variable names, which are:
{borderWidth} - internal borderWidth storage
{hScroll} - internal hScroll value storage
{vScroll} - internal vScroll value storage
{hScrollBar} - pointer to the horizontal scroll bar
{vScrollBar} - pointer to the vertical scroll bar
{bone} - rectangular widget between the scrollbars
{autoHScroll} - internal autoHScroll value storage
{autoVScroll} - internal autoVScroll value storage
The reserved method names:
set_h_scroll
set_v_scroll
insert_bone
setup_indents
reset_indents
borderWidth
autoHScroll
autoVScroll
hScroll
vScroll
The reserved widget names:
HScroll
VScroll
Bone
=back
=head1 Properties
=over
=item autoHScroll BOOLEAN
Selects
if
the horizontal scrollbar is to be shown and hidden dynamically,
depending on the widget layout.
=item autoVScroll BOOLEAN
Selects
if
the vertical scrollbar is to be shown and hidden dynamically,
depending on the widget layout.
=item borderWidth INTEGER
Width of the border
around
the widget.
Depends on the C<skin> property.
=item hScroll BOOLEAN
Selects
if
the horizontal scrollbar is visible. If it is, C<{hScrollBar}>
points to it.
=item vScroll BOOLEAN
Selects
if
the vertical scrollbar is visible. If it is, C<{vScrollBar}>
points to it.
=item scrollBarClass STRING = Prima::ScrollBar
A create-only property that allows to change the scrollbar class
=item hScrollBarProfile, vScrollBarProfile HASH
Create-only properties that allows to adjust the scrollbar parameters
when
the scrollbars are created
=back
=head1 Methods
=over
=item setup_indents
The method is never called directly; it should be called whenever the widget
layout is changed so that its indents are affected. The method is a request
to recalculate indents, depending on the new widget layout.
The method is not reentrant; to receive this callback and update the widget
layout that in turn can result in more C<setup_indents> calls, overload
C<reset_indents> .
=item reset_indents
Called
after
C<setup_indents> updates the internal widget layout, to give a
chance to follow up the layout changes. Does not
do
anything by
default
.
=back
=head1 AUTHOR
Dmitry Karasik, E<lt>dmitry
@karasik
.eu.orgE<gt>.
=head1 SEE ALSO
L<Prima>, L<Prima::Lists>, L<Prima::Edit>