/**************************************************************************** * tooltips.c * * * * Implements tool tips (help ballons) for the XForms GUI library. * * * * Copyright (C) 1997 Michael Chu * * This file is part of the tooltips system for XForms. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * 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, write to the Free Software * * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * * Contact information: Michael Chu * * mmchu@pobox.com * ****************************************************************************/ #include #include #include #include #include "forms.h" #include "tooltips_forms.h" #include "tooltips.h" /* The tooltips copyright. */ static char *tooltips_copyright = "Tooltips Library, Copyright (C) 1997 Michael Chu"; /**************************************************************************** * tooltips_initialize: * * * * Summary: Will initialize the tooltips system, making it ready to * * display tooltip messages. * * NOTE: I assume that fl_initialize has already been called * * to initialize the XForms system. * * * * Input: None. * * * * Returns: Error code: TOOLTIPS_ERROR_NOERROR if no error. * * TOOLTIPS_ERROR_ALREADYINITIALIZED if system already * * initialized. * * * * Global State Affected: * * Idle callback is registered with XForms system to handle * * tooltips displaying. * ****************************************************************************/ TOOLTIPS_ERROR tooltips_initialize() { /* make sure tooltips_copyright is used at least once. */ tooltips_copyright = tooltips_copyright; /* make sure that system is not already initialized. */ if (tooltips_internal_set_initialize_state( TOOLTIPS_INTERNAL_CHECK_INITIALIZED) == 1) { /* system is alreay initialized! */ return(TOOLTIPS_ERROR_ALREADYINITIALIZED); } /* set system initialization status. */ tooltips_internal_set_initialize_state(TOOLTIPS_INTERNAL_SET_INITIALIZED); /* map color for tooltip background. */ fl_mapcolor(TOOLTIPS_TIP_BACKGROUND_MAPINDEX, TOOLTIPS_TIP_BACKGROUND_RED, TOOLTIPS_TIP_BACKGROUND_GREEN, TOOLTIPS_TIP_BACKGROUND_BLUE); /* return no error. */ return(TOOLTIPS_ERROR_NOERROR); } /**************************************************************************** * tooltips_shutdown: * * * * Summary: Will shutdown the tooltips system, making it no longer ready * * to display tooltip messages. * * NOTE: I assume that fl_initialize has already been called * * to initialize the XForms system. * * * * Input: None. * * * * Returns: Error code: TOOLTIPS_ERROR_NOERROR if no error. * * TOOLTIPS_ERROR_NOTINITIALIZED if system not already * * initialized. * * * * Global State Affected: * * Idle callback is unregistered with XForms system. * ****************************************************************************/ TOOLTIPS_ERROR tooltips_shutdown() { /* make sure that system is already initialized. */ if (tooltips_internal_set_initialize_state( TOOLTIPS_INTERNAL_CHECK_INITIALIZED) == 0) { /* system is not initialized! */ return(TOOLTIPS_ERROR_NOTINITIALIZED); } /* set system initialization status. */ tooltips_internal_set_initialize_state(TOOLTIPS_INTERNAL_UNSET_INITIALIZED); /* clear the list. */ tooltips_internal_listhead(NULL, TOOLTIPS_INTERNAL_LIST_CLEAR); /* SHOULD PROBABLY FREE THE COLOR MAP INDEX WE HAVE ALLOCATED! */ /* return no error. */ return(TOOLTIPS_ERROR_NOERROR); } /**************************************************************************** * tooltips_suspend: * * * * Summary: Will suspend the tooltips system. * * NOTE: If any tooltips are showing, then they will be hidden. * * * * Input: None. * * * * Returns: Error code: TOOLTIPS_ERROR_NOERROR if no error. * * TOOLTIPS_ERROR_NOTINITIALIZED if system not already * * initialized. * * TOOLTIPS_ERROR_ALREADYSUSPENDED if system already * * suspended. * * * * Global State Affected: * * Suspends the tooltips system from displaying tooltips. * ****************************************************************************/ TOOLTIPS_ERROR tooltips_suspend() { /* make sure we are already initialized. */ if (tooltips_internal_set_initialize_state( TOOLTIPS_INTERNAL_CHECK_INITIALIZED) == 0) { /* system is not initialized! */ return(TOOLTIPS_ERROR_NOTINITIALIZED); } /* make sure we are not already suspended. */ if (tooltips_internal_set_suspend_mode( TOOLTIPS_INTERNAL_CHECK_SUSPENDED) == 1) { /* system is already suspended! */ return(TOOLTIPS_ERROR_ALREADYSUSPENDED); } /* hide any tooltips showing. */ tooltips_internal_hidealltips(); /* set system suspension mode. */ tooltips_internal_set_suspend_mode(TOOLTIPS_INTERNAL_SET_SUSPENDED); /* return no error. */ return(TOOLTIPS_ERROR_NOERROR); } /**************************************************************************** * tooltips_resume: * * * * Summary: Will resume the tooltips system. * * * * Input: None. * * * * Returns: Error code: TOOLTIPS_ERROR_NOERROR if no error. * * TOOLTIPS_ERROR_NOTINITIALIZED if system not already * * initialized. * * TOOLTIPS_ERROR_NOTSUSPENDED if system is not * * already suspended. * * * * Global State Affected: * * Unsuspends the tooltips system. * ****************************************************************************/ TOOLTIPS_ERROR tooltips_resume() { /* make sure we are already initialized. */ if (tooltips_internal_set_initialize_state( TOOLTIPS_INTERNAL_CHECK_INITIALIZED) == 0) { /* system is not initialized! */ return(TOOLTIPS_ERROR_NOTINITIALIZED); } /* make sure we are already suspended. */ if (tooltips_internal_set_suspend_mode( TOOLTIPS_INTERNAL_CHECK_SUSPENDED) == 0) { /* system is not suspended! */ return(TOOLTIPS_ERROR_NOTSUSPENDED); } /* set system suspension mode. */ tooltips_internal_set_suspend_mode(TOOLTIPS_INTERNAL_UNSET_SUSPENDED); /* return no error. */ return(TOOLTIPS_ERROR_NOERROR); } /**************************************************************************** * tooltips_getstatus: * * * * Summary: Will return the status of the tooltips system. * * * * Input: theStatusPtr: pointer to status structure to return status. * * NOTE: theStatusPtr must have memory allocated to it! * * If theStatusPtr is NULL, no action will be taken. * * * * Returns: Error code: TOOLTIPS_ERROR_NOERROR if no error. * * TOOLTIPS_ERROR_NULLADDRESS if a NULL pointer was * * passed in. * * * * Global State Affected: * * None. * ****************************************************************************/ TOOLTIPS_ERROR tooltips_getstatus(TOOLTIPS_STATUS *theStatusPtr) { int theState = 0; /* used to store state. */ TOOLTIPS_LIST *tempNodePtr = NULL; /* used to traverse linked list. */ /* make sure theStatusPtr is valid (to the best of our ability). */ if (theStatusPtr != NULL) { /* get initialization status. */ theState = tooltips_internal_set_initialize_state( TOOLTIPS_INTERNAL_CHECK_INITIALIZED); if (theState == 0) { /* system is not initialized, so cannot be suspended either or have registered tooltips. */ theStatusPtr->initialized = 0; theStatusPtr->suspendmode = 0; theStatusPtr->showing = 0; theStatusPtr->numtips = 0; } else if (theState == 1) { /* system is initialized. */ theStatusPtr->initialized = 1; } else { /* could not figure out state! so make it obvious that there is a bug. */ theStatusPtr->initialized = -1; theStatusPtr->suspendmode = 0; theStatusPtr->showing = 0; theStatusPtr->numtips = 0; /* return because of unknown error. */ return(TOOLTIPS_ERROR_UNKNOWNERROR); } /* only get further information about system if system is initialized. */ if (theStatusPtr->initialized == 1) { /* get suspension status. */ theState = tooltips_internal_set_suspend_mode( TOOLTIPS_INTERNAL_CHECK_SUSPENDED); if (theState == 0) { /* system is not suspended. */ theStatusPtr->suspendmode = 0; } else if (theState == 1) { /* system is suspended. */ theStatusPtr->suspendmode = 1; } else { /* could not figure out state! so make it obvious that there is a bug. */ theStatusPtr->suspendmode = -1; theStatusPtr->showing = 0; theStatusPtr->numtips = 0; /* return because of unknown error. */ return(TOOLTIPS_ERROR_UNKNOWNERROR); } /* get first node of list. */ tempNodePtr = tooltips_internal_listhead(NULL, TOOLTIPS_INTERNAL_LIST_RETURN); /* by default, start count at zero. */ theStatusPtr->numtips = 0; /* initially, we assume nothing is showing. */ theStatusPtr->showing = 0; /* count number of nodes in list. */ /* while the node is not NULL, keep counting. */ while (tempNodePtr != NULL) { /* if we are currently showing anything, then note it. */ if (tempNodePtr->theTipFormPtr != NULL) { theStatusPtr->showing = 1; } /* increment the count and go to next node. */ theStatusPtr->numtips = theStatusPtr->numtips + 1; tempNodePtr = tempNodePtr->nextNodePtr; } } /* return no error. */ return(TOOLTIPS_ERROR_NOERROR); } else { /* return NULL pointer error. */ return(TOOLTIPS_ERROR_NULLADDRESS); } } /**************************************************************************** * tooltips_addtip: * * * * Summary: Will add the given tooltip to the tooltips system. * * * * Input: whichObjectPtr: pointer to object to "attach" tooltip to. * * theTipPtr: string for tooltips system to display. * * * * Returns: Error code: TOOLTIPS_ERROR_NOERROR if no error. * * TOOLTIPS_ERROR_NOTINITIALIZED if system not already * * initialized. * * TOOLTIPS_ERROR_ALREADYREGISTERED if XForms object * * is already registered with tooltips system. * * TOOLTIPS_ERROR_NOTENOUGHMEMORY if not enough * * memory was available to update linked list. * * TOOLTIPS_ERROR_NULLADDRESS if a NULL pointer was * * passed in. * * * * Global State Affected: * * Object is registered with tooltips system. * ****************************************************************************/ TOOLTIPS_ERROR tooltips_addtip(FL_OBJECT *whichObjectPtr, char *theTipPtr) { TOOLTIPS_LIST *tempNodePtr = NULL; /* used to traverse linked list. */ TOOLTIPS_LIST *newNodePtr = NULL; /* used to create new node in linked list. */ /* make sure we are already initialized. */ if (tooltips_internal_set_initialize_state( TOOLTIPS_INTERNAL_CHECK_INITIALIZED) == 0) { /* system is not initialized! */ return(TOOLTIPS_ERROR_NOTINITIALIZED); } /* make sure we were not passed NULL pointers. */ if ((whichObjectPtr == NULL) || (theTipPtr == NULL)) { /* we have NULL pointers! */ return(TOOLTIPS_ERROR_NULLADDRESS); } /* make sure the object we were provided has the correct pointers internally set that we need. */ if (whichObjectPtr->form == NULL) { /* since every object should have a form and have its form pointer set to the form, then, if this pointer is not set, we do not know what happened! */ return(TOOLTIPS_ERROR_UNKNOWNERROR); } /* get first node of list. */ tempNodePtr = tooltips_internal_listhead(NULL, TOOLTIPS_INTERNAL_LIST_RETURN); /* check the nodes in list to make sure object is not already registered. */ /* while the node is not NULL, keep looking. */ while (tempNodePtr != NULL) { /* if we found a node with the object we are trying to register, then return already registered error. */ if (tempNodePtr->theObjectPtr == whichObjectPtr) { /* return already registered error. */ return(TOOLTIPS_ERROR_ALREADYREGISTERED); } else { /* advance node. */ tempNodePtr = tempNodePtr->nextNodePtr; } } /* if we got this far, then let us add a new node. */ newNodePtr = malloc(sizeof(TOOLTIPS_LIST)); /* get first node of list. */ tempNodePtr = tooltips_internal_listhead(NULL, TOOLTIPS_INTERNAL_LIST_RETURN); /* make sure we got allocated our memory. */ if (newNodePtr != NULL) { /* initialize the node first. */ newNodePtr->theObjectPtr = NULL; newNodePtr->theFormPtr = NULL; newNodePtr->theTipPtr = NULL; newNodePtr->theTimerFormPtr = NULL; newNodePtr->theTimerObjectPtr = NULL; newNodePtr->theTipFormPtr = NULL; newNodePtr->theJustification = TOOLTIPS_JUSTIFY_BOTTOM; newNodePtr->theJustification = TOOLTIPS_JUSTIFYPOINT_TOPLEFT; newNodePtr->shouldShow = 1; newNodePtr->currentlyShowing = 0; newNodePtr->prevNodePtr = NULL; newNodePtr->nextNodePtr = NULL; /* set the object and form pointers. */ newNodePtr->theObjectPtr = whichObjectPtr; newNodePtr->theFormPtr = whichObjectPtr->form; /* duplicate the tip passed in. */ newNodePtr->theTipPtr = malloc(((sizeof(char))*(strlen(theTipPtr)+1))); strcpy(newNodePtr->theTipPtr, theTipPtr); /* make sure we got allocated our memory for the string. */ if (newNodePtr->theTipPtr == NULL) { /* free the memory we allocated for the node. */ free(newNodePtr); newNodePtr = NULL; /* we could not get memory for the string, so return not enough memory error. */ return(TOOLTIPS_ERROR_NOTENOUGHMEMORY); } /* if this is first tip, then just register it with tooltips_internal_listhead, otherwise, first link node to old head node. */ if (tempNodePtr != NULL) { /* first set the next node pointer to current listhead node. */ newNodePtr->nextNodePtr = tempNodePtr; /* now, set old node previous node pointer to this new node. */ tempNodePtr->prevNodePtr = newNodePtr; } /* register this new node as new listhead node. */ tooltips_internal_listhead(newNodePtr, TOOLTIPS_INTERNAL_LIST_SET); /* register our pre-handler for this object. */ fl_set_object_prehandler(whichObjectPtr, tooltips_internal_pre_handler); } else { /* we could not get memory for the node, so return not enough memory error. */ return(TOOLTIPS_ERROR_NOTENOUGHMEMORY); } /* return no error. */ return(TOOLTIPS_ERROR_NOERROR); } /**************************************************************************** * tooltips_removetip: * * * * Summary: Will remove the given tooltip from the tooltips system. * * NOTE: if tooltip is currently showing, then it is hidden. * * * * Input: whichObjectPtr: pointer to object to unregister from tooltips * * system. * * * * Returns: Error code: TOOLTIPS_ERROR_NOERROR if no error. * * TOOLTIPS_ERROR_NOTINITIALIZED if system not already * * initialized. * * TOOLTIPS_ERROR_NOTREGISTERED if XForms object is * * not registered with tooltips system. * * TOOLTIPS_ERROR_NULLADDRESS if a NULL pointer was * * passed in. * * * * Global State Affected: * * Object is unregistered with tooltips system. * ****************************************************************************/ TOOLTIPS_ERROR tooltips_removetip(FL_OBJECT *whichObjectPtr) { TOOLTIPS_LIST *tempNodePtr = NULL; /* used to hold pointer to the node to delete. */ /* make sure we are already initialized. */ if (tooltips_internal_set_initialize_state( TOOLTIPS_INTERNAL_CHECK_INITIALIZED) == 0) { /* system is not initialized! */ return(TOOLTIPS_ERROR_NOTINITIALIZED); } /* make sure we were not passed a NULL pointer. */ if (whichObjectPtr == NULL) { /* we have a NULL pointer! */ return(TOOLTIPS_ERROR_NULLADDRESS); } /* get node of object. */ tempNodePtr = tooltips_internal_getnode(whichObjectPtr); /* if we found the node, then remove it, else, return an error. */ if (tempNodePtr != NULL) { /* if the tooltip is currently showing, then hide it. */ if (tempNodePtr->theTipFormPtr != NULL) { if (tempNodePtr->currentlyShowing != 0) { fl_hide_form(tempNodePtr->theTipFormPtr->ToolTip); tempNodePtr->currentlyShowing = 0; } fl_free_form(tempNodePtr->theTipFormPtr->ToolTip); free(tempNodePtr->theTipFormPtr); tempNodePtr->theTipFormPtr = NULL; } /* if the tooltip timer form exists, then hide and free it. */ if (tempNodePtr->theTimerFormPtr != NULL) { fl_hide_form(tempNodePtr->theTimerFormPtr); fl_free_form(tempNodePtr->theTimerFormPtr); tempNodePtr->theTimerFormPtr = NULL; tempNodePtr->theTimerObjectPtr = NULL; } /* first deallocate the string for the tip if it exists. */ if (tempNodePtr->theTipPtr != NULL) { /* deallocate string memory. */ free(tempNodePtr->theTipPtr); } /* if we have a previous node, then link the previous node to the next node. */ if (tempNodePtr->prevNodePtr != NULL) { /* link previous node to next node. */ tempNodePtr->prevNodePtr->nextNodePtr = tempNodePtr->nextNodePtr; } /* if we have a next node, then link the next node to the previous node. */ if (tempNodePtr->nextNodePtr != NULL) { /* link next node to previous node. */ tempNodePtr->nextNodePtr->prevNodePtr = tempNodePtr->prevNodePtr; } /* if this is the first node in the list, then register the next node as the new listhead node. */ if (tempNodePtr->prevNodePtr == NULL) { /* register next node as new listhead node. */ tooltips_internal_listhead(tempNodePtr->nextNodePtr, TOOLTIPS_INTERNAL_LIST_SET); } /* disassociate this link completely from the list and delete it. */ tempNodePtr->prevNodePtr = NULL; tempNodePtr->nextNodePtr = NULL; free(tempNodePtr); /* SHOULD PROBABLY FIND A WAY TO UNREGISTER POST-HANDLER! */ /* return no error. */ return(TOOLTIPS_ERROR_NOERROR); } else { /* return object not registered error. */ return(TOOLTIPS_ERROR_NOTREGISTERED); } } /**************************************************************************** * tooltips_removeformtips: * * * * Summary: Will remove all the tooltips associated with objects of the * * given form. * * NOTE: if tooltip is currently showing, then it is hidden. * * * * Input: whichFormPtr: pointer to form to use when finding objects to * * unregister. * * * * Returns: Error code: TOOLTIPS_ERROR_NOERROR if no error. * * TOOLTIPS_ERROR_NOTINITIALIZED if system not already * * initialized. * * TOOLTIPS_ERROR_NONEFROMFORM if there are no * * objects from this form registered with the * * system. * * TOOLTIPS_ERROR_NULLADDRESS if a NULL pointer was * * passed in. * * * * Global State Affected: * * All objects associated with the form are unregistered from * * the system. * ****************************************************************************/ TOOLTIPS_ERROR tooltips_removeformtips(FL_FORM *whichFormPtr) { TOOLTIPS_LIST *tempNodePtr = NULL; /* used to traverse linked list. */ TOOLTIPS_LIST *nextNodePtr = NULL; /* used to temporarily hold next pointer. */ int foundObject = 0; /* flag to see whether or not we have actually found an object from this form. */ /* make sure we are already initialized. */ if (tooltips_internal_set_initialize_state( TOOLTIPS_INTERNAL_CHECK_INITIALIZED) == 0) { /* system is not initialized! */ return(TOOLTIPS_ERROR_NOTINITIALIZED); } /* make sure we were not passed a NULL pointer. */ if (whichFormPtr == NULL) { /* we have a NULL pointer! */ return(TOOLTIPS_ERROR_NULLADDRESS); } /* get first node of list. */ tempNodePtr = tooltips_internal_listhead(NULL, TOOLTIPS_INTERNAL_LIST_RETURN); /* go through entire list and delete node with forms same as the form given. */ while (tempNodePtr != NULL) { /* if this node belongs to an object associated with the form, then delete it. */ if (tempNodePtr->theFormPtr == whichFormPtr) { /* note that we have found an object. */ foundObject = 1; /* if the tooltip is currently showing, then hide it. */ if (tempNodePtr->theTipFormPtr != NULL) { if (tempNodePtr->currentlyShowing != 0) { fl_hide_form(tempNodePtr->theTipFormPtr->ToolTip); tempNodePtr->currentlyShowing = 0; } fl_free_form(tempNodePtr->theTipFormPtr->ToolTip); free(tempNodePtr->theTipFormPtr); tempNodePtr->theTipFormPtr = NULL; } /* if the tooltip timer form exists, then hide and free it. */ if (tempNodePtr->theTimerFormPtr != NULL) { fl_hide_form(tempNodePtr->theTimerFormPtr); fl_free_form(tempNodePtr->theTimerFormPtr); tempNodePtr->theTimerFormPtr = NULL; tempNodePtr->theTimerObjectPtr = NULL; } /* first deallocate the string for the tip if it exists. */ if (tempNodePtr->theTipPtr != NULL) { /* deallocate string memory. */ free(tempNodePtr->theTipPtr); } /* if we have a previous node, then link the previous node to the next node. */ if (tempNodePtr->prevNodePtr != NULL) { /* link previous node to next node. */ tempNodePtr->prevNodePtr->nextNodePtr = tempNodePtr->nextNodePtr; } /* if we have a next node, then link the next node to the previous node. */ if (tempNodePtr->nextNodePtr != NULL) { /* link next node to previous node. */ tempNodePtr->nextNodePtr->prevNodePtr = tempNodePtr->prevNodePtr; } /* if this is the first node in the list, then register the next node as the new listhead node. */ if (tempNodePtr->prevNodePtr == NULL) { /* register next node as new listhead node. */ tooltips_internal_listhead(tempNodePtr->nextNodePtr, TOOLTIPS_INTERNAL_LIST_SET); } /* temporarily store next node pointer. */ nextNodePtr = tempNodePtr->nextNodePtr; /* disassociate this link completely from the list and delete it. */ tempNodePtr->prevNodePtr = NULL; tempNodePtr->nextNodePtr = NULL; free(tempNodePtr); /* SHOULD PROBABLY FIND A WAY TO UNREGISTER POST-HANDLER! */ /* set node pointer to next node. */ tempNodePtr = nextNodePtr; nextNodePtr = NULL; } else { /* advance to next node. */ tempNodePtr = tempNodePtr->nextNodePtr; } } /* if we found an object to delete, then return no error, otherwise, return none from form error. */ if (foundObject == 1) { /* return no error. */ return(TOOLTIPS_ERROR_NOERROR); } else { /* return none from form error. */ return(TOOLTIPS_ERROR_NONEFROMFORM); } } /**************************************************************************** * tooltips_cleartips: * * * * Summary: Will remove all the tooltips from the system. * * NOTE: if any tooltip is currently showing, then it is hidden. * * * * Input: None. * * * * Returns: Error code: TOOLTIPS_ERROR_NOERROR if no error. * * TOOLTIPS_ERROR_NOTINITIALIZED if system not already * * initialized. * * * * Global State Affected: * * All tooltips are removed from the system. * ****************************************************************************/ TOOLTIPS_ERROR tooltips_cleartips() { /* make sure we are already initialized. */ if (tooltips_internal_set_initialize_state( TOOLTIPS_INTERNAL_CHECK_INITIALIZED) == 0) { /* system is not initialized! */ return(TOOLTIPS_ERROR_NOTINITIALIZED); } /* clear the list. */ tooltips_internal_listhead(NULL, TOOLTIPS_INTERNAL_LIST_CLEAR); /* return no error. */ return(TOOLTIPS_ERROR_NOERROR); } /**************************************************************************** * tooltips_gettip: * * * * Summary: Will return the tooltip associated with the object. * * * * Input: whichObjectPtr: pointer to object whose tooltip should be * * returned. * * theTipPtrPtr: pointer to a pointer location where tooltip is to * * be copied. * * NOTE: We will not free any previous memory allocated and * * pointed to by *theTipPtrPtr since we cannot guarantee * * that if *theTipPtrPtr is non-NULL that it points to a * * valid address, therefore, it is the user's * * responsibility to prevent memory leaks by free any * * memory previously pointed to by *theTipPtrPtr! * * * * Returns: Error code: TOOLTIPS_ERROR_NOERROR if no error. * * TOOLTIPS_ERROR_NOTINITIALIZED if system not already * * initialized. * * TOOLTIPS_ERROR_NOTREGISTERED if XForms object is * * not registered with tooltips system. * * TOOLTIPS_ERROR_NOTENOUGHMEMORY if not enough * * memory was available to update linked list. * * TOOLTIPS_ERROR_NULLADDRESS if a NULL pointer was * * passed in. * * * * Global State Affected: * * None. * ****************************************************************************/ TOOLTIPS_ERROR tooltips_gettip(FL_OBJECT *whichObjectPtr, char **theTipPtrPtr) { TOOLTIPS_LIST *tempNodePtr = NULL; /* used to hold pointer to the node to delete. */ /* make sure we are already initialized. */ if (tooltips_internal_set_initialize_state( TOOLTIPS_INTERNAL_CHECK_INITIALIZED) == 0) { /* system is not initialized! */ return(TOOLTIPS_ERROR_NOTINITIALIZED); } /* make sure we were not passed NULL pointers. */ if ((whichObjectPtr == NULL) || (theTipPtrPtr == NULL)) { /* we have NULL pointers! */ return(TOOLTIPS_ERROR_NULLADDRESS); } /* get node of object. */ tempNodePtr = tooltips_internal_getnode(whichObjectPtr); /* initialize tip pointer to NULL. */ *theTipPtrPtr = NULL; /* if we found the node, then return the tooltip message. */ if (tempNodePtr != NULL) { /* copy the tooltip into the given pointer. */ *theTipPtrPtr = malloc(((sizeof(char))*(strlen(tempNodePtr->theTipPtr)+1))); strcpy(*theTipPtrPtr, tempNodePtr->theTipPtr); /* make sure we got memory allocated. */ if (*theTipPtrPtr == NULL) { return(TOOLTIPS_ERROR_NOTENOUGHMEMORY); } /* return no error. */ return(TOOLTIPS_ERROR_NOERROR); } else { /* return object not registered error. */ return(TOOLTIPS_ERROR_NOTREGISTERED); } } /**************************************************************************** * tooltips_setjustification: * * * * Summary: Will set the justification of the tooltip of an object * * registered with the tooltips system. * * * * Input: whichObjectPtr: pointer to object whose tooltip should be * * rejustified. * * theJustification: what justification from object to use. * * theJustificationPoint: which point on tooltip to justify from. * * * * Returns: Error code: TOOLTIPS_ERROR_NOERROR if no error. * * TOOLTIPS_ERROR_NOTINITIALIZED if system not already * * initialized. * * TOOLTIPS_ERROR_NOTREGISTERED if XForms object is * * not registered with tooltips system. * * TOOLTIPS_ERROR_BADJUSTIFICATION if justification * * combination is invalid. * * TOOLTIPS_ERROR_NULLADDRESS if a NULL pointer was * * passed in. * * * * Global State Affected: * * The justification of the object is modified. * ****************************************************************************/ TOOLTIPS_ERROR tooltips_setjustification(FL_OBJECT *whichObjectPtr, TOOLTIPS_JUSTIFICATION theJustification, TOOLTIPS_JUSTIFICATIONPOINT theJustificationPoint) { TOOLTIPS_LIST *tempNodePtr = NULL; /* used to hold pointer to the node to delete. */ int validChoice = 0; /* flag for whether we have a valid choice for justification. */ /* make sure we are already initialized. */ if (tooltips_internal_set_initialize_state( TOOLTIPS_INTERNAL_CHECK_INITIALIZED) == 0) { /* system is not initialized! */ return(TOOLTIPS_ERROR_NOTINITIALIZED); } /* make sure we were not passed a NULL pointer. */ if (whichObjectPtr == NULL) { /* we have a NULL pointer! */ return(TOOLTIPS_ERROR_NULLADDRESS); } /* get node of object. */ tempNodePtr = tooltips_internal_getnode(whichObjectPtr); /* if we found the node, then return the tooltip message. */ if (tempNodePtr != NULL) { /* make sure that certain combinations of justification are not allowed. */ /* NOTE: we use reverse logic. we assume everything is a bad combination at first and only turn on validChoice flag if we find a valid choice. */ if (theJustification == TOOLTIPS_JUSTIFY_TOPLEFT) { switch (theJustificationPoint) { case TOOLTIPS_JUSTIFYPOINT_TOPRIGHT: case TOOLTIPS_JUSTIFYPOINT_RIGHT: case TOOLTIPS_JUSTIFYPOINT_BOTTOMLEFT: case TOOLTIPS_JUSTIFYPOINT_BOTTOM: case TOOLTIPS_JUSTIFYPOINT_BOTTOMRIGHT: validChoice = 1; break; default: break; } } if (theJustification == TOOLTIPS_JUSTIFY_TOP) { switch (theJustificationPoint) { case TOOLTIPS_JUSTIFYPOINT_BOTTOMLEFT: case TOOLTIPS_JUSTIFYPOINT_BOTTOM: case TOOLTIPS_JUSTIFYPOINT_BOTTOMRIGHT: validChoice = 1; break; default: break; } } if (theJustification == TOOLTIPS_JUSTIFY_TOPRIGHT) { switch (theJustificationPoint) { case TOOLTIPS_JUSTIFYPOINT_TOPLEFT: case TOOLTIPS_JUSTIFYPOINT_LEFT: case TOOLTIPS_JUSTIFYPOINT_BOTTOMLEFT: case TOOLTIPS_JUSTIFYPOINT_BOTTOM: case TOOLTIPS_JUSTIFYPOINT_BOTTOMRIGHT: validChoice = 1; break; default: break; } } if (theJustification == TOOLTIPS_JUSTIFY_LEFT) { switch (theJustificationPoint) { case TOOLTIPS_JUSTIFYPOINT_TOPRIGHT: case TOOLTIPS_JUSTIFYPOINT_RIGHT: case TOOLTIPS_JUSTIFYPOINT_BOTTOMRIGHT: validChoice = 1; break; default: break; } } if (theJustification == TOOLTIPS_JUSTIFY_RIGHT) { switch (theJustificationPoint) { case TOOLTIPS_JUSTIFYPOINT_TOPLEFT: case TOOLTIPS_JUSTIFYPOINT_LEFT: case TOOLTIPS_JUSTIFYPOINT_BOTTOMLEFT: validChoice = 1; break; default: break; } } if (theJustification == TOOLTIPS_JUSTIFY_BOTTOMLEFT) { switch (theJustificationPoint) { case TOOLTIPS_JUSTIFYPOINT_TOPLEFT: case TOOLTIPS_JUSTIFYPOINT_TOP: case TOOLTIPS_JUSTIFYPOINT_TOPRIGHT: case TOOLTIPS_JUSTIFYPOINT_RIGHT: case TOOLTIPS_JUSTIFYPOINT_BOTTOMRIGHT: validChoice = 1; break; default: break; } } if (theJustification == TOOLTIPS_JUSTIFY_BOTTOM) { switch (theJustificationPoint) { case TOOLTIPS_JUSTIFYPOINT_TOPLEFT: case TOOLTIPS_JUSTIFYPOINT_TOP: case TOOLTIPS_JUSTIFYPOINT_TOPRIGHT: validChoice = 1; break; default: break; } } if (theJustification == TOOLTIPS_JUSTIFY_BOTTOMRIGHT) { switch (theJustificationPoint) { case TOOLTIPS_JUSTIFYPOINT_TOPLEFT: case TOOLTIPS_JUSTIFYPOINT_TOP: case TOOLTIPS_JUSTIFYPOINT_TOPRIGHT: case TOOLTIPS_JUSTIFYPOINT_LEFT: case TOOLTIPS_JUSTIFYPOINT_BOTTOMLEFT: validChoice = 1; break; default: break; } } /* we could not confirm that this justification was a valid one, then return bad justification error. */ if (validChoice == 0) { /* return bad justification error. */ return(TOOLTIPS_ERROR_BADJUSTIFICATION); } /* set justification information. */ tempNodePtr->theJustification = theJustification; tempNodePtr->theJustificationPoint = theJustificationPoint; /* return no error. */ return(TOOLTIPS_ERROR_NOERROR); } else { /* return object not registered error. */ return(TOOLTIPS_ERROR_NOTREGISTERED); } } /**************************************************************************** * tooltips_getjustification: * * * * Summary: Will get the justification of the tooltip of an object * * registered with the tooltips system. * * * * Input: whichObjectPtr: pointer to object whose tooltip should be * * rejustified. * * theJustificationPtr: pointer to location to store justification * * that is returned. * * theJustificationPointPtr: pointer to location to store * * justification point that is returned. * * * * Returns: Error code: TOOLTIPS_ERROR_NOERROR if no error. * * TOOLTIPS_ERROR_NOTINITIALIZED if system not already * * initialized. * * TOOLTIPS_ERROR_NOTREGISTERED if XForms object is * * not registered with tooltips system. * * TOOLTIPS_ERROR_NULLADDRESS if a NULL pointer was * * passed in. * * * * Global State Affected: * * The justification of the object is modified. * ****************************************************************************/ TOOLTIPS_ERROR tooltips_getjustification(FL_OBJECT *whichObjectPtr, TOOLTIPS_JUSTIFICATION *theJustificationPtr, TOOLTIPS_JUSTIFICATIONPOINT *theJustificationPointPtr) { TOOLTIPS_LIST *tempNodePtr = NULL; /* used to hold pointer to the node to delete. */ /* make sure we are already initialized. */ if (tooltips_internal_set_initialize_state( TOOLTIPS_INTERNAL_CHECK_INITIALIZED) == 0) { /* system is not initialized! */ return(TOOLTIPS_ERROR_NOTINITIALIZED); } /* make sure we were not passed a NULL pointer. */ if (whichObjectPtr == NULL) { /* we have a NULL pointer! */ return(TOOLTIPS_ERROR_NULLADDRESS); } /* get node of object. */ tempNodePtr = tooltips_internal_getnode(whichObjectPtr); /* if we found the node, then return the tooltip message. */ if (tempNodePtr != NULL) { /* store justification information. */ *theJustificationPtr = tempNodePtr->theJustification; *theJustificationPointPtr = tempNodePtr->theJustificationPoint; /* return no error. */ return(TOOLTIPS_ERROR_NOERROR); } else { /* return object not registered error. */ return(TOOLTIPS_ERROR_NOTREGISTERED); } } /**************************************************************************** * tooltips_internal_set_initialize_state: * * * * Summary: Will get/set the initialization state of the system. * * (i.e. whether or not system is initialized or not) * * * * Input: whichAction: code for whether to set/unset/get state. * * * * Returns: 0: current state is uninitialized. * * 1: current state is initialized. * * * * Global State Affected: * * The initialization state of the system is set. * ****************************************************************************/ int tooltips_internal_set_initialize_state(TOOLTIPS_INTERNAL_INITCODE whichAction) { static int currentState = 0; /* by default, system starts out as uninitialized. */ /* act on particular action. */ switch (whichAction) { case TOOLTIPS_INTERNAL_SET_INITIALIZED: /* set state as initialized. */ currentState = 1; break; case TOOLTIPS_INTERNAL_UNSET_INITIALIZED: /* set state as uninitialized. */ currentState = 0; break; case TOOLTIPS_INTERNAL_CHECK_INITIALIZED: /* return the current state. */ break; default: /* should never get here since we are only using this function internally and should always call it correctly! */ assert(0); break; } /* return the current state of the system. */ return(currentState); } /**************************************************************************** * tooltips_internal_set_suspend_mode: * * * * Summary: Will get/set the suspension mode of the system. * * (i.e. whether or not system is suspended or not) * * * * Input: whichAction: code for whether to set/unset/get state. * * * * Returns: 0: current state is unsuspended. * * 1: current state is suspended. * * * * Global State Affected: * * The suspension mode of the system is set. * ****************************************************************************/ int tooltips_internal_set_suspend_mode(TOOLTIPS_INTERNAL_SUSPENDCODE whichAction) { static int currentState = 0; /* by default, system starts out as unsuspended. */ /* act on particular action. */ switch (whichAction) { case TOOLTIPS_INTERNAL_SET_SUSPENDED: /* set state as suspended. */ currentState = 1; break; case TOOLTIPS_INTERNAL_UNSET_SUSPENDED: /* set state as unsuspended. */ currentState = 0; break; case TOOLTIPS_INTERNAL_CHECK_SUSPENDED: /* return the current state. */ break; default: /* should never get here since we are only using this function internally and should always call it correctly! */ assert(0); break; } /* return the current state of the system. */ return(currentState); } /**************************************************************************** * tooltips_internal_hidealltips: * * * * Summary: Will hide any existing tooltips showing. * * * * Input: None. * * * * Returns: None. * * * * Global State Affected: * * Any tooltips currently showing will be hidden. * ****************************************************************************/ void tooltips_internal_hidealltips() { TOOLTIPS_LIST *tempNodePtr = NULL; /* used to traverse linked list. */ /* get first node of list. */ tempNodePtr = tooltips_internal_listhead(NULL, TOOLTIPS_INTERNAL_LIST_RETURN); /* go through entire list and hide any tooltip that is currently showing. */ while (tempNodePtr != NULL) { /* if the tooltip is currently shown, then hide it. */ if (tempNodePtr->theTipFormPtr != NULL) { if (tempNodePtr->currentlyShowing != 0) { fl_hide_form(tempNodePtr->theTipFormPtr->ToolTip); tempNodePtr->currentlyShowing = 0; } fl_free_form(tempNodePtr->theTipFormPtr->ToolTip); free(tempNodePtr->theTipFormPtr); tempNodePtr->theTipFormPtr = NULL; } /* if the tooltip timer form exists, then hide and free it. */ if (tempNodePtr->theTimerFormPtr != NULL) { fl_hide_form(tempNodePtr->theTimerFormPtr); fl_free_form(tempNodePtr->theTimerFormPtr); tempNodePtr->theTimerFormPtr = NULL; tempNodePtr->theTimerObjectPtr = NULL; } /* advance to next node. */ tempNodePtr = tempNodePtr->nextNodePtr; } } /**************************************************************************** * tooltips_internal_gettipdimensions: * * * * Summary: Will return the height/width of the tooltip window given the * * particular tooltip object with text filled in. * * NOTE: This function adds in the TOOLTIPS_TIP_HEIGHT_BORDER to * * the height and TOOLTIPS_TIP_WIDTH_BORDER to the width. * * * * Input: theToolTipPtr: pointer to the text object belonging to the * * tooltip. * * theHeightPtr: pointer to location to store height of tooltip. * * theWidthPtr: pointer to location to store width of tooltip. * * * * Returns: The width to set the given tooltip for a "correct fit." * * * * Global State Affected: * * None. * ****************************************************************************/ void tooltips_internal_gettipdimensions(FL_OBJECT *theToolTipPtr, FL_Coord *theHeightPtr, FL_Coord *theWidthPtr) { /* get the dimensions of the tooltip. */ fl_get_string_dimension(theToolTipPtr->lstyle, theToolTipPtr->lsize, theToolTipPtr->label, strlen(theToolTipPtr->label), theHeightPtr, theWidthPtr); /* adjust height and width for borders. */ *theHeightPtr = *theHeightPtr + (2*TOOLTIPS_TIP_HEIGHT_BORDER); *theWidthPtr = *theWidthPtr + (2*TOOLTIPS_TIP_WIDTH_BORDER); } /**************************************************************************** * tooltips_internal_getnode: * * * * Summary: Will get the node associated with the XForms object. * * * * Input: whichObjectPtr: pointer to the XForms object. * * * * Returns: The pointer to the node in the internal tooltips linked list * * associated with the given object. NULL is returned if no * * such node exists. * * * * Global State Affected: * * None. * ****************************************************************************/ TOOLTIPS_LIST *tooltips_internal_getnode(FL_OBJECT *whichObjectPtr) { TOOLTIPS_LIST *tempNodePtr = NULL; /* used to hold pointer to the node to delete. */ /* get first node of list. */ tempNodePtr = tooltips_internal_listhead(NULL, TOOLTIPS_INTERNAL_LIST_RETURN); /* find the node we are looking for. */ while ((tempNodePtr != NULL) && (tempNodePtr->theObjectPtr != whichObjectPtr)) { /* advance to next node. */ tempNodePtr = tempNodePtr->nextNodePtr; } /* if we could not find a node, then return NULL, otherwise, return the node. */ if (tempNodePtr != NULL) { /* return the node. */ return(tempNodePtr); } else { /* return NULL. */ return(NULL); } } /**************************************************************************** * tooltips_internal_removenode: * * * * Summary: Will remove the given object node from the internal list. * * NOTE: if tooltip is currently showing, then it is hidden. * * NOTE: usually only called when object is being cleaned up, * * and we have no guarantee if the timer object pointer * * is valid anymore, so this is essentially * * tooltips_removetip but without error returning and * * also does not remove the timer form. * * * * Input: whichObjectPtr: pointer to object to unregister from tooltips * * system. * * * * Returns: None. * * * * Global State Affected: * * Object node is deleted from internal list. * ****************************************************************************/ void tooltips_internal_removenode(FL_OBJECT *whichObjectPtr) { TOOLTIPS_LIST *tempNodePtr = NULL; /* used to hold pointer to the node to delete. */ /* get node of object. */ tempNodePtr = tooltips_internal_getnode(whichObjectPtr); /* if we found the node, then remove it. */ if (tempNodePtr != NULL) { /* if the tooltip is currently showing, then hide it. */ if (tempNodePtr->theTipFormPtr != NULL) { if (tempNodePtr->currentlyShowing != 0) { fl_hide_form(tempNodePtr->theTipFormPtr->ToolTip); tempNodePtr->currentlyShowing = 0; } fl_free_form(tempNodePtr->theTipFormPtr->ToolTip); free(tempNodePtr->theTipFormPtr); tempNodePtr->theTipFormPtr = NULL; } /* first deallocate the string for the tip if it exists. */ if (tempNodePtr->theTipPtr != NULL) { /* deallocate string memory. */ free(tempNodePtr->theTipPtr); } /* if we have a previous node, then link the previous node to the next node. */ if (tempNodePtr->prevNodePtr != NULL) { /* link previous node to next node. */ tempNodePtr->prevNodePtr->nextNodePtr = tempNodePtr->nextNodePtr; } /* if we have a next node, then link the next node to the previous node. */ if (tempNodePtr->nextNodePtr != NULL) { /* link next node to previous node. */ tempNodePtr->nextNodePtr->prevNodePtr = tempNodePtr->prevNodePtr; } /* if this is the first node in the list, then register the next node as the new listhead node. */ if (tempNodePtr->prevNodePtr == NULL) { /* register next node as new listhead node. */ tooltips_internal_listhead(tempNodePtr->nextNodePtr, TOOLTIPS_INTERNAL_LIST_SET); } /* disassociate this link completely from the list and delete it. */ tempNodePtr->prevNodePtr = NULL; tempNodePtr->nextNodePtr = NULL; free(tempNodePtr); /* SHOULD PROBABLY FIND A WAY TO UNREGISTER POST-HANDLER! */ } } /**************************************************************************** * tooltips_internal_listhead: * * * * Summary: Will get/set/clear the internal tooltips list structure. * * * * Input: listHeadPtr: pointer to new list head node. * * whichAction: code for whether to set/clear/return head pointer. * * * * Returns: The current head pointer of the internal tooltips linked list. * * * * Global State Affected: * * The internal linked list of tooltips is set. * ****************************************************************************/ TOOLTIPS_LIST *tooltips_internal_listhead(TOOLTIPS_LIST *listHeadPtr, TOOLTIPS_INTERNAL_LISTCODE whichAction) { static TOOLTIPS_LIST *currentHeadPtr = NULL; /* pointer to current head node of the linked list. */ TOOLTIPS_LIST *tempNodePtr = NULL; /* used to traverse linked list. */ TOOLTIPS_LIST *nextNodePtr = NULL; /* used to temporary hold next node pointer. */ /* act on particular action. */ switch (whichAction) { case TOOLTIPS_INTERNAL_LIST_SET: /* set head node pointer to new pointer. */ currentHeadPtr = listHeadPtr; break; case TOOLTIPS_INTERNAL_LIST_CLEAR: /* clear entire list. */ /* hide any tooltips showing. */ tooltips_internal_hidealltips(); /* make sure list is not empty. */ if (currentHeadPtr != NULL) { /* first start at head of list. */ tempNodePtr = currentHeadPtr; /* go through entire list. */ while (tempNodePtr != NULL) { /* if the tooltip is currently shown, then hide it. */ if (tempNodePtr->theTipFormPtr != NULL) { if (tempNodePtr->currentlyShowing != 0) { fl_hide_form(tempNodePtr->theTipFormPtr->ToolTip); tempNodePtr->currentlyShowing = 0; } fl_free_form(tempNodePtr->theTipFormPtr->ToolTip); free(tempNodePtr->theTipFormPtr); tempNodePtr->theTipFormPtr = NULL; } /* if the tooltip timer form exists, then hide and free it. */ if (tempNodePtr->theTimerFormPtr != NULL) { fl_hide_form(tempNodePtr->theTimerFormPtr); fl_free_form(tempNodePtr->theTimerFormPtr); tempNodePtr->theTimerFormPtr = NULL; tempNodePtr->theTimerObjectPtr = NULL; } /* first, if the tip string exists, free that memory. */ if (tempNodePtr->theTipPtr != NULL) { /* deallocate string memory. */ free(tempNodePtr->theTipPtr); } /* store next pointer. */ nextNodePtr = tempNodePtr->nextNodePtr; /* free the node. */ free(tempNodePtr); tempNodePtr = NULL; /* reset to next node. */ tempNodePtr = nextNodePtr; nextNodePtr = NULL; } /* set head node pointer to NULL. */ currentHeadPtr = NULL; } break; case TOOLTIPS_INTERNAL_LIST_RETURN: /* return head node pointer. */ break; default: /* should never get here since we are only using this function internally and should always call it correctly! */ assert(0); break; } /* return the head node pointer. */ return(currentHeadPtr); } /**************************************************************************** * tooltips_internal_pre_handler: * * * * Summary: Main procedure which handles the detection and displaying of * * tooltips. * * * * Input: whichObjectPtr: pointer to the object this pre-handler * * handler. * * theEvent: the event that triggered the pre-handler. * * mouseX: the X location of the mouse relative to window. * * mouseY: the Y location of the mouse relative to window. * * pushedKey: which mouse key was pushed. * * xEvent: pointer to xevent that triggered this. * * * * Returns: 0: not used by XForms. * * * * Global State Affected: * * Times to display tooltips are detected and the appropriate * * tooltips are displayed and removed. * ****************************************************************************/ int tooltips_internal_pre_handler(FL_OBJECT *whichObjectPtr, int theEvent, FL_Coord mouseX, FL_Coord mouseY, int pushedKey, void *xEvent) { TOOLTIPS_LIST *theNodePtr = NULL; /* pointer to the node associated with this object. */ FL_Coord newX = 0, newY = 0; /* new X and Y location of tip form. */ FL_Coord newHeight = 0, newWidth = 0; /* new height and width of tip. */ FL_Coord rootX = 0, rootY = 0; /* X and Y dimensions of the root screen. */ static handlerInUse = 0; /* used to attempt to limit handler use to one at a time. */ /* try to make sure handler is not entered by two threads at once. */ if ((++handlerInUse) != 1) { handlerInUse--; return(0); } /* first make sure that we are initialized and not suspended. */ if ((tooltips_internal_set_initialize_state( TOOLTIPS_INTERNAL_CHECK_INITIALIZED)) && (!(tooltips_internal_set_suspend_mode( TOOLTIPS_INTERNAL_CHECK_SUSPENDED)))) { /* get the node of this object, if it exists. */ theNodePtr = tooltips_internal_getnode(whichObjectPtr); /* make sure that this object is one we are supposed to act on. also, make sure that this object is one we are supposed to show. */ if ((theNodePtr != NULL) && (theNodePtr->shouldShow != 0)) { /* act on certain events. */ switch (theEvent) { case FL_ENTER: /* mouse has entered object, so show the tooltip. */ /* tooltip should never be showing already when we enter it! */ assert(theNodePtr->theTipFormPtr == NULL); /* assuming tip is not already showing or scheduled to show, then show it. */ if ((theNodePtr->theTipFormPtr == NULL) && (theNodePtr->theTimerFormPtr == NULL)) { /* create a new form. */ theNodePtr->theTipFormPtr = create_form_ToolTip(); /* set the label and color. */ fl_set_object_label(theNodePtr->theTipFormPtr->Tip, theNodePtr->theTipPtr); fl_set_object_color(theNodePtr->theTipFormPtr->Tip, TOOLTIPS_TIP_BACKGROUND_MAPINDEX, TOOLTIPS_TIP_BACKGROUND_MAPINDEX); /* get the root window dimensions. */ fl_get_win_size(fl_root, &rootX, &rootY); /* get the dimensions for the tip. */ tooltips_internal_gettipdimensions(theNodePtr->theTipFormPtr->Tip, &newHeight, &newWidth); /* calculate X/Y location for the tip. NOTE: for now, we only implement orienting, TOOLTIPS_JUSTIFY_BOTTOM and TOOLTIPS_JUSTIFYPOINT_TOPLEFT. */ newX = theNodePtr->theFormPtr->x + theNodePtr->theObjectPtr->x + ((theNodePtr->theObjectPtr->w)/2); newY = theNodePtr->theFormPtr->y + theNodePtr->theObjectPtr->y + theNodePtr->theObjectPtr->h + TOOLTIPS_TIP_DISTANCE; /* if the place we were supposed to place the tooltip would have made it go off the bottom of the screen, then place tip above instead. NOTE: newWidth is the measurement of the thinner part of the tip which is our normal height. */ if ((newY+newWidth) > rootY) { newY = theNodePtr->theFormPtr->y + theNodePtr->theObjectPtr->y - newWidth - TOOLTIPS_TIP_DISTANCE; } /* SHOULD REALLY DEAL WITH JUSTIFICATION HERE! */ /* adjust the tooltip location to make sure it shows up on the screen. */ /* if the tooltip would fall off the left end of the screen, then make it line up with the left end of the screen. else, if it would fall off the right end of the screen, then make it line up with the right end of the screen. */ if (newX < 0) { newX = 0; } /* NOTE: newHeight is the measurement of the longer part of the tip which is our normal width. */ if ((newX+newHeight) > rootX) { newX = rootX - newHeight; } /* set the geometry of the tooltips form. */ fl_set_form_geometry(theNodePtr->theTipFormPtr->ToolTip, newX, newY, newHeight, newWidth); /* create a timer to put in a delay before displaying tooltip. */ /* first create a new form. */ theNodePtr->theTimerFormPtr = fl_bgn_form(FL_NO_BOX, newWidth, newHeight); /* add in a new timer object. */ theNodePtr->theTimerObjectPtr = fl_add_timer(FL_HIDDEN_TIMER, 0, 0, newWidth, newHeight, ""); /* set the timer callback. */ fl_set_object_callback(theNodePtr->theTimerObjectPtr, tooltips_internal_timer_handler, 0); /* store the object this timer is associated with. */ theNodePtr->theTimerObjectPtr->u_vdata = whichObjectPtr; /* done making the form. */ fl_end_form(); /* make form so it is in the exact position of the new tooltip. this guarantees no overlap with the object. */ fl_set_form_geometry(theNodePtr->theTimerFormPtr, newX, newY, newHeight, newWidth); /* lower the object to ensure it will no be seen. */ fl_lower_form(theNodePtr->theTimerFormPtr); /* show the form so the timer will be active. */ fl_show_form(theNodePtr->theTimerFormPtr, FL_PLACE_GEOMETRY, FL_NOBORDER, ""); /* set the timer for the delay. */ fl_set_timer(theNodePtr->theTimerObjectPtr, TOOLTIPS_DELAY); } break; case FL_LEAVE: /* mouse has left the object, so stop showing the tooltip if it was showing. */ if (theNodePtr->theTipFormPtr != NULL) { /* hide the tooltip. */ if (theNodePtr->currentlyShowing != 0) { fl_hide_form(theNodePtr->theTipFormPtr->ToolTip); theNodePtr->currentlyShowing = 0; } fl_free_form(theNodePtr->theTipFormPtr->ToolTip); free(theNodePtr->theTipFormPtr); theNodePtr->theTipFormPtr = NULL; } /* if the tooltip timer form exists, then hide and free it. */ if (theNodePtr->theTimerFormPtr != NULL) { fl_hide_form(theNodePtr->theTimerFormPtr); fl_free_form(theNodePtr->theTimerFormPtr); theNodePtr->theTimerFormPtr = NULL; theNodePtr->theTimerObjectPtr = NULL; } break; case FL_PUSH: /* mouse button was pushed, so stop showing the tooltip if it was showing. */ if (theNodePtr->theTipFormPtr != NULL) { /* hide the tooltip. */ if (theNodePtr->currentlyShowing != 0) { fl_hide_form(theNodePtr->theTipFormPtr->ToolTip); theNodePtr->currentlyShowing = 0; } fl_free_form(theNodePtr->theTipFormPtr->ToolTip); free(theNodePtr->theTipFormPtr); theNodePtr->theTipFormPtr = NULL; } /* if the tooltip timer form exists, then hide and free it. */ if (theNodePtr->theTimerFormPtr != NULL) { fl_hide_form(theNodePtr->theTimerFormPtr); fl_free_form(theNodePtr->theTimerFormPtr); theNodePtr->theTimerFormPtr = NULL; theNodePtr->theTimerObjectPtr = NULL; } break; case FL_FREEMEM: /* this object is scheduled for deletion, so delete the tip from the system. */ tooltips_internal_removenode(theNodePtr->theObjectPtr); break; default: break; } } } /* decrement handler use count. */ handlerInUse--; /* return 0. */ return(0); } /**************************************************************************** * tooltips_internal_timer_handler: * * * * Summary: Callback procedure that allows tooltips to be displayed at a * * delay. * * * * Input: timerObject: pointer to the timer object. * * * * Returns: void. * * * * Global State Affected: * * Display the tooltip that is designated. * ****************************************************************************/ void tooltips_internal_timer_handler(FL_OBJECT *timerObject, long data) { TOOLTIPS_LIST *theNodePtr = NULL; /* pointer to the node associated with this object. */ /* get the node of this object, if it exists. */ theNodePtr = tooltips_internal_getnode( ((FL_OBJECT *)(timerObject->u_vdata))); /* if the object still exists in our list, then show it. */ if (theNodePtr != NULL) { /* show the tooltip! */ fl_show_form(theNodePtr->theTipFormPtr->ToolTip, FL_PLACE_GEOMETRY, FL_NOBORDER, ""); /* if the tooltip timer form exists, then hide and free it. */ if (theNodePtr->theTimerFormPtr != NULL) { fl_hide_form(theNodePtr->theTimerFormPtr); fl_free_form(theNodePtr->theTimerFormPtr); theNodePtr->theTimerFormPtr = NULL; theNodePtr->theTimerObjectPtr = NULL; } /* mark tooltip as showing. */ theNodePtr->currentlyShowing = 1; } }