TODO
1. we need to implement searching/sorting for virtual controls somehow
- 2. when changing selection the lines are refreshed twice
+ ?2. when changing selection the lines are refreshed twice
*/
// ============================================================================
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED)
class WXDLLEXPORT wxListHeaderData : public wxObject
{
-protected:
- long m_mask;
- int m_image;
- wxString m_text;
- int m_format;
- int m_width;
- int m_xpos,
- m_ypos;
- int m_height;
-
public:
wxListHeaderData();
wxListHeaderData( const wxListItem &info );
int GetWidth() const;
int GetFormat() const;
+protected:
+ long m_mask;
+ int m_image;
+ wxString m_text;
+ int m_format;
+ int m_width;
+ int m_xpos,
+ m_ypos;
+ int m_height;
+
private:
- DECLARE_DYNAMIC_CLASS(wxListHeaderData);
+ void Init();
};
//-----------------------------------------------------------------------------
public:
wxListHeaderWindow();
- virtual ~wxListHeaderWindow();
wxListHeaderWindow( wxWindow *win,
wxWindowID id,
long style = 0,
const wxString &name = "wxlistctrlcolumntitles" );
+ virtual ~wxListHeaderWindow();
+
void DoDrawRect( wxDC *dc, int x, int y, int w, int h );
void DrawCurrent();
void AdjustDC(wxDC& dc);
bool m_dirty;
private:
+ // common part of all ctors
+ void Init();
+
DECLARE_DYNAMIC_CLASS(wxListHeaderWindow)
DECLARE_EVENT_TABLE()
};
// wxListHeaderData
//-----------------------------------------------------------------------------
-IMPLEMENT_DYNAMIC_CLASS(wxListHeaderData,wxObject);
-
-wxListHeaderData::wxListHeaderData()
+void wxListHeaderData::Init()
{
m_mask = 0;
- m_image = 0;
+ m_image = -1;
m_format = 0;
m_width = 0;
m_xpos = 0;
m_height = 0;
}
+wxListHeaderData::wxListHeaderData()
+{
+ Init();
+}
+
wxListHeaderData::wxListHeaderData( const wxListItem &item )
{
+ Init();
+
SetItem( item );
- m_xpos = 0;
- m_ypos = 0;
- m_height = 0;
}
void wxListHeaderData::SetItem( const wxListItem &item )
{
m_mask = item.m_mask;
- m_text = item.m_text;
- m_image = item.m_image;
- m_format = item.m_format;
- SetWidth(item.m_width);
+ if ( m_mask & wxLIST_MASK_TEXT )
+ m_text = item.m_text;
+
+ if ( m_mask & wxLIST_MASK_IMAGE )
+ m_image = item.m_image;
+
+ if ( m_mask & wxLIST_MASK_FORMAT )
+ m_format = item.m_format;
+
+ if ( m_mask & wxLIST_MASK_WIDTH )
+ SetWidth(item.m_width);
}
void wxListHeaderData::SetPosition( int x, int y )
m_width = w;
if (m_width < 0)
m_width = WIDTH_COL_DEFAULT;
- if (m_width < WIDTH_COL_MIN)
+ else if (m_width < WIDTH_COL_MIN)
m_width = WIDTH_COL_MIN;
}
bool wxListHeaderData::HasImage() const
{
- return (m_image != 0);
+ return m_image != -1;
}
bool wxListHeaderData::IsHit( int x, int y ) const
return ((x >= m_xpos) && (x <= m_xpos+m_width) && (y >= m_ypos) && (y <= m_ypos+m_height));
}
-void wxListHeaderData::GetItem( wxListItem &item )
+void wxListHeaderData::GetItem( wxListItem& item )
{
item.m_mask = m_mask;
item.m_text = m_text;
EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus)
END_EVENT_TABLE()
-wxListHeaderWindow::wxListHeaderWindow( void )
+void wxListHeaderWindow::Init()
{
- m_owner = (wxListMainWindow *) NULL;
m_currentCursor = (wxCursor *) NULL;
- m_resizeCursor = (wxCursor *) NULL;
m_isDragging = FALSE;
+ m_dirty = FALSE;
}
-wxListHeaderWindow::wxListHeaderWindow( wxWindow *win, wxWindowID id, wxListMainWindow *owner,
- const wxPoint &pos, const wxSize &size,
- long style, const wxString &name ) :
- wxWindow( win, id, pos, size, style, name )
+wxListHeaderWindow::wxListHeaderWindow()
{
+ Init();
+
+ m_owner = (wxListMainWindow *) NULL;
+ m_resizeCursor = (wxCursor *) NULL;
+}
+
+wxListHeaderWindow::wxListHeaderWindow( wxWindow *win,
+ wxWindowID id,
+ wxListMainWindow *owner,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style,
+ const wxString &name )
+ : wxWindow( win, id, pos, size, style, name )
+{
+ Init();
+
m_owner = owner;
-// m_currentCursor = wxSTANDARD_CURSOR;
- m_currentCursor = (wxCursor *) NULL;
m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
- m_isDragging = FALSE;
- m_dirty = FALSE;
SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE ) );
}
-wxListHeaderWindow::~wxListHeaderWindow( void )
+wxListHeaderWindow::~wxListHeaderWindow()
{
delete m_resizeCursor;
}
{
m_owner->GetColumn( i, item );
int wCol = item.m_width;
- int cw = wCol - 2; // the width of the rect to draw
- int xEnd = x + wCol;
+ // the width of the rect to draw: make it smaller to fit entirely
+ // inside the column rect
+ int cw = wCol - 2;
dc.SetPen( *wxWHITE_PEN );
DoDrawRect( &dc, x, HEADER_OFFSET_Y, cw, h-2 );
- wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw-5, h-4 );
+
+ // if we have an image, draw it on the right of the label
+ int image = item.m_image;
+ if ( image != -1 )
+ {
+ wxImageList *imageList = m_owner->m_small_image_list;
+ if ( imageList )
+ {
+ int ix, iy;
+ imageList->GetSize(image, ix, iy);
+
+ imageList->Draw
+ (
+ image,
+ dc,
+ x + cw - ix - 1,
+ HEADER_OFFSET_Y + (h - 4 - iy)/2,
+ wxIMAGELIST_DRAW_TRANSPARENT
+ );
+
+ cw -= ix + 2;
+ }
+ //else: ignore the column image
+ }
+
+ // draw the text clipping it so that it doesn't overwrite the column
+ // boundary
+ wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
dc.DrawText( item.GetText(),
x + EXTRA_WIDTH, HEADER_OFFSET_Y + EXTRA_HEIGHT );
- x += wCol;
-
- if (xEnd > w+5)
+ if ( x > w - wCol + 5 )
break;
+
+ x += wCol;
}
dc.EndDrawing();
}
m_minX = xpos;
}
- if (event.LeftDown())
+ if (event.LeftDown() || event.RightUp())
{
- if (hit_border)
+ if (hit_border && event.LeftDown())
{
m_isDragging = TRUE;
m_currentX = x;
DrawCurrent();
CaptureMouse();
}
- else
+ else // click on a column
{
wxWindow *parent = GetParent();
- wxListEvent le( wxEVT_COMMAND_LIST_COL_CLICK, parent->GetId() );
+ wxListEvent le( event.LeftDown()
+ ? wxEVT_COMMAND_LIST_COL_CLICK
+ : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK,
+ parent->GetId() );
le.SetEventObject( parent );
+ le.m_pointDrag = event.GetPosition();
+
+ // the position should be relative to the parent window, not
+ // this one for compatibility with MSW and common sense: the
+ // user code doesn't know anything at all about this header
+ // window, so why should it get positions relative to it?
+ le.m_pointDrag.y -= GetSize().y;
+
le.m_col = m_column;
parent->GetEventHandler()->ProcessEvent( le );
}
long wxListMainWindow::HitTestLine(size_t line, int x, int y) const
{
+ wxASSERT_MSG( line < GetItemCount(), _T("invalid line in HitTestLine") );
+
wxListLineData *ld = GetLine(line);
if ( ld->HasImage() && GetLineIconRect(line).Inside(x, y) )
to = GetItemCount() - 1;
}
- if ( HasCurrent() && m_current > from && m_current <= to )
+ if ( HasCurrent() && m_current >= from && m_current <= to )
{
RefreshLine(m_current);
}
if (event.Dragging())
{
if (m_dragCount == 0)
- m_dragStart = wxPoint(x,y);
+ {
+ // we have to report the raw, physical coords as we want to be
+ // able to call HitTest(event.m_pointDrag) from the user code to
+ // get the item being dragged
+ m_dragStart = event.GetPosition();
+ }
m_dragCount++;
_T("SetColumnWidth() can only be called in report mode.") );
m_dirty = TRUE;
+ wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin;
+ if ( headerWin )
+ headerWin->m_dirty = TRUE;
wxListHeaderDataList::Node *node = m_columns.Item( col );
wxCHECK_RET( node, _T("no column?") );
// been added and its position is not known yet
if ( m_dirty )
{
- m_dirty = FALSE;
-
RecalculatePositions(TRUE /* no refresh */);
}
{
CalcUnscrolledPosition( x, y, &x, &y );
+ size_t count = GetItemCount();
+
if ( HasFlag(wxLC_REPORT) )
{
size_t current = y / GetLineHeight();
- flags = HitTestLine(current, x, y);
- if ( flags )
- return current;
+ if ( current < count )
+ {
+ flags = HitTestLine(current, x, y);
+ if ( flags )
+ return current;
+ }
}
else // !report
{
// TODO: optimize it too! this is less simple than for report view but
// enumerating all items is still not a way to do it!!
- size_t count = GetItemCount();
for ( size_t current = 0; current < count; current++ )
{
flags = HitTestLine(current, x, y);
wxListItem::wxListItem()
{
- m_mask = 0;
- m_itemId = 0;
- m_col = 0;
- m_state = 0;
- m_stateMask = 0;
- m_image = 0;
- m_data = 0;
- m_format = wxLIST_FORMAT_CENTRE;
- m_width = 0;
-
m_attr = NULL;
+
+ Clear();
}
void wxListItem::Clear()
m_col = 0;
m_state = 0;
m_stateMask = 0;
- m_image = 0;
+ m_image = -1;
m_data = 0;
m_format = wxLIST_FORMAT_CENTRE;
m_width = 0;
- m_text = _T("");
+ m_text.clear();
ClearAttributes();
}