home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
pentlk11.zip
/
STROKE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-13
|
65KB
|
1,184 lines
/******************************************************************************
* *
* Name: STROKE.C *
* *
* Copyright : COPYRIGHT IBM CORPORATION, 1993 *
* LICENSED MATERIAL - PROGRAM PROPERTY OF IBM *
* *
* Description: This program processes all of the ink related functions *
* for the application. *
* *
* DISCLAIMER OF WARRANTIES. The following [enclosed] code is *
* sample code created by IBM Corporation. This sample code is not *
* part of any standard or IBM product and is provided to you solely *
* for the purpose of assisting you in the development of your *
* applications. The code is provided "AS IS", without *
* warranty of any kind. IBM shall not be liable for any damages *
* arising out of your use of the sample code, even if they have been *
* advised of the possibility of such damages. *
* *
******************************************************************************/
#define INCL_PM
#define INCL_DOS
/******************************************************************************
* System include files *
******************************************************************************/
#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <penpm.h>
/******************************************************************************
* Application specific include file *
******************************************************************************/
#include "stroke.h"
/******************************************************************************
* Exported routines *
******************************************************************************/
HWND APIENTRY InitTimedInk ( HWND, MMTIME * );
BOOL APIENTRY PlayTimedInk ( HWND );
BOOL APIENTRY StopTimedInk ( HWND );
BOOL APIENTRY RecordTimedInk ( HWND );
BOOL APIENTRY PurgeTimedInk ( HWND );
BOOL APIENTRY DestroyTimeInk ( HWND );
MRESULT EXPENTRY InkWinProc ( HWND, ULONG, MRESULT, MRESULT );
BOOL APIENTRY InkTimedInk ( HWND, MMTIME );
/******************************************************************************
* Internal routines *
******************************************************************************/
ULONG TimeToPoints ( PMYWINDOWDATA, MMTIME );
BOOL InkStroke ( PMYWINDOWDATA, ULONG );
BOOL AppendStrokes ( PMYWINDOWDATA, PSTROKEDATA );
BOOL ScaleStrokeData ( PMYWINDOWDATA );
BOOL EraseTimedInk ( PMYWINDOWDATA );
/******************************************************************************
* Used to track the current time reported from Multimedia. *
******************************************************************************/
MMTIME *pCurrMMTime;
/******************************************************************************
* *
* Subroutine: InitTimedInk *
* *
* Function: This function performs the initialization for the inking *
* window. It allocates a block of memory for the data structure *
* used by the inking window. It then creates a transparent window *
* to ink into. *
* *
* Parameters: hwndParent - is the window handle to the parent window. The *
* parent window will be the window containing the *
* image to be annotated. *
* *
* Internal *
* References: None *
* *
* Pen For OS2 *
* References: None *
* *
******************************************************************************/
HWND APIENTRY InitTimedInk ( HWND hwndParent, MMTIME *pMMTime )
{
PMYWINDOWDATA pMyWindowData;
APIRET rc;
HAB hab;
HMQ hmq;
QMSG qmsg;
HWND hwndInking;
static BOOL WindowClassRegistered = FALSE;
RECTL rcl;
pMyWindowData = (PMYWINDOWDATA) malloc ( sizeof ( MYWINDOWDATA ) );
/***************************************************************************
* Verify that the memory for the data structure has been allocated. If not *
* return a NULLHANDLE to signify an error condition. *
***************************************************************************/
if ( pMyWindowData == NULL )
{
return ( NULLHANDLE );
};
pCurrMMTime = pMMTime;
pMyWindowData->hwndParent = hwndParent;
pMyWindowData->hab = WinQueryAnchorBlock ( hwndParent );
/***************************************************************************
* Register the window class for the inking window, if it has not already *
* been done. *
***************************************************************************/
if ( !WindowClassRegistered )
{
/************************************************************************
* When the class is registered, reserve 4 more bytes to keep the *
* pointer to pMyWindowData structure. *
************************************************************************/
if ( !WinRegisterClass ( pMyWindowData->hab,
WC_INK_WINDOW,
InkWinProc,
CS_SYNCPAINT,
sizeof ( PMYWINDOWDATA ) ) )
{
/*********************************************************************
* If the class has not been registered return a NULLHANDLE to *
* signify an error condition. *
*********************************************************************/
free ( pMyWindowData );
return ( NULLHANDLE );
};
/************************************************************************
* If all goes well, set flag to indicate that the class has been *
* already been registered. *
************************************************************************/
WindowClassRegistered = TRUE;
};
/***************************************************************************
* Determine the size of the window, then create then inking window. *
***************************************************************************/
WinQueryWindowRect ( pMyWindowData->hwndParent, &rcl );
hwndInking = WinCreateWindow ( pMyWindowData->hwndParent,
WC_INK_WINDOW,
NULL,
0,
0,
0,
rcl.xRight,
rcl.yTop,
pMyWindowData->hwndParent,
HWND_TOP,
ID_INK_WINDOW,
(PVOID) pMyWindowData,
NULL );
/***************************************************************************
* Verify that the window has been created. If not return NULLHANDLE to *
* signify an error condition, else return the handle to the inking window. *
***************************************************************************/
if ( !hwndInking )
{
free ( pMyWindowData );
return ( NULLHANDLE );
};
return ( hwndInking );
}
/******************************************************************************
* *
* Subroutine: DestroyTimedInk *
* *
* Function: This function performs the cleanup for the inking window and *
* the associated memory. *
* *
* Parameters: hwndParent - is the window handle to the parent window. The *
* parent window will be the window containing the *
* image to be annotated. *
* *
* Internal *
* References: EraseTimedInk - Cleans up display of window *
* PurgeTimedInk - Purge previous recording *
* *
* Pen For OS2 *
* References: None *
* *
******************************************************************************/
BOOL APIENTRY DestroyTimedInk ( HWND hWnd )
{
PMYWINDOWDATA pMyWindowData;
HWND hwndAudio;
/***************************************************************************
* Get pointer to the window data. *
***************************************************************************/
pMyWindowData = (PMYWINDOWDATA) WinQueryWindowPtr ( hWnd, 0 );
/*****************************************************************
* Close the audio dialog window along with this window. *
*****************************************************************/
if (hwndAudio = WinWindowFromID(pMyWindowData->hwndParent,
IDD_AUDIO))
{
WinSendMsg(hwndAudio,
WM_CLOSE,
(MPARAM) NULL,
(MPARAM) NULL);
};
EraseTimedInk ( pMyWindowData );
PurgeTimedInk ( pMyWindowData->hwnd );
WinDestroyWindow ( pMyWindowData->hwnd );
free ( pMyWindowData );
pMyWindowData = (PMYWINDOWDATA) NULL;
return ( IME_NO_ERROR );
}
/******************************************************************************
* *
* Subroutine: ScaleStrokeData *
* *
* Function: Converts stroke data in high resolution to screen resolution. *
* *
* Parameters: hWnd - Window handle for the inking window. *
* *
* Internal *
* References: AppendStrokes - Appends new stroke to linked list pointer to by *
* pStrokeHead *
* *
* Pen For OS2 *
* References: WrtMapPointLong - Scales stroke data from one resolution to *
* another. *
* *
******************************************************************************/
BOOL ScaleStrokeData ( PMYWINDOWDATA pMyWindowData )
{
PSTROKEDATA pTempStrokeHead;
PSTROKEDATA pTempCurrStroke;
PSTROKEDATA pStrokeScaled;
RECTL rcl;
/***************************************************************************
* If the high resolution stroke data hasn't been scaled yet, then allocate *
* memory for the scaled stroke data. *
***************************************************************************/
if ( !pMyWindowData->pScaledHead )
{
/************************************************************************
* Start off by saving the pointer to the high resolution stroke data, *
* setting the pointer to the current stroke to convert, and then *
* resetting the stroke head pointer to null. *
************************************************************************/
pTempStrokeHead = pMyWindowData->pStrokeHead;
pTempCurrStroke = pMyWindowData->pStrokeHead;
pMyWindowData->pStrokeHead = NULL;
/************************************************************************
* For every stroke in the high resolution stroke data linked list, *
* allocate memory for the scaled stroke, copy high resolution stroke *
* information to the scaled stroke structure, allocate memory for the *
* scaled point information, and append new stroke to linked list. *
************************************************************************/
while ( pTempCurrStroke )
{
pStrokeScaled = (PSTROKEDATA) malloc ( sizeof(STROKEDATA) );
memcpy ( pStrokeScaled,
pTempCurrStroke,
sizeof(STROKEDATA) );
pStrokeScaled->pXY = (PPOINTL) malloc ( sizeof(POINTL) *
pStrokeScaled->ulNumPoints );
AppendStrokes ( pMyWindowData, pStrokeScaled );
pTempCurrStroke = pTempCurrStroke->psdFwd;
};
/************************************************************************
* pStrokeHead now points to a linked list of stroke headers for the *
* scaled stroke data. Each stroke in this list has a pointer to an *
* array of POINTL data structures, however the points in the array have *
* not yet been set. Save the pointer to the new linked list and restore *
* the pointer to the high resolution linked list. *
************************************************************************/
pMyWindowData->pScaledHead = pMyWindowData->pStrokeHead;
pMyWindowData->pStrokeHead = pTempStrokeHead;
};
/***************************************************************************
* For each stroke in the linked list, copy the high resolution point data, *
* and then scale it to the appropriate size. *
***************************************************************************/
WinQueryWindowRect ( pMyWindowData->hwnd, &rcl );
pTempCurrStroke = pMyWindowData->pStrokeHead;
pStrokeScaled = pMyWindowData->pScaledHead;
while ( pTempCurrStroke )
{
memcpy ( pStrokeScaled->pXY,
pTempCurrStroke->pXY,
sizeof(POINTL) * pStrokeScaled->ulNumPoints );
/************************************************************************
* WrtMapPointLong will convert the input points to a new resolution. *
* The things to note here are that: 1) NULLHANDLE is used as the input *
* window handle; and 2) the calculation for the extents. The NULLHANDLE *
* is used since we have already asked for the coordinates to be *
* adjusted relative to the window at liftoff time. The documentation *
* can be confusing on this point. If we were to provide the window *
* for this window, then all of the points would be offset by the *
* position of the window relative to the desktop origin. The extents *
* are adjusted for changes in the window size. There is an inverse *
* relationship between the extents and ink. Increase the extents and *
* ink will be shrink. Decrease the extents and the ink will expand. *
************************************************************************/
WrtMapPointLong(NULLHANDLE,
pStrokeScaled->pXY,
MP_SCALE,
((pStrokeScaled->ulXExtent * pMyWindowData->OrgWindowSize.cx) / rcl.xRight),
((pStrokeScaled->ulYExtent * pMyWindowData->OrgWindowSize.cy) / rcl.yTop ),
0UL,
0UL,
pStrokeScaled->ulNumPoints);
pTempCurrStroke = pTempCurrStroke->psdFwd;
pStrokeScaled = pStrokeScaled->psdFwd;
};
return ( IME_NO_ERROR );
}
/******************************************************************************
* *
* Subroutine: PlayTimedInk *
* *
* Function: Initializes data structure for playback of a recording. *
* *
* Parameters: hWnd - Window handle for the inking window. *
* *
* Internal *
* References: EraseTimedInk - Cleanup display of window *
* ScaleStrokeData - Scale data from high resolution *
* *
* Pen For OS2 *
* References: None *
* *
******************************************************************************/
BOOL APIENTRY PlayTimedInk ( HWND hWnd )
{
PMYWINDOWDATA pMyWindowData;
/***************************************************************************
* Get pointer to the window data. *
***************************************************************************/
pMyWindowData = (PMYWINDOWDATA) WinQueryWindowPtr ( hWnd, 0 );
EraseTimedInk ( pMyWindowData );
/***************************************************************************
* Convert high resolution stroke data to screen resolution *
***************************************************************************/
if ( !pMyWindowData->pScaledHead )
{
ScaleStrokeData ( pMyWindowData );
};
/***************************************************************************
* Prepare to playback the timed ink by setting current stroke to first *
* stroke in linked list. If the first stroke exists set pointer to current *
* point and set the number of points remaining to be inked for the current *
* stroke. *
***************************************************************************/
pMyWindowData->pCurrStroke = pMyWindowData->pScaledHead;
if ( pMyWindowData->pCurrStroke != NULL )
{
pMyWindowData->NumPointsLeft = pMyWindowData->pCurrStroke->ulNumPoints;
pMyWindowData->pCurrPoint = pMyWindowData->pCurrStroke->pXY;
};
/***************************************************************************
* Set flags to indicate current state. *
***************************************************************************/
pMyWindowData->fPlay = TRUE;
pMyWindowData->fRecord = FALSE;
return ( IME_NO_ERROR );
}
/******************************************************************************
* *
* Subroutine: RecordTimedInk *
* *
* Function: Initializes application in preparation to record timed ink. *
* *
* Parameters: hWnd - Window handle for inking window *
* *
* Internal *
* References: EraseTimedInk - Cleanup display of window *
* PurgeTimedInk - Purge previous recording *
* *
* Pen For OS2 *
* References: None *
* *
******************************************************************************/
BOOL APIENTRY RecordTimedInk ( HWND hWnd )
{
PMYWINDOWDATA pMyWindowData;
APIRET rc;
/***************************************************************************
* Get pointer to the window data. *
***************************************************************************/
pMyWindowData = (PMYWINDOWDATA) WinQueryWindowPtr ( hWnd, 0 );
/***************************************************************************
* Cleanup the window for the next recording. *
***************************************************************************/
EraseTimedInk ( pMyWindowData );
/***************************************************************************
* Free all of the old stroke data. *
***************************************************************************/
if ( pMyWindowData->pStrokeHead != NULL )
{
PurgeTimedInk ( hWnd );
}
/***************************************************************************
* Set flags to indicate current state. *
***************************************************************************/
pMyWindowData->fPlay = FALSE;
pMyWindowData->fRecord = TRUE;
return ( IME_NO_ERROR );
}
/******************************************************************************
* *
* Subroutine: EraseTimedInk *
* *
* Function: Removes ink from the transparent inking window. *
* *
* Parameters: pMyWindowData - Pointer to windon specific information *
* *
* Internal *
* References: None *
* *
* Pen For OS2 *
* References: None *
* *
******************************************************************************/
BOOL EraseTimedInk ( PMYWINDOWDATA pMyWindowData )
{
RECTL rcl;
/***************************************************************************
* Force the window to be repainted but without showing handwritten part. *
***************************************************************************/
GpiDeleteSegments ( pMyWindowData->hps, 1, pMyWindowData->NumSegments );
pMyWindowData->NumSegments = 0;
WinQueryWindowRect ( pMyWindowData->hwndParent, &rcl );
WinInvalidateRect ( pMyWindowData->hwndParent, &rcl, TRUE);
/***************************************************************************
* Set flags to indicate current state. *
***************************************************************************/
pMyWindowData->fPlay = FALSE;
pMyWindowData->fRecord = FALSE;
return ( IME_NO_ERROR );
}
/******************************************************************************
* *
* Subroutine: StopTimedInk *
* *
* Function: Stops recording of timed ink. *
* *
* Parameters: hWnd - Window handle for inking window *
* *
* Internal *
* References: None *
* *
* Pen For OS2 *
* References: None *
* *
******************************************************************************/
BOOL APIENTRY StopTimedInk ( HWND hWnd )
{
RECTL rcl;
PMYWINDOWDATA pMyWindowData;
/***************************************************************************
* Get pointer to the window data. *
***************************************************************************/
pMyWindowData = (PMYWINDOWDATA) WinQueryWindowPtr ( hWnd, 0 );
/***************************************************************************
* Set flags to indicate current state. *
***************************************************************************/
pMyWindowData->fPlay = FALSE;
pMyWindowData->fRecord = FALSE;
return ( IME_NO_ERROR );
}
/******************************************************************************
* *
* Subroutine: PurgeTimedInk *
* *
* Function: Purges all strokes from memory. *
* *
* Parameters: hWnd - Window handle for inking window *
* *
* Internal *
* References: None *
* *
* Pen For OS2 *
* References: None *
* *
******************************************************************************/
BOOL APIENTRY PurgeTimedInk ( HWND hWnd )
{
PMYWINDOWDATA pMyWindowData;
PSTROKEDATA pTempStroke;
/***************************************************************************
* Get pointer to the window data. *
***************************************************************************/
pMyWindowData = (PMYWINDOWDATA) WinQueryWindowPtr ( hWnd, 0 );
/***************************************************************************
* Set flags to indicate current state. *
***************************************************************************/
pMyWindowData->fPlay = FALSE;
pMyWindowData->fRecord = FALSE;
pMyWindowData->pCurrStroke = pMyWindowData->pStrokeHead;
while ( pMyWindowData->pCurrStroke != NULL )
{
pTempStroke = pMyWindowData->pCurrStroke->psdFwd;
free ( pMyWindowData->pCurrStroke->pXY );
free ( pMyWindowData->pCurrStroke );
pMyWindowData->pCurrStroke = pTempStroke;
};
pMyWindowData->pStrokeHead = NULL;
pMyWindowData->pCurrStroke = pMyWindowData->pScaledHead;
while ( pMyWindowData->pCurrStroke != NULL )
{
pTempStroke = pMyWindowData->pCurrStroke->psdFwd;
free ( pMyWindowData->pCurrStroke->pXY );
free ( pMyWindowData->pCurrStroke );
pMyWindowData->pCurrStroke = pTempStroke;
};
pMyWindowData->pScaledHead = NULL;
return ( IME_NO_ERROR );
}
/******************************************************************************
* *
* Subroutine: AppendStrokes *
* *
* Function: Append a new stroke to the linked list of strokes for the *
* current recording.
* *
* Parameters: pMyWindowData - Pointer to window instance data *
* pStrokeData - Pointer to the stroke data of the stroke to be *
* appended to the linked list of strokes *
* *
* Internal *
* References: None *
* *
* Pen For OS2 *
* References: None *
* *
******************************************************************************/
BOOL AppendStrokes ( PMYWINDOWDATA pMyWindowData, PSTROKEDATA pStrokeData )
{
/***************************************************************************
* If the stroke head pointer is null, then this is the first stroke in the *
* linked list of strokes. *
***************************************************************************/
if ( pMyWindowData->pStrokeHead == NULL )
{
pMyWindowData->pStrokeHead = pStrokeData;
pMyWindowData->pCurrStroke = pStrokeData;
return ( IME_NO_ERROR );
};
/***************************************************************************
* Otherwise, append the new stroke to the end of the linked list. *
***************************************************************************/
pMyWindowData->pCurrStroke->psdFwd = pStrokeData;
pStrokeData->psdBack = pMyWindowData->pCurrStroke;
pMyWindowData->pCurrStroke = pStrokeData;
return ( IME_NO_ERROR );
}
/******************************************************************************
* *
* Subroutine: InkTimedInk *
* *
* Function: This is a recursive routine that determines the strokes and *
* points that need to be inked for this time interval. *
* *
* Parameters: hWnd - Window handle to inking window *
* ElapsedTime - This is the elapsed time ,in MMTIME units, from *
* the start of the recording *
* *
* Internal *
* References: TimeToPoints - Convert a time duration to the number of points *
* to ink for the time duration *
* InkStroke - Draw the stroke to the window *
* InkTimedInk - Determine how much more to ink *
* *
* Pen For OS2 *
* References: None *
* *
******************************************************************************/
BOOL APIENTRY InkTimedInk ( HWND hWnd, MMTIME ElapsedTime )
{
ULONG PointsToInk;
static MMTIME LastElapsedTime;
PMYWINDOWDATA pMyWindowData;
/***************************************************************************
* Get pointer to the window data. *
***************************************************************************/
pMyWindowData = (PMYWINDOWDATA) WinQueryWindowPtr ( hWnd, 0 );
/***************************************************************************
* If the pointer to the window data is null return FALSE to indicate an *
* error condition. *
***************************************************************************/
if ( pMyWindowData == NULL )
return ( IME_INVALID_POINTER );
/***************************************************************************
* If the pointer to the current stroke is null then there are no more *
* strokes remaining to be inked, so return TRUE to indicate things are ok. *
***************************************************************************/
if ( pMyWindowData->pCurrStroke == NULL )
{
return ( IME_NO_ERROR );
};
/***************************************************************************
* ulUser1 contains the start time for the stroke. If the current elapsed *
* time is less than the start time for the current stroke, then there are *
* aren't any points to ink for this time period. Save the elapsed time for *
* this call and TRUE to indicate things are ok. *
***************************************************************************/
if ( ElapsedTime < pMyWindowData->pCurrStroke->ulUser1 )
{
LastElapsedTime = ElapsedTime;
return ( IME_NO_ERROR );
};
/***************************************************************************
* ulUser2 contains the end time for the stroke. If the current elapsed *
* time is greater than or equal to the end time for the current stroke, *
* then the rest of the current stroke needs to be inked and perhaps more. *
* Thus ink the rest of this stroke, set the last elapsed time, move to the *
* next stroke and make the recursive call to determine if more points need *
* to be inked, and return. *
***************************************************************************/
if ( ElapsedTime >= pMyWindowData->pCurrStroke->ulUser2 )
{
InkStroke ( pMyWindowData, pMyWindowData->NumPointsLeft );
LastElapsedTime = pMyWindowData->pCurrStroke->ulUser2;
pMyWindowData->pCurrStroke = pMyWindowData->pCurrStroke->psdFwd;
/************************************************************************
* If there are more strokes in the linked list then move to next stroke *
************************************************************************/
if ( pMyWindowData->pCurrStroke != NULL )
{
pMyWindowData->NumPointsLeft = pMyWindowData->pCurrStroke->ulNumPoints;
pMyWindowData->pCurrPoint = pMyWindowData->pCurrStroke->pXY;
InkTimedInk ( hWnd, ElapsedTime );
};
return ( IME_NO_ERROR );
};
/***************************************************************************
* If we get to this point then only a portion of the current stroke needs *
* to be inked at this time. Determine how many points to ink, ink the *
* points, set the elapsed time, and return. *
***************************************************************************/
PointsToInk = TimeToPoints ( pMyWindowData, ElapsedTime - LastElapsedTime );
InkStroke ( pMyWindowData, PointsToInk );
LastElapsedTime = ElapsedTime;
return ( IME_NO_ERROR );
}
/******************************************************************************
* *
* Subroutine: TimeToPoints *
* *
* Function: This function calcualates and returns the number of points to *
* be inked for a given amount of time. *
* *
* Parameters: pMyWindowData - Pointer to window data *
* DeltaTime - The amount of time that needs to be inked *
* *
* Internal *
* References: None *
* *
* Pen For OS2 *
* References: None *
* *
******************************************************************************/
ULONG TimeToPoints ( PMYWINDOWDATA pMyWindowData, MMTIME DeltaTime )
{
ULONG NumOfPoints;
/***************************************************************************
* MMTIME is 1/3000 of a second. The sample rate is given in points per *
* second. Thus the number of points to ink is calculated by: *
* *
* 1 SECOND NUM OF POINTS *
* ---------------- X DeltaTime MMTIMEUNITS X ------------- *
* 3000 MMTIMEUNITS SECOND *
* *
* Once the estimate of the number of points has been made, check to see if *
* it exceeds the number of points remaining to be inked in the current *
* stroke. Return the minimum of these two numbers. *
***************************************************************************/
NumOfPoints = DeltaTime * pMyWindowData->pCurrStroke->ulSampleRate / 3000 ;
if ( pMyWindowData->NumPointsLeft < NumOfPoints )
{
NumOfPoints = pMyWindowData->NumPointsLeft;
};
return ( NumOfPoints );
}
/******************************************************************************
* *
* Subroutine: InkStroke *
* *
* Function: This function draws the ink to the display during playback. It *
* uses paths to draw 2 pel wide geometric lines. It then updates *
* the number of points still waiting to be drawn, and moves the *
* current point pointer to the next point to be drawn. *
* *
* Parameters: pMyWindowData - Pointer to window data *
* NumOfPoints - Number of points to ink from the current stroke *
* *
* Internal *
* References: None *
* *
* Pen For OS2 *
* References: None *
* *
******************************************************************************/
BOOL InkStroke ( PMYWINDOWDATA pMyWindowData, ULONG NumOfPoints )
{
/***************************************************************************
* If the current point is the first point in the stroke then the stroke *
* not been inked yet. So move to the first point in the presentation space *
* in preparation for the polyline. *
***************************************************************************/
if ( pMyWindowData->pCurrPoint == pMyWindowData->pCurrStroke->pXY )
{
GpiOpenSegment ( pMyWindowData->hps, ++pMyWindowData->NumSegments );
GpiMove ( pMyWindowData->hps, pMyWindowData->pCurrPoint );
};
/***************************************************************************
* Now draw the stroke on the screen *
***************************************************************************/
GpiBeginPath ( pMyWindowData->hps, 1 );
GpiPolyLine ( pMyWindowData->hps, NumOfPoints, pMyWindowData->pCurrPoint );
GpiEndPath ( pMyWindowData->hps );
GpiStrokePath ( pMyWindowData->hps, 1, 0 );
/***************************************************************************
* Update the window data to indicate the number of points yet to be inked *
* in the current stroke and move the current point pointer to the next *
* next point to the last point inked. *
***************************************************************************/
pMyWindowData->NumPointsLeft -= NumOfPoints;
pMyWindowData->pCurrPoint += NumOfPoints;
/***************************************************************************
* If last point in stroke has been inked, then close the graphic segment. *
***************************************************************************/
if ( pMyWindowData->pCurrPoint == NULL )
{
GpiCloseSegment ( pMyWindowData->hps );
};
return ( IME_NO_ERROR );
}
/******************************************************************************
* *
* Subroutine: InkWinProc *
* *
* Function: Window procedure for inking window. The inking window is a *
* transparent window that we will be inking to during the capture *
* and playback of stroke data. *
* *
* Parameters: hWnd - Window handle *
* msg - Message Id *
* mp1 - Message Parameter 1 *
* mp2 - Message Parameter 2 *
* *
* Internal *
* References: AppendStrokes - Append strokes to linked list *
* ScaleStrokeData - Scale strokes from high resolution *
* PlayTimedInk - Prepare to playback recording *
* InkTimedInk - Draw ink to window *
* StopTimedInk - Stop playback or recording *
* *
* Pen For OS2 *
* References: WrtQueryEventData - Get the event data from Pen for OS/2 *
* WrtQueryStrokeData - Get stroke data *
* *
******************************************************************************/
MRESULT EXPENTRY InkWinProc ( HWND hWnd,
ULONG msg,
MRESULT mp1,
MRESULT mp2 )
{
SIZEL PageSize;
PMYWINDOWDATA pMyWindowData;
ULONG buflen;
PSTROKEDATA pStrokeData;
static MMTIME TouchdownTime = 0;
static MMTIME LiftoffTime = 0;
APIRET rc;
static USHORT PointCounter = 0;
static POINTL pPoint[8];
static BOOL StrokeBufferOverrun = FALSE;
RECTL rcl;
HPS hpspaint;
WRTEVENTDATA EventData;
/***************************************************************************
* Get pointer to the window data. *
***************************************************************************/
pMyWindowData = (PMYWINDOWDATA) WinQueryWindowPtr ( hWnd, 0 );
switch ( msg )
{
/************************************************************************
* Create this transparent window and setup the pMyWindowData. This *
* structure is kept in reserved area. *
************************************************************************/
case WM_CREATE:
{
/*********************************************************************
* Initialize window instance data *
*********************************************************************/
pMyWindowData = (PMYWINDOWDATA) PVOIDFROMMP ( mp1 );
if ( !WinSetWindowPtr ( hWnd, 0, (PVOID) pMyWindowData ) )
return ( (MPARAM) TRUE );
pMyWindowData->hwnd = hWnd;
/*********************************************************************
* Create the presentation space for the window *
*********************************************************************/
pMyWindowData->hab = WinQueryAnchorBlock ( hWnd );
pMyWindowData->hdc = WinOpenWindowDC ( hWnd );
DevQueryCaps ( pMyWindowData->hdc, CAPS_WIDTH, 1L, &PageSize.cx );
DevQueryCaps ( pMyWindowData->hdc, CAPS_HEIGHT, 1L, &PageSize.cy );
pMyWindowData->hps = GpiCreatePS ( pMyWindowData->hab,
pMyWindowData->hdc,
&PageSize,
( PU_PELS |
GPIT_NORMAL |
GPIF_LONG |
GPIA_ASSOC ) );
if ( pMyWindowData->hps == GPI_ERROR )
{
return ( (MPARAM) TRUE );
};
/*********************************************************************
* Prepare the presentation space for drawing and retaining *
* the graphic primatives *
*********************************************************************/
GpiSetDrawingMode ( pMyWindowData->hps, DM_DRAWANDRETAIN );
GpiSetDrawControl ( pMyWindowData->hps,
DCTL_ERASE,
DCTL_OFF );
pMyWindowData->NumSegments = 0;
/*********************************************************************
* Set initial presentation space attributes *
*********************************************************************/
pMyWindowData->CurrentColor = CLR_RED;
GpiSetColor ( pMyWindowData->hps,
pMyWindowData->CurrentColor );
GpiSetLineWidthGeom ( pMyWindowData->hps, 2L );
GpiSetLineEnd ( pMyWindowData->hps, LINEEND_ROUND );
GpiSetLineJoin ( pMyWindowData->hps, LINEJOIN_ROUND );
/*********************************************************************
* Set flags to initial state *
*********************************************************************/
pMyWindowData->td = FALSE;
pMyWindowData->fPlay = FALSE;
pMyWindowData->fRecord = FALSE;
/*********************************************************************
* Make the window visible and return *
*********************************************************************/
WinShowWindow ( hWnd, TRUE );
return ( (MRESULT) FALSE );
break;
}
/************************************************************************
* Get the start time of stroke, Capture mouse messages, move to *
* the point where the pen touches the workpad to ink. *
************************************************************************/
case WM_TOUCHDOWN:
{
/*********************************************************************
* Only process this message if we are in the process of creating *
* a new recording. *
*********************************************************************/
if ( pMyWindowData->fRecord )
{
/******************************************************************
* Get the current time in MMTIME *
******************************************************************/
TouchdownTime = *(pCurrMMTime);
GpiOpenSegment ( pMyWindowData->hps, ++pMyWindowData->NumSegments );
WinQueryWindowRect ( hWnd, &rcl );
pMyWindowData->OrgWindowSize.cx = rcl.xRight;
pMyWindowData->OrgWindowSize.cy = rcl.yTop;
PointCounter = 0;
pMyWindowData->td = TRUE;
WinSetCapture ( HWND_DESKTOP, hWnd );
/******************************************************************
* Note that the (SHORT) cast is required in order to maintain *
* sign. *
******************************************************************/
pMyWindowData->points.x = (SHORT) SHORT1FROMMP ( mp1 );
pMyWindowData->points.y = (SHORT) SHORT2FROMMP ( mp1 );
GpiMove ( pMyWindowData->hps, &pMyWindowData->points );
/******************************************************************
* TDN_INFINTE: Inform Pen for OS/2 that the mouse button down *
* is not required. *
* TDN_HIFREQ_MOUSEMOVE: Inform Pen for OS/2 to report the points *
* as mousemoves but at the sensor sample rate. *
* TDN_NO_INK_STROKE: Inform Pen for OS/2 not to ink the points *
* since we will be doing our inking. *
******************************************************************/
return ( (MRESULT) ( TDN_INFINITE |
TDN_HIFREQ_MOUSEMOVE |
TDN_NO_INK_STROKE ));
};
break;
}
/************************************************************************
* For this message, the inking is done to show the stroke. *
************************************************************************/
case WM_MOUSEMOVE:
{
if ( pMyWindowData != NULL )
{
if ( pMyWindowData->td && pMyWindowData->fRecord )
{
/***************************************************************
* This release of Pen for OS/2 has a maximum limit to the size *
* of the stroke buffer. It is limited to 1024 points or eight *
* seconds per stroke. If the maximum size of the stroke buffer *
* is reached, then inform the user via a tone. *
***************************************************************/
if ( StrokeBufferOverrun )
{
DosBeep ( 4000, 16 );
return ( (MRESULT) TRUE );
};
/***************************************************************
* Get the event data to see if the stroke buffer has been *
* been filled. *
***************************************************************/
EventData.cbStructSize = sizeof(EventData);
WrtQueryEventData ( &EventData );
if ( EventData.flEventStatus & WRT_BUFFER_OVERRUN )
{
DosBeep ( 4000, 16 );
/************************************************************
* Force the inking for all of the remaining points. *
************************************************************/
GpiBeginPath ( pMyWindowData->hps, 1 );
GpiPolyLine ( pMyWindowData->hps, PointCounter, pPoint );
GpiEndPath ( pMyWindowData->hps );
GpiStrokePath ( pMyWindowData->hps, 1, 0 );
GpiCloseSegment ( pMyWindowData->hps );
StrokeBufferOverrun = TRUE;
return ( (MRESULT) TRUE );
};
/***************************************************************
* Keep the (x,y) coordinate in a buffer of 8 entries. *
* Note that the (SHORT) cast is required in order to maintain *
* sign. *
***************************************************************/
pPoint[PointCounter].x = (SHORT) SHORT1FROMMP( mp1 );
pPoint[PointCounter].y = (SHORT) SHORT2FROMMP( mp1 );
PointCounter++;
if (PointCounter == 8)
{
GpiBeginPath ( pMyWindowData->hps, 1 );
GpiPolyLine ( pMyWindowData->hps, 8L, pPoint );
GpiEndPath ( pMyWindowData->hps );
GpiStrokePath ( pMyWindowData->hps, 1, 0 );
PointCounter = 0;
}
return ( (MRESULT) TRUE );
};
};
break;
}
/************************************************************************
* Stroke ends. Collect stroke end time, No more mouse message *
* capture, Get the stroke data and Call AppendStrokes to adjust *
* the stroke linked list in pMyWindowData. *
************************************************************************/
case WM_LIFTOFF:
{
if ( pMyWindowData->td && pMyWindowData->fRecord )
{
/******************************************************************
* Get the current time in MMTIME *
******************************************************************/
LiftoffTime = *(pCurrMMTime);
WinSetCapture ( HWND_DESKTOP, NULLHANDLE );
pMyWindowData->td = FALSE;
/******************************************************************
* If the buffer was overrun, then the points have already been *
* displayed. *
******************************************************************/
if ( !StrokeBufferOverrun )
{
/******************************************************************
* Force the inking for all of the remaining points. *
* Note that the (SHORT) cast is required in order to maintain *
* sign. *
******************************************************************/
pPoint[PointCounter].x = (SHORT) SHORT1FROMMP( mp1 );
pPoint[PointCounter].y = (SHORT) SHORT2FROMMP( mp1 );
PointCounter++;
GpiBeginPath ( pMyWindowData->hps, 1 );
GpiPolyLine ( pMyWindowData->hps, PointCounter, pPoint );
GpiEndPath ( pMyWindowData->hps );
GpiStrokePath ( pMyWindowData->hps, 1, 0 );
GpiCloseSegment ( pMyWindowData->hps );
};
/******************************************************************
* Get the size of the stroke buffer. *
******************************************************************/
buflen = 0;
pStrokeData = NULL;
rc = WrtQueryStrokeData ( (PBYTE) pStrokeData, &buflen, hWnd, QSD_SCALE, 0, 0, 0 );
if ( rc )
return (MRESULT) TRUE;
if ( !buflen )
return (MRESULT) TRUE;
/******************************************************************
* Allocate memory for the stroke buffer. *
******************************************************************/
pStrokeData = (PSTROKEDATA) malloc ( buflen );
if ( !pStrokeData )
{
return ( (MRESULT) TRUE );
};
/******************************************************************
* Get the stroke data *
******************************************************************/
pStrokeData->cbStructSize = sizeof ( STROKEDATA );
if ( WrtQueryStrokeData ( (PBYTE) pStrokeData,
&buflen,
pMyWindowData->hwnd,
QSD_STANDARDIZED_RES,
0,
0,
0 ) )
return ( (MRESULT) LO_STROKE_PROCESSED );
/******************************************************************
* Append current stroke to linked list *
******************************************************************/
AppendStrokes ( pMyWindowData, pStrokeData );
/******************************************************************
* Use existing structure entries for the stroke to hold the *
* touchdown and liftoff times for the current stroke *
******************************************************************/
pStrokeData->ulUser1 = TouchdownTime;
pStrokeData->ulUser2 = LiftoffTime;
StrokeBufferOverrun = FALSE;
return ( (MRESULT) LO_STROKE_PROCESSED );
}
else
{
return ( (MRESULT) LO_DEFAULT );
};
return ( (MRESULT) FALSE );
}
/************************************************************************
* Repaint the window, let the default window procedure handle. *
************************************************************************/
case WM_PAINT:
{
hpspaint = WinBeginPaint ( hWnd, pMyWindowData->hps, &rcl );
GpiDrawChain ( hpspaint );
WinEndPaint ( hpspaint );
return ( (MRESULT) TRUE );
}
/************************************************************************
* Clean up before we close the window *
************************************************************************/
case WM_DESTROY:
{
GpiDestroyPS ( pMyWindowData->hps );
return ( (MRESULT) FALSE );
}
/************************************************************************
* When the parent window is resized, this window is resized. Scale the *
* data to the new size, and playback the ink into the window at the new *
* scale. *
************************************************************************/
case WM_SIZE:
{
if ( pMyWindowData != NULL )
{
if ( pMyWindowData->pStrokeHead )
{
WinShowWindow ( pMyWindowData->hwnd, FALSE );
ScaleStrokeData ( pMyWindowData );
PlayTimedInk ( pMyWindowData->hwnd );
InkTimedInk ( pMyWindowData->hwnd, *(pCurrMMTime) );
StopTimedInk ( pMyWindowData->hwnd );
WinShowWindow ( pMyWindowData->hwnd, TRUE );
}
else
EraseTimedInk ( pMyWindowData );
};
return ( (MRESULT) FALSE );
}
default:
break;
};
return( (MRESULT) WinDefWindowProc ( hWnd, msg, mp1, mp2 ) );
};