Prima::faq - Frequently asked questions about Prima
The FAQ covers various topics around Prima, such as distribution, compilation, installation, and programming.
Prima is a general-purpose extensible graphical user interface toolkit with a rich set of standard widgets and an emphasis on 2D image processing tasks. A Perl program using Prima looks and behaves identically in the X11 and Windows environments.
A Yet Another Perl GUI.
Prima was started on OS/2, where Tk didn't run. We have had two options - either port Tk, or write something on our own, probably better than the existing tools. We believe that we've succeeded.
However, Prima's support for OS/2 was removed because no one needed that in 2012.
Why not? Perl is great. The high-level GUI logic fits badly into C, C++, or the like, so a scripting language is probably the way to go here.
Unless your language has runtime binding with perl, you cannot.
Dmitry Karasik implemented the majority of the toolkit, after the original idea by Anton Berezin. Many contributors helped the development of the toolkit since then.
The copyright is a modified BSD license, where only two first paragraphs remain out of the original four. The text of copyright is present in almost all files of the toolkit.
You can do this in several ways. The project would probably best benefit from the advocacy because not many people use it. Of course, you can send in new widgets, patches, suggestions, or even donations. Also, documentation is the topic that needs particular attention, since my native language is not English, so if there are volunteers for polishing the Prima docs, you are very welcome.
http://www.prima.eu.org contains links to source and binary download resources, and some other useful info.
Depends on where you are and what are your goals. On unix, the best is to use the source. On win32 the binaries based on Strawberry Perl distribution are preferred. If you happen to use cygwin you are probably still better off using the source.
First, check if you downloaded the Prima binary for the correct version of Perl, that should be enough.
To install, unpack the archive and type 'perl ms_install.pl'. The files will be copied into the perl tree.
Type the following:
perl Makefile.PL make make install
If the 'perl Makefile.PL' fails with errors, you can check makefile.log to see if anything is wrong. A typical situation here is that Makefile.PL might report that it cannot find the Perl library, for example, where the real problem is that it invokes the compiler in the wrong way.
Note, that to get Prima working from sources, your system must contain graphic libraries, such as libgif or ligjpeg, for Prima to load graphic files.
To load and save images, Prima uses graphic libraries. Such as, to load GIF files, the libgif library is used, etc. Makefile.PL finds available libraries and links Prima against these. It is possible to compile Prima without any, but this is not useful.
On every supported platform Prima can make use of the following graphic libraries:
libXpm - Xpm pixmaps libjpeg - JPEG images libgif - GIF images libpng - PNG images libtiff - tiff images libwebp,libwebpdemux,libwebpmux - WebP images libheif - Heif images
Strawberry perl and Cygwin come with most of them, so on these installations Prima just compiles without any trouble. For other perl builds, use one of the Prima::codecs:: modules that contain the needed include and lib files. If you are installing Prima with CPAN, that gets done automatically.
Prima::codecs::
img/codec_XXX.c files are C sources for support of the graphic libraries. In case a particular codec does not compile, the ultimate fix is to remove the file and re-run Makefile.PL . This way the problem can be avoided easily, although at the cost of a lack of support for that graphic format.
img/codec_XXX.c
perl -MPrima::noX11 -MPrima -e 'print map { $_->{name}.qq(\n) } @{Prima::Image->codecs};'
The library is probably located in such a location Makefile.PL must be told about by adding LIBPATH+=/mypath/lib, and possibly INCPATH+=/mypath/include in the command line. Check makefile.log created by Makefile.PL for the actual errors reported when it tries to use the library.
There are various reasons why a compilation may fail. The best would be to copy the output together with outputs of env and perl -V and send these to the author, or better, open a GitHub issue here https://github.com/dk/Prima/issues.
Again, there are reasons for Prima to fail.
First, check whether all main files are installed correctly. Prima.pm must be in your perl directory, and the Prima library file ( Prima.a or Prima.so for unix, Prima.dll for win32 ) is copied in the correct location in the perl tree.
Second, try to run 'perl -MPrima -e 1' . If Prima.pm is not found, the error message would be something like
Can't locate Prima.pm in @INC
If the Prima library or one of the libraries it depends on cannot be found, perl Dynaloader would complain. On win32 this usually happens when some dll files Prima needs are not found. If this is the case, try to copy these files into your PATH, for example in C:/Windows .
ActiveState doesn't seem to support anymore compilation of locally built libraries and doesn't provide precompiled Prima distributions either. Consider using Strawberry or msys2 builds instead.
This error happens when you are running under the X11 environment and no connection to the X11 display can be established. Check your DISPLAY environment variable, or use the --display command line parameter. If you do not want Prima to connect to the display, for example, to use it inside of a CGI script, either use the --no-x11 parameter or include the use Prima::noX11 statement in your program.
use Prima::noX11
Check whether you have Xft and fontconfig installed. Prima benefits greatly from having been compiled with Xft/fontconfig. Read more in Prima::X11 .
Prima documentation comes in .pm and .pod files. These, when installed, are copied under the perl tree, and the man tree in unix. So, 'perldoc Prima' should be sufficient to invoke the main page of the Prima documentation. Other pages can be invoked as 'perldoc Prima::Buttons', say, or, for the graphical pod reader, 'podview Prima::Buttons'. podview is the Prima doc viewer, which is also capable of displaying any POD page.
There is also the pdf file on the Prima website http://prima.eu.org/ that contains the same set of documentation but composed as a single book. Its sources are in the utils/makedoc directory, are somewhat rudimentary, and require an installation of latex and dvips to produce one of the tex, dvi, ps, or pdf targets.
It does if you 1) compile Prima with cocoa and 2) allow the application (XQuartz and probably terminal) to access the screen. To do the latter, Choose the Apple menu, System Preferences, click Security & Privacy, then click Privacy. Click on an icon on the left lower corner to allow changes. Then, in the screen recording tab, add XQuartz to the list of allowed applications. Note that it might not work if you run your application from a (remote) ssh session - I couldn't find how to enable screen grabbing for sshd.
https://github.com/dk/Prima/issues is the place.
podview Prima::VB::VBLoader
use Prima::noX11; # this prevents Prima from connecting to the X11 display use Prima; my $i = Prima::Image-> load( ... )
Note that drawing on images will be somewhat limited.
$widget-> set( property1 => $value1, property2 => $value2, ... );
If the feature is not managed by none of the Prima::Edit properties, you need to overload ::on_paint. It is not as hard as you might think.
Prima::Edit
::on_paint
If the feature is generic enough, you can send a GitHub pull request.
Well, I'd probably love to see the feature in Prima as well, but I don't have time to write it myself. Send in a patch, and I promise I'll check it out.
This would most certainly happen when you rely on your screen properties. There are several ways to avoid this problem.
First, if one programs a window where there are many widgets independent of each other size, one actually can supply coordinates for these widgets as they are positioned on a screen. Don't forget to set the designScale property of the parent window, which contains the dimensions of the font used to design the window. One can get these by executing
designScale
perl -MPrima -MPrima::Application -le '$_=$::application->font; print $_->width, q( ), $_->height';
This way, the window and the widgets would get resized automatically under another font.
Second, in case the widget layout is not that independent, one can position the widgets relatively to each other by explicitly calculating widget extension. For example, an InputLine would have a height relative to the font, and to have a widget placed exactly say 2 pixels above the input line, code something like
InputLine
my $input = $owner-> insert( InputLine, ... ); my $widget = $owner-> insert( Widget, bottom => $input-> top + 2 );
Of course, one can change the font as well, but it is a bad idea since users would get annoyed by this.
Third, one can use geometry managers, similar to the ones in Tk. See Prima::Widget::pack and Prima::Widget::place.
Finally, check the widget layouts with Prima::Stress written specifically for this purpose:
perl -MPrima::Stress myprogram
There are lots and lots of examples of this. Find a widget class similar to what you are about to write, and follow the idea. There are, though, some non-evident moments worth enumerating.
Test your widget class with different default settings, such as colors, fonts, parent sizes, and widget properties such as buffered and visible.
buffered
visible
Try to avoid special properties for new, where for example a particular property must always be supplied, or never supplied, or a particular combination of properties is expected. See if the DWIM principle can be applied instead.
new
Do not be afraid to define and redefine notification types. These have a large number of options, to be programmed once and then used as DWIM helpers. Consider for what notifications the user callback routines ( onXxxx ) would be best to be called first, or last, and whether a notification should allow multiple callbacks or only one.
If there is a functionality better off performed by the user-level code, consider creating an individual notification for this purpose.
Repaint only the changed areas, not the whole widget.
If your widget has scrollable areas, use the scroll method.
scroll
Inside on_paint check whether the whole or only a part of the widget is about to be repainted. Simple optimizations here increase the speed.
on_paint
Avoid using pre-cooked data in on_paint, such as when for example only a particular part of a widget was invalidated, and this fact is stored in an internal variable. This is because when the actual on_paint call is executed, the invalid area may be larger than was invalidated by the class actions. If you must though, compare values of the clipRect property to see whether the invalid area is indeed the same as it is expected.
clipRect
Remember, that inside on_paint all coordinates are inclusive-inclusive, while the widget coordinates generally are inclusive-exclusive.
Note, that the buffered property does not guarantee that the widget output would be buffered. The same goes with antialias and layered; these functions are opportunistic. Use the is_surface_buffered, can_draw_alpha, and is_surface_layered functions to make sure that these requests were respected.
antialias
layered
is_surface_buffered
can_draw_alpha
is_surface_layered
Write some documentation and examples of use.
Check Prima/VB/examples/Widgety.pm . This file, if loaded through the 'Add widget' command in VB, adds the example widget class and example VB property into the VB palette and Object Inspector.
Prima by default is unicode-aware, in some areas more than the Perl (as of 5.38) itself.
For example, on win32 Perl has huge problems with filenames with unicode characters, and this is recommended to mitigate using Prima::sys::FS, which overrides open, opendir and the like builtin functions with their unicode-friendly versions. It doesn't though overload -f and -e syntax, so use _f,_e etc instead.
open
opendir
-f
-e
_f
_e
Displaying UTF8 text is unproblematic because Perl scalars can be unambiguously told whether the text they contain is in UTF8 or not. The text that comes from the user input, ie keyboard and clipboard, can be treated and reported to Prima either as UTF8 or plain text, depending on the Prima::Application::wantUnicodeInput property, which is set to 1 by default. Remember though that if data are to be put through file I/O, the 'utf8' IO layer must be selected ( see open ).
Prima::Application::wantUnicodeInput
'utf8'
The keyboard input is also easy because a character key event comes with the character code, not the character itself, and conversion between these is done via standard perl's chr and ord.
chr
ord
The clipboard input is more complicated because the clipboard may contain both UTF8 and plain text data at once, and it must be decided by the programmer explicitly which one is desired. See more in "Unicode" in Prima::Clipboard.
$::application-> open_help( "file://$0" ); $::application-> open_help( "file://$0|DESCRIPTION" ); $::application-> open_help( 'My::Package/BUGS' );
Prima doesn't work if called from more than one thread, since Perl scalars cannot be shared between threads automatically, but only if explicitly told, by using thread::shared. Prima does work in multithread environments though, but only given it runs within a dedicated thread. It is important not to call Prima methods from any other thread because scalars that may be created inside these calls will be unavailable to the Prima core, which would result in strange errors.
It is possible to run things in parallel by calling the event processing by hand: instead of entering the main loop with
run Prima;
one can write
while ( $::application-> yield) { ... do some calculations .. }
That'll give Prima a chance to handle accumulated events, but that technique is only viable if calculations can be quantized into relatively short time frames.
The generic solution would be harder to implement and debug, but it scales well. The idea is to fork a process, then communicate with it via its stdin and/or stdout ( see perlipc how to do that), and use Prima::File to asynchronously read data passed through a pipe or a socket.
Note: the Win32 runtime library does not support asynchronous pipes, only asynchronous sockets. Cygwin does support both asynchronous pipes and sockets.
Prima::sys::AnyEvent can be used to organize event loops driven by Prima with AnyEvent support:
use Prima qw(sys::AnyEvent); use AnyEvent; my $ev = AnyEvent->timer(after => 1, cb => sub { print "waited 1 second!\n" }); run Prima;
this is the preferred, but not the only solution.
If you need AnyEvent to drive the event loop, you can fire up the Prima yield() call once in a while:
my $timer = AnyEvent->timer(after => 0, interval => 1/20, cb => sub { $::application->yield; });
If you want to use Prima's internal event loop system you have to install POE::Loop::Prima and include it in your code before Prima is loaded like below: use POE 'Loop::Prima'; use Prima qw/Application/; use AnyEvent;
You can call AnyEvent::detect to check if the implementation is 'AnyEvent::Impl::POE' if you want to use Prima's event loop or if it should be the event loop implementation you expect such as 'AnyEvent::Impl::EV';
AnyEvent::detect
'AnyEvent::Impl::POE'
'AnyEvent::Impl::EV'
If you use POE::Loop::Prima then you can continue to call run Prima and should not call AnyEvent's condition variable recv function.
run Prima
recv
If you want to use another event library implementation of AnyEvent, you have to not call run Prima but instead call AnyEvent's condition variable recv function.
See full examples in examples/socket_anyevent1.pl, examples/socket_anyevent2.pl, and examples/socket_anyevent_poe.pl.
The Prima::Component::post_message method posts a message through the system event dispatcher and returns immediately; when the message arrives, the onPostMessage notification is triggered:
Prima::Component::post_message
onPostMessage
use Prima qw(Application); my $w = Prima::MainWindow-> create( onPostMessage => sub { shift; print "@_\n" }); $w-> post_message(1,2); print "3 4 "; run Prima; output: 3 4 1 2
This technique is fine when all calls to the post_message on the object are controlled. To multiplex callbacks one can use one of the two scalars passed to post_message as callback identification. This is done by "post" in Prima::Utils, which internally intercepts $::application's PostMessage and provides the procedural interface to the same function:
post_message
$::application
PostMessage
use Prima qw(Application); use Prima::Utils qw(post); post( sub { print "@_\n" }, 'a'); print "b"; run Prima; output: ba
The tabbed notebooks work as parent widgets for Prima::Notebook, which doesn't have any interface elements on its own and provides only a page-flipping function. The sub-widgets, therefore, are to be addressed as $TabbedNotebook-> Notebook-> MyButton.
Prima::Notebook
$TabbedNotebook-> Notebook-> MyButton
Take a look at Prima::IPA, Prima::OpenGL, Prima::Image::Magick, PDL::PrimaImage, and PDL::Drawing::Prima . These modules compile against the Prima dynamic module and start from there. Note - it's important to include PRIMA_VERSION_BOOTCHECK in the "BOOT:" section, to avoid binary incompatibilities if there should be any.
You'll need some files that PAR cannot detect automatically. During the compilation phase Makefile.PL creates the utils/par.txt file that contains these files. Include them with this command:
pp -A utils/par.txt -o a.out my_program
Dmitry Karasik, <dmitry@karasik.eu.org>.
Prima
To install Prima, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Prima
CPAN shell
perl -MCPAN -e shell install Prima
For more information on module installation, please visit the detailed CPAN module installation guide.