📄 quiklist.c
字号:
/********************************************************************* FILE: QuikList.c** DESCRIPTION: The QuikList project module. This version of QuikList (2) shows you* how to do quick record lookup from a database using* multiple Graffiti characters. It also add list scrolling* using the up and down buttons on the device..\** VERSION: 2.0**********************************************************************/#include <PalmOS.h>#include <PalmCompatibility.h>#include <TxtGlue.h>#include "QuikList.h"#include "QuikListRsc.h"#include "Utils.h"#include "UtilsRsc.h"/*********************************************************************** * FUNCTION: StartGraffitiLookup * * DESCRIPTION: Initiate a record lookup using a user-entered keystroke, * The lookup uses a two-part timing mechanism: one setting * for the EvtGetEvent timeout value, and a secondary counter. * * RETURNED: Nothing. * SIDE EFFECTS: Sets three global variables: * gFindStr (the lookup string), the EvtGetEvent timeout setting, * and the lookup counter. ***********************************************************************/ static void StartGraffitiLookup( Char chr // ( in ) The next char to put in the lookup string.){ Int32 findStrLen = StrLen ( gFindStr ); // Turn on lookup indicator so user knows a lookup is taking place FrmShowObject ( FrmGetActiveForm (), FrmGetObjectIndex ( FrmGetActiveForm (), MainLookupIndicatorLabel )); // Set up the lookup string gFindStr [ findStrLen ] = chr; gFindStr [ findStrLen + 1 ] = NULL; // Arm (rearm) the nilEvent timer and its counter. We need a value > 1 in// nileventCnt because nilEvents may appear for reasons other than// the timer. gEventTimeout = LOOKUP_TIMER_CNT; gNilEventCnt = NIL_EVENT_CNT;}/*********************************************************************** * FUNCTION: StopGrafftiLookup * * DESCRIPTION: Check to see if there's an active Graffiti lookup going on. * If so, check for termination. This gets called every * LOOKUP_TIMER_CNT ticks until gNilEventCnt is zero. * * RETURNED: Nothing. ***********************************************************************/ static void StopGrafftiLookup( void){ gNilEventCnt--; if ( gNilEventCnt == 0 ) {// Hide the lookup indicator, clear the lookup string, and // turn off nilEvent generation. FrmHideObject ( FrmGetActiveForm (), FrmGetObjectIndex ( FrmGetActiveForm (), MainLookupIndicatorLabel )); gFindStr [ 0 ] = NULL; gEventTimeout = evtWaitForever; }}/*********************************************************************** * FUNCTION: DBSearch * * DESCRIPTION: Search a database, using a modified binary search, for the * first record alphabetically that matches a specific string. * NOTE: This routine assumes that the database records are * sorted in ascending order. * * RETURNED: -1 if no match is found, the record index otherwise. ***********************************************************************/ static Int32 DBSearch // ( out ) -1 (not found) or record index( Char * fStrP, // ( in ) the string to match against DmOpenRef dbRef // ( in ) the database to search){ Char recData [ MAX_NAME_LENGTH ]; Int16 compare, result = -1; UInt16 mid, lower = 0; UInt16 fStrLen = ( UInt16 ) StrLen ( fStrP ); UInt16 numRecs = DmNumRecords ( gDBRef ); UInt16 upper = numRecs - 1; // Binary search loop looking for a match do { mid = (( lower + upper ) / 2 ); // Get next search location// Check for a match GetRecordData ( dbRef, mid, recData ); compare = TxtCaselessCompare ( fStrP, fStrLen, NULL, recData, fStrLen, NULL );// Found, return record # and get out the binary search loop if ( compare == 0 ) { result = ( Int16 ) mid; break; }// Check for termination if ( mid == lower || mid == upper ) break; // Not found, move search location else if ( compare < 0 ) upper = mid; else lower = mid; } while ( 1 );// If a match, look at the predecessor records sequentially// to find the lowest record # that still matches. if ( result > 0 ) { do { result--; GetRecordData ( dbRef, ( UInt16 ) result, recData ); compare = TxtCaselessCompare ( fStrP, fStrLen, NULL, recData, fStrLen, NULL ); // When we hit the first record that doesn't match, increment the// record pointer back to the lowest record # that does match and exit. if ( compare > 0 ) { result++; break; } } while ( result != 0 ); } return ( result );}#pragma mark ----------------/*********************************************************************** * FUNCTION: MainFormDrawList ** DESCRIPTION: Draw the main form list. In between each line,* check for a new incoming keystroke. If there is one, do* another Graffiti lookup. * * RETURNED: nothing ***********************************************************************/static void MainFormDrawList( void){#define NUM_REDRAWS 1 UInt16 i, j; Coord x, y; EventType event; Char name [ MAX_NAME_LENGTH ];// Erase the list's rectangle WinEraseRectangle ( &gListBounds, 0 ); for ( i = 0; i < VIS_ITEMS; i++ ) { // Check for keystroke in middle of list redraw.// If there is one, do a lookup to see if there is a new list location// match. If so, stop redrawing until the next redraw kicks in.// StopRedraw is set in ProcessKeystroke. if ( ! gStopDrawing ) { if ( EvtSysEventAvail ( false )) { EvtGetEvent ( &event, 0 ); SysHandleEvent ( &event ); if ( event.eType == keyDownEvent ) { Boolean handled = MainFormProcessKeystroke ( ( UInt8 ) event.data.keyDown.chr, true ); if ( gStopDrawing ) return; } }// No event available, keep drawing the current list x = ( Coord ) ( gListBounds.topLeft.x + 2 ); y = ( Coord ) ( gListBounds.topLeft.y + ( i * FONT_HEIGHT )); // Draw more than once to slow things down for testing *name = NULL; GetRecordData ( gDBRef, gTopItem + i, name ); for ( j = 0; j < NUM_REDRAWS; j++ ) WinDrawChars ( name, StrLen ( name ), x, y ); } }}/*********************************************************************** * FUNCTION: FitToListBoundaries * * DESCRIPTION: Check an incoming list position to make sure it* it fits within the legal boundaries for the list. * * RETURNED: A valid list position ***********************************************************************/static Int16 FitToListBoundaries( Int16 topItem // ( in ) the list item to check){ Int16 result = topItem; if ( result < 0 ) result = 0; if ( result > gListSize - VIS_ITEMS ) result = gListSize - VIS_ITEMS; return ( result );}/*********************************************************************** * FUNCTION: MainFormProcessKeystroke * * DESCRIPTION: Process a keystroke event for the Main form. That typically means * to see if there is a record that starts with a specific string. * * RETURNED: A boolean set to True if the keystroke was handled. It also set * the global gStopDrawing ***********************************************************************/static Boolean MainFormProcessKeystroke( UInt8 chr, // ( in ) keystroke to process Boolean drawing // ( in ) Currently drawing a list?){ Boolean handled = false;// First, check for scroll up/down buttons if ( chr == vchrPageUp ) { if ( gTopItem != 0 ) { gTopItem = FitToListBoundaries ( gTopItem - VIS_ITEMS + 1 ); MainFormDrawList (); } handled = true; } else if ( chr == vchrPageDown ) { if ( gTopItem != gListSize - VIS_ITEMS ) { gTopItem = FitToListBoundaries ( gTopItem + VIS_ITEMS - 1 ); MainFormDrawList (); } handled = true; } else // If it's a valid char, start Graffiti lookup if ( TxtGlueCharIsPrint ( chr )) { Int32 recLoc = -1; handled = true;// Only do the lookup if there's room in the lookup string if ( StrLen ( gFindStr ) < MAX_MATCH_CHAR ) { StartGraffitiLookup (( Char ) chr ); // Lookup started, check for a record that starts with the string recLoc = DBSearch ( gFindStr, gDBRef ); if ( recLoc >= 0 ) { // Found a record, redraw the list so the matched record is the topmost// visible item. If this is a redraw for a multi-char match (if drawing == true),// this redraw takes place before the previous list drawing completes. gTopItem = FitToListBoundaries (( Int16 ) recLoc ); MainFormDrawList ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -