pod::Prima::Object(3)
π pod::Prima::Object(3) π
User Contributed Perl Documentation Β· Prima::Object β base toolkit classes π
πΈ NAME πΈ
Prima::Object β base toolkit classes π
π¦ SYNOPSIS π¦
okay bestie, here's the whole vibe in one little block:
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 π
Okay so Prima::Object and Prima::Component are literally the root classes of the Prima toolkit hierarchy. Every other class is derived from the Component class, which is the only descendant of the Object class. Both of these classes are never used for instantiating objects, although it is possible with the
Prima::Component-> new( .. parameters ... );
call. This document describes the basic concepts of OO programming with the Prima toolkit. Although the Component class has wider functionality than the Object class, all the examples are 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 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 usedcreate()instead ofnew(), 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" and "width" parameters, as well as by the "right", "size", and/or "rect". The default of both "left" and "width" properties is 100. But if, for example, only the "right" parameter was passed to new(), then it is the profile_check_in()'s job to calculate the value for the "left" property, given that "width" 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 the "name" 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
);
Okay so this only makes sense when you already know beforehand that Prima::Image::set is aware of this combo and calls neither ::type nor ::palette, but instead does another image conversion. Like, itβs a specific-set situation, bestie. π
Some properties are read-only and some are write-only. Some methods that could have been properties are not β theyβre just plain methods with a get_ or set_ name prefix. Ngl, there isnβt much certainty about which methods are better off as properties and which are better off as plain methods, and vice versa. Thatβs just the vibe. π«Ά
But hereβs the useful bit: if get_ or set_ methods canβt be used in write or read fashion (respectively), then the R/O and W/O properties can β and they raise an exception if you try to do the forbidden thing. Periodt. π
β¨ Links between objects β¨
Prima::Component descendants can be used as containers β i.e., objects that sit on a higher hierarchy level than others, like the child-parent relationship. The βchildrenβ objects have their ::owner property value assigned to a reference to an βownerβ object, while the βownerβ object contains the list of its children. Itβs a one-to-many hierarchy scheme: a βchildβ object can only have a single owner, while an βownerβ object can have many children. And yes, 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 this relation, and itβs writable β the object can change its owner dynamically. Thereβs no corresponding property that manages children objects, but there is the method get_components(), which returns an array of the child references. Slay. π
The owner-child relationship gets used in several ways in the toolkit. For example, widgets that are children of another widget appear (usually, but not always) inside 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: 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, so when the application finishes, this feature helps clean up the widgets and quit gracefully. Iconic cleanup behavior, honestly. π§
Implementation note: the name'owner'was taken instead of the initial'parent', because'parent'is a fixed term for widget hierarchy relationship description. ThePrima::Widgetrelationship 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 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βs 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. Very demure, very mindful. πΈ
π¦ 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 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 the onPostMessage 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. No cap. β¨
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 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()usingset()
$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. Not me being obsessed with queue order, but here we are. π
It is a distinctive feature of the Prima toolkit that two objects of the same class may have different set of event handlers. Main character energy for every object, honestly. π
π₯ Flow π₯
When there is more than one handler of a particular event type present on an object, a question may arise about what the callbackβs call priorities are 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 πΈ
okay so if you've got both anonymous subs and direct/delegated methods hanging out on the same object, somebody's gotta decide which callback class gets called first. and tbh both orders are useful:
- if a class is designed so that some default action is meant to be overridden, it's 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 might be the vibe instead
one of the two constants nt::PrivateFirst and nt::CustomFirst defines the event execution order. pick your fighter π
Direction π¦
almost the same as order, bestie, but used for finer granulation of the event flow β for that we have the direction constants nt::FluxNormal and nt::FluxReverse.
the 'normal flux' defines the FIFO (first in first out) direction. meaning: the sooner the callback is registered, the greater priority it has during execution. so 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, not 12, because the PostMessage event type is prototyped as nt::FluxReverse. plot twist! π
Execution control π
so earlier it was stated that events are additive β the callback storage is never discarded when the 'set'-syntax is used. iconic. however, an 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 these 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, ngl.
in contrast with nt::Single, the nt::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 as nt::Multiple, except that the event flow can be stopped at any time by calling the clear_event() method. main character energy honestly.
so yeah, there are 12 possible event type combinations, but half of them are not usable for anything π. the combinations from the other 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. but bestie, the 0 and 1 results do not mean success or failure β they simply reflect whether the clear_event() method was called during the processing (1 if it was not called, 0 otherwise). no cap.
the state is kept during the whole processing stage and can be accessed by the Component::eventFlag property. since it's 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 it's 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 toclear_event()inside ant::Event-prototyped event call does not automatically stop the execution. the execution stops if the state value equals0after the callback is finished. so theeventFlag(1)call cancels the effect ofclear_event(). lowkey important, don't skip this one π«Ά
a particular coding style is used when the event is nt::Single-prototyped and is called many times in a row, so the overheads of calling notify() become a burden. although the notify() logic is somewhat complicated, it's 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;
slay, efficiency π
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. periodt.
however β and this is the part where you gotta pay attention β there are special considerations about 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 ππ). consider yourself warned, bestie.
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
SUPERis 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 neededSUPERmethod:
sub setup
{
my ( $orig, $self ) = ( shift, shift );
...
$orig->( $self, @_ );
...
}
if you know the 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. iykyk β¨
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 be1for a normal, operational object state, and2if the object is alive but in itsinit()stage. example:
print $obj-> name if Prima::Object::alive( $obj);
cleanupβ called right after thedestroy()started. used to initiate thecmDestroyevent. is never called directly.create CLASS, %PARAMETERSβ same asnew.destroyβ initiates the object destruction. callscleanup()and thendone().destroy()can be called several times and is the only Prima re-entrant function, therefore it may not be overloaded.doneβ called by thedestroy()method aftercleanup()is finished. used to free the object resources, as a finalization stage. duringdone()no events are allowed to circulate, andalive()returns0. the object is not usable afterdone()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@PARAMETERSand the values are the corresponding object properties.init %PARAMETERSβ the most important stage of the object creation process.%PARAMETERSis the modified hash that was passed tonew(). the modification consists of merging with the result of theprofile_default()method inside theprofile_check_in()method.init()is responsible for applying the relevant data fromPARAMETERSto the corresponding object properties. is never called directly.insert CLASS, %PARAMETERSβ a convenience wrapper fornew()that explicitly sets theownerproperty for a newly created object. so:
$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. iconic, honestly π«Ά
new CLASS, %PARAMETERSβ creates a new object instance of the givenCLASSand 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. thePROFILEis a reference to thePARAMETERShash, passed to thenew()method. the hash is merged with the hash produced by theprofile_default()method after passing both through theprofile_check_in(). the merge result is stored back inPROFILE.
the method is never called directly.
profile_check_in CUSTOM_PROFILE, DEFAULT_PROFILE
This is literally stage two of the whole object-creation pipeline, bestie. It takes CUSTOM_PROFILE β that's the reference to the PARAMETERS you handed to new() β and smooths out any lingering ambiguities in it by comparing against, and pulling fallback values from, DEFAULT_PROFILE, which is the result that came out of the profile_default() method. π
Fr fr, the method is never called directly. Hands off. π
profile_default
Returns a hash stuffed with the appropriate default values for, like, all the properties of the class. In the object creation process it's the provider of fall-back values and gets called (once π) during that process.
Buuut here's the slay part: unlike the other creation-process-related functions, this one can actually be used directly. β¨
Can be called in the context of a class. π
raise_ro TEXT
Throws an exception with text TEXT when a read-only property gets called in a set-context. So if you try to write to something that's read-only, this is the icon that calls you out. π©
raise_wo TEXT
Throws an exception with text TEXT when a write-only property gets called in a get-context. Same energy, other direction. π«Ά
set %PARAMETERS
The default behavior is equivalent to literally this exact code, no cap:
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 β main character energy, honestly. π
Like the code above, it raises an exception if a 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. Periodt. π ββοΈ
π¦ 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, and it's used to create a context for the SUB and is also passed as a parameter to it when the event callback is called. If the REFEREE is undef (or just wasn't specified at all, ngl), then the caller object is assumed instead. REFEREE also gets implicitly attached to the object β the implementation frees the link between the objects when one of these gets destroyed. π
INDEX is the desired insert position in the notification list. By default it's -1, which means 'in the start'. If the notification type contains the nt::FluxNormal bit set, the newly inserted SUB will be called first. If it has nt::FluxReverse, it's called last, correspondingly. π«
Returns a positive integer value on success, and 0 on failure. That value can be used later 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 β a warning gets issued on such an attempt. π¨
See also: "detach".
bring NAME, MAX_DEPTH=0
Looks for the child object that has a name equal to NAME. Returns its reference on success, undef otherwise. It's a convenience method that makes possible the usage of the following constructs, iykyk:
$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 it's the same as alive() == 1, except that can_event() fails if an invalid object reference is passed. π
clear_event
Clears the event state, which gets 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 you're signalling that further processing should be stopped β f ex on MouseDown doing something else than the base widget. π±οΈ
See more in "Execution control". And 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. Beep beep, bestie. π
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 the 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 returns 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.
See "Events" and "Flow" for details.
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 notification_types(). π£
notify() accepts a variable number of parameters, and while it is possible, it is not recommended to call notify() with an excessive number of parameters. The call with a deficient number of parameters results in an exception. π
Example:
$obj-> notify( "PostMessage", 0, 1);
See "Events" and "Flow" for details.
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 that "PostMessage" will be called, however. Just so you know. π
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, 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 it's the key point in enabling the following syntax, bestie:
$obj-> onPostMessage( sub { ... });
or
$obj-> set( onPostMessage => sub { ... });
which are shortcuts for
$obj-> add_notification( "PostMessage", sub { ... });
Ate. π
unlink_notifier REFERRER
Removes all notification subs from all event lists bound to the REFERRER object. Clean slate, no cap. β¨
π Prima::Component properties π
deepChildLookup BOOL
If set, the lookup by name uses a breadth-first deep lookup into the object hierarchy. If unset (which is the 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's present in the $owner namespace. πΈ
In the get-context it 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, like this:
$obj-> name( "Obj");
$obj-> owner( $owner);
...
$owner-> Obj-> destroy;
Trust, it just hits different when your names are clean. π¦
...and to prevent all those system-dependent headaches π« . Like, if your system lets you predefine object parameters by name (or by class), then bestie, there is literally no way to know the system's naming restrictions beforehand. Case in point: over in the X11 window system, this resource string right here would make every single Prima toolkit button green π:
Prima*Button*backColor: green
So if you go putting special characters like ":" or "*" in an object's name, you'd make that X11 resource unusable. Don't do that to yourself π.
ownerOBJECT β sets the owner of the object, which can be aPrima::Componentdescendant. Setting an owner does not change its reference count, k? Some classes are fine with OBJECT beingundef, and some are absolutely not. Rules of the land:- All widget objects cannot exist without a valid owner π
Prima::Application, on the flip side, can only exist with the owner set toundefPrima::Imageobjects are just like "whatever" β totally indifferent to the owner property π¦
Now, changing the owner dynamically? Allowed, sure, but it's lowkey a main source of implementation bugs, because the whole hierarchy tree has to be recreated π. You won't see that effect in perl, but the results are deeply system-dependent, and any code that changes the owner property should be thoroughly tested. Not me warning you twice, but like, warning you twice π«Ά.
Changes to "owner" fire up to three notifications:
"ChangeOwner"β called on the object itself"ChildLeave"β tells the previous owner the object is about to dip"ChildEnter"β tells the new owner they've got a new child π
β¨ Prima::Component events β¨
ChangeOwnerOLD_OWNER β called when the object changes its owner. It's giving "new management" energy π .ChildEnterCHILD β triggered when a child object gets attached, either as a brand-new instance or because of a runtime owner change. Welcome to the family π.ChildLeaveCHILD β triggered when a child object is detached, either because it's getting destroyed or because of a runtime owner change. Sad girl hours π.Createβ the very first event the object sees. Called automatically afterinit()finishes. Is never called directly, periodt.Destroyβ the last event the object sees. Called automatically beforedone()starts. Also never called directly. Main character's final scene π.PostMessageSCALAR1, SCALAR2 β called after thepost_message()call is issued β but not insidepost_message(), nope. It fires after the next idle event loop π. SCALAR1 and SCALAR2 are the data you passed topost_message(). Slay, async queen β¨.SysHandleβ okay so sometimes Prima needs to implicitly re-create the system handle of a component. This re-creation usually happens deep inside the Prima core, but if widgets on the screen get re-created, they might get repainted π¨. This happens when the underlying system either doesn't have an API to change a certain property at runtime, or when such a re-creation happens on one of the component's parents β which leads to a whole downward cascade of children being re-created π. It can also happen when the user changes some system settings, like resolution, so some resources have to change accordingly.
You'll only actually need this event when the system handle (the one you can grab with get_handle) gets used further, or in the case where Prima doesn't restore some properties bound to the system handle. iykyk π
π AUTHOR π
Dmitry Karasik, <dmitry@karasik.eu.org> π.
πΈ SEE ALSO πΈ
Prima, Prima::internals, Prima::EventHook. Go read them, bestie, they're iconic π«Ά.
That's the whole page, babe! π This little masterpiece is from pod::Prima::Object(3) β perl v5.42.0, dated 2024-08-20. Go forth and build something gorgeous with it β¨ππ¦
π¦ where this page comes from
- opensuse-leap 16.0: perl-Prima 1.74000-bp160.1.13 Β· AGPL-3.0-only AND BSD-2-Clause
- opensuse-leap 16.0: perl-Prima 1.74000-bp160.1.13 Β· AGPL-3.0-only AND BSD-2-Clause
- opensuse-leap 16.0: perl-Prima 1.74000-bp160.1.13 Β· AGPL-3.0-only AND BSD-2-Clause
- opensuse-leap 16.0: perl-Prima 1.74000-bp160.1.13 Β· AGPL-3.0-only AND BSD-2-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms