/*[]=====================================================================[]*/ /*[] LeadTools Run Time Library - Version 14 []*/ /*[] []*/ /*[] []*/ /*[] Copyright (c) 1991-2004 LEAD Technologies, Inc. []*/ /*[] All Rights Reserved. []*/ /*[]=====================================================================[]*/ // Some Usefull termenologyies // 1) Active Node: Is the node that contains the data that the client asked // by calling Undo or Redo operation. // 2) There must be an active node at any given time. // 3) When UL_Redo or UL_Undo operations return successfully, they will be holding // the data that the client asked in both pActvData and uDataInfo. For // pActvData , becuase it is a pointer, you must not use it or change it. // But you can copy it to another compatible variable, and this what you // should do, and then use that compaible variable. // 4) uDataInfo can be used by client to specify what type of data the client // wants to deal with. For example if the client is using 2 types of data, // let say struct A... and struct B..., the client specifies in his UL_Append that // if uDataInfo is 1 then this is of type A, and if it is 2 then it is of type B. // This information is also returned when the user calls UL_Redo or UL_Undo functions, // the client then uses uDataInfo to know what pActvData he is using. // 5) The member FreeNode in the UNDOLIST struct must be able to free // any type of data it might have. this function is suported by the user. #include "ImgPF.h" L_VOID Child_OnSize (HWND hWnd, L_UINT nState, L_INT nCx, L_INT nCy); //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// //[*] Function: UL_DelFirstNode. [*]// //[*] [*]// //[*] Description: This function deletes the first node of [*]// //[*] the pUndoList. [*]// //[*] [*]// //[*] Param: [in] pUndoList. The undo list structure. [*]// //[*] [*]// //[*] Return: < 0. See error codes. [*]// //[*] UL_SUCCESS. If function succeeds. The [*]// //[*] deleted node is deleted by [*]// //[*] the function member [*]// //[*] "UL_FreeData" of the pUndoList[*]// //[*] data structure. [*]// //[*] [*]// //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// L_INT UL_DelFirstNode (LPUNDOLIST pUndoList) { LPUNDOLISTNODE pToDeleteNode; LPUNDOLISTNODE pNextNode; if (!pUndoList) return UL_INVPARAM; // if the list is empty then return if (!(pToDeleteNode = pUndoList->firstNode)) return UL_LISTEMPTY; // Now i am the first node pNextNode = pToDeleteNode->next; pUndoList->firstNode = pNextNode; if (pNextNode) { // Copy the Activity state from the deleted node to the new node if (pToDeleteNode->bIsActive) pNextNode->bIsActive = TRUE; pNextNode->prev = NULL; } pUndoList->FreeNode (pToDeleteNode->pNodeData, pToDeleteNode->uUserInfo); free (pToDeleteNode); return UL_SUCCESS; } //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// //[*] Function: UL_AppendInt(). (This is an internal func) [*]// //[*] [*]// //[*] Description: This is an internal function that append [*]// //[*] a new node to the UndoList. If the list [*]// //[*] is full then the first node will be deleted [*]// //[*] using the delete function provided by the [*]// //[*] user in the pUndoList structure. [*]// //[*] [*]// //[*] Param: [in] pUndoList. The undo list structure. [*]// //[*] [in] pNewData. New data to be added. [*]// //[*] [in] uNewDataInfo. Extra information the client [*]// //[*] can use. It is primary used [*]// //[*] to describe the type of [*]// //[*] structue of pNewData. [*]// //[*] [out] bDelFromEnd. If this operation lead to a [*]// //[*] a deletion of a node or more, [*]// //[*] then this variable when the [*]// //[*] functions returns has a TRUE [*]// //[*] value if the deletion occurs [*]// //[*] at the end of the list, else [*]// //[*] the deletion occured at the [*]// //[*] nodes in the first of the [*]// //[*] list. This variable has [*]// //[*] meaning if the return value [*]// //[*] of the function > 1. [*]// //[*] [*]// //[*] Return: < 0. See error codes. [*]// //[*] memory for the node. [*]// //[*] >= 0 Function succeed but deleted [*]// //[*] a number of nodes. The number [*]// //[*] of nodes deleted is the value [*]// //[*] of the 'return value' [*]// //[*] [*]// //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// L_INT UL_Append (LPUNDOLIST pUndoList, L_VOID * pNewData, L_UINT uNewDataInfo, L_BOOL * bDelFromEnd) { LPUNDOLISTNODE pNewNode; LPUNDOLISTNODE pNode; LPUNDOLISTNODE pTmpNode; LPUNDOLISTNODE pDeleteNode; L_UINT uNodesCount; L_UINT uDeletedCount; if (!pUndoList) return UL_INVPARAM; pNewNode = (LPUNDOLISTNODE) malloc (sizeof(UNDOLISTNODE)); memset (pNewNode, 0, sizeof(UNDOLISTNODE)); if (!pNewNode) return UL_NOMEMORY; pNewNode->pNodeData = pNewData; pNewNode->uUserInfo = uNewDataInfo; pNewNode->bIsActive = TRUE; if (!(pNode = pUndoList->firstNode)) { // This is the first node that is attached in this list pUndoList->firstNode = pNewNode; return UL_SUCCESS; } // Find the active node. There should be an active node. Find it uNodesCount = 0; // After the loops finish and finding the active node, if // 1) pNode->next == NULL, then pNode points to the last node of the list, and // uNodesCount equals to the number of nodes currently (ie before the addition) // exists in the list. // 2) pNode->next != NULL, then pNode->next is the starting deletion of // the nodes. and uNodesCount is the number of nodes currentlly (== == ==) // will be after deletion the nodes. while (pNode) { uNodesCount++; if (pNode->bIsActive) break; pNode = pNode->next; } if (pNode->next) { // There exists nodes after this active node, so delete all nodes // starting from pNode->next till the end of the list. pDeleteNode = pNode->next; pNode->next = pNewNode; pNewNode->prev = pNode; pNode->bIsActive = FALSE; uDeletedCount = 0; while (pDeleteNode) { uDeletedCount++; pTmpNode = pDeleteNode->next; pUndoList->FreeNode (pDeleteNode->pNodeData, pDeleteNode->uUserInfo); free (pDeleteNode); pDeleteNode = pTmpNode; } if (bDelFromEnd) *bDelFromEnd = TRUE; return uDeletedCount; } else { // This is the last node, then attach the new node at the end of the list. pNode->next = pNewNode; pNode->bIsActive = FALSE; pNewNode->prev = pNode; // if the list, before this addition, is full then delete the first node. if (uNodesCount == pUndoList->uMaxEntries) { UL_DelFirstNode (pUndoList); if (bDelFromEnd) *bDelFromEnd = FALSE; return 1; // One node deleted } else return UL_SUCCESS; // No node(s) deleted } } //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// //[*] Function: UL_DeleteAllNodes. [*]// //[*] [*]// //[*] Description: This function deletes all the nodes of the [*]// //[*] pUndoList. [*]// //[*] [*]// //[*] Param: [in] pUndoList. The undo list structure. [*]// //[*] [*]// //[*] Return: < 0. See error codes. [*]// //[*] UL_SUCCESS. If deleted all the nodes. [*]// //[*] [*]// //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// L_INT UL_DeleteAllNodes (LPUNDOLIST pUndoList) { LPUNDOLISTNODE pNode; LPUNDOLISTNODE pNextNode; if (!pUndoList) return UL_INVPARAM; pNode = pUndoList->firstNode; pUndoList->firstNode = NULL; while (pNode) { pNextNode = pNode->next; pUndoList->FreeNode (pNode->pNodeData, pNode->uUserInfo); free (pNode); pNode = pNextNode; } return UL_SUCCESS; } //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// //[*] Function: UL_Redo. [*]// //[*] [*]// //[*] Description: This function makes an REDO operation on [*]// //[*] the undo list. It does not delete any nodes [*]// //[*] [*]// //[*] Param: [in] pUndoList. The undo list structure. [*]// //[*] Param: [out] pActvData. A pointer that contains the [*]// //[*] active data returned by this [*]// //[*] call. [*]// //[*] Param: [out] pActvDataInfo.Information about the [*]// //[*] pActvData. [*]// //[*] [*]// //[*] Return: FALSE. If there is no active node. [*]// //[*] TRUE. The function succeeded. [*]// //[*] [*]// //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// L_INT UL_Redo (LPUNDOLIST pUndoList, L_VOID ** pActvData, L_UINT * pActvDataInfo) { LPUNDOLISTNODE pNode; L_INT nRet; if (!pUndoList || !pActvData || !pActvDataInfo) return UL_INVPARAM; if (!(pNode = pUndoList->firstNode)) return UL_LISTEMPTY; // List is empty (which means undo list is empty) // Find the active node while (pNode) { if (pNode->bIsActive) { if (pNode->next) { // There is other node(s), so set the next node as active and take its data pNode->bIsActive = FALSE; pNode = pNode->next; pNode->bIsActive = TRUE; *pActvData = pNode->pNodeData; *pActvDataInfo = pNode->uUserInfo; nRet = UL_SUCCESS; break; } else { nRet = UL_NOREDO; break; } } else pNode = pNode->next; } return nRet; } //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// //[*] Function: UL_Undo. [*]// //[*] [*]// //[*] Description: This function makes an UNDO operation on [*]// //[*] the undo list. It does not delete any nodes [*]// //[*] [*]// //[*] Param: [in] pUndoList. The undo list structure. [*]// //[*] Param: [out] pActvData. A pointer that contains the [*]// //[*] active data returned by this [*]// //[*] call. [*]// //[*] Param: [out] pActvDataInfo.Information about the [*]// //[*] pActvData. [*]// //[*] Param: [in] pNewData. A pointer that contains the [*]// //[*] data that migh be appended in [*]// //[*] list. It is appened only if [*]// //[*] there is no active node. [*]// //[*] Param: [in] pNewDataInfo. Information about the [*]// //[*] pNewData. [*]// //[*] [*]// //[*] Return: FALSE. If there is no nodes. [*]// //[*] TRUE. The function succeeded. [*]// //[*] [*]// //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// L_INT UL_Undo (LPUNDOLIST pUndoList, L_VOID ** pActvData, L_UINT * pActvDataInfo) { LPUNDOLISTNODE pNode; L_BOOL bFoundActiveNode = FALSE; if (!pUndoList || !pActvData || !pActvDataInfo) return UL_INVPARAM; if (!(pNode = pUndoList->firstNode)) return UL_LISTEMPTY; // List is empty (which means undo list is empty) // Find first active node. while (!pNode->bIsActive) pNode = pNode->next; // If there is a previous node then make an undo if (pNode->prev) { pNode->bIsActive = FALSE; pNode = pNode->prev; pNode->bIsActive = TRUE; *pActvData = pNode->pNodeData; *pActvDataInfo = pNode->uUserInfo; return UL_SUCCESS; } else return UL_NOUNDO; } //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// //[*] Function: UL_Init. [*]// //[*] [*]// //[*] Description: Initialaze the Data Structure of the [*]// //[*] undo list. [*]// //[*] [*]// //[*] Param: [in] pUndoList. The undo list structure. [*]// //[*] Param: [in] *UL_FreeData. A user defined function that [*]// //[*] deals with freeing any [*]// //[*] allocated data in the [*]// //[*] node->pUndoNodeData. [*]// //[*] Param: [in] uMaxEntries. Maximun number of nodes in the[*]// //[*] undo list structure. [*]// //[*] [*]// //[*] Return: void. [*]// //[*] [*]// //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// L_INT UL_Init (LPUNDOLIST pUndoList, UL_FREEFUNCTION FreeNode, L_UINT uMaxEntries) { if (!pUndoList || !FreeNode) return UL_INVPARAM; if (!uMaxEntries) return UL_INVPARAM; memset (pUndoList, 0, sizeof(UNDOLIST)); pUndoList->FreeNode = FreeNode; pUndoList->uMaxEntries = uMaxEntries; return UL_SUCCESS; } //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// //[*] Function: UL_IsRedoAvailable. [*]// //[*] [*]// //[*] Description: This function checks whether a Redo [*]// //[*] operation is available. [*]// //[*] [*]// //[*] Param: [in] pUndoList. The undo list structure. [*]// //[*] [*]// //[*] Return: TRUE. If we can perform a Redo operation. [*]// //[*] FALSE. If we can not . [*]// //[*] [*]// //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// L_BOOL UL_IsRedoAvailable (LPUNDOLIST pUndoList) { // Redo is available if there exists an Active Node. And this active // node is not the last node LPUNDOLISTNODE pNode; if (!pUndoList) return FALSE; if (!(pNode = pUndoList->firstNode)) return FALSE; while (pNode) { if (pNode->bIsActive) // If this node is the last node then return false, else return true return (pNode->next ? TRUE : FALSE); pNode = pNode->next; } return FALSE; } //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// //[*] Function: UL_IsUndoAvailable. [*]// //[*] [*]// //[*] Description: This function checks whether an Undo [*]// //[*] operation is available. [*]// //[*] [*]// //[*] Param: [in] pUndoList. The undo list structure. [*]// //[*] [*]// //[*] Return: TRUE. If we can perform an Undo operation.[*]// //[*] FALSE. If we can not. [*]// //[*] [*]// //[*]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-[*]// L_BOOL UL_IsUndoAvailable (LPUNDOLIST pUndoList) { // for the Undo list to be available it must have at least one node // in the list, and the first node is not active. if (!pUndoList) return FALSE; if (pUndoList->firstNode) return (pUndoList->firstNode->bIsActive ? FALSE : TRUE); else return FALSE; } // Use this function to loop all nodes of the list. L_VOID LoopIt (LPUNDOLIST pUndoList, L_UINT uUserInfo) { RGBQUAD pPalette[256]; //0 MemorizeAndCopyBitmap _ Before L_UINT n = 0, nRet; //1 MemorizeAndCopyBitmap _ After pCHILDDATA pData; //2 MemorizeBitmap _ Before LPUNDOLISTNODE node; //3 MemorizeBitmap _ After DWORD d = 1, i; //9 AddBitmap //100 UndoRedo //5656 Function Call if (!(node = pUndoList->firstNode)) return; while (node) { // START CODE FROM HERE memset (pPalette, 7, sizeof(PALETTEENTRY) * 256); n++; pData = (pCHILDDATA) node->pNodeData; nRet = L_GetBitmapColors(&pData->LeadBitmap, 0, 256, pPalette); for (i = 0; i <256 ;i++) { if ((pPalette[i].rgbBlue != i) || (pPalette[i].rgbRed != i) || (pPalette[i].rgbGreen != i)) { d = 0; } } // END CODE HERE node = node->next; } } /* LLL EEEEEEEEE AAAAAAAA DDDDDD LLL EEEEEEEEEE AAAAAAAAAA DDD DDD LLL EEE AAA AAA DDD DDD LLL EEEEEEEEEE AAA AAA DDD DDD LLL EEEEEEEEEE AAAAAAAAAA DDD DDD LLL EEE AAAAAAAAAA DDD DDD LLLLLLLL EEEEEEEEEE AAA AAA DDD DDD LLLLLLLL EEEEEEEEE AAA AAA DDDDD */ #define UL_SAVEDCHILDDATA 0 L_VOID SetSavedData (HWND hWnd, CONST pCHILDDATA pData, pCHILDDATA pUndoData); L_VOID FreeFun (LPVOID pData, UINT uType) { pCHILDDATA pChildData; switch (uType) { case UL_SAVEDCHILDDATA: pChildData = (pCHILDDATA) pData; if (pChildData->LeadBitmap.Flags.Allocated) { L_FreeBitmap (&pChildData->LeadBitmap); L_InitBitmap(&pChildData->LeadBitmap, sizeof(BITMAPHANDLE), 0, 0, 0); } if (pChildData->bmFloater.Flags.Allocated) { L_FreeBitmap (&pChildData->bmFloater); L_InitBitmap(&pChildData->bmFloater, sizeof(BITMAPHANDLE), 0, 0, 0); } if (pChildData->bmSave.Flags.Allocated) { L_FreeBitmap (&pChildData->bmSave); L_InitBitmap(&pChildData->bmSave, sizeof(BITMAPHANDLE), 0, 0, 0); } if (pChildData->pPolyPt) { GlobalFreePtr(pChildData->pPolyPt); pChildData->pPolyPt = NULL; } free (pChildData); break; } } // hWndChild is he handle of the child window that contans pData L_VOID L_UndoList_Init (HWND hWndChild, UL_FREEFUNCTION FreeFun, L_UINT uMaxEntries) { pCHILDDATA pData; pCHILDDATA pSavedData = NULL; pData = LOCKCHILDDATA (hWndChild); if (UL_Init (&pData->UndoList, FreeFun, uMaxEntries) != UL_SUCCESS) return; pSavedData = (pCHILDDATA) calloc (1, sizeof(CHILDDATA)); if (!pSavedData) return; // Initiate data SetSavedData (hWndChild, pData, pSavedData); UL_Append (&pData->UndoList, (L_VOID*) pSavedData, UL_SAVEDCHILDDATA, NULL); UNLOCKCHILDDATA (hWndChild); } // The function will copy the handle and data of LeadBitmap, the member of pData // structre. So it is safe, after calling this function, to free the data or // handle of LeadBitmap. // hWndChild is he handle of the child window that contans pData L_VOID L_UndoList_AddBitmap (HWND hWndChild) { pCHILDDATA pSavedData = NULL; pCHILDDATA pData; HCURSOR hOldCur; pData = LOCKCHILDDATA (hWndChild); hOldCur = SetCursor(LoadCursor (NULL, IDC_WAIT)); pSavedData = (pCHILDDATA) calloc (1, sizeof(CHILDDATA)); if (!pSavedData) return; SetSavedData (hWndChild, pData, pSavedData); UL_Append (&pData->UndoList, (L_VOID*) pSavedData, UL_SAVEDCHILDDATA, NULL); SetStatusBarText(TEXT(""), &pData->LeadBitmap, szPos, szColor); SetCursor(hOldCur); UNLOCKCHILDDATA (hWndChild); } static L_VOID L_UndoList_UndoRedo (HWND hWndChild, L_BOOL bIsUndo) { BITMAPHANDLE bL; pCHILDDATA pSavedData = NULL; pCHILDDATA pData; HCURSOR hOldCur; L_VOID * pActiveData; L_UINT uUndoType; UNDOLIST TmpUL; RECT rcRect; L_UINT uMem; //MEMDISK// L_INT nShow; pData = LOCKCHILDDATA (hWndChild); if (bIsUndo) { if (!UL_IsUndoAvailable(&pData->UndoList)) { UNLOCKCHILDDATA (hWndChild); return; } else UL_Undo (&pData->UndoList, &pActiveData, &uUndoType); } else { if (!UL_IsRedoAvailable(&pData->UndoList)) { UNLOCKCHILDDATA (hWndChild); return; } else UL_Redo (&pData->UndoList, &pActiveData, &uUndoType); } hOldCur = SetCursor(LoadCursor (NULL, IDC_WAIT)); // process the retured data switch (uUndoType) { case UL_SAVEDCHILDDATA: // Free the All Bitmaps in the ChildWindow //MEMDISK...// if (pData->LeadBitmap.Flags.Allocated) { L_GetBitmapMemoryInfo (&pData->LeadBitmap, &uMem, NULL, NULL, NULL, NULL, NULL); if (uMem == TYPE_CONV) //...MEMDISK// L_FreeBitmap (&pData->LeadBitmap); } //MEMDISK...// if (pData->bmSave.Flags.Allocated) L_FreeBitmap (&pData->bmSave); //MEMDISK...// if (pData->bmFloater.Flags.Allocated) L_FreeBitmap (&pData->bmFloater); // Free any allocated data if (pData->pPolyPt) GlobalFreePtr (pData->pPolyPt); pData->pPolyPt = NULL; // Take a COPY from the returned data pSavedData = (pCHILDDATA) pActiveData; L_CopyBitmapHandle (&bL, &pSavedData->LeadBitmap, sizeof(BITMAPHANDLE)); TmpUL = pData->UndoList; memcpy (pData, pSavedData, sizeof(CHILDDATA)); pData->UndoList = TmpUL; // At this point pData->LeadBitmap is on DISK, in the contrary of bmSave and bmFloater L_CopyBitmapHandle(&pData->LeadBitmap, &bL, sizeof(BITMAPHANDLE)); //MEMDISK// L_CopyBitmap2 (&pData->bmSave, &pSavedData->bmSave, TYPE_CONV, sizeof(BITMAPHANDLE)); L_CopyBitmap2 (&pData->bmFloater, &pSavedData->bmFloater, TYPE_CONV, sizeof(BITMAPHANDLE)); if (pSavedData->pPolyPt) { pData->pPolyPt = (POINT *) GlobalAllocPtr(GHND, sizeof(POINT)); if (pData->pPolyPt) { pData->pPolyPt->x = pSavedData->pPolyPt->x; pData->pPolyPt->y = pSavedData->pPolyPt->y; } } if (L_BitmapHasRgn(&pData->LeadBitmap)) { pData->uTimerID = SetTimer(hWndChild, 1, 100, NULL); } else { KillTimer (hWndChild, 1); } GetClientRect(hWndChild, &rcRect); if(IsZoomed(hWndChild)) nShow = SIZEFULLSCREEN; else if (IsIconic (hWndChild)) { nShow = SIZEICONIC ; } else nShow = SIZENORMAL; FORWARD_WM_SIZE (hWndChild, nShow, rcRect.right, rcRect.bottom, ChildWndProc); InvalidateRect(hWndChild, NULL, TRUE); break; } SetCursor(hOldCur); UNLOCKCHILDDATA (hWndChild); } // hWndChild is he handle of the child window that contans pData L_VOID L_UndoList_Undo (HWND hWndChild) { pCHILDDATA pData = LOCKCHILDDATA(hWndChild); L_UndoList_UndoRedo (hWndChild, TRUE); UNLOCKCHILDDATA(hWndChild); } // hWndChild is he handle of the child window that contans pData L_VOID L_UndoList_Redo (HWND hWndChild) { pCHILDDATA pData = LOCKCHILDDATA(hWndChild); L_UndoList_UndoRedo (hWndChild, FALSE); UNLOCKCHILDDATA(hWndChild); } // hWndChild is he handle of the child window that contans pData L_INT L_UndoList_DestroyList (HWND hWndChild) { pCHILDDATA pData; L_INT nRet; pData = LOCKCHILDDATA (hWndChild); nRet = UL_DeleteAllNodes (&pData->UndoList); UNLOCKCHILDDATA (hWndChild); return nRet; } // hWndChild is he handle of the child window that contans pData L_BOOL L_UndoList_RedoExists (HWND hWndChild) { pCHILDDATA pData; L_BOOL nRet; pData = LOCKCHILDDATA (hWndChild); nRet = UL_IsRedoAvailable(&pData->UndoList); UNLOCKCHILDDATA (hWndChild); return nRet; } // hWndChild is he handle of the child window that contans pData L_BOOL L_UndoList_UndoExists (HWND hWndChild) { pCHILDDATA pData; L_BOOL nRet; pData = LOCKCHILDDATA (hWndChild); nRet = UL_IsUndoAvailable(&pData->UndoList); UNLOCKCHILDDATA (hWndChild); return nRet; } // Use it if you want to change the bitmap from DISK to CONV L_VOID MemorizeBitmap (HWND hWndChild) { BITMAPHANDLE Bitmap; pCHILDDATA pData; L_UINT uMem; //MEMDISK// pData = LOCKCHILDDATA (hWndChild); //MEMDISK...// L_GetBitmapMemoryInfo (&pData->LeadBitmap, &uMem, NULL, NULL, NULL, NULL, NULL); if (uMem == TYPE_DISK) { L_CopyBitmap2 (&Bitmap, &pData->LeadBitmap, TYPE_CONV, sizeof(BITMAPHANDLE)); L_CopyBitmapHandle (&pData->LeadBitmap, &Bitmap, sizeof(BITMAPHANDLE)); } UNLOCKCHILDDATA (hWndChild); } // Use it when you want to copy the LeadBitmap into the Dialog Bitmap Data L_VOID MemorizeAndCopyBitmap (HWND hWndChild, pBITMAPHANDLE pDlgBitmap) { pCHILDDATA pData; L_UINT uMem; //MEMDISK// pData = LOCKCHILDDATA (hWndChild); //MEMDISK...// L_GetBitmapMemoryInfo (&pData->LeadBitmap, &uMem, NULL, NULL, NULL, NULL, NULL); if (uMem == TYPE_DISK) L_CopyBitmap2 (pDlgBitmap, &pData->LeadBitmap, TYPE_CONV, sizeof(BITMAPHANDLE)); else L_CopyBitmap (pDlgBitmap, &pData->LeadBitmap, sizeof(BITMAPHANDLE)); UNLOCKCHILDDATA (hWndChild); } L_VOID FreeMemorizedBitmap (HWND hWndChild) { pCHILDDATA pData; L_UINT uMem; //MEMDISK// pData = LOCKCHILDDATA (hWndChild); L_GetBitmapMemoryInfo (&pData->LeadBitmap, &uMem, NULL, NULL, NULL, NULL, NULL); if (uMem == TYPE_CONV) //..MEMDISK// L_FreeBitmap(&pData->LeadBitmap); UNLOCKCHILDDATA (hWndChild); } L_VOID SetSavedData (HWND hWnd, CONST pCHILDDATA pData, pCHILDDATA pUndoData) { RECT rcClient; L_INT nShow; GetClientRect (hWnd, &rcClient); { if(IsZoomed(hWnd)) nShow = SIZEFULLSCREEN; else if (IsIconic (hWnd)) { nShow = SIZEICONIC ; } else nShow = SIZENORMAL; Child_OnSize (hWnd, nShow, RECTWIDTH (&rcClient), RECTHEIGHT (&rcClient)); } memcpy (pUndoData, pData, sizeof(CHILDDATA)); // Copy all bitmaps in the pData to pUndoData and make them on DISK L_CopyBitmap2 (&pUndoData->LeadBitmap, &pData->LeadBitmap, TYPE_DISK, sizeof(BITMAPHANDLE)); L_CopyBitmap2 (&pUndoData->bmFloater, &pData->bmFloater, TYPE_DISK, sizeof(BITMAPHANDLE)); L_CopyBitmap2 (&pUndoData->bmSave, &pData->bmSave, TYPE_DISK, sizeof(BITMAPHANDLE)); // Copy allocated memory after u allocate new one if (pData->pPolyPt) { pUndoData->pPolyPt = (POINT *) GlobalAllocPtr(GHND, sizeof(POINT)); if (pUndoData->pPolyPt) { pUndoData->pPolyPt->x = pData->pPolyPt->x; pUndoData->pPolyPt->y = pData->pPolyPt->y; } } }