//------------------------------------------------------------------------- // Desc: FlmForm class // Tabs: 3 // // Copyright (c) 1999-2003,2005-2006 Novell, Inc. All Rights Reserved. // // This program is free software; you can redistribute it and/or // modify it under the terms of version 2 of the GNU General Public // License as published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, contact Novell, Inc. // // To contact Novell about this file by physical or electronic mail, // you may find current contact information at www.novell.com // // $Id: fform.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ //------------------------------------------------------------------------- #include "fform.h" #include "flaimsys.h" #define COLUMN_DIFF(uiCol1,uiCol2) \ (FLMUINT)(((uiCol1) <= (uiCol2)) \ ? (FLMUINT)((uiCol2) - (uiCol1)) \ : (FLMUINT)((uiCol1) - (uiCol2))) FSTATIC FLMBOOL flmIsUnsigned( char * pszEditBuf, FLMUINT * puiValue, char * pszErrMsg); FSTATIC RCODE flintRecEditKeyHook( F_RecEditor * pRecEditor, NODE * pCurNd, FLMUINT uiKeyIn, void * UserData, FLMUINT * puiKeyOut); FSTATIC FLMBOOL pulldownKeyFunc( FlmPulldownList * pPulldown, FLMUINT uiKeyIn, FLMUINT * puiKeyOut, void * pvAppData); /*=========================================================================== Desc: Initializes variables ===========================================================================*/ FlmForm::FlmForm() { m_pScreen = NULL; m_pThread = NULL; m_bMonochrome = FALSE; // Future support m_pDisplayWindow = NULL; m_pStatusWindow = NULL; m_uiRows = 0; m_uiCols = 0; m_uiUpperLeftRow = 0; m_uiUpperLeftColumn = 0; m_uiBackColor = WPS_BLUE; m_uiForeColor = WPS_WHITE; m_uiTopFormRow = 0; m_pCurObject = NULL; m_pFirstObject = NULL; m_pLastObject = NULL; m_pEventCB = NULL; m_pvAppData = NULL; m_bGetKeyStrokes = FALSE; m_bShowingHelpStatus = FALSE; m_uiLastTimeBeeped = 0; m_bValuesChanged = FALSE; m_bInteracting = FALSE; m_pszEditBuf = NULL; m_uiEditBufSize = 0; m_uiMaxCharsToEnter = 0; m_uiNumCharsEntered = 0; m_uiEditColumn = 0; m_uiEditRow = 0; m_uiEditWidth = 0; m_uiEditBufPos = 0; m_uiEditBufLeftColPos = 0; } FlmForm::~FlmForm() { FlmFormObject * pFormObject; FlmFormObject * pNextObject; // Delete all form objects pFormObject = m_pFirstObject; while (pFormObject) { pNextObject = pFormObject->getNextObject(); pFormObject->Release(); pFormObject = pNextObject; if (pFormObject == m_pFirstObject) { break; } } // Release the windows if (m_pDisplayWindow) { (void)FTXWinFree( &m_pDisplayWindow); } if (m_pStatusWindow) { (void)FTXWinFree( &m_pStatusWindow); } if (m_pszEditBuf) { f_free( &m_pszEditBuf); } } /*=========================================================================== Desc: Initializes variables ===========================================================================*/ RCODE FlmForm::init( FTX_SCREEN_p pScreen, FlmThreadContext * pThread, const char * pszTitle, FLMUINT uiTitleBackColor, FLMUINT uiTitleForeColor, const char * pszHelp, FLMUINT uiHelpBackColor, FLMUINT uiHelpForeColor, FLMUINT uiULX, FLMUINT uiULY, FLMUINT uiLRX, FLMUINT uiLRY, FLMBOOL bCreateStatusBar, FLMBOOL bCreateBorder, FLMUINT uiBackColor, FLMUINT uiForeColor) { RCODE rc = FERR_OK; FLMUINT uiNumCols; FLMUINT uiNumRows; FLMUINT uiStartCol; // Form must not already have been initialized. if (m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } m_pScreen = pScreen; m_pThread = pThread; if( !uiLRX && !uiLRY) { if( FTXScreenGetSize( pScreen, &uiNumCols, &uiNumRows) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } uiNumRows -= uiULY; uiNumCols -= uiULX; } else { uiNumRows = (uiLRY - uiULY) + 1; uiNumCols = (uiLRX - uiULX) + 1; } uiStartCol = uiULX; if (bCreateStatusBar) { uiNumRows -= 2; // Add 2 to account for the status bar } // Create the display window of the appropriate size. if (FTXWinInit( pScreen, uiNumCols, uiNumRows, &m_pDisplayWindow) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } // Position the window on the screen. m_uiUpperLeftRow = uiULY; m_uiUpperLeftColumn = uiStartCol; if (FTXWinMove( m_pDisplayWindow, uiStartCol, uiULY) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } // Prevent window from scrolling. if (FTXWinSetScroll( m_pDisplayWindow, FALSE) != FTXRC_SUCCESS) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } // Don't wrap lines. if (FTXWinSetLineWrap( m_pDisplayWindow, FALSE) != FTXRC_SUCCESS) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } // Input cursor should not be present initially. if (FTXWinSetCursorType( m_pDisplayWindow, WPS_CURSOR_INVISIBLE) != FTXRC_SUCCESS) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } // Set foreground and background color for window. if (FTXWinSetBackFore( m_pDisplayWindow, m_bMonochrome ? WPS_BLACK : uiBackColor, m_bMonochrome ? WPS_WHITE : uiForeColor) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } m_uiBackColor = uiBackColor; m_uiForeColor = uiForeColor; // Clear the window if (FTXWinClear( m_pDisplayWindow) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } if (bCreateBorder) { if (FTXWinDrawBorder( m_pDisplayWindow) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } m_uiUpperLeftRow++; m_uiUpperLeftColumn++; } if (pszTitle && *pszTitle) { if (FTXWinSetTitle( m_pDisplayWindow, pszTitle, uiTitleBackColor, uiTitleForeColor) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } } if (pszHelp && *pszHelp) { if (FTXWinSetHelp( m_pDisplayWindow, pszHelp, uiHelpBackColor, uiHelpForeColor) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } } if (bCreateStatusBar) { if (FTXWinInit( pScreen, uiNumCols, 2, &m_pStatusWindow) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } if (FTXWinMove( m_pStatusWindow, uiStartCol, uiULY + uiNumRows) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } if (FTXWinSetScroll( m_pStatusWindow, FALSE) != FTXRC_SUCCESS) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } if (FTXWinSetCursorType( m_pStatusWindow, WPS_CURSOR_INVISIBLE) != FTXRC_SUCCESS) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } if (FTXWinSetBackFore( m_pStatusWindow, m_bMonochrome ? WPS_BLACK : WPS_GREEN, WPS_WHITE) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } if (FTXWinClear( m_pStatusWindow) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } if (FTXWinOpen( m_pStatusWindow) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } } // Open the display window AFTER the status // window so it will get the input focus. if (FTXWinOpen( m_pDisplayWindow) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } // Get the actual number of rows and columns that are // available in the window - must be done after // setting the border, etc. if (FTXWinGetCanvasSize( m_pDisplayWindow, &m_uiCols, &m_uiRows) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } m_uiTopFormRow = 0; refresh(); Exit: return( rc); } /*=========================================================================== Desc: Redisplay the form. ===========================================================================*/ void FlmForm::refresh( void) { FlmFormObject * pObject; // Set foreground and background color for window. FTXWinSetBackFore( m_pDisplayWindow, m_bMonochrome ? WPS_BLACK : m_uiBackColor, m_bMonochrome ? WPS_WHITE : m_uiForeColor); // Clear the screen (void)FTXWinClear( m_pDisplayWindow); // Redisplay all of the items on the screen. pObject = m_pFirstObject; while (pObject) { displayObject( pObject); if ((pObject = pObject->getNextObject()) == m_pFirstObject) break; } } /*=========================================================================== Desc: Sets foreground and background color for an object in the form. ===========================================================================*/ void FlmForm::setObjectColor( FLMUINT uiObjectId, FLMUINT uiBackColor, FLMUINT uiForeColor ) { FlmFormObject * pObject; // Form must be initialized flmAssert( m_pDisplayWindow != NULL); // See if we can find the object. if ((pObject = findObject( uiObjectId)) == NULL) { flmAssert( 0); } else { // Set the foreground and background color of the object. pObject->setBackColor( uiBackColor); pObject->setForeColor( uiForeColor); // Redisplay the object. displayObject( pObject); } } /*=========================================================================== Desc: Gets an object's foreground and background colors. ===========================================================================*/ void FlmForm::getObjectColor( FLMUINT uiObjectId, FLMUINT * puiBackColor, FLMUINT * puiForeColor ) { FlmFormObject * pObject; // Form must be initialized flmAssert( m_pDisplayWindow != NULL); // See if we can find the object. if ((pObject = findObject( uiObjectId)) == NULL) { flmAssert( 0); } else { // Get the foreground and background color of the object. *puiBackColor = pObject->getBackColor(); *puiForeColor = pObject->getForeColor(); } } /*=========================================================================== Desc: Sets display only flag for an object in the form. ===========================================================================*/ void FlmForm::setObjectDisplayOnlyFlag( FLMUINT uiObjectId, FLMBOOL bDisplayOnly ) { FlmFormObject * pObject; // Form must be initialized flmAssert( m_pDisplayWindow != NULL); // See if we can find the object. if ((pObject = findObject( uiObjectId)) == NULL) { flmAssert( 0); } else { // Set the display only flag for the object. pObject->setDisplayOnly( bDisplayOnly); } } /*=========================================================================== Desc: Sets display only flag for an object in the form. ===========================================================================*/ void FlmForm::getObjectDisplayOnlyFlag( FLMUINT uiObjectId, FLMBOOL * pbDisplayOnly ) { FlmFormObject * pObject; // Form must be initialized flmAssert( m_pDisplayWindow != NULL); // See if we can find the object. if ((pObject = findObject( uiObjectId)) == NULL) { flmAssert( 0); } else { // Get the display only flag for the object. *pbDisplayOnly = pObject->isDisplayOnly(); } } /*=========================================================================== Desc: Sets value for an object in the form. ===========================================================================*/ RCODE FlmForm::setObjectValue( FLMUINT uiObjectId, void * pvValue, FLMUINT uiLen ) { RCODE rc = FERR_OK; FlmFormObject * pObject; F_UNREFERENCED_PARM( uiLen); // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // See if we can find the object. if ((pObject = findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } // Set the object's value, depending on object type. switch (pObject->getObjectType()) { case FORM_TEXT_OBJECT: { FlmFormTextObject * pTextObject = (FlmFormTextObject *)pObject; rc = pTextObject->setValue( (const char *)pvValue); break; } case FORM_UNSIGNED_OBJECT: { FlmFormUnsignedObject * pUnsignedObject = (FlmFormUnsignedObject *)pObject; rc = pUnsignedObject->setValue( (FLMUINT)pvValue); break; } case FORM_SIGNED_OBJECT: { FlmFormSignedObject * pSignedObject = (FlmFormSignedObject *)pObject; rc = pSignedObject->setValue( (FLMINT)pvValue); break; } case FORM_PULLDOWN_OBJECT: { FlmFormPulldownObject * pPulldownObject = (FlmFormPulldownObject *)pObject; rc = pPulldownObject->setCurrentItem( (FLMUINT)pvValue); break; } case FORM_RECORD_OBJECT: { FlmFormRecordObject * pRecordObject = (FlmFormRecordObject *)pObject; rc = pRecordObject->setValue( (NODE *)pvValue); break; } default: rc = RC_SET( FERR_NOT_IMPLEMENTED); break; } if (RC_BAD( rc)) { goto Exit; } m_bValuesChanged = TRUE; // Redisplay the object. if (m_bInteracting && pObject == m_pCurObject) { // Call changeFocus to reset edit buffer. (void)changeFocus( pObject, FALSE, TRUE); } else { displayObject( pObject); } Exit: return( rc); } /*=========================================================================== Desc: Sets a return address to populate when the form has been filled in - or when the object changes its value. ===========================================================================*/ RCODE FlmForm::setObjectReturnAddress( FLMUINT uiObjectId, void * pvReturnAddress, FLMUINT * puiReturnLen ) { RCODE rc = FERR_OK; FlmFormObject * pObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // See if we can find the object. if ((pObject = findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } pObject->setReturnAddress( pvReturnAddress, puiReturnLen); Exit: return( rc); } /*=========================================================================== Desc: Sets a return path in a GEDCOM tree to populate when the form has been filled in. ===========================================================================*/ RCODE FlmForm::setObjectReturnPath( FLMUINT uiObjectId, FLMUINT * puiReturnPath ) { RCODE rc = FERR_OK; FlmFormObject * pObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // See if we can find the object. if ((pObject = findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } pObject->setReturnPath( puiReturnPath); Exit: return( rc); } /*=========================================================================== Desc: Sets the help lines for an object in the form. ===========================================================================*/ RCODE FlmForm::setObjectHelp( FLMUINT uiObjectId, const char * pszHelpLine1, const char * pszHelpLine2) { RCODE rc = FERR_OK; FlmFormObject * pObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // See if we can find the object. if ((pObject = findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } rc = pObject->setHelp( pszHelpLine1, pszHelpLine2); Exit: return( rc); } /*=========================================================================== Desc: Sets value for a object in the form. ===========================================================================*/ RCODE FlmForm::setFormEventCB( FORM_EVENT_CB_p pEventCB, void * pvAppData, FLMBOOL bGetKeyStrokes ) { RCODE rc = FERR_OK; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } m_pEventCB = pEventCB; m_pvAppData = pvAppData; m_bGetKeyStrokes = bGetKeyStrokes; Exit: return( rc); } /*=========================================================================== Desc: Add a text object to the form. ===========================================================================*/ RCODE FlmForm::addTextObject( FLMUINT uiObjectId, const char * pszDefaultVal, FLMUINT uiMaxChars, FLMUINT uiWidth, FLMUINT uiFormat, FLMBOOL bDisplayOnly, FLMUINT uiBackColor, FLMUINT uiForeColor, FLMUINT uiRow, FLMUINT uiColumn) { RCODE rc = FERR_OK; FlmFormObject * pPrevObject; FlmFormTextObject * pTextObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object ID is not already used. if ((pPrevObject = findObject( uiObjectId)) != NULL) { rc = RC_SET( FERR_EXISTS); goto Exit; } // Find the objects this object should be linked to. This routine // also determines if there is an overlap. If so, it will return // an error. if (RC_BAD( rc = getObjectLocation( uiWidth, uiRow, uiColumn, &pPrevObject))) { goto Exit; } // Create a text object and link into the form. if ((pTextObject = new FlmFormTextObject) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if (RC_BAD( rc = pTextObject->setup( this, uiObjectId, uiMaxChars, uiWidth, uiFormat, bDisplayOnly, uiBackColor, uiForeColor, uiRow, uiColumn))) { goto Exit; } if (RC_BAD( rc = pTextObject->setValue( pszDefaultVal))) { goto Exit; } // Link the object into the form in its proper place. linkObjectInForm( pTextObject, pPrevObject); // Display the object displayObject( pTextObject); Exit: return( rc); } /*=========================================================================== Desc: Add an unsigned numeric object to the form. ===========================================================================*/ RCODE FlmForm::addUnsignedObject( FLMUINT uiObjectId, FLMUINT uiDefaultVal, FLMUINT uiMinVal, FLMUINT uiMaxVal, FLMUINT uiWidth, FLMUINT uiFormat, FLMBOOL bDisplayOnly, FLMUINT uiBackColor, FLMUINT uiForeColor, FLMUINT uiRow, FLMUINT uiColumn ) { RCODE rc = FERR_OK; FlmFormObject * pPrevObject; FlmFormUnsignedObject * pUnsignedObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object ID is not already used. if ((pPrevObject = findObject( uiObjectId)) != NULL) { rc = RC_SET( FERR_EXISTS); goto Exit; } // Find the objects this object should be linked to. This routine // also determines if there is an overlap. If so, it will return // an error. if (RC_BAD( rc = getObjectLocation( uiWidth, uiRow, uiColumn, &pPrevObject))) { goto Exit; } // Create an unsigned number object and link into the form. if ((pUnsignedObject = new FlmFormUnsignedObject) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if (RC_BAD( rc = pUnsignedObject->setup( this, uiObjectId, uiMinVal, uiMaxVal, uiWidth, uiFormat, bDisplayOnly, uiBackColor, uiForeColor, uiRow, uiColumn))) { goto Exit; } if (RC_BAD( rc = pUnsignedObject->setValue( uiDefaultVal))) { goto Exit; } // Link the object into the form in its proper place. linkObjectInForm( pUnsignedObject, pPrevObject); // Display the object displayObject( pUnsignedObject); Exit: return( rc); } /*=========================================================================== Desc: Add a signed numeric object to the form. ===========================================================================*/ RCODE FlmForm::addSignedObject( FLMUINT uiObjectId, FLMINT iDefaultVal, FLMINT iMinVal, FLMINT iMaxVal, FLMUINT uiWidth, FLMUINT uiFormat, FLMBOOL bDisplayOnly, FLMUINT uiBackColor, FLMUINT uiForeColor, FLMUINT uiRow, FLMUINT uiColumn ) { RCODE rc = FERR_OK; FlmFormObject * pPrevObject; FlmFormSignedObject * pSignedObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object ID is not already used. if ((pPrevObject = findObject( uiObjectId)) != NULL) { rc = RC_SET( FERR_EXISTS); goto Exit; } // Find the objects this object should be linked to. This routine // also determines if there is an overlap. If so, it will return // an error. if (RC_BAD( rc = getObjectLocation( uiWidth, uiRow, uiColumn, &pPrevObject))) { goto Exit; } // Create a signed number object and link into the form. if ((pSignedObject = new FlmFormSignedObject) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if (RC_BAD( rc = pSignedObject->setup( this, uiObjectId, iMinVal, iMaxVal, uiWidth, uiFormat, bDisplayOnly, uiBackColor, uiForeColor, uiRow, uiColumn))) { goto Exit; } if (RC_BAD( rc = pSignedObject->setValue( iDefaultVal))) { goto Exit; } // Link the object into the form in its proper place. linkObjectInForm( pSignedObject, pPrevObject); // Display the object displayObject( pSignedObject); Exit: return( rc); } /*=========================================================================== Desc: Add a pulldown object to the form. ===========================================================================*/ RCODE FlmForm::addPulldownObject( FLMUINT uiObjectId, FLMUINT uiWidth, FLMUINT uiHeight, FLMUINT uiBackColor, FLMUINT uiForeColor, FLMUINT uiRow, FLMUINT uiColumn, FLMBOOL bAutoEnter ) { RCODE rc = FERR_OK; FlmFormObject * pPrevObject; FlmFormPulldownObject * pPulldownObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object ID is not already used. if ((pPrevObject = findObject( uiObjectId)) != NULL) { rc = RC_SET( FERR_EXISTS); goto Exit; } // Find the objects this object should be linked to. This routine // also determines if there is an overlap. If so, it will return // an error. if (RC_BAD( rc = getObjectLocation( uiWidth, uiRow, uiColumn, &pPrevObject))) { goto Exit; } // Create a signed number object and link into the form. if ((pPulldownObject = new FlmFormPulldownObject) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if (RC_BAD( rc = pPulldownObject->setup( this, uiObjectId, uiWidth, uiHeight, uiBackColor, uiForeColor, uiRow, uiColumn))) { goto Exit; } pPulldownObject->setEnterMode( bAutoEnter); // Link the object into the form in its proper place. linkObjectInForm( pPulldownObject, pPrevObject); // Display the object displayObject( pPulldownObject); Exit: return( rc); } /*=========================================================================== Desc: Add a pulldown item to a pulldown object in the form. ===========================================================================*/ RCODE FlmForm::addPulldownItem( FLMUINT uiObjectId, FLMUINT uiItemId, const char * pszDisplayValue, FLMUINT uiShortcutKey) { RCODE rc = FERR_OK; FlmFormPulldownObject * pPulldownObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object has been defined. if ((pPulldownObject = (FlmFormPulldownObject *)findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } // Add the item to the pulldown if (RC_BAD( rc = pPulldownObject->addItem( uiItemId, pszDisplayValue, uiShortcutKey))) { goto Exit; } // Display the object displayObject( pPulldownObject); Exit: return( rc); } /*=========================================================================== Desc: Remove a pulldown item from a pulldown object in the form. ===========================================================================*/ RCODE FlmForm::removePulldownItem( FLMUINT uiObjectId, FLMUINT uiItemId ) { RCODE rc = FERR_OK; FlmFormPulldownObject * pPulldownObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object has been defined. if ((pPulldownObject = (FlmFormPulldownObject *)findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } // Remove the item to the pulldown if (RC_BAD( rc = pPulldownObject->removeItem( uiItemId))) { goto Exit; } // Display the object displayObject( pPulldownObject); Exit: return( rc); } /*=========================================================================== Desc: Removes all pulldown items from a pulldown object in the form. ===========================================================================*/ RCODE FlmForm::clearPulldownItems( FLMUINT uiObjectId ) { RCODE rc = FERR_OK; FlmFormPulldownObject * pPulldownObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object has been defined. if ((pPulldownObject = (FlmFormPulldownObject *)findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } // Clear all items from the pulldown if (RC_BAD( rc = pPulldownObject->clearItems())) { goto Exit; } // Display the object displayObject( pPulldownObject); Exit: return( rc); } /*=========================================================================== Desc: Sets a callback function for inserting new items into a pulldown object inside a form. ===========================================================================*/ RCODE FlmForm::setPulldownInsertCallback( FLMUINT uiObjectId, INSERT_FUNC_p pCallback, void * pvAppData ) { RCODE rc = FERR_OK; FlmFormPulldownObject * pPulldownObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object has been defined. if ((pPulldownObject = (FlmFormPulldownObject *)findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } // Set the callback for the pulldown object. pPulldownObject->setPulldownInsertCallback( pCallback, pvAppData); Exit: return( rc); } /*=========================================================================== Desc: Sets flag indicating that we are to return all of the items in the list for this object on the screen, not just the current one. ===========================================================================*/ RCODE FlmForm::setPulldownReturnAll( FLMUINT uiObjectId, FLMUINT uiItemIdTag, FLMUINT uiItemNameTag ) { RCODE rc = FERR_OK; FlmFormPulldownObject * pPulldownObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object has been defined. if ((pPulldownObject = (FlmFormPulldownObject *)findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } // Set the callback for the pulldown object. pPulldownObject->setPulldownReturnAll( uiItemIdTag, uiItemNameTag); Exit: return( rc); } /*=========================================================================== Desc: Gets the pulldown object for a specific object on the form. ===========================================================================*/ FlmPulldownList * FlmForm::getPulldownObject( FLMUINT uiObjectId ) { FlmPulldownList * pPulldown = NULL; FlmFormPulldownObject * pPulldownObject; // Form must be initialized if (!m_pDisplayWindow) { goto Exit; } // Make sure the object has been defined. if ((pPulldownObject = (FlmFormPulldownObject *)findObject( uiObjectId)) == NULL) { goto Exit; } // Get the callback for the pulldown object. pPulldown = pPulldownObject->getPulldownObject(); Exit: return( pPulldown); } /*=========================================================================== Desc: Sets the mode for entering an object - does it happen automatically? Used only for pulldown and record objects. ===========================================================================*/ RCODE FlmForm::setEnterMode( FLMUINT uiObjectId, FLMBOOL bAutoEnter ) { RCODE rc = FERR_OK; FlmFormObject * pObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object has been defined. if ((pObject = findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } if (pObject->getObjectType() == FORM_PULLDOWN_OBJECT) { ((FlmFormPulldownObject *)pObject)->setEnterMode( bAutoEnter); } else if (pObject->getObjectType() == FORM_RECORD_OBJECT) { ((FlmFormRecordObject *)pObject)->setEnterMode( bAutoEnter); } else { flmAssert( 0); } Exit: return( rc); } /*=========================================================================== Desc: Adds a GEDCOM record(s) object - for editing GEDCOM. ===========================================================================*/ RCODE FlmForm::addRecordObject( FLMUINT uiObjectId, const char * pszTitle, NODE * pDefaultRecords, FLMUINT uiWidth, FLMUINT uiBackColor, FLMUINT uiForeColor, FLMUINT uiRow, FLMUINT uiColumn, FLMBOOL bAutoEnter) { RCODE rc = FERR_OK; FlmFormObject * pPrevObject; FlmFormRecordObject * pRecordObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object ID is not already used. if ((pPrevObject = findObject( uiObjectId)) != NULL) { rc = RC_SET( FERR_EXISTS); goto Exit; } // Find the objects this object should be linked to. This routine // also determines if there is an overlap. If so, it will return // an error. if (RC_BAD( rc = getObjectLocation( uiWidth, uiRow, uiColumn, &pPrevObject))) { goto Exit; } // Create a signed number object and link into the form. if ((pRecordObject = new FlmFormRecordObject) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if (RC_BAD( rc = pRecordObject->setup( this, uiObjectId, pszTitle, uiWidth, uiBackColor, uiForeColor, uiRow, uiColumn))) { goto Exit; } if (RC_BAD( rc = pRecordObject->setValue( pDefaultRecords))) { goto Exit; } pRecordObject->setEnterMode( bAutoEnter); // Link the object into the form in its proper place. linkObjectInForm( pRecordObject, pPrevObject); // Display the object displayObject( pRecordObject); Exit: return( rc); } /*=========================================================================== Desc: Sets the database handle and container for a GEDCOM record(s) object. ===========================================================================*/ RCODE FlmForm::setRecordObjectDbAndCont( FLMUINT uiObjectId, HFDB hDb, FLMUINT uiContainer ) { RCODE rc = FERR_OK; FlmFormObject * pObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object ID is not already used. if ((pObject = findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } ((FlmFormRecordObject *)pObject)->setDb( hDb); ((FlmFormRecordObject *)pObject)->setContainer( uiContainer); Exit: return( rc); } /*=========================================================================== Desc: Moves the form cursor to the first object on the form. ===========================================================================*/ FLMUINT FlmForm::firstObject( FLMBOOL bSkipDisplayOnly, FLMBOOL bSkipEditable, FLMBOOL bRaiseExitEvent, FLMBOOL bRaiseEnterEvent ) { FLMUINT uiChar = 0; FlmFormObject * pFirstObject; if (m_pFirstObject) { flmAssert( !bSkipDisplayOnly || !bSkipEditable); // Verify the current object. if (bRaiseExitEvent && m_pCurObject) { if (!verifyObject( bRaiseExitEvent)) goto Exit; } pFirstObject = m_pFirstObject; // Skip any objects that are display only if the // bSkipDisplayOnly flag is set if (bSkipDisplayOnly) { while (pFirstObject->isDisplayOnly()) { pFirstObject = pFirstObject->getNextObject(); if (pFirstObject == m_pFirstObject) { break; } } } // Skip any objects that are NOT display only if the // bSkipEditable flag is set else if (bSkipEditable) { while (!pFirstObject->isDisplayOnly()) { pFirstObject = pFirstObject->getNextObject(); if (pFirstObject == m_pFirstObject) { break; } } } uiChar = changeFocus( pFirstObject, bRaiseEnterEvent, FALSE); } Exit: return( uiChar); } /*=========================================================================== Desc: Moves the form cursor to the last object on the form. ===========================================================================*/ FLMUINT FlmForm::lastObject( FLMBOOL bSkipDisplayOnly, FLMBOOL bSkipEditable, FLMBOOL bRaiseExitEvent, FLMBOOL bRaiseEnterEvent ) { FLMUINT uiChar = 0; FlmFormObject * pLastObject; if (m_pLastObject) { flmAssert( !bSkipDisplayOnly || !bSkipEditable); // Verify the current object. if (!verifyObject( bRaiseExitEvent)) goto Exit; pLastObject = m_pLastObject; // Skip any objects that are display only if the // bSkipDisplayOnly flag is set if (bSkipDisplayOnly) { while (pLastObject->isDisplayOnly()) { pLastObject = pLastObject->getPrevObject(); if (pLastObject == m_pLastObject) { break; } } } // Skip any objects that are NOT display only if the // bSkipEditable flag is set else if (bSkipEditable) { while (!pLastObject->isDisplayOnly()) { pLastObject = pLastObject->getPrevObject(); if (pLastObject == m_pLastObject) { break; } } } uiChar = changeFocus( pLastObject, bRaiseEnterEvent, FALSE); } Exit: return( uiChar); } /*=========================================================================== Desc: Moves the form cursor to the next object on the form. ===========================================================================*/ FLMUINT FlmForm::nextObject( FLMBOOL bSkipDisplayOnly, FLMBOOL bSkipEditable, FLMBOOL bRaiseExitEvent, FLMBOOL bRaiseEnterEvent ) { FLMUINT uiChar = 0; FlmFormObject * pNextObject; if (m_pCurObject) { flmAssert( !bSkipDisplayOnly || !bSkipEditable); // Verify the current object. if (!verifyObject( bRaiseExitEvent)) goto Exit; // Skip any objects that are display only if the // bSkipDisplayOnly flag is set pNextObject = m_pCurObject->getNextObject(); if (bSkipDisplayOnly) { while (pNextObject != m_pCurObject && pNextObject->isDisplayOnly()) { pNextObject = pNextObject->getNextObject(); } } // Skip any objects that are NOT display only if the // bSkipEditable flag is set else if (bSkipEditable) { while (pNextObject != m_pCurObject && !pNextObject->isDisplayOnly()) { pNextObject = pNextObject->getNextObject(); } } uiChar = changeFocus( pNextObject, bRaiseEnterEvent, FALSE); } Exit: return( uiChar); } /*=========================================================================== Desc: Moves the form cursor to the previous object on the form. ===========================================================================*/ FLMUINT FlmForm::prevObject( FLMBOOL bSkipDisplayOnly, FLMBOOL bSkipEditable, FLMBOOL bRaiseExitEvent, FLMBOOL bRaiseEnterEvent ) { FLMUINT uiChar = 0; FlmFormObject * pPrevObject; if (m_pCurObject) { flmAssert( !bSkipDisplayOnly || !bSkipEditable); // Verify the current object. if (!verifyObject( bRaiseExitEvent)) goto Exit; pPrevObject = m_pCurObject->getPrevObject(); // Skip any objects that are display only if the // bSkipDisplayOnly flag is set if (bSkipDisplayOnly) { while (pPrevObject != m_pCurObject && pPrevObject->isDisplayOnly()) { pPrevObject = pPrevObject->getPrevObject(); } } // Skip any objects that are NOT display only if the // bSkipEditable flag is set else if (bSkipEditable) { while (pPrevObject != m_pCurObject && !pPrevObject->isDisplayOnly()) { pPrevObject = pPrevObject->getPrevObject(); } } uiChar = changeFocus( pPrevObject, bRaiseEnterEvent, FALSE); } Exit: return( uiChar); } /*=========================================================================== Desc: Moves the form cursor to the object on the form that is above the current object (if any). ===========================================================================*/ FLMUINT FlmForm::upObject( FLMBOOL bSkipDisplayOnly, FLMBOOL bSkipEditable, FLMBOOL bRaiseExitEvent, FLMBOOL bRaiseEnterEvent ) { FLMUINT uiChar = 0; FlmFormObject * pUpObject; FlmFormObject * pPrevObject; FLMUINT uiRow; FLMUINT uiColumn; FLMUINT uiClosestDistance; FLMUINT uiDistance; if (m_pCurObject) { flmAssert( !bSkipDisplayOnly || !bSkipEditable); // Verify the current object. if (!verifyObject( bRaiseExitEvent)) goto Exit; uiRow = m_pCurObject->getRow(); uiColumn = m_pCurObject->getColumn(); // Skip past all of the objects on the current row. pPrevObject = m_pCurObject->getPrevObject(); while (pPrevObject != m_pCurObject && pPrevObject->getRow() == uiRow) { pPrevObject = pPrevObject->getPrevObject(); } // Skip any objects that are display only if the // bSkipDisplayOnly flag is set if (bSkipDisplayOnly) { while (pPrevObject != m_pCurObject && pPrevObject->isDisplayOnly()) { pPrevObject = pPrevObject->getPrevObject(); } } // Skip any objects that are NOT display only if the // bSkipEditable flag is set else if (bSkipEditable) { while (pPrevObject != m_pCurObject && !pPrevObject->isDisplayOnly()) { pPrevObject = pPrevObject->getPrevObject(); } } // If there are no rows above this one, there is no up object. if (pPrevObject->getRow() < uiRow) { uiRow = pPrevObject->getRow(); // Find the object on this current row whose column is closest to // our current object. uiClosestDistance = COLUMN_DIFF( uiColumn, pPrevObject->getColumn()); pUpObject = pPrevObject; pPrevObject = pPrevObject->getPrevObject(); while (pPrevObject->getRow() == uiRow) { if ((pPrevObject->isDisplayOnly() && !bSkipDisplayOnly) || (!pPrevObject->isDisplayOnly() && !bSkipEditable)) { uiDistance = COLUMN_DIFF( uiColumn, pPrevObject->getColumn()); if (uiDistance >= uiClosestDistance) { break; } pUpObject = pPrevObject; uiClosestDistance = uiDistance; } pPrevObject = pPrevObject->getPrevObject(); } uiChar = changeFocus( pUpObject, bRaiseEnterEvent, FALSE); } else if (m_uiTopFormRow) { // Scroll up one line of the form is not displaying the top line // on the screen. m_uiTopFormRow--; m_uiEditRow++; refresh(); } } Exit: return( uiChar); } /*=========================================================================== Desc: Moves the form cursor to the object on the form that is below the current object (if any). ===========================================================================*/ FLMUINT FlmForm::downObject( FLMBOOL bSkipDisplayOnly, FLMBOOL bSkipEditable, FLMBOOL bRaiseExitEvent, FLMBOOL bRaiseEnterEvent ) { FLMUINT uiChar = 0; FlmFormObject * pDownObject; FlmFormObject * pNextObject; FLMUINT uiRow; FLMUINT uiColumn; FLMUINT uiClosestDistance; FLMUINT uiDistance; if (m_pCurObject) { flmAssert( !bSkipDisplayOnly || !bSkipEditable); // Verify the current object. if (!verifyObject( bRaiseExitEvent)) goto Exit; uiRow = m_pCurObject->getRow(); uiColumn = m_pCurObject->getColumn(); // Skip past all of the objects on the current row. pNextObject = m_pCurObject->getNextObject(); while (pNextObject != m_pCurObject && pNextObject->getRow() == uiRow) { pNextObject = pNextObject->getNextObject(); } // Skip any objects that are display only if the // bSkipDisplayOnly flag is set if (bSkipDisplayOnly) { while (pNextObject != m_pCurObject && pNextObject->isDisplayOnly()) { pNextObject = pNextObject->getNextObject(); } } // Skip any objects that are NOT display only if the // bSkipEditable flag is set else if (bSkipEditable) { while (pNextObject != m_pCurObject && !pNextObject->isDisplayOnly()) { pNextObject = pNextObject->getNextObject(); } } // If there are no rows below this one, there is no down object. if (pNextObject->getRow() > uiRow) { uiRow = pNextObject->getRow(); // Find the object on this current row whose column is closest to // our current object. uiClosestDistance = COLUMN_DIFF( uiColumn, pNextObject->getColumn()); pDownObject = pNextObject; pNextObject = pNextObject->getNextObject(); while (pNextObject->getRow() == uiRow) { if ((pNextObject->isDisplayOnly() && !bSkipDisplayOnly) || (!pNextObject->isDisplayOnly() && !bSkipEditable)) { uiDistance = COLUMN_DIFF( uiColumn, pNextObject->getColumn()); if (uiDistance >= uiClosestDistance) { break; } pDownObject = pNextObject; uiClosestDistance = uiDistance; } pNextObject = pNextObject->getNextObject(); } uiChar = changeFocus( pDownObject, bRaiseEnterEvent, FALSE); } } Exit: return( uiChar); } /*=========================================================================== Desc: Populates any registered return addresses with data from the form. ===========================================================================*/ RCODE FlmForm::getAllReturnData( void) { RCODE rc = FERR_OK; RCODE tmpRc; FlmFormObject * pObject = m_pFirstObject; for (;;) { // Don't quit on first bad one. Save RC and continue. if (RC_BAD( tmpRc = pObject->populateReturnAddress())) { rc = tmpRc; } pObject = pObject->getNextObject(); if (pObject == m_pFirstObject) { break; } } return( rc); } /*=========================================================================== Desc: Populates any registered return paths in a GEDCOM tree with data from the form. ===========================================================================*/ RCODE FlmForm::getAllReturnDataToTree( POOL * pPool, NODE * pTree) { RCODE rc = FERR_OK; RCODE tmpRc; FlmFormObject * pObject = m_pFirstObject; for (;;) { // Don't quit on first bad one. Save RC and continue. if (RC_BAD( tmpRc = pObject->populateReturnPath( pPool, pTree))) { rc = tmpRc; } pObject = pObject->getNextObject(); if (pObject == m_pFirstObject) { break; } } return( rc); } /*=========================================================================== Desc: Executes a form - handles all user input in the form. Return value is the last character that was pressed. ===========================================================================*/ FLMUINT FlmForm::interact( FLMBOOL * pbValuesChanged, FLMUINT * puiCurrObjectId) { FLMUINT uiChar; m_bValuesChanged = FALSE; // Form must be initialized if (!m_pDisplayWindow) { uiChar = 0; goto Exit; } // Set focus to the first object on the form. m_bInteracting = TRUE; m_pCurObject = NULL; firstObject( TRUE, FALSE, FALSE, TRUE); beep( NULL, (const char *)m_pCurObject); // Loop forever getting input. for (;;) { // See if we have been told to exit. if ((m_pThread) && (m_pThread->getShutdownFlag())) { uiChar = 0; goto Exit; } // Need to refresh the input cursor, in case it was changed by // a callback function. displayInputCursor(); if (FTXWinTestKB( m_pDisplayWindow) == FTXRC_SUCCESS) { FTXWinInputChar( m_pDisplayWindow, &uiChar); // Clear error message out of status line. beep( NULL, (const char *)m_pCurObject); if (m_pEventCB && m_bGetKeyStrokes) { if (!m_pEventCB( FORM_EVENT_KEY_STROKE, this, m_pCurObject, uiChar, &uiChar, m_pvAppData)) { // Must verify current object, unless callback changes the // character to ESCAPE. if (uiChar == WPK_ESCAPE || verifyObject( TRUE)) { goto Exit; } else { continue; } } } Handle_Char: switch( uiChar) { case WPK_DOWN: case WPK_CTRL_N: if ((uiChar = downObject( TRUE, FALSE, TRUE, TRUE)) != 0) goto Handle_Char; break; case WPK_UP: case WPK_CTRL_P: if ((uiChar = upObject( TRUE, FALSE, TRUE, TRUE)) != 0) goto Handle_Char; break; case WPK_PGUP: case WPK_CTRL_DOWN: case WPK_CTRL_UP: case WPK_PGDN: break; case WPK_CTRL_HOME: if ((uiChar = firstObject( TRUE, FALSE, TRUE, TRUE)) != 0) goto Handle_Char; break; case WPK_CTRL_END: if ((uiChar = lastObject( TRUE, FALSE, TRUE, TRUE)) != 0) goto Handle_Char; break; case WPK_CTRL_D: if (m_pCurObject->getObjectType() == FORM_PULLDOWN_OBJECT) { Edit_Pulldown_Error: beep( "Cannot edit: press ENTER to select from list"); } else if (m_pCurObject->getObjectType() == FORM_RECORD_OBJECT) { Edit_Record_Error: beep( "Press ENTER to edit record"); } else { clearLine(); } break; case WPK_DELETE: if (m_pCurObject->getObjectType() == FORM_PULLDOWN_OBJECT) { goto Edit_Pulldown_Error; } else if (m_pCurObject->getObjectType() == FORM_RECORD_OBJECT) { goto Edit_Record_Error; } else { deleteChar(); } break; case WPK_HOME: cursorHome(); break; case WPK_END: cursorEnd(); break; case WPK_INSERT: if (m_bInsertMode) { m_bInsertMode = FALSE; FTXWinSetCursorType( m_pDisplayWindow, WPS_CURSOR_VISIBLE | WPS_CURSOR_BLOCK); } else { m_bInsertMode = TRUE; FTXWinSetCursorType( m_pDisplayWindow, WPS_CURSOR_VISIBLE | WPS_CURSOR_UNDERLINE); } break; case WPK_RIGHT: if ((uiChar = cursorRight()) != 0) goto Handle_Char; break; case WPK_LEFT: if ((uiChar = cursorLeft()) != 0) goto Handle_Char; break; case WPK_CTRL_RIGHT: case WPK_CTRL_LEFT: case WPK_CTRL_C: case WPK_CTRL_X: case WPK_CTRL_V: break; case WPK_BACKSPACE: if (m_pCurObject->getObjectType() == FORM_PULLDOWN_OBJECT) { goto Edit_Pulldown_Error; } else if (m_pCurObject->getObjectType() == FORM_RECORD_OBJECT) { goto Edit_Record_Error; } else { backspaceChar(); } break; case WPK_ENTER: if (m_pCurObject->getObjectType() == FORM_PULLDOWN_OBJECT) { FlmFormPulldownObject * pPulldownObject = (FlmFormPulldownObject *)m_pCurObject; FLMUINT uiOldItemId; FLMUINT uiNewItemId; pPulldownObject->getCurrentItem( &uiOldItemId); uiChar = pPulldownObject->select(); pPulldownObject->getCurrentItem( &uiNewItemId); if (uiOldItemId != uiNewItemId) { m_bValuesChanged = TRUE; } if (uiChar) goto Handle_Char; } else if (m_pCurObject->getObjectType() == FORM_RECORD_OBJECT) { FLMBOOL bChanged; uiChar = ((FlmFormRecordObject *)m_pCurObject)->edit( &bChanged); if (bChanged) { m_bValuesChanged = TRUE; } if (uiChar) goto Handle_Char; } else { if ((uiChar = nextObject( TRUE, FALSE, TRUE, TRUE)) != 0) goto Handle_Char; } break; case WPK_TAB: if ((uiChar = nextObject( TRUE, FALSE, TRUE, TRUE)) != 0) goto Handle_Char; break; case WPK_STAB: if ((uiChar = prevObject( TRUE, FALSE, TRUE, TRUE)) != 0) goto Handle_Char; break; case WPK_ALT_H: // Help on form case WPK_CTRL_H: // Help on field in form. break; case WPK_ESCAPE: case WPK_ALT_Q: case WPK_F1: // Done with form - submit. // Verify the current object if not ESCAPE character if (uiChar == WPK_ESCAPE || verifyObject( TRUE)) { if (m_pEventCB && m_bGetKeyStrokes) { if (m_pEventCB( FORM_EVENT_EXIT_FORM, this, m_pCurObject, uiChar, &uiChar, m_pvAppData)) { goto Exit; } } else { goto Exit; } } break; case 0: break; default: if ((uiChar >= ' ') && (uiChar <= 0x7F)) { if (m_pCurObject->getObjectType() == FORM_PULLDOWN_OBJECT) { goto Edit_Pulldown_Error; } else if (m_pCurObject->getObjectType() == FORM_RECORD_OBJECT) { goto Edit_Record_Error; } else { insertChar( uiChar); } } else { beep( "Keystroke not recognized"); } break; } } else { f_sleep( 1); } } Exit: if (puiCurrObjectId && m_pCurObject) { *puiCurrObjectId = m_pCurObject->getObjectId(); } *pbValuesChanged = m_bValuesChanged; m_bInteracting = FALSE; return( uiChar); } /*=========================================================================== Desc: Retrieves various kinds of information about an object on a form. ===========================================================================*/ RCODE FlmForm::getObjectInfo( FLMUINT uiObjectId, FormObjectType * peObjectType, FLMUINT * puiBackColor, FLMUINT * puiForeColor, FLMUINT * puiRow, FLMUINT * puiCol, FLMUINT * puiWidth, void * pvMin, void * pvMax, FLMBOOL * pbDisplayOnly ) { RCODE rc = FERR_OK; FlmFormObject * pObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object has been defined. if ((pObject = findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } if (peObjectType) { *peObjectType = pObject->getObjectType(); } if (puiBackColor) { *puiBackColor = pObject->getBackColor(); } if (puiForeColor) { *puiForeColor = pObject->getForeColor(); } if (puiRow) { *puiRow = pObject->getRow(); } if (puiCol) { *puiCol = pObject->getColumn(); } if (puiWidth) { *puiWidth = pObject->getWidth(); } if (pvMin) { switch (pObject->getObjectType()) { case FORM_UNSIGNED_OBJECT: *((FLMUINT *)pvMin) = ((FlmFormUnsignedObject *)pObject)->getMin(); break; case FORM_SIGNED_OBJECT: *((FLMINT *)pvMin) = ((FlmFormSignedObject *)pObject)->getMin(); break; default: *((FLMUINT *)pvMin) = 0; break; } } if (pvMax) { switch (pObject->getObjectType()) { case FORM_UNSIGNED_OBJECT: *((FLMUINT *)pvMax) = ((FlmFormUnsignedObject *)pObject)->getMax(); break; case FORM_SIGNED_OBJECT: *((FLMINT *)pvMax) = ((FlmFormSignedObject *)pObject)->getMax(); break; default: *((FLMUINT *)pvMax) = pObject->getMaxEditChars(); break; } } if (pbDisplayOnly) { *pbDisplayOnly = pObject->isDisplayOnly(); } Exit: return( rc); } /*=========================================================================== Desc: Retrieve a text value from the form ===========================================================================*/ RCODE FlmForm::getTextVal( FLMUINT uiObjectId, FLMUINT * puiLen, char * pszValRV) { RCODE rc = FERR_OK; FlmFormTextObject * pTextObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object has been defined. if ((pTextObject = (FlmFormTextObject *)findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } if (pTextObject->getObjectType() != FORM_TEXT_OBJECT) { flmAssert( 0); } if (RC_BAD( rc = pTextObject->getValue( puiLen, pszValRV))) { goto Exit; } Exit: return( rc); } /*=========================================================================== Desc: Retrieve an unsigned numeric value from the form ===========================================================================*/ RCODE FlmForm::getUnsignedVal( FLMUINT uiObjectId, FLMUINT * puiValRV ) { RCODE rc = FERR_OK; FlmFormObject * pObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object has been defined. if ((pObject = findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } if (pObject->getObjectType() == FORM_UNSIGNED_OBJECT) { if (RC_BAD( rc = ((FlmFormUnsignedObject *)pObject)->getValue( puiValRV))) { goto Exit; } } else if (pObject->getObjectType() == FORM_PULLDOWN_OBJECT) { if (RC_BAD( rc = ((FlmFormPulldownObject *)pObject)->getCurrentItem( puiValRV))) { goto Exit; } } else { flmAssert( 0); } Exit: return( rc); } /*=========================================================================== Desc: Retrieve a signed numeric value from the form ===========================================================================*/ RCODE FlmForm::getSignedVal( FLMUINT uiObjectId, FLMINT * piValRV ) { RCODE rc = FERR_OK; FlmFormSignedObject * pSignedObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object has been defined. if ((pSignedObject = (FlmFormSignedObject *)findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } if (pSignedObject->getObjectType() != FORM_SIGNED_OBJECT) { flmAssert( 0); } if (RC_BAD( rc = pSignedObject->getValue( piValRV))) { goto Exit; } Exit: return( rc); } /*=========================================================================== Desc: Retrieve a GEDCOM record value from the form ===========================================================================*/ RCODE FlmForm::getRecordVal( FLMUINT uiObjectId, NODE * * ppRecord, POOL * pPool) { RCODE rc = FERR_OK; FlmFormRecordObject * pRecordObject; // Form must be initialized if (!m_pDisplayWindow) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Make sure the object has been defined. if ((pRecordObject = (FlmFormRecordObject *)findObject( uiObjectId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } if (pRecordObject->getObjectType() != FORM_RECORD_OBJECT) { flmAssert( 0); } if (RC_BAD( rc = pRecordObject->getValue( ppRecord, pPool))) { goto Exit; } Exit: return( rc); } /*=========================================================================== Desc: Verifies the current object and sets its value if it is verified. Otherwise, returns FALSE. ===========================================================================*/ FLMBOOL FlmForm::verifyObject( FLMBOOL bRaiseExitEvent ) { FLMBOOL bOk = TRUE; FLMUINT uiVal; FLMINT iVal; // Verify the input - make sure it is null terminated first. m_pszEditBuf [m_uiNumCharsEntered] = 0; switch (m_pCurObject->getObjectType()) { case FORM_TEXT_OBJECT: ((FlmFormTextObject *)m_pCurObject)->setValue( m_pszEditBuf); break; case FORM_UNSIGNED_OBJECT: if (!((FlmFormUnsignedObject *)m_pCurObject)->verifyValue( m_pszEditBuf, &uiVal)) { bOk = FALSE; goto Exit; } ((FlmFormUnsignedObject *)m_pCurObject)->setValue( uiVal); break; case FORM_SIGNED_OBJECT: if (!((FlmFormSignedObject *)m_pCurObject)->verifyValue( m_pszEditBuf, &iVal)) { bOk = FALSE; goto Exit; } ((FlmFormSignedObject *)m_pCurObject)->setValue( iVal); break; case FORM_PULLDOWN_OBJECT: case FORM_RECORD_OBJECT: break; } // Do exit callback if (m_pEventCB && bRaiseExitEvent) { bOk = m_pEventCB( FORM_EVENT_EXIT_OBJECT, this, m_pCurObject, 0, NULL, m_pvAppData); } Exit: return( bOk); } /*=========================================================================== Desc: Moves the form cursor to the first object on the form. ===========================================================================*/ FLMUINT FlmForm::changeFocus( FlmFormObject * pNewObject, FLMBOOL bRaiseEnterEvent, FLMBOOL bForceChange) { FLMUINT uiChar = 0; char * pszTmp; FLMUINT uiMaxEditChars; // Form must be initialized if (!m_pDisplayWindow) { goto Exit; } // Go to the new object on the form. if ((pNewObject) && ((m_pCurObject != pNewObject) || (bForceChange))) { // Redisplay the current object. if (m_pCurObject) { displayObject( m_pCurObject); } // Determine if the object is visible. m_pCurObject = pNewObject; if (!isVisible( pNewObject)) { // Object not visible, reposition the form and redisplay the entire // form. // If the object will fit in the first page of the form, set the // top form of the row to zero. if (pNewObject->getRow() < m_uiTopFormRow) { m_uiTopFormRow = pNewObject->getRow(); } else { if (pNewObject->getRow() > m_uiRows - 1) { m_uiTopFormRow = pNewObject->getRow() - m_uiRows + 1; } else { flmAssert( 0); // Should never be able to get here. m_uiTopFormRow = 0; } } refresh(); } // Do the entry callback if (m_pEventCB && bRaiseEnterEvent) { (void)m_pEventCB( FORM_EVENT_ENTER_OBJECT, this, m_pCurObject, 0, NULL, m_pvAppData); } // Set up to edit the new object. uiMaxEditChars = pNewObject->getMaxEditChars(); if (m_uiEditBufSize < uiMaxEditChars + 1) { // Allocate a new buffer. if( RC_BAD( f_alloc( uiMaxEditChars + 1, &pszTmp))) { goto Exit; } if (m_pszEditBuf) { f_free( &m_pszEditBuf); m_pszEditBuf = NULL; m_uiEditBufSize = 0; } m_pszEditBuf = pszTmp; m_uiEditBufSize = uiMaxEditChars + 1; } m_uiMaxCharsToEnter = uiMaxEditChars; pNewObject->formatEditBuffer( m_pszEditBuf); m_uiNumCharsEntered = f_strlen( m_pszEditBuf); m_uiEditWidth = pNewObject->getWidth(); m_uiEditBufPos = 0; m_uiEditBufLeftColPos = 0; m_uiEditColumn = pNewObject->getColumn(); m_uiEditRow = pNewObject->getRow() - m_uiTopFormRow; m_bInsertMode = TRUE; m_pCurObject = pNewObject; m_bShowingHelpStatus = FALSE; beep( NULL, (const char *)m_pCurObject); FTXWinSetCursorType( m_pDisplayWindow, WPS_CURSOR_VISIBLE | WPS_CURSOR_UNDERLINE); // Set the background and foreground color refreshLine( m_uiEditBufPos, m_uiEditWidth); if ((m_pCurObject->getObjectType() == FORM_PULLDOWN_OBJECT) && (((FlmFormPulldownObject *)m_pCurObject)->isAutoEnterMode())) { uiChar = WPK_ENTER; } else if ((m_pCurObject->getObjectType() == FORM_RECORD_OBJECT) && (((FlmFormRecordObject *)m_pCurObject)->isAutoEnterMode())) { uiChar = WPK_ENTER; } } Exit: return( uiChar); } /*=========================================================================== Desc: Finds an object by tag number. ===========================================================================*/ FlmFormObject * FlmForm::findObject( FLMUINT uiObjectId ) { FlmFormObject * pObject; // Follow the linked list of objects until we find the one that matches // the tag we are looking for. if ((pObject = m_pFirstObject) != NULL) { for (;;) { if (pObject->getObjectId() == uiObjectId) break; pObject = pObject->getNextObject(); // break when we have circled all the way around. if (pObject == m_pFirstObject) { pObject = NULL; break; } } } return( pObject); } /*=========================================================================== Desc: Determines if an object is currently visible. ===========================================================================*/ FLMBOOL FlmForm::isVisible( FlmFormObject * pObject ) { return( (FLMBOOL)((pObject->getRow() >= m_uiTopFormRow && pObject->getRow() <= m_uiTopFormRow + m_uiRows - 1) ? (FLMBOOL)TRUE : (FLMBOOL)FALSE)); } /*=========================================================================== Desc: Displays an object - if it is visible. ===========================================================================*/ void FlmForm::displayObject( FlmFormObject * pObject ) { // If the object is visible, tell it to display itself. if (isVisible( pObject)) { pObject->display( pObject->getRow() - m_uiTopFormRow, pObject->getColumn()); } } /*=========================================================================== Desc: Determines where an object should be linked into the form. Also determines if the object overlaps any other objects. If so, an error will be returned. ===========================================================================*/ RCODE FlmForm::getObjectLocation( FLMUINT uiWidth, FLMUINT uiRow, FLMUINT uiColumn, FlmFormObject ** ppPrevObject ) { RCODE rc = FERR_OK; FlmFormObject * pPrevObject; FlmFormObject * pNextObject; // Follow linked list of objects until we find the one that is just // before this one. pPrevObject = NULL; pNextObject = m_pFirstObject; while (pNextObject && pNextObject->getRow() < uiRow) { pPrevObject = pNextObject; if ((pNextObject = pNextObject->getNextObject()) == m_pFirstObject) { pNextObject = NULL; break; } } // If the next object is on the same row as the new // object, search down the row until we hit an // object whose column is > the new object's column. while (pNextObject && pNextObject->getRow() == uiRow && pNextObject->getColumn() < uiColumn) { pPrevObject = pNextObject; if ((pNextObject = pNextObject->getNextObject()) == m_pFirstObject) { pNextObject = NULL; break; } } // If the previous object is on the same row, see if there // is any overlap between it, the new object, and the next // object. if (uiWidth) { if (pPrevObject && pPrevObject->getWidth() && pPrevObject->getRow() == uiRow) { if (pPrevObject->getColumn() + pPrevObject->getWidth() - 1 >= uiColumn) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } } if (pNextObject && pNextObject->getWidth() && pNextObject->getRow() == uiRow) { if (uiColumn + uiWidth - 1 >= pNextObject->getColumn()) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } } } // Make sure the column plus its width will fit in the form window. if (uiColumn + uiWidth > m_uiCols) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } *ppPrevObject = pPrevObject; Exit: return( rc); } /*=========================================================================== Desc: Links an object into a form - after the passed in prev object. ===========================================================================*/ void FlmForm::linkObjectInForm( FlmFormObject * pNewObject, FlmFormObject * pPrevObject ) { FlmFormObject * pNextObject; if (!m_pFirstObject) { pNextObject = pPrevObject = m_pFirstObject = m_pLastObject = pNewObject; } else if (!pPrevObject) { pPrevObject = m_pLastObject; pNextObject = m_pFirstObject; m_pFirstObject = pNewObject; } else { if ((pNextObject = pPrevObject->getNextObject()) == m_pFirstObject) { m_pLastObject = pNewObject; } } pNewObject->setNextObject( pNextObject); pNewObject->setPrevObject( pPrevObject); pNextObject->setPrevObject( pNewObject); pPrevObject->setNextObject( pNewObject); } /*=========================================================================== Desc: Refresh the portion of the line specified. ===========================================================================*/ void FlmForm::refreshLine( FLMUINT uiPos, FLMUINT uiChars ) { FLMBYTE ucSaveByte; // Use foreground color as background color, and vice versa when // editing. FTXWinSetBackFore( m_pDisplayWindow, m_bMonochrome ? WPS_WHITE : m_pCurObject->getForeColor(), m_bMonochrome ? WPS_BLACK : m_pCurObject->getBackColor()); // If there are fewer characters in the edit buffer than // what we are being asked to display, we need to blank // out whatever portion comes after the end of line. if (uiChars > m_uiNumCharsEntered - uiPos) { if (uiPos < m_uiNumCharsEntered) { m_pszEditBuf [m_uiNumCharsEntered] = 0; FTXWinPrintStrXY( m_pDisplayWindow, &m_pszEditBuf [uiPos], m_uiEditColumn + uiPos - m_uiEditBufLeftColPos, m_uiEditRow); uiChars -= (m_uiNumCharsEntered - uiPos); } else { FTXWinSetCursorPos( m_pDisplayWindow, m_uiEditColumn + uiPos - m_uiEditBufLeftColPos, m_uiEditRow); } // Blank out the rest of the box up to the number of // characters specified. while (uiChars) { FTXWinPrintChar( m_pDisplayWindow, ' '); uiChars--; } } else { ucSaveByte = m_pszEditBuf [uiPos + uiChars]; m_pszEditBuf [uiPos + uiChars] = 0; FTXWinPrintStrXY( m_pDisplayWindow, &m_pszEditBuf [uiPos], m_uiEditColumn + uiPos - m_uiEditBufLeftColPos, m_uiEditRow); m_pszEditBuf [uiPos + uiChars] = ucSaveByte; } } /*=========================================================================== Desc: Move cursor to the beginning of the line ===========================================================================*/ void FlmForm::cursorHome( void) { if (m_uiEditBufPos) { m_uiEditBufPos = 0; if (m_uiEditBufLeftColPos) { m_uiEditBufLeftColPos = 0; refreshLine( m_uiEditBufLeftColPos, m_uiEditWidth); } } else { beep( "Already at beginning of line"); } } /*=========================================================================== Desc: Move cursor to the end of the line ===========================================================================*/ void FlmForm::cursorEnd( void) { if (m_uiEditBufPos < m_uiNumCharsEntered) { m_uiEditBufPos = m_uiNumCharsEntered; if (m_uiEditBufLeftColPos + m_uiEditWidth <= m_uiNumCharsEntered) { m_uiEditBufLeftColPos = m_uiNumCharsEntered - m_uiEditWidth + 1; refreshLine( m_uiEditBufLeftColPos, m_uiEditWidth); } } else { beep( "Already at end of line"); } } /*=========================================================================== Desc: Move cursor right one character. ===========================================================================*/ FLMUINT FlmForm::cursorRight( void) { FLMUINT uiChar = 0; if ((m_uiEditBufPos < m_uiNumCharsEntered) && (m_pCurObject->getObjectType() != FORM_PULLDOWN_OBJECT) && (m_pCurObject->getObjectType() != FORM_RECORD_OBJECT)) { m_uiEditBufPos++; if (m_uiEditBufLeftColPos + m_uiEditWidth - 1 < m_uiEditBufPos) { m_uiEditBufLeftColPos++; refreshLine( m_uiEditBufLeftColPos, m_uiEditWidth); } } else { uiChar = nextObject(); } return( uiChar); } /*=========================================================================== Desc: Move cursor left one character. ===========================================================================*/ FLMUINT FlmForm::cursorLeft( void) { FLMUINT uiChar = 0; if ((m_uiEditBufPos) && (m_pCurObject->getObjectType() != FORM_PULLDOWN_OBJECT) && (m_pCurObject->getObjectType() != FORM_RECORD_OBJECT)) { m_uiEditBufPos--; if (m_uiEditBufLeftColPos > m_uiEditBufPos) { m_uiEditBufLeftColPos--; refreshLine( m_uiEditBufLeftColPos, m_uiEditWidth); } } else { uiChar = prevObject(); } return( uiChar); } /*=========================================================================== Desc: Delete the character the cursor is positioned on. ===========================================================================*/ void FlmForm::deleteChar( void) { if (m_uiEditBufPos < m_uiNumCharsEntered) { if (m_uiEditBufPos < m_uiNumCharsEntered - 1) { f_memmove( &m_pszEditBuf [m_uiEditBufPos], &m_pszEditBuf [m_uiEditBufPos + 1], m_uiNumCharsEntered - m_uiEditBufPos - 1); } m_uiNumCharsEntered--; if (m_uiEditWidth <= m_uiNumCharsEntered - m_uiEditBufLeftColPos + 1) { refreshLine( m_uiEditBufPos, m_uiEditWidth - (m_uiEditBufPos - m_uiEditBufLeftColPos)); } else { refreshLine( m_uiEditBufPos, m_uiNumCharsEntered - m_uiEditBufPos + 1); } m_bValuesChanged = TRUE; } else { beep( "At end of line - nothing to delete"); } } /*=========================================================================== Desc: Insert a character where the cursor is positioned. ===========================================================================*/ void FlmForm::insertChar( FLMUINT uiChar ) { // See if the buffer is full. if ((m_uiNumCharsEntered == m_uiMaxCharsToEnter) && ((m_bInsertMode) || (m_uiEditBufPos == m_uiNumCharsEntered))) { beep( "Maximum number of characters have been entered"); return; } if (m_uiEditBufPos == m_uiNumCharsEntered) { m_pszEditBuf [m_uiNumCharsEntered++] = (FLMBYTE)uiChar; m_uiEditBufPos++; if (m_uiNumCharsEntered == m_uiMaxCharsToEnter) { refreshLine( m_uiEditBufPos - 1, 1); } else if (m_uiEditBufPos - m_uiEditBufLeftColPos >= m_uiEditWidth) { m_uiEditBufLeftColPos++; refreshLine( m_uiEditBufLeftColPos, m_uiEditWidth); } else { refreshLine( m_uiEditBufPos - 1, 1); } } else if (m_bInsertMode) { f_memmove( &m_pszEditBuf [m_uiEditBufPos + 1], &m_pszEditBuf [m_uiEditBufPos], m_uiNumCharsEntered - m_uiEditBufPos); m_uiNumCharsEntered++; m_pszEditBuf [m_uiEditBufPos++] = (FLMBYTE)uiChar; if (m_uiEditBufPos - m_uiEditBufLeftColPos >= m_uiEditWidth) { m_uiEditBufLeftColPos++; refreshLine( m_uiEditBufLeftColPos, m_uiEditWidth); } else if (m_uiEditWidth <= m_uiNumCharsEntered - m_uiEditBufLeftColPos + 1) { refreshLine( m_uiEditBufPos - 1, m_uiEditWidth - (m_uiEditBufPos - 1 - m_uiEditBufLeftColPos)); } else { refreshLine( m_uiEditBufPos - 1, m_uiNumCharsEntered - (m_uiEditBufPos - 1)); } } else { m_pszEditBuf [m_uiEditBufPos++] = (FLMBYTE)uiChar; if (m_uiEditBufPos - m_uiEditBufLeftColPos >= m_uiEditWidth) { m_uiEditBufLeftColPos++; refreshLine( m_uiEditBufLeftColPos, m_uiEditWidth); } else { refreshLine( m_uiEditBufPos - 1, 1); } } m_bValuesChanged = TRUE; } /*=========================================================================== Desc: Delete the character to the left of the cursor. ===========================================================================*/ void FlmForm::backspaceChar( void) { if (m_uiEditBufPos) { m_uiEditBufPos--; if (m_uiEditBufPos < m_uiNumCharsEntered - 1) { f_memmove( &m_pszEditBuf [m_uiEditBufPos], &m_pszEditBuf [m_uiEditBufPos + 1], m_uiNumCharsEntered - m_uiEditBufPos - 1); } m_uiNumCharsEntered--; if (m_uiEditBufPos <= m_uiEditBufLeftColPos && m_uiEditBufLeftColPos) { if (m_uiEditBufPos) { m_uiEditBufLeftColPos = m_uiEditBufPos - 1; } else { m_uiEditBufLeftColPos = 0; } if (m_uiEditWidth > m_uiNumCharsEntered - m_uiEditBufLeftColPos + 1) { refreshLine( m_uiEditBufLeftColPos, m_uiNumCharsEntered - m_uiEditBufLeftColPos + 1); } else { refreshLine( m_uiEditBufLeftColPos, m_uiEditWidth); } } else if (m_uiEditWidth > m_uiNumCharsEntered - m_uiEditBufLeftColPos + 1) { refreshLine( m_uiEditBufPos, m_uiNumCharsEntered - m_uiEditBufPos + 2); } else { refreshLine( m_uiEditBufPos, m_uiEditWidth - (m_uiEditBufPos - m_uiEditBufLeftColPos)); } m_bValuesChanged = TRUE; } else { beep( "Cannot backspace - at beginning of line"); } } /*=========================================================================== Desc: Delete all characters from current cursor position to end of line, including the character the cursor is currently positioned on. ===========================================================================*/ void FlmForm::clearLine( void) { if (m_uiEditBufPos < m_uiNumCharsEntered) { m_uiNumCharsEntered = m_uiEditBufPos; refreshLine( m_uiEditBufPos, m_uiEditWidth - (m_uiEditBufPos - m_uiEditBufLeftColPos)); m_bValuesChanged = TRUE; } else { beep( "Nothing to clear - at end of line"); } } /*=========================================================================== Desc: Redisplay the input cursor. ===========================================================================*/ void FlmForm::displayInputCursor( void) { FLMUINT uiCol; FLMUINT uiRow; FTXWinGetCursorPos( m_pDisplayWindow, &uiCol, &uiRow); if ((uiCol != m_uiEditColumn + (m_uiEditBufPos - m_uiEditBufLeftColPos)) || (uiRow != m_uiEditRow)) { FTXWinSetCursorPos( m_pDisplayWindow, m_uiEditColumn + (m_uiEditBufPos - m_uiEditBufLeftColPos), m_uiEditRow); } } /*=========================================================================== Desc: Beep and display an error message in the status box. ===========================================================================*/ void FlmForm::beep( const char * pszErrMsg1, const char * pszErrMsg2) { FLMUINT uiElapTime; FLMUINT uiMilli; if (m_pStatusWindow) { if (pszErrMsg1) { FTXWinSetBackFore( m_pStatusWindow, m_bMonochrome ? WPS_BLACK : WPS_RED, WPS_WHITE); FTXWinClearLine( m_pStatusWindow, 0, 0); FTXWinClearLine( m_pStatusWindow, 0, 1); FTXWinPrintStrXY( m_pStatusWindow, pszErrMsg1, 0, 0); if (pszErrMsg2) { FTXWinPrintStrXY( m_pStatusWindow, pszErrMsg2, 0, 1); } FTXWinSetBackFore( m_pStatusWindow, m_bMonochrome ? WPS_BLACK : WPS_GREEN, WPS_WHITE); uiElapTime = FLM_GET_TIMER() - m_uiLastTimeBeeped; FLM_TIMER_UNITS_TO_MILLI( uiElapTime, uiMilli); if (uiMilli >= 100) { ftxBeep(); m_uiLastTimeBeeped = FLM_GET_TIMER(); } m_bShowingHelpStatus = FALSE; } else if (!m_bShowingHelpStatus) { FlmFormObject * pObject = (FlmFormObject *)pszErrMsg2; char szHelp1 [100]; char szHelp2 [100]; FTXWinClearLine( m_pStatusWindow, 0, 0); FTXWinClearLine( m_pStatusWindow, 0, 1); pObject->getHelp( szHelp1, sizeof( szHelp1), szHelp2, sizeof( szHelp2)); if (szHelp1 [0]) { FTXWinPrintStrXY( m_pStatusWindow, szHelp1, 0, 0); } if (szHelp2 [0]) { FTXWinPrintStrXY( m_pStatusWindow, szHelp2, 0, 1); } m_bShowingHelpStatus = TRUE; } } } /*=========================================================================== Desc: Initializes variables ===========================================================================*/ FlmFormObject::FlmFormObject() { m_uiObjectId = 0; m_uiRow = 0; m_uiColumn = 0; m_uiWidth = 0; m_uiFormat = 0; m_bDisplayOnly = FALSE; m_uiHelpBuffSize = 0; m_pszHelpLine1 = NULL; m_pszHelpLine2 = NULL; m_pForm = NULL; m_uiMaxEditChars = 0; m_pvReturnAddress = NULL; m_puiReturnLen = NULL; m_uiReturnPath [0] = 0; m_uiBackColor = WPS_WHITE; m_uiForeColor = WPS_BLUE; m_pNextObject = NULL; m_pPrevObject = NULL; } FlmFormObject::~FlmFormObject() { if (m_pszHelpLine1) { f_free( &m_pszHelpLine1); } } /*=========================================================================== Desc: Output text to the field - justify to left, center or right. ===========================================================================*/ void FlmFormObject::outputText( char * pszText, FLMUINT uiRow, FLMUINT uiColumn) { FLMUINT uiChars = f_strlen( pszText); FTX_WINDOW_p pWindow = m_pForm->getWindow(); FLMUINT uiPreFill = 0; FLMUINT uiPostFill = 0; char * pszDispText; char * pszRestoreChar = NULL; char ucSave; FTXWinSetBackFore( pWindow, m_pForm->getMonochrome() ? WPS_BLACK : m_uiBackColor, m_pForm->getMonochrome() ? WPS_WHITE : m_uiForeColor); if (m_uiFormat & FORMAT_LEFT_JUSTIFY) { Left_Justify: pszDispText = pszText; if (uiChars <= m_uiWidth) { uiPostFill = m_uiWidth - uiChars; } else { pszRestoreChar = &pszText [m_uiWidth]; ucSave = *pszRestoreChar; *pszRestoreChar = 0; } } else if (m_uiFormat & FORMAT_RIGHT_JUSTIFY) { if (uiChars > m_uiWidth) { pszDispText = &pszText [uiChars - m_uiWidth]; } else { pszDispText = pszText; uiPreFill = m_uiWidth - uiChars; } } else if (m_uiFormat & FORMAT_CENTER_JUSTIFY) { if (uiChars > m_uiWidth) { pszDispText = &pszText [(uiChars - m_uiWidth) / 2]; pszRestoreChar = &pszDispText [m_uiWidth]; ucSave = *pszRestoreChar; *pszRestoreChar = 0; } else { pszDispText = pszText; uiPreFill = (m_uiWidth - uiChars) / 2; uiPostFill = m_uiWidth - uiChars - uiPreFill; } } else { goto Left_Justify; } FTXWinSetCursorPos( pWindow, uiColumn, uiRow); // Do the blank prefill. while (uiPreFill) { FTXWinPrintChar( pWindow, ' '); uiPreFill--; } // Output the text - will be right justified. if (*pszDispText) { FTXWinPrintStr( pWindow, pszDispText); } // Blank fill the rest while (uiPostFill) { FTXWinPrintChar( pWindow, ' '); uiPostFill--; } // Restore any overwritten character. if (pszRestoreChar) { *pszRestoreChar = ucSave; } } /*=========================================================================== Desc: Set help for an object on the form. ===========================================================================*/ RCODE FlmFormObject::setHelp( const char * pszHelpLine1, const char * pszHelpLine2) { RCODE rc = FERR_OK; FLMUINT uiLen1; FLMUINT uiLen2; char * pszTmp; uiLen1 = (FLMUINT)((pszHelpLine1) ? (FLMUINT)f_strlen( pszHelpLine1) : (FLMUINT)0); uiLen2 = (FLMUINT)((pszHelpLine2) ? (FLMUINT)f_strlen( pszHelpLine2) : (FLMUINT)0); // Allocate one buffer for both strings. if (uiLen1 + uiLen2 + 2 > m_uiHelpBuffSize) { if( RC_BAD( rc = f_alloc( uiLen1 + uiLen2 + 2, &pszTmp))) { goto Exit; } if (m_pszHelpLine1) { f_free( &m_pszHelpLine1); m_pszHelpLine1 = NULL; m_uiHelpBuffSize = 0; } m_pszHelpLine1 = pszTmp; m_uiHelpBuffSize = uiLen1 + uiLen2 + 2; } // Copy help line one into the buffer. if (pszHelpLine1 && uiLen1) { f_memcpy( m_pszHelpLine1, pszHelpLine1, uiLen1); } m_pszHelpLine1 [uiLen1] = 0; // Copy help line 2 into the buffer. m_pszHelpLine2 = m_pszHelpLine1 + uiLen1 + 1; if (pszHelpLine2 && uiLen2) { f_memcpy( m_pszHelpLine2, pszHelpLine2, uiLen2); } m_pszHelpLine2 [uiLen2] = 0; Exit: return( rc); } /*=========================================================================== Desc: Get the help lines for an object on the form. ===========================================================================*/ void FlmFormObject::getHelp( char * pszHelpLine1, FLMUINT uiHelpSize1, char * pszHelpLine2, FLMUINT uiHelpSize2) { FLMUINT uiLen; if (!m_pszHelpLine1) { *pszHelpLine1 = 0; } else { uiLen = f_strlen( m_pszHelpLine1); if (uiLen >= uiHelpSize1) { uiLen = uiHelpSize1 - 1; } if (uiLen) { f_memcpy( pszHelpLine1, m_pszHelpLine1, uiLen); } pszHelpLine1 [uiLen] = 0; } if (!m_pszHelpLine2) { *pszHelpLine2 = 0; } else { uiLen = f_strlen( m_pszHelpLine2); if (uiLen >= uiHelpSize2) { uiLen = uiHelpSize2 - 1; } if (uiLen) { f_memcpy( pszHelpLine2, m_pszHelpLine2, uiLen); } pszHelpLine2 [uiLen] = 0; } } /*=========================================================================== Desc: Finds the registered return path in the tree - will create a node, unless the root node of the path does not match the root node of the tree. ===========================================================================*/ NODE * FlmFormObject::findPath( POOL * pPool, NODE * pTree) { NODE * pNode = NULL; NODE * pParentNode; FLMUINT uiLevel; FLMUINT uiTagNum; RCODE rc; if (m_uiReturnPath [0] == GedTagNum( pTree)) { pNode = pTree; uiLevel = 1; for (;;) { uiTagNum = m_uiReturnPath [uiLevel]; if (!uiTagNum) break; pParentNode = pNode; pNode = GedChild( pParentNode); while ((pNode) && (GedTagNum( pNode) != uiTagNum)) { pNode = GedSibNext( pNode); } if (!pNode) { if ((pNode = GedNodeMake( pPool, uiTagNum, &rc)) == NULL) { goto Exit; } GedChildGraft( pParentNode, pNode, GED_LAST); } uiLevel++; } } Exit: return( pNode); } /*=========================================================================== Desc: Initializes variables ===========================================================================*/ FlmFormTextObject::FlmFormTextObject() { m_pszValue = NULL; } FlmFormTextObject::~FlmFormTextObject() { if (m_pszValue) { f_free( &m_pszValue); } } /*=========================================================================== Desc: Sets up a text object on a form. ===========================================================================*/ RCODE FlmFormTextObject::setup( FlmForm * pForm, FLMUINT uiObjectId, FLMUINT uiMaxChars, FLMUINT uiWidth, FLMUINT uiFormat, FLMBOOL bDisplayOnly, FLMUINT uiBackColor, FLMUINT uiForeColor, FLMUINT uiRow, FLMUINT uiColumn ) { RCODE rc = FERR_OK; if (m_pForm) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } if( RC_BAD( rc = f_alloc( uiMaxChars + 1, &m_pszValue))) { goto Exit; } m_uiMaxEditChars = uiMaxChars; m_pForm = pForm; m_eObjectType = FORM_TEXT_OBJECT; m_uiObjectId = uiObjectId; m_uiRow = uiRow; m_uiColumn = uiColumn; m_uiWidth = uiWidth; m_uiFormat = uiFormat; m_bDisplayOnly = bDisplayOnly; setBackColor( uiBackColor); setForeColor( uiForeColor); Exit: return( rc); } /*=========================================================================== Desc: Set the current value for a text object in a form. ===========================================================================*/ RCODE FlmFormTextObject::setValue( const char * pszValue) { RCODE rc = FERR_OK; FLMUINT uiLen = f_strlen( pszValue); if (uiLen > m_uiMaxEditChars) { flmAssert( 0); rc = RC_SET( FERR_CONV_DEST_OVERFLOW); uiLen = m_uiMaxEditChars; } f_memcpy( m_pszValue, pszValue, uiLen); m_pszValue [uiLen] = 0; //Exit: return( rc); } /*=========================================================================== Desc: Gets the current value for a text object in a form. ===========================================================================*/ RCODE FlmFormTextObject::getValue( FLMUINT * puiLen, char * pszValue) { RCODE rc = FERR_OK; FLMUINT uiLen; if (!pszValue) { *puiLen = (FLMUINT)((m_pszValue) ? (FLMUINT)f_strlen( m_pszValue) + 1 : (FLMUINT)1); } else { uiLen = f_strlen( m_pszValue); if (uiLen > *puiLen - 1) { flmAssert( 0); rc = RC_SET( FERR_CONV_DEST_OVERFLOW); uiLen = *puiLen - 1; } f_memcpy( pszValue, m_pszValue, uiLen); pszValue [uiLen] = 0; *puiLen = uiLen + 1; } return( rc); } /*=========================================================================== Desc: Displays the current value for a text object in a form. ===========================================================================*/ void FlmFormTextObject::display( FLMUINT uiDisplayRow, FLMUINT uiDisplayColumn ) { outputText( m_pszValue, uiDisplayRow, uiDisplayColumn); } /*=========================================================================== Desc: Formats the current value into an edit buffer that will be used to edit the object. ===========================================================================*/ void FlmFormTextObject::formatEditBuffer( char * pszEditBuf) { f_strcpy( pszEditBuf, m_pszValue); } /*=========================================================================== Desc: Formats the current value into an the return address, if any. ===========================================================================*/ RCODE FlmFormTextObject::populateReturnAddress( void) { RCODE rc = FERR_OK; if (m_pvReturnAddress) { rc = getValue( m_puiReturnLen, (char *)m_pvReturnAddress); } return( rc); } /*=========================================================================== Desc: Formats the current value into an node in the tree, if any. ===========================================================================*/ RCODE FlmFormTextObject::populateReturnPath( POOL * pPool, NODE * pTree) { RCODE rc = FERR_OK; char * pszTmp; FLMUINT uiLen; NODE * pNode; if (m_uiReturnPath [0]) { if ((pNode = findPath( pPool, pTree)) != NULL) { if( RC_BAD( rc = f_alloc( m_uiMaxEditChars + 1, &pszTmp))) { goto Exit; } uiLen = m_uiMaxEditChars + 1; if (RC_OK( rc = getValue( &uiLen, pszTmp))) { rc = GedPutNATIVE( pPool, (NODE *)pNode, pszTmp); } f_free( &pszTmp); } } Exit: return( rc); } /*=========================================================================== Desc: Initializes variables ===========================================================================*/ FlmFormUnsignedObject::FlmFormUnsignedObject() { m_uiValue = 0; // Current value in the object m_uiMin = 0; m_uiMax = 0; } FlmFormUnsignedObject::~FlmFormUnsignedObject() { } /*=========================================================================== Desc: Sets up an unsigned object on a form. ===========================================================================*/ RCODE FlmFormUnsignedObject::setup( FlmForm * pForm, FLMUINT uiObjectId, FLMUINT uiMin, FLMUINT uiMax, FLMUINT uiWidth, FLMUINT uiFormat, FLMBOOL bDisplayOnly, FLMUINT uiBackColor, FLMUINT uiForeColor, FLMUINT uiRow, FLMUINT uiColumn ) { RCODE rc = FERR_OK; FLMUINT uiHexDigits; if (m_pForm) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } m_pForm = pForm; m_eObjectType = FORM_UNSIGNED_OBJECT; m_uiObjectId = uiObjectId; if (uiMin > uiMax) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } m_uiMin = uiMin; m_uiMax = uiMax; // Determine the maximum number of edit characters - based on maximum // value. Calculate the maximum decimal digits and the maximum // hex digits - take the greater of these two. m_uiMaxEditChars = 1; uiMax /= 10; while (uiMax) { uiMax /= 10; m_uiMaxEditChars++; } uiHexDigits = 3; // Accounts for at least "0x" and one digit uiMax = m_uiMax >> 4; while (uiMax) { uiMax >>= 4; uiHexDigits++; } if (uiHexDigits > m_uiMaxEditChars) { m_uiMaxEditChars = uiHexDigits; } if (uiWidth > m_uiMaxEditChars) { m_uiMaxEditChars = uiWidth; } m_uiRow = uiRow; m_uiColumn = uiColumn; m_uiWidth = uiWidth; m_uiFormat = uiFormat; m_bDisplayOnly = bDisplayOnly; setBackColor( uiBackColor); setForeColor( uiForeColor); Exit: return( rc); } /*=========================================================================== Desc: Set the current value for an unsigned object in a form. ===========================================================================*/ RCODE FlmFormUnsignedObject::setValue( FLMUINT uiValue ) { RCODE rc = FERR_OK; if (uiValue < m_uiMin || uiValue > m_uiMax) { flmAssert( 0); rc = RC_SET( FERR_CONV_DEST_OVERFLOW); } m_uiValue = uiValue; //Exit: return( rc); } /*=========================================================================== Desc: Gets the current value for an unsigned object in a form. ===========================================================================*/ RCODE FlmFormUnsignedObject::getValue( FLMUINT * puiValue ) { *puiValue = m_uiValue; return( FERR_OK); } /*=========================================================================== Desc: Converts the text and verifies that it is a proper unsigned value. ===========================================================================*/ FSTATIC FLMBOOL flmIsUnsigned( char * pszEditBuf, FLMUINT * puiValue, char * pszErrMsg) { FLMBOOL bOk = TRUE; FLMUINT uiValue = 0; // Convert the value - using HEX or decimal. if ((*pszEditBuf == '0') && ((*(pszEditBuf + 1) == 'x') || (*(pszEditBuf + 1) == 'X'))) { pszEditBuf += 2; if (!(*pszEditBuf)) { bOk = FALSE; f_strcpy( pszErrMsg, "Invalid HEX number - must have at least one hex digit"); goto Exit; } // Hex conversion while (*pszEditBuf) { if (((*pszEditBuf >= '0') && (*pszEditBuf <= '9')) || ((*pszEditBuf >= 'A') && (*pszEditBuf <= 'F')) || ((*pszEditBuf >= 'a') && (*pszEditBuf <= 'f'))) { if (uiValue > 0x0FFFFFFF) { bOk = FALSE; f_strcpy( pszErrMsg, "HEX number is too large"); goto Exit; } uiValue <<= 4; if ((*pszEditBuf >= '0') && (*pszEditBuf <= '9')) { uiValue += (FLMUINT)(*pszEditBuf - '0'); } else if ((*pszEditBuf >= 'A') && (*pszEditBuf <= 'F')) { uiValue += (FLMUINT)(*pszEditBuf - 'A' + 10); } else { uiValue += (FLMUINT)(*pszEditBuf - 'a' + 10); } } else { f_strcpy( pszErrMsg, "Invalid digit in HEX number"); bOk = FALSE; goto Exit; } pszEditBuf++; } } else { if (!(*pszEditBuf)) { bOk = FALSE; f_strcpy( pszErrMsg, "Invalid number - must have at least one decimal digit"); goto Exit; } // Decimal conversion while (*pszEditBuf) { if ((*pszEditBuf >= '0') && (*pszEditBuf <= '9')) { if (uiValue > (0xFFFFFFFF / 10)) { Too_Large_Error: bOk = FALSE; f_strcpy( pszErrMsg, "Decimal number is too large"); goto Exit; } uiValue *= 10; if (uiValue > 0xFFFFFFFF - (FLMUINT)(*pszEditBuf - '0')) { goto Too_Large_Error; } uiValue += (FLMUINT)(*pszEditBuf - '0'); } else { f_strcpy( pszErrMsg, "Invalid digit in number"); bOk = FALSE; goto Exit; } pszEditBuf++; } } *puiValue = uiValue; Exit: return( bOk); } /*=========================================================================== Desc: Converts the text and verifies that it is a proper unsigned value. ===========================================================================*/ FLMBOOL FlmFormUnsignedObject::verifyValue( char * pszEditBuf, FLMUINT * puiValue) { FLMBOOL bOk = TRUE; char szErrMsg [100]; FLMUINT uiValue; bOk = flmIsUnsigned( pszEditBuf, &uiValue, szErrMsg); if (!bOk) { m_pForm->beep( szErrMsg); goto Exit; } if ((uiValue < m_uiMin) || (uiValue > m_uiMax)) { f_sprintf( (char *)szErrMsg, "Value must be >= %u and <= %u", (unsigned)m_uiMin, (unsigned)m_uiMax); m_pForm->beep( szErrMsg); bOk = FALSE; goto Exit; } *puiValue = uiValue; Exit: return( bOk); } /*=========================================================================== Desc: Displays the current value for an unsigned object in a form. ===========================================================================*/ void FlmFormUnsignedObject::display( FLMUINT uiDisplayRow, FLMUINT uiDisplayColumn ) { char szValue [20]; formatEditBuffer( szValue); outputText( szValue, uiDisplayRow, uiDisplayColumn); } /*=========================================================================== Desc: Formats the current value into an edit buffer that will be used to edit the object. ===========================================================================*/ void FlmFormUnsignedObject::formatEditBuffer( char * pszEditBuf) { char szFormat [10]; if (m_uiFormat & (FORMAT_UPPER_HEX | FORMAT_LOWER_HEX)) { if (m_uiFormat & FORMAT_ZERO_LEAD) { if (m_uiFormat & FORMAT_UPPER_HEX) { f_sprintf( (char *)szFormat, "0x%%0%uX", (unsigned)m_uiWidth); } else { f_sprintf( (char *)szFormat, "0x%%0%ux", (unsigned)m_uiWidth); } f_sprintf( (char *)pszEditBuf, "%s%u", (char *)szFormat, (unsigned)m_uiValue); } else if (m_uiFormat & FORMAT_UPPER_HEX) { f_sprintf( (char *)pszEditBuf, "0x%X", (unsigned)m_uiValue); } else { f_sprintf( (char *)pszEditBuf, "0x%x", (unsigned)m_uiValue); } } else { if (m_uiFormat & FORMAT_ZERO_LEAD) { f_sprintf( (char *)szFormat, "%%0%uu", (unsigned)m_uiWidth); f_sprintf( (char *)pszEditBuf, "%s%u", (char *)szFormat, (unsigned)m_uiValue); } else { f_sprintf( (char *)pszEditBuf, "%u", (unsigned)m_uiValue); } } } /*=========================================================================== Desc: Formats the current value into an the return address, if any. ===========================================================================*/ RCODE FlmFormUnsignedObject::populateReturnAddress( void) { RCODE rc = FERR_OK; if (m_pvReturnAddress) { rc = getValue( (FLMUINT *)m_pvReturnAddress); } return( rc); } /*=========================================================================== Desc: Formats the current value into an node in the tree, if any. ===========================================================================*/ RCODE FlmFormUnsignedObject::populateReturnPath( POOL * pPool, NODE * pTree) { RCODE rc = FERR_OK; NODE * pNode; FLMUINT uiValue; if (m_uiReturnPath [0]) { if ((pNode = findPath( pPool, pTree)) != NULL) { if (RC_OK( rc = getValue( &uiValue))) { rc = GedPutUINT( pPool, pNode, uiValue); } } } return( rc); } /*=========================================================================== Desc: Initializes variables ===========================================================================*/ FlmFormSignedObject::FlmFormSignedObject() { m_iValue = 0; // Current value in the object m_iMin = 0; m_iMax = 0; } FlmFormSignedObject::~FlmFormSignedObject() { } /*=========================================================================== Desc: Sets up a signed object on a form. ===========================================================================*/ RCODE FlmFormSignedObject::setup( FlmForm * pForm, FLMUINT uiObjectId, FLMINT iMin, FLMINT iMax, FLMUINT uiWidth, FLMUINT uiFormat, FLMBOOL bDisplayOnly, FLMUINT uiBackColor, FLMUINT uiForeColor, FLMUINT uiRow, FLMUINT uiColumn ) { RCODE rc = FERR_OK; FLMUINT uiTmpDigits; FLMUINT uiTmp; if (m_pForm) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } m_pForm = pForm; m_eObjectType = FORM_SIGNED_OBJECT; m_uiObjectId = uiObjectId; if (iMin > iMax) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } m_iMin = iMin; m_iMax = iMax; // First look at the maximum width required for the maximum number. // Look at the number of digits required for both a HEX and a // non-hex representation. m_uiMaxEditChars = 1; if (iMax < 0) { m_uiMaxEditChars++; iMax = -iMax; } iMax /= 10; while (iMax) { iMax /= 10; m_uiMaxEditChars++; } // Calculate the digits required to enter the number in hex. uiTmpDigits = 3; // Accounts for at least "0x" and one digit uiTmp = ((FLMUINT)m_iMax) >> 4; while (uiTmp) { uiTmp >>= 4; uiTmpDigits++; } if (uiTmpDigits > m_uiMaxEditChars) { m_uiMaxEditChars = uiTmpDigits; } // Now look at the minimum number. uiTmpDigits = 1; if (iMin < 0) { uiTmpDigits++; iMin = -iMin; } iMin /= 10; while (iMin) { iMin /= 10; uiTmpDigits++; } if (uiTmpDigits > m_uiMaxEditChars) { m_uiMaxEditChars = uiTmpDigits; } // Calculate the hex digits for the minimum number. uiTmpDigits = 3; // Accounts for at least "0x" and one digit uiTmp = ((FLMUINT)m_iMin) >> 4; while (uiTmp) { uiTmp >>= 4; uiTmpDigits++; } if (uiTmpDigits > m_uiMaxEditChars) { m_uiMaxEditChars = uiTmpDigits; } // Finally, if the width is greater, set it as the maximum // edit characters. if (uiWidth > m_uiMaxEditChars) { m_uiMaxEditChars = uiWidth; } m_uiRow = uiRow; m_uiColumn = uiColumn; m_uiWidth = uiWidth; m_uiFormat = uiFormat; m_bDisplayOnly = bDisplayOnly; setBackColor( uiBackColor); setForeColor( uiForeColor); Exit: return( rc); } /*=========================================================================== Desc: Set the current value for a signed object in a form. ===========================================================================*/ RCODE FlmFormSignedObject::setValue( FLMINT iValue ) { RCODE rc = FERR_OK; if (iValue < m_iMin || iValue > m_iMax) { flmAssert( 0); rc = RC_SET( FERR_CONV_DEST_OVERFLOW); } m_iValue = iValue; //Exit: return( rc); } /*=========================================================================== Desc: Gets the current value for a signed object in a form. ===========================================================================*/ RCODE FlmFormSignedObject::getValue( FLMINT * piValue ) { *piValue = m_iValue; return( FERR_OK); } /*=========================================================================== Desc: Converts the text and verifies that it is a proper signed value. ===========================================================================*/ FLMBOOL FlmFormSignedObject::verifyValue( char * pszEditBuf, FLMINT * piValue) { FLMBOOL bOk = TRUE; FLMUINT uiValue = 0; FLMINT iValue; char szErrMsg [100]; FLMBOOL bNegative; // Convert the value - using HEX or decimal. if ((*pszEditBuf == '0') && ((*(pszEditBuf + 1) == 'x') || (*(pszEditBuf + 1) == 'X'))) { pszEditBuf += 2; if (!(*pszEditBuf)) { bOk = FALSE; m_pForm->beep( "Invalid HEX number"); goto Exit; } // Hex conversion while (*pszEditBuf) { if (((*pszEditBuf >= '0') && (*pszEditBuf <= '9')) || ((*pszEditBuf >= 'A') && (*pszEditBuf <= 'F')) || ((*pszEditBuf >= 'a') && (*pszEditBuf <= 'f'))) { if (uiValue > 0x0FFFFFFF) { bOk = FALSE; m_pForm->beep( "HEX number is too large"); goto Exit; } uiValue <<= 4; if ((*pszEditBuf >= '0') && (*pszEditBuf <= '9')) { uiValue += (FLMUINT)(*pszEditBuf - '0'); } else if ((*pszEditBuf >= 'A') && (*pszEditBuf <= 'F')) { uiValue += (FLMUINT)(*pszEditBuf - 'A' + 10); } else { uiValue += (FLMUINT)(*pszEditBuf - 'a' + 10); } } else { m_pForm->beep( "Invalid digit in HEX number"); bOk = FALSE; goto Exit; } pszEditBuf++; } iValue = (FLMINT)uiValue; } else { if (*pszEditBuf == '-') { bNegative = TRUE; pszEditBuf++; } else { bNegative = FALSE; } // Decimal conversion while (*pszEditBuf) { if ((*pszEditBuf >= '0') && (*pszEditBuf <= '9')) { if (((!bNegative) && (uiValue > (0x7FFFFFFF / 10))) || ((bNegative) && (uiValue > (0x80000000 / 10)))) { Too_Large_Error: bOk = FALSE; if (!bNegative) { m_pForm->beep( "Decimal number is too large"); } else { m_pForm->beep( "Negative decimal number is too small"); } goto Exit; } uiValue *= 10; if (((!bNegative) && (uiValue > 0x7FFFFFFF - (FLMUINT)(*pszEditBuf - '0'))) || ((bNegative) && (uiValue > 0x80000000 - (FLMUINT)(*pszEditBuf - '0')))) { goto Too_Large_Error; } uiValue += (FLMUINT)(*pszEditBuf - '0'); } else { m_pForm->beep( "Invalid digit in number"); bOk = FALSE; goto Exit; } pszEditBuf++; } iValue = (FLMINT)uiValue; if ((bNegative) && (uiValue != 0x80000000)) { iValue = -iValue; } } if ((iValue < m_iMin) || (iValue > m_iMax)) { f_sprintf( (char *)szErrMsg, "Value must be >= %u and <= %u", (unsigned)m_iMin, (unsigned)m_iMax); m_pForm->beep( szErrMsg); bOk = FALSE; goto Exit; } *piValue = iValue; Exit: return( bOk); } /*=========================================================================== Desc: Displays the current value for a signed object in a form. ===========================================================================*/ void FlmFormSignedObject::display( FLMUINT uiDisplayRow, FLMUINT uiDisplayColumn ) { char szValue [20]; formatEditBuffer( szValue); outputText( szValue, uiDisplayRow, uiDisplayColumn); } /*=========================================================================== Desc: Formats the current value into an edit buffer that will be used to edit the object. ===========================================================================*/ void FlmFormSignedObject::formatEditBuffer( char * pszEditBuf) { char szFormat [10]; if (m_uiFormat & (FORMAT_UPPER_HEX | FORMAT_LOWER_HEX)) { if (m_uiFormat & FORMAT_ZERO_LEAD) { if (m_uiFormat & FORMAT_UPPER_HEX) { f_sprintf( (char *)szFormat, "0x%%0%uX", (unsigned)m_uiWidth); } else { f_sprintf( (char *)szFormat, "0x%%0%ux", (unsigned)m_uiWidth); } f_sprintf( (char *)pszEditBuf, "%s%d", (char *)szFormat, (int)m_iValue); } else if (m_uiFormat & FORMAT_UPPER_HEX) { f_sprintf( (char *)pszEditBuf, "0x%X", (unsigned)m_iValue); } else { f_sprintf( (char *)pszEditBuf, "0x%x", (unsigned)m_iValue); } } else { if (m_uiFormat & FORMAT_ZERO_LEAD) { f_sprintf( (char *)szFormat, "%%0%ud", (unsigned)m_uiWidth); f_sprintf( (char *)pszEditBuf, "%s%d", (char *)szFormat, (int)m_iValue); } else { f_sprintf( (char *)pszEditBuf, "%u", (unsigned)m_iValue); } } } /*=========================================================================== Desc: Formats the current value into an the return address, if any. ===========================================================================*/ RCODE FlmFormSignedObject::populateReturnAddress( void) { RCODE rc = FERR_OK; if (m_pvReturnAddress) { rc = getValue( (FLMINT *)m_pvReturnAddress); } return( rc); } /*=========================================================================== Desc: Formats the current value into an node in the tree, if any. ===========================================================================*/ RCODE FlmFormSignedObject::populateReturnPath( POOL * pPool, NODE * pTree) { RCODE rc = FERR_OK; NODE * pNode; FLMINT iValue; if (m_uiReturnPath [0]) { if ((pNode = findPath( pPool, pTree)) != NULL) { if (RC_OK( rc = getValue( &iValue))) { rc = GedPutINT( pPool, pNode, iValue); } } } return( rc); } /*=========================================================================== Desc: Initializes variables ===========================================================================*/ FlmFormRecordObject::FlmFormRecordObject() { m_pszTitle = NULL; m_bAutoEnter = TRUE; m_hDb = HFDB_NULL; m_uiContainer = FLM_DATA_CONTAINER; GedPoolInit( &m_pool, 512); m_pRecord = NULL; m_uiFirstNode = 0; m_uiCurrNode = 0; } FlmFormRecordObject::~FlmFormRecordObject() { GedPoolFree( &m_pool); if (m_pszTitle) { f_free( &m_pszTitle); } } /*=========================================================================== Desc: Sets up a GEDCOM record object on a form. ===========================================================================*/ RCODE FlmFormRecordObject::setup( FlmForm * pForm, FLMUINT uiObjectId, const char * pszTitle, FLMUINT uiWidth, FLMUINT uiBackColor, FLMUINT uiForeColor, FLMUINT uiRow, FLMUINT uiColumn) { RCODE rc = FERR_OK; FLMUINT uiLen; if (m_pForm) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } m_pForm = pForm; m_eObjectType = FORM_RECORD_OBJECT; m_uiObjectId = uiObjectId; m_uiMaxEditChars = 16; if (m_uiMaxEditChars < uiWidth) { m_uiMaxEditChars = uiWidth; } m_uiRow = uiRow; m_uiColumn = uiColumn; m_uiWidth = uiWidth; m_bDisplayOnly = FALSE; setBackColor( uiBackColor); setForeColor( uiForeColor); if (pszTitle && *pszTitle) { uiLen = f_strlen( pszTitle); if( RC_BAD( rc = f_alloc( uiLen + 1, &m_pszTitle))) { goto Exit; } f_memcpy( m_pszTitle, pszTitle, uiLen + 1); } Exit: return( rc); } /*=========================================================================== Desc: Set the current value for a GEDCOM record object in a form. ===========================================================================*/ RCODE FlmFormRecordObject::setValue( NODE * pRecord ) { RCODE rc = FERR_OK; GedPoolReset( &m_pool, NULL); if (!pRecord) { m_pRecord = NULL; } else { if ((m_pRecord = GedCopy( &m_pool, GED_FOREST, pRecord)) == NULL) { GedPoolReset( &m_pool, NULL); rc = RC_SET( FERR_MEM); goto Exit; } } Exit: return( rc); } /*=========================================================================== Desc: Gets the current value for a GEDCOM record object in a form. ===========================================================================*/ RCODE FlmFormRecordObject::getValue( NODE * * ppRecordValue, POOL * pPool) { RCODE rc = FERR_OK; if (!m_pRecord) { *ppRecordValue = NULL; } else { if ((*ppRecordValue = GedCopy( pPool, GED_FOREST, m_pRecord)) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } } Exit: return( rc); } /*=========================================================================== Desc: Displays the current value for a GEDCOM record object in a form. ===========================================================================*/ void FlmFormRecordObject::display( FLMUINT uiDisplayRow, FLMUINT uiDisplayColumn ) { char szValue [200]; formatEditBuffer( szValue); outputText( szValue, uiDisplayRow, uiDisplayColumn); } /*=========================================================================== Desc: Formats the current value into an edit buffer that will be used to edit the object. ===========================================================================*/ void FlmFormRecordObject::formatEditBuffer( char * pszEditBuf) { if (m_pszTitle && *m_pszTitle) { f_strcpy( pszEditBuf, m_pszTitle); } else { *pszEditBuf = 0; } } /*=========================================================================== Desc: Formats the current value into an the return address, if any. ===========================================================================*/ RCODE FlmFormRecordObject::populateReturnAddress( void) { RCODE rc = FERR_OK; if (m_pvReturnAddress) { rc = getValue( (NODE * *)m_pvReturnAddress, (POOL *)m_puiReturnLen); } return( rc); } /*=========================================================================== Desc: Formats the current value into an node in the tree, if any. ===========================================================================*/ RCODE FlmFormRecordObject::populateReturnPath( POOL * pPool, NODE * pTree) { RCODE rc = FERR_OK; NODE * pNode; NODE * pTmpNode; NODE * pTmpNode2; NODE * pLastSib; if (m_uiReturnPath [0]) { if ((pNode = findPath( pPool, pTree)) != NULL) { // Clip out any previous children. if (GedChild( pNode)) { GedClip( GED_FOREST, GedChild( pNode)); } // Graft in the new nodes as a forest of children. pTmpNode = m_pRecord; pLastSib = NULL; while (pTmpNode) { if ((pTmpNode2 = GedCopy( pPool, GED_TREE, pTmpNode)) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if (pLastSib) { GedSibGraft( pLastSib, pTmpNode2, GED_LAST); } else { GedChildGraft( pNode, pTmpNode2, GED_LAST); } pLastSib = pTmpNode2; pTmpNode = GedSibNext( pTmpNode); } } } Exit: return( rc); } /**************************************************************************** Name: flintRecEditKeyHook Desc: Keyboard callback for edit records within a form. *****************************************************************************/ FSTATIC RCODE flintRecEditKeyHook( F_RecEditor * pRecEditor, NODE * pCurNd, FLMUINT uiKeyIn, void * UserData, FLMUINT * puiKeyOut ) { F_UNREFERENCED_PARM( pCurNd); F_UNREFERENCED_PARM( pRecEditor); *((FLMUINT *)UserData) = uiKeyIn; switch (uiKeyIn) { case WPK_TAB: case WPK_STAB: case WPK_LEFT: case WPK_RIGHT: if (puiKeyOut) { *puiKeyOut = WPK_ESCAPE; } break; default: if (puiKeyOut) { *puiKeyOut = uiKeyIn; } break; } return( FERR_OK); } /*=========================================================================== Desc: Pops into the editor for the GEDCOM record. ===========================================================================*/ FLMUINT FlmFormRecordObject::edit( FLMBOOL * pbChanged ) { FLMUINT uiExitChar = 0; FTX_SCREEN_p pScreen = m_pForm->getScreen(); F_RecEditor * pRecEditor = NULL; POOL tmpPool; NODE * pFirstRecord; NODE * pTmpRecord; NODE * pCopyRecord; NODE * pLastCopiedRecord; NODE * pCurrentNode; NODE * pFirstNode; FLMUINT uiCurrNode; FLMUINT uiFirstNode; FLMUINT uiNumRows; FLMUINT uiNumCols; FLMBOOL bHaveFirstNode; FLMBOOL bHaveCurrNode; *pbChanged = FALSE; GedPoolInit( &tmpPool, 512); if (RC_BAD( getValue( &pTmpRecord, &tmpPool))) { goto Exit; } if (FTXScreenGetSize( pScreen, &uiNumCols, &uiNumRows) != FTXRC_SUCCESS) { goto Exit; } if ((pRecEditor = new F_RecEditor) == NULL) { goto Exit; } if (RC_BAD( pRecEditor->Setup( pScreen))) { goto Exit; } pRecEditor->setTitle( m_pszTitle); pRecEditor->setKeyHook( flintRecEditKeyHook, (void *)&uiExitChar); pRecEditor->setTree( pTmpRecord); pRecEditor->setDefaultSource( m_hDb, m_uiContainer); pRecEditor->setShutdown( m_pForm->getThread()->getShutdownFlagAddr()); // Get a pointer to the current node - using the ordinal position // that was previously saved. pCurrentNode = pFirstNode = pTmpRecord; uiCurrNode = m_uiCurrNode; uiFirstNode = m_uiFirstNode; flmAssert( uiCurrNode >= uiFirstNode); while (pCurrentNode && uiCurrNode) { uiCurrNode--; pCurrentNode = pCurrentNode->next; if (uiFirstNode) { uiFirstNode--; pFirstNode = pCurrentNode; } } if (pCurrentNode) { pRecEditor->setCurrentNode( pCurrentNode); } if (pFirstNode) { pRecEditor->setFirstNode( pFirstNode); } pRecEditor->interactiveEdit( 3, 3, uiNumCols - 6, uiNumRows - 6, TRUE, TRUE); if (uiExitChar == WPK_ESCAPE) { uiExitChar = 0; } else { // Locate the first record - in case some were inserted. pCurrentNode = pRecEditor->getCurrentNode(); pFirstNode = pRecEditor->getFirstNode(); pFirstRecord = pTmpRecord = pRecEditor->getRootNode( pCurrentNode); for (;;) { if ((pTmpRecord = GedSibPrev( pTmpRecord)) == NULL) { break; } pFirstRecord = pTmpRecord; } // Determine the ordinal position of the first and current node. m_uiCurrNode = 0; m_uiFirstNode = 0; uiCurrNode = 0; bHaveFirstNode = bHaveCurrNode = FALSE; pTmpRecord = pFirstRecord; while (pTmpRecord) { if (pTmpRecord == pCurrentNode) { m_uiCurrNode = uiCurrNode; bHaveCurrNode = TRUE; } else if (pTmpRecord == pFirstNode) { m_uiFirstNode = uiCurrNode; bHaveFirstNode = TRUE; } if (bHaveFirstNode && bHaveCurrNode) { break; } pTmpRecord = pRecEditor->getNextNode( pTmpRecord, FALSE); uiCurrNode++; } // Copy the records back into the form record object. While // copying them back, see if any of them were changed. GedPoolReset( &m_pool, NULL); m_pRecord = NULL; pLastCopiedRecord = NULL; pTmpRecord = pFirstRecord; while (pTmpRecord) { if (pRecEditor->isRecordModified( pTmpRecord)) { *pbChanged = TRUE; } // Copy the record into the form object. pRecEditor->copyCleanRecord( &m_pool, pTmpRecord, &pCopyRecord); if (pLastCopiedRecord) { GedSibGraft( pLastCopiedRecord, pCopyRecord, GED_LAST); } else { m_pRecord = pCopyRecord; } pLastCopiedRecord = pCopyRecord; // Go to the next record. pTmpRecord = GedSibNext( pTmpRecord); } } Exit: if (pRecEditor) { pRecEditor->Release(); } GedPoolFree( &tmpPool); return( uiExitChar); } /*=========================================================================== Desc: Initializes variables ===========================================================================*/ FlmFormPulldownObject::FlmFormPulldownObject() { m_pPulldown = NULL; m_bAutoEnter = TRUE; m_bReturnAll = FALSE; m_uiItemIdTag = 0; m_uiItemNameTag = 0; } FlmFormPulldownObject::~FlmFormPulldownObject() { if (m_pPulldown) { m_pPulldown->Release(); } } /*=========================================================================== Desc: Sets up a pulldown object on a form. ===========================================================================*/ RCODE FlmFormPulldownObject::setup( FlmForm * pForm, FLMUINT uiObjectId, FLMUINT uiWidth, FLMUINT uiHeight, FLMUINT uiBackColor, FLMUINT uiForeColor, FLMUINT uiRow, FLMUINT uiColumn ) { RCODE rc = FERR_OK; F_UNREFERENCED_PARM( uiHeight); if (m_pForm) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } m_pForm = pForm; m_eObjectType = FORM_PULLDOWN_OBJECT; m_uiObjectId = uiObjectId; m_uiMaxEditChars = 16; if (m_uiMaxEditChars < uiWidth) { m_uiMaxEditChars = uiWidth; } if ((m_pPulldown = new FlmPulldownList) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } m_pPulldown->setBackColor( uiBackColor); m_pPulldown->setForeColor( uiForeColor); m_uiRow = uiRow; m_uiColumn = uiColumn; m_uiWidth = uiWidth; setBackColor( uiBackColor); setForeColor( uiForeColor); Exit: return( rc); } /*=========================================================================== Desc: Sets the current item for a pulldown object on a form. ===========================================================================*/ RCODE FlmFormPulldownObject::setCurrentItem( FLMUINT uiItemId ) { RCODE rc = FERR_OK; if (!m_pPulldown) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } rc = m_pPulldown->setCurrentItem( uiItemId); Exit: return( rc); } /*=========================================================================== Desc: Gets the current item for a pulldown object on a form. ===========================================================================*/ RCODE FlmFormPulldownObject::getCurrentItem( FLMUINT * puiItemId ) { RCODE rc = FERR_OK; if (!m_pPulldown) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } rc = m_pPulldown->getCurrentItem( puiItemId); Exit: return( rc); } /*=========================================================================== Desc: Adds an item to a pulldown object on a form. ===========================================================================*/ RCODE FlmFormPulldownObject::addItem( FLMUINT uiItemId, const char * pszDisplayValue, FLMUINT uiShortcutKey) { RCODE rc = FERR_OK; if (!m_pPulldown) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } rc = m_pPulldown->addItem( uiItemId, pszDisplayValue, uiShortcutKey, NULL, NULL, NULL); Exit: return( rc); } /*=========================================================================== Desc: Adds an item from a pulldown object on a form. ===========================================================================*/ RCODE FlmFormPulldownObject::removeItem( FLMUINT uiItemId ) { RCODE rc = FERR_OK; if (!m_pPulldown) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } rc = m_pPulldown->removeItem( uiItemId); Exit: return( rc); } /*=========================================================================== Desc: Removes all items from a pulldown object on a form. ===========================================================================*/ RCODE FlmFormPulldownObject::clearItems( void) { RCODE rc = FERR_OK; if (!m_pPulldown) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } rc = m_pPulldown->clearItems(); Exit: return( rc); } /*=========================================================================== Desc: Displays the current value for a pulldown object in a form. ===========================================================================*/ void FlmFormPulldownObject::display( FLMUINT uiDisplayRow, FLMUINT uiDisplayColumn ) { char szValue [80]; formatEditBuffer( szValue); outputText( szValue, uiDisplayRow, uiDisplayColumn); } /*=========================================================================== Desc: Formats the current value into an edit buffer that will be used to edit the object. ===========================================================================*/ void FlmFormPulldownObject::formatEditBuffer( char * pszEditBuf) { FLMUINT uiItemId; FLMUINT uiLen; if (RC_BAD( m_pPulldown->getCurrentItem( &uiItemId))) { *pszEditBuf = 0; } else { uiLen = m_uiMaxEditChars + 1; m_pPulldown->getItemDispValue( uiItemId, &uiLen, pszEditBuf); } } /*=========================================================================== Desc: Formats the current value into an the return address, if any. ===========================================================================*/ RCODE FlmFormPulldownObject::populateReturnAddress( void) { RCODE rc = FERR_OK; if (m_pvReturnAddress) { rc = getCurrentItem( (FLMUINT *)m_pvReturnAddress); } return( rc); } /*=========================================================================== Desc: Formats the current value into an node in the tree, if any. ===========================================================================*/ RCODE FlmFormPulldownObject::populateReturnPath( POOL * pPool, NODE * pTree) { RCODE rc = FERR_OK; NODE * pNode; FLMUINT uiValue; FLMUINT uiItemId; if (m_uiReturnPath [0]) { if ((pNode = findPath( pPool, pTree)) != NULL) { if (m_bReturnAll) { // Clip out any previous children. if (GedChild( pNode)) { GedClip( GED_FOREST, GedChild( pNode)); } // Graft in the new nodes as a forest of children // list of IDs are the immediate children. Underneat // each ID node is the name node. if (RC_OK( m_pPulldown->getFirstItem( &uiItemId))) { for (;;) { FLMUINT uiLen; char * pszName; NODE * pIdNode; NODE * pNameNode; // Create the ID node. if ((pIdNode = GedNodeMake( pPool, m_uiItemIdTag, &rc)) == NULL) { break; } if (RC_BAD( rc = GedPutUINT( pPool, pIdNode, uiItemId))) { break; } // Create the name node. if ((pNameNode = GedNodeMake( pPool, m_uiItemNameTag, &rc)) == NULL) { break; } GedChildGraft( pIdNode, pNameNode, GED_LAST); m_pPulldown->getItemDispValue( uiItemId, &uiLen, NULL); uiLen++; if ((pszName = (char *)GedAllocSpace( pPool, pNameNode, FLM_TEXT_TYPE, uiLen)) == NULL) { rc = RC_SET( FERR_MEM); break; } m_pPulldown->getItemDispValue( uiItemId, &uiLen, pszName); GedChildGraft( pNode, pIdNode, GED_LAST); // Go to the next item in the list. if (RC_BAD( m_pPulldown->getNextItem( uiItemId, &uiItemId))) { break; } } } } else { if (RC_OK( rc = getCurrentItem( &uiValue))) { rc = GedPutRecPtr( pPool, pNode, uiValue); } } } } return( rc); } /*=========================================================================== Desc: Handles keystrokes for a pulldown box on a form. ===========================================================================*/ FSTATIC FLMBOOL pulldownKeyFunc( FlmPulldownList * pPulldown, FLMUINT uiKeyIn, FLMUINT * puiKeyOut, void * pvAppData ) { FLMBOOL bContinue = TRUE; F_UNREFERENCED_PARM( pPulldown); F_UNREFERENCED_PARM( pvAppData); *puiKeyOut = uiKeyIn; switch (uiKeyIn) { case WPK_TAB: case WPK_STAB: case WPK_LEFT: case WPK_RIGHT: bContinue = FALSE; break; default: break; } return( bContinue); } /*=========================================================================== Desc: Enters the editor for the pulldown list and allows the user to select one of the items from the list. ===========================================================================*/ FLMUINT FlmFormPulldownObject::select( void) { FLMUINT uiBoxUpperLeftCol; FLMUINT uiBoxUpperLeftRow; FLMUINT uiBoxHeight; FLMUINT uiBoxWidth; FLMUINT uiExitChar; FLMUINT uiExitValue; FLMUINT uiFormColumns = m_pForm->getColumns(); FLMUINT uiFormRows = m_pForm->getRows(); FTX_SCREEN_p pScreen = m_pForm->getScreen(); FLMBOOL bRedisplay; for (;;) { m_pPulldown->calcEditLocation( uiFormRows, uiFormColumns, m_pForm->getEditRow(), m_uiColumn, m_uiWidth, &uiBoxWidth, &uiBoxHeight, &uiBoxUpperLeftCol, &uiBoxUpperLeftRow); m_pPulldown->interact( pScreen, m_pForm->getThread(), uiBoxWidth, uiBoxHeight, TRUE, m_pForm->getUpperLeftColumn() + uiBoxUpperLeftCol, m_pForm->getUpperLeftRow() + uiBoxUpperLeftRow, FALSE, 0, &uiExitChar, &uiExitValue, 1, &bRedisplay, pulldownKeyFunc, NULL); if (!bRedisplay) { break; } } display( m_pForm->getEditRow(), m_uiColumn); if (uiExitChar == WPK_ENTER) { uiExitChar = WPK_TAB; } else if (uiExitChar == WPK_ESCAPE) { uiExitChar = 0; } return( uiExitChar); } /*=========================================================================== Desc: Set insert key callback for pulldown object on a form. ===========================================================================*/ void FlmFormPulldownObject::setPulldownInsertCallback( INSERT_FUNC_p pCallback, void * pvAppData) { if (m_pPulldown) { m_pPulldown->setPulldownInsertCallback( pCallback, pvAppData); } } /*=========================================================================== Desc: Initializes variables ===========================================================================*/ FlmPulldownList::FlmPulldownList() { m_bMonochrome = FALSE; m_bInteracting = FALSE; m_uiBackColor = WPS_BLUE; m_uiForeColor = WPS_WHITE; m_pFirstItem = NULL; m_pLastItem = NULL; m_pCurrentItem = NULL; m_pTopItem = NULL; m_pWindow = NULL; m_pShortcutKeys = NULL; m_uiShortcutKeyArraySize = 0; m_uiNumShortcutKeys = 0; m_pszTypedownBuf = NULL; m_uiTypedownBufSize = 0; m_uiNumTypedownChars = 0; m_uiMaxTypedownChars = 0; m_uiDispOffset = 0; m_pThread = NULL; m_pszListTitle = NULL; m_uiListTitleBufSize = 0; m_uiListTitleBackColor = WPS_BLACK; m_uiListTitleForeColor = WPS_WHITE; m_pszListHelp = NULL; m_uiListHelpBufSize = 0; m_uiListHelpBackColor = WPS_BLACK; m_uiListHelpForeColor = WPS_WHITE; m_pInsertFunc = NULL; m_pvAppData = NULL; } FlmPulldownList::~FlmPulldownList() { clearItems(); if (m_pShortcutKeys) { f_free( &m_pShortcutKeys); } if (m_pszTypedownBuf) { f_free( &m_pszTypedownBuf); } if (m_pWindow) { (void)FTXWinFree( &m_pWindow); } if (m_pszListTitle) { f_free( &m_pszListTitle); } if (m_pszListHelp) { f_free( &m_pszListHelp); } } /*=========================================================================== Desc: Finds an item by the item ID. ===========================================================================*/ FlmPulldownItem * FlmPulldownList::findItem( FLMUINT uiItemId ) { FlmPulldownItem * pItem; pItem = m_pFirstItem; while (pItem) { if (pItem->uiItemId == uiItemId) { break; } pItem = pItem->pNext; } return( pItem); } /*=========================================================================== Desc: Sets the title for the pulldown list. ===========================================================================*/ RCODE FlmPulldownList::setTitle( const char * pszListTitle, FLMUINT uiBackColor, FLMUINT uiForeColor) { RCODE rc = FERR_OK; char * pszTmp; FLMUINT uiLen; if (!pszListTitle || !(*pszListTitle)) { if (m_pszListTitle) { f_free( &m_pszListTitle); } m_pszListTitle = NULL; m_uiListTitleBufSize = 0; } else { uiLen = f_strlen( pszListTitle); if (m_uiListTitleBufSize < uiLen + 1) { if( RC_BAD( rc = f_alloc( uiLen + 1, &pszTmp))) { goto Exit; } if (m_pszListTitle) { f_free( &m_pszListTitle); m_pszListTitle = NULL; m_uiListTitleBufSize = 0; } m_pszListTitle = pszTmp; m_uiListTitleBufSize = uiLen + 1; } f_strcpy( m_pszListTitle, pszListTitle); } m_uiListTitleBackColor = uiBackColor; m_uiListTitleForeColor = uiForeColor; Exit: return( rc); } /*=========================================================================== Desc: Sets the help for the pulldown list. ===========================================================================*/ RCODE FlmPulldownList::setHelp( const char * pszListHelp, FLMUINT uiBackColor, FLMUINT uiForeColor) { RCODE rc = FERR_OK; char * pszTmp; FLMUINT uiLen; if (!pszListHelp || !(*pszListHelp)) { if (m_pszListHelp) { f_free( &m_pszListHelp); } m_pszListHelp = NULL; m_uiListHelpBufSize = 0; } else { uiLen = f_strlen( pszListHelp); if (m_uiListHelpBufSize < uiLen + 1) { if( RC_BAD( rc = f_alloc( uiLen + 1, &pszTmp))) { goto Exit; } if (m_pszListHelp) { f_free( &m_pszListHelp); m_pszListHelp = NULL; m_uiListHelpBufSize = 0; } m_pszListHelp = pszTmp; m_uiListHelpBufSize = uiLen + 1; } f_strcpy( m_pszListHelp, pszListHelp); } m_uiListHelpBackColor = uiBackColor; m_uiListHelpForeColor = uiForeColor; Exit: return( rc); } /*=========================================================================== Desc: Sets the current item for a pulldown list. ===========================================================================*/ RCODE FlmPulldownList::setCurrentItem( FLMUINT uiItemId ) { RCODE rc = FERR_OK; FlmPulldownItem * pItem; if (!uiItemId) { m_pCurrentItem = m_pFirstItem; } else { // Find the item if ((pItem = findItem( uiItemId)) == NULL) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } m_pCurrentItem = pItem; } Exit: return( rc); } /*=========================================================================== Desc: Gets the current item for a pulldown list. ===========================================================================*/ RCODE FlmPulldownList::getCurrentItem( FLMUINT * puiItemId ) { RCODE rc = FERR_OK; if (!m_pCurrentItem) { if (!m_pFirstItem) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } m_pCurrentItem = m_pFirstItem; } *puiItemId = m_pCurrentItem->uiItemId; Exit: return( rc); } /*=========================================================================== Desc: Gets the first item in a pulldown list. ===========================================================================*/ RCODE FlmPulldownList::getFirstItem( FLMUINT * puiItemId ) { RCODE rc = FERR_OK; if (!m_pFirstItem) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } *puiItemId = m_pFirstItem->uiItemId; Exit: return( rc); } /*=========================================================================== Desc: Gets the last item in a pulldown list. ===========================================================================*/ RCODE FlmPulldownList::getLastItem( FLMUINT * puiItemId ) { RCODE rc = FERR_OK; if (!m_pLastItem) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } *puiItemId = m_pLastItem->uiItemId; Exit: return( rc); } /*=========================================================================== Desc: Gets the next item in a pulldown list. ===========================================================================*/ RCODE FlmPulldownList::getNextItem( FLMUINT uiItemId, FLMUINT * puiNextItemId ) { FlmPulldownItem * pItem; RCODE rc = FERR_OK; pItem = m_pFirstItem; while( pItem) { if( pItem->uiItemId == uiItemId) { pItem = pItem->pNext; break; } pItem = pItem->pNext; } if( !pItem) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } *puiNextItemId = pItem->uiItemId; Exit: return( rc); } /*=========================================================================== Desc: Gets the previous item in a pulldown list. ===========================================================================*/ RCODE FlmPulldownList::getPrevItem( FLMUINT uiItemId, FLMUINT * puiPrevItemId ) { FlmPulldownItem * pItem; RCODE rc = FERR_OK; pItem = m_pLastItem; while( pItem) { if( pItem->uiItemId == uiItemId) { pItem = pItem->pPrev; break; } pItem = pItem->pPrev; } if( !pItem) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } *puiPrevItemId = pItem->uiItemId; Exit: return( rc); } /*=========================================================================== Desc: Gets the display value for an item in the pulldown list. ===========================================================================*/ RCODE FlmPulldownList::getItemDispValue( FLMUINT uiItemId, FLMUINT * puiDispBufLen, char * pszDisplayValue) { RCODE rc = FERR_OK; FlmPulldownItem * pItem; // Find the item if ((pItem = findItem( uiItemId)) == NULL) { flmAssert( 0); *pszDisplayValue = 0; rc = RC_SET( FERR_NOT_FOUND); goto Exit; } if (!pszDisplayValue) { *puiDispBufLen = pItem->uiDisplayValueLen; } else { (*puiDispBufLen)--; if (*puiDispBufLen > pItem->uiDisplayValueLen) { *puiDispBufLen = pItem->uiDisplayValueLen; } f_memcpy( pszDisplayValue, pItem->pszDisplayValue, *puiDispBufLen); pszDisplayValue [*puiDispBufLen] = 0; } Exit: return( rc); } /*=========================================================================== Desc: Sets the display value for an item in the pulldown list. ===========================================================================*/ RCODE FlmPulldownList::setDisplayValue( FLMUINT uiItemId, const char * pszDisplayValue) { RCODE rc = FERR_OK; FlmPulldownItem * pItem; FLMUINT uiLen; char * pszTmp; // Find the item if ((pItem = findItem( uiItemId)) == NULL) { flmAssert( 0); rc = RC_SET( FERR_NOT_FOUND); goto Exit; } uiLen = f_strlen( pszDisplayValue); if (uiLen <= pItem->uiDisplayValueLen) { f_strcpy( pItem->pszDisplayValue, pszDisplayValue); // See if we need to recalculate maximum typedown // characters. if (pItem->uiDisplayValueLen >= m_uiMaxTypedownChars) { recalcMaxWidth(); } } else { if( RC_BAD( rc = f_alloc( uiLen + 1, &pszTmp))) { goto Exit; } f_free( &pItem->pszDisplayValue); pItem->pszDisplayValue = pszTmp; f_strcpy( pszTmp, pszDisplayValue); // See if we need to increase the size of the typedown // buffer. if (uiLen + 1 > m_uiTypedownBufSize) { if (m_pszTypedownBuf) { f_free( &m_pszTypedownBuf); m_pszTypedownBuf = NULL; m_uiTypedownBufSize = 0; } if( RC_BAD( rc = f_alloc( uiLen + 6, &m_pszTypedownBuf))) { f_free( &pItem); goto Exit; } m_uiTypedownBufSize = uiLen + 6; } if (uiLen > m_uiMaxTypedownChars) { m_uiMaxTypedownChars = uiLen; } } pItem->uiDisplayValueLen = uiLen; refresh(); Exit: return( rc); } /*=========================================================================== Desc: Recalculates the maximum width for the pulldown list. ===========================================================================*/ void FlmPulldownList::recalcMaxWidth( void) { FlmPulldownItem * pItem; m_uiMaxTypedownChars = 0; pItem = m_pFirstItem; while (pItem) { if (pItem->uiDisplayValueLen > m_uiMaxTypedownChars) { m_uiMaxTypedownChars = pItem->uiDisplayValueLen; } pItem = pItem->pNext; } } /*=========================================================================== Desc: Finds the entry for a particular shortcut key. ===========================================================================*/ FlmShortcutKey * FlmPulldownList::findShortcutKey( FLMUINT uiShortcutKey ) { FlmShortcutKey * pShortcutKey; FLMUINT uiLow; FLMUINT uiMid; FLMUINT uiHigh; FLMUINT uiNumShortcutKeys; uiShortcutKey = (FLMUINT)f_toupper( uiShortcutKey); if (m_uiNumShortcutKeys <= 1) { pShortcutKey = (FlmShortcutKey *)(((m_pShortcutKeys) && (m_pShortcutKeys [0].uiShortcutKey == uiShortcutKey)) ? m_pShortcutKeys : (FlmShortcutKey *)NULL); goto Exit; } pShortcutKey = NULL; uiNumShortcutKeys = m_uiNumShortcutKeys - 1; for (uiHigh = uiNumShortcutKeys, uiLow = 0 ; ; ) { uiMid = (uiLow + uiHigh) >> 1; // (uiLow + uiHigh) / 2 if (uiShortcutKey == m_pShortcutKeys [uiMid ].uiShortcutKey) { // Found a match pShortcutKey = &m_pShortcutKeys [uiMid]; break; } // Check if we are done - where low equals high. if (uiLow >= uiHigh) { break; // Done - item not found. } if (uiShortcutKey < m_pShortcutKeys [uiMid ].uiShortcutKey) { if (uiMid == 0) { break; // Way too high? } uiHigh = uiMid - 1; // Too high } else { if (uiMid == uiNumShortcutKeys) { break; // Done - Hit the top } uiLow = uiMid + 1; // Too low } } Exit: return( pShortcutKey); } /*=========================================================================== Desc: Records a shortcut key and the item it is pointing to. ===========================================================================*/ RCODE FlmPulldownList::addShortcutKey( FLMUINT uiShortcutKey, FlmPulldownItem * pItem ) { RCODE rc = FERR_OK; FlmShortcutKey * pShortcutKey; FLMUINT uiPos; FlmShortcutKey TmpShortCut; uiShortcutKey = (FLMUINT)f_toupper( uiShortcutKey); // Make sure the shortcut key is not already defined. if ((pShortcutKey = findShortcutKey( uiShortcutKey)) != NULL) { flmAssert( 0); rc = RC_SET( FERR_EXISTS); goto Exit; } // Make sure we have space to insert the shortcut key if (m_uiNumShortcutKeys == m_uiShortcutKeyArraySize) { if( RC_BAD( rc = f_alloc( sizeof( FlmShortcutKey) * (m_uiShortcutKeyArraySize + 5), &pShortcutKey))) { goto Exit; } // Make sure the shortcut is not defined. if (m_pShortcutKeys) { f_memcpy( pShortcutKey, m_pShortcutKeys, sizeof( FlmShortcutKey) * m_uiShortcutKeyArraySize); f_free( &m_pShortcutKeys); } m_pShortcutKeys = pShortcutKey; m_uiShortcutKeyArraySize += 5; } // Insert the shortcut key at end of list. pShortcutKey = &m_pShortcutKeys [m_uiNumShortcutKeys]; m_uiNumShortcutKeys++; pShortcutKey->uiShortcutKey = uiShortcutKey; pShortcutKey->pItem = pItem; pItem->uiShortcutKey = uiShortcutKey; // Bubble key down to where it belongs in the list. if (m_uiNumShortcutKeys > 1) { uiPos = m_uiNumShortcutKeys - 1; while (uiPos && m_pShortcutKeys [m_uiNumShortcutKeys - 1].uiShortcutKey < m_pShortcutKeys [uiPos - 1].uiShortcutKey) { uiPos--; } // No need to do anything if the new shortcut is // already in its place. if (uiPos < m_uiNumShortcutKeys - 1) { // Save new shortcut into a temporary buffer. f_memcpy( &TmpShortCut, &m_pShortcutKeys [m_uiNumShortcutKeys - 1], sizeof( FlmShortcutKey)); // Move everything from the insert position to the end of the array // up one slot. f_memmove( &m_pShortcutKeys [uiPos + 1], &m_pShortcutKeys [uiPos], sizeof( FlmShortcutKey) * (m_uiNumShortcutKeys - uiPos - 1)); // Put the new shortcut into its slot in the array. f_memcpy( &m_pShortcutKeys [uiPos], &TmpShortCut, sizeof( FlmShortcutKey)); } } Exit: return( rc); } /*=========================================================================== Desc: Removes a shortcut key that is pointing to an item. ===========================================================================*/ void FlmPulldownList::removeShortcutKey( FLMUINT uiShortcutKey ) { FlmShortcutKey * pShortcutKey; FLMUINT uiPos; uiShortcutKey = (FLMUINT)f_toupper( uiShortcutKey); // Make sure the shortcut key is defined. if ((pShortcutKey = findShortcutKey( uiShortcutKey)) == NULL) { flmAssert( 0); } else { // Move everything above that position down by one. uiPos = (FLMUINT)(pShortcutKey - m_pShortcutKeys); f_memmove( pShortcutKey, &pShortcutKey [1], sizeof( FlmShortcutKey) * (m_uiNumShortcutKeys - uiPos - 1)); m_uiNumShortcutKeys--; } } /*=========================================================================== Desc: Adds an item to a pulldown list. ===========================================================================*/ RCODE FlmPulldownList::addItem( FLMUINT uiItemId, const char * pszDisplayValue, FLMUINT uiShortcutKey, FlmPulldownList * pSubList, ITEM_FUNC_p pFunc, void * pvAppData) { RCODE rc = FERR_OK; FlmPulldownItem * pItem; FLMUINT uiLen; // Make sure the item is not already defined. if ((pItem = findItem( uiItemId)) != NULL) { rc = RC_SET( FERR_EXISTS); goto Exit; } // Allocate memory for the new item. if( RC_BAD( rc = f_alloc( sizeof( FlmPulldownItem), &pItem))) { goto Exit; } f_memset( pItem, 0, sizeof( FlmPulldownItem)); uiLen = f_strlen( pszDisplayValue); if( RC_BAD( rc = f_alloc( uiLen + 1, &pItem->pszDisplayValue))) { f_free( &pItem); goto Exit; } // See if we need to increase the size of the typedown // buffer. if (uiLen + 1 > m_uiTypedownBufSize) { if (m_pszTypedownBuf) { f_free( &m_pszTypedownBuf); m_pszTypedownBuf = NULL; m_uiTypedownBufSize = 0; } if( RC_BAD( rc = f_alloc( uiLen + 6, &m_pszTypedownBuf))) { f_free( &pItem); goto Exit; } m_uiTypedownBufSize = uiLen + 6; } if (uiLen > m_uiMaxTypedownChars) { m_uiMaxTypedownChars = uiLen; } pItem->uiItemId = uiItemId; f_memcpy( pItem->pszDisplayValue, pszDisplayValue, uiLen + 1); pItem->uiDisplayValueLen = uiLen; pItem->uiShortcutKey = 0; pItem->pSubList = pSubList; pItem->pFunc = pFunc; pItem->pvAppData = pvAppData; if ((pItem->pPrev = m_pLastItem) == NULL) { pItem->uiItemNumber = 1; m_pFirstItem = pItem; } else { m_pLastItem->pNext = pItem; pItem->uiItemNumber = m_pLastItem->uiItemNumber + 1; } m_pLastItem = pItem; if (!m_pCurrentItem) { m_pCurrentItem = pItem; } if (uiShortcutKey) { if (RC_BAD( rc = addShortcutKey( uiShortcutKey, pItem))) { removeItem( uiItemId); goto Exit; } } Exit: return( rc); } /*=========================================================================== Desc: Adds an item to a pulldown list. ===========================================================================*/ RCODE FlmPulldownList::insertItem( FLMUINT uiPositionItemId, FLMBOOL bInsertBefore, FLMUINT uiItemId, const char * pszDisplayValue, FLMUINT uiShortcutKey, FlmPulldownList * pSubList, ITEM_FUNC_p pFunc, void * pvAppData) { RCODE rc = FERR_OK; FlmPulldownItem * pItem; FlmPulldownItem * pPositionItem; FlmPulldownItem * pBeforeItem; FlmPulldownItem * pAfterItem; FLMUINT uiLen; FLMUINT uiItemNumber; // Find the position item, if any. pPositionItem = (FlmPulldownItem *)((uiPositionItemId) ? findItem( uiPositionItemId) : (FlmPulldownItem *)NULL); // Make sure the item is not already defined. if ((pItem = findItem( uiItemId)) != NULL) { flmAssert( 0); rc = RC_SET( FERR_EXISTS); goto Exit; } // Allocate memory for the new item. if( RC_BAD( rc = f_alloc( sizeof( FlmPulldownItem), &pItem))) { goto Exit; } f_memset( pItem, 0, sizeof( FlmPulldownItem)); uiLen = f_strlen( pszDisplayValue); if( RC_BAD( rc = f_alloc( uiLen + 1, &pItem->pszDisplayValue))) { f_free( &pItem); goto Exit; } // See if we need to increase the size of the typedown // buffer. if (uiLen + 1 > m_uiTypedownBufSize) { if (m_pszTypedownBuf) { f_free( &m_pszTypedownBuf); m_pszTypedownBuf = NULL; m_uiTypedownBufSize = 0; } if( RC_BAD( rc = f_alloc( uiLen + 6, &m_pszTypedownBuf))) { f_free( &pItem); goto Exit; } m_uiTypedownBufSize = uiLen + 6; } if (uiLen > m_uiMaxTypedownChars) { m_uiMaxTypedownChars = uiLen; } pItem->uiItemId = uiItemId; f_memcpy( pItem->pszDisplayValue, pszDisplayValue, uiLen + 1); pItem->uiDisplayValueLen = uiLen; pItem->uiShortcutKey = 0; pItem->pSubList = pSubList; pItem->pFunc = pFunc; pItem->pvAppData = pvAppData; if (!pPositionItem) { pPositionItem = (FlmPulldownItem *)((bInsertBefore) ? m_pFirstItem : m_pLastItem); } // Determine the before and after items. if (bInsertBefore) { pBeforeItem = (FlmPulldownItem *)((pPositionItem) ? pPositionItem->pPrev : (FlmPulldownItem *)NULL); pAfterItem = pPositionItem; } else { pBeforeItem = pPositionItem; pAfterItem = (FlmPulldownItem *)((pPositionItem) ? pPositionItem->pNext : (FlmPulldownItem *)NULL); } // Link new item between the before and after items. if ((pItem->pPrev = pBeforeItem) == NULL) { pItem->uiItemNumber = 1; m_pFirstItem = pItem; } else { pBeforeItem->pNext = pItem; pItem->uiItemNumber = pBeforeItem->uiItemNumber + 1; } if ((pItem->pNext = pAfterItem) == NULL) { m_pLastItem = pItem; } else { pAfterItem->pPrev = pItem; } if (!m_pCurrentItem) { m_pCurrentItem = pItem; } if (!m_pTopItem) { m_pTopItem = pItem; } // Renumber everything after the new item. uiItemNumber = pItem->uiItemNumber + 1; while (pAfterItem) { pAfterItem->uiItemNumber = uiItemNumber++; pAfterItem = pAfterItem->pNext; } // Add the shortcut key, if any. if (uiShortcutKey) { if (RC_BAD( rc = addShortcutKey( uiShortcutKey, pItem))) { removeItem( uiItemId); goto Exit; } } Exit: return( rc); } /*=========================================================================== Desc: Adds shortcut key for a particular item in the list. ===========================================================================*/ RCODE FlmPulldownList::addShortcutKey( FLMUINT uiItemId, FLMUINT uiShortcutKey ) { RCODE rc = FERR_OK; FlmPulldownItem * pItem; // Make sure the item is not already defined. if ((pItem = findItem( uiItemId)) == NULL) { flmAssert( 0); rc = RC_SET( FERR_NOT_FOUND); goto Exit; } flmAssert( uiShortcutKey); if (RC_BAD( rc = addShortcutKey( uiShortcutKey, pItem))) { goto Exit; } Exit: return( rc); } /*=========================================================================== Desc: Removes an item from a pulldown list. ===========================================================================*/ RCODE FlmPulldownList::removeItem( FLMUINT uiItemId ) { RCODE rc = FERR_OK; FlmPulldownItem * pItem; FlmPulldownItem * pTmpItem; FLMUINT uiSaveLen; if ((pItem = findItem( uiItemId)) == NULL) { flmAssert( 0); rc = RC_SET( FERR_NOT_FOUND); goto Exit; } uiSaveLen = pItem->uiDisplayValueLen; // If the one we are removing is the current item, adjust // the current item pointer. if (m_pCurrentItem == pItem) { if ((m_pCurrentItem = pItem->pNext) == NULL) { m_pCurrentItem = pItem->pPrev; } } // If the one we are removing is the top item, adjust // the top item pointer. if (m_pTopItem == pItem) { if ((m_pTopItem = pItem->pNext) == NULL) { m_pTopItem = pItem->pPrev; } } // Decrement all of the item numbers of items that come after this // one. pTmpItem = pItem->pNext; while (pTmpItem) { pTmpItem->uiItemNumber--; pTmpItem = pTmpItem->pNext; } // Unlink the item from the list. if (pItem->pNext) { pItem->pNext->pPrev = pItem->pPrev; } else { m_pLastItem = pItem->pPrev; } if (pItem->pPrev) { pItem->pPrev->pNext = pItem->pNext; } else { m_pFirstItem = pItem->pNext; } if (pItem->pszDisplayValue) { f_free( &pItem->pszDisplayValue); } if (pItem->uiShortcutKey) { removeShortcutKey( pItem->uiShortcutKey); } f_free( &pItem); // See if we need to recalculate maximum typedown // characters. if (uiSaveLen >= m_uiMaxTypedownChars) { recalcMaxWidth(); } Exit: return( rc); } /*=========================================================================== Desc: Clears all items from a pulldown list. ===========================================================================*/ RCODE FlmPulldownList::clearItems( void) { FlmPulldownItem * pItem; FlmPulldownItem * pNextItem; pItem = m_pFirstItem; while (pItem) { pNextItem = pItem->pNext; if (pItem->pszDisplayValue) { f_free( &pItem->pszDisplayValue); } f_free( &pItem); pItem = pNextItem; } m_pFirstItem = NULL; m_pLastItem = NULL; m_pCurrentItem = NULL; if (m_pShortcutKeys) { f_free( &m_pShortcutKeys); m_uiShortcutKeyArraySize = 0; m_uiNumShortcutKeys = 0; m_pShortcutKeys = NULL; } return( FERR_OK); } /*=========================================================================== Desc: Display one item in the pulldown list. ===========================================================================*/ void FlmPulldownList::displayItem( FlmPulldownItem * pItem, FLMBOOL bIsCurrentItem) { FLMUINT uiRow = pItem->uiItemNumber - m_pTopItem->uiItemNumber; FLMUINT uiLen; char * pszDisp; char ucSave; if (bIsCurrentItem) { FTXWinSetBackFore( m_pWindow, m_bMonochrome ? WPS_WHITE : m_uiForeColor, m_bMonochrome ? WPS_BLACK : m_uiBackColor); } else { FTXWinSetBackFore( m_pWindow, m_bMonochrome ? WPS_BLACK : m_uiBackColor, m_bMonochrome ? WPS_WHITE : m_uiForeColor); } FTXWinSetCursorPos( m_pWindow, 0, uiRow); if (m_uiDispOffset < pItem->uiDisplayValueLen) { uiLen = pItem->uiDisplayValueLen - m_uiDispOffset; pszDisp = &pItem->pszDisplayValue [m_uiDispOffset]; if (uiLen > m_uiCols) { uiLen = m_uiCols; ucSave = pszDisp [uiLen]; pszDisp [uiLen] = 0; FTXWinPrintStr( m_pWindow, pszDisp); pszDisp [uiLen] = ucSave; } else { FTXWinPrintStr( m_pWindow, pszDisp); } } else { uiLen = 0; } // Clear the rest of the line if (uiLen < m_uiCols) { FTXWinClearLine( m_pWindow, uiLen, uiRow); } if (bIsCurrentItem) { if (!m_uiNumTypedownChars || m_uiNumTypedownChars <= m_uiDispOffset) { FTXWinSetCursorPos( m_pWindow, 0, uiRow); } else if (m_uiNumTypedownChars - m_uiDispOffset <= m_uiCols) { FTXWinSetCursorPos( m_pWindow, m_uiNumTypedownChars - m_uiDispOffset, uiRow); } else { FTXWinSetCursorPos( m_pWindow, m_uiCols, uiRow); } } } /*=========================================================================== Desc: Refresh the display ===========================================================================*/ void FlmPulldownList::refresh( void) { FLMUINT uiCnt; FlmPulldownItem * pItem; FLMBOOL bDispCurrent; if (m_bInteracting) { FTXWinSetBackFore( m_pWindow, m_bMonochrome ? WPS_BLACK : m_uiBackColor, m_bMonochrome ? WPS_WHITE : m_uiForeColor); // Clear the screen (void)FTXWinClear( m_pWindow); bDispCurrent = FALSE; for (uiCnt = 0, pItem = m_pTopItem; uiCnt < m_uiRows && pItem; uiCnt++, pItem = pItem->pNext) { if (pItem == m_pCurrentItem) { bDispCurrent = TRUE; } else { displayItem( pItem, FALSE); } } // Always display the current item last, so that the cursor will // be positioned on it. if (bDispCurrent) { displayItem( m_pCurrentItem, TRUE); } } } /*=========================================================================== Desc: Move cursor to the specified item - refresh if necessary. ===========================================================================*/ void FlmPulldownList::positionTo( FLMUINT uiItemId ) { FlmPulldownItem * pItem; if (m_bInteracting) { if ((pItem = findItem( uiItemId)) != NULL) { m_uiNumTypedownChars = 0; positionTo( pItem, FALSE); } } else { setCurrentItem( uiItemId); } } /*=========================================================================== Desc: Move cursor to the specified item - refresh if necessary. ===========================================================================*/ void FlmPulldownList::positionTo( FlmPulldownItem * pItem, FLMBOOL bForceRefresh ) { FLMUINT uiCnt; FLMUINT uiCounter; if ((bForceRefresh) || ((pItem->uiItemNumber < m_pTopItem->uiItemNumber) || (pItem->uiItemNumber > m_pTopItem->uiItemNumber + m_uiRows - 1))) { m_pCurrentItem = pItem; if (pItem->uiItemNumber <= m_uiRows) { m_pTopItem = m_pFirstItem; } else { m_pTopItem = m_pCurrentItem; for (uiCnt = (m_uiRows - 1) / 2, uiCounter = 0; uiCounter < uiCnt; uiCounter++) { m_pTopItem = m_pTopItem->pPrev; } } refresh(); } else { displayItem( m_pCurrentItem, FALSE); m_pCurrentItem = pItem; displayItem( m_pCurrentItem, TRUE); } } /*=========================================================================== Desc: Move cursor down ===========================================================================*/ void FlmPulldownList::cursorDown( void) { m_uiNumTypedownChars = 0; *m_pszTypedownBuf = 0; if (m_pCurrentItem->pNext) { if (m_pCurrentItem->pNext->uiItemNumber - m_pTopItem->uiItemNumber + 1 > m_uiRows) { m_pCurrentItem = m_pCurrentItem->pNext; m_pTopItem = m_pTopItem->pNext; refresh(); } else { displayItem( m_pCurrentItem, FALSE); m_pCurrentItem = m_pCurrentItem->pNext; displayItem( m_pCurrentItem, TRUE); } } else { displayItem( m_pCurrentItem, TRUE); } } /*=========================================================================== Desc: Move cursor up ===========================================================================*/ void FlmPulldownList::cursorUp( void) { m_uiNumTypedownChars = 0; *m_pszTypedownBuf = 0; if (m_pCurrentItem->pPrev) { if (m_pCurrentItem == m_pTopItem) { m_pCurrentItem = m_pCurrentItem->pPrev; m_pTopItem = m_pTopItem->pPrev; refresh(); } else { displayItem( m_pCurrentItem, FALSE); m_pCurrentItem = m_pCurrentItem->pPrev; displayItem( m_pCurrentItem, TRUE); } } else { displayItem( m_pCurrentItem, TRUE); } } /*=========================================================================== Desc: Scroll display left ===========================================================================*/ void FlmPulldownList::scrollLeft( void) { if (m_uiDispOffset) { m_uiDispOffset--; refresh(); } } /*=========================================================================== Desc: Scroll display right ===========================================================================*/ void FlmPulldownList::scrollRight( void) { if (m_uiMaxTypedownChars - m_uiDispOffset > m_uiCols) { m_uiDispOffset++; refresh(); } } /*=========================================================================== Desc: Move cursor down a page ===========================================================================*/ void FlmPulldownList::pageDown( void) { FLMUINT uiCnt; m_uiNumTypedownChars = 0; *m_pszTypedownBuf = 0; if (m_pCurrentItem->uiItemNumber + m_uiRows > m_pLastItem->uiItemNumber) { cursorEnd(); } else { uiCnt = m_uiRows; while (uiCnt) { m_pCurrentItem = m_pCurrentItem->pNext; m_pTopItem = m_pTopItem->pNext; uiCnt--; } refresh(); } } /*=========================================================================== Desc: Move cursor up a page ===========================================================================*/ void FlmPulldownList::pageUp( void) { FLMUINT uiCnt; m_uiNumTypedownChars = 0; *m_pszTypedownBuf = 0; if (m_pTopItem->uiItemNumber < m_uiRows) { cursorHome(); } else { uiCnt = m_uiRows; while (uiCnt) { m_pCurrentItem = m_pCurrentItem->pPrev; m_pTopItem = m_pTopItem->pPrev; uiCnt--; } refresh(); } } /*=========================================================================== Desc: Move cursor to first item ===========================================================================*/ void FlmPulldownList::cursorHome( void) { m_uiNumTypedownChars = 0; *m_pszTypedownBuf = 0; if (m_pTopItem != m_pFirstItem) { m_pCurrentItem = m_pFirstItem; m_pTopItem = m_pFirstItem; refresh(); } else if (m_pCurrentItem != m_pFirstItem) { displayItem( m_pCurrentItem, FALSE); m_pCurrentItem = m_pFirstItem; displayItem( m_pCurrentItem, TRUE); } else { displayItem( m_pCurrentItem, TRUE); } } /*=========================================================================== Desc: Move cursor to last item ===========================================================================*/ void FlmPulldownList::cursorEnd( void) { m_uiNumTypedownChars = 0; *m_pszTypedownBuf = 0; if (m_pLastItem->uiItemNumber - m_pTopItem->uiItemNumber + 1 > m_uiRows) { m_pCurrentItem = m_pLastItem; m_pTopItem = m_pLastItem; while (m_pLastItem->uiItemNumber - m_pTopItem->uiItemNumber + 1 < m_uiRows) { m_pTopItem = m_pTopItem->pPrev; } refresh(); } else if (m_pCurrentItem != m_pLastItem) { displayItem( m_pCurrentItem, FALSE); m_pCurrentItem = m_pLastItem; displayItem( m_pCurrentItem, TRUE); } else { displayItem( m_pCurrentItem, TRUE); } } /*=========================================================================== Desc: Move cursor to last item ===========================================================================*/ void FlmPulldownList::backspaceChar( void) { FlmPulldownItem * pItem; if (m_uiNumTypedownChars) { m_uiNumTypedownChars--; m_pszTypedownBuf [m_uiNumTypedownChars] = 0; if (!m_uiNumTypedownChars) { cursorHome(); } else { // See if any of the items match this one pItem = m_pFirstItem; while ((pItem) && (f_strnicmp( pItem->pszDisplayValue, m_pszTypedownBuf, m_uiNumTypedownChars) != 0)) { pItem = pItem->pNext; } // If we found something, move to it. if (pItem) { positionTo( pItem, FALSE); } else { flmAssert( 0); } } } } /*=========================================================================== Desc: Perform typedown ===========================================================================*/ void FlmPulldownList::typedown( FLMUINT uiChar ) { FlmPulldownItem * pItem; // Not a shortcut key, see about typedown. if (m_uiNumTypedownChars < m_uiMaxTypedownChars) { m_pszTypedownBuf [m_uiNumTypedownChars] = (FLMBYTE)uiChar; m_pszTypedownBuf [m_uiNumTypedownChars + 1] = 0; // See if any of the items match this one pItem = m_pFirstItem; while ((pItem) && (f_strnicmp( pItem->pszDisplayValue, m_pszTypedownBuf, m_uiNumTypedownChars + 1) != 0)) { pItem = pItem->pNext; } // If we found something, move to it. if (pItem) { m_uiNumTypedownChars++; positionTo( pItem, FALSE); } } } /*=========================================================================== Desc: See if the key typed is a shortcut. If so, move to that item. ===========================================================================*/ FLMBOOL FlmPulldownList::shortcutKey( FLMUINT uiChar ) { FlmShortcutKey * pShortcutKey = findShortcutKey( uiChar); if (!pShortcutKey) { return( FALSE); } m_uiNumTypedownChars = 0; *m_pszTypedownBuf = 0; positionTo( pShortcutKey->pItem, FALSE); return( TRUE); } /*=========================================================================== Desc: Calculates where a pulldown list should be displayed for editing. ===========================================================================*/ void FlmPulldownList::calcEditLocation( FLMUINT uiScreenRows, FLMUINT uiScreenCols, FLMUINT uiAnchorRow, FLMUINT uiLeftAnchorCol, FLMUINT uiAnchorWidth, FLMUINT * puiBoxWidth, FLMUINT * puiBoxHeight, FLMUINT * puiUpperLeftCol, FLMUINT * puiUpperLeftRow ) { FLMUINT uiTotalItems = (FLMUINT)((m_pLastItem) ? m_pLastItem->uiItemNumber : (FLMUINT)1); FLMUINT uiMinBoxHeight; FLMUINT uiMaxBoxHeight; FLMUINT uiMinBoxWidth; FLMUINT uiMaxBoxWidth; FLMUINT uiRightAnchorCol = uiLeftAnchorCol + uiAnchorWidth; FLMUINT uiTestLeftCol; FLMUINT uiTestLeftRow; FLMUINT uiTestWidth; FLMUINT uiTestHeight; FLMUINT uiQuadrant; FLMUINT uiMinWidth; // Decrement left anchor column by one if it is not zero already. if (uiLeftAnchorCol) { uiLeftAnchorCol--; } uiMinWidth = (FLMUINT)((m_pszListTitle) ? (FLMUINT)f_strlen( m_pszListTitle) : (FLMUINT)0); if (m_pszListHelp) { if (uiMinWidth < f_strlen( m_pszListHelp)) { uiMinWidth = f_strlen( m_pszListHelp); } } uiMinWidth += 4; if (!m_pLastItem) { uiMinBoxHeight = uiMaxBoxHeight = 5; uiMinBoxWidth = uiMaxBoxWidth = 15; } else { uiMinBoxHeight = uiMaxBoxHeight = uiTotalItems + 2; if (uiMinBoxHeight > 7) { uiMinBoxHeight = 7; } uiMinBoxWidth = uiMaxBoxWidth = m_uiMaxTypedownChars + 2; if (uiMinBoxWidth > 15) { uiMinBoxWidth = 15; } } if (uiMaxBoxWidth < uiMinWidth) uiMaxBoxWidth = uiMinWidth; // Test quadrant to right/down from right side anchor. uiQuadrant = 1; for (;; uiQuadrant++) { switch (uiQuadrant) { case 1: // quadrant to right and down from right side of anchor uiTestLeftCol = uiRightAnchorCol; uiTestLeftRow = uiAnchorRow; uiTestWidth = uiScreenCols - uiRightAnchorCol; uiTestHeight = uiScreenRows - uiAnchorRow; break; case 2: // quadrant to right and up from right side of anchor uiTestLeftCol = uiRightAnchorCol; uiTestLeftRow = ((FLMUINT)(uiMaxBoxHeight > uiAnchorRow) ? (FLMUINT)0 : uiAnchorRow + 1 - uiMaxBoxHeight); uiTestWidth = uiScreenCols - uiRightAnchorCol; uiTestHeight = uiAnchorRow + 1; break; case 3: // quadrant to left and down from left side of anchor uiTestLeftCol = (FLMUINT)((uiMaxBoxWidth >= uiLeftAnchorCol) ? (FLMUINT)0 : uiLeftAnchorCol + 1 - uiMaxBoxWidth); uiTestLeftRow = uiAnchorRow; uiTestWidth = uiLeftAnchorCol + 1; uiTestHeight = uiScreenRows - uiAnchorRow; break; case 4: // quadrant to left and up from left side of anchor uiTestLeftCol = (FLMUINT)((uiMaxBoxWidth >= uiLeftAnchorCol) ? (FLMUINT)0 : uiLeftAnchorCol + 1 - uiMaxBoxWidth); uiTestLeftRow = ((FLMUINT)(uiMaxBoxHeight > uiAnchorRow) ? (FLMUINT)0 : uiAnchorRow + 1 - uiMaxBoxHeight); uiTestWidth = uiLeftAnchorCol + 1; uiTestHeight = uiAnchorRow + 1; break; case 5: default: // Try moving anchor column to the left and/or up one column // at a time and testing the four options above again. if (uiRightAnchorCol) { if ((uiRightAnchorCol > uiLeftAnchorCol + 2) || (!uiAnchorRow)) { uiRightAnchorCol--; uiQuadrant = 0; continue; } else { uiAnchorRow--; uiQuadrant = 0; continue; } } else if (uiAnchorRow) { uiAnchorRow--; uiQuadrant = 0; continue; } flmAssert( 0); // We have too small of a screen if we get to here. break; } if ((uiTestHeight >= uiMinBoxHeight) && (uiTestWidth >= uiMinBoxWidth)) { *puiBoxHeight = (FLMUINT)((uiTestHeight >= uiMaxBoxHeight) ? uiMaxBoxHeight : uiTestHeight); *puiBoxWidth = (FLMUINT)((uiTestWidth >= uiMaxBoxWidth) ? uiMaxBoxWidth : uiTestWidth); *puiUpperLeftCol = uiTestLeftCol; *puiUpperLeftRow = uiTestLeftRow; goto Exit; } } Exit: return; } /*=========================================================================== Desc: User interaction with a pulldown list. ===========================================================================*/ RCODE FlmPulldownList::interact( FTX_SCREEN_p pScreen, FlmThreadContext * pThread, FLMUINT uiWidth, FLMUINT uiHeight, FLMBOOL bDoBorder, FLMUINT uiULX, FLMUINT uiULY, FLMBOOL bReturnOnShortcut, FLMUINT uiResponseTimeout, FLMUINT * puiExitChar, FLMUINT * puiExitValue, FLMUINT uiExitValueDepth, FLMBOOL * pbRedisplay, LIST_KEY_FUNC_p pKeyFunc, void * pvAppData ) { RCODE rc = FERR_OK; FLMUINT uiChar; FLMUINT uiScreenCols; FLMUINT uiScreenRows; FLMUINT uiStartTime; FlmPulldownItem * pSaveCurrentItem; FLMUINT uiMinWidth; FLMBOOL bBoxFixed = TRUE; FLMUINT uiSaveWidth = uiHeight; FLMUINT uiSaveHeight = uiWidth; if (pbRedisplay) { *pbRedisplay = FALSE; } Start_Over: m_pThread = pThread; m_pWindow = NULL; *puiExitChar = 0; *puiExitValue = 0; m_bInteracting = TRUE; m_uiNumTypedownChars = 0; flmAssert( uiExitValueDepth >= 1); f_memset( puiExitValue, 0, sizeof( FLMUINT) * uiExitValueDepth); FTXScreenGetSize( pScreen, &uiScreenCols, &uiScreenRows); // If either width or height is passed in as zero, we // need to calculate the box position - put in the center // of the screen. if (!uiWidth || !uiHeight) { bBoxFixed = FALSE; uiMinWidth = (FLMUINT)((m_pszListTitle) ? (FLMUINT)f_strlen( m_pszListTitle) : (FLMUINT)0); if (m_pszListHelp) { if (uiMinWidth < f_strlen( m_pszListHelp)) { uiMinWidth = f_strlen( m_pszListHelp); } } uiMinWidth += 4; if (!itemCount()) { uiWidth = uiMinWidth; uiHeight = 3; } else { uiWidth = maxWidth() + 2; if (uiWidth < uiMinWidth) { uiWidth = uiMinWidth; } uiHeight = itemCount() + 2; } if (uiWidth > uiScreenCols) { uiWidth = uiScreenCols; } if (uiHeight > uiScreenRows) { uiHeight = uiScreenRows; } uiULX = (uiScreenCols - uiWidth) / 2; uiULY = (uiScreenRows - uiHeight) / 2; if (uiULY < 3) { uiULY = 3; } if (uiULX < 3) { uiULX = 3; } if (uiHeight > uiScreenRows - (uiULY * 2)) { uiHeight = uiScreenRows - (uiULY * 2); } if (uiWidth > uiScreenCols - (uiULX * 2)) { uiWidth = uiScreenCols - (uiULX * 2); } } // Create the display window of the appropriate size. if (FTXWinInit( pScreen, uiWidth, uiHeight, &m_pWindow) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } // Position the window on the screen. if (FTXWinMove( m_pWindow, uiULX, uiULY) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } // Prevent window from scrolling. if (FTXWinSetScroll( m_pWindow, FALSE) != FTXRC_SUCCESS) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } // Don't wrap lines. if (FTXWinSetLineWrap( m_pWindow, FALSE) != FTXRC_SUCCESS) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } // Input cursor should not be present initially. if (FTXWinSetCursorType( m_pWindow, WPS_CURSOR_INVISIBLE) != FTXRC_SUCCESS) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } // Set foreground and background color for window. if (FTXWinSetBackFore( m_pWindow, m_bMonochrome ? WPS_BLACK : m_uiBackColor, m_bMonochrome ? WPS_WHITE : m_uiForeColor) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } // Clear the window if (FTXWinClear( m_pWindow) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } if (bDoBorder) { if (FTXWinDrawBorder( m_pWindow) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } if (m_pszListTitle && *m_pszListTitle) { FTXWinSetTitle( m_pWindow, m_pszListTitle, m_uiListTitleBackColor, m_uiListTitleForeColor); } if (m_pszListHelp && *m_pszListHelp) { FTXWinSetHelp( m_pWindow, m_pszListHelp, m_uiListHelpBackColor, m_uiListHelpForeColor); } } if (FTXWinOpen( m_pWindow) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } if (FTXWinGetCanvasSize( m_pWindow, &m_uiCols, &m_uiRows) != FTXRC_SUCCESS) { rc = RC_SET( FERR_MEM); goto Exit; } // Position on the current value if (!m_pCurrentItem) { m_pCurrentItem = m_pFirstItem; } pSaveCurrentItem = m_pCurrentItem; if (m_pCurrentItem) { positionTo( m_pCurrentItem, TRUE); } FTXWinSetCursorType( m_pWindow, WPS_CURSOR_VISIBLE | WPS_CURSOR_UNDERLINE); // Loop forever getting input. uiStartTime = FLM_GET_TIMER(); FLM_SECS_TO_TIMER_UNITS( uiResponseTimeout, uiResponseTimeout); for (;;) { // See if we have been told to exit. if ((pThread) && (pThread->getShutdownFlag())) { uiChar = 0; *puiExitValue = 0; goto Exit; } // See if the response timeout period has elapsed if( uiResponseTimeout) { if( (FLM_GET_TIMER() - uiStartTime) >= uiResponseTimeout) { uiChar = 0; *puiExitValue = 0; goto Exit; } } // Need to refresh the input cursor, in case it was changed by // a callback function. if (FTXWinTestKB( m_pWindow) == FTXRC_SUCCESS) { FTXWinInputChar( m_pWindow, &uiChar); uiStartTime = FLM_GET_TIMER(); if (pKeyFunc) { if (!((*pKeyFunc)( this, uiChar, &uiChar, pvAppData))) { if (m_pCurrentItem) { *puiExitValue = m_pCurrentItem->uiItemId; } goto Exit; } } switch( uiChar) { case WPK_INSERT: if (m_pInsertFunc) { char szItemName [100]; FLMUINT uiNewItem; FLMUINT uiNewShortcutKey; FLMUINT uiBeforeId; FLMUINT uiAfterId; uiBeforeId = (FLMUINT)((m_pCurrentItem && m_pCurrentItem->pPrev) ? m_pCurrentItem->pPrev->uiItemId : (FLMUINT)0); uiAfterId = (FLMUINT)((m_pCurrentItem && m_pCurrentItem->pNext) ? m_pCurrentItem->pNext->uiItemId : (FLMUINT)0); if ((*m_pInsertFunc)( this, uiBeforeId, uiAfterId, &uiNewItem, &uiNewShortcutKey, szItemName, sizeof( szItemName), m_pvAppData)) { if (RC_OK( insertItem( uiBeforeId, FALSE, uiNewItem, szItemName, uiNewShortcutKey, NULL, NULL, NULL))) { m_bInteracting = FALSE; setCurrentItem( uiNewItem); uiWidth = uiSaveWidth; uiHeight = uiSaveHeight; (void)FTXWinFree( &m_pWindow); m_pWindow = NULL; if (pbRedisplay) { *pbRedisplay = TRUE; goto Exit; } goto Start_Over; } } } break; case WPK_DELETE: if (m_pInsertFunc && m_pCurrentItem) { FLMUINT uiItemId = m_pCurrentItem->uiItemId; FlmPulldownItem * pItem; if (m_pCurrentItem->pNext) { pItem = m_pCurrentItem->pNext; } else { pItem = m_pCurrentItem->pPrev; } removeItem( uiItemId); m_bInteracting = FALSE; if (pItem) { setCurrentItem( pItem->uiItemId); } uiWidth = uiSaveWidth; uiHeight = uiSaveHeight; (void)FTXWinFree( &m_pWindow); m_pWindow = NULL; if (pbRedisplay) { *pbRedisplay = TRUE; goto Exit; } goto Start_Over; } break; case WPK_CTRL_N: case WPK_DOWN: case WPK_TAB: if (m_pCurrentItem) { cursorDown(); } break; case WPK_CTRL_P: case WPK_UP: case WPK_STAB: if (m_pCurrentItem) { cursorUp(); } break; case WPK_CTRL_LEFT: if (m_pCurrentItem) { scrollLeft(); } break; case WPK_CTRL_RIGHT: if (m_pCurrentItem) { scrollRight(); } break; case WPK_PGUP: if (m_pCurrentItem) { pageUp(); } break; case WPK_CTRL_DOWN: case WPK_CTRL_UP: break; case WPK_PGDN: if (m_pCurrentItem) { pageDown(); } break; case WPK_CTRL_D: break; case WPK_CTRL_HOME: case WPK_HOME: if (m_pCurrentItem) { cursorHome(); } break; case WPK_CTRL_END: case WPK_END: if (m_pCurrentItem) { cursorEnd(); } break; case WPK_BACKSPACE: if (m_pCurrentItem) { backspaceChar(); } break; case WPK_ENTER: Process_Key: if (m_pCurrentItem) { *puiExitValue = m_pCurrentItem->uiItemId; if (m_pCurrentItem->pSubList) { FLMUINT uiBoxUpperLeftCol; FLMUINT uiBoxUpperLeftRow; FLMUINT uiBoxHeight; FLMUINT uiBoxWidth; FLMUINT uiExitChar; if (bBoxFixed) { m_pCurrentItem->pSubList->calcEditLocation( uiScreenRows, uiScreenCols, uiULY + 1 + (m_pCurrentItem->uiItemNumber - m_pTopItem->uiItemNumber), uiULX, uiWidth, &uiBoxWidth, &uiBoxHeight, &uiBoxUpperLeftCol, &uiBoxUpperLeftRow); } else { uiBoxWidth = 0; uiBoxHeight = 0; uiBoxUpperLeftCol = 0; uiBoxUpperLeftRow = 0; } m_pCurrentItem->pSubList->setCurrentItem( 0); flmAssert( uiExitValueDepth > 1); if (uiExitValueDepth > 1) { m_pCurrentItem->pSubList->interact( pScreen, pThread, uiBoxWidth, uiBoxHeight, TRUE, uiBoxUpperLeftCol, uiBoxUpperLeftRow, bReturnOnShortcut, uiResponseTimeout, &uiExitChar, &puiExitValue [1], uiExitValueDepth - 1, NULL, pKeyFunc, pvAppData); if (!uiExitChar) { uiChar = 0; goto Exit; } if (uiExitChar != WPK_ESCAPE) { uiChar = uiExitChar; goto Exit; } } else { goto Exit; } } else if (m_pCurrentItem->pFunc) { if (!m_pCurrentItem->pFunc( this, m_pCurrentItem->uiItemId, m_pCurrentItem->pvAppData)) { goto Exit; } } else { goto Exit; } } break; case WPK_ALT_H: case WPK_CTRL_H: break; // Help case WPK_ESCAPE: m_pCurrentItem = pSaveCurrentItem; *puiExitValue = 0; goto Exit; case 0: // Callback can change key to zero to do nothing. break; default: if (m_pCurrentItem) { // First, see if it is a shortcut key. if (shortcutKey( uiChar)) { if (bReturnOnShortcut) { if (m_pCurrentItem->pSubList || m_pCurrentItem->pFunc) { goto Process_Key; } else { *puiExitValue = m_pCurrentItem->uiItemId; goto Exit; } } } else { typedown( uiChar); } } break; } } else { f_sleep( 1); } } Exit: *puiExitChar = uiChar; m_pThread = NULL; if (m_pWindow) { (void)FTXWinFree( &m_pWindow); m_pWindow = NULL; } m_bInteracting = FALSE; return( rc); }