00001 // $Id: coldrop.cpp 1052 2006-05-15 14:19:14Z 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 // coldrop.cpp - Colour drop-down list support 00100 00101 /* 00102 */ 00103 00104 00105 //----------------------------------------------------------------------------------------- 00106 // Include files 00107 00108 #include "camtypes.h" 00109 #include "camelot.h" 00110 #include "errors.h" 00111 #include "palman.h" 00112 #include "cartprov.h" 00113 00114 #include "bitmapdropdown.h" 00115 00116 00117 00118 00119 CC_IMPLEMENT_DYNCREATE(CBitmapDropDown, ListItem); 00120 00121 00122 00123 //----------------------------------------------------------------------------------------- 00124 // This must be defined AFTER all CC_IMPLEMENT_DYNCREATE calls 00125 #define new CAM_DEBUG_NEW 00126 00127 00128 CBDDItemInfo::CBDDItemInfo() 00129 { 00130 m_uiBitmapResID = (UINT32)-1; 00131 } 00132 00133 00134 CBDDItemInfo::CBDDItemInfo(UINT32 uiBitmapResID, String_256 strText) 00135 { 00136 m_uiBitmapResID = uiBitmapResID; 00137 m_bHasText = strText.IsEmpty(); 00138 00139 if (m_bHasText) 00140 m_strText = strText; 00141 else 00142 { 00143 // Workaround the DropDown feature - it distinguish the items by 00144 // their names (so we can't select items with empty text. 00145 static UINT32 s_iDummy = 0; 00146 m_strText._MakeMsg(_T("%d"), ++s_iDummy); 00147 } 00148 } 00149 00150 const CBDDItemInfo& CBDDItemInfo::operator=(const CBDDItemInfo& rOther) 00151 { 00152 m_uiBitmapResID = rOther.m_uiBitmapResID; 00153 m_bHasText = rOther.m_bHasText; 00154 m_strText = rOther.m_strText; 00155 00156 return *this; 00157 } 00158 00159 UINT32 CBDDItemInfo::GetBitmapID() 00160 { 00161 return m_uiBitmapResID; 00162 } 00163 00164 String_256 CBDDItemInfo::GetText() 00165 { 00166 return m_strText; 00167 } 00168 00169 BOOL CBDDItemInfo::HasText() 00170 { 00171 return m_bHasText; 00172 } 00173 00174 00175 00176 00177 00178 00179 00180 00181 00182 00183 00184 /****************************************************************************** 00185 Function : wxCamBitmapDropdownPopup::PaintComboControl 00186 Author : Mikhail Tatarnikov 00187 Purpose : Paints the currently selected item into the control itself (not to the dropdown list) 00188 Returns : void 00189 Exceptions: 00190 Parameters: [in] wxDC& dc - context to draw to; 00191 [in] const wxRect& rect - the item size. 00192 Notes : The default behaivour is to leave the control blank if no item is selected. 00193 ******************************************************************************/ 00194 void wxCamBitmapDropdownPopup::PaintComboControl(wxDC& dc, const wxRect& rect) 00195 { 00196 if (!(m_combo->GetWindowStyle() & wxODCB_STD_CONTROL_PAINT)) 00197 { 00198 // m_combo->DrawFocusBackground(dc,rect,0); 00199 00200 // Draw the control regardless whether it has an item selected or not. 00201 OnDrawItem(dc, rect, m_value, wxODCB_PAINTING_CONTROL); 00202 00203 return; 00204 } 00205 00206 wxComboPopup::PaintComboControl(dc,rect); 00207 } 00208 00209 /****************************************************************************** 00210 Function : wxCamBitmapDropdownPopup::GetAdjustedSize 00211 Author : Mikhail Tatarnikov 00212 Purpose : Calculates the dropdown list size 00213 Returns : wxSize - the popup list size. 00214 Exceptions: 00215 Parameters: [in] INT32 minWidth - minimum width; in the current implemetation it's the 00216 size of combobox control itself. In this function we 00217 ignore it; 00218 [in] int prefHeight - the preffered height; TYPENOTE: Correct 00219 [in] int maxHeight - maximum allowed height. TYPENOTE: Correct 00220 Notes : 00221 ******************************************************************************/ 00222 wxSize wxCamBitmapDropdownPopup::GetAdjustedSize(int /* TYPENOTE: Correct */ minWidth, int /* TYPENOTE: Correct */ prefHeight, int /* TYPENOTE: Correct */ maxHeight) 00223 { 00224 // We should ignore the min width, since it's usually the size of the combobox 00225 // (we can have a dropdown with width less than the control). 00226 00227 INT32 height = 250; 00228 BOOL bNeedScrollbar = FALSE; 00229 00230 if ( m_strings.GetCount() ) 00231 { 00232 if ( prefHeight > 0 ) 00233 height = prefHeight; 00234 00235 if ( height > maxHeight ) 00236 height = maxHeight; 00237 00238 INT32 totalHeight = GetTotalHeight(); // + 3; 00239 if ( height >= totalHeight ) 00240 { 00241 height = totalHeight; 00242 } 00243 else 00244 { 00245 // Adjust height to a multiple of the height of the first item 00246 // NB: Calculations that take variable height into account 00247 // are unnecessary. 00248 INT32 fih = GetLineHeight(0); 00249 INT32 shown = height/fih; 00250 height = shown * fih; 00251 00252 bNeedScrollbar = TRUE; 00253 } 00254 } 00255 else 00256 height = 50; 00257 00258 // Take scrollbar into account in width calculations 00259 INT32 iWidth = GetWidestItemWidth(); 00260 if (bNeedScrollbar) 00261 iWidth += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); 00262 // INT32 widestWidth = m_widestWidth + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); 00263 00264 return wxSize(iWidth, height+2); 00265 } 00266 00267 00268 CBitmapDropDown::CBitmapDropDown() 00269 { 00270 } 00271 00272 00273 00274 CBitmapDropDown::~CBitmapDropDown() 00275 { 00276 } 00277 00278 00279 00280 00281 /****************************************************************************** 00282 Function : CBitmapDropDown::AddItem 00283 Author : Mikhail Tatarnikov 00284 Purpose : Adds a new item (icon + text) 00285 Returns : void 00286 Exceptions: 00287 Parameters: [in] UINT32 uiBitmapResID - bitmap resource for the item; 00288 [in] String_256 strText - item label. 00289 Notes : 00290 ******************************************************************************/ 00291 void CBitmapDropDown::AddItem(UINT32 uiBitmapResID, String_256 strText) 00292 { 00293 m_vecItems.push_back(CBDDItemInfo(uiBitmapResID, strText)); 00294 00295 // Get the point to the last stored 00296 CBDDItemInfo* poItem = &(m_vecItems[m_vecItems.size() - 1]); 00297 DropDown::AddItem((void*)poItem); 00298 00299 SetSelectedIndex(0); 00300 } 00301 00302 /****************************************************************************** 00303 Function : CBitmapDropDown::AddDivider 00304 Author : Mikhail Tatarnikov 00305 Purpose : Add a divider 00306 Returns : void 00307 Exceptions: 00308 Parameters: None 00309 Notes : 00310 ******************************************************************************/ 00311 void CBitmapDropDown::AddDivider() 00312 { 00313 DropDown::AddItem(NULL); 00314 } 00315 00316 /****************************************************************************** 00317 Function : CBitmapDropDown::DeleteItem 00318 Author : Mikhail Tatarnikov 00319 Purpose : Removes an item from dropdown 00320 Returns : void 00321 Exceptions: 00322 Parameters: [in] INT32 iIndex - index of an item to be removed. 00323 Notes : 00324 ******************************************************************************/ 00325 void CBitmapDropDown::DeleteItem(INT32 iIndex) 00326 { 00327 ASSERT(FALSE); // Not implemented yet. 00328 } 00329 00330 00331 /****************************************************************************** 00332 Function : CBitmapDropDown::GetItemData 00333 Author : Mikhail Tatarnikov 00334 Purpose : Obtains the data for an item. 00335 Returns : void* - the pointer to the data. 00336 Exceptions: 00337 Parameters: [in] INT32 iItemIndex - item index to get data for. 00338 Notes : Since the information is stored in the internal array (not in the combobox 00339 itself), we need to override the default behaivour. 00340 ******************************************************************************/ 00341 void* CBitmapDropDown::GetItemData(INT32 iItemIndex) 00342 { 00343 // Check if we are requested information about "unselected" item. 00344 if (iItemIndex < 0) 00345 return (void*)(&m_oUnselectedItemInfo); 00346 00347 // The normal items are stored in the items collection. 00348 CBDDItemInfo* poItem = &(m_vecItems[iItemIndex]); 00349 00350 return (void*)poItem; 00351 } 00352 00353 00354 /****************************************************************************** 00355 Function : CBitmapDropDown::HasIcon 00356 Author : Mikhail Tatarnikov 00357 Purpose : Determines if the item (represented by its data) has an icon 00358 Returns : BOOL - TRUE if icon was supplied for the item, FALSE otherwise. 00359 Exceptions: 00360 Parameters: [in] void* pvItemData - the item data. 00361 Notes : 00362 ******************************************************************************/ 00363 BOOL CBitmapDropDown::HasIcon(void* pvItemData) 00364 { 00365 CBDDItemInfo* pItemInfo = reinterpret_cast<CBDDItemInfo*>(pvItemData); 00366 if (pItemInfo->GetBitmapID() != (UINT32)-1) 00367 return TRUE; 00368 00369 return FALSE; 00370 } 00371 00372 /****************************************************************************** 00373 Function : CBitmapDropDown::HasText 00374 Author : Mikhail Tatarnikov 00375 Purpose : Determines whether an item has text label 00376 Returns : BOOL - TRUE if text was supplied for the item, FALSE otherwise. 00377 Exceptions: 00378 Parameters: [in] void* pvItemData - the item data. 00379 Notes : 00380 ******************************************************************************/ 00381 BOOL CBitmapDropDown::HasText(void* pvItemData) 00382 { 00383 CBDDItemInfo* pItemInfo = reinterpret_cast<CBDDItemInfo*>(pvItemData); 00384 return pItemInfo->HasText(); 00385 } 00386 00387 00388 /****************************************************************************** 00389 Function : CBitmapDropDown::GetText 00390 Author : Mikhail Tatarnikov 00391 Purpose : Obtains label for the item. 00392 Returns : wxString - 00393 Exceptions: 00394 Parameters: [in] void* pvItemData - the item data; 00395 [in] INT32 iItem - the item index. 00396 Notes : 00397 ******************************************************************************/ 00398 wxString CBitmapDropDown::GetText(void* pvItemData, INT32 iItem) 00399 { 00400 if (!pvItemData) 00401 return DropDown::GetText(pvItemData, iItem); 00402 00403 CBDDItemInfo* pItemInfo = reinterpret_cast<CBDDItemInfo*>(pvItemData); 00404 00405 return pItemInfo->GetText(); 00406 } 00407 00408 00409 00410 /****************************************************************************** 00411 Function : CBitmapDropDown::Init 00412 Author : Mikhail Tatarnikov 00413 Purpose : Initialize the control 00414 Returns : BOOL - TRUE if success, FALSE otherwise. 00415 Exceptions: 00416 Parameters: [in] CWindowID Window - the parent window, NULL to deinitialize; 00417 [in] CGadgetID Gadget - the control ID. 00418 Notes : 00419 ******************************************************************************/ 00420 BOOL CBitmapDropDown::Init(CWindowID Window, CGadgetID Gadget) 00421 { 00422 if (Window) 00423 { 00424 // Obtain the gadget and check if it has an appropriate class (we can 00425 // be attached to owner-draw combobox obly). 00426 wxWindow * pGadget = DialogManager::GetGadget(Window, Gadget); 00427 if (pGadget && pGadget->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox))) 00428 { 00429 if (!Initialised) // Only ever add myself to the list once 00430 { 00431 m_pPopup = new wxCamBitmapDropdownPopup(this); 00432 ERROR2IF(!m_pPopup, FALSE, "Could not get new list popup"); 00433 ((wxOwnerDrawnComboBox *)pGadget)->SetPopupControl(m_pPopup); 00434 CurrentDropDowns.AddHead(this); 00435 } 00436 00437 ParentDlg = Window; 00438 ParentGadget = Gadget; 00439 00440 Initialised = TRUE; 00441 return(TRUE); 00442 } 00443 ERROR3("CBitmapDropDown::Init failed - illegal Gadget"); 00444 return(FALSE); 00445 } 00446 else 00447 { 00448 // release all memory 00449 KillList(); 00450 ClearList(); 00451 ParentDlg=NULL; 00452 ParentGadget=0; 00453 Initialised=FALSE; 00454 CurrentDropDowns.RemoveItem(this); 00455 return TRUE; 00456 } 00457 } 00458 00459 00460 /****************************************************************************** 00461 Function : CBitmapDropDown::HandleDrawItemInternal 00462 Author : Mikhail Tatarnikov 00463 Purpose : Handles items drawing 00464 Returns : wxSize - the size of the item. 00465 Exceptions: 00466 Parameters: [in] wxDC& dc - device context to draw to; 00467 [in] const wxRect& Rect - the clipping area for the item; 00468 [in] INT32 item - item index; 00469 [in] INT32 flags - flags (see odcombo.h, the only specified flag at the 00470 moment of writing is wxCP_PAINTING_CONTROL); 00471 [in] BOOL Draw - TRUE if we should draw, FALSE in case of size measurement. 00472 Notes : 00473 ******************************************************************************/ 00474 wxSize CBitmapDropDown::HandleDrawItemInternal(wxDC& dc, const wxRect& Rect, INT32 item, INT32 flags, BOOL Draw) 00475 { 00476 const INT32 ciBorderSize = 2; 00477 const INT32 ciInterval = 6; 00478 00479 00480 if (CCamApp::IsDisabled()) // Inside an error handler 00481 return (wxDefaultSize); 00482 00483 // wxOwnerDrawnComboBox* pGadget = GetBox(); 00484 00485 // if ((INT32)pInfo->itemID == -1 || (INT32)pInfo->itemData == -1) // Draw item -1: just exit 00486 // return(FALSE); 00487 00488 void* pvItemData = GetItemData(item); 00489 00490 // Determine if it is a divider item 00491 if (!pvItemData) 00492 { 00493 // It's a divider, so draw it specially - it is a simple black line across the center of the rectangle 00494 if (Draw) 00495 { 00496 wxCoord midpoint = Rect.GetTop()+Rect.GetHeight()/2; 00497 wxPen OldPen=dc.GetPen(); 00498 dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT))); 00499 dc.DrawLine(Rect.GetLeft(), midpoint, Rect.GetRight()+1, midpoint); 00500 dc.SetPen(OldPen); 00501 } 00502 return(wxSize(-1,5)); 00503 } 00504 00505 // CBDDItemInfo* pItemInfo = reinterpret_cast<CBDDItemInfo*>(pvItemData); 00506 00507 if (!Draw) 00508 { 00509 // The item height is the icon height, if any. We don't shrink the icon. 00510 // If there's no icon, the height is the text height. 00511 wxRect rcDummy(-1, -1, -1, -1); 00512 00513 // Obtain the icon size. 00514 wxSize szIcon(0, 0); 00515 if (HasIcon(pvItemData)) 00516 szIcon = DrawIcon(dc, rcDummy, item, flags, FALSE); 00517 00518 // Obtain the text size. 00519 wxSize szText(0, 0); 00520 if (HasText(pvItemData)) 00521 szText = DrawText(pvItemData, dc, rcDummy, item, flags, FALSE); 00522 00523 wxSize szItem; 00524 szItem.y = max(szText.y, szIcon.y); 00525 szItem.x = szIcon.x + szText.x; 00526 00527 // If both text and icon exist, there should be an interval between them 00528 if (HasIcon(pvItemData) && HasText(pvItemData)) 00529 szItem.x += ciInterval; 00530 00531 // Add a border. 00532 szItem.x += 2*ciBorderSize; 00533 szItem.y += 2*ciBorderSize; 00534 00535 return szItem; 00536 } 00537 00538 00539 00540 wxRect rcTemp = Rect; 00541 rcTemp.Deflate(ciBorderSize); 00542 00543 wxPalette* popalOld = NULL; 00544 00545 // Draw the icon, if any. 00546 if (HasIcon(pvItemData)) 00547 { 00548 if (PaletteManager::UsePalette()) 00549 popalOld = PaletteManager::StartPaintPalette(&dc); 00550 00551 wxSize szIcon = DrawIcon(dc, rcTemp, item, flags, TRUE); 00552 00553 // Calculate the text size. 00554 INT32 iShift = szIcon.x + ciInterval; 00555 rcTemp.Offset(iShift, 0); 00556 00557 INT32 iNewWidth = rcTemp.GetWidth() - ciInterval; 00558 rcTemp.SetWidth(iNewWidth < 1 ? 1 : iNewWidth); 00559 } 00560 00561 00562 00563 if (HasText(pvItemData)) 00564 DrawText(pvItemData, dc, rcTemp, item, flags, TRUE); 00565 00566 // Restore the DC's previous palette if we selected our one in 00567 if (popalOld) 00568 PaletteManager::StopPaintPalette(&dc, popalOld); 00569 00570 return(wxDefaultSize); 00571 } 00572 00573 00574 /****************************************************************************** 00575 Function : CBitmapDropDown::DrawIcon 00576 Author : Mikhail Tatarnikov 00577 Purpose : Draws item icon 00578 Returns : wxSize - the icon size 00579 Exceptions: 00580 Parameters: [in] wxDC& dc - device context to draw to; 00581 [in] const wxRect& Rect - the clipping area for the item; 00582 [in] INT32 item - item index; 00583 [in] INT32 flags - flags (see odcombo.h, the only specified flag at the 00584 moment of writing is wxCP_PAINTING_CONTROL); 00585 [in] BOOL Draw - TRUE if we should draw, FALSE in case of size measurement. 00586 Notes : 00587 ******************************************************************************/ 00588 wxSize CBitmapDropDown::DrawIcon(wxDC& dc, const wxRect& rcIcon, INT32 item, INT32 flags, BOOL Draw) 00589 { 00590 // wxBitmap * pBitmap = CamArtProvider::Get()->FindBitmap(BitmapID, (CamArtFlags)(CAF_DEFAUL T| (Disabled?CAF_GREYED:0))); 00591 wxSize szBitmap(0, 0); 00592 00593 void* pvItemData = GetItemData(item); 00594 CBDDItemInfo* pItemInfo = reinterpret_cast<CBDDItemInfo*>(pvItemData); 00595 00596 wxBitmap* pBitmap = CamArtProvider::Get()->FindBitmap(pItemInfo->GetBitmapID(), CAF_DEFAULT); 00597 if (!pBitmap) 00598 return szBitmap; 00599 00600 szBitmap.x = pBitmap->GetWidth(); 00601 szBitmap.y = pBitmap->GetHeight(); 00602 00603 if (Draw) 00604 { 00605 dc.DrawBitmap(*pBitmap, rcIcon.GetLeft(), rcIcon.GetTop(), TRUE); 00606 /* 00607 // Calculate the destination bitmap size (the bitmap can be bigger than the draw rect, so 00608 // we need to shrink it. 00609 wxSize szDestination; 00610 szDestination.x = min(szBitmap.x, rcIcon.GetWidth()); 00611 szDestination.y = min(szBitmap.y, rcIcon.GetHeight()); 00612 00613 wxMemoryDC dcMem; 00614 dcMem.SelectObject(*pBitmap); 00615 00616 dc.Blit(rcIcon.GetLeft(), rcIcon.GetTop(), szDestination.x, szDestination.y, &dcMem, 0, 0); 00617 */ 00618 } 00619 return szBitmap; 00620 } 00621 00622 00623 /****************************************************************************** 00624 Function : CBitmapDropDown::SetUnselectedIntem 00625 Author : Mikhail Tatarnikov 00626 Purpose : Sets the information for "unselected item" 00627 Returns : void 00628 Exceptions: 00629 Parameters: [in] UINT32 uiBitmapID - the "unselected" item bitmap; 00630 [in] String_256 strText - label for the item. 00631 Notes : These bitmap and label will be drawn when no item is selected 00632 (by default nothing is drawn) 00633 ******************************************************************************/ 00634 void CBitmapDropDown::SetUnselectedIntem(UINT32 uiBitmapID, String_256 strText) 00635 { 00636 m_oUnselectedItemInfo = CBDDItemInfo(uiBitmapID, strText); 00637 } 00638