Here it is. I use this only as a gimmick in my current project (the normal
search is in a fulltext index). But it works quite well. DoDatabaseListAction()
checks currently only for the first key pressed. You can change that easily in
place.
If you haven't dealt with tables, it should be easier (but not better) if you
change it to deal with lists.
Best practice should be to put this code into the Memo example that comes with
PODS and CW and later include the table code into your own project.
- ListTable is my table id.
- RecordDBRecordPtr is a pointer to my database database record structure.
- RecordDB is my database (change this name to MemoDB for use with the Memo
example)
First, add a few global variables to your project:
// This is used to indicate if the table has the focus.
// If it hasn't the focus we don't want to handle a keyDown event
// there of course
Boolean OneHandedTableHasFocus = true;
// CurrentRecord is the record which the custom table draw
// callback draws and is used to scroll to the record. Naming is the
// same as in the Memo example
UInt16 CurrentRecord = noRecordSelected;
(Actually, in my project I set OneHandedTableHasFocus to false initially. If
you have multiple input fields on your form and want to support this navigation
on older devices below OS ? where frmObjectFocusTakeEvent isn't available, you
have to check yourself if your list/table has the focus. You can do this by
checking for object focus (check the API docs) each time a key is pressed for
example).
Then, in your form event handler you need to add a few things:
// BEGIN OF FORM HANDLER SECTION. Include this appropriately in your form
handler
/* Check if the table has the object focus. If your form isn't in object focus
mode or you want to support older deviced (AFAIK OS < 5) make sure you set
OneHandedTableHasFocus by hand appropriately (refer to the API docs)
*/
if (event->eType == frmObjectFocusTakeEvent)
{
frm = FrmGetActiveForm();
if (event->data.frmObjectFocusTake.objectID == ListTable)
{
OneHandedTableHasFocus = true;
}
else
{
OneHandedTableHasFocus = false;
}
}
// Handle Key events if a key is pressed and the table has the focus
if (event->eType == keyDownEvent)
{
if ((!TxtCharIsHardKey(event->data.keyDown.modifiers,
event->data.keyDown.chr)) && OneHandedTableHasFocus)
{
if (TxtGlueCharIsPrint (event->data.keyDown.chr))
handled = DoDatabaseListAction (frm,
event->data.keyDown.chr, RecordDB);
}
}
// END OF FORM HANDLER SECTION
/***********************************************************************
*
* FUNCTION: ListViewScrollTo
*
* Scrolls to a specific redord number (the record that matches the key)
*
* -- snip Fuer Five-Way Navigation verwendet --- snip
*
***********************************************************************/
static void ListViewScrollTo (Int16 row)
{
UInt16 attr;
TablePtr table;
// RectangleType rect;
DmRecordInfo(RecordDB, row, &attr, NULL, NULL);
if (!(attr & dmRecAttrSecret))
{
table = GetObjectPtr (ListTable);
/* snipped. That's for One handed table navigation
// Falls vorige selektion auf gleicher seite vorhanden, loeschen
if (OneHandedSelectedRow >= 0)
{
TblGetItemBounds (table, OneHandedSelectedRow, 0, &rect);
WinEraseRectangle(&rect, 0);
ListViewDrawRecord(table, OneHandedSelectedRow, 0, &rect);
}
*/
// Set the current record to the record that matched our key
CurrentRecord = row;
// Redraw the table.
ListViewLoadRecords (FrmGetActiveForm());
TblRedrawTable(table);
/* snip.
if (TblFindRowID (table, row, &OneHandedSelectedRow))
{
FrmGlueNavRemoveFocusRing (FrmGetActiveForm());
ListViewSelectTableItem(true, table, OneHandedSelectedRow, 0,
&rect);
OneHandedRecordSelected = true;
}
*/
}
}
/* This function is called by the form event handler when a key is pressed.
Note that only one chracter at a time is processed here. You can easily
change
this behaviour at this place, SetDatabaseListSelection() will already
handle it.
*/
static Boolean DoDatabaseListAction (FormPtr frmP, UInt16 c, DmOpenRef dbP)
{
Boolean handled = false;
TablePtr tblP;
Boolean selection;
Int16 row, column;
column = 0;
tblP = FrmGetObjectPtr (frmP, FrmGetObjectIndex (frmP, ListTable));
// Check for printable character and perform a search
if ((((Char)c & ~0x20) >= 'A') && (((Char)c & ~0x20)<= 'Z'))
{
Char buf[2] = {c, 0};
SetDatabaseListSelection (tblP, buf, 1, false, dbP);
handled = true;
}
return handled;
}
static Int16 SetDatabaseListSelection (TablePtr tblP, Char *name, Int32 len,
Boolean caseSensitive, DmOpenRef dbP)
{
SysDBListItemType* arrayP;
//Int16 selection;
Int16 row, column;
Int16 val;
MemHandle recH;
RecordDBRecordPtr recP; // Pointer to my database structure
UInt16 attr;
UInt16 numRecs;
// row = INTERNALRECS;
// Top visible record in your database
row = 0;
column = 0;
numRecs = DmNumRecords(dbP);
if (len == 0)
{
len = StrLen (name);
if (len == 0)
{
goto Exit;
}
}
if (caseSensitive)
{
while (row < (numRecs-1))
{
DmRecordInfo(dbP, row, &attr, NULL, NULL);
if (!(attr & dmRecAttrSecret)) // only visible records
{
recH = DmQueryRecord (dbP, row);
if (recH == 0)
{
//MemHandleUnlock (recH);
break;
}
recP = MemHandleLock (recH);
if (recP->title == 0)
{
MemHandleUnlock (recH);
break;
}
val = StrNCompare (name, &recP->title, len);
if(val == 0)
{
MemHandleUnlock (recH);
break; // match
}
else if (val < 0)
{
MemHandleUnlock (recH);
row--;
break;
}
MemHandleUnlock (recH);
}
row++;
}
}
else
{
while (row < (numRecs-1))
{
DmRecordInfo(dbP, row, &attr, NULL, NULL);
if (!(attr & dmRecAttrSecret)) // nur sichtbare records
{
recH = DmQueryRecord (dbP, row);
if (recH == 0)
{
//MemHandleUnlock (recH);
break;
}
recP = MemHandleLock (recH);
if (recP->title == 0)
{
MemHandleUnlock (recH);
break;
}
val = StrNCaselessCompare (name, &recP->title, len);
if(val == 0)
{
MemHandleUnlock (recH);
break; // match
}
else if (val < 0)
{
row--;
MemHandleUnlock (recH);
break;
}
MemHandleUnlock (recH);
}
row++;
}
}
Exit:
ListViewScrollTo (row);
return row;
}
Regards,
Benjamin Stadin
--
For information on using the PalmSource Developer Forums, or to unsubscribe,
please see http://www.palmos.com/dev/support/forums/