Beruflich Dokumente
Kultur Dokumente
May 2011
August 2011
Prism v3.4.x
Copyright 2010-2011
Copyright 2011
Copyright 2010-2011
info@bwembedded.com
No part of the document may be reproduced in any form without the express written
consent of Blue Water Embedded, Inc
Prism, Prism Micro, Prism Insight, Prism Micro Insight, and Prism Runtime Framework
are trademarks of Blue Water Embedded, Inc.
Revision History
Date Revision Change By
8/17/2011 7 Event Recorder/Playback, Panel Push/Pop Stack Reset JC
8/3/2011 6 Improved macro functionality detailed RN
6/13/2011 5 Chapter 10 added KM
5/30/2011 4 Modernized Look&Feel for Insight added JC
5/11/2011 3 Graphics Data Pipeline and diagrams added. KM
3/25/2011 2 Event table update KM
11/18/2010 1 TOC added JC
7/16/2010 Initial Release
Table of Contents
Developers Guide ....................................................................................................... 1
Revision History ........................................................................................................... 3
FORWARD .................................................................................................................. 7
The Prism Documentation Set ..................................................................................... 8
What exactly is Prism, and why is it written using C++? .............................................. 9
Why C++? .................................................................................................................. 10
1 GETTING STARTED ............................................................................................. 11
1.1 Installing and Building the Prism Runtime Framework ..................................... 11
1.1.1 Installing Prism .......................................................................................... 11
1.1.2 Building the Prism Runtime Framework..................................................... 11
1.2 Prism File Description ...................................................................................... 12
1.3 Memory Footprint ............................................................................................. 21
1.4 Paint Engines ................................................................................................... 21
1.5 Additional Drivers ............................................................................................. 24
1.6 Pre-configured Make/Project files .................................................................... 24
2 DEFINITIONS ........................................................................................................ 25
2.1 Terms and Data Types..................................................................................... 25
2.2 Panels and Widgets and Utility classes............................................................ 25
2.3 Parent Child Sibling .................................................................................... 25
2.4 Fundamental Data Types ................................................................................. 26
2.5 Naming Conventions ........................................................................................ 27
2.6 pm_bitmap_t .................................................................................................... 28
2.7 Pm_Brush ........................................................................................................ 28
2.8 pm_canvas_t .................................................................................................... 31
2.9 pm_event_t ...................................................................................................... 32
2.10 pm_font_t ...................................................................................................... 33
2.11 pm_point_t .................................................................................................... 34
2.12 Pm_Region ................................................................................................... 35
2.13 Pm_Snapshot ............................................................................................... 37
3 THE EXECUTION MODEL .................................................................................... 39
3.1 Runtime Execution Model ................................................................................ 39
3.2 Framework Overview ....................................................................................... 39
FORWARD
The personnel at Blue Water Embedded thank you for choosing the Prism family of
embedded graphical interface development tools. We believe Prism is the most robust,
best supported, and easiest to use graphical interface software package available today
at any cost.
The developers at Blue Water Embedded have been working in the embedded graphics
industry for nearly 14 years, and have worked on thousands of applications and unique
products. We have been involved in developing consumer electronics, office
equipment, desktop applications, military devices, and medical instrumentation to name
a few of the types of projects in which we have participated.
The engineering staff at Blue Water Embedded wants your project to be successful, and
we sincerely want to assist you in accomplishing this goal. Never hesitate to ask us
questions or make suggestions which will help us to improve our software.
Blue Water Embedded also welcomes the opportunity to assist in your product
development at any level. We can provide training, porting and customization services,
or complete turnkey application development. Contact our sales department if you
would like to learn more about any of these services.
For urgent matters, you can always call us directly at (810) 987-3002 and ask for
technical support. The Prism Runtime Framework and Prism Insight support personnel
are the same software engineers who developed the software, so we are confident you
will get timely and accurate answers to your questions!
The Prism Evaluation Kit- This document is a brief introduction to Prism which shows
you how to launch the Prism Insight application, run sample example applications, and
how to generate a UI application on your desktop.
The Prism Runtime Framework Developers Guide (this manual) - This is a detailed
description of the Prism Runtime Framework; what is does, how it does it, and what you
need to know to use the software to your best advantage.
The Prism Runtime Framework API Reference Manual- This manual documents every
class and public function of the Prism Runtime Framework. This manual will be very
helpful when you begin using the Prism API directly in your application software.
The Prism Insight Users Guide- This manual documents how to use the Prism Insight
application to change your framework settings, create UI screen designs, manage and
edit strings, and generate system resource files among a host of other capabilities.
All of these manuals are provided in electronic (PDF) formats. Prism is living software
product, and as such is constantly being enhanced, updated, improved, and revised.
These revisions include updates to the manuals and related documentation. For this
reason your manuals may not always match with 100% accuracy the contents and
function of the Prism Runtime Framework. We try to keep these discrepancies to a
minimum and insure no large modification to the framework is released without a
matching update to the documentation set.
All users of the Prism software are allowed to update their electronic documentation set
as often as desired. The latest PDF manuals are always available for download at the
following URL:
http://www.bwembedded.com/SecureManual/prismman.php
Contact us to get the latest username and password to download the manuals.
This is the Prism software library, which implements a very stable runtime environment
for managing your user interface application, and provides a complete customizable
widget set you can use and build on to provide the UI input and output elements needed
by your product user.
These are the design and prototyping desktop applications which can be run in nearly
any Windows or Linux/X11 desktop. Prism Insight was designed and written to make it
very easy to create the screens or panels which will comprise your user interface. You
can visually design and layout your screens, and Prism Insight tool generates the
required source code and data structures (in normal, human readable form!) that are
required to actually implement your UI design on your target system.
The Blue Water Embedded, Inc. team is dedicated to providing best in class technical
support to our customers. Your product's success is our success. With a license
purchase, 90 days of technical support is included from the date you purchase and
receive (usually via ftp download links) the software. With valid support contracts,
technical support includes phone support during normal business hours, email support
and software updates.
Blue Water Embedded offers a two-day Prism training class which can be held at our
facility or yours. Many times we find prospects have a basic understanding of what a
GUI entails. Blue Water Embedded has developed a program to help you apply Prism
Insight and the Prism library and maximize the benefits of the software. Contact a sales
team member to learn more and schedule a training class today.
Why C++?
Prism is written in C++ because the authors believe this is a natural language for
implementing a UI framework and widget set. We do not use some of the more
advanced features of C++ such as Exceptions, Templates, or Runtime Type
Identification. We use C with Classes, which in the end means if you are a proficient
C programmer you will have absolutely no problem using the Prism Runtime Framework
effectively.
One advantage of using the C++ language is there are fewer API function names for
you to learn. We use the same function name to accomplish common tasks such as
assigning colors or fonts for every Prism class. This reduces the learning curve and
helps you become proficient with the framework API very quickly. This manual will
explain everything you need to know to use Prism effectively, whether you are primarily
a C language developer or if you have several years experience with C++, C#, or other
languages.
A common concern among developers of safety critical devices is the C++ memory
allocation operator new and potential heap fragmentation. Prism utilizes several
strategies to overcome this concern, including providing its own operating specific
versions of the new and delete operators, and strategies to completely eliminate post-
boot heap allocations are also supported. Whatever your requirements, Prism is
designed to function correctly in high level of concern devices.
1 GETTING STARTED
1.1 Installing and Building the Prism Runtime Framework
Your distribution may contain specific instructions regarding the folder into which Prism
should be installed. This matters only for specific RTOS integrations, to insure the
provided make/project files can correctly locate the RTOS specific header files.
Your Prism distribution normally includes makefiles or project files specific to your
designated toolchain. We support a wide variety of toolchains and build environments,
so if you do not find a project file for your specific tools please notify Blue Water
Embedded.
When the library is configured, it includes a header file prism_settings.h. The header
file is found in prism\include\prism_settings.h and is automatically generated by Prism
Insight and should not be modified manually. To change your prism_settings.h file, you
should run the Prism Insight application and run through the various settings screens to
turn on and off the options your target requires, then use the Generate Prism Settings
command to update your prism_settings.h header file.
Depending on your desktop environment preference, when you first install the Prism
software, the prism_settings.h header file is configured to build the Prism library for
either the Win32 or X11. Whenever possible, this file is also pre-configured for your
target RTOS and hardware. You can reconfigure the library at any time to build for your
intended target. It is important to remember whenever you update your
prism_settings.h header file; you need to re-build the Prism library in addition to your
application files.
The Prism source files are located in the \prism\source folder and sub-folders, and the
matching Prism header files are located in the \prism\include folder and sub-folders.
The sub-folders contain drivers and operating system integration files specific to various
hardware platforms and operating systems. Your installation package includes only
those drivers and operating system integration files required for your specified target.
The build directory contains project and makefiles for your compiler and operating
system, along with project files for building the Panels and/or X11 desktop simulation
environments.
The fonts directory contains free TrueType fonts you can use as part of your
application.
The include directory contains your Prism header files. The root \include directory
contains all of the header files of the core Prism Runtime Framework. The sub-
directories within this folder contain header files for specific graphics hardware drivers,
keyboard drivers, mouse drivers, and touch drivers. The specific set of drivers included
in your distribution will vary depending on your selected target hardware.
The rtos sub-directory contains header files specific to your Prism/RTOS combination.
Prism implements a thin abstraction layer to isolate RTOS requirements from the core
library files.
The Insight directory contains the Prism Insight application and related example project
files.
The source directory contains the Prism core library files and related drivers. The
\source directory structure is a mirror of the \include directory structure.
The core Framework source and header files, in alphabetical order, include:
prism_anim_prompt.cpp / .h
These files declare the Pm_Animated_Prompt widget class and define the matching
implementation.
prism_big5_map.cpp / .h
These optional files declare the Chinese Big 5 character encoding to Unicode mapping
tables.
prism_bitmap_prompt.cpp / .h
These files declare the Pm_Bmp_Prompt widget class and define the matching
implementation.
prism_bmp_btn.cpp / .h
These files declare the Pm_Bmp_Btn widget class and define the matching
implementation.
prism_bmp_dec_btn.cpp / .h
These files declare the Pm_Bmp_Decorated_Btn widget class and define the matching
implementation.
prism_bmp_rotate.cpp / .h
These files define the Pm_Bitmap_Rotator class used for runtime rotation of bitmaps
and text.
prism_brush.cpp / .h
These files define the Pm_Brush class, which is used for most painting operations.
prism_button.cpp / .h
These files define the base Pm_Btn class, which is a base class for most other button
widget types.
prism_dec_panel.cpp / .h
These files define the Pm_Decorated_Panel class, which is a panel class supporting
several pre-defined decorations such as Pm_Title_Bar and Pm_Status_Bar.
prism_drop_box.cpp / .h
These files declare the optional Pm_Drop_Box widget class and define the matching
implementation.
prism_event_mgr.cpp / .h
These files declare the Pm_Event_Manager framework class and define the matching
implementation.
prism_exclusive_btn.cpp / .h
These files declare the Pm_Exclusive_Btn widget class and define the matching
implementation.
prism_file_wrapper.cpp /.h
These files declare the optional Pm_File class and define the matching implementation.
Pm_File is a filesystem abstraction class implemented within Prism to insure operating
system portability related to filesystem APIs.
prism_framework.cpp / .h
These files declare and implement the Pm_Framework class, which is a class for
organizing and granting access to the Prism Runtime Framework components.
prism_graphic_reader.cpp / .h
These files declare the optional Pm_Graphic_Reader base class, which defines the
APIs for runtime decode and conversion of various graphics file types.
prism_group.cpp / .h
These files declare the Pm_Group widget class and define the matching
implementation. Pm_Group is a simple container class used to visually and logically
group collections of child widgets.
prism_help_btn.cpp / .h
These files declare the Pm_Help_Btn widget class and define the matching
implementation.
prism_icon.cpp / .h
These files declare the Pm_Icon widget class and define the matching implementation.
The Pm_Icon class is a simple graphic display widget.
prism_icon_btn.cpp / .h
These files declare the Pm_Icon_Btn widget class and define the matching
implementation.
prism_input_device.cpp / .h
These files declare the common API used for all Prism input device drivers and define
generic implementations for common functions.
prism_jpg_reader.cpp / .h
These optional files declare and implement the Pm_Jpg_Reader class, which is used
for runtime decode and conversion of JPG format graphic files.
prism_list.cpp /.h
These files declare the Pm_List, Pm_Vert_List, and Pm_Horz_List panel types and the
matching implementations.
prism_math.cpp /.h
These files declare various utilities functions for Sin, Cos, Min, Max, and related
functions.
prism_menu.cpp / .h
These optional files declare the Pm_Menu panel, Pm_Menu_Bar widget, and
Pm_Menu_Btn widget classes and their matching implementations.
prism_ml_popup.cpp / .h
These files declare the Pm_ML_Popup_Panel panel class and define the matching
implementation.
prism_ml_prompt.cpp / .h
These files declare the Pm_ML_Prompt widget class and define the matching
implementation.
prism_ml_text_btn.cpp / .h
These files declare the PM_ML_Text_Btn widget class and define the matching
implementation.
prism_ml_text_input.cpp / .h
These files declare the Pm_ML_Text_Input widget class and define the matching
implementation.
prism_paint_engine.cpp / .h
These files declare the base Pm_Paint_Engine paint class and define the matching
implementation. Pm_Paint_Engine defines the painting API used by all widgets and
panels and the application level software. Pm_Paint_Engine provides the entry point for
all primitive painting functions, and performs required checks and validation of input
prism_paint_gradient.cpp / .h
These optional files declare the Pm_Gradient class and define the matching
implementation. Pm_Gradient painting engine, which is used to dynamically create
gradient fills for various widget and panel types.
prism_panel.cpp / .h
These files declare the Pm_Panel panel class and define the matching implementation.
prism_password.cpp / .h
These optional files declare the Pm_Password text input widget and define the
matching implementation.
prism_png_reader.cpp / .h
These optional files declare the Pm_Png_Reader class and its implementation. The
Pm_Png_Reader class is used for runtime decoding and conversion of PNG format
image files. This class is not required for correct operation of the framework.
prism_point.h
This file declares the pm_point_t data type and defines the matching implementation.
prism_popup.cpp / .h
These files declare the Pm_Popup_Panel panel class and define the matching
implementation.
prism_progress_bar.cpp / .h
These files declare the Pm_Progress_Bar widget class and define the matching
implementation.
prism_progress_panel.cpp / .h
These files declare the Pm_Progress_Panel panel class and define the matching
implementation.
prism_prompt.cpp / .h
These files declare the Pm_Prompt text display widget and define the matching
implementation.
prism_region.cpp / .h
These files declare the Pm_Region class and define the matching implementation.
prism_res_file.h
This optional file defines the format of a Prism binary resource file.
prism_resource_mgr.cpp / .h
These files declare the Pm_Resource_Manager framework class and define the
matching implementation.
prism_screen_mgr.cpp /.h
These files declare the Pm_Screen_Manager framework class and define the matching
implementation.
prism_scroll.cpp / .h
These optional files declare the Pm_Scroll, Pm_VScroll, and Pm_HScroll widget
classes and define the matching implementations.
prism_shadow_btn.cpp / .h
These files declare the Pm_Shadow_Btn widget class and define the matching
implementation.
prism_slider.cpp / .h
These files declare the Pm_Slider widget class and define the matching implementation.
prism_snapshot.cpp / .h
This file declares the Pm_Snapshot class and defines the matching implementation.
prism_spin_btn.cpp / .h
These files declare the Pm_Spin_Btn class and the matching implementation.
prism_sprite.cpp / .h
These files declare the Pm_Sprite class and related data structures and
implementation.
prism_startup.cpp
This file contains the Prism startup function named PrismAppStart. This function
creates each of the Prism Runtime Framework core components and prepares the
Prism runtime environment for use by the application.
prism_status.h
prism_status_bar.cpp / .h
These files declare the Pm_Status_Bar widget class and matching implementation.
prism_std_int.h
This file declares the Prism basic data types, including the C99 data types.
prism_string_lib.h
This file declares the Prism string handling functions for various character encoding
methods.
prism_tab_panel.cpp / .h
These optional files declare the Pm_Tab_Panel panel class and matching
implementation.
prism_text_input.cpp / .h
These files declare the basic single-line text input widget and matching implementation.
prism_text_widget.cpp / .h
These files declare the base Pm_Text_Widget class and matching implementation.
prism_timer_mgr.cpp / .h
prism_title_bar.cpp / .h
These optional files declare the Pm_Title_Bar widget and matching implementation.
prism_tool_bar.cpp / .h
These optional files declare the Pm_Tool_Bar and Pm_Button_Group classes and their
corresponding implementation.
prism_tree_view.cpp / .h
These files declare the Pm_Tree_Node widget and Pm_Tree_View panel classes and
their implementations.
prism_txt_icon_btn.cpp / .h
These files declare the Pm_Text_Icon_Btn widget class and define the matching
implementation.
prism_virtual_list.cpp / .h
These files declare the Pm_Virtual_List panel class and define the matching
implementation.
prism_vprompt.cpp / .h
These files declare the Pm_VPrompt widget class and define the matching
implementation.
prism_widget.cpp / .h
These files declare the base Pm_Widget class, which is used as the base class for all
displaying widget and panel types.
prism_zip.cpp / .h
These files declare the Pm_Zip and Pm_Unzip utility functions and their matching
implementations.
The code size of the Prism framework changes based on which features and
components you choose to include. Also remember most linkers will not include
components that are not referenced.
Prism provides detailed configuration settings to allow you to trim features you are not
using. For example, if you do not need desktop style TitleBar widgets for your panels,
you can turn this feature off in the configuration settings. You can do the same for
many optional features, such as scroll bars, filesystem dependent components, and
runtime image decompression components.
When asked for a rule of thumb, we have observed linker map files that range from
40Kbytes for Prism Micro to nearly 200Kbytes for Prism with all features enabled using
the ARM mode (32 bit instruction set) build for an ARM9 processor. Similar code size
can be expected for other targets.
The ROM footprint of Prism Micro can be very low, less than 40 KBytes. We are
commonly running entire applications within the 256 KBytes internal flash of Cortex M3
devices. Of course you must sacrifice some capabilities to make the footprint small,
and Prism Micro allows you to remove features like scroll bars and other widgets with
ease.
As for RAM, Prism can run with a 4 KByte stack. The amount of heap required is always
a difficult question to answer because it depends heavily on the application
organization. A realistic minimum heap size might be 16 KBytes. If Prism is running on
a CPU with an external LCD driver and external graphics RAM, we can do all drawing
directly into that external graphics RAM. This is common for example with an external
controller made by companies like ILITEK or Solomon Systech, where the graphics
RAM is actually incorporated within the LCD display. The performance and capabilities
are not as good with this type of system, but the RAM requirements are minimal.
In addition to the core framework source files listed above, you will need to include a
Prism Paint Engine specific to your hardware in your framework build. We will discuss
the Paint Engine classes in much more detail in a later chapter, however to enable you
to build a working Prism library we need to introduce the files and class hierarchy here.
The Pm_Paint_Engine class serves as a base class for painting and related API
functions. Pm_Paint_Engine provides a thin layer of abstraction between the Prism
widgets and the underlying hardware, allowing Prism to be easily ported to new
hardware targets.
Derived from the Pm_Paint_Engine base are classes providing a common set of
functions supporting each color depth and color format. Derived from these color-
format-specific engines are actual hardware specific engines that are optimized to utilize
your target hardware to the fullest extent. The following diagram illustrates the C++
derivation or hierarchy of the paint engine classes for a general target:
Derived From
Derived From
Physical Display
Your Prism distribution includes at a minimum the desktop platform specific painting
engine and usually at least one additional engine specific to your hardware.
The base Pm_Paint_Engine source files are included the Prism core, and they always
need to be included in every build of the Prism Runtime Framework. This class is not
specific to your hardware or color depth. The files comprising the base
Pm_Paint_Engine class include:
The color-format specific derivations of the base painting class are contained in the
drivers\graphics sub-directory. You will need to include at least one of these mid-level
paint engines in your library build. Choose the filename that matches the color depth of
your target system. For example, if your target will run using 16-bpp (bit-per-pixel) color
format, choose the prism_pe_base_16bpp. If your target will run at 24-bpp, include the
prism_pe_base_24bpp.cpp file in your library build.
Finally, you will need to include the hardware-level driver specific to your target
platform. For the Panels simulation environment, the driver is named
prism_pe_panels_xxx where xxx is the desired color depth. For Linux/X11, the driver
is named prism_pe_x11_xxx where again xxx is the color depth of the desired
simulation environment.
The filename for your target hardware should be intuitive based on the CPU / graphics
controller name.
For example, to build the Prism Runtime Framework for 16-bpp color depth for the
Microsoft Windows desktop, you would include in your Prism build:
As a second example, to build the Prism Runtime Framework for 16-bpp color depth for
the Atmel AT91SAM9M10 target hardware, you would include in your Prism build:
Additional drivers are provided with Prism for keyboard/keypad and mouse. Drivers for
touch input devices are available for a nominal fee. The specific drivers provided will
vary depending on your selection of target hardware and operating system.
The \prism\build directory contains multiple project files and makefiles for building the
Prism Runtime Framework using a variety of tools, operating systems, and target
controllers. Your Prism distribution should include a makefile or project file for building
the Prism Runtime Frame for your desktop environment, and an additional build file to
be used for your target environment. Simply scan the \prism\build directory to find the
build files provided in your distribution.
2 DEFINITIONS
This chapter describes some terminology you will need to learn in order to understand
the Prism Runtime Framework API and execution environment, and introduces the data
type names that are used to pass and return parameters within the Prism API.
It is sometimes convenient to divide the Prism classes into several groups: the Panel
classes, the Widget classes, the Managers, and the Utility classes.
Widgets are graphical objects like buttons and scroll bars. Widgets are derived at some
point from the Pm_Widget class. Widgets can paint themselves, can receive events,
and have common set of member functions and variables.
Panels are objects derived at some point from the Pm_Panel class. Panels are
generally used as background containers to which you might add other Panels and
widgets. Panels are also derived from the Pm_Widget class, and therefore panels can
also paint themselves and receive events. Panels are a superset of the Pm_Widget
members and functions.
The Managers are overseers of the executing UI application. The mangers include the
Pm_Event_Manager and Pm_Resource_Manager, among others. The managers are
what compose the Framework portion of the Prism Runtime Framework. They are not
visible (with the exception of the Pm_Screen_Manager), but they are essential to the
capabilities of the runtime environment.
Utility classes are neither panels nor widgets. Utility classes refer to classes such as the
runtime image readers, or the Pm_Brush class. These classes are not derived from
Pm_Widget and do not directly participate in the UI by painting themselves, however
they are still critically important to the final working system.
These terms refer to the relationship between the Panels and widgets which compose
your user interface implementation. The Prism API allows you to link one object to
Blue Water Embedded, Inc. Page 25
Developers Guide
another, after which the objects will operate together. For example, if you link a
Pm_Button widget to a Pm_Panel widget, the Pm_Panel is from that point referred to as
the Parent of the button. If the panel is moved, the button will automatically move with
it. If the Parent is scrolled, the button will scroll up or down or left or right within the
panel client area. The Panel is the parent object, and the button is the child object.
You can link any type of object to any other type of object, meaning that an object does
not have to be Panel to be a parent or a button to be a child. You could link a Panel to
become a child of a Button. Prism imposes no restrictions on what type of objects may
be used as parents or children, and imposes no limits on the nesting level of your parent
child child linkage. You can, at any time, unlink or link any object to any other.
If you link multiple buttons to a common parent panel, the buttons are said to be
siblings. Any set of objects which share a common parent are termed siblings.
An object can and often is both a parent and a child at the same time. For example,
you might create a background panel, and add to this panel several child panels, and
add to the child panels several other widgets. So the middle-level panels are children of
the background, but parents of the inner widgets. This is normal and very common in
Prism software development.
This section describes fundamental data types used in Prism. Prism uses simple 8, 16,
and 32 bit data storage types, and more complex types for passing information such as
color, position, bitmap and font data. Prism utilizes the C99 data types as the basis for
all other user-defined types, which will make the most basic types immediately
recognizable for those users who are familiar with the basic C99 defined data type
definitions.
Prism class names are always preceded with Pm_, and each word of the class name
is separated by an underscore. The first letter of each work is capitalized, as in
Pm_Screen_Manager, Pm_Widget, and Pm_Panel.
Prism structures and other user-defined types are always lowercase, with an
underscore between words, and followed by _t indicating this is a data type.
Examples are pm_point_t, pm_color_t, and pm_font_t.
Class member variables are always prefixed with lowercase m, as in mSize and
mFont. Pointer variable names are always prefixed with lowercase p as in pFont and
pData. Member pointers are prefixed with both m and p as in mpFont and mpData.
Variable names and API function names always use a capital letter for each word of the
variable name of function name. Examples of API function names are AssignFont(),
Link(), MoveFocusTo(), etc. Example member variable names include mpVScroll,
mpFont, mSize, etc.
There are a large number of style flags, event types, status flags, and various other
enumerations and definitions you will need to become familiar with when you begin
writing custom painting functions or creating your own derived widgets. We try to be
consistent and precise in our naming conventions to make this learning process as
short as possible.
The Prism style flags always begin with PM_. The style flags are enumerated in the
header file for the base class that defines them.
2.6 pm_bitmap_t
pm_bitmap_t is a structure that contains the information required by the Prism paint
engines to render a bitmap to the graphics buffer. The bitmap structure defines the data
format, color depth, compression type, bitmap size, and contains a pointer to the actual
bitmap data array.
Several variations within each color format for endian-ness and color channel order are
supported. Prism bitmaps may optionally be compressed and may have an alpha
channel.
pm_bitmap_t data structures are usually created by Prism Insight and saved in your
resource file(s); however, they can also be created dynamically by the runtime image
readers or by other means as well. When you use pm_bitmap_t data created by the
Prism Insight application, you will refer to those bitmaps using Bitmap IDs, which are
linked to pm_bitmap_t data structures by the Pm_Resource_Manager.
struct pm_bitmap_t
{
uint8_t *pStart;
uint32_t TransColor;
uint16_t Width;
uint16_t Height;
uint8_t BitsPix;
uint8_t Flags;
};
The Flags field contains color format modifiers recognized by the paint engine, and
indicated whether the bitmap uses compression. The BitsPix field indicates how many
bits of data are required to encode one pixel color. The Width and Height fields indicate
the image dimensions. The TransColor field is only used of the image does not include
an alpha channel but does encode transparency. The pStart field is a pointer to the
actual bitmap data.
2.7 Pm_Brush
class Pm_Brush
{
friend class Pm_Paint_Engine;
public:
Pm_Brush();
Pm_Brush(pm_color_t _LineColor,
pm_color_t _FillColor,
pm_int_t BStyle = PBS_NO_ALIAS,
pm_int_t _LineWidth = 1,
const pm_font_t *_pFont = NULL);
~Pm_Brush();
pm_bitmap_t *pBitmap;
const pm_font_t *pFont;
uint32_t Pattern;
pm_int_t Width;
pm_int_t Style;
pm_color_t LineColor;
pm_color_t FillColor;
};
A Pm_Brush is used to pass color and font data to the painting API functions. A
Pm_Brush contains the LineColor, FillColor, Pattern, Width, and Style for each paint
operation. The Pm_Brush class is defined as shown:
LineColor is the color used for paint the outline of rectangles, the line color for lines, and
the text foreground color for text..
FillColor is the color value used to fill rectangles, polygons, etc. The FillColor is only
used if the brush style includes PBS_SOLID_FILL.
Pattern is used only for painting pattern lines, and defines the LineColor/ FillColor
pattern to be used for painting a pattern line.
Width is the brush width. This defines the border width for any outlined object such as a
rectangle or circle.
PBS_NO_ALIAS
This flag is applied to line, circle, and all arc painting. This flag indicates that no ant-
aliasing should occur. This is faster than anti-aliasing but also produces a more jagged
painting appearance.
PBS_SOLID_FILL
This style flag indicates that the painted shape will be filled with the FillColor. In the
case of text, this style indicates that the text background will be filled rather than
transparent.
PBS_BMP_FILL
This style flag indicates that the painted shape will be filled with a user-supplied bitmap.
PBS_TRUE_ALIAS
This flag is applied to line, circle, and related arc painting and also to text painting. This
flag indicates that the painting should be anti-aliased to an unknown or varying
background color. This means that the painting engine will read the background color as
it paints each pixel and perform anti-aliasing with the actually background color value.
This is slower than no alias or simple alias, but produces the best looking results over a
varying background such as when painting over a background bitmap.
PBS_ROUNDED
This flag is applied only when painting wide lines. This flag indicates the line ends
should be capped with a round endpoint.
PBS_CENTER_LINE
This flag indicates when painting a wide line or wide outline, the outline should be
centered around the passed pixel coordinates. The alternative, if this flag is not set, is
the passed pixel coordinates define the outer edge of the wide line, and the outline is
painted inward.
PBS_PATTERN
This flag is applied only to line painting, and indicates the line should be painted in an
on-off pattern as defined by the Brush.Pattern parameter.
The Brush.pBitmap field allows the caller to pass a bitmap used for bitmap fill of the
painted shape.
2.8 pm_canvas_t
struct pm_canvas_t
{
pm_color_t **pScanPointers;
pm_portal_t *pPortal;
pm_bitmap_t *pMap;
Pm_Widget *pNotify;
pm_canvas_t *pNext;
pm_canvas_t *pPrev;
Pm_Region Invalid;
pm_int_t Id;
pm_int_t Alpha;
pm_uint_t Type;
pm_int_t PaintCount;
pm_int_t HardwareLayer;
pm_int_t PaintOffsetX;
pm_int_t PaintOffsetY;
pm_int_t DisplayOffsetX;
pm_int_t DisplayOffsetY;
};
Applications do not normally directly modify any of the pm_canvas_t data fields. These
fields are managed by Pm_Paint_Engine. Applications simply create canvases, open
canvases, paint on canvases, and close them. The Pm_Paint_Engine manages the
display of canvases and overlay of different canvas types on the background frame
buffer.
2.9 pm_event_t
pm_event_t is used to pass incoming event information to receiving widgets and panels.
The pm_event_t structure is shown (in reduced form) below:
struct pm_event_t
{
public:
pm_event_t();
pm_event_t(uint16_t Val) ;
pm_event_t(Pm_Widget *Target, uint16_t Val);
Pm_Widget *pSource;
Pm_Widget *pTarget;
uint16_t Type;
uint16_t Param;
union
{
void *pData;
Pm_Region Region;
pm_point_t Point;
int32_t Payload[2];
int32_t User_int32[2];
uint32_t User_uint32[2];
int16_t User_int16[4];
uint16_t User_uint16[4];
uint8_t User_uint8[8];
};
};
For events generated by Prism widgets, the pSource parameter always points to the
event originator. The Type field identifies the event type, which defines the event and
defines which of the data fields within the event, if any, are utilized.
2.10 pm_font_t
A pm_font_t is a data structure that provides the information required by the Prism pain
engine to render text to the graphics buffer. Prism fonts contain the information to
define the font character widths, baseline, and character range of each font. Prism
fonts can be linked together to support large fonts containing multiple code pages.
struct pm_font_t
{
uint8_t Type;
uint8_t Ascent;
uint8_t Descent;
uint8_t CharHeight;
uint8_t PreSpace;
uint8_t PostSpace;
uint8_t LineHeight;
uint16_t BytesPerLine;
uint16_t FirstChar;
uint16_t LastChar;
uint16_t *pOffsets;
pm_font_t *pNextPage;
uint8_t *pData;
};
The font Type indicates how the font data is encoded. This field is utilized by the
painting engine to properly paint the font characters. The font Ascent and Descent
indicate the Ascent and Descent of the font, in pixels, from the font baseline.
The CharHeight field indicates the total height of the font in pixels.
The PreSpace and PostSpace fields indicate the amount of whitespace to allow before
and after each line of text in a multi-line text widget.
The BytesPerLine, FirstChar, and LastChar fields are used to by the Pm_Paint_Engine
to properly locate the data for a particular character within the font data block.
The pOffsets and pData fields point to a character offset and character data tables,
respectively. The pNextPage is used for multi-page fonts, where a single font may have
multiple character pages.
2.11 pm_point_t
This is a simple x,y coordinate structure. In Prism, x, y position is always relative to the
top-left corner of the screen and the top-left pixel is always pixel address 0,0. Pixel y
values increase as you move from top to bottom on the display screen. This convention
is opposite of the standard Cartesian coordinate system, but is a common practice in
graphics programming.
struct pm_point_t
{
void Set(pm_int_t InX, pm_int_t InY)
{
x = (int16_t) InX;
y = (int16_t) InY;
}
int16_t x;
int16_t y;
};
2.12 Pm_Region
Prism uses rectangular screen areas to define an objects limits and which areas of the
screen the object painting will be clipped within. Its also very common when writing
custom Paint function to need to work with regions on the screen. For this reason the
Pm_Region class is defined to simply doing math and logical operations with screen
regions.
struct Pm_Region
{
void Set(pm_point_t UpperLeft, pm_point_t BottomRight)
{
Left = UpperLeft.x;
Top = UpperLeft.y;
Right = BottomRight.x;
Bottom = BottomRight.y;
}
int16_t Left;
int16_t Top;
int16_t Right;
int16_t Bottom;
};
2.13 Pm_Snapshot
The Pm_Snapshot structure is used internally by Prism when painting a mouse cursor
in software, without a dedicated hardware mouse support. In this case, Prism must
save the pixels in the area beneath the mouse position before drawing the mouse
bitmap. The saved area is then restored when the mouse cursor is moved and the
process repeats.
The Pm_Snapshot structure can also be used by application to copy and move
rectangular area of pixel about on the screen.
The Pm_Paint_Engine class also has optional functions to create a snapshot of any
screen area at runtime and save this snapshot as a MS Panels formatted bitmap image.
This capability can be useful for creating screen shots for automated testing or for
marketing materials.
class Pm_Snapshot
{
public:
Pm_Snapshot(void)
{
mRegion.Set(0, 0, 0, 0);
mBitmap.pData = 0;
mValid = FALSE;
mDataSize = 0;
}
~Pm_Snapshot()
{
if (mBitmap.pData)
{
delete mBitmap.pData;
}
}
void Reset(void);
void Shift(pm_int_t xShift, pm_int_t yShift)
{mRegion.Shift(xShift, yShift);}
private:
Pm_Region mRegion;
pm_bitmap_t mBitmap;
int32_t mDataSize;
pm_bool_t mValid;
};
This chapter provides an overview of the Prism runtime framework and describes how
the various high-level components interact to support and bring structure to your user
interface application. We will introduce the framework components at a high level view,
and the leave the details of each class implementation to the following chapters.
In the multitasking model, input drivers and any system task can directly interact with
Prism using the Prism API and event manager. In the standalone model, input devices
are usually polled by the Prism loop and only the Prism loop can send and receive
events.
The components of Prism which control the execution of the GUI application are
Pm_Framework, Pm_Animation_Manager, Pm_Data_Manager, Pm_Event_Manager,
Pm_Paint_Engine, Pm_Resource_Manager, Pm_Screen_Manager, and
Pm_Timer_Manager. These components are all implemented as C++ classes that are
instantiated when the function PrismInitialize is called, usually during system startup.
The PrismInitialize function is called near the start of the PrismTask for most operating
system integrations.
If you are familiar with common desktop UI programming systems such as Microsoft
MFC programming, you will quickly understand the Prism execution model because it is
modeled after these desktop environments in terms of being event driven and is also
similar as to how objects invalidate themselves to signal the Screen Manager they need
to be repainted.
The class Pm_Framework is composed entirely of static functions for assigning and
retrieving pointers to instances of the remaining framework components.
Pm_Framework provides convenient methods to allow any porting of the application
level software to invoke the Prism API, regardless of whether that software is
considered part of the UI software or whether that software is executing withing the
scope of a Prism widget class.
Pm_Screen_Manager keeps track of the visible UI elements, where they are located,
and the status of each. Pm_Screen_Manager decides where to direct input events
such as touch screen or keypad events, and makes sure that those events are
processed by the correct panels and widgets. Pm_Screen_Manager also provided a
mechanism for user-defined event types to be handled by a user-define event
processing function. Finally, Pm_Screen_Manager keeps track of which parts of the
visible screen need to be re-painted, and invoked the required panel and widget
painting functions to refresh the screen as needed.
Pm_Event_Manager provides an API for sending and receiving system and user-
defined event types. Events are what drive your user interface; events make widgets do
things and cause screen changes. The Pm_Event_Manager implementation is often
highly specific to the underlying operating system details, but this dependence is hidden
from the application level software. To the Prism application, the Pm_Event_Manager
API is all that is visible and all that is needed to send and receive all event types.
Pm_Event_Manager may be responsible for managing multiple Event Queues,
depending on how many UI threads are executing simultaneously.
Pm_Event_Manger also blocks the Prism task(s) when no events are available for
processing. This is how Prism suspends itself when the UI is idle. Pm_Event_Manager
will automatically wake up and resume the Prism thread when an input event is
received. Exactly how this wakeup occurs is unique to each operating system
integration, but to the application developer the key point is that Prism automatically
suspends or blocks when the UI is idle, and the Pm_Event_Manager forms the main
execution loop. Applications must always return from Event handlers and painting
functions and not block within those functions.
Pm_Paint_Engine provides the API definition by which all panels and widgets paint
themselves. While not part of the framework execution loop, the Pm_Paint_Engine is
vital to maintaining portability in your application across different hardware platforms
and is there counted as part of the runtime framework.
The following is a simple visual model of the operating Prism Runtime Framework:
Pm_Event_Manager
Event
Timer Driver Queue
Event
Event
Queue
Queue
Pm_Timer_Manager
System
Resources
Pm_Screen_Manager
Pm_Resource_Manager
Pm_Widget
Pm_Panel Pm_Widget
Pm_Widget
Pm_Paint_Engine Base
Display Device
Input devices drivers such as touch input or keypad input drivers send events into
Pm_Event_Manager. Pm_Timers may also be active and sending events into
Pm_Event_Manager.
Pm_Timer_Manager starts and stop timers as directed by the application software, and
receives input from the RTOS timer driver to generate PM_TIMEOUT events.
Pm_Event_Manager maintains one event queue for each UI task, which may be only
one task. Pm_Event_Manager passes events to Pm_Screen_Manager for routing to the
correct object.
Pm_Resource_Manager loads resources and prepares them for use by the application.
The application widgets query the resource manager when they paint themselves to
obtain color, bitmap, font, and string resources.
The Panels and Widgets utilize the Pm_Paint_Engine API to render themselves on the
screen. The Pm_Paint_Engine derived graphics drivers do the final rendering to the
display hardware.
Once the Prism task is started, the function named PrismInitialize (), found in the file
named prism_startup.cpp, is called to create each of the Prism Runtime Framework
components. Once PrismInitialize() returns, a user-supplied function named
PrismAppStart is called to initialize the user interface.
PrismAppStart usually loads the resource required by the application into the
Pm_Resource_Manager, waits for input devices to be ready, and then creates the intial
screen(s) to be displayed. The Prism Insight tool will generate your PrismAppStart
function for you if desired.
The exact Prism startup sequence may vary from one operating system to another;
however, from the application perspective the startup is always the same regardless of
the target platform and operating system. PrismAppStart is the application UI software
entry point, and this is where you create the first screen(s) to be displayed.
After calling PrismAppStart(), the Prism startup code calls a member function of the
Pm_Screen_Manager named Execute(). The execute function begins retrieving
events from the Pm_Event_Manager and sending them to your Prism panels and
widgets for processing. This is the Prism Event Loop, and it runs forever. On a
multitasking system, the Prism Event Loop automatically blocks or suspends when the
Pm_Event_Manager indicates there are not events needing to be processed.
4.1 Pm_Screen_Manager
Pm_Screen_Manager is a background panel, to which you link the other panels and
widgets you want to have visible on the display device. Pm_Screen_Manager is
derived from Pm_Panel, so really Pm_Screen_Manager is just another Pm_Panel to
which we have added some additional functions for keeping track of which object has
input focus and to which object input events should be directed.
We will describe the terms Link and Unlink as they are used in Prism programming in
full detail in a later chapter, but for an introduction you need to understand the Prism
keeps tracks of all of your panels and widgets using simple doubly linked lists. When
you link a panel or widget to Pm_Screen_Manager, this panel or widget becomes a
child of Pm_Screen_Manager, and also (by default) becomes visible. When you Unlink
a panel or widget, that object has no parent and is no longer visible.
Pm_Screen_Manager also keeps track of which panel and widget has input focus. This
concept is mainly used for keyboard or keypad input, but can be used with a touch
screen or mouse as well. When keyboard or keypad input events arrive,
Pm_Screen_Manager directs them to the correct child widget by keeping track of which
widget has input focus.
Pm_Screen_Manager maintains global color and style settings for various widget types
such as Pm_Button, Pm_Scroll, Pm_Title, and Pm_Menu. This makes it easy for your
application to change the default appearance of all buttons or or scroll bars, simply by
modifying these settings within Pm_Screen_Manager.
Pm_Screen_Manager keeps track of objects and regions that have been invalidated.
When the Pm_Event_Manager discovers no events are available for processing, the
Pm_Screen_Manager is invoked to efficiently repaint those objects and screen regions
that need to be refreshed.
Pm_Screen_Manager handles the routing of Mouse and/or touch screen input events to
the various widgets on the screen. Mouse and Touch input drivers send events into the
Pm_Event_Manager that encode the pixel coordinates of the mouse or touch event.
Pm_Screen_Manager searches for the topmost visible and selectable widget that lies
beneath the indicated coordinates, and routes the input event to that object.
PM_EVENT_PEN_DRAG- Sent for touch or mouse drag, when the left mouse
button is clicked or the screen is touched.
Additional touch screen input events are defined to support capacitive touch screens
that can generate multi-touch input and input gestures. These additional events are
enabled when the configuration value PRISM_FLICK_GESTURE_SUPPORT is
defined. The additional event types include:
PM_EVENT_CANVAS_CHANGE
PM_EVENT_ST_PAN_U
PM_EVENT_ST_PAN_DOWN
PM_EVENT_ST_PAN_LEFT
PM_EVENT_ST_PAN_RIGHT
PM_EVENT_ST_ROTATE_CW
PM_EVENT_ST_ROTATE_CCW
PM_EVENT_MT_PAN_UP
PM_EVENT_MT_PAN_DOWN
PM_EVENT_MT_PAN_LEFT
PM_EVENT_MT_PAN_RIGHT
PM_EVENT_ZOOM_IN
PM_EVENT_ZOOM_OUT
5.1 Pm_Event_Manager
Pm_Event_Manager maintains any number of FIFO event queues, and provides API
functions for sending events into these queues. Pm_Event_Manager also prevents
input events from being posted into the event queue when the screen is not stable,
meaning that input events are lock-out when a screen transition is occurring.
Pm_Event_Manager also provides services for creating new event queues and for
removing unwanted events after a widget has been removed or destroyed.
Events are placed in the event queue by calling the PostHead() and PostTail() API
functions. PostHead() places an event at the head of the queue (first to be processed),
while PostTail() places an event at the tail of the queue (last to be processed).
Events are always copied into the event queue to protect against posting events that
are dynamically allocated in stack (i.e. automatic event structures) or heap space.
When the event queue is empty, Pm_Event_Manager blocks the executing thread until
a new event arrives. The specific mechanisms for this vary from one operating system
to another.
Prevents user input and child event notifications via the InputProtect() API function.
This prevents spurious input during screen transition / animation sequences.
5.1.2 pm_event_t
Prism defines its own pm_event_t data format. The Prism event format never changes
from one operating system to another or when running on the desktop vs. running on
your target. When running with a real-time operating system, Prism implements each of
the event queues maintained by Pm_Event_Manager by utilizing the underlying
operating system services. To your application level software, it always appears simply
as Prism events running through the Pm_Event_Manager, regardless of the underlying
implementation. This helps to make your application software completely portable
across operating systems.
NewEvent.Type = EventType;
NewEvent.pTarget = NULL;
NewEvent.Param = Param;
Pm_Framework::EventManager()->PostTail(NewEvent);
}
Routing by initializing the Event.pTarget field is not recommended for targets that are
not statically allocated. There is no method for Prism to verify that an Event.pTarget
pointer is valid, therefore routing an Event to an object that might be deleted before the
event is delivered could cause a system failure by invalid pointer reference.
If you initialize the Event.pTarget field with a pointer to an object, your application
should try to insure that the object is not deleted before the event is processed. To
handle this situation, Pm_Event_Manager provides a Purge() API function that is called
automatically whenever any Prism widget is destroyed using the Pm_Widget::Destroy
function. The purpose of the Purge function is to locate any events in the event queue
that have pTarget fields that are not NULL, and detect if the event is directed to a widget
that is being destroyed (or any child of a widget being destroyed).
There are a set of events that Prism automatically generates and sends to notify panels
and widgets of changes in system status. For example, events are sent to notify a
widget that it has become visible, or has obtained inpu t focus, or that the active system
language has changed.
The Prism widgets have event handlers defined to handle these pre-defined system
events, or at least the events that they need to catch and take action on. It is also
possible for your application to catch system events and it is quote common to do so. If
you define a handler for a system event by making a corresponding entry in your event
table (we will talk more about event tables in the Pm_Widget chapter), it is important
that you pass the event to your base class in addition to taking whatever action you
want to add. If you do not pass system events to your base class, you effectively
prevent Prism from seeing the event, and unpredictable results may occur.
PM_EVENT_RESIZE
This event can be sent to force an object to resize itself. The Event.Region field should
contain the new desired position and size of the target object.
PM_EVENT_CLOSE
This event can be sent to a Pm_Panel derived object to cause the object to Destroy
itself.
PM_EVENT_HIDE
This event is sent to an object whenever that object is Unlinked or hidden. This event
tells the object that it is about to become invisible. Often Panels or other widgets take
specific actions, such as stopping running timers, when they are no longer visible.
PM_EVENT_SHOW
This event is sent to an object whenever it is made visible. This event allows the object
to do any preparations for display that were not done in the object constructor, or
perform actions that need to be completed each time the object is re-displayed.
PM_EVENT_PEN_DRAG
This event is sent when the mouse/touch device pen is down and moving. The
Event.Point field contains the mouse/touch pen position in pixels. These events are
caught by moveable objects such as sliders and scroll bars, and can also be caught by
the application software.
PM_EVENT_PEN_MOVE
This event is sent when a mouse device is moved, but no button is clicked. Note that
this event type cannot be generated for touch input, since there is no input available
when the touch screen is not in the pen down state.
PM_EVENT_PENDOWN
This event is sent when the mouse or touch input device changes state from pen up (or
no mouse button) to pen down (or left mouse button clicked).
PM_EVENT_PENUP
This event is sent when the mouse or touch input device changes state from down (or
clicked) to up (or not clicked), as in the left mouse button is release or the touch screen
pen is raised.
PM_EVENT_PAINT
This event can be sent to force an object invalidate and repaint itself.
PM_EVENT_GAINED_FOCUS
Pm_Screen_Manager sends this event to objects when they gain keypad input focus.
Objects may draw themselves differently when they have input focus to give the user a
visual queue as to which object is currently active.
PM_EVENT_LOST_FOCUS
Pm_Screen_Manager sends this event to all objects that were previously members of
the branch of the display tree that has now lost input focus.
PM_EVENT_NEW_LANGUAGE
This event is broadcast to all visible widgets when the active language is changed by
calling the Pm_Resource_Manager::SetCurrentLanguage() API function. The purpose
of this event is to allow all text objects which have a stringId to lookup their new string
value, in other words this event causes all text displayed on the screen to be translated
to the active language.
PM_EVENT_MOUSE_OVER
This event is supported only for mouse input devices. This event is sent when the
mouse pointer enters the mSize bounding region of an object. Many Prism objects
draw themselves in a unique fashion when the mouse hovers over the object.
PM_EVENT_MOUSE_NOTOVER
This event is supported only for mouse input devices. This event is sent when the
mouse pointer leaves the mSize bounding region of an object.
PM_EVENT_TERMINATE
This event can be sent into Prism to terminate the event loop and execution thread of
the target Pm_Screen_Manager.
PM_EVENT_PARENTSIZED
This event is sent by Pm_Panel to inform child widgets that the parent Panel has been
resized. Often child widgets will resize or relocate themselves based on the Parent
panel size.
PM_EVENT_VSCROLL
This event is sent by child Pm_VScroll widgets to cause the parent Panel to scroll
vertically. The application software can also send this event to force a panel to scroll
the contents of the client area.
PM_EVENT_HSCROLL
This event is sent by child Pm_HScroll widgets to cause the parent Panel to scroll
horizontally. The application software can also send this event to force a panel to scroll
the contents of the client area.
PM_EVENT_TIMEOUT
This event is sent when a user-defined timer expires. The Event.Param holds the timer
Id, which allows an object to have multiple simultaneous timers running.
PM_EVENT_KEYPAD_PUSH
PM_EVENT_KEYPAD_RELEASE
PM_EVENT_SLIDER_MOVE
This event is sent by Pm_Slider widgets to inform the parent that the slider value has
been changed. The Event.Param holds the slider Id, and the Event.Payload[0] holds
the new slider value.
PM_EVENT_CLOSING
PM_EVENT_PAINT_NOTIFY
This event can be sent to a designated target to notify the target when a canvas has
been updated. This is useful for applications which are configured to have some off-
screen objects painting to a non-visible canvas, and then allow a visible object to
display the resulting canvas bitmap on a visible display.
PM_EVENT_NEW_RESOURCES
PM_EVENT_CANVAS_CHANGE
This event is sent by a parent Pm_Panel to all of the panels child widgets when the
parent panels painting canvas is changed. This re-assigns the active canvas of all of
the panels child widgets, to insure they are painting to the same canvas as the parent.
Child Event Notifications are send by your panel children to the parent panel. You then
program your UI application by catching these events as they are generated by your
child widgets and acting on them. Maybe event types contain other information in the
event payload, such as scroll position, button ID value, or the sender of the event.
These Event.Type values are actually encoded with the child object ID and the event
type the child object is generating. Prism provides a macro to make this Event.Type
encoding transparent and self-documenting in your application software. The macro is
named PM_CEN, which stands for Prism Child Event Notification. We will provide an
example of using the PM_CEN macro in the following section.
The Notify() function traverses an Event Table for that object, seeking an entry in the
event table which matches the event type received. If a match is found, the event table
specifies an Event Handler function to be called for that event. If not match is found for
the Event.Type, the event is by default passed to the target objects parent.
Event Handler tables are generally defined by the Prism Insight application, but they
can also be defined by you or more often extended by you to add additional events you
might be interested in. You can add new entries to the event table created by Prism
Insight as long as you do not work within the delimited area of the table.
Event Handler Tables are arrays of pm_event_table_entry records. Each record looks
like this:
typedef struct {
uint32_t EventType;
pm_int_t (Pm_Widget::*Handler) (const pm_event_t &Event);
} pm_event_table_entry;
Each record is simply the event type we are interested in handling, and a pointer to the
function which will be called if and when that event arrives. The Event Handler Table
always ends with a NULL record terminator, meaning that the last entry is always
EventType = 0 and a NULL function pointer. This terminates the array.
The following is a simple example of how an Event Handler Table might be defined and
coded for a fictional panel class named MyPanel, which has buttons with ID values
IDB_BUTTON_GO and IDB_BUTTON_STOP.
////////////////////////////////////////////////////////////////////////////
// First, the Event Handler Table is defined:
pm_event_table_entry MyPanel_Event_Table[] = {
{PM_EVENT_SHOW, PM_EVENT_HANDLER(&MyPanel::OnEventShow)},
{PM_CEN(MyPanel::IDB_BUTTON_GO, PM_EVENT_CLICKED),
PM_EVENT_HANDLER(&MyPanel::OnEventGoClicked)},
{PM_CEN(MyPanel::IDB_BUTTON_STOP, PM_EVENT_CLICKED),
PM_EVENT_HANDLER(&MyPanel:OnEventStopClicked)},
{0, NULL}
};
The first entry above is a system event handler, PM_EVENT_SHOW. This means
every time MyPanel is displayed, we want the PmPanel::OnEventShow function to be
called.
The next two entries are CEN (Child Event Notification) handlers. These handlers
specify the Event.Type by using the PM_CEN macro, and again the function to be
called if and when these events arrive.
These event tables and event handler functions will usually be created for you by Prism
Insight, and all you need to do is fill in the contents of the event handler function(s).
However, it is useful to understand the inner workings and be able to create and modify
your own event tables.
The API reference manual specifies the exact event types supported by each type of
Prism widget.
Event handlers should always follow a basic structure. First of all, event handler
functions return a pm_int_t value. This value returned is nearly always 0, because non-
zero return values have special significance. A non-zero return value indicates that the
event handler is signaling the termination of a modal execution loop, and desires to
return the Event Handler return value to the caller of the Execute() function. In most
cases, Event Handlers do not want to trigger the termination of the Execute() function
and they therefore return the value 0.
Event handler for pre-defined system events should always pass the event to the
objects base class to allow Prism to see and act on the event. This is an example of an
event handler for the PM_EVENT_SHOW system event:
SetColor(PM_CI_NORMAL, CID_RED);
return 0;
}
In the above example, we first called the base class event handler. If you do not know
of an exact event handler for the event type you are processing, you can always call the
base class Notify function by default. Directly invoking the correct event handler of the
base class is more efficient, but not critical.
There is nothing magical about the function name OnEventShow. The Prism
developers try to use function names that indicate the type of event the function is
designed to handle, but you can use any names or convention you like for naming your
event handler functions. All that matters is the function signature matches what is
shown above.
Aside from the pre-defined system event types described in the previous sections,
Prism also supports the application defining, sending, and handling events with custom
or application defined meanings.
User defined events are distinguished by the Event.Type field, which is above the value
of FIRST_APP_EVENT for user defined event types. User-defined events are never
caught or interpreted by the Prism framework, so the payload of these events is
completely at the discretion of the application. The exception to this is the Event.pTarget
field, which can still be used (with caution!) to direct an event to a particular object.
Prism includes mechanisms to allow an application to record and playback input events,
effectively creating user-input macros. This is useful in creating standalone demos (no
user-interaction required), UI testing, etc. Event recorded can be saved in either XML
format (intended for use on targets with a filesystem) or C data array format (to allow
compiling the macro data directly into the application).
The macro record and macro playback code are optional and can be enabled using the
defines PRISM_MACRO_RECORDER and PRISM_MACRO_PLAYBACK, which are
produced by Prism Insight in your prism_settings.h header file when you enable these
options.
The macro record and playback feature is most commonly utilized as follows:
4) Moving to the target, the macro data is either compiled as a data array
within the application, or it is read from the target filesystem.
5) The macro playback function is invoked, and the target begins to self
drive without any user input.
Macro Recorder:
Pm_Event_Manager::SaveMacroXMLFile() or
Pm_Event_Manager::SaveMacroCArray()
The two Save file APIs are required so that the events can be saved either as XML to
be read and played back on the target file system, or as a C array to be compiled and
linked with the target application for targets that do not have a filesystem.
Macro Playback:
If the target has a filesystem and the macro file is in XML format, then the API
Pm_Timer_Manager::ReadMacroXmlFile() is used to read and parse the macro event
data. If the target has no filesystem and the macro data has been compiled into the
application, then the API Pm_Timer_Manager::AssignMacroEventList is used to
initialize the macro event list prior to beginning playback.
6.1 Pm_Timer_Manager
Prism Timers are are not directly linked to hardware-level timer interrupts, and
should not be used for precise timing operations.
The Prism timer facility is generally driven by one operating system level timer. If there
is no operating system, some low-level timer facility must be implemented to provide a
time base into the Pm_Timer_Manager.
Timers are invoked in your application software by calling the SetTimer API function.
Only Pm_Widget derived objects can create and use Prism timers, because Prism is
going to send an event to the timer owner when the timer expires. Prism notifies the
timer owner by calling the owners Notify function, therefore the timer owner must be a
Pm_Widget derived object.
Timers are started by calling the SetTimer() API function. The full prototype of this
function is:
The TimerId is any application defined timer Id value. This value is passed back to the
timer owner in the timeout event.Param data field. This allows one widget to start and
receive events from several timers simultaneously.
The FirstVal parameter specifies the intial timeout period. Note Prism timer intervals
are not absolute but are relative to the period at which the TimerTick function is called.
For most RTOS integrations and targets the TimerTick function is called at a 50ms
interval. The application software can use the #defined value PRISM_TICS_SEC as a
reference to setting timeout values in the application software.
The RepeatVal parameter specifies how often the timeout should repeat after the first
timeout interval. If this value is 0, the timer will timout only once and will automatically
stop and delete itself after this first timeout interval.
Timers are stopped and deleted by calling the KillTimer(TimerId) API function. If
TimerId is non-zero, only the timer owned by the caller and having the requested Id
value will be stopped and deleted. If the TimerId value is 0, all timers owned by the
caller will be stopped and deleted.
#define MY_TIMER_ID 1
pm_event_table_entry MyPanel_Event_Table[] = {
{PM_EVENT_SHOW, PM_EVENT_HANDLER(&MyPanel::OnEventShow)},
.
.
};
// start the timer in the panel constructor. This can be done at any time,
// not just during panel construction:
MyPanel::MyPanel(.)
{
7.1 Pm_Resource_Manager
The Prism Resource Manager is a fully static class that provides APIs for loading,
removing, and retrieving the various assets required by the application. These assets
might include bitmaps, fonts, color, strings, and any combination thereof.
Applications can define any number of additional resources, and can also replace the
default system resources. Usually resources are loaded from resource files, which can
be in source code, binary, or XML formats and any combination.
Pm_Resource_Manager provides APIs for loading resources from a file into RAM, or
optionally for loading resources in place and setting up RAM based tables pointing into
these resources located in FLASH or other non-volatile storage.
Resource files are automatically generated by Prism Insight. You have full control over
when resource files are generated and control over what is included in each resource
file. Resource files can be in Source format and/or binary formats.
Source format resource files are generated using normal C syntax and data structures.
You compile and link the source format resource files along with the remainder of your
application software. Source format resource files are the simplest to use but can
become large and cannot be installed at runtime in shipped binary units.
Binary format resource files are also produced by Prism Insight, but differ from source
format in that they are installed at runtime. Binary format resource files require either a
filesystem on the target hardware or some method for programming the binary data into
FLASH on the target system. Binary resource files are often used for runtime updates to
the system. Binary resource files can also be used when the target CPU has both
internal and external FLASH storarge. Usually code is placed in the internal storage,
while the binary resources are placed in the larger but slower external FLASH storage.
You can include any combination of source and binary format resource files in your
product. You might ship your product with one source format set of resources bound to
the application binary, but allow users to install optional binary resource files to add
languages or change color themes.
Resource ID types use a simple naming convention to distinguish them and make the
Prism code easy to read. The resource Id name always prefixed with one of 4 prefixes:
Pm_Resource_Manager::LoadConstResources(pm_res_table_t *pTable)
contain multiple themes or skins. This is useful for devices that will have a large
number of screens and user profiles. Examples are Universal Remote Control device or
portable music player. Themes or skins are collections of any grouping of images,
fonts, strings and color resources. Themes can be changed at runtime, allowing you to
re-skin your application on the fly. You can compile more than one theme into your
application, or themes can be installed at runtime by loading binary or XML resource
files using a filesystem or other FLASH storage means.
Prism Insight allows you to generate resource files containing individual themes, or you
can generate a single resource file that contains multiple themes.
You will often need to use and manipulate resources directly in your application
software. For example, you might want to obtain a pointer to a text string or a pointer to
a bitmap. APIs are provided for this purpose as the following:
Pm_Resource_Manager::GetColor(pm_uint_t ResId)
Pm_Resource_Manager::GetBitmap(pm_uint_t ResId)
Pm_Resource_Manager::GetFont(pm_uint_t ResId)
Pm_Resource_Manager::LookupString(pm_uint_t StringId)
Shorthand macros for these functions are also provide in the form of:
8.1 Pm_Paint_Engine
Pm_Paint_Engine class is an abstract class which defines the functions and function
parameters available to applications and to the Prism widget and panel classes for
painting on the display device, or more accurately for painting into the frame buffer(s).
From the Pm_Paint_Engine class the base classes for each color depth and color
format are derived. These base classes provide the low-level drawing capability of a
particular paint engine for a particular color depth and format. Even if creating a new
paint engine for custom hardware, you will never need to implement the basic drawing
primitives in your software, as these primitives are already implemented in the color
depth specific base classes.
From the base class is derived the hardware-specific driver class. The driver class may
contain only hardware initialization code, or it might contain a large number of function
overrides in the case of a hardware accelerated graphics controller. Prism always
attempts to utilize all available hardware acceleration capabilities.
8.2 Pm_HiColor_Sim_Engine
The Pm_Paint_Engine derived classes always attempt to draw at the hardware specific
native color format. This ensures the least overhead and best runtime performance.
The one exception to this rule that that when running with the Pm_HiColor_Sim_Engine.
This paint engine always runs at 32-bpp internally, but converts the final output buffer to
the color format required by your hardware display device. The
Pm_HiColor_Sim_Engine allows advanced alpha-blending and fading effects even
when the final output device is a grayscale or color depth limited device.
The Pm_HiColor_Sim_Engine can be configured for any output device from 4-bpp
grayscale to 16-bit 5:6:5 color depth. Internally this driver always implements all
painting using 32-bit 8:8:8:8 color format. The final output buffer is then downsampled
to the final output color format. This downsampling step requires additional overhead,
and should only be used when the target CPU bandwidth is sufficient to allow this type
of operation.
The following diagram illustrated the Pm_Paint_Engine class hierarchy and API usage:
Pm_Paint_Engine
(provides API definition and Painting entry points)
prism_pe_base_x_bits_per_pix
(painting primitives at each color format)
prism_pe_hardware_specific
(hardware specific init and optimization)
Directly writes to
There are many different Pm_Paint_Engine derived classes for different hardware
graphics controllers, different color depths, and different screen orientations. You will
normally include only one Pm_Paint_Engine derived driver class in your framework
build, except for special cases where multiple screen drivers are required because of
run time changes to screen orientation or graphics hardware. You will always include
the base Pm_Paint_Engine class and the color format specific template class in your
framework build.
Position 0,0 is always the to-left most corner of the screen. This is true even if your
screen is rotated from its native mounting orientation. Increasing X coordinates move
from left to right across the screen. Increasing Y coordinates move from top to bottom
down the screen.
Positive Y values moving down the screen is opposite of the standard Cartesian x,y
plane; however, this convention has been used for graphical systems for many years
and it somewhat standard among graphics API systems.
Prism provides a set of drivers for a large set of specific graphics controllers. Graphics
controllers can be internal to the die of the core CPU, or they can be external devices
communicated with over serial or parallel interface between CPU and graphics
controller/driver.
The graphics controller is responsible for generating the timing signals required by your
physical display and for refreshing the display by constantly shifting the pixel data to the
display, usually at a rate between 50 and 75 Hz. Configuring the graphics controller, no
matter how it is interfaced to the core CPU, is the job of the hardware-specific Prism
paint engine.
Graphics controllers require some physical memory for storing the pixel color data. This
memory is normally referred to as a frame buffer, i.e. a memory buffer that holds one
frame of pixel data. This memory might be part of the internal RAM of your core CPU, it
might be a portion of a large external SRAM, or it might be incorporated with an external
graphics controller that is integrated with your display (usually referred to as GRAM).
Regardless where the memory for your pixel data is located, the hardware specific
Prism paint engine is responsible for getting your pixel color values stored into this
frame buffer or buffers. Exactly how this data gets written into your frame buffer is
dependent on your hardware architecture and your Prism paint engine configuration.
We refer to this data channel as the Graphics Data Pipeline.
When you paint lines, text, and bitmaps within Prism, this painting is usually NOT done
directly to the visible frame buffer, for a variety of reasons including the following:
1) For systems utilizing an external graphics controller which provides the frame
buffer memory, access to this memory is usually not random access or fast, but
instead requires registers on the external controller be written to specify the
memory address, following by reads or writes to another register to actually
reads or write data.
2) Modifying the visible frame buffer data while that buffer is being shifted to the
display can cause artifacts and tearing. Buffer updates are normally
synchronized with the LCD V-Sync vertical retrace signal.
For these reasons the Prism paint engine classes support different models for defining
how the graphical information your application paints ends up in the visible frame buffer.
These different models are defined by a set of configuration options in the Insight
settings screens which generate a corresponding set of configuration flags in the
prism_settings.h header file. The following sections and diagrams are helpful in
understanding the Prism Graphics Data Pipeline models.
Nearly all Prism paint engines support the concept of double-buffering. Double-
buffering means that at least two hardware frame buffers are maintained, and Prism
ping-pongs between the two buffers during each paint operation.
Double buffering requires that Prism maintain one visible buffer and one working
buffer. The visible buffer is being shifted to the display by the LCD controller
hardware. The working buffer is the buffer into which you are painting. When you
conclude a painting operation, Prism swaps the two buffers.
After the buffer swap, Prism must synchronize the two buffers to insure that graphics
integrity is maintained. Prism keeps track of the region with the working buffer that has
been modified, and copies this region to the new working buffer immediately after the
ping-pong swap operation.
Hardware support for double-buffering is becoming more common; however, the real
key to fast double-buffering is having a DMA or 2D bit-blit engine accelerator to optimize
the buffer synchronization operation.
Multiple software canvas support is required for screen fade transitions, but otherwise is
not required. Be aware this option can consume copious amounts of dynamic memory
if the additional canvases are large.
In the diagram above, the Prism paint engine does NOT utilize any local frame buffer.
In this case, all painting functions are implemented to directly write to an external
display controller. This type of implementation is usually not preferred; however, it can
be the only solution for systems that do not have enough local memory available to hold
a frame buffer. Examples which utilize this type of architecture include certain ARM-
CortexM3 devices without external RAM, along with certain PIC type devices that
likewise have no memory bank large enough to hold a graphics frame buffer.
In this case, the Prism paint engine is organized such that all paint operations are
immediately rendered directly in the external GRAM (Graphics RAM) present on an
external controller/driver. Examples of these types of external controller include several
made by ILITEK, Himax, Solomon Systech, and Renesas.
Note, if the bus between the core CPU and external controller is a serial bus such as an
SPI interface, this archicture can experience performance bottlenecks.
The diagram above represents one of the simplest pipelines supported. In this case
there is one local frame buffer, and this frame buffer is directly driven to the display.
This model is avoided when possible to prevent tearing, unless the display image is
very static or all painting can be done with the vertical retrace period. This requires the
paint engine force synchronization with the Vertical Sync signal.
Model 3: Single local frame buffer, external controller with embedded GRAM:
This model requires more memory than model 1, to hold a local frame buffer. However,
the advantage is that for 16-bpp and higher color depths, Prism can support full alpha-
blending, panel fades, and true anti-aliased text because the local frame buffer is fast
random access memory. This model also allows Prism to update the external GRAM
quickly in one window-mode transfer to the external controller. Prism always keeps
track of the invalid region of the local frame buffer, and therefore only this invalid region
is transferred after each screen update.
The diagram above illustrates another very common graphics pipeline model. In this
model, multiple graphics frame buffers are created in random-access memory that are
directly accessible to the core CPU. With each screen update, the working and
display buffers are toggled in a ping-pong fashion. This eliminates visual tearing of the
display, and on many hardware devices this double-buffering mechanism is hardware
accelerated.
This is a very common graphics pipeline model, and utilized on a broad range of
devices running at a large number of color depths and formats.
The model above illustrates a Prism paint engine supporting multiple managed software
paint canvases. In this model, Prism create a composite of the background and overlay
canvases, and ping-pongs the composite display buffer in a mannor identical to the
direct double-buffering model.
Model 5 adds the ability to do screen fades and rapid screen transition animations to
your Prism application. This model uses much more memory than the simpler models,
but this is the price of more sophisticated graphical animations.
The model shown above is also a common implementation for systems utilizing an LCD
with integration GRAM, but requiring the sophisticated features such as screen
transitions and alpha blending. Note, this model is not much different than model 5,
other than the GRAM is usually not local random-access memory but is instead external
memory that requires a specific protocol to modify.
This is the paint engine for monochrome operation. You should derive your hardware-
specific engine from this class if you are going to write a custom monochrome painting
driver.
These modules implement a 256 color paint engine base. Both 3:3:2 RGB packed pixel
format and and 8-bit palette mode operation are supported by this base class.
This is the base class for 16 bit (65K Color) operation. Both 5:6:5 and 5:5:5 color
formats, in both RGB and BGR color order are supported by this base class.
This is the base class for 24-bit 8:8:8 operation. This class supports both RGB and BGR
color order.
This is the base class for 32-bit operation which is alpha-red-green-blue or blue-green-
red-alpha.
Prism provides a set of paint engines and operating system integration files which
enable you to build and run your Prism application as a Microsoft Windows desktop
application or as a Linux/X11 desktop application.
We call this the Desktop Simulation Environment since you are not running Prism on
your intended target (although in some case Windows or X11 may be your final target!).
The Desktop Simulation Environment is as pixel accurate as possible, since Prism does
not utilize the underlying operating system drawing APIs to render graphics. Prism
utilizes its own painting APIs to render all graphics and text, even when running on the
desktop. This ensures your user-interface will look and function exactly the same on
your desktop and on your final target.
For the Microsoft Windows environment, Prism provides the following paint engines to
allow you to run at the required color depth and format within a Windows window. Note
in some cases Microsoft does not support the required color format, in which case
Prism converts the Prism frame buffer data format into the next higher color format
which is supported by Microsoft. This does not affect the colors of your user interface in
any significant way, but does add a small amount of overhead when running on the
desktop. The performance of most desktop CPUs more than compensates for this.
prism_pe_windows_1bpp
prism_pe_windows_2bpp
prism_pe_windows_4bpp
prism_pe_windows_8bpp
prism_pe_windows_16bpp
prism_pe_windows_24bpp
prism_pe_windows_32bpp
For the Linux/X11 environment, the following desktop paint engines are provided:
prism_pe_x11_16bpp.cpp
prism_pe_x11_24bpp.cpp
To build and run with the Linux operating system, you should include the file
prism_for_x11.cpp in your Prism library build. This file is found in the \prism\source\rtos
sub-directory.
Its nearly impossible for Prism to correct for differences in pixel size between your
desktop environment and your target system. If pixels are packed more tightly on your
desktop because you are using a very high screen resolution, your Prism screens will
appear smaller on your desktop than they will be on your target. One way to
compensate for this is to run your desktop at a lower x,y resolution.
For the Windows desktop, Microsoft compilers version 8 (Visual Studio 2005), version 9
(Visual Studio 2008) and version 10 (Visual Studio 2010) are supported. For Linux
desktop the GNU toolchain is supported.
This static function returns a pointer to the active Pm_Screen_Manager instance. Any
thread can access the Pm_Screen_Manager at any time, even non-UI threads. The
following function returns the ID value of the top-most panel currently displayed:
pm_int_t GetTopPanelId(void)
{
Pm_Screen_Manager *ps = Pm_Framework::ScreenManager();
if (pTop)
{
return pTop->GetId();
}
return 0;
}
Pm_Framework provides a set of helper APIs are to simplify paint operations. Painting
is done by the Pm_Paint_Engine instance, however these wrapper functions allow the
application software to simple call Line and PaintText without concern for the active
canvas or Paint Engine instance. This is not an exhaustive list, but a list of the most
commonly used painting API functions.
void CloseCanvas(void)
This is a wrapper function for Pm_Paint_Engine::Line. This function locates the active
paint engine for the callers default canvas.
These are wrapper functions for the Pm_Paint_Engine::TextWidth API functions. These
functions locate the active paint engine for the callers default canvas. The first version
accepts a pointer to a font; the second version accepts a font Id.
Pm_Widget is the base class from which all viewable Prism widgets are derived. The
Prism widget classes such as Pm_Button or Pm_Prompt provide custom Paint function
to tailor their appearance, and may provide custom event handler to tailor their
operation, but the core functionality of all widgets is defined by the Pm_Widget base
class and its member functions.
To really get the most out of Prism, you will need to learn the Pm_Widget public API
functions and feel comfortable overriding those functions to create your own custom
widgets. The Prism widget classes are in many ways designed to be rather simple, with
the goal being to keep the framework code size to a minimum and make it very easy for
you to derive your own custom classes from the Prism base implementations. This
allows you to extend the Prism framework easily and efficiently to produce a user-
interface that sets your product apart from all others.
The following sections will describe in detail the public functions and data members of
Pm_Widget. With this information, you will gain a clear understanding of how Prism
works.
Pm_Screen_Manager keeps track of invalidated objects, and calls the objects Paint
member functions to refresh those invalid objects on the visible canvas. If you want to
customize the appearance of a widget beyond what can be accomplished with style
flags and colors and fonts, you will need to derive a custom class and override the Paint
member function. This gives you complete control of the objects appearance.
The Notify function for most classes simply processes the class event table, and if no
match is found passes the event to the base class. If you want to catch events, you
simply need to define your own event table for use by your class.
Pm_Widget also provides members and functions for linking widgets together, making
one widget the parent of another. This is how the tree-structured list of widgets that is
central to the organization of the Prism display is constructed. Pm_Widget always
keeps child objects linked in their Z-order, meaning the first object in the child linked-list
is always on top of any other sibling child objects, and the last child object in the linked
list of child object is always on the bottom. Even if child objects do not visually overlap,
this logical Z-ordering still occurs.
Pm_Widget provides a common set of style flags, status flags, and member variables
needed by all visible widget and panel types. These include, for example, a member
variable named mSize which determines an objects position and size on the canvas, as
well as the actual canvas Id to which this widget is painted.
Pm_Widget also maintains a small color table which is inherited by all widget classes.
Some classes extend this color table to support additional color values, but this base set
is common to all widgets.
This section focuses on the key API functions of the Pm_Widget class, explains their
purpose and function, and includes many code examples to demonstrate their use. For
a complete listing of the Pm_Widget API functions refer to the Prism API reference
manual.
These are the constructors for Pm_Widget. The Size parameter specifies the initial
region or position and size of the widget. The Id parameter is used by controls such as
buttons and sliders to report events back to their parent. The style parameter defines a
set of basic appearance attributes such as border style (thin, thick, raised),
transparency, and whether the widget is enabled or accepts user input.
Page 78 Blue Water Embedded, Inc.
Developers Guide
The second constructor differs from the first only in that the Size paramenter is not
required. In this case, the widget creates itself with a default size, and the application
should then call the Resize function to assign the widgets position and size before the
widget is displayed. This version is used if the widget size or position is not known at
the time of construction.
The Paint function is the most commonly overridden function when creating custom
widget classes. Overriding the Paint function is how you accomplish creating custom
widgets with your own required appearance.
The Invalid parameter passed to the paint function informs the widget of the screen area
that needs to be refreshed. This screen area will most often be as large or larger than
the widget or panel being painted, but in some cases the invalid region may not
encompass the entire widget. In those cases, the widget can optionally paint just that
area which overlaps the Invalid parameter.
Most often widgets ignore the Invalid parameter and simply pass this to the Paint
Engine OpenCanvas() API. This allows the Paint engine to limit your painting to the
invalid area, and your Paint function can simply refresh the entire widget every time the
Paint function is called. The paint engine will trim your paint operations to the invalid
area.
An example of a custom widget which overrides the Paint function is provided at the end
of this manual.
These functions are used to add one object to another, by linking the object pWho to the
caller this. You can also link objects to each other by explicitly passing the caller, and
in:
Pm_Framework::ScreenManager()->Link(pWho);
The Link function makes pWho a child of the object being linked to, which becomes the
parent of pWho. Once an object has been linked to its parent, the parent object owns
the child. Deleting the parent object automatically deletes the child, and moving the
parent object automatically moves the child, and so on. When you Link a child object to
a visible window, that object becomes visible unless the DoShow parameter is set to
False.
The Link function always places the linked object at the front or of the Z-order of the
parents list of child objects. Re-Linking an object that is already a child of the parent
simply moves the object to the front of the child list, which places the object in front of
its siblings on the screen.
The LinkTail function shares all of the properties of the Link function, except the linked
object is linked at the back, or at the tail end of the parents child object list. The LinkTail
function is often used when adding elements to a Pm_List derived parent, to insure that
the elements maintain the same order in the parent list in which they were added to the
list.
Any type of object can be linked to any other, and this nesting can continue ad-infinitum
within the limits of your target system memory. For example a top-level panel might be
constructed, and to this panel you might link several child panels. Within those child
panels, you might link several different types of child buttons. Finally you might link the
top level panel to the screen manager. This is the common sequence in which complex
panels and screens are constructed.
The Unlink function serves the opposite purpose of Link. An object can be unlinked
from its parent at any time, in which case ownership of the object returns to the
application. The application may later Destroy the object, it it may re-link the object to
the same parent or even to a differing parent.
A single object should never be simultaneously linked to multiple parents! This could
cause the object to be doubly-deleted, if both parent objects are destroyed.
The Unlink function causes a PM_EVENT_HIDE event to be sent to pWho, and to all of
the children of pWho, assuming pWho was linked to a visible parent.
The Destroy function is used to Unlink and delete and object. Destroy is designed to be
a failsafe object cleanup function, and it is recommended that applications structured to
create panels when needed and delete panels when those panels are not required
always use the Destroy function to destroy panels and child widgets.
In addition to Unlinking and deleting pWho, the Destroy function performs the following
tasks:
- Kills any timers owned by the object or any children of the object.
- Purges the event queue of any events bound for pWho or any of pWhos
children.
- Checks for self-deletion, and insures this does not occur by requesting that
Pm_Screen_Manager destroys the object. Therefore, Destroy(this) is perfectly
safe and even expected in normal Prism applications.
- Insures that pWho and none of the children of pWho have captured input
device(s), and if so frees those input device(s).
This function is used to add style flags to an object. The available style flags are
documented in the API reference manual. Many style flags are specific to certain object
types, while others are supported by all object types.
The Style flags supported by each object type are documented in the API reference
manual.
This function removes the style flags contained in the Mask parameter from the objects
internal Style variable. Objects do not automatically invalidate themselves based on a
change to the Style flags.
uint32_t GetStyle(void)
This function is used to modify which Child Event Notifications a widget should send to
its parent.
All widgets have a default set of event notifications that they enable and this is
documented in the Prism API reference manual. Prism widgets do not by default
enable all possible event notifications in order to reduce the number of events being
generated and processed by the Prism Event Mmanager. The SetEventMask function
is provided to allow you to enable or disable particular events from your child widgets.
pWidget->SetEventMask(pWidget->GetEventMask() |
EVENTMASK(PM_EVENT_FOCUS_LOST));
The following table lists the available event masks with a brief description of each:
Comments Default
PM_EVENT_TXT_SELECT Sent by text input widgets when the user selects a Disabled
block of text
PM_EVENT_TXT_EDIT Sent by text input widgets when the user modifies the Disabled
text input widget text value in any way
PM_EVENT_TXT_EDITDONE Sent when the user completes text modifications Enabled
(object loses focus or CR input key is received)
These functions instruct the Pm_Screen_Manager to record that the caller is visually
invalid and needs to repaint. The first version passes the region defining the exact
invalid area, while the second version invalidates the entire mSize region of the caller.
Note that painting is not directly invoked by this function call. This function simply
creates a record of an invalidation. Later, when the Pm_Event_Manager finds the event
queue for this task is empty, the Pm_Screen_Manager will optimize the list of invalid
entries and invoke the necessary Paint functions to refresh the screen.
12 PROGRAMMING EXAMPLES
This chapter demonstrates several common programming tasks in order to illustrate the
use of the Pm_Widget class member functions. Remember all displayable Prism panel
and widget classes are derived at some point from class Pm_Widget, and therefore
these operations can be performed from within any member function of a derived class.
One of the most basic properties of all Prism objects is the objects position on the
screen. Pm_Widget maintains this information, along with clipping and Z-ordering
information to insure that objects are only allowed to paint to the areas of the screen
that are owned by the object. An objects position is held in the Pm_Widget member
variable mSize, which is a value of type Pm_Region. You can always determine where
an object is at any time by examining the objects mSize data member. Pm_Widget
also maintains a separate but related member called mClient, which is an additional
Pm_Region member that indicates the client rectangle of the object. The mSize and
mClient variables can be equal for a borderless widget.
For example, by using the mSize variables and the Pm_Region::Overlap function, we
can easily determine if two objects overlap using the following code segment:
The Pm_Widget member function Link() is used to attach one object to another. When
one object is linked to another, it becomes a child of the object is has been linked to.
When an object is linked to a visible parent, the object and all of its child objects
become visible (unless you explicitly prevent this). The Pm_Widget::Link(Pm_Widget
*pWhat, pm_bool_t Show) function links one object to another. The default value of the
Show parameter is TRUE, meaning when an object is linked to a visible parent, that
object also becomes visible.
The following function creates a Pm_Panel, adds a Pm_Button to the panel, then
displays the panel by linking the panel to Pm_Screen_Manager:
void DisplayPanel(void)
{
Pm_Region Size;
Size.Set(0, 0, 239, 319);
pPanel->Center(pBtn);
pPanel->Link(pBtn);
The above example assumes the function is not a member of a Pm_Widget derived
class. If the example above is a member function of a Pm_Widget derived class, the
Pm_Framework:: scope resolution operator can be eliminated.
The Pm_Widget member function Parent() returns a pointer to the parent of the current
object. The returned pointer is also a pointer to a Pm_Widget. If the object has no
parent (i.e. the object has not been Linked to another object), the Parent() function will
return a NULL pointer.
It is acceptable, given enough dynamic memory is available, to create all of your user
interface panels during system startup and never delete them. In that case, the
application would create an array of pointers to the Pm_Panels that compose the user
interface, and the Unlink function would always be used to remove panels from the
display rather than the Destroy function. This is a common method for implementing
applications on failsafe secure devices to eliminate the runtime memory allocations
needed if panels are created and deleted as they are needed.
When any widget is linked to another, the widget is in effect owned by the parent
widget. Destroying the parent widget deletes all children of that parent as well as the
parent. If you unlink a widget or panel from its parent, you are responsible for the
widget from that point forward. You might at a later time link the widget once again to
some parent object, or you might destroy the widget. The important thing to remember
is that once you Unlink a widget from its parent, the Prism framework no longer has any
information about the widget and it is the responsibility of the application software to
track the widget at that point to prevent memory leaks.
For example, an object could count the number of siblings (i.e. objects with the same
parent) it has using the following code sequence:
while(pChild != NULL)
{
Count++;
pChild = pChild->Next();
}
return Count;
}
enum PrismButtonIds {
PM_BTN_ID_OK = 1000,
PM_BTN_ID_APPLY,
PM_BTN_ID_YES,
PM_BTN_ID_NO,
PM_BTN_ID_CANCEL,
PM_BTN_ID_RETRY,
PM_BTN_ID_ABORT,
PM_BTN_ID_CLOSE
};
Buttons with the Ids listed above are automatically recognized by Pm_Panel derived
classes.
At any time you can locate a child object using the objects ID with the Find() function.
Find will search the child list of the current object for an object with an ID value
matching the passed in value.
Object IDs can also useful for locating top-level panels. It is often the case one panel
needs to locate another panel, or some portion of the business logic wants to send a
user-defined message to a particular panel.
The following demonstrates finding a top-level panel based on the Panel Id, and
sending a user-defined message to the panel:
if(pPanel != NULL)
{
NewEvent.pTarget = pPanel;
Pm_Framework::EventManager()->PostTail(NewEvent);
return TRUE;
}
return FALSE;
}
typedef struct {
uint32_t EventType;
pm_int_t (Pm_Widget::*Handler) (const pm_event_t &Event);
} pm_event_table_entry;
The EventType member is the Event.Type field you want to catch, and the Handler is
the address of the function that should be called when the event arrives. If we repeat
the previous example, the Event Table for the MainMenu class now looks like this:
pm_event_table_entry MainMenu_Events[] = {
{PM_EVENT_SHOW, PM_EVENT_HANDLER(&MainMenu::OnEventShow)},
{PM_CEN(BTN_ID_MENU1, PM_EVENT_CLICKED),
PM_EVENT_HANDLER(&MainMenu::OnEventMenu1Clicked)},
{PM_CEN(BTN_ID_MENU2, PM_EVENT_CLICKED),
PM_EVENT_HANDLER(&MainMenu::OnEventMenu2Clicked)},
{PM_CEN(BTN_ID_MENU3, PM_EVENT_CLICKED),
PM_EVENT_HANDLER(&MainMenu::OnEventMenu3Clicked)},
Observe the functions above are very short and easy to read. This is a dramatic
improvement in code style as compared to the long switch-case statement that often
results from not using Event Tables.
Finally, the Notify function when using Event Tables will look similar to this:
while(pEventList->EventType)
{
if (pEventList->EventType == Event.Type)
{
if (pEventList->Handler == NULL)
{
return 0;
}
return PM_CALL_EVENT_HANDLER(*this, pEventList->Handler)(Event);
}
pEventList++;
}
return Pm_Panel::Notify(Event);
}
Note, Prism Insight automatically produces the Notify function and the Event Table for
you. All you need to do is create your child widgets and assign IDs to them, and Insight
will do the rest. This above information is provided so that you can understand exactly
what is occurring under the hood of your Event Tables and Event Handler functions.
Prism provides for a high degree of customization in the appearance of each type of
panel and widget that compose your user interface via style flags, bitmap assignment,
color assignment, and font assignment. You can extend these capabilities further by
deriving your own widget types from the classes provided within the Prism framework.
In order to customize the appearance of a custom widget, you will generally need to
override the Paint() function. When you override this function in your custom widget
types, you now have full control over how and what the widget paints on the canvas
when the widget is visible.
The incoming Invalid parameter informs you of exactly what part of the panel or widget
needs to be repainted. You can generally just pass this parameter to the OpenCanvas
call that will begin your Paint function, but you can also use this parameter to determine
what needs to be repainted if your Paint function is very long or complex.
In the following example, we will create a new button class derived from Pm_Btn. This
class will override the Paint function to change the button color each time the button is
pressed, and also display a counter value (0 9) that will increment each time the
button is clicked.
private:
pm_int_t mClickCount;
};
The Notify function simply checks for PenDown events, and passes all other events to
the base class:
// color IDs 0 15 are the standard VGA color palette. Use these
// colors as my background color and change it each time I am clicked.
#if defined(PRISM_GRADIENT_BUTTONS)
SetColor(PM_BCI_GRADIENT1_NORMAL, mClickCount);
SetColor(PM_BCI_GRADIENT1_HASFOCUS, mClickCount);
#endif
OpenCanvas(Invalid); // note 2
Pm_Btn::Paint(Invalid) // note 3
CloseCanvas(); // note 5
}
Running this code by adding this button type to a panel and clicking on the button
produces a series of button colors and counter values. The following image is a
sequence of screen shots resulting from running the above MyButton class:
Note 1: This is how we are changing the button color, by assigning the member
variables of the Pm_Btn class that hold the color values that will be used to paint the
button. If the button is painting a gradient fill, we need to assign a different set of color
that if the button is using a solid fill.
Note 2: Before we call any painting API functions, we need to call OpenCanvas to
prepare the canvas for painting and to initialize the clipping area.
Note 3: This statement calls the base class Paint function to paint the button
background. It is very common to invoke the base class Paint function if your
customization will be drawn on top of the background painting.
Note 4: This statement loads a pm_font_t pointer into the brush we are using for
painting text. The font point is located by invoking the PFR macro, which is a shorthand
method of asking the resource manager for the font pointer corresponding to a font Id.
The 4 resource request macros and their expansion are:
The FID_MEDIUM_FONT is one of two always defined font Ids, the other being
FID_SMALL_FONT. You can always use these two fonts in your application, in addition
to any other fonts you have added to your resource list.
Note 5: You always need to end your Paint function with a call to CloseCanvas. If you
forget to call CloseCanvas, the canvas will be locked and no panels or widgets will be
able to paint on this canvas. This error is usually readily apparent and easily corrected.
Often when Child Event Notifications are received, the user-interface must transition to
a new state or panel. This is very easy to accomplish, and there are many supporting
structures implemented by Prism in Pm_Screen_Manager to make state transitions and
screen navigation easy to accomplish.
The MainScreen class of the music player, implemented in the file mainscreen.cpp,
defines the following event table:
pm_event_table_entry MainScreen_Events[] = {
{PM_CEN(MainScreen::IDB_PLAYLISTS, PM_EVENT_CLICK),
PM_EVENT_HANDLER(&MainScreen::OnEventPlaylistsClicked)},
{PM_CEN(MainScreen::IDB_SETTINGS, PM_EVENT_CLICK),
PM_EVENT_HANDLER(&MainScreen::OnEventSettingsClicked)},
{PM_CEN(MainScreen::IDB_GENRES, PM_EVENT_CLICK),
PM_EVENT_HANDLER(&MainScreen::OnEventGenresClicked)},
{PM_CEN(MainScreen::IDB_SONGS, PM_EVENT_CLICK),
PM_EVENT_HANDLER(&MainScreen::OnEventSongsClicked)},
{PM_CEN(MainScreen::IDB_SETTINGS, PM_EVENT_CLICK),
PM_EVENT_HANDLER(&MainScreen::OnEventSettingsClicked)},
{PM_CEN(MainScreen::IDB_ARTISTS, PM_EVENT_CLICK),
PM_EVENT_HANDLER(&MainScreen::OnEventSettingsClicked)},
{PM_CEN(MainScreen::IDB_ALBUMNS, PM_EVENT_CLICK),
PM_EVENT_HANDLER(&MainScreen::OnEventSettingsClicked)},
{0, NULL}
};
Each of these events is CENs from the main screen child buttons. When a button is
clicked, the MainScreen handles the event as shown below:
The available Panel transition modes are defined in the prism_panel.hpp header file. If
no transition mode is defined, the panel is simply displayed immediately as soon as it is
linked to the Pm_Screen_Manager.
Note in this case the MainScreen did not destroy itself or remove itself from the display.
The MainScreen is therefore still linked to the Pm_Screen_Manager, and the new panel
is simply stacked on top of the MainScreen. Returning to the main screen therefore
requires nothing more than destroying the PlaylistScreen, as shown:
The PlaylistScreen simply removes itself from the ScreenManager to return to the
MainScreen.
This mechanism works fine for simple applications, but begins to have drawbacks as
the complexity of the application grows. One drawback is that this will only work if each
panel covers the entire display screen. If it did not, the old panel might still be visible
behind the new panel. In some cases this is desired, but if not a different method for
changing the displayed panel needs to be used.
A different approach to the problem involves creating all of the panels that may be
required by the application at system startup, and keeping pointers to these panels in an
application defined panel array. In this case, the Panels are never Destroyed or re-
created, they are simply Linked and Unlinked from the Pm_Screen_Manager as the
user navigates from screen to screen within the user interface. These are called
Persistent Panels because they are not re-created and deleted when needed, they are
always present in memory and they are simply displayed when required. The drawback
to persistent panels is that they can require a much larger heap space if you have a
large number of panels defined in your application, since all the panels are allocated at
once during system startup.
A less obvious advantage to persistent panels is they always re-appear in the same
state as they were left, unless the application software forces a change. Therefore, as
an example, if a panel has child toggle buttons for setting various options of the device,
these buttons need to be initialized to the proper state when the panel is constructed.
This means the proper state in this case must be stored off in some external data
structure that remembers the status of each setting.
With persistent panels, the panel is never re-constructed after the intial device power-
on. Therefore, each time the panel is displayed, the child toggle buttons are always in
the correct state, reflecting the last user setting, and no external structure for storing the
button states is required.