I have been trying to make the signature++ sample in the palm knowledge base
work in my palm os 4.1 device and I am having a really hard time with that.
I am not sure what changes will be required and how the bitmap will work for
the newer palm devices. Has anybody had any success with it? Here is the
code from the palm knowledge base. I am working with CW R 6, IDE version
4.0.1. Any help will be highly appreciated.
>From the palm knowledge base:
This sample shows how to capture a signature and convert it into a bitmap.
It also shows how to use a gadget to capture pen input and how to set up the
clipping region to a particular rectangle on the screen. Please note that
this sample code demonstrates a method that should not be used with Palm OS�
release 3.5 or higher. Instead, the Windows API available for Palm OS
release 3.5 or higher should be used in your application. Also, because
there is no API in the Palm OS prior to release 3.5 for converting a screen
rectangle into a bitmap, this sample includes code that is not supported and
will work only on Palm OS 2.x, 3.0, 3.1, and 3.2. This sample creates only a
noncompressed, 1-bit-deep bitmap.Three header files, KeyPrv.h, SysEvtPrv.h,
and SystemPrv.h, are needed to compile the sample code. All three of these
header files are in the Palm OS release 3.0 SDK. The SystemPrv.h header file
is in the Palm OS release 3.1 and Palm VII SDKs included with Metrowerks
CodeWarrior for the Palm OS R6, but not the other two files.
/***********************************************************************
SAMPLE NAME: Signature++
FILE: Signature.c
DESCRIPTION: Implementation file for the signature++ sample
**********************************************************************/
#include <Pilot.h> // all the system toolbox headers
#include <SysEvtMgr.h> // Needed for search for EvtSysEventAvail
#include <FeatureMgr.h> // Needed to get the ROM version
#include "SignatureAppRsc.h" // application resource defines
/***********************************************************************
* Global defines for this module
**********************************************************************/
#define version20 0x02000000 // Palm OS 2.0 version number
#define version32 0x03200000 // Palm OS 3.2 version number
#define DB_NAME "BitmapDB:dsSP"
#define DB_TYPE 'DATA'
#define DB_CREATOR 'dsSP'
/***********************************************************************
* Global variables for this module
**********************************************************************/
static BitmapPtr gBitmapPtr = NULL; // This will point to our signature
bitmap
static DmOpenRef gBitmapDB = NULL; // This will hold a reference to our DB
/***********************************************************************
* Prototypes for internal functions
**********************************************************************/
static Boolean StartApplication(void);
static void StopApplication(void);
static VoidPtr GetObjectPtr(Int objectID);
static FieldPtr GetFocusObjectPtr(void);
static BitmapPtr GetSignatureBitmap( RectangleType* theBoundsPtr );
static void GetSignatureGadgetBounds( RectangleType* theBoundsPtr );
static void CaptureSignature(void);
static void MainViewInit(FormPtr theFormPtr);
static Boolean MainViewHandleEvent(EventPtr event);
static Boolean ApplicationHandleEvent(EventPtr event);
static void EventLoop(void);
/***********************************************************************
*
* FUNCTION: RomVersionCompatible
*
* DESCRIPTION: Check that the ROM version meets your
* minimum and maximum requirement. Warn if the app was
* switched to.
*
* PARAMETERS: minVersion - minimum rom version required
* (see sysFtrNumROMVersion in SystemMgr.h
* for format)
* maxVersion - maximum rom version required
* launchFlags - flags indicating how the application was
* launched. A warning is displayed only if
* these flags indicate that the app is
* launched normally.
*
* RETURNED: zero if rom is compatible else an error code
*
***********************************************************************/
static Err RomVersionCompatible(DWord minVersion, DWord maxVersion, Word
launchFlags)
{
DWord romVersion;
SWord theShortVersion;
// See if we're on a version of the ROM that we can run safely on.
// The system records the version number in a feature. A feature is a
// piece of information which can be looked up by a creator and feature
// number.
FtrGet(sysFtrCreator, sysFtrNumROMVersion, &romVersion);
theShortVersion = romVersion >> 16;
if ( (theShortVersion < (minVersion >> 16)) ||
(theShortVersion > (maxVersion >> 16)) )
{
// If the user launched the app from the launcher, explain
// why the app shouldn't run. If the app was contacted for something
// else, like it was asked to find a string by the system find, then
// don't bother the user with a warning dialog. These flags tell how
// the app was launched to decided if a warning should be displayed.
if ((launchFlags & (sysAppLaunchFlagNewGlobals | sysAppLaunchFlagUIApp))
==
(sysAppLaunchFlagNewGlobals | sysAppLaunchFlagUIApp))
{
FrmAlert (RomIncompatibleAlert);
// Pilot 1.0 will continuously relaunch this app unless we switch to
// another safe one. The sysFileCDefaultApp is considered "safe".
if (romVersion < 0x02000000)
AppLaunchWithCommand(sysFileCDefaultApp, sysAppLaunchCmdNormalLaunch,
NULL);
}
return (sysErrRomIncompatible);
}
return 0;
}
/***********************************************************************
*
* FUNCTION: GetObjectPtr
*
* DESCRIPTION: P10. This routine returns a pointer to an object in the
active form.
*
* PARAMETERS: objectID - id of the object
*
* RETURNED: pointer to the object's data structure
*
***********************************************************************/
static VoidPtr GetObjectPtr(Int objectID)
{
FormPtr frm;
frm = FrmGetActiveForm();
return(FrmGetObjectPtr(frm, FrmGetObjectIndex(frm, objectID)));
}
/***********************************************************************
*
* FUNCTION: GetFocusObjectPtr
*
* DESCRIPTION: This routine returns a pointer to the field object, in
* the current form, that has the focus.
*
* PARAMETERS: nothing
*
* RETURNED: pointer to a field object or NULL of there is no focus
*
***********************************************************************/
static FieldPtr GetFocusObjectPtr(void)
{
FormPtr frm;
Int focus;
// Get a pointer to tha active form and the index of the form object with
focus.
frm = FrmGetActiveForm();
focus = FrmGetFocus(frm);
// If no object has the focus return NULL pointer.
if (focus == noFocus)
return(NULL);
// Return a pointer to the object with focus.
return(FrmGetObjectPtr(frm, focus));
}
/***********************************************************************
/ MAJOR CHANGES FROM THE STARTER PROJECT TEMPLATE BEGIN HERE
/***********************************************************************
/***********************************************************************
*
* FUNCTION: StartApplication
*
* DESCRIPTION: This routine sets up the initial state of the application.
* It opens the application's database and sets up global
variables.
*
* PARAMETERS: None.
*
* RETURNED: true if error (database couldn't be created)
*
***********************************************************************/
static Boolean StartApplication(void)
{
Err theError;
UInt theIndex = 0;
VoidHand theRecHandle;
VoidPtr theRecPtr;
ULong theSize;
// Check and see if our application's database exists. If not, then
// create it. This database will be used to store the bitmap.
gBitmapDB = DmOpenDatabaseByTypeCreator(DB_TYPE, DB_CREATOR,
dmModeReadWrite);
if (!gBitmapDB)
{
// Create the database
theError = DmCreateDatabase(0, DB_NAME, DB_CREATOR, DB_TYPE, false);
if (theError) return theError;
// Then open it
gBitmapDB = DmOpenDatabaseByTypeCreator(DB_TYPE, DB_CREATOR,
dmModeReadWrite);
if (!gBitmapDB) return (1);
}
else
{
// Try to find an existing bitmap. If one exists, then use that
// as the default bitmap;
if (DmNumRecords( gBitmapDB ) > 0)
{
// Grab out database record and lock it down if it exists
theRecHandle = DmGetRecord( gBitmapDB, theIndex );
if (theRecHandle)
{
theRecPtr = MemHandleLock( theRecHandle );
// Copy the data from the record into the bitmap pointer global
theSize = MemPtrSize(theRecPtr);
gBitmapPtr = MemPtrNew( theSize );
MemMove( gBitmapPtr, theRecPtr, theSize );
// Finally, unlock the record handle
MemHandleUnlock( theRecHandle );
}
}
}
return false;
}
/***********************************************************************
*
* FUNCTION: StopApplication
*
* DESCRIPTION: This routine closes the application's database
* and saves the current state of the application.
*
* PARAMETERS: nothing
*
* RETURNED: nothing
*
***********************************************************************/
static void StopApplication(void)
{
UInt theIndex = 0;
VoidHand theRecHandle;
VoidPtr theRecPtr;
ULong theSize;
// Save out the bitmap to the application database
// First remove any existing record
if (DmNumRecords( gBitmapDB ) > 0)
DmRemoveRecord( gBitmapDB, theIndex );
if (gBitmapPtr)
{
// Create a record from our bitmap
theSize = MemPtrSize( gBitmapPtr );
theRecHandle = DmNewHandle( gBitmapDB, theSize );
if (!theRecHandle)
return;
// Copy the bitmap data into the new record
theRecPtr = MemHandleLock( theRecHandle );
DmWrite( theRecPtr, 0, gBitmapPtr, theSize );
MemHandleUnlock( theRecHandle );
// Now, attach the new record to the database
DmAttachRecord( gBitmapDB, &theIndex, theRecHandle, NULL );
}
// Close the application's database
DmCloseDatabase( gBitmapDB );
}
/***********************************************************************
*
* FUNCTION: GetSignatureBitmap
*
* DESCRIPTION: This routine converts the screen drawing into a bitmap
* WARNING: THIS CODE IS NOT SUPPORTED CODE AND MAY NOT WORK
* ON DEVICES WHOSE OS VERSION IS OTHER THAN 2.X, 3.0,
* 3.1, OR 3.2.
*
* PARAMETERS: theBoundsPtr - the bounds of the gadget
*
* RETURNED: A pointer to the bitmap
*
***********************************************************************/
static BitmapPtr GetSignatureBitmap( RectangleType* theBoundsPtr )
{
WinHandle theWindowHandle;
Word theError;
BitmapPtr theBitmapPtr = NULL;
Word theRowBytes, theHeight;
// First, free the previous bitmap if it exists
if (gBitmapPtr)
{
MemPtrFree( gBitmapPtr );
gBitmapPtr = NULL;
}
// Create an offscreen window to copy the bits bounded by the gadget into.
// This will make converting the window into a bitmap a little easier for
us
// You could just copy the screen bits directly into the bitmap, but that
// would require more pointer arithmetic and POSE complains when you read
// directly from the screen.
theWindowHandle = WinCreateOffscreenWindow( theBoundsPtr->extent.x,
theBoundsPtr->extent.y, screenFormat, &theError );
if (!theError)
{
// Now, copy the gadgets screen rectangle into the new window. This will
offset
// the screen bits to (0, 0) in the offscreen window.
WinCopyRectangle( NULL, theWindowHandle, theBoundsPtr, 0, 0, scrCopy );
// Now, this is the tricky part. There is no API for getting the bits on
the screen
// into a bitmap, so this code is unsupported and will only work on Palm
OS 2.x, 3.0,
// 3.1, and 3.2 devices. This is why we limit this sample to only those
versions in
// the RomVersionCompatible function. This code will also only work on a
device with
// a screen depth of 1.
// WARNING: THIS CODE IS NOT SUPPORTED CODE AND MAY NOT WORK ON DEVICES
// WHOSE OS VERSION IS OTHER THAN 2.X, 3.0, 3.1, OR 3.2
// Cache a couple of important bits of information
theRowBytes = theWindowHandle->gDeviceP->rowBytes;
theHeight = theWindowHandle->gDeviceP->height;
// Now, allocate our bitmap and set all the important bits of information.
theBitmapPtr = MemPtrNew( sizeof(BitmapType) + (theRowBytes*theHeight) );
if (theBitmapPtr)
{
MemSet( theBitmapPtr, sizeof(BitmapType) + (theRowBytes*theHeight), 0 );
theBitmapPtr->width = theWindowHandle->gDeviceP->width;
theBitmapPtr->height = theWindowHandle->gDeviceP->height;
theBitmapPtr->rowBytes = theWindowHandle->gDeviceP->rowBytes;
theBitmapPtr->pixelSize = theWindowHandle->gDeviceP->pixelSize;
theBitmapPtr->nextDepthOffset = NULL;
// CreateOffscreenWindow does not, by default, create a compressed window
theBitmapPtr->flags.compressed = theWindowHandle->gDeviceP->compressed;
// All bitmaps are version 1 bitmaps without a color table.
theBitmapPtr->version = 1;
theBitmapPtr->flags.hasColorTable = 0;
// Move the offscreen bits into our bitmap. The baseAddr field
// contains the bit array of our bitmap for 1-bit, uncompressed bitmaps.
MemMove( (Ptr)((ULong)(theBitmapPtr) + sizeof(BitmapType)),
theWindowHandle->gDeviceP->baseAddr, theRowBytes * theHeight );
}
// Delete the window that we created with WinCreateOffscreenWindow
WinDeleteWindow( theWindowHandle, false );
}
// Finally, return our bitmap
return theBitmapPtr;
}
/***********************************************************************
*
* FUNCTION: GetSignatureGadgetBounds
*
* DESCRIPTION: This routine grabs the bounds of the signature gadget
*
* PARAMETERS: theBoundsPtr - the bounds of the gadget
*
* RETURNED: nothing
*
***********************************************************************/
static void GetSignatureGadgetBounds( RectangleType* theBoundsPtr )
{
FormPtr theFormPtr;
FormGadgetType* theGadgetPtr;
theFormPtr = FrmGetActiveForm();
theGadgetPtr = GetObjectPtr( MainSignatureGadget );
FrmGetObjectBounds( theFormPtr,
FrmGetObjectIndex(theFormPtr, MainSignatureGadget), theBoundsPtr );
}
/***********************************************************************
*
* FUNCTION: CaptureSignature
*
* DESCRIPTION: This routine captures the signature and converts it
* into a bitmap
*
* PARAMETERS: None
*
* RETURNED: nothing
*
***********************************************************************/
static void CaptureSignature()
{
SWord x, y, prevX, prevY;
Boolean penDown;
RectangleType theClipRectangle;
RectangleType theGadgetBounds;
// Grab the gadget's bounds
GetSignatureGadgetBounds( &theGadgetBounds );
// Grab the coordinates of the pen
EvtGetPen( &prevX, &prevY, &penDown );
// Save off the current clip rectangle and set the new clipping
// rectangle to be the bounds of the signature gadget.
WinGetClip( &theClipRectangle );
WinSetClip( &theGadgetBounds );
// Track the pen
do
{
EvtGetPen(&x, &y, &penDown);
// Don't bother to do anything if the user hasn't moved
// the pen!
if ((x != prevX || y != prevY))
{
WinDrawLine( prevX, prevY, x, y );
prevX = x;
prevY = y;
}
} while (penDown);
// Turn the drawing into a bitmap and save the bitmap in a global
gBitmapPtr = GetSignatureBitmap( &theGadgetBounds );
// Restore the old clipping rectangle
WinSetClip( &theClipRectangle );
}
/***********************************************************************
*
* FUNCTION: MainViewInit
*
* DESCRIPTION: Initializes for the "main" form.
*
* PARAMETERS: theFormPtr - a pointer to the form
*
* RETURNED: nothing
*
***********************************************************************/
static void MainViewInit( FormPtr theFormPtr )
{
RectangleType theBounds;
GetSignatureGadgetBounds( &theBounds );
// Draw a frame around our gadget so that users know where to sign
WinDrawRectangleFrame( simpleFrame, &theBounds );
// Draw the signature bitmap if it exists (it would have been setup
// by StartApplication)
if (gBitmapPtr)
WinDrawBitmap( gBitmapPtr, theBounds.topLeft.x, theBounds.topLeft.y );
}
/***********************************************************************
*
* FUNCTION: MainViewHandleEvent
*
* DESCRIPTION: Handles processing of events for the "main" form.
*
* PARAMETERS: event - the most recent event.
*
* RETURNED: True if the event is handled, false otherwise.
*
***********************************************************************/
static Boolean MainViewHandleEvent(EventPtr event)
{
Boolean handled = false;
FormPtr theFormPtr;
SWord x, y;
Boolean penDown;
RectangleType theGadgetBounds;
switch (event->eType)
{
// A frmUpdateEvent will only come through if we explicitly call
FrmUpdateForm,
// or if a dialog was opened over our form and there wasn't enough memory
to save
// the bits behind the dialog.
case frmUpdateEvent:
theFormPtr = FrmGetActiveForm();
// If a bitmap ptr exists, then draw it.
if (gBitmapPtr)
{
// Grab the gadget's bounds
GetSignatureGadgetBounds( &theGadgetBounds );
// Draw the signature bitmap
WinDrawBitmap( gBitmapPtr, theGadgetBounds.topLeft.x,
theGadgetBounds.topLeft.y );
}
// Note that we don't set handled to true. This is so the OS will
// tell the rest of the form to redraw itself.
break;
case ctlSelectEvent:
if (event->data.ctlSelect.controlID == MainClearButton)
{
// Grab the gadget's bounds
GetSignatureGadgetBounds( &theGadgetBounds );
// Erase the rectangle
WinEraseRectangle( &theGadgetBounds, 0 );
// Free the memory held by the bitmap
if (gBitmapPtr)
{
MemPtrFree( gBitmapPtr );
gBitmapPtr = NULL;
}
}
break;
case penDownEvent:
// Grab the bounds for the signature gadget
GetSignatureGadgetBounds( &theGadgetBounds );
// Grab the location of the pen down event
EvtGetPen( &x, &y, &penDown );
// Capture the signature if the point was within the signature
// gadget's bounds
if (RctPtInRectangle( x, y, &theGadgetBounds) )
{
CaptureSignature();
handled = true;
}
break;
case frmOpenEvent:
theFormPtr = FrmGetActiveForm();
// Initialize the main view
MainViewInit(theFormPtr);
// Draw the form.
FrmDrawForm( theFormPtr );
handled = true;
break;
case menuEvent:
if (event->data.menu.itemID == OptionsAboutSignature)
{
MenuEraseStatus( 0 );
AbtShowAbout( DB_CREATOR );
handled = true;
}
break;
}
return(handled);
}
/***********************************************************************
/ MAJOR CHANGES FROM THE STARTER PROJECT TEMPLATE END HERE
/***********************************************************************
/***********************************************************************
*
* FUNCTION: ApplicationHandleEvent
*
* DESCRIPTION: This routine loads a form resource and sets the event
handler for the form.
*
* PARAMETERS: event - a pointer to an EventType structure
*
* RETURNED: True if the event has been handled and should not be
* passed to a higher level handler.
*
***********************************************************************/
static Boolean ApplicationHandleEvent(EventPtr event)
{
FormPtr frm;
Int formId;
Boolean handled = false;
if (event->eType == frmLoadEvent)
{
// Load the form resource specified in the event then activate the form.
formId = event->data.frmLoad.formID;
frm = FrmInitForm(formId);
FrmSetActiveForm(frm);
// Set the event handler for the form. The handler of the currently
// active form is called by FrmDispatchEvent each time it receives an
event.
switch (formId)
{
case MainForm:
FrmSetEventHandler(frm, MainViewHandleEvent);
break;
}
handled = true;
}
return handled;
}
/***********************************************************************
*
* FUNCTION: EventLoop
*
* DESCRIPTION: A simple loop that obtains events from the Event
* Manager and passes them on to various applications and
* system event handlers before passing them on to
* FrmDispatchEvent for default processing.
*
* PARAMETERS: None.
*
* RETURNED: Nothing.
*
***********************************************************************/
static void EventLoop(void)
{
EventType event;
Word error;
do
{
// Get the next available event.
EvtGetEvent(&event, evtWaitForever);
// Give the system a chance to handle the event.
if (! SysHandleEvent(&event))
// Give the menu bar a chance to update and handle the event.
if (! MenuHandleEvent(0, &event, &error))
// Give the application a chance to handle the event.
if (! ApplicationHandleEvent(&event))
// Let the form object provide default handling of the event.
FrmDispatchEvent(&event);
}
while (event.eType != appStopEvent);
}
/***********************************************************************
*
* FUNCTION: PilotMain
*
* DESCRIPTION: This function is the equivalent of a main() function
* under standard "C". It is called by the Emulator to begin
* execution of this application.
*
* PARAMETERS: cmd - command specifying how to launch the application.
* cmdPBP - parameter block for the command.
* launchFlags - flags used to configure the launch.
*
* RETURNED: Any applicable error codes.
*
***********************************************************************/
DWord PilotMain(Word cmd, Ptr cmdPBP, Word launchFlags)
{
Word error; // Error starting the app
// This app makes use of PalmOS 2.0 features. It will crash if
// run on an earlier version of PalmOS. Detect and warn if this happens,
// then exit.
error = RomVersionCompatible (version20, version32, launchFlags);
if (error)
return error;
// Check for a normal launch.
if (cmd == sysAppLaunchCmdNormalLaunch)
{
// Initialize the application's global variables and database.
if (!StartApplication())
{
// Start the first form.
FrmGotoForm(MainForm);
// Start the event loop.
EventLoop();
// Clean up before exiting the applcation.
StopApplication();
}
}
return 0;
}
--
For information on using the Palm Developer Forums, or to unsubscribe, please
see http://www.palmos.com/dev/support/forums/