Prima::Docks - dockable widgets |
Prima::Docks - dockable widgets
The module contains a set of classes and an implementation of dockable widgets
interface. The interface assumes two parties, the dockable widget
and the dock widget; the generic methods for the dock widget class are contained in
Prima::AbstractDocker::Interface
package.
A dockable widget is required to take particular steps before it can dock to a dock widget. It needs to talk to the dock and find out if it is allowed to land, or if the dock contains lower-level dock widgets that might suit better for docking. If there's more than one dock widget in the program, the dockable widget can select between the targets; this is especially actual when a dockable widget is dragged by mouse and the arbitration is performed on geometrical distance basis.
The interface implies that there exists at least one tree-like hierarchy of dock widgets,
linked up to a root dock widget. The hierarchy is not required to follow
parent-child relationships, although this is the default behavior.
All dockable widgets are expected to know explicitly what hierarchy tree they
wish to dock to. Prima::InternalDockerShuttle
introduces dockingRoot
property
for this purpose.
The conversation between parties starts when a dockable widget
calls open_session
method of the dock. The dockable widget passes
set of parameters signaling if the widget is ready to change its size
in case the dock widget requires so, and how. open_session
method can either refuse
or accept the widget.
In case of the positive answer from open_session
, the dockable widget
calls query
method, which either returns a new rectangle, or another dock widget.
In the latter case, the caller can enumerate all available dock widgets by
repetitive calls to next_docker
method. The session is closed by close_session
call; after that, the widget is allowed to dock by setting its owner
to the dock widget, the rect
property to the negotiated position and size, and
calling dock
method.
open_session
/close_session
brackets are used to cache all necessary
calculations once, making query
call as light as possible. This design allows
a dockable widget, when dragged, repeatedly ask all reachable docks in an
optimized way. The docking sessions are kept open until the drag
session is finished.
The conversation can be schematized in the following code:
my $dock = $self-> dockingRoot; my $session_id = $dock-> open_session({ self => $self }); return unless $session_id; my @result = $dock-> query( $session_id, $self-> rect ); if ( 4 == scalar @result) { # new rectangle is returned if ( ..... is new rectangle acceptable ? ... ) { $dock-> close_session( $session_id); $dock-> dock( $self); return; } } elsif ( 1 == scalar @result) { # another dock returned my $next = $result[0]; while ( $next) { if ( ... is new docker acceptable? ....) { $dock-> close_session( $session_id); $next-> dock( $self); return; } $next = $dock-> next_docker( $session_id, $self-> origin ); } } $dock-> close_session( $session_id);
Since even the simplified code is quite cumbersome, direct calls to
open_session
are rare. Instead, Prima::InternalDockerShuttle
implements find_docking
method which performs the arbitration automatically
and returns the appropriate dock widget.
Prima::InternalDockerShuttle
is a class that implements dockable
widget functionality. It also employs a top-level window-like wrapper widget
for the dockable widget when it is not docked.
By default, Prima::ExternalDockerShuttle
is used as the wrapper widget class.
It is not required, however, to use neither Prima::InternalDockerShuttle
nor Prima::AbstractDocker::Interface
to implement a dockable widget;
the only requirements to one is to respect open_session
/close_session
protocol.
Prima::InternalDockerShuttle
initiates a class hierarchy of dockable widgets.
Its descendants are Prima::LinearWidgetDocker
and, in turn, Prima::SingleLinearWidgetDocker
.
Prima::SimpleWidgetDocker
and Prima::LinearWidgetDocker
, derived from
Prima::AbstractDocker::Interface
, begin hierarchy of dock widgets.
The full hierarchy is as follows:
Prima::AbstractDocker::Interface Prima::SimpleWidgetDocker Prima::ClientWidgetDocker Prima::LinearWidgetDocker Prima::FourPartDocker
Prima::InternalDockerShuttle Prima::LinearDockerShuttle Prima::SingleLinearWidgetDocker
Prima::ExternalDockerShuttle
All docker widget classes are derived from Prima::AbstractDocker::Interface
.
Depending on the specialization, they employ more or less sophisticated schemes
for arranging dockable widgets inside. The most complicated scheme is implemented
in Prima::LinearWidgetDocker
; it does not allow children overlapping and is
able to rearrange with children and resize itself when a widget is docked or undocked.
The package provides only basic functionality. Module Prima::DockManager
provides common dockable controls, - toolbars, panels, speed buttons etc.
based on Prima::Docks
module. See the Prima::DockManager manpage.
Implements generic functionality of a docket widget. The class is
not derived from Prima::Widget
; is used as a secondary ascendant class
for dock widget classes.
Since the class is not Prima::Object
descendant, it provides
only run-time implementation of its properties. It is up to the
descendant object whether the properties are recognized on the creation stage
or not.
fingerprint
property is not part
of the protocol, and is not required to be present in a dockable widget implementation.
Default value: 0x0000FFFF
$self-> dockup( $upper_dock_not_parent );
$upper_dock_not_parent-> add_notification( 'Destroy', sub { return unless $_[0] == $self-> dockup; undef $self-> {dockup_event_id}; $self-> dockup( undef ); }, $self);
$self-> {destroy_id} = $self-> add_notification( 'Destroy', sub { $self-> dockup( undef ); } unless $self-> {destroy_id};
next_docker
method.
owner
property. The method
adapts the dock widget layout and lists WIDGET into list of
docked widgets. The method does not change owner
property of WIDGET.
The method must not be called directly.
rearrange
.
undef
.
The enumeration pointer is reset by query
call.
X and Y are coordinates of the point of interest.
undef
otherwise.
The following keys must be set in PROFILE:
sizes
key does not contain the desired
size.
sizeable
flags are set to 0,
and none of sizes
can be accepted by the dock widget, open_session
fails.
sizes
or sizeable
keys of open_session
profile were set, the returned size
might be different from the current docking widget size.
Once the caller finds the result appropriate, it is allowed to change
its owner to the dock; after that, it must change its origin and size correspondingly
to the result, and then call dock
.
If the dock cannot accept the widget, but contains lower-lever
dock widgets, returns the first lower-lever widget. The caller
can use subsequent calls to next_docker
to enumerate all
lower-level dock widgets. A call to query
resets the internal enumeration pointer.
If the widget cannot be landed, an empty array is returned.
$self-> redock_widget($_) for $self-> docklings;
but usually rearrange
is faster.
redock
method in its namespace, it is called instead.
owner
property of WIDGET.
The method must not be called directly.
A simple dock widget; accepts any widget that geometrically fits into. Allows overlapping of the docked widgets.
A simple dock widget; accepts any widget that can be fit to cover all dock's interior.
A toolbar-like docking widget class. The implementation does not allow tiling, and can reshape the dock widget and rearrange the docked widgets if necessary.
Prima::LinearWidgetDocker
is orientation-dependent; its main axis,
governed by vertical
property, is used to align docked widgets in
'lines', which in turn are aligned by the opposite axis ( 'major' and 'minor' terms
are used in the code for the axes ).
grow::XXX
constants, that describes how
the dock widget can be resized. The constants are divided in two
sets, direct and indirect, or, vertical
property independent and
dependent.
The first set contains explicitly named constants:
grow::Left grow::ForwardLeft grow::BackLeft grow::Down grow::ForwardDown grow::BackDown grow::Right grow::ForwardRight grow::BackRight grow::Up grow::ForwardUp grow::BackUp
that select if the widget can be grown to the direction shown.
These do not change meaning when vertical
changes, though they do
change the dock widget behavior. The second set does not affect
dock widget behavior when vertical
changes, however the names
are not that illustrative:
grow::MajorLess grow::ForwardMajorLess grow::BackMajorLess grow::MajorMore grow::ForwardMajorMore grow::BackMajorMore grow::MinorLess grow::ForwardMinorLess grow::BackMinorLess grow::MinorMore grow::ForwardMinorMore grow::BackMinorMore
Forward
and Back
prefixes select if the dock widget can be
respectively expanded or shrunk in the given direction. Less
and
More
are equivalent to Left
and Right
when vertical
is 0,
and to Up
and Down
otherwise.
The use of constants from the second set is preferred.
Default value: 0
vertical
is 0, up otherwise ), as if there's
a 'pocket'. If 0, a widget is neither allowed to dock outside the
inferior, nor is allowed to stay docked ( and is undocked automatically )
when the dock widget shrinks so that the docked widget cannot stay in
the dock boundaries.
Default value: 1
Default value: 0
dock
is successfully finished.
dock
is unsuccessfully finished. This only
happens if WIDGET does not follow the docking protocol, and inserts
itself into a non-approved area.
undock
is finished.
Descendant of Prima::LinearWidgetDocker
. In addition
to the constraints, introduced by the ascendant class,
Prima::SingleLinearWidgetDocker
allows only one line ( or row,
depending on vertical
property value ) of docked widgets.
Implementation of a docking widget, with its four sides acting as 'rubber' docking areas.
Default value: Prima::LinearWidgetDocker
.
Create-only property.
Default value: Prima::LinearWidgetDocker
.
Create-only property.
Default value: Prima::LinearWidgetDocker
.
Create-only property.
Default value: Prima::LinearWidgetDocker
.
Create-only property.
Default value: Prima::ClientWidgetDocker
.
Create-only property.
Create-only property.
Create-only property.
Create-only property.
Create-only property.
Create-only property.
Create-only property.
Create-only property.
Create-only property.
Create-only property.
Create-only property.
Create-only property.
The class provides a container, or a 'shuttle', for a client widget, while is docked to
an Prima::AbstractDocker::Interface
descendant instance. The functionality includes
communicating with dock widgets, the user interface for dragging and interactive dock selection,
and a client widget container for non-docked state. The latter is implemented by
reparenting of the client widget to an external shuttle widget, selected by externalDockerClass
property. Both user interfaces for the docked and the non-docked shuttle states are minimal.
The class implements dockable widget functionality, served by Prima::AbstractDocker::Interface
,
while itself it is derived from Prima::Widget
only.
See also: Prima::ExternalDockerShuttle.
owner
and clipOwner
properties must not be used.
Run-time only property.
undef
,
the shuttle is in the non-docked state.
Default value: undef
undef
, the shuttle can only exist in the non-docked state.
Default value: undef
See USAGE for reference.
Default value: Prima::ExternalDockerShuttle
Default value: Prima::MDI
( Prima::ExternalDockerShuttle
is derived from Prima::MDI
).
Default value: 0x0000FFFF
Default value: 5,5,5,5
.
Default value: 10
Default value: 0
Default value: 0
If it is 1, RECT is an array with the coordinates of the shuttle rectangle
before the drag has started; ANCHOR_X and ANCHOR_Y are coordinates of the
aperture point where the mouse event occurred that has initiated the drag.
Depending on how the drag session ended, the shuttle can be relocated to
another dock, undocked, or left intact. Also, Dock
, Undock
, or
FailDock
notifications can be triggered.
If STATE is 0, RECT, ANCHOR_X ,and ANCHOR_Y parameters are not used.
find_docking
caches the dock widget sessions, and provides a
possibility to select different parameters passed to open_session
for different dock widgets. To achieve this, GetCaps
request
notification is triggered, which fills the parameters. The default
action sets sizeable
options according to x_sizeable
and y_sizeable
properties.
In case an appropriate landing area is found, Landing
notification is triggered with the proposed dock widget
and the target rectangle. The area can be rejected on this stage
if Landing
returns negative answer.
On success, returns a dock widget found and the target rectangle; the widget is never docked though. On failure returns an empty array.
This method is used by the dragging routine to provide a visual feedback to the user, to indicate that a shuttle may or may not land in a particular area.
close
function of the EDS ( external docker shuttle ). To cancel
the closing, clear_event
must be called inside the event handler.
open_session
call.
The default action sets sizeable
options according to x_sizeable
and y_sizeable
properties.
clear_event
must be called.
A shuttle class, used to host a client of Prima::InternalDockerShuttle
widget when it is in the non-docked state. The class represents an
emulation of a top-level window, which can be moved, resized ( this
feature is not on by default though ), and closed.
Prima::ExternalDockerShuttle
is inherited from Prima::MDI
class, and
its window emulating functionality is a subset of its ascendant.
See also the Prima::MDI manpage.
A simple descendant of Prima::InternalDockerShuttle
, used
for toolbars. Introduces orientation and draws a tiny header along
the minor shuttle axis. All its properties concern only
the way the shuttle draws itself.
Default value: 8
indents
property; besides the
space for the header, all indents are assigned to indent
property value.
Default value: 0
Dmitry Karasik, <dmitry@karasik.eu.org>.
Prima, the Prima::Widget manpage, the Prima::MDI manpage, the Prima::DockManager manpage, examples/dock.pl
Prima::Docks - dockable widgets |