Bugfix : Zooming works correct, no more errors on screen.
[xara-cairo.git] / wxOil / dropdown.cpp
blob316fcb49e5b84900882c07f5fb93d18709f59bcc
1 // $Id: dropdown.cpp 1412 2006-07-05 19:53:47Z alex $
2 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
3 ================================XARAHEADERSTART===========================
5 Xara LX, a vector drawing and manipulation program.
6 Copyright (C) 1993-2006 Xara Group Ltd.
7 Copyright on certain contributions may be held in joint with their
8 respective authors. See AUTHORS file for details.
10 LICENSE TO USE AND MODIFY SOFTWARE
11 ----------------------------------
13 This file is part of Xara LX.
15 Xara LX is free software; you can redistribute it and/or modify it
16 under the terms of the GNU General Public License version 2 as published
17 by the Free Software Foundation.
19 Xara LX and its component source files are distributed in the hope
20 that it will be useful, but WITHOUT ANY WARRANTY; without even the
21 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22 See the GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License along
25 with Xara LX (see the file GPL in the root directory of the
26 distribution); if not, write to the Free Software Foundation, Inc., 51
27 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 ADDITIONAL RIGHTS
31 -----------------
33 Conditional upon your continuing compliance with the GNU General Public
34 License described above, Xara Group Ltd grants to you certain additional
35 rights.
37 The additional rights are to use, modify, and distribute the software
38 together with the wxWidgets library, the wxXtra library, and the "CDraw"
39 library and any other such library that any version of Xara LX relased
40 by Xara Group Ltd requires in order to compile and execute, including
41 the static linking of that library to XaraLX. In the case of the
42 "CDraw" library, you may satisfy obligation under the GNU General Public
43 License to provide source code by providing a binary copy of the library
44 concerned and a copy of the license accompanying it.
46 Nothing in this section restricts any of the rights you have under
47 the GNU General Public License.
50 SCOPE OF LICENSE
51 ----------------
53 This license applies to this program (XaraLX) and its constituent source
54 files only, and does not necessarily apply to other Xara products which may
55 in part share the same code base, and are subject to their own licensing
56 terms.
58 This license does not apply to files in the wxXtra directory, which
59 are built into a separate library, and are subject to the wxWindows
60 license contained within that directory in the file "WXXTRA-LICENSE".
62 This license does not apply to the binary libraries (if any) within
63 the "libs" directory, which are subject to a separate license contained
64 within that directory in the file "LIBS-LICENSE".
67 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
68 ----------------------------------------------
70 Subject to the terms of the GNU Public License (see above), you are
71 free to do whatever you like with your modifications. However, you may
72 (at your option) wish contribute them to Xara's source tree. You can
73 find details of how to do this at:
74 http://www.xaraxtreme.org/developers/
76 Prior to contributing your modifications, you will need to complete our
77 contributor agreement. This can be found at:
78 http://www.xaraxtreme.org/developers/contribute/
80 Please note that Xara will not accept modifications which modify any of
81 the text between the start and end of this header (marked
82 XARAHEADERSTART and XARAHEADEREND).
85 MARKS
86 -----
88 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
89 designs are registered or unregistered trademarks, design-marks, and/or
90 service marks of Xara Group Ltd. All rights in these marks are reserved.
93 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
94 http://www.xara.com/
96 =================================XARAHEADEREND============================
99 // dropdown.cpp - Drop-down list base class
101 // >>>> See O:\camelot\docs\howtouse\DropDowns.doc for details of use <<<<
107 //-----------------------------------------------------------------------------------------
108 // Include files
110 #include "camtypes.h"
112 #include "camelot.h"
113 #include "dropdown.h"
114 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
115 #include "palman.h"
118 //-----------------------------------------------------------------------------------------
119 // Implementation of dynamic classes
121 CC_IMPLEMENT_DYNCREATE(DropDown, ListItem)
124 //-----------------------------------------------------------------------------------------
125 // This must be defined AFTER all CC_IMPLEMENT_DYNCREATE calls
126 #define new CAM_DEBUG_NEW
129 //-----------------------------------------------------------------------------------------
130 // Statics
132 List DropDown::CurrentDropDowns;
134 wxCamVListBoxComboPopup::wxCamVListBoxComboPopup(DropDown * pDropDown) :
135 wxVListBoxComboPopup(),
136 m_pDropDown(pDropDown)
140 wxCamVListBoxComboPopup::~wxCamVListBoxComboPopup()
144 void wxCamVListBoxComboPopup::OnDrawItem(wxDC& dc, const wxRect& rect, int /*TYPENOTE: CORRECT*/ item, int /*TYPENOTE: CORRECT*/ flags) const
146 dc.SetFont( m_useFont );
147 if (m_pDropDown)
148 m_pDropDown->HandleDrawItemInternal(dc, rect, item, flags, TRUE);
151 wxCoord wxCamVListBoxComboPopup::OnMeasureItem(size_t item) const
153 wxScreenDC dc;
154 dc.SetFont( m_useFont );
155 if (m_pDropDown)
156 return m_pDropDown->HandleDrawItemInternal(dc, wxRect(-1, -1, -1, -1), item, 0, FALSE).GetHeight();
157 else
158 return 24;
161 wxCoord wxCamVListBoxComboPopup::OnMeasureItemWidth( size_t item ) const
163 wxScreenDC dc;
164 dc.SetFont( m_useFont );
165 if (m_pDropDown)
166 return m_pDropDown->HandleDrawItemInternal(dc, wxRect(-1, -1, -1, -1), item, 0, FALSE).GetWidth();
167 else
168 return -1; // default - will be measured from text width
173 /********************************************************************************************
175 > DropDown::DropDown()
177 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
178 Date: 29/8/95
180 Purpose: DropDown constructor
182 Notes: Follow this up with a call to Init()
184 SeeAlso: DropDown::Init; ColourDropDown; FontDropDown
186 ********************************************************************************************/
188 DropDown::DropDown()
190 ParentDlg = NULL;
191 m_pPopup = NULL;
192 ParentGadget = 0;
193 Initialised = FALSE;
198 /********************************************************************************************
200 > virtual DropDown::~DropDown()
202 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
203 Date: 29/8/95
205 Purpose: DropDown destructor
207 ********************************************************************************************/
209 DropDown::~DropDown()
211 if (Initialised)
213 // Do any deinit here
214 Init(NULL, 0);
218 /********************************************************************************************
220 > wxOwnerDrawnComboBox * DropDown::GetBox()
222 Author: AlexBligh
223 Date: 13/05/2005
224 Returns: A pointer to the combo box
225 Purpose: Return the pointer to the combo box (once class is initialized) or NULL
226 on error
228 ********************************************************************************************/
230 wxOwnerDrawnComboBox * DropDown::GetBox()
232 wxWindow * pGadget = DialogManager::GetGadget(ParentDlg, ParentGadget);
233 ERROR2IF(!pGadget || !pGadget->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)), NULL, "Bad Dropdown Gadget");
234 return (wxOwnerDrawnComboBox *)pGadget;
237 /********************************************************************************************
239 > virtual BOOL DropDown::Init(CWindowID Window, CGadgetID Gadget)
241 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
242 Date: 29/8/95
244 Inputs: Window - The Window in which your dropdown list gadget resides or NULL to denitialise
245 Gadget - The GadgetID of the deropdown list gadget
247 Returns: TRUE if it succeeded in connecting itself to your gadget
248 FALSE if it failed
250 Purpose: DropDown initialiser
252 ********************************************************************************************/
254 BOOL DropDown::Init(CWindowID Window, CGadgetID Gadget)
256 if (Window)
258 wxWindow * pGadget = DialogManager::GetGadget(Window, Gadget);
259 if (pGadget && pGadget->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)))
261 if (!Initialised) // Only ever add myself to the list once
263 m_pPopup = new wxCamVListBoxComboPopup(this);
264 ERROR2IF(!m_pPopup, FALSE, "Could not get new list popup");
265 ((wxOwnerDrawnComboBox *)pGadget)->SetPopupControl(m_pPopup);
266 CurrentDropDowns.AddHead(this);
269 ParentDlg = Window;
270 ParentGadget = Gadget;
272 Initialised = TRUE;
273 return(TRUE);
275 ERROR3("DropDown::Init failed - illegal Gadget");
276 return(FALSE);
278 else
280 // release all memory
281 KillList();
282 ClearList();
283 ParentDlg=NULL;
284 ParentGadget=0;
285 Initialised=FALSE;
286 CurrentDropDowns.RemoveItem(this);
287 return TRUE;
291 /********************************************************************************************
293 > static void DropDown::KillDropDownsByWindow(CWindowID Window)
295 Author: Alex Bligh <alex@alex.org.uk>
296 Date: 15/05/2005
298 Purpose: Kills all the dropdowns associated with a particular window
299 This is called when that window is dying. We can't delete the dropdowns
300 but we can deinit them so they won't cause anyone eny hassle.
302 ********************************************************************************************/
304 void DropDown::KillDropDownsByWindow(CWindowID Window)
306 // First kill any associated with this window
307 DropDown *Ptr = (DropDown *) CurrentDropDowns.GetHead();
308 while (Ptr != NULL)
310 DropDown * Next = (DropDown *) CurrentDropDowns.GetNext(Ptr); // as we may remove this item from the list
311 if (Ptr->Initialised && (Ptr->ParentDlg==Window))
312 Ptr->Init(NULL, 0);
313 Ptr = Next;
316 // Now process children if any
317 wxWindowList::Node * pNode = Window->GetChildren().GetFirst();
318 while (pNode)
320 KillDropDownsByWindow(pNode->GetData());
321 pNode = pNode->GetNext();
323 return;
327 /********************************************************************************************
329 > void DropDown::ClearList(void)
331 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
332 Date: 13/9/95
334 Purpose: Clears all items from the list
336 ********************************************************************************************/
338 void DropDown::ClearList(void)
340 wxOwnerDrawnComboBox * pGadget = GetBox();
341 if (!pGadget)
342 return;
343 pGadget->Clear();
348 /********************************************************************************************
350 > void DropDown::SetListRedraw(BOOL Enable)
352 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
353 Date: 13/9/95
355 Inputs: Enable - TRUE to enable, FALSE to disable redraw
357 Purpose: Enables/Disables redraw of the combobox. Put around a sequence of calls
358 to AddItem to stop flickery redraws as you add items.
360 ********************************************************************************************/
362 void DropDown::SetListRedraw(BOOL Enable)
364 wxOwnerDrawnComboBox * pGadget = GetBox();
365 if (!pGadget)
366 return;
367 if (Enable)
368 pGadget->Thaw();
369 else
370 pGadget->Freeze();
375 /********************************************************************************************
377 > void DropDown::AddItem(void * ItemData)
379 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
380 Date: 13/9/95
382 Inputs: ItemData - A data value to associate with this item. This must be unique
383 so you can use this ItemData to determine how to redraw the item.
384 The value NULL is special: It puts a non-selectable divider line into
385 the list.
387 Purpose: Adds another item or divider to the end of the current list
389 ********************************************************************************************/
391 void DropDown::AddItem(void * ItemData)
393 wxOwnerDrawnComboBox * pGadget = GetBox();
394 if (!pGadget)
395 return;
396 INT32 n=pGadget->Append(wxEmptyString); // put in an empty string first
397 m_pPopup->SetItemClientData(n, ItemData, wxClientData_Void);
398 if (ItemData)
399 pGadget->SetString(n, GetText(ItemData, n));
402 /********************************************************************************************
404 > void DropDown::DeleteItem(INT32 index)
406 Author: Martin Wuerthner <xara@mw-software.com>
407 Date: 22/05/06
409 Inputs: index - the index of the item to be removed
410 Purpose: Removes an item from the list
412 ********************************************************************************************/
414 void DropDown::DeleteItem(INT32 index)
416 wxOwnerDrawnComboBox * pGadget = GetBox();
417 if (!pGadget)
418 return;
419 INT32 count = (INT32)pGadget->GetCount();
420 if (index >= 0 && index < count)
422 pGadget->Delete(index);
424 else
426 ERROR3("DropDown::RemoveItem - attempt to delete non-existing item");
430 /********************************************************************************************
432 > void DropDown::SetSelectedIndex(INT32 SelectedIndex)
434 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
435 Date: 13/9/95
437 Inputs: SelectedIndex - the index (0 based) of the item in the drop list
439 Purpose: Sets the index of the selected item in the list.
440 Take care never to set a divider as the selected item (it'll work,
441 but it's a silly item to have selected!)
443 ********************************************************************************************/
445 void DropDown::SetSelectedIndex(INT32 SelectedIndex)
447 wxOwnerDrawnComboBox * pGadget = GetBox();
448 if (!pGadget)
449 return;
450 pGadget->SetSelection(SelectedIndex); // And set the appropriate selected item
454 /********************************************************************************************
456 > void * DropDown::GetItemData(INT32 ItemIndex)
458 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
459 Date: 13/9/95
461 Inputs: ItemIndex - the index (0 based) of the item in the drop list (e.g. as
462 given to you by GetSelectedValueIndex() on DIM_SELECTION_CHANGED)
464 Returns: NULL, or the data word held in the indexed item
466 Purpose: Retrieves the data for a given item in the list
468 ********************************************************************************************/
470 void * DropDown::GetItemData(INT32 ItemIndex)
472 wxOwnerDrawnComboBox * pGadget = GetBox();
473 if (!pGadget)
474 return NULL;
475 return m_pPopup->GetItemClientData(ItemIndex);
480 /********************************************************************************************
482 > INT32 DropDown::GetNumberOfItems(void)
484 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
485 Date: 13/9/95
487 Returns: A count of how many items are in the list.
488 Indexes in the list will go from 0 to GetNumberOfItems()-1
490 Purpose: Determines the number of items in the list
492 ********************************************************************************************/
494 INT32 DropDown::GetNumberOfItems(void)
496 wxOwnerDrawnComboBox * pGadget = GetBox();
497 if (!pGadget)
498 return 0;
499 return((INT32)pGadget->GetCount());
504 /********************************************************************************************
506 > virtual BOOL DropDown::HandleDrawItemInternal(CWindowID hDlg, UINT32 wParam, INT32 lParam)
508 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
509 Date: 29/8/95
511 Inputs: hDlg - The CWindowID of the control which needs redrawing
512 wParam, lParam - As for the WM_DRAWITEM message
514 Returns: TRUE if it handled (claimed) the message
515 FALSE if it did not handle the message
517 Purpose: Handles redraw of items in a DropDown control
519 Notes: Called by HandleDrawItem when this object has been identified as the owner
520 of the control to be redrawn.
522 This method should only be overridden in extreme circumstances
524 If the item data for this item is NULL, then a divider line will be drawn.
525 Otherwise, your derived DrawIcon and DrawText methods will be called.
527 Scope: private
529 SeeAlso: DropDown::HasIcon; DropDown::DrawIcon; DropDown::DrawText
531 ********************************************************************************************/
533 wxSize DropDown::HandleDrawItemInternal(wxDC& dc, const wxRect& Rect, INT32 item, INT32 flags, BOOL Draw)
535 const INT32 border = 2;
537 if (CCamApp::IsDisabled()) // Inside an error handler
538 return(wxDefaultSize);
540 wxOwnerDrawnComboBox * pGadget = GetBox();
542 // if ((INT32)pInfo->itemID == -1 || (INT32)pInfo->itemData == -1) // Draw item -1: just exit
543 // return(FALSE);
545 void * ItemData = GetItemData(item);
546 // Determine if it is a divider item
547 if (!ItemData)
549 // It's a divider, so draw it specially - it is a simple black line across the center of the rectangle
550 wxCoord midpoint = Rect.GetTop()+Rect.GetHeight()/2;
551 if (Draw)
553 wxPen OldPen=dc.GetPen();
554 dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)));
555 dc.DrawLine(Rect.GetLeft(), midpoint, Rect.GetRight()+1, midpoint);
556 dc.SetPen(OldPen);
558 return(wxSize(-1,5));
561 // If we aren't drawing, we should get the size of the text and return that appopriately modified
562 if (!Draw)
564 // Call the derived class
565 wxRect def(-1,-1,-1,-1);
566 wxSize TextSize = DrawText(ItemData, dc, def, item, flags, FALSE); // Rect is unused here as Draw is FALSE
567 TextSize.x+=2*border;
568 TextSize.y+=2*border; // This gives us the bounding rect as we leave some space around it
569 if (HasIcon(ItemData))
571 // There is an icon. It's width is equal to the text height less 2 (deflated in both
572 // directions. There is also a 6 pixel space
573 TextSize.x += (TextSize.y-2)+6;
575 return TextSize;
578 wxRect rect=Rect;
579 rect.Deflate(border);
581 // Calculate where the colour splodge (if any) will go (also used to shift text to the right later)
582 wxRect IconRect=rect;
583 IconRect.Deflate(1);
584 IconRect.SetWidth(IconRect.GetHeight());
586 wxRect TextRect=rect;
588 wxPalette * OldPal = NULL;
590 // If it's a special item with a colour splodge, or a normal colour item, draw the colour splodge
591 if (HasIcon(ItemData))
593 if (PaletteManager::UsePalette())
594 OldPal = PaletteManager::StartPaintPalette(&dc);
596 // Call the derived class to draw the icon
597 if (Draw)
598 DrawIcon(ItemData, dc, IconRect, !pGadget->IsEnabled(), flags);
600 // Shift the text to the right of the icon
601 INT32 shift=IconRect.GetWidth()+6;
602 TextRect.Offset(shift,0);
603 INT32 NewWidth=TextRect.GetWidth()-shift;
604 TextRect.SetWidth(NewWidth<1?1:NewWidth);
607 if (TextRect.GetWidth()>1) // if there's room to draw any text, draw it
609 // Call derived class to draw the text
610 if (Draw)
611 DrawText(ItemData, dc, TextRect, item, flags, TRUE);
614 // Restore the DC's previous palette if we selected our one in
615 if (OldPal)
616 PaletteManager::StopPaintPalette(&dc, OldPal);
618 return(wxDefaultSize);
623 /********************************************************************************************
625 > virtual BOOL DropDown::HasIcon(void * ItemData)
627 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
628 Date: 13/9/95
630 Inputs: ItemData - Your item data
632 Returns: TRUE if this item needs an icon to the left of it, FALSE if not
634 Purpose: Determine if an item needs an icon next to it
636 Notes: Called by HandleDrawItemInternal when this object has been identified as the
637 owner of the control to be redrawn.
639 This method MUST be overridden by derived classes to provide redraw of their
640 dropdown list items. The base class returns FALSE
642 If you return TRUE, you must also provide the DrawIcon method
644 SeeAlso: DropDown::DrawIcon; DropDown::DrawText
646 ********************************************************************************************/
648 BOOL DropDown::HasIcon(void * ItemData)
650 return(FALSE);
655 /********************************************************************************************
657 > virtual BOOL DropDown::DrawIcon(void * ItemData, wxDC& dc, wxRect& IconRect, BOOL Disabled)
659 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
660 Date: 13/9/95
662 Inputs: ItemData - Your item data
663 dc - The DC to render into
664 IconRect - points at a rectangle (square in fact) to be drawn within
665 Disabled - TRUE if the item is disabled so should be drawn greyed
667 Returns: TRUE if this item needs an icon to the left of it, FALSE if not
669 Purpose: Draws the icon for an item
671 Notes: Called by HandleDrawItemInternal when this object has been identified as the
672 owner of the control to be redrawn - ONLY called if HasIcon returned TRUE
674 This method MUST be overridden by derived classes to provide redraw of their
675 dropdown list items. The base class does nothing.
677 On entry, the DC is ready for you to draw into, including having the camelot
678 palette selected in etc.
680 SeeAlso: DropDown::HasIcon; DropDown::DrawText; ColourDropDown::DrawIcon
682 ********************************************************************************************/
684 BOOL DropDown::DrawIcon(void * ItemData, wxDC& dc, wxRect& IconRect, BOOL Disabled, INT32 flags)
686 return(TRUE);
691 /********************************************************************************************
693 > virtual wxSize DropDown::DrawText(void * ItemData, wxDC& dc, wxRect& TextRect, INT32 Item, INT32 flags, BOOL Draw)
695 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
696 Date: 13/9/95
698 Inputs: ItemData - Your item data
699 wxDC& - the DC to draw into
700 TextRect - points at a rectangle in which the text should be rendered
701 Item - the index of the item
702 flags - the flags sent to OnDrawItem
703 Draw - TRUE to Draw, FALSE to just get a size
705 Returns: The size of the text
707 Purpose: Draws the text for an item
709 Notes: Called by HandleDrawItemInternal when this object has been identified as the
710 owner of the control to be redrawn, if HasIcon returned TRUE
712 This method MUST be overridden by derived classes to provide redraw of their
713 dropdown list items. The base class draws nothing.
715 Note that on entry, the text FG/BG colours have been set up appropriately
716 for the state of the item (shaded, selected, etc)
717 Basically, all you have to do is find the text and do a DrawText call.
719 SeeAlso: DropDown::DrawIcon; DropDown::DrawIcon; ColourDropDown::DrawText
721 ********************************************************************************************/
723 wxSize DropDown::DrawText(void * ItemData, wxDC& dc, wxRect& TextRect, INT32 item, INT32 flags, BOOL Draw)
725 if (Draw)
727 if ( (m_pPopup->wxVListBox::GetSelection() == (INT32)item) && !(flags & wxODCB_PAINTING_CONTROL) )
728 dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) );
729 else
730 dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) );
733 wxString Text = GetText(ItemData, item);
734 wxCoord w, h;
735 dc.GetTextExtent(Text, &w, &h);
736 wxSize size(w,dc.GetCharHeight());
738 if (Draw)
739 dc.DrawText( Text, TextRect.x, TextRect.y );
741 return size;