NAME
Prima::Object - base toolkit classes
SYNOPSIS
if ( $obj-> isa('Prima::Component')) {
# set and get a property
my $name = $obj-> name;
$obj->name( 'an object' );
# set a notification callback
$obj-> onPostMessage( sub {
shift;
print "hey! I've received this: @_\n";
});
# can set multiple properties. note, that 'name' and 'owner',
# replaces the old values, while onPostMessage subs are aggregated.
$obj-> set(
name => 'AnObject',
owner => $new_owner,
onPostMessage => sub {
shift;
print "hey! me too!\n";
},
);
# de-reference by name
$new_owner-> AnObject-> post_message(1,2);
}
DESCRIPTION
Prima::Object and Prima::Component are the root classes of the Prima toolkit hierarchy. All the other classes are derived from the Component class, which in turn is the only descendant of the Object class. Both of these classes are never used for instantiating objects, although this is possible with the
Prima::Component-> new( .. parameters ... );
call. This document describes the basic concepts of the OO programming with the Prima toolkit. Although the Component class has wider functionality than the Object class, all the examples will be explained using Component, since Object has no descendant classes other than Component anyway, and all the functionality of Object is present in Component too. This document partially overlaps with the information from Prima::internals, where the latter though focuses on a C programmer's perspective, while this document is about the perl programming.
Object base features
Creation
Object creation has fixed syntax:
$new_object = Class-> new(
parameter => value,
parameter => value,
...
);
The parameters and the values form a hash which is passed to the new() method. This hash is applied to the default parameter-value hash ( a profile ), specific to every Prima class. The object creation is performed in several stages.
- new
-
The new() constructor method calls the profile_default() method that returns ( as its name states ) the default profile, a hash with the appropriate default values assigned to its keys. The Component class defaults are
name => ref $_[ 0], owner => $::application, delegations => undef,
(also, see the source file Prima/Classes.pm):
While the exact meaning of these parameters is described later in "Properties", the idea is that a newly created object will have the 'owner' parameter set to '$::application' and 'delegations' to undef, etc etc - unless these parameters are explicitly passed to new(). Example:
$a1 = Prima::Component-> new();
$a1's owner will be $::application
$a2 = Prima::Component-> new( owner => $a1);
$a2's owner will be $a1. The actual merging of the default and the parameter hashes is performed in the next stage, in the profile_check_in() method which is called inside the profile_add() method.
Note: the older syntax used create() instead of new(), which is still valid but is not preferred.
- profile_check_in
-
The profile_check_in() method merges the default and the parameter profiles. By default, all the specified parameters have the ultimate precedence over the default ones, but in case the parameter specification is incomplete or ambiguous, the profile_check_in()'s task is to determine the actual parameter values. For example, the Component::profile_check_in method maintains simple automatic naming of the newly created objects. That is, if the object's name was not passed to new() as a parameter, then it is assigned to a string formed from the class name and some number, for example, Component1, Component2, etc.
In another example, the Prima::Widget::profile_check_in() method resolves eventual ambiguities caused by different ways of assigning widget positions on the screen. A widget's horizontal position can be specified by using the
left
andwidth
parameters, as well as by theright
,size
, and/orrect
. The default of bothleft
andwidth
properties is 100. But if, for example, only theright
parameter was passed to new(), then it is the profile_check_in()'s job to calculate the value for theleft
property, given thatwidth
is still 100.After the profiles are merged, the resulting hash is passed to the third stage, init().
- init
-
The init() method's task is to map the profile hash into the newly created object, e.g., assign the
name
parameter value to thename
property, and so on - for all relevant parameters. After that, it has to return the profile so that the overridden init() methods can perform the same actions. This stage along with the previous one can be found in almost all Prima classes.Note: usually the init() attaches the object to its owner in keep the newly-created object instance from being deleted by the garbage-collection mechanisms. See more on that later ( see "Links between objects").
After the init() finishes, the new() method calls the setup() method
- setup
-
The setup() method is a convenience function, it is used when any post-init actions must be taken. It is seldom overloaded, primarily because the Component::setup() method calls the
onCreate
notification, which is more convenient to overload than the setup().
As can be noticed from the code pieces above, a successful new() call returns a newly created object. If an error condition occurs, undef is returned. Only the errors that were generated via die() during the init() stage result in undef. Other errors raise an exception instead. It is not recommended to wrap the new() calls in an eval{}
block and to recover after the error because it can only occur in the two following situations. The first is a system error, either inside perl or Prima core (f ex an out-of-memory error), and not much can be done here since that error can very probably lead to an unstable program. The second reason is the programmer's error when a nonexistent parameter key or an invalid value is passed.
After a call to the new() method, the object can participate in the toolkit's event flow. The onCreate
event is always the first event the object receives, and after it, other events can be sent and received.
Destruction
Object destruction can be caused by many conditions, but the execution ultimately passes through the destroy() method. destroy(), as well as new(), performs the following finalizing steps:
- cleanup
-
The first method called inside the destroy() is cleanup(). The cleanup() method is a counter-method to setup(), as destroy() is the counter-method to new(). cleanup() generates the
onDestroy
event, which again can be overridden more easily than the cleanup() itself.onDestroy
is always the last event the object sees. After the cleanup() no events are allowed to circulate. - done
-
The done() method is the counter-method to init() and is the proper place to free all object resources. Although it is as safe to overload done() as init(), it gets overloaded, primarily because overloading
onDestroy
is easier.
The typical conditions that lead to the object destruction are a direct destroy() call, the garbage collection mechanisms, the user-initiated window closing action ( for Prima::Window
only ), and an exception during the init() stage. Thus, one must be careful implementing done() which could be also called if init() throws an exception.
Methods
The class methods are declared and used with the perl OO syntax, which allows two ways of referencing a method in the object's class:
$object-> method();
and
method( $object);
The actual code is a sub, located under the object class package. The overloaded methods that call their ancestor code use the
$object-> SUPER::method();
syntax. Most of the Prima methods have a fixed number of parameters.
Properties
Properties are methods that combine the functionality of two ephemeral methods, "get" and "set". The idea behind properties is that many object parameters require two independent methods, one that returns some internal state and another that changes it. For example, for managing the object name, set_name() and get_name() methods are needed. Indeed, the early Prima implementation dealt with a large amount of these get's and set's, but later these method pairs were deprecated in favor of the properties. Instead, there is now only one method name() ( referred to as ::name
later in the documentation ).
A property returns a value if no parameters (except the object itself) are passed, and changes the internal data to the passed parameters otherwise. Here's a sketch code for the ::name
property implementation:
sub name
{
return $_[0]-> {name} unless $#_;
$_[0]->{name} = $_[1];
}
There are many examples of properties throughout the toolkit. Not all properties deal with scalar values, some accept arrays or hashes as well. The properties can be set-called not only by name like
$object-> name( "new name");
but also with the set() method. The set() method accepts a hash, that is similar to hashes passed to new(), and also assigns its values to the corresponding properties. For example, the code
$object-> name( "new name");
$object-> owner( $owner);
can be rewritten as
$object-> set(
name => "new name",
owner => $owner
);
A minor speed-up is gained here by eliminating some of the C-to-perl and perl-to-C calls, especially if the code called is implemented in C. The only problem with this technique is that the order in which the properties are set is undefined. Therefore, the usage of set() is recommended either when the property order is irrelevant, or it is known beforehand that such a call speeds up the code, or is the only way to achieve the required result. An example of the latter case shows that Prima::Image calls
$image-> type( $a);
$image-> palette( $b);
and
$image-> palette( $b);
$image-> type( $a);
produce different results. It is indeed the only solution to request a change that converts an image using both type and palette at the same time, to use the following code:
$image-> set(
type => $a,
palette => $b
);
This though makes sense only when it is known beforehand that Prima::Image::set
is aware of this combination and calls neither ::type
nor ::palette
but performs another image conversion instead.
Some properties are read-only and some are write-only. Some methods that might be declared as properties are not; these are declared as plain methods with get_ or set_ name prefix. There is not much certainty about what methods are better off being declared as properties and vice versa.
However, if get_ or set_ methods cannot be used in, correspondingly, write or read fashion, the R/O and W/O properties can. They raise an exception in an attempt to do so.
Links between objects
Prima::Component descendants can be used as containers, ie objects that are on a higher hierarchy level than the others, f ex the child-parent relationship. The 'children' objects have the ::owner
property value assigned to a reference to an 'owner' object, while the 'owner' object contains the list of its children. It is a one-to-many hierarchy scheme, as a 'child' object can only have a single owner, while an 'owner' object can have many children. The same object can be an owner and a child at the same time, so the owner-child hierarchy can be viewed as a tree-like structure, too.
The Prima::Component::owner property maintains such a relation, and is writable - the object can change its owner dynamically. There is no corresponding property that manages children objects, but there is the method get_components(), that returns an array of the child references.
The owner-child relationship is used in several ways in the toolkit. For example, the widgets that are children of another widget appear ( usually, but not always ) inside of the rectangular area occupied by the owner widget. Some events ( keyboard events, for example ) are propagated automatically up and/or down the object tree. Another important feature is that when an object gets destroyed its children are destroyed first. In a typical program the whole object tree roots in a Prima::Application object instance. When the application finishes, this feature helps clean up the widgets and quit gracefully.
Implementation note: the name 'owner' was taken instead of the initial 'parent', because the 'parent' is a fixed term for widget hierarchy relationship description. The Prima::Widget relationship between owner and child is not the same as GUI's parent-to-child. The parent is the widget for the children widgets located in and clipped by its inferior. The owner widget is more than that, its children can be located outside its owner's boundaries.
An alternative to the new() method, the insert() method is used to explicitly select the owner of the newly created object. The insert() method too can be considered a constructor in the OO-terms. It makes the code
$obj = Class-> new( owner => $owner, name => 'name);
more readable by introducing the
$obj = $owner-> insert( 'Class', name => 'name');
syntax. These two code blocks are identical
There is another type of relation where objects can hold references to each other. Internally this link level is used to keep objects from deletion by garbage collection mechanisms. This relation is the many-to-many scheme, where every object can have many links to other objects. This functionality is managed by the attach() and detach() methods.
Events
Prima::Component descendants employ a well-developed event propagation mechanism, which allows the handling of events using several different schemes. An event is a condition, caused by the system or the user, or an explicit notify() call. The formerly described events onCreate and onDestroy are triggered after a new object is created or before it gets destroyed. These two events, and the described below onPostMessage event are available for all Prima objects. New classes can register their own events and define their execution flow, using the notification_types() method. This method returns all available information about the events registered in a class.
Prima defines also the non-object event dispatching and filtering mechanism, available through the "event_hook" static method.
Propagation
The event propagation mechanism has three different schemes of registering a user-defined callback, either on the object itself, on the object class, or on the class of some other object
In the descriptions of the schemes below, there are example codes of how to catch the following event depending on the scheme used:
$obj-> notify("PostMessage", $data1, $data2);
- Direct methods
-
As is usual in the OO programming, event callback routines are declared as methods. 'Direct methods' employ this paradigm too, so if the class method named
on_postmessage
is present, it will be called as a method ( i.e., in the object context ) when theonPostMessage
event is sent. For example:sub on_postmessage { my ( $self, $data1, $data2) = @_; ... }
The callback name is the modified lower-case event name: the name for the Create event is on_create, PostMessage - on_postmessage, etc. These methods can be overloaded in the object's class descendants. The only note on declaring these methods in the first instance is that no
::SUPER
call is needed because these methods are not defined by default.Usually, the direct methods are used for internal bookkeeping, reacting to the events that are not meant to be passed to the program. For example, the Prima::Button class catches mouse and keyboard events in such a way, because usually, the only notification that is interesting for the code that employs push-buttons is
Click
, and rarely anything else. This scheme is convenient when an event handling routine serves internal, implementation-specific needs. - Delegated methods
-
The delegated methods are used when objects ( mostly widgets ) include other dependent objects, and the functionality requires interaction between these. The callback functions here are the same methods as the direct methods, except that they get called in the context of two, not one, objects. If, for example, an $obj's owner, $owner, would be interested in $obj's PostMessage event, it would register the notification callback by issuing the following call:
$obj-> delegations([ $owner, 'PostMessage']);
where the actual callback sub will be declared as
sub Obj_PostMessage { my ( $self, $obj, $data1, $data2) = @_; }
Note that the naming style is different - the callback name is constructed from the object name ( let's assume that $obj's name is 'Obj') and the event name. ( This is one of the reasons why Component::profile_check_in() performs automatic naming of newly created objects). Note also that the context objects are $self ( that equals $owner in this case) and $obj.
The delegated methods can be used not only for owner-child relations. Every Prima object is free to add a delegation method to every other object. However, if the objects are in other than the owner-child relation, it is a good practice to add Destroy notification to the object whose events are of interest, so if it gets destroyed, the partner object gets a message about that.
- Anonymous subroutines
-
The two previous callback types are more relevant when a separate class is designed. However, in the Prima toolkit, it is not necessary to declare a new class every time the event handling is needed. It is possible to use the third and the most powerful event hook scheme using perl anonymous subroutines ( subs ) for easy customization.
Contrary to the usual OO event implementations, when only one routine per class dispatches an event and calls the inherited handlers when it is appropriate, the Prima event handling mechanism can accept many event handlers for one object ( it is greatly facilitated by the fact that perl has anonymous subs, however).
All the callback routines are called when an event is triggered, one by one in turn. If the direct and delegated methods can only be multiplexed by the usual OO inheritance, the anonymous subs are allowed to be many by design. There are three syntaxes for setting such an event hook; the example below sets a hook on $obj using each syntax for a different situation:
- during new():
$obj = Class-> new( ... onPostMessage => sub { my ( $self, $data1, $data2) = @_; }, ... );
- after new() using set()
$obj-> set( onPostMessage => sub { my ( $self, $data1, $data2) = @_; });
- after new() using the event name:
$obj-> onPostMessage( sub { my ( $self, $data1, $data2) = @_; });
The events can be addressed as properties, with the exception that they are not substitutive but additive. The additivity means that when the latter type of syntax is used, the subs already registered do not get overwritten or discarded but stack in the internal object queue. Thus,
$obj-> onPostMessage( sub { print "1" }); $obj-> onPostMessage( sub { print "2" }); $obj-> notify( "PostMessage", 0, 0);
code block would print
21
as the execution result.
It is a distinctive feature of the Prima toolkit that two objects of the same class may have different set of event handlers.
Flow
When there is more than one handler of a particular event type present on an object, a question may arise about what are the callback's call priorities and when the event processing stops. One of the ways to regulate the event flow is based on prototyping events, by using the notification_types() event type description. This function returns a hash, where the keys are the event names and the values are the constants that describe the event flow. A constant is a bitwise OR combination of several basic flow nt::XXX
constants, that control the following three aspects of the event flow:
- Order
-
If both anonymous subs and direct/delegated methods are present, the object needs to decide which callback class must be called first. Both 'orders' are useful: for example, if a class is designed in such a way that some default action is meant to be overridden, it is better to call the custom actions first. If, on the contrary, a class event handler does most of the heavy lifting, then the reverse order may be preferred instead. One of the two
nt::PrivateFirst
andnt::CustomFirst
constants defines the event execution order. - Direction
-
Almost the same as the order, but used for finer granulation of the event flow, the direction constants
nt::FluxNormal
andnt::FluxReverse
are used. The 'normal flux' defines the FIFO ( first in first out ) direction. That means, that the sooner the callback is registered, the greater priority it would have during the execution. The code block from the example above$obj-> onPostMessage( sub { print "1" }); $obj-> onPostMessage( sub { print "2" }); $obj-> notify( "PostMessage", 0, 0);
results in
21
, not12
because the PostMessage event type is prototyped asnt::FluxReverse
. - Execution control
-
It was stated above that the events are additive, - the callback storage is never discarded when 'set'-syntax is used. However, the event can be told to behave like a substitutive property, e.g. to call one and only one callback. This functionality is managed by the
nt::Single
bit in the execution control constant set, which consists of the following constants:nt::Single nt::Multiple nt::Event
These constants are mutually exclusive, and may not appear together in an event type declaration. A
nt::Single
-prototyped notification calls only the first ( or the last - depending on order and direction bits ) callback. The usage of this constant is somewhat limited.In contrast with
nt::Single
, thent::Multiple
constant sets the execution control to call all the available callbacks, with respect to the direction and the order bits.The third constant,
nt::Event
, is the same asnt::Multiple
, except that the event flow can be stopped at any time by calling the clear_event() method.
Although there are 12 possible event type combinations, half of them are not usable for anything. The combinations from another half were assigned more-less descriptive names:
nt::Default ( PrivateFirst | Multiple | FluxReverse)
nt::Property ( PrivateFirst | Single | FluxNormal )
nt::Request ( PrivateFirst | Event | FluxNormal )
nt::Notification ( CustomFirst | Multiple | FluxReverse )
nt::Action ( CustomFirst | Single | FluxReverse )
nt::Command ( CustomFirst | Event | FluxReverse )
Success state
Events do not return values, although the event generator, the notify() method does - it returns either 1 or 0, which is the value of the event state. The 0 and 1 results however do not mean either success or failure, they simply reflect the fact whether the clear_event() method was called during the processing - 1 if it was not, 0 otherwise. The state is kept during the whole processing stage and can be accessed by the Component::eventFlag property. Since it is allowed to call the notify() method inside event callbacks, the object maintains a stack for those states. The Component::eventFlag property always works with the topmost one and fails if is called from outside the event processing stage; clear_event() is no more than an alias for the eventFlag(0) call. The state stack is operated by the push_event() and pop_event() methods.
Implementation note: a call to clear_event() inside a nt::Event
-prototyped event call does not automatically stop the execution. The execution stops if the state value equals 0 after the callback is finished. The eventFlag(1) call thus cancels the effect of clear_event().
A particular coding style is used when the event is nt::Single
-prototyped and is called many times in a row, so overheads of calling notify() become a burden. Although the notify() logic is somewhat complicated, it is rather simple in the nt::Single
case. The helper function get_notify_sub() returns the context of the callback to be called, so it can be used to emulate the notify() behavior. For example:
for ( ... ) {
$result = $obj-> notify( "Measure", @parms);
}
can be expressed in more cumbersome, but efficient code if the nt::Single
-prototyped event is used:
my ( $notifier, @notifyParms) = $obj-> get_notify_sub( "Measure" );
$obj-> push_event;
for ( ... ) {
$notifier-> ( @notifyParms, @parms);
# $result = $obj-> eventFlag; # this is optional
}
$result = $obj-> pop_event;
Inheritance
The design of the Prima classes is meant to be as close as possible to the standard perl OO model. F.ex. to subclass a new package, a standard
use base qw(ParentClass);
or even
out @ISA = qw(ParentClass);
should be just fine.
However, there are special considerations about the multiple inheritance and the order of the ancestor classes. First, the base class should be a Prima class, i e
use base qw(Prima::Widget MyRole);
not
use base qw(MyRole Prima::Widget);
This is caused by the perl OO model where if more than one base class has the same method, only the first method will be actual, and Prima conforms to that. F ex defining a MyRole::init
won't have any effect where MyRole is not the first base class (and things will explode badly if it is).
In a very special case where the MyRole class needs to have methods that overload Prima core, XS-implemented methods, a special technique is used:
First, in MyRole, declare a special method
CORE_METHODS
, returning all names of the core symbols to be overloaded in that role:package MyRole; sub CORE_METHODS { qw(setup) }
Do not subclass MyRole from Prima objects though.
Define the methods as if you would define a normal overridden method, with one important exception: since perl's SUPER is package-based, not object-based, the
$self->SUPER::foo()
pattern will not work for calling the methods that are up in the hierarchy. Instead, the first parameter to these methods is an anonymous subroutine that will call the needed SUPER method:sub setup { my ( $orig, $self ) = ( shift, shift ); ... $orig->( $self, @_ ); ... }
If you know Moose standard syntax
around
, this is the same idea.Note that this method will be called after the descendant class
setup
if the class has one. This is a bit confusing as in all types of OO inheritance sub-class code is always called after the super-class, not vice versa. This might change in the future, too.In the descendant class, inherit from the MyRole normally, but in addition to that make the call to overload its special methods:
package MyWidget; use base qw(Prima::Widget MyRole); __PACKAGE__->inherit_core_methods('MyRole');
Check also Prima::Widget::GroupScroller as an example.
API
Prima::Object methods
- alive
-
Returns the object 'vitality' state - true if the object is alive and usable, false otherwise. This method can be used as a general checkout if the scalar passed is a Prima object, and if it is usable. The true return value can be 1 for normal and operational object state, and 2 if the object is alive but in its init() stage. Example:
print $obj-> name if Prima::Object::alive( $obj);
- cleanup
-
Called right after the destroy() started. Used to initiate the
cmDestroy
event. Is never called directly. - create CLASS, %PARAMETERS
-
Same as new.
- destroy
-
Initiates the object destruction. Calls cleanup() and then done(). destroy() can be called several times and is the only Prima re-entrant function, therefore may not be overloaded.
- done
-
Called by the destroy() method after cleanup() is finished. Used to free the object resources, as a finalization stage. During done() no events are allowed to circulate, and alive() returns 0. The object is not usable after done() finishes. Is never called directly.
Note: the eventual child objects are destroyed inside the done() call.
- get @PARAMETERS
-
Returns a hash where the keys are @PARAMETERS and values are the corresponding object properties.
- init %PARAMETERS
-
The most important stage of the object creation process. %PARAMETERS is the modified hash that was passed to new(). The modification consists of merging with the result of the profile_default() method inside the profile_check_in() method. init() is responsible for applying the relevant data from PARAMETERS to the corresponding object properties. Is never called directly.
- insert CLASS, %PARAMETERS
-
A convenience wrapper for new() that explicitly sets the owner property for a newly created object.
$obj = $owner-> insert( 'Class', name => 'name');
is identical to
$obj = Class-> new( owner => $owner, name => 'name);
insert() has another syntax that allows simultaneous creation of several objects:
@objects = $owner-> insert( [ 'Class', %parameters], [ 'Class', %parameters], ... );
With this syntax, all newly created objects would have $owner set to their 'owner' properties.
- new CLASS, %PARAMETERS
-
Creates a new object instance of the given CLASS and sets its properties corresponding to the passed parameter hash. Examples:
$obj = Class-> new( PARAMETERS); $obj = Prima::Object::new( "class" , PARAMETERS);
Is never called in an object context.
Alias: create()
- profile_add PROFILE
-
The first stage of the object creation process. The PROFILE is a reference to the PARAMETERS hash, passed to the new() method. The hash is merged with the hash produced by the profile_default() method after passing both through the profile_check_in(). The merge result is stored back in PROFILE.
The method is never called directly.
- profile_check_in CUSTOM_PROFILE, DEFAULT_PROFILE
-
The second stage of the object creation process. Resolves eventual ambiguities in CUSTOM_PROFILE, which is the reference to the PARAMETERS passed to new(), by comparing to and using the default values from the DEFAULT_PROFILE, which in turn is the result of the profile_default() method.
The method is never called directly.
- profile_default
-
Returns a hash of the appropriate default values for all properties of the class. In the object creation process serves as a provider of fall-back values, and is called (once) during the process. The method can be used directly, contrary to the other creation process-related functions.
Can be called in a context of a class.
- raise_ro TEXT
-
Throws an exception with text TEXT when a read-only property is called in a set- context.
- raise_wo TEXT
-
Throws an exception with text TEXT when a write-only property is called in a get-context.
- set %PARAMETERS
-
The default behavior is equivalent to the following code:
sub set { my $obj = shift; my %PARAMETERS = @_; $obj-> $_( $PARAMETERS{$_}) for keys %PARAMETERS; }
Assigns the object properties correspondingly to the PARAMETERS hash. Many Prima::Component descendants overload set() to make it more efficient for particular parameter key patterns.
Like the code above, raises an exception if the key in PARAMETERS has no correspondent object property.
- setup
-
The last stage of the object creation process. Called after init() finishes. Used to initiate the
onCreate
event. Is never called directly.
Prima::Component methods
- add_notification NAME, SUB, REFERRER = undef, INDEX = -1
-
Adds the SUB to the list of notifications for the event NAME. REFEREE is the object reference, which is used to create a context to the SUB and is also passed as a parameter to it when the event callback is called. If the REFEREE is undef ( or is not specified ), then the caller object is assumed. REFEREE also gets implicitly attached to the object, - the implementation frees the link between the objects when one of these gets destroyed.
INDEX is a desired insert position in the notification list. By default, it is -1, which means 'in the start'. If the notification type contains nt::FluxNormal bit set, the newly inserted SUB will be called first. If it has nt::FluxReverse, it is called last, correspondingly.
Returns a positive integer value on success, and 0 on failure. This value can be later used to refer to the SUB in remove_notification().
See also:
remove_notification
,get_notification
. - attach OBJECT
-
Inserts the OBJECT into the list of the attached objects and increases the OBJECT's reference count. The list may not hold more than one reference to the same object; the warning is issued on such an attempt.
See also:
detach
. - bring NAME, MAX_DEPTH=0
-
Looks for the child object that has a name that equal to NAME. Returns its reference on success, undef otherwise. It is a convenience method, that makes possible the usage of the following constructs:
$obj-> name( "Obj"); $obj-> owner( $owner); ... $owner-> Obj-> destroy; ... $obj-> deepChildLookup(1); $obj-> insert(Foo => name => 'Bar'); $owner-> Bar-> do_something;
See also:
find_component
,deepChildLookup
- can_event
-
Returns true if the object event circulation is allowed. In general, the same as
alive() == 1
, except that can_event() fails if an invalid object reference is passed. - clear_event
-
Clears the event state, that is set to 1 when the event processing begins. Signals the event execution stop for the nt::Event-prototyped events.
See also: "Events",
push_event
,pop_event
,::eventFlag
,notify
.Use this call in your overloaded event handlers when signalling that further processing should be stopped, f ex onMouseDown doing something else than the base widget.
See more in "Execution control". Check the exact
nt::
type of the event in the Prima/Classes.pm source. - detach OBJECT, KILL
-
Removes the OBJECT from the list of the attached objects and decreases the OBJECT's reference count. If KILL is true, destroys the OBJECT.
See also:
attach
- event_error
-
Issues a system-dependent warning sound signal.
- event_hook [ SUB ]
-
Installs the SUB to receive all events on all Prima objects. The SUB receives the same parameters passed to notify and must return an integer, either 1 or 0, to pass or block the event respectively.
If no SUB is set, returns the currently installed event hook pointer. If SUB is set, replaces the old hook sub with SUB. If SUB is
'undef'
, event filtering is not used.Since the
'event_hook'
mechanism allows only one hook routine to be installed at a time, direct usage of the method is discouraged. Instead, use the Prima::EventHook API for multiplexing access to the hook.The method is static and can be called either with or without a class or an object as a first parameter.
- find_component NAME
-
Performs a depth-first search on children tree hierarchy, matching the object that has a name equal to NAME. Returns its reference on success, undef otherwise.
See also:
bring
- get_components
-
Returns an array of the child objects.
See:
new
, "Links between objects". - get_handle
-
Returns a system-dependent handle for the object. For example, Prima::Widget returns its system Window/HWND handles, Prima::DeviceBitmap - its system Pixmap/HBITMAP handles, etc.
Can be used to pass the handle value outside the program, for eventual interprocess communication.
- get_notification NAME, @INDEX_LIST
-
For each index in the INDEX_LIST returns three scalars, bound to the index position in the NAME event notification list. These three scalars are REFERRER, SUB, and ID. REFERRER and SUB are those passed to
add_notification
, and ID is its saved result.See also:
remove_notification
,add_notification
. - get_notify_sub NAME
-
A convenience method for the nt::Single-prototyped events. Returns the code reference and the context for the first notification sub for event NAME.
See "Success state" for example.
- notification_types
-
Returns a hash, where the keys are the event names and the values are the
nt::
constants that describe the event flow.Can be called in the context of a class.
- notify NAME, @PARAMETERS
-
Calls the subroutines bound to the event NAME with parameters @PARAMETERS in the context of the object. The calling order is described by the
nt::
constants, from the hash returned by the notification_types().notify() accepts a variable number of parameters, and while it is possible, it is not recommended to call notify() with the excessive number of parameters. The call with the deficient number of parameters results in an exception.
Example:
$obj-> notify( "PostMessage", 0, 1);
- pop_event
-
Closes the event processing stage bracket.
See
push_event
, "Events" - post_message SCALAR1, SCALAR2
-
Calls the
PostMessage
event with parameters SCALAR1 and SCALAR2 once during the next idle event loop. Returns immediately. Does not guarantee thatPostMessage
will be called, however.See also "post" in Prima::Utils
- push_event
-
Opens the event processing stage bracket.
See
pop_event
, "Events" - remove_notification ID
-
Removes the notification subroutine that was registered before using the
add_notification
method, and where the ID was its result. After the successful removal, the eventual context object gets implicitly detached from the storage object.See also:
add_notification
,get_notification
. - set_notification NAME, SUB
-
Adds the SUB to the event NAME notification list. Rarely used directly, but is a key point in enabling the following syntax:
$obj-> onPostMessage( sub { ... });
or
$obj-> set( onPostMessage => sub { ... });
that are shortcuts for
$obj-> add_notification( "PostMessage", sub { ... });
- unlink_notifier REFERRER
-
Removes all notification subs from all event lists bound to the REFERRER object.
Prima::Component properties
- deepChildLookup BOOL
-
If set, the lookup by name uses a breadth-first deep lookup into the object hierarchy. If unset (default), only immediate children objects are searched.
$self->deepChildLookup(0); $self->Child1->GrandChild2; ... $self->deepChildLookup(1); $self->GrandChild2;
- eventFlag STATE
-
Provides access to the last event processing state in the object event state stack.
See also: "Success state",
clear_event
, "Events". - delegations [ <REFERRER>, NAME, <NAME>, < <REFERRER>, NAME, ... > ]
-
Accepts an anonymous array in the set- context, which consists of a list of event NAMEs, that a REFERRER object ( the caller object by default ) is interested in. Registers notification entries if the subs with the naming scheme REFERRER_NAME are present on the REFERRER namespace. The example code
$obj-> name("Obj"); $obj-> delegations([ $owner, 'PostMessage']);
registers the Obj_PostMessage callback if it is present in the $owner namespace.
In the get- context returns an array reference that reflects the object's delegated events list content.
See also: "Delegated methods".
- name NAME
-
Maintains the object name. NAME can be an arbitrary string, however it is recommended against the usage of special characters and spaces in NAME, to facilitate the indirect object access coding style:
$obj-> name( "Obj"); $obj-> owner( $owner); ... $owner-> Obj-> destroy;
and to prevent system-dependent issues. If the system provides capabilities that allow to predefining some object parameters by its name (or its class), then it is impossible to know beforehand the system naming restrictions. For example, in the X11 window system the following resource string would make all Prima toolkit buttons green:
Prima*Button*backColor: green
In this case, using special characters such as
:
or*
in the name of an object would make the X11 resource unusable. - owner OBJECT
-
Sets the owner of the object, which may be a Prima::Component descendant. Setting an owner to an object does not alter its reference count. Some classes allow OBJECT to be undef, while some do not. All widget objects can not exist without a valid owner; Prima::Application on the contrary can only exist with the owner set to undef. Prima::Image objects are indifferent to the value of the owner property.
Changing the owner dynamically is allowed, but it is a main source of implementation bugs since the whole hierarchy tree needs to be recreated. Although this effect is not visible in perl, the results are deeply system-dependent, and the code that changes owner property should be thoroughly tested.
Changes to the
owner
result in up to three notifications:ChangeOwner
, which is called to the object itself,ChildLeave
, which notifies the previous owner that the object is about to leave, andChildEnter
, telling the new owner about the new child.
Prima::Component events
- ChangeOwner OLD_OWNER
-
Called when the object changes its owner.
- ChildEnter CHILD
-
Triggered when a child object is attached, either as a new instance or as a result of runtime owner change.
- ChildLeave CHILD
-
Triggered when a child object is detached, either because it is getting destroyed or as a result of runtime owner change.
- Create
-
The first event the object sees. Called automatically after init() is finished. Is never called directly.
- Destroy
-
The last event the object sees. Called automatically before done() is started. Is never called directly.
- PostMessage SCALAR1, SCALAR2
-
Called after the post_message() call is issued, however not inside post_message() but after the next idle event loop. SCALAR1 and SCALAR2 are the data passed to the post_message().
- SysHandle
-
Sometimes Prima needs to implicitly re-create the system handle of a component. The re-creation usually happens deep inside the Prima core, however, if widgets on the screen are re-created, then they might get repainted. This happens when the underlying system either doesn't have API to change a certain property during the runtime or when such a re-creation happens on one of the component's parents, leading to a downward cascade of re-creation of the children. Also, it may happen when the user changes some system settings resolution so that some resources have to be changed accordingly.
This event will be only needed when the system handle (that can be acquired by
get_handle
) is used further, or in the case when Prima doesn't restore some properties bound to the system handle.
AUTHOR
Dmitry Karasik, <dmitry@karasik.eu.org>.