NAME
Prima::Docks - dockable widgets
DESCRIPTION
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.
USAGE
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
Prima::DockManager.
Prima::AbstractDocker::Interface
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.
Properties
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 INTEGER
A custom bit mask, to be used by docking widgets to reject
inappropriate dock widgets on early stage. The "fingerprint"
property is not part of the protocol, and is not required to be
present in a dockable widget implementation.
Default value: 0x0000FFFF
dockup DOCK_WIDGET
Selects the upper link in dock widgets hierarchy tree. The upper
link is required to be a dock widget, but is not required to be a
direct or an indirect parent. In this case, however, the
maintenance of the link must be implemented separately, for
example:
$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};
Methods
add_subdocker SUBDOCK
Appends SUBDOCK to the list of lower-level docker widgets. The
items of the list are returned by "next_docker" method.
check_session SESSION
Debugging procedure; checks SESSION hash, warns if its members are
invalid or incomplete. Returns 1 if no fatal errors were
encountered; 0 otherwise.
close_session SESSION
Closes docking SESSION and frees the associated resources.
dock WIDGET
Called after WIDGET is successfully finished negotiation with the
dock widget and changed its "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.
dock_bunch @WIDGETS
Effectively docks set of WIDGETS by updating internal structures
and calling "rearrange".
docklings
Returns array of docked widgets.
next_docker SESSION, [ X, Y ]
Enumerates lower-level docker widgets within SESSION; returns one
docker widget at a time. After the last widget returns "undef".
The enumeration pointer is reset by "query" call.
X and Y are coordinates of the point of interest.
open_session PROFILE
Opens docking session with parameters stored in PROFILE and returns
session ID scalar in case of success, or "undef" otherwise. The
following keys must be set in PROFILE:
position ARRAY
Contains two integer coordinates of the desired position of a
widget in (X,Y) format in screen coordinate system.
self WIDGET
Widget that is about to dock.
sizeable ARRAY
Contains two boolean flags, representing if the widget can be
resized to an arbitrary size, horizontally and vertically. The
arbitrary resize option used as last resort if "sizes" key does
not contain the desired size.
sizeMin ARRAY
Two integers; minimal size that the widget can accept.
sizes ARRAY
Contains arrays of points in (X,Y) format; each point
represents an acceptable size of the widget. If "sizeable"
flags are set to 0, and none of "sizes" can be accepted by the
dock widget, "open_session" fails.
query SESSION [ X1, Y1, X2, Y2 ]
Checks if a dockable widget can be landed into the dock. If it
can, returns a rectangle that the widget must be set to. If
coordinates ( X1 .. Y2 ) are specified, returns the rectangle
closest to these. If "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.
rearrange
Effectively re-docks all the docked widgets. The effect is as same
as of
$self-> redock_widget($_) for $self-> docklings;
but usually "rearrange" is faster.
redock_widget WIDGET
Effectively re-docks the docked WIDGET. If WIDGET has "redock"
method in its namespace, it is called instead.
remove_subdocker SUBDOCK
Removes SUBDOCK from the list of lower-level docker widgets. See
also add_subdocker.
replace FROM, TO
Assigns widget TO same owner and rectangle as FROM. The FROM widget
must be a docked widget.
undock WIDGET
Removes WIDGET from list of docked widgets. The layout of the dock
widget can be changed after execution of this method. The method
does not change "owner" property of WIDGET.
The method must not be called directly.
Prima::SimpleWidgetDocker
A simple dock widget; accepts any widget that geometrically fits into.
Allows overlapping of the docked widgets.
Prima::ClientWidgetDocker
A simple dock widget; accepts any widget that can be fit to cover all
dock’s interior.
Prima::LinearWidgetDocker
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 ).
Properties
growable INTEGER
A combination of "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
hasPocket BOOLEAN
A boolean flag, affects the possibility of a docked widget to
reside outside the dock widget inferior. If 1, a docked wigdet is
allowed to stay docked ( or dock into a position ) further on the
major axis ( to the right when "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
vertical BOOLEAN
Selects the major axis of the dock widget. If 1, it is vertical,
horizontal otherwise.
Default value: 0
Events
Dock
Called when "dock" is successfully finished.
DockError WIDGET
Called when "dock" is unsuccessfully finished. This only happens if
WIDGET does not follow the docking protocol, and inserts itself
into a non-approved area.
Undock
Called when "undock" is finished.
Prima::SingleLinearWidgetDocker
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.
Prima::FourPartDocker
Implementation of a docking widget, with its four sides acting as
’rubber’ docking areas.
Properties
indents ARRAY
Contains four integers, specifying the breadth of offset for each
side. The first integer is width of the left side, the second -
height of the bottom side, the third - width of the right side, the
fourth - height of the top side.
dockerClassLeft STRING
Assigns class of left-side dock window.
Default value: "Prima::LinearWidgetDocker". Create-only property.
dockerClassRight STRING
Assigns class of right-side dock window.
Default value: "Prima::LinearWidgetDocker". Create-only property.
dockerClassTop STRING
Assigns class of top-side dock window.
Default value: "Prima::LinearWidgetDocker". Create-only property.
dockerClassBottom STRING
Assigns class of bottom-side dock window.
Default value: "Prima::LinearWidgetDocker". Create-only property.
dockerClassClient STRING
Assigns class of center dock window.
Default value: "Prima::ClientWidgetDocker". Create-only property.
dockerProfileLeft HASH
Assigns hash of properties, passed to the left-side dock widget
during the creation.
Create-only property.
dockerProfileRight HASH
Assigns hash of properties, passed to the right-side dock widget
during the creation.
Create-only property.
dockerProfileTop HASH
Assigns hash of properties, passed to the top-side dock widget
during the creation.
Create-only property.
dockerProfileBottom HASH
Assigns hash of properties, passed to the bottom-side dock widget
during the creation.
Create-only property.
dockerProfileClient HASH
Assigns hash of properties, passed to the center dock widget during
the creation.
Create-only property.
dockerDelegationsLeft ARRAY
Assigns the left-side dock list of delegated notifications.
Create-only property.
dockerDelegationsRight ARRAY
Assigns the right-side dock list of delegated notifications.
Create-only property.
dockerDelegationsTop ARRAY
Assigns the top-side dock list of delegated notifications.
Create-only property.
dockerDelegationsBottom ARRAY
Assigns the bottom-side dock list of delegated notifications.
Create-only property.
dockerDelegationsClient ARRAY
Assigns the center dock list of delegated notifications.
Create-only property.
dockerCommonProfile HASH
Assigns hash of properties, passed to all five dock widgets during
the creation.
Create-only property.
Prima::InternalDockerShuttle
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".
Properties
client WIDGET
Provides access to the client widget, which always resides either
in the internal or the external shuttle. By default there is no
client, and any widget capable of changing its parent can be set as
one. After a widget is assigned as a client, its "owner" and
"clipOwner" properties must not be used.
Run-time only property.
dock WIDGET
Selects the dock widget that the shuttle is landed on. If "undef",
the shuttle is in the non-docked state.
Default value: "undef"
dockingRoot WIDGET
Selects the root of dock widgets hierarchy. If "undef", the
shuttle can only exist in the non-docked state.
Default value: "undef"
See "USAGE" for reference.
externalDockerClass STRING
Assigns class of external shuttle widget.
Default value: "Prima::ExternalDockerShuttle"
externalDockerModule STRING
Assigns module that contains the external shuttle widget class.
Default value: "Prima::MDI" ( "Prima::ExternalDockerShuttle" is
derived from "Prima::MDI" ).
externalDockerProfile HASH
Assigns hash of properties, passed to the external shuttle widget
during the creation.
fingerprint INTEGER
A custom bit mask, used to reject inappropriate dock widgets on
early stage.
Default value: 0x0000FFFF
indents ARRAY
Contains four integers, specifying the breadth of offset in pixels
for each widget side in the docked state.
Default value: "5,5,5,5".
snapDistance INTEGER
A maximum offset, in pixels, between the actual shuttle coordinates
and the coordinates proposed by the dock widget, where the shuttle
is allowed to land. In other words, it is the distance between the
dock and the shuttle when the latter ’snaps’ to the dock during the
dragging session.
Default value: 10
x_sizeable BOOLEAN
Selects whether the shuttle can change its width in case the dock
widget suggests so.
Default value: 0
y_sizeable BOOLEAN
Selects whether the shuttle can change its height in case the dock
widget suggests so.
Default value: 0
Methods
client2frame X1, Y1, X2, Y2
Returns a rectangle that the shuttle would occupy if its client
rectangle is assigned to X1, Y1, X2, Y2 rectangle.
dock_back
Docks to the recent dock widget, if it is still available.
drag STATE, RECT, ANCHOR_X, ANCHOR_Y
Initiates or aborts the dragging session, depending on STATE
boolean flag.
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 DOCK, [ POSITION ]
Opens a session with DOCK, unless it is already opened, and
negotiates about the possibility of landing ( at particular
POSITION, if this parameter is present ).
"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.
frame2client X1, Y1, X2, Y2
Returns a rectangle that the client would occupy if the shuttle
rectangle is assigned to X1, Y1, X2, Y2 rectangle.
redock
If docked, undocks form the dock widget and docks back. If not
docked, does not perform anything.
Events
Dock
Called when shuttle is docked.
EDSClose
Triggered when the user presses close button or otherwise activates
the "close" function of the EDS ( external docker shuttle ). To
cancel the closing, "clear_event" must be called inside the event
handler.
FailDock X, Y
Called after the dragging session in the non-docked stage is
finished, but did not result in docking. X and Y are the
coordinates of the new external shuttle position.
GetCaps DOCK, PROFILE
Called before the shuttle opens a docking session with DOCK widget.
PROFILE is a hash reference, which is to be filled inside the event
handler. After that PROFILE is passed to "open_session" call.
The default action sets "sizeable" options according to
"x_sizeable" and "y_sizeable" properties.
Landing DOCK, X1, Y1, X2, Y2
Called inside the docking session, after an appropriate dock widget
is selected and the landing area is defined as X1, Y1, X2, Y2. To
reject the landing on either DOCK or area, "clear_event" must be
called.
Undock
Called when shuttle is switched to the non-docked state.
Prima::ExternalDockerShuttle
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 Prima::MDI.
Properties
shuttle WIDGET
Contains reference to the dockable WIDGET
Prima::LinearDockerShuttle
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.
Properties
headerBreadth INTEGER
Breadth of the header in pixels.
Default value: 8
indent INTEGER
Provides a wrapper to "indents" property; besides the space for the
header, all indents are assigned to "indent" property value.
vertical BOOLEAN
If 1, the shuttle is drawn as a vertical bar. If 0, the shuttle is
drawn as a horizontal bar.
Default value: 0
AUTHOR
Dmitry Karasik, <dmitry@karasik.eu.org>.
SEE ALSO
Prima, Prima::Widget, Prima::MDI, Prima::DockManager, examples/dock.pl