1. the main function for item insertion is now DoInsertItems() which allows for much more efficient addition of many new items at once 2. the items client data management is done entirely in wxItemContainer itself, the derived classes don't have to distinguish between void and object client data 3. many fixes for sorted controls, in particular implemented wxCB_SORT support in wxGTK combobox git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@47730 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
432 lines
12 KiB
C++
432 lines
12 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/os2/checklst.cpp
|
|
// Purpose: implementation of wxCheckListBox class
|
|
// Author: David Webster
|
|
// Modified by:
|
|
// Created: 10/13/99
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) David Webster
|
|
// Licence: wxWindows licence
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ============================================================================
|
|
// headers & declarations
|
|
// ============================================================================
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#if wxUSE_CHECKLISTBOX && wxUSE_OWNER_DRAWN
|
|
|
|
#include "wx/checklst.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/object.h"
|
|
#include "wx/log.h"
|
|
#include "wx/window.h"
|
|
#include "wx/dcmemory.h"
|
|
#include "wx/dcscreen.h"
|
|
#include "wx/settings.h"
|
|
#include "wx/listbox.h"
|
|
#include "wx/bitmap.h"
|
|
#include "wx/colour.h"
|
|
#include "wx/font.h"
|
|
#endif
|
|
|
|
#include "wx/ownerdrw.h"
|
|
|
|
#define INCL_PM
|
|
#include <os2.h>
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// private functions
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// get item (converted to right type)
|
|
#define GetItem(n) ((wxCheckListBoxItem *)(GetItem(n)))
|
|
|
|
// ============================================================================
|
|
// implementation
|
|
// ============================================================================
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxCheckListBox, wxListBox)
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// declaration and implementation of wxCheckListBoxItem class
|
|
// ----------------------------------------------------------------------------
|
|
|
|
class wxCheckListBoxItem : public wxOwnerDrawn
|
|
{
|
|
friend class wxCheckListBox;
|
|
public:
|
|
//
|
|
// ctor
|
|
//
|
|
wxCheckListBoxItem(wxCheckListBox* pParent, size_t nIndex);
|
|
|
|
//
|
|
// Drawing functions
|
|
//
|
|
virtual bool OnDrawItem( wxDC& rDc,
|
|
const wxRect& rRect,
|
|
wxODAction eAct,
|
|
wxODStatus eStat
|
|
);
|
|
|
|
//
|
|
// Simple accessors
|
|
//
|
|
bool IsChecked(void) const { return m_bChecked; }
|
|
void Check(bool bCheck);
|
|
void Toggle(void) { Check(!IsChecked()); }
|
|
|
|
private:
|
|
bool m_bChecked;
|
|
wxCheckListBox* m_pParent;
|
|
size_t m_nIndex;
|
|
}; // end of CLASS wxCheckListBoxItem
|
|
|
|
|
|
|
|
wxCheckListBoxItem::wxCheckListBoxItem(wxCheckListBox* pParent, size_t nIndex)
|
|
:wxOwnerDrawn( wxEmptyString, true /* checkable */ )
|
|
{
|
|
m_bChecked = false;
|
|
m_pParent = pParent;
|
|
m_nIndex = nIndex;
|
|
|
|
//
|
|
// We don't initialize m_nCheckHeight/Width vars because it's
|
|
// done in OnMeasure while they are used only in OnDraw and we
|
|
// know that there will always be OnMeasure before OnDraw
|
|
//
|
|
SetMarginWidth(GetDefaultMarginWidth());
|
|
} // end of wxCheckListBoxItem::wxCheckListBoxItem
|
|
|
|
|
|
|
|
bool wxCheckListBoxItem::OnDrawItem ( wxDC& rDc,
|
|
const wxRect& rRect,
|
|
wxODAction eAct,
|
|
wxODStatus eStat )
|
|
{
|
|
wxRect vRect = rRect;
|
|
|
|
::WinQueryWindowRect( m_pParent->GetHWND(), &rDc.m_vRclPaint );
|
|
if (IsChecked())
|
|
eStat = (wxOwnerDrawn::wxODStatus)(eStat | wxOwnerDrawn::wxODChecked);
|
|
|
|
//
|
|
// Unfortunately PM doesn't quite get the text position exact. We need to alter
|
|
// it down and to the right, just a little bit. The coords in rRect are OS/2
|
|
// coords not wxWidgets coords.
|
|
//
|
|
vRect.x += 5;
|
|
vRect.y -= 3;
|
|
if (wxOwnerDrawn::OnDrawItem( rDc, vRect, eAct, eStat))
|
|
{
|
|
size_t nCheckWidth = GetDefaultMarginWidth();
|
|
size_t nCheckHeight = m_pParent->GetItemHeight();
|
|
int nParentHeight;
|
|
int nX = rRect.GetX();
|
|
int nY = rRect.GetY();
|
|
int nOldY = nY;
|
|
wxColour vColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
|
wxPen vPenBack;
|
|
wxPen vPenPrev;
|
|
|
|
m_pParent->GetSize( NULL, &nParentHeight);
|
|
|
|
nY = nParentHeight - nY - nCheckHeight;
|
|
vPenBack = wxPen(vColour, 1, wxSOLID);
|
|
|
|
//
|
|
// Erase the 1-pixel border
|
|
//
|
|
rDc.SetPen(vPenBack);
|
|
rDc.DrawRectangle( nX, nY, nCheckWidth, nCheckHeight );
|
|
|
|
//
|
|
// Now we draw the smaller rectangle
|
|
//
|
|
nY++;
|
|
nCheckWidth -= 2;
|
|
nCheckHeight -= 2;
|
|
|
|
//
|
|
// Draw hollow gray rectangle
|
|
//
|
|
rDc.SetPen(*wxGREY_PEN);
|
|
rDc.DrawRectangle( nX, nY, nCheckWidth, nCheckHeight );
|
|
|
|
nX++;
|
|
if (IsChecked())
|
|
{
|
|
//
|
|
// Draw the check by loading the sys standard bitmap and drawing it
|
|
//
|
|
HBITMAP hChkBmp = ::WinGetSysBitmap( HWND_DESKTOP, SBMP_MENUCHECK );
|
|
POINTL vPoint = {nX, nOldY + 3};
|
|
|
|
::WinDrawBitmap( rDc.GetHPS(),
|
|
hChkBmp,
|
|
NULL,
|
|
&vPoint,
|
|
NULL,
|
|
NULL,
|
|
DBM_NORMAL
|
|
);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
} // end of wxCheckListBoxItem::OnDrawItem
|
|
|
|
//
|
|
// Change the state of the item and redraw it
|
|
//
|
|
void wxCheckListBoxItem::Check( bool bCheck )
|
|
{
|
|
m_bChecked = bCheck;
|
|
|
|
//
|
|
// Index may be chanegd because new items were added/deleted
|
|
//
|
|
if (m_pParent->GetItemIndex(this) != (int)m_nIndex)
|
|
{
|
|
//
|
|
// Update it
|
|
//
|
|
int nIndex = m_pParent->GetItemIndex(this);
|
|
|
|
wxASSERT_MSG(nIndex != wxNOT_FOUND, wxT("what does this item do here?"));
|
|
|
|
m_nIndex = (size_t)nIndex;
|
|
}
|
|
|
|
|
|
wxCommandEvent vEvent( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED,m_pParent->GetId());
|
|
|
|
vEvent.SetInt(m_nIndex);
|
|
vEvent.SetEventObject(m_pParent);
|
|
m_pParent->ProcessCommand(vEvent);
|
|
} // end of wxCheckListBoxItem::Check
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// implementation of wxCheckListBox class
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// define event table
|
|
// ------------------
|
|
BEGIN_EVENT_TABLE(wxCheckListBox, wxListBox)
|
|
EVT_CHAR(wxCheckListBox::OnChar)
|
|
EVT_LEFT_DOWN(wxCheckListBox::OnLeftClick)
|
|
END_EVENT_TABLE()
|
|
|
|
|
|
|
|
//
|
|
// Control creation
|
|
// ----------------
|
|
//
|
|
|
|
//
|
|
// Default ctor: use Create() to really create the control
|
|
//
|
|
wxCheckListBox::wxCheckListBox()
|
|
:wxCheckListBoxBase()
|
|
{
|
|
} // end of wxCheckListBox::wxCheckListBox
|
|
|
|
//
|
|
// Ctor which creates the associated control
|
|
//
|
|
wxCheckListBox::wxCheckListBox ( wxWindow* pParent,
|
|
wxWindowID vId,
|
|
const wxPoint& rPos,
|
|
const wxSize& rSize,
|
|
int nStrings,
|
|
const wxString asChoices[],
|
|
long lStyle,
|
|
const wxValidator& rVal,
|
|
const wxString& rsName)
|
|
:wxCheckListBoxBase()
|
|
{
|
|
Create( pParent, vId, rPos, rSize, nStrings, asChoices, lStyle | wxLB_OWNERDRAW, rVal, rsName );
|
|
} // end of wxCheckListBox::wxCheckListBox
|
|
|
|
wxCheckListBox::wxCheckListBox ( wxWindow* pParent,
|
|
wxWindowID vId,
|
|
const wxPoint& rPos,
|
|
const wxSize& rSize,
|
|
const wxArrayString& asChoices,
|
|
long lStyle,
|
|
const wxValidator& rVal,
|
|
const wxString& rsName )
|
|
:wxCheckListBoxBase()
|
|
{
|
|
wxCArrayString chs(asChoices);
|
|
Create( pParent, vId, rPos, rSize, chs.GetCount(), chs.GetStrings(),
|
|
lStyle | wxLB_OWNERDRAW, rVal, rsName );
|
|
} // end of wxCheckListBox::wxCheckListBox
|
|
|
|
void wxCheckListBox::Delete(unsigned int n)
|
|
{
|
|
wxCHECK_RET( IsValid(n),
|
|
wxT("invalid index in wxCheckListBox::Delete") );
|
|
wxListBox::Delete(n);
|
|
|
|
//
|
|
// Free memory
|
|
//
|
|
delete m_aItems[n];
|
|
m_aItems.RemoveAt(n);
|
|
} // end of wxCheckListBox::Delete
|
|
|
|
int wxCheckListBox::DoInsertItems(const wxArrayStringsAdapter& items,
|
|
unsigned int pos,
|
|
void **clientData,
|
|
wxClientDataType type)
|
|
{
|
|
// pos is validated in wxListBox
|
|
int result = wxListBox::DoInsertItems( items, pos, clientData, type );
|
|
unsigned int n = items.GetCount();
|
|
for (unsigned int i = 0; i < n; i++)
|
|
{
|
|
wxOwnerDrawn* pNewItem = CreateItem((size_t)(pos + i));
|
|
|
|
pNewItem->SetName(items[i]);
|
|
m_aItems.Insert(pNewItem, (size_t)(pos + i));
|
|
::WinSendMsg( (HWND)GetHWND(),
|
|
LM_SETITEMHANDLE,
|
|
(MPARAM)(i + pos),
|
|
MPFROMP(pNewItem)
|
|
);
|
|
}
|
|
return result;
|
|
} // end of wxCheckListBox::DoInsertItems
|
|
|
|
bool wxCheckListBox::SetFont ( const wxFont& rFont )
|
|
{
|
|
for (unsigned int i = 0; i < m_aItems.GetCount(); i++)
|
|
m_aItems[i]->SetFont(rFont);
|
|
wxListBox::SetFont(rFont);
|
|
return true;
|
|
} // end of wxCheckListBox::SetFont
|
|
|
|
|
|
|
|
//
|
|
// Create/retrieve item
|
|
// --------------------
|
|
//
|
|
|
|
//
|
|
// Create a check list box item
|
|
//
|
|
wxOwnerDrawn* wxCheckListBox::CreateItem(size_t nIndex)
|
|
{
|
|
wxCheckListBoxItem* pItem = new wxCheckListBoxItem( this, nIndex );
|
|
return pItem;
|
|
} // end of wxCheckListBox::CreateItem
|
|
|
|
|
|
|
|
//
|
|
// Return item size
|
|
// ----------------
|
|
//
|
|
long wxCheckListBox::OS2OnMeasure ( WXMEASUREITEMSTRUCT* pItem )
|
|
{
|
|
if (!pItem)
|
|
pItem = (WXMEASUREITEMSTRUCT*)new OWNERITEM;
|
|
if (wxListBox::OS2OnMeasure(pItem))
|
|
{
|
|
POWNERITEM pStruct = (POWNERITEM)pItem;
|
|
|
|
//
|
|
// Save item height
|
|
//
|
|
m_nItemHeight = pStruct->rclItem.yTop - pStruct->rclItem.yBottom;
|
|
|
|
//
|
|
// Add place for the check mark
|
|
//
|
|
pStruct->rclItem.xRight += wxOwnerDrawn::GetDefaultMarginWidth();
|
|
return long(MRFROM2SHORT((USHORT)m_nItemHeight, (USHORT)(pStruct->rclItem.xRight - pStruct->rclItem.xLeft)));
|
|
}
|
|
return 0L;
|
|
} // end of wxCheckListBox::CreateItem
|
|
|
|
|
|
|
|
//
|
|
// Check items
|
|
// -----------
|
|
//
|
|
bool wxCheckListBox::IsChecked(unsigned int uiIndex) const
|
|
{
|
|
return GetItem(uiIndex)->IsChecked();
|
|
} // end of wxCheckListBox::IsChecked
|
|
|
|
void wxCheckListBox::Check(unsigned int uiIndex, bool bCheck)
|
|
{
|
|
GetItem(uiIndex)->Check(bCheck);
|
|
} // end of wxCheckListBox::Check
|
|
|
|
|
|
|
|
//
|
|
// Process events
|
|
// --------------
|
|
//
|
|
void wxCheckListBox::OnChar ( wxKeyEvent& rEvent )
|
|
{
|
|
if (rEvent.GetKeyCode() == WXK_SPACE)
|
|
GetItem(GetSelection())->Toggle();
|
|
else
|
|
rEvent.Skip();
|
|
} // end of wxCheckListBox::OnChar
|
|
|
|
void wxCheckListBox::OnLeftClick ( wxMouseEvent& rEvent )
|
|
{
|
|
//
|
|
// Clicking on the item selects it, clicking on the checkmark toggles
|
|
//
|
|
if (rEvent.GetX() <= wxOwnerDrawn::GetDefaultMarginWidth())
|
|
{
|
|
int nParentHeight;
|
|
wxScreenDC vDc;
|
|
wxCoord vHeight;
|
|
|
|
GetSize( NULL, &nParentHeight );
|
|
vDc.SetFont(GetFont());
|
|
vHeight = (wxCoord)(vDc.GetCharHeight() * 2.5);
|
|
|
|
//
|
|
// This, of course, will not work if the LB is scrolled
|
|
//
|
|
int nY = rEvent.GetY();
|
|
|
|
nY = nParentHeight - (nY + vHeight);
|
|
|
|
size_t nItem = (size_t)(nY / vHeight);
|
|
|
|
if (nItem < m_nNumItems)
|
|
GetItem(nItem)->Toggle();
|
|
//
|
|
// else: it's not an error, just click outside of client zone
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Implement default behaviour: clicking on the item selects it
|
|
//
|
|
rEvent.Skip();
|
|
}
|
|
} // end of wxCheckListBox::OnLeftClick
|
|
|
|
#endif // wxUSE_CHECKLISTBOX && wxUSE_OWNER_DRAWN
|