00001 // $Id: oilprog.cpp 1282 2006-06-09 09:46:49Z alex $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 00099 /* 00100 The progress indicator (OIL implementation). 00101 00102 00103 */ 00104 00105 00106 #include "camtypes.h" 00107 00108 #include <string.h> // for memset() 00109 #include "csrstack.h" 00110 #include "oilprog.h" 00111 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00112 #include "keypress.h" 00113 #include "unicdman.h" 00114 00115 //#include "justin.h" // for cursor bitmaps 00116 //#include "justin2.h" 00117 00118 00119 DECLARE_SOURCE("$Revision: 1282 $"); 00120 00121 00122 00123 // This structure defines a pair of bitmaps, which can be combined to make a cursor. 00124 00125 struct MaskPair 00126 { 00127 UINT32 AndID; 00128 UINT32 XorID; 00129 }; 00130 00131 00132 struct CursorMask 00133 { 00134 CBitmap* pAndMask; 00135 CBitmap* pXorMask; 00136 }; 00137 00138 00139 00140 // Declare an array of CursorMasks, which together form the animation sequence. 00141 00142 const INT32 nFrameCount = 9; 00143 INT32 CurrentFrame; 00144 00145 CursorMask CursorSeq[nFrameCount]; 00146 00147 00148 00149 // This array stores the numeric resource identifiers of each mask bitmap. 00150 00151 const MaskPair CursorMaskID[nFrameCount] = 00152 { 00153 { _R(IDB_AND_PROGRESS_0), _R(IDB_XOR_PROGRESS_0) }, 00154 { _R(IDB_AND_PROGRESS_1), _R(IDB_XOR_PROGRESS_1) }, 00155 { _R(IDB_AND_PROGRESS_2), _R(IDB_XOR_PROGRESS_2) }, 00156 { _R(IDB_AND_PROGRESS_3), _R(IDB_XOR_PROGRESS_3) }, 00157 { _R(IDB_AND_PROGRESS_4), _R(IDB_XOR_PROGRESS_4) }, 00158 { _R(IDB_AND_PROGRESS_5), _R(IDB_XOR_PROGRESS_5) }, 00159 { _R(IDB_AND_PROGRESS_6), _R(IDB_XOR_PROGRESS_6) }, 00160 { _R(IDB_AND_PROGRESS_7), _R(IDB_XOR_PROGRESS_7) }, 00161 { _R(IDB_AND_PROGRESS_8), _R(IDB_XOR_PROGRESS_8) } 00162 }; 00163 00164 00165 00166 // GDI objects we use etc. 00167 00168 CDC* pMemoryDC1; 00169 CDC* pMemoryDC2; 00170 CBitmap* pAndBmp; 00171 CBitmap* pXorBmp; 00172 CFont* pCursorFont; 00173 00174 CRect TextRect; 00175 CRect MaskRect; 00176 00177 00178 00179 00180 /******************************************************************************************** 00181 > BOOL InitProgressCursor() 00182 00183 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00184 Created: 19/11/93 00185 Inputs: - 00186 Outputs: - 00187 Returns: TRUE if initialisation was successful. 00188 Purpose: Does initial calculations and creates all the GDI objects that 00189 UpdateProgressCursor() requires. 00190 Errors: - 00191 SeeAlso: UpdateProgressCursor; DeInitProgressCursor 00192 ********************************************************************************************/ 00193 00194 BOOL InitProgressCursor() 00195 { 00196 // Load in the mask bitmap pairs which make up the cursor animation sequence. 00197 for (INT32 i = 0; i < nFrameCount; i++) 00198 { 00199 // Allocate two new bitmap objects on the heap. 00200 CursorSeq[i].pAndMask = new CBitmap; 00201 CursorSeq[i].pXorMask = new CBitmap; 00202 if (!CursorSeq[i].pAndMask || !CursorSeq[i].pXorMask) 00203 { 00204 if (IsUserName("JustinF")) 00205 TRACE( _T("Couldn't allocate CBitmap objects in InitProgressCursor()!\n")); 00206 return FALSE; 00207 } 00208 00209 // Load the appropriate bitmaps from resources. 00210 if (!CursorSeq[i].pAndMask->LoadBitmap(CursorMaskID[i].AndID) || 00211 !CursorSeq[i].pXorMask->LoadBitmap(CursorMaskID[i].XorID)) 00212 { 00213 if (IsUserName("JustinF")) 00214 TRACE( _T("Couldn't load bitmap resources in InitProgressCursor()!\n")); 00215 return FALSE; 00216 } 00217 00218 // In the debugging version, check for AppStudio sabotage (it converts monochrome 00219 // bitmaps to colour - b*st*rd!) 00220 #ifdef _DEBUG 00221 BITMAP andinfo, xorinfo; 00222 CursorSeq[i].pAndMask->GetObject(sizeof(andinfo), &andinfo); 00223 CursorSeq[i].pXorMask->GetObject(sizeof(xorinfo), &xorinfo); 00224 ENSURE(andinfo.bmBitsPixel == 1 && andinfo.bmPlanes == 1 && 00225 xorinfo.bmBitsPixel == 1 && xorinfo.bmPlanes == 1, 00226 "Bitmaps in InitProgressCursor() are not monochrome!\n"); 00227 #endif // _DEBUG 00228 } 00229 00230 // Make two scratch bitmaps with the same size as cursors. These bitmaps are 00231 // monochrome, like standard Windows cursors. 00232 pAndBmp = new CBitmap; 00233 pXorBmp = new CBitmap; 00234 if (!pAndBmp || !pXorBmp || 00235 !pAndBmp->CreateBitmap(Cursor::Width(), Cursor::Height(), 1, 1, 0) || 00236 !pXorBmp->CreateBitmap(Cursor::Width(), Cursor::Height(), 1, 1, 0)) 00237 { 00238 if (IsUserName("JustinF")) 00239 TRACE( _T("Couldn't create scratch bitmaps in InitProgressCursor()!\n")); 00240 return FALSE; 00241 } 00242 00243 // Create a font to write the percentage text with. 00244 LOGFONT fontinfo; 00245 memset(&fontinfo, 0, sizeof(fontinfo)); // all fields zero means use default values 00246 fontinfo.lfCharSet = UnicodeManager::GetFontCharSet(); 00247 fontinfo.lfHeight = -Cursor::Width() / 3; 00248 00249 pCursorFont = new CFont; 00250 if (!pCursorFont || !pCursorFont->CreateFontIndirect(&fontinfo)) 00251 { 00252 if (IsUserName("JustinF")) 00253 TRACE( _T("Couldn't create font object in InitProgressCursor()!\n")); 00254 return FALSE; 00255 } 00256 00257 // Make a device context in memory which is compatible with the screen. 00258 pMemoryDC1 = new CDC; 00259 pMemoryDC2 = new CDC; 00260 if (!pMemoryDC1 || !pMemoryDC2 || 00261 !pMemoryDC1->CreateCompatibleDC(0) || 00262 !pMemoryDC2->CreateCompatibleDC(0)) 00263 { 00264 if (IsUserName("JustinF")) 00265 TRACE( _T("Couldn't create memory DC's in InitProgressCursor()!\n")); 00266 return FALSE; 00267 } 00268 00269 // Find out how large the font we created REALLY is, so we can calculate where within 00270 // the cursor we can write the text. 00271 TEXTMETRIC textinfo; 00272 CFont* pf = pMemoryDC1->SelectObject(pCursorFont); 00273 pMemoryDC1->GetTextMetrics(&textinfo); 00274 pMemoryDC1->SelectObject(pf); 00275 00276 // The text appears at the bottom of the cursor. Calculate its bounding rectangle, which 00277 // includes room for a two-pixel wide border 00278 TextRect.left = 0; 00279 TextRect.top = Cursor::Height() - textinfo.tmAscent; 00280 TextRect.right = Cursor::Width(); 00281 TextRect.bottom = Cursor::Height(); 00282 00283 // The mask bitmaps are stretched into the remaining square space. 00284 MaskRect.top = 0; 00285 MaskRect.bottom = Cursor::Height() - textinfo.tmHeight; 00286 MaskRect.left = Cursor::Width() / 2 - MaskRect.bottom / 2; 00287 MaskRect.right = Cursor::Width() / 2 + MaskRect.bottom / 2; 00288 00289 // Finally, set the animation to begin with the first frame and . . . success! 00290 CurrentFrame = 0; 00291 return TRUE; 00292 } 00293 00294 00295 00296 00297 00298 /******************************************************************************************** 00299 > Cursor* UpdateProgressCursor(INT32 percent) 00300 00301 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> (Messed around by Jason) 00302 Created: 19/11/93 00303 Inputs: percent - A value between 0% and 100% to be displayed under the pointer, OR 00304 -1 to indicate that no percentage should be displayed. 00305 Outputs: - 00306 Returns: A pointer to the new progress cursor object if successful, NULL otherwise. 00307 Purpose: (If percent >= 0 it draws the percentage text into the cursor masks and then) 00308 creates and sets a new cursor. 00309 Errors: - 00310 SeeAlso: InitProgressCursor; DeInitProgressCursor 00311 ********************************************************************************************/ 00312 00313 Cursor* UpdateProgressCursor(INT32 percent) 00314 { 00315 // Before we get too confused, the truth table for the combination of the 2 bitmaps is: 00316 // 00317 // ANDbmp XORbmp Result in cursor 00318 // Black Black Black 00319 // Black White White 00320 // White Black Transparent 00321 // White White Invert screen colour at this point 00322 // 00323 // First, we set AND/XOR to White/Black respectively so that the cursor is transparent... 00324 00325 CBitmap* poldbmp1 = pMemoryDC1->SelectObject(pAndBmp); 00326 pMemoryDC1->PatBlt(0, 0, Cursor::Width(), Cursor::Height(), WHITENESS); 00327 00328 CBitmap* poldbmp2 = pMemoryDC2->SelectObject(pXorBmp); 00329 pMemoryDC2->PatBlt(0, 0, Cursor::Width(), Cursor::Height(), BLACKNESS); 00330 00331 // Find out how large the mask bitmaps are (they are assumed to all be of the same size). 00332 BITMAP bmpinfo; 00333 CursorSeq[CurrentFrame].pAndMask->GetObject(sizeof(bmpinfo), &bmpinfo); 00334 00335 // Stretch the cursor masks for the current animation frame into the scratch bitmaps. 00336 // First the XOR mask, then the AND mask. 00337 pMemoryDC2->SelectObject(CursorSeq[CurrentFrame].pXorMask); // source 00338 pMemoryDC1->SelectObject(pXorBmp); // destination 00339 pMemoryDC1->StretchBlt(MaskRect.left, MaskRect.top, MaskRect.Width(), MaskRect.Height(), 00340 pMemoryDC2, 0, 0, bmpinfo.bmWidth, bmpinfo.bmHeight, SRCCOPY); 00341 00342 pMemoryDC2->SelectObject(CursorSeq[CurrentFrame].pAndMask); // source 00343 pMemoryDC1->SelectObject(pAndBmp); // destination 00344 pMemoryDC1->StretchBlt(MaskRect.left, MaskRect.top, MaskRect.Width(), MaskRect.Height(), 00345 pMemoryDC2, 0, 0, bmpinfo.bmWidth, bmpinfo.bmHeight, SRCCOPY); 00346 00347 if (percent >= 0) // Only display percentage text if 'percent' >= 0 00348 { 00349 // Next, write the percentage text inside the text rectangle. 00350 // We want this to be black text on a white rub-out box, so we plot black-on-white text 00351 // into the XOR bitmap, and black-on-black into the AND bitmap (rather than plotting a 00352 // rectangle, because we want the rub-out box to be only slightly bigger than the text 00353 // sitting upon it...) 00354 pMemoryDC1->SelectObject(pXorBmp); 00355 00356 pMemoryDC1->SetTextColor(RGB(0, 0, 0)); 00357 pMemoryDC1->SetBkColor(RGB(255, 255, 255)); 00358 00359 CFont *poldfont1 = pMemoryDC1->SelectObject(pCursorFont); 00360 TCHAR txt[8]; // Cache - percentage text 00361 INT32 numchars; // Cache - number of chars in the above %age text 00362 00363 String_32 jcf(_R(IDS_PERCENT_FORMAT)); 00364 numchars = ::wsprintf(txt, jcf, (INT32) percent); 00365 pMemoryDC1->DrawText(txt, numchars, &TextRect, 00366 DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOPREFIX); 00367 00368 pMemoryDC1->SelectObject(pAndBmp); 00369 pMemoryDC1->SetTextColor(RGB(0, 0, 0)); 00370 pMemoryDC1->SetBkColor(RGB(0, 0, 0)); 00371 00372 pMemoryDC1->DrawText(txt, numchars, &TextRect, 00373 DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOPREFIX); 00374 00375 pMemoryDC1->SelectObject(poldfont1); 00376 } 00377 00378 // Deselect the bitmaps. 00379 pMemoryDC1->SelectObject(poldbmp1); 00380 pMemoryDC2->SelectObject(poldbmp2); 00381 00382 // Finally, create and set the new cursor. 00383 Cursor* pnc = new Cursor(pAndBmp, pXorBmp); 00384 if (!pnc || !pnc->IsValid()) 00385 { 00386 if (IsUserName("JustinF")) 00387 TRACE( _T("Couldn't create new Cursor object in UpdateProgressCursor()!\n")); 00388 delete pnc; 00389 return 0; 00390 } 00391 00392 // Update the animation frame counter. 00393 if (++CurrentFrame >= nFrameCount) CurrentFrame = 0; 00394 return pnc; 00395 } 00396 00397 00398 00399 00400 00401 /******************************************************************************************** 00402 > void DeInitProgressCursor() 00403 00404 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00405 Created: 19/11/93 00406 Inputs: - 00407 Outputs: - 00408 Returns: - 00409 Purpose: Deallocates all objects created in InitProgressCursor() 00410 Errors: - 00411 SeeAlso: InitProgressCursor; UpdateProgressCursor 00412 ********************************************************************************************/ 00413 00414 void DeInitProgressCursor() 00415 { 00416 // Deallocate the mask bitmaps. 00417 for (INT32 i = 0; i < nFrameCount; i++) 00418 { 00419 CursorSeq[i].pAndMask->DeleteObject(); 00420 CursorSeq[i].pXorMask->DeleteObject(); 00421 delete CursorSeq[i].pAndMask; 00422 delete CursorSeq[i].pXorMask; 00423 } 00424 00425 // Destroy the other GDI objects. 00426 pMemoryDC1->DeleteDC(); 00427 delete pMemoryDC1; 00428 00429 pMemoryDC2->DeleteDC(); 00430 delete pMemoryDC2; 00431 00432 pAndBmp->DeleteObject(); 00433 delete pAndBmp; 00434 00435 pXorBmp->DeleteObject(); 00436 delete pXorBmp; 00437 00438 delete pCursorFont; 00439 } 00440 00441 00442 00443 00444 /******************************************************************************************** 00445 > BOOL BreakKeyHit() 00446 00447 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00448 Created: 18/11/93 00449 Inputs: - 00450 Outputs: - 00451 Returns: TRUE if the Escape key is pressed. 00452 Purpose: Checks if the user is trying to interrupt or cancel a task. 00453 Errors: - 00454 SeeAlso: ContinueSlowJob 00455 ********************************************************************************************/ 00456 00457 BOOL BreakKeyHit() 00458 { 00459 return KeyPress::IsEscapePressed(); 00460 /* 00461 if (::GetAsyncKeyState(CAMKEY(ESCAPE)) <0 ) 00462 { 00463 MSG msg; 00464 BOOL Again; 00465 // if Esc is pressed down, lets throw away all key messages otherwise the Esc is likely 00466 // to get passed on e.g. to the next dialog box 00467 do 00468 { 00469 Again = PeekMessage( &msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ); 00470 } while (Again); 00471 00472 return TRUE; 00473 } 00474 return FALSE; 00475 */ 00476 } 00477 00478 00479 00480 00481 /******************************************************************************************** 00482 00483 > void Beep() 00484 00485 Author: Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> 00486 Created: 19/11/93 00487 Inputs: - 00488 Outputs: - 00489 Returns: - 00490 Purpose: Makes a beep sound, stupid! 00491 Errors: - 00492 SeeAlso: BreakKeyHit; ContinueSlowJob 00493 00494 ********************************************************************************************/ 00495 00496 void Beep() 00497 { 00498 ::MessageBeep(MB_OK); 00499 }