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
33 Conditional upon your continuing compliance with the GNU General Public
34 License described above, Xara Group Ltd grants to you certain additional
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.
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
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).
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.
96 =================================XARAHEADEREND============================
99 // dropdown.cpp - Drop-down list base class
101 // >>>> See O:\camelot\docs\howtouse\DropDowns.doc for details of use <<<<
107 //-----------------------------------------------------------------------------------------
110 #include "camtypes.h"
113 #include "dropdown.h"
114 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
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 //-----------------------------------------------------------------------------------------
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
);
148 m_pDropDown
->HandleDrawItemInternal(dc
, rect
, item
, flags
, TRUE
);
151 wxCoord
wxCamVListBoxComboPopup::OnMeasureItem(size_t item
) const
154 dc
.SetFont( m_useFont
);
156 return m_pDropDown
->HandleDrawItemInternal(dc
, wxRect(-1, -1, -1, -1), item
, 0, FALSE
).GetHeight();
161 wxCoord
wxCamVListBoxComboPopup::OnMeasureItemWidth( size_t item
) const
164 dc
.SetFont( m_useFont
);
166 return m_pDropDown
->HandleDrawItemInternal(dc
, wxRect(-1, -1, -1, -1), item
, 0, FALSE
).GetWidth();
168 return -1; // default - will be measured from text width
173 /********************************************************************************************
175 > DropDown::DropDown()
177 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
180 Purpose: DropDown constructor
182 Notes: Follow this up with a call to Init()
184 SeeAlso: DropDown::Init; ColourDropDown; FontDropDown
186 ********************************************************************************************/
198 /********************************************************************************************
200 > virtual DropDown::~DropDown()
202 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
205 Purpose: DropDown destructor
207 ********************************************************************************************/
209 DropDown::~DropDown()
213 // Do any deinit here
218 /********************************************************************************************
220 > wxOwnerDrawnComboBox * DropDown::GetBox()
224 Returns: A pointer to the combo box
225 Purpose: Return the pointer to the combo box (once class is initialized) or NULL
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>
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
250 Purpose: DropDown initialiser
252 ********************************************************************************************/
254 BOOL
DropDown::Init(CWindowID Window
, CGadgetID Gadget
)
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);
270 ParentGadget
= Gadget
;
275 ERROR3("DropDown::Init failed - illegal Gadget");
280 // release all memory
286 CurrentDropDowns
.RemoveItem(this);
291 /********************************************************************************************
293 > static void DropDown::KillDropDownsByWindow(CWindowID Window)
295 Author: Alex Bligh <alex@alex.org.uk>
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();
310 DropDown
* Next
= (DropDown
*) CurrentDropDowns
.GetNext(Ptr
); // as we may remove this item from the list
311 if (Ptr
->Initialised
&& (Ptr
->ParentDlg
==Window
))
316 // Now process children if any
317 wxWindowList::Node
* pNode
= Window
->GetChildren().GetFirst();
320 KillDropDownsByWindow(pNode
->GetData());
321 pNode
= pNode
->GetNext();
327 /********************************************************************************************
329 > void DropDown::ClearList(void)
331 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
334 Purpose: Clears all items from the list
336 ********************************************************************************************/
338 void DropDown::ClearList(void)
340 wxOwnerDrawnComboBox
* pGadget
= GetBox();
348 /********************************************************************************************
350 > void DropDown::SetListRedraw(BOOL Enable)
352 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
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();
375 /********************************************************************************************
377 > void DropDown::AddItem(void * ItemData)
379 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
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
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();
396 INT32 n
=pGadget
->Append(wxEmptyString
); // put in an empty string first
397 m_pPopup
->SetItemClientData(n
, ItemData
, wxClientData_Void
);
399 pGadget
->SetString(n
, GetText(ItemData
, n
));
402 /********************************************************************************************
404 > void DropDown::DeleteItem(INT32 index)
406 Author: Martin Wuerthner <xara@mw-software.com>
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();
419 INT32 count
= (INT32
)pGadget
->GetCount();
420 if (index
>= 0 && index
< count
)
422 pGadget
->Delete(index
);
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>
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();
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>
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();
475 return m_pPopup
->GetItemClientData(ItemIndex
);
480 /********************************************************************************************
482 > INT32 DropDown::GetNumberOfItems(void)
484 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
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();
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>
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.
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
545 void * ItemData
= GetItemData(item
);
546 // Determine if it is a divider item
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;
553 wxPen OldPen
=dc
.GetPen();
554 dc
.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)));
555 dc
.DrawLine(Rect
.GetLeft(), midpoint
, Rect
.GetRight()+1, midpoint
);
558 return(wxSize(-1,5));
561 // If we aren't drawing, we should get the size of the text and return that appopriately modified
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;
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
;
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
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
611 DrawText(ItemData
, dc
, TextRect
, item
, flags
, TRUE
);
614 // Restore the DC's previous palette if we selected our one in
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>
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
)
655 /********************************************************************************************
657 > virtual BOOL DropDown::DrawIcon(void * ItemData, wxDC& dc, wxRect& IconRect, BOOL Disabled)
659 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
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
)
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>
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
)
727 if ( (m_pPopup
->wxVListBox::GetSelection() == (INT32
)item
) && !(flags
& wxODCB_PAINTING_CONTROL
) )
728 dc
.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
) );
730 dc
.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
) );
733 wxString Text
= GetText(ItemData
, item
);
735 dc
.GetTextExtent(Text
, &w
, &h
);
736 wxSize
size(w
,dc
.GetCharHeight());
739 dc
.DrawText( Text
, TextRect
.x
, TextRect
.y
);