]> git.saurik.com Git - wxWidgets.git/blame - src/generic/listctrl.cpp
several mac fixes (Mark Newsams patches)
[wxWidgets.git] / src / generic / listctrl.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
54442116
VZ
2// Name: generic/listctrl.cpp
3// Purpose: generic implementation of wxListCtrl
c801d85f 4// Author: Robert Roebling
cf1dfa6b 5// Vadim Zeitlin (virtual list control support)
0208334d
RR
6// Id: $Id$
7// Copyright: (c) 1998 Robert Roebling
bd8289c1 8// Licence: wxWindows licence
c801d85f
KB
9/////////////////////////////////////////////////////////////////////////////
10
b54e41c5
VZ
11/*
12 FIXME for virtual list controls
13
14 +1. clicking on the item with a mouse is awfully slow, what is going on?
15 note that selecting with keyboard seems to be much faster
16 => fixed HighlightAll() - iterating over 1000000 items *is* slow
17
18 2. background colour is wrong?
19 */
20
21/*
22 TODO for better virtual list control support:
23
24 1. less dumb line caching, we should cache at least all those visible
25 in the control itself and probably twice as many (we might also need to
26 cache the first one always for geometry calculations?)
27
28 +2. storing selections: we can't use an array to store the selected indices
29 like right now as selecting all in a control with 1000000 items is not
30 doable like this - instead, store selections as collection of individual
31 items and ranges
32
33 => wxSelectionStore
34
35 3. we need to implement searching/sorting somehow
36
37 4. the idea of storing the line index in the line itself is really stupid,
38 we shouldn't need it - but for this we have to get rid of all calles to
39 wxListLineData::GetFoo() and replace them with something like
40 if ( IsVirtual()
41 ... we have it ourselves ...
42 else
43 line->GetFoo();
1e4d446b
VZ
44
45 => done
46
47 5. attributes support: we need OnGetItemAttr() as well!
b54e41c5
VZ
48 */
49
1370703e
VZ
50// ============================================================================
51// declarations
52// ============================================================================
53
54// ----------------------------------------------------------------------------
55// headers
56// ----------------------------------------------------------------------------
57
c801d85f 58#ifdef __GNUG__
510fc784
RR
59 #pragma implementation "listctrl.h"
60 #pragma implementation "listctrlbase.h"
1e4d446b 61#endif
5cd89174 62
1e6d9499
JS
63// For compilers that support precompilation, includes "wx.h".
64#include "wx/wxprec.h"
65
66#ifdef __BORLANDC__
67#pragma hdrstop
68#endif
69
1e6feb95
VZ
70#if wxUSE_LISTCTRL
71
0208334d
RR
72#include "wx/dcscreen.h"
73#include "wx/app.h"
02527779 74#include "wx/listctrl.h"
b54e41c5 75#include "wx/imaglist.h"
f6bcfd97 76#include "wx/dynarray.h"
c801d85f 77
3fb435df
RR
78#ifdef __WXGTK__
79#include <gtk/gtk.h>
80#include "wx/gtk/win_gtk.h"
81#endif
82
2e4df4bf
VZ
83// ----------------------------------------------------------------------------
84// events
85// ----------------------------------------------------------------------------
86
87DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG)
88DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG)
89DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT)
90DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT)
91DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM)
92DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS)
93DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO)
94DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO)
95DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED)
96DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED)
97DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN)
98DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM)
99DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK)
100DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK)
101DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK)
102DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED)
103
cf1dfa6b
VZ
104// ----------------------------------------------------------------------------
105// constants
106// ----------------------------------------------------------------------------
107
108// the height of the header window (FIXME: should depend on its font!)
109static const int HEADER_HEIGHT = 23;
110
111// the scrollbar units
112static const int SCROLL_UNIT_X = 15;
113static const int SCROLL_UNIT_Y = 15;
114
115// the spacing between the lines (in report mode)
b54e41c5 116static const int LINE_SPACING = 0;
cf1dfa6b
VZ
117
118// extra margins around the text label
119static const int EXTRA_WIDTH = 3;
120static const int EXTRA_HEIGHT = 4;
121
122// offset for the header window
123static const int HEADER_OFFSET_X = 1;
124static const int HEADER_OFFSET_Y = 1;
125
126// when autosizing the columns, add some slack
127static const int AUTOSIZE_COL_MARGIN = 10;
128
129// default and minimal widths for the header columns
130static const int WIDTH_COL_DEFAULT = 80;
131static const int WIDTH_COL_MIN = 10;
132
efbb7287
VZ
133// ============================================================================
134// private classes
135// ============================================================================
136
b54e41c5
VZ
137// ----------------------------------------------------------------------------
138// wxSelectionStore
139// ----------------------------------------------------------------------------
140
141int CMPFUNC_CONV wxSizeTCmpFn(size_t n1, size_t n2) { return n1 - n2; }
142
143WX_DEFINE_SORTED_EXPORTED_ARRAY(size_t, wxIndexArray);
144
145// this class is used to store the selected items in the virtual list control
146// (but it is not tied to list control and so can be used with other controls
147// such as wxListBox in wxUniv)
148//
149// the idea is to make it really smart later (i.e. store the selections as an
150// array of ranes + individual items) but, as I don't have time to do it now
151// (this would require writing code to merge/break ranges and much more) keep
152// it simple but define a clean interface to it which allows it to be made
153// smarter later
154class WXDLLEXPORT wxSelectionStore
155{
156public:
157 wxSelectionStore() : m_itemsSel(wxSizeTCmpFn) { Init(); }
158
159 // set the total number of items we handle
160 void SetItemCount(size_t count) { m_count = count; }
161
162 // special case of SetItemCount(0)
163 void Clear() { m_itemsSel.Clear(); m_count = 0; }
164
165 // must be called when a new item is inserted/added
166 void OnItemAdd(size_t item) { wxFAIL_MSG( _T("TODO") ); }
167
168 // must be called when an item is deleted
169 void OnItemDelete(size_t item);
170
171 // select one item, use SelectRange() insted if possible!
172 //
173 // returns true if the items selection really changed
174 bool SelectItem(size_t item, bool select = TRUE);
175
176 // select the range of items
177 void SelectRange(size_t itemFrom, size_t itemTo, bool select = TRUE);
178
179 // return true if the given item is selected
180 bool IsSelected(size_t item) const;
181
182 // return the total number of selected items
183 size_t GetSelectedCount() const
184 {
185 return m_defaultState ? m_count - m_itemsSel.GetCount()
186 : m_itemsSel.GetCount();
187 }
188
189private:
190 // (re)init
191 void Init() { m_defaultState = FALSE; }
192
193 // the total number of items we handle
194 size_t m_count;
195
196 // the default state: normally, FALSE (i.e. off) but maybe set to TRUE if
197 // there are more selected items than non selected ones - this allows to
198 // handle selection of all items efficiently
199 bool m_defaultState;
200
201 // the array of items whose selection state is different from default
202 wxIndexArray m_itemsSel;
203
204 DECLARE_NO_COPY_CLASS(wxSelectionStore)
205};
206
efbb7287
VZ
207//-----------------------------------------------------------------------------
208// wxListItemData (internal)
209//-----------------------------------------------------------------------------
210
cf1dfa6b 211class WXDLLEXPORT wxListItemData
efbb7287 212{
efbb7287 213public:
cf1dfa6b
VZ
214 wxListItemData(wxListMainWindow *owner);
215 ~wxListItemData() { delete m_attr; delete m_rect; }
efbb7287 216
efbb7287 217 void SetItem( const wxListItem &info );
cf1dfa6b
VZ
218 void SetImage( int image ) { m_image = image; }
219 void SetData( long data ) { m_data = data; }
efbb7287
VZ
220 void SetPosition( int x, int y );
221 void SetSize( int width, int height );
54442116
VZ
222
223 bool HasText() const { return !m_text.empty(); }
224 const wxString& GetText() const { return m_text; }
225 void SetText(const wxString& text) { m_text = text; }
226
cf1dfa6b
VZ
227 // we can't use empty string for measuring the string width/height, so
228 // always return something
229 wxString GetTextForMeasuring() const
230 {
231 wxString s = GetText();
232 if ( s.empty() )
233 s = _T('H');
234
235 return s;
236 }
237
efbb7287 238 bool IsHit( int x, int y ) const;
54442116 239
cf1dfa6b
VZ
240 int GetX() const;
241 int GetY() const;
efbb7287
VZ
242 int GetWidth() const;
243 int GetHeight() const;
cf1dfa6b
VZ
244
245 int GetImage() const { return m_image; }
246 bool HasImage() const { return GetImage() != -1; }
247
efbb7287
VZ
248 void GetItem( wxListItem &info ) const;
249
6c02c329
VZ
250 void SetAttr(wxListItemAttr *attr) { m_attr = attr; }
251 wxListItemAttr *GetAttr() const { return m_attr; }
efbb7287 252
54442116 253public:
cf1dfa6b
VZ
254 // the item image or -1
255 int m_image;
256
257 // user data associated with the item
258 long m_data;
54442116 259
cf1dfa6b
VZ
260 // the item coordinates are not used in report mode, instead this pointer
261 // is NULL and the owner window is used to retrieve the item position and
262 // size
263 wxRect *m_rect;
264
265 // the list ctrl we are in
266 wxListMainWindow *m_owner;
267
268 // custom attributes or NULL
54442116
VZ
269 wxListItemAttr *m_attr;
270
271protected:
cf1dfa6b
VZ
272 // common part of all ctors
273 void Init();
54442116 274
cf1dfa6b 275 wxString m_text;
efbb7287
VZ
276};
277
278//-----------------------------------------------------------------------------
279// wxListHeaderData (internal)
280//-----------------------------------------------------------------------------
281
282class WXDLLEXPORT wxListHeaderData : public wxObject
283{
284protected:
285 long m_mask;
286 int m_image;
287 wxString m_text;
288 int m_format;
289 int m_width;
2c1f73ee
VZ
290 int m_xpos,
291 m_ypos;
efbb7287
VZ
292 int m_height;
293
294public:
295 wxListHeaderData();
296 wxListHeaderData( const wxListItem &info );
297 void SetItem( const wxListItem &item );
298 void SetPosition( int x, int y );
299 void SetWidth( int w );
300 void SetFormat( int format );
301 void SetHeight( int h );
302 bool HasImage() const;
54442116
VZ
303
304 bool HasText() const { return !m_text.empty(); }
305 const wxString& GetText() const { return m_text; }
306 void SetText(const wxString& text) { m_text = text; }
307
efbb7287 308 void GetItem( wxListItem &item );
54442116
VZ
309
310 bool IsHit( int x, int y ) const;
efbb7287
VZ
311 int GetImage() const;
312 int GetWidth() const;
313 int GetFormat() const;
f6bcfd97 314
efbb7287
VZ
315private:
316 DECLARE_DYNAMIC_CLASS(wxListHeaderData);
317};
318
319//-----------------------------------------------------------------------------
320// wxListLineData (internal)
321//-----------------------------------------------------------------------------
322
2c1f73ee
VZ
323WX_DECLARE_LIST(wxListItemData, wxListItemDataList);
324#include "wx/listimpl.cpp"
325WX_DEFINE_LIST(wxListItemDataList);
326
cf1dfa6b 327class WXDLLEXPORT wxListLineData
efbb7287
VZ
328{
329public:
cf1dfa6b
VZ
330 // the list of subitems: only may have more than one item in report mode
331 wxListItemDataList m_items;
332
333 // this is not used in report view
334 struct GeometryInfo
335 {
336 // total item rect
337 wxRect m_rectAll;
338
339 // label only
340 wxRect m_rectLabel;
341
342 // icon only
343 wxRect m_rectIcon;
344
345 // the part to be highlighted
b54e41c5 346 wxRect m_rectHighlight;
cf1dfa6b 347 } *m_gi;
efbb7287 348
cf1dfa6b 349 // is this item selected? [NB: not used in virtual mode]
b54e41c5 350 bool m_highlighted;
cf1dfa6b
VZ
351
352 // back pointer to the list ctrl
353 wxListMainWindow *m_owner;
efbb7287
VZ
354
355public:
5cd89174 356 wxListLineData(wxListMainWindow *owner);
cf1dfa6b
VZ
357
358 ~wxListLineData() { delete m_gi; }
359
360 // are we in report mode?
361 inline bool InReportView() const;
362
363 // are we in virtual report mode?
b54e41c5 364 inline bool IsVirtual() const;
cf1dfa6b
VZ
365
366 // these 2 methods shouldn't be called for report view controls, in that
367 // case we determine our position/size ourselves
368
369 // calculate the size of the line
efbb7287 370 void CalculateSize( wxDC *dc, int spacing );
cf1dfa6b
VZ
371
372 // remember the position this line appears at
373 void SetPosition( int x, int y, int window_width, int spacing );
374
5cd89174
VZ
375 // wxListCtrl API
376
377 void SetImage( int image ) { SetImage(0, image); }
378 int GetImage() const { return GetImage(0); }
379 bool HasImage() const { return GetImage() != -1; }
380 bool HasText() const { return !GetText(0).empty(); }
cf1dfa6b 381
efbb7287
VZ
382 void SetItem( int index, const wxListItem &info );
383 void GetItem( int index, wxListItem &info );
cf1dfa6b 384
54442116 385 wxString GetText(int index) const;
efbb7287 386 void SetText( int index, const wxString s );
cf1dfa6b 387
6c02c329
VZ
388 wxListItemAttr *GetAttr() const;
389 void SetAttr(wxListItemAttr *attr);
390
cf1dfa6b 391 // return true if the highlighting really changed
b54e41c5 392 bool Highlight( bool on );
cf1dfa6b 393
b54e41c5 394 void ReverseHighlight();
cf1dfa6b 395
b54e41c5 396 bool IsHighlighted() const
cf1dfa6b 397 {
b54e41c5 398 wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") );
cf1dfa6b 399
b54e41c5 400 return m_highlighted;
cf1dfa6b
VZ
401 }
402
5cd89174
VZ
403 // draw the line on the given DC in icon/list mode
404 void Draw( wxDC *dc );
405
406 // the same in report mode
407 void DrawInReportMode( wxDC *dc,
408 const wxRect& rect,
409 const wxRect& rectHL,
410 bool highlighted );
f6bcfd97 411
efbb7287 412private:
cf1dfa6b
VZ
413 // set the line to contain num items (only can be > 1 in report mode)
414 void InitItems( int num );
415
416 // get the mode (i.e. style) of the list control
417 inline int GetMode() const;
418
efbb7287
VZ
419 void SetAttributes(wxDC *dc,
420 const wxListItemAttr *attr,
cf1dfa6b
VZ
421 const wxColour& colText,
422 const wxFont& font,
b54e41c5 423 bool highlight);
efbb7287 424
5cd89174
VZ
425 // these are only used by GetImage/SetImage above, we don't support images
426 // with subitems at the public API level yet
427 void SetImage( int index, int image );
428 int GetImage( int index ) const;
efbb7287
VZ
429};
430
f6bcfd97
BP
431WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData, wxListLineDataArray);
432#include "wx/arrimpl.cpp"
433WX_DEFINE_OBJARRAY(wxListLineDataArray);
434
efbb7287
VZ
435//-----------------------------------------------------------------------------
436// wxListHeaderWindow (internal)
437//-----------------------------------------------------------------------------
438
439class WXDLLEXPORT wxListHeaderWindow : public wxWindow
440{
441protected:
442 wxListMainWindow *m_owner;
443 wxCursor *m_currentCursor;
444 wxCursor *m_resizeCursor;
445 bool m_isDragging;
f6bcfd97
BP
446
447 // column being resized
448 int m_column;
449
450 // divider line position in logical (unscrolled) coords
451 int m_currentX;
452
453 // minimal position beyond which the divider line can't be dragged in
454 // logical coords
455 int m_minX;
efbb7287
VZ
456
457public:
458 wxListHeaderWindow();
f6bcfd97
BP
459 virtual ~wxListHeaderWindow();
460
461 wxListHeaderWindow( wxWindow *win,
462 wxWindowID id,
463 wxListMainWindow *owner,
464 const wxPoint &pos = wxDefaultPosition,
465 const wxSize &size = wxDefaultSize,
466 long style = 0,
467 const wxString &name = "wxlistctrlcolumntitles" );
468
efbb7287 469 void DoDrawRect( wxDC *dc, int x, int y, int w, int h );
efbb7287 470 void DrawCurrent();
f6bcfd97
BP
471 void AdjustDC(wxDC& dc);
472
473 void OnPaint( wxPaintEvent &event );
efbb7287
VZ
474 void OnMouse( wxMouseEvent &event );
475 void OnSetFocus( wxFocusEvent &event );
476
f6bcfd97
BP
477 // needs refresh
478 bool m_dirty;
479
efbb7287
VZ
480private:
481 DECLARE_DYNAMIC_CLASS(wxListHeaderWindow)
482 DECLARE_EVENT_TABLE()
483};
484
485//-----------------------------------------------------------------------------
486// wxListRenameTimer (internal)
487//-----------------------------------------------------------------------------
488
489class WXDLLEXPORT wxListRenameTimer: public wxTimer
490{
491private:
1370703e 492 wxListMainWindow *m_owner;
efbb7287
VZ
493
494public:
495 wxListRenameTimer( wxListMainWindow *owner );
496 void Notify();
497};
498
499//-----------------------------------------------------------------------------
500// wxListTextCtrl (internal)
501//-----------------------------------------------------------------------------
502
503class WXDLLEXPORT wxListTextCtrl: public wxTextCtrl
504{
505private:
506 bool *m_accept;
507 wxString *m_res;
508 wxListMainWindow *m_owner;
509 wxString m_startValue;
510
511public:
512 wxListTextCtrl() {}
513 wxListTextCtrl( wxWindow *parent, const wxWindowID id,
514 bool *accept, wxString *res, wxListMainWindow *owner,
515 const wxString &value = "",
516 const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize,
517 int style = 0,
518 const wxValidator& validator = wxDefaultValidator,
809934d2 519 const wxString &name = "listctrltextctrl" );
efbb7287 520 void OnChar( wxKeyEvent &event );
c13cace1 521 void OnKeyUp( wxKeyEvent &event );
efbb7287
VZ
522 void OnKillFocus( wxFocusEvent &event );
523
524private:
525 DECLARE_DYNAMIC_CLASS(wxListTextCtrl);
526 DECLARE_EVENT_TABLE()
527};
528
529//-----------------------------------------------------------------------------
530// wxListMainWindow (internal)
531//-----------------------------------------------------------------------------
532
24b9f055
VZ
533WX_DECLARE_LIST(wxListHeaderData, wxListHeaderDataList);
534#include "wx/listimpl.cpp"
535WX_DEFINE_LIST(wxListHeaderDataList);
536
cf1dfa6b 537class WXDLLEXPORT wxListMainWindow : public wxScrolledWindow
efbb7287 538{
efbb7287
VZ
539public:
540 wxListMainWindow();
1370703e
VZ
541 wxListMainWindow( wxWindow *parent,
542 wxWindowID id,
543 const wxPoint& pos = wxDefaultPosition,
544 const wxSize& size = wxDefaultSize,
545 long style = 0,
546 const wxString &name = _T("listctrlmainwindow") );
547
548 virtual ~wxListMainWindow();
549
cf1dfa6b
VZ
550 bool HasFlag(int flag) const { return m_parent->HasFlag(flag); }
551
1370703e 552 // return true if this is a virtual list control
cf1dfa6b
VZ
553 bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL); }
554
5cd89174
VZ
555 // return true if the control is in report mode
556 bool InReportView() const { return HasFlag(wxLC_REPORT); }
557
b54e41c5
VZ
558 // return true if we are in single selection mode, false if multi sel
559 bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL); }
560
cf1dfa6b
VZ
561 // do we have a header window?
562 bool HasHeader() const
563 { return HasFlag(wxLC_REPORT) && !HasFlag(wxLC_NO_HEADER); }
1370703e 564
b54e41c5 565 void HighlightAll( bool on );
cf1dfa6b
VZ
566
567 // all these functions only do something if the line is currently visible
568
569 // change the line "selected" state, return TRUE if it really changed
b54e41c5
VZ
570 bool HighlightLine( size_t line, bool highlight = TRUE);
571
572 // as HighlightLine() but do it for the range of lines: this is incredibly
573 // more efficient for virtual list controls!
574 //
575 // NB: unlike HighlightLine() this one does refresh the lines on screen
576 void HighlightLines( size_t lineFrom, size_t lineTo, bool on = TRUE );
cf1dfa6b
VZ
577
578 // toggle the line state and refresh it
b54e41c5
VZ
579 void ReverseHighlight( size_t line )
580 { HighlightLine(line, !IsHighlighted(line)); RefreshLine(line); }
cf1dfa6b 581
6b4a8d93
VZ
582 // return true if the line is highlighted
583 bool IsHighlighted(size_t line) const;
584
cf1dfa6b
VZ
585 // refresh one or several lines at once
586 void RefreshLine( size_t line );
587 void RefreshLines( size_t lineFrom, size_t lineTo );
588
6b4a8d93
VZ
589 // refresh all lines below the given one: the difference with
590 // RefreshLines() is that the index here might not be a valid one (happens
591 // when the last line is deleted)
592 void RefreshAfter( size_t lineFrom );
efbb7287 593
5cd89174
VZ
594 // the methods which are forwarded to wxListLineData itself in list/icon
595 // modes but are here because the lines don't store their positions in the
596 // report mode
597
598 // get the bound rect for the entire line
599 wxRect GetLineRect(size_t line) const;
600
601 // get the bound rect of the label
602 wxRect GetLineLabelRect(size_t line) const;
603
604 // get the bound rect of the items icon (only may be called if we do have
605 // an icon!)
606 wxRect GetLineIconRect(size_t line) const;
607
608 // get the rect to be highlighted when the item has focus
609 wxRect GetLineHighlightRect(size_t line) const;
610
611 // get the size of the total line rect
612 wxSize GetLineSize(size_t line) const
613 { return GetLineRect(line).GetSize(); }
614
615 // return the hit code for the corresponding position (in this line)
616 long HitTestLine(size_t line, int x, int y) const;
617
efbb7287 618 void EditLabel( long item );
efbb7287
VZ
619 void OnRenameTimer();
620 void OnRenameAccept();
621
622 void OnMouse( wxMouseEvent &event );
623 void MoveToFocus();
cf1dfa6b
VZ
624
625 // called to switch the selection from the current item to newCurrent,
626 void OnArrowChar( size_t newCurrent, const wxKeyEvent& event );
627
efbb7287
VZ
628 void OnChar( wxKeyEvent &event );
629 void OnKeyDown( wxKeyEvent &event );
630 void OnSetFocus( wxFocusEvent &event );
631 void OnKillFocus( wxFocusEvent &event );
efbb7287 632 void OnScroll(wxScrollWinEvent& event) ;
f6bcfd97 633
cf1dfa6b
VZ
634 void OnPaint( wxPaintEvent &event );
635
efbb7287 636 void DrawImage( int index, wxDC *dc, int x, int y );
5cd89174
VZ
637 void GetImageSize( int index, int &width, int &height ) const;
638 int GetTextLength( const wxString &s ) const;
efbb7287
VZ
639
640 void SetImageList( wxImageList *imageList, int which );
641 void SetItemSpacing( int spacing, bool isSmall = FALSE );
642 int GetItemSpacing( bool isSmall = FALSE );
cf1dfa6b 643
efbb7287
VZ
644 void SetColumn( int col, wxListItem &item );
645 void SetColumnWidth( int col, int width );
cf1dfa6b
VZ
646 void GetColumn( int col, wxListItem &item ) const;
647 int GetColumnWidth( int col ) const;
648 int GetColumnCount() const { return m_columns.GetCount(); }
649
650 // returns the sum of the heights of all columns
651 int GetHeaderWidth() const;
652
5cd89174 653 int GetCountPerPage() const;
cf1dfa6b 654
efbb7287
VZ
655 void SetItem( wxListItem &item );
656 void GetItem( wxListItem &item );
657 void SetItemState( long item, long state, long stateMask );
658 int GetItemState( long item, long stateMask );
efbb7287
VZ
659 void GetItemRect( long index, wxRect &rect );
660 bool GetItemPosition( long item, wxPoint& pos );
661 int GetSelectedItemCount();
cf1dfa6b
VZ
662
663 // set the scrollbars and update the positions of the items
b54e41c5
VZ
664 void RecalculatePositions();
665
666 // refresh the window and the header
667 void RefreshAll();
cf1dfa6b 668
efbb7287
VZ
669 long GetNextItem( long item, int geometry, int state );
670 void DeleteItem( long index );
671 void DeleteAllItems();
672 void DeleteColumn( int col );
673 void DeleteEverything();
674 void EnsureVisible( long index );
675 long FindItem( long start, const wxString& str, bool partial = FALSE );
676 long FindItem( long start, long data);
677 long HitTest( int x, int y, int &flags );
678 void InsertItem( wxListItem &item );
efbb7287 679 void InsertColumn( long col, wxListItem &item );
efbb7287
VZ
680 void SortItems( wxListCtrlCompare fn, long data );
681
cf1dfa6b 682 size_t GetItemCount() const;
1370703e 683 bool IsEmpty() const { return GetItemCount() == 0; }
2c1f73ee
VZ
684 void SetItemCount(long count);
685
b54e41c5 686 void ResetCurrent() { m_current = (size_t)-1; }
cf1dfa6b
VZ
687 bool HasCurrent() const { return m_current != (size_t)-1; }
688
689 // send out a wxListEvent
690 void SendNotify( size_t line,
691 wxEventType command,
692 wxPoint point = wxDefaultPosition );
693
b54e41c5
VZ
694 // override base class virtual to reset m_lineHeight when the font changes
695 virtual bool SetFont(const wxFont& font)
696 {
697 if ( !wxScrolledWindow::SetFont(font) )
698 return FALSE;
699
700 m_lineHeight = 0;
701
702 return TRUE;
703 }
cf1dfa6b
VZ
704
705 // these are for wxListLineData usage only
706
707 // get the backpointer to the list ctrl
708 wxListCtrl *GetListCtrl() const
709 {
710 return wxStaticCast(GetParent(), wxListCtrl);
711 }
712
713 // get the height of all lines (assuming they all do have the same height)
714 wxCoord GetLineHeight() const;
715
716 // get the y position of the given line (only for report view)
717 wxCoord GetLineY(size_t line) const;
718
719//protected:
720 // the array of all line objects for a non virtual list control
721 wxListLineDataArray m_lines;
722
723 // the list of column objects
724 wxListHeaderDataList m_columns;
725
726 // currently focused item or -1
727 size_t m_current;
728
729 // the item currently being edited or -1
730 size_t m_currentEdit;
731
732 // the number of lines per page
733 int m_linesPerPage;
734
735 // this flag is set when something which should result in the window
736 // redrawing happens (i.e. an item was added or deleted, or its appearance
737 // changed) and OnPaint() doesn't redraw the window while it is set which
738 // allows to minimize the number of repaintings when a lot of items are
739 // being added. The real repainting occurs only after the next OnIdle()
740 // call
741 bool m_dirty;
742
b54e41c5
VZ
743 wxBrush *m_highlightBrush;
744 wxColour *m_highlightColour;
cf1dfa6b
VZ
745 int m_xScroll,
746 m_yScroll;
747 wxImageList *m_small_image_list;
748 wxImageList *m_normal_image_list;
749 int m_small_spacing;
750 int m_normal_spacing;
751 bool m_hasFocus;
752
753 bool m_lastOnSame;
754 wxTimer *m_renameTimer;
755 bool m_renameAccept;
756 wxString m_renameRes;
757 bool m_isCreated;
758 int m_dragCount;
759 wxPoint m_dragStart;
760
761 // for double click logic
762 size_t m_lineLastClicked,
763 m_lineBeforeLastClicked;
764
1370703e 765protected:
cf1dfa6b 766 // the total count of items in a virtual list control
b54e41c5 767 size_t m_countVirt;
cf1dfa6b 768
b54e41c5
VZ
769 // the object maintaining the items selection state, only used in virtual
770 // controls
771 wxSelectionStore m_selStore;
cf1dfa6b 772
1370703e
VZ
773 // common part of all ctors
774 void Init();
775
cf1dfa6b
VZ
776 // intiialize m_[xy]Scroll
777 void InitScrolling();
778
1370703e
VZ
779 // get the line data for the given index
780 wxListLineData *GetLine(size_t n) const
781 {
782 wxASSERT_MSG( n != (size_t)-1, _T("invalid line index") );
783
cf1dfa6b
VZ
784 if ( IsVirtual() )
785 {
786 wxConstCast(this, wxListMainWindow)->CacheLineData(n);
787
788 n = 0;
789 }
790
1370703e
VZ
791 return &m_lines[n];
792 }
793
b54e41c5
VZ
794 // get a dummy line which can be used for geometry calculations and such:
795 // you must use GetLine() if you want to really draw the line
796 wxListLineData *GetDummyLine() const;
cf1dfa6b
VZ
797
798 // cache the line data of the n-th line in m_lines[0]
799 void CacheLineData(size_t line);
800
b54e41c5
VZ
801 // get the range of visible lines
802 void GetVisibleLinesRange(size_t *from, size_t *to);
803
804 // force us to recalculate the range of visible lines
805 void ResetVisibleLinesRange() { m_lineFrom = (size_t)-1; }
806
807 // get the colour to be used for drawing the rules
808 wxColour GetRuleColour() const
809 {
810#ifdef __WXMAC__
811 return *wxWHITE;
812#else
813 return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT);
814#endif
815 }
cf1dfa6b 816
efbb7287 817private:
cf1dfa6b
VZ
818 // initialize the current item if needed
819 void UpdateCurrent();
820
821 // called when an item is [un]focuded, i.e. becomes [not] current
822 //
823 // currently unused
824 void OnFocusLine( size_t line );
825 void OnUnfocusLine( size_t line );
826
827 // the height of one line using the current font
828 wxCoord m_lineHeight;
829
830 // the total header width or 0 if not calculated yet
831 wxCoord m_headerWidth;
832
b54e41c5
VZ
833 // the first and last lines being shown on screen right now (inclusive),
834 // both may be -1 if they must be calculated so never access them directly:
835 // use GetVisibleLinesRange() above instead
836 size_t m_lineFrom,
837 m_lineTo;
838
efbb7287
VZ
839 DECLARE_DYNAMIC_CLASS(wxListMainWindow);
840 DECLARE_EVENT_TABLE()
841};
842
843// ============================================================================
844// implementation
845// ============================================================================
846
b54e41c5
VZ
847// ----------------------------------------------------------------------------
848// wxSelectionStore
849// ----------------------------------------------------------------------------
850
851bool wxSelectionStore::IsSelected(size_t item) const
852{
853 bool isSel = m_itemsSel.Index(item) != wxNOT_FOUND;
854
855 // if the default state is to be selected, being in m_itemsSel means that
856 // the item is not selected, so we have to inverse the logic
857 return m_defaultState ? !isSel : isSel;
858}
859
860bool wxSelectionStore::SelectItem(size_t item, bool select)
861{
862 // search for the item ourselves as like this we get the index where to
863 // insert it later if needed, so we do only one search in the array instead
864 // of two (adding item to a sorted array requires a search)
865 size_t index = m_itemsSel.IndexForInsert(item);
866 bool isSel = index < m_itemsSel.GetCount() && m_itemsSel[index] == item;
867
868 if ( select != m_defaultState )
869 {
870 if ( !isSel )
871 {
872 m_itemsSel.AddAt(item, index);
873
874 return TRUE;
875 }
876 }
877 else // reset to default state
878 {
879 if ( isSel )
880 {
881 m_itemsSel.RemoveAt(index);
882 return TRUE;
883 }
884 }
885
886 return FALSE;
887}
888
889void wxSelectionStore::SelectRange(size_t itemFrom, size_t itemTo, bool select)
890{
891 wxASSERT_MSG( itemFrom <= itemTo, _T("should be in order") );
892
893 // are we going to have more [un]selected items than the other ones?
894 if ( itemTo - itemFrom > m_count / 2 )
895 {
896 if ( select != m_defaultState )
897 {
898 // the default state now becomes the same as 'select'
899 m_defaultState = select;
900
901 // so all the old selections (which had state select) shouldn't be
902 // selected any more, but all the other ones should
903 wxIndexArray selOld = m_itemsSel;
904 m_itemsSel.Empty();
905
906 // TODO: it should be possible to optimize the searches a bit
907 // knowing the possible range
908
909 size_t item;
910 for ( item = 0; item < itemFrom; item++ )
911 {
912 if ( selOld.Index(item) == wxNOT_FOUND )
913 m_itemsSel.Add(item);
914 }
915
916 for ( item = itemTo + 1; item < m_count; item++ )
917 {
918 if ( selOld.Index(item) == wxNOT_FOUND )
919 m_itemsSel.Add(item);
920 }
921 }
922 else // select == m_defaultState
923 {
924 // get the inclusive range of items between itemFrom and itemTo
925 size_t count = m_itemsSel.GetCount(),
926 start = m_itemsSel.IndexForInsert(itemFrom),
927 end = m_itemsSel.IndexForInsert(itemTo);
928
929 if ( start == count || m_itemsSel[start] < itemFrom )
930 {
931 start++;
932 }
933
934 if ( end == count || m_itemsSel[end] > itemTo )
935 {
936 end--;
937 }
938
939 if ( start <= end )
940 {
941 // delete all of them (from end to avoid changing indices)
942 for ( int i = end; i >= (int)start; i-- )
943 {
944 m_itemsSel.RemoveAt(i);
945 }
946 }
947 }
948 }
949 else // "few" items change state
950 {
951 // just add the items to the selection
952 for ( size_t item = itemFrom; item <= itemTo; item++ )
953 {
954 SelectItem(item, select);
955 }
956 }
957}
958
959void wxSelectionStore::OnItemDelete(size_t item)
960{
961 size_t count = m_itemsSel.GetCount(),
962 i = m_itemsSel.IndexForInsert(item);
963
964 if ( i < count && m_itemsSel[i] == item )
965 {
966 // this item itself was in m_itemsSel, remove it from there
967 m_itemsSel.RemoveAt(i);
938b652b
VZ
968
969 count--;
b54e41c5
VZ
970 }
971
972 // and adjust the index of all which follow it
973 while ( i < count )
974 {
975 // all following elements must be greater than the one we deleted
976 wxASSERT_MSG( m_itemsSel[i] > item, _T("logic error") );
977
978 m_itemsSel[i++]--;
979 }
980}
981
c801d85f
KB
982//-----------------------------------------------------------------------------
983// wxListItemData
984//-----------------------------------------------------------------------------
985
cf1dfa6b 986void wxListItemData::Init()
c801d85f 987{
92976ab6
RR
988 m_image = -1;
989 m_data = 0;
cf1dfa6b 990
0530737d 991 m_attr = NULL;
e1e955e1 992}
c801d85f 993
cf1dfa6b 994wxListItemData::wxListItemData(wxListMainWindow *owner)
c801d85f 995{
cf1dfa6b 996 Init();
0530737d 997
cf1dfa6b
VZ
998 m_owner = owner;
999
1000 if ( owner->HasFlag(wxLC_REPORT) )
1001 {
1002 m_rect = NULL;
1003 }
1004 else
1005 {
1006 m_rect = new wxRect;
1007 }
e1e955e1 1008}
c801d85f
KB
1009
1010void wxListItemData::SetItem( const wxListItem &info )
1011{
cf1dfa6b 1012 if ( info.m_mask & wxLIST_MASK_TEXT )
54442116 1013 SetText(info.m_text);
cf1dfa6b 1014 if ( info.m_mask & wxLIST_MASK_IMAGE )
54442116 1015 m_image = info.m_image;
cf1dfa6b 1016 if ( info.m_mask & wxLIST_MASK_DATA )
54442116 1017 m_data = info.m_data;
0530737d
VZ
1018
1019 if ( info.HasAttributes() )
1020 {
1021 if ( m_attr )
1022 *m_attr = *info.GetAttributes();
1023 else
1024 m_attr = new wxListItemAttr(*info.GetAttributes());
1025 }
1026
cf1dfa6b
VZ
1027 if ( m_rect )
1028 {
1029 m_rect->x =
1030 m_rect->y =
1031 m_rect->height = 0;
1032 m_rect->width = info.m_width;
1033 }
e1e955e1 1034}
c801d85f 1035
debe6624 1036void wxListItemData::SetPosition( int x, int y )
c801d85f 1037{
cf1dfa6b
VZ
1038 wxCHECK_RET( m_rect, _T("unexpected SetPosition() call") );
1039
1040 m_rect->x = x;
1041 m_rect->y = y;
e1e955e1 1042}
c801d85f 1043
1e6d9499 1044void wxListItemData::SetSize( int width, int height )
c801d85f 1045{
cf1dfa6b 1046 wxCHECK_RET( m_rect, _T("unexpected SetSize() call") );
c801d85f 1047
cf1dfa6b
VZ
1048 if ( width != -1 )
1049 m_rect->width = width;
1050 if ( height != -1 )
1051 m_rect->height = height;
e1e955e1 1052}
c801d85f 1053
debe6624 1054bool wxListItemData::IsHit( int x, int y ) const
c801d85f 1055{
cf1dfa6b
VZ
1056 wxCHECK_MSG( m_rect, FALSE, _T("can't be called in this mode") );
1057
1058 return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x, y);
e1e955e1 1059}
c801d85f 1060
fd9811b1 1061int wxListItemData::GetX() const
c801d85f 1062{
cf1dfa6b
VZ
1063 wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
1064
1065 return m_rect->x;
e1e955e1 1066}
c801d85f 1067
fd9811b1 1068int wxListItemData::GetY() const
c801d85f 1069{
cf1dfa6b
VZ
1070 wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
1071
1072 return m_rect->y;
e1e955e1 1073}
c801d85f 1074
fd9811b1 1075int wxListItemData::GetWidth() const
c801d85f 1076{
cf1dfa6b
VZ
1077 wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
1078
1079 return m_rect->width;
e1e955e1 1080}
c801d85f 1081
fd9811b1 1082int wxListItemData::GetHeight() const
c801d85f 1083{
cf1dfa6b 1084 wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
c801d85f 1085
cf1dfa6b 1086 return m_rect->height;
e1e955e1 1087}
c801d85f 1088
0530737d 1089void wxListItemData::GetItem( wxListItem &info ) const
c801d85f 1090{
92976ab6
RR
1091 info.m_text = m_text;
1092 info.m_image = m_image;
1093 info.m_data = m_data;
c801d85f 1094
0530737d
VZ
1095 if ( m_attr )
1096 {
1097 if ( m_attr->HasTextColour() )
1098 info.SetTextColour(m_attr->GetTextColour());
1099 if ( m_attr->HasBackgroundColour() )
1100 info.SetBackgroundColour(m_attr->GetBackgroundColour());
1101 if ( m_attr->HasFont() )
1102 info.SetFont(m_attr->GetFont());
1103 }
e1e955e1 1104}
c801d85f
KB
1105
1106//-----------------------------------------------------------------------------
1107// wxListHeaderData
1108//-----------------------------------------------------------------------------
1109
1110IMPLEMENT_DYNAMIC_CLASS(wxListHeaderData,wxObject);
1111
fd9811b1 1112wxListHeaderData::wxListHeaderData()
c801d85f 1113{
92976ab6
RR
1114 m_mask = 0;
1115 m_image = 0;
1116 m_format = 0;
1117 m_width = 0;
1118 m_xpos = 0;
1119 m_ypos = 0;
1120 m_height = 0;
e1e955e1 1121}
c801d85f
KB
1122
1123wxListHeaderData::wxListHeaderData( const wxListItem &item )
1124{
92976ab6
RR
1125 SetItem( item );
1126 m_xpos = 0;
1127 m_ypos = 0;
1128 m_height = 0;
e1e955e1 1129}
c801d85f
KB
1130
1131void wxListHeaderData::SetItem( const wxListItem &item )
1132{
92976ab6
RR
1133 m_mask = item.m_mask;
1134 m_text = item.m_text;
1135 m_image = item.m_image;
1136 m_format = item.m_format;
cf1dfa6b
VZ
1137
1138 SetWidth(item.m_width);
e1e955e1 1139}
c801d85f 1140
debe6624 1141void wxListHeaderData::SetPosition( int x, int y )
c801d85f 1142{
92976ab6
RR
1143 m_xpos = x;
1144 m_ypos = y;
e1e955e1 1145}
c801d85f 1146
debe6624 1147void wxListHeaderData::SetHeight( int h )
c801d85f 1148{
92976ab6 1149 m_height = h;
e1e955e1 1150}
c801d85f 1151
debe6624 1152void wxListHeaderData::SetWidth( int w )
c801d85f 1153{
92976ab6 1154 m_width = w;
cf1dfa6b
VZ
1155 if (m_width < 0)
1156 m_width = WIDTH_COL_DEFAULT;
1157 if (m_width < WIDTH_COL_MIN)
1158 m_width = WIDTH_COL_MIN;
e1e955e1 1159}
c801d85f 1160
debe6624 1161void wxListHeaderData::SetFormat( int format )
c801d85f 1162{
92976ab6 1163 m_format = format;
e1e955e1 1164}
c801d85f 1165
fd9811b1 1166bool wxListHeaderData::HasImage() const
c801d85f 1167{
92976ab6 1168 return (m_image != 0);
e1e955e1 1169}
c801d85f 1170
c801d85f
KB
1171bool wxListHeaderData::IsHit( int x, int y ) const
1172{
92976ab6 1173 return ((x >= m_xpos) && (x <= m_xpos+m_width) && (y >= m_ypos) && (y <= m_ypos+m_height));
e1e955e1 1174}
c801d85f
KB
1175
1176void wxListHeaderData::GetItem( wxListItem &item )
1177{
92976ab6
RR
1178 item.m_mask = m_mask;
1179 item.m_text = m_text;
1180 item.m_image = m_image;
1181 item.m_format = m_format;
1182 item.m_width = m_width;
e1e955e1 1183}
c801d85f 1184
fd9811b1 1185int wxListHeaderData::GetImage() const
c801d85f 1186{
92976ab6 1187 return m_image;
e1e955e1 1188}
c801d85f 1189
fd9811b1 1190int wxListHeaderData::GetWidth() const
c801d85f 1191{
92976ab6 1192 return m_width;
e1e955e1 1193}
c801d85f 1194
fd9811b1 1195int wxListHeaderData::GetFormat() const
c801d85f 1196{
92976ab6 1197 return m_format;
e1e955e1 1198}
c801d85f
KB
1199
1200//-----------------------------------------------------------------------------
1201// wxListLineData
1202//-----------------------------------------------------------------------------
1203
cf1dfa6b
VZ
1204inline int wxListLineData::GetMode() const
1205{
b54e41c5 1206 return m_owner->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE;
cf1dfa6b 1207}
c801d85f 1208
cf1dfa6b 1209inline bool wxListLineData::InReportView() const
c801d85f 1210{
cf1dfa6b 1211 return m_owner->HasFlag(wxLC_REPORT);
e1e955e1 1212}
c801d85f 1213
b54e41c5 1214inline bool wxListLineData::IsVirtual() const
c801d85f 1215{
cf1dfa6b
VZ
1216 return m_owner->IsVirtual();
1217}
2c1f73ee 1218
5cd89174 1219wxListLineData::wxListLineData( wxListMainWindow *owner )
cf1dfa6b
VZ
1220{
1221 m_owner = owner;
1222 m_items.DeleteContents( TRUE );
2c1f73ee 1223
cf1dfa6b
VZ
1224 if ( InReportView() )
1225 {
1226 m_gi = NULL;
1227 }
1228 else // !report
1229 {
1230 m_gi = new GeometryInfo;
1231 }
f6bcfd97 1232
b54e41c5 1233 m_highlighted = FALSE;
f6bcfd97 1234
cf1dfa6b
VZ
1235 InitItems( GetMode() == wxLC_REPORT ? m_owner->GetColumnCount() : 1 );
1236}
f6bcfd97 1237
cf1dfa6b
VZ
1238void wxListLineData::CalculateSize( wxDC *dc, int spacing )
1239{
1240 wxListItemDataList::Node *node = m_items.GetFirst();
1241 wxCHECK_RET( node, _T("no subitems at all??") );
1242
1243 wxListItemData *item = node->GetData();
1244
1245 switch ( GetMode() )
1246 {
1247 case wxLC_ICON:
1248 case wxLC_SMALL_ICON:
1249 {
1250 m_gi->m_rectAll.width = spacing;
1251
1252 wxString s = item->GetText();
1253
1254 wxCoord lw, lh;
1255 if ( s.empty() )
5d25c050 1256 {
cf1dfa6b
VZ
1257 lh =
1258 m_gi->m_rectLabel.width =
1259 m_gi->m_rectLabel.height = 0;
5d25c050 1260 }
cf1dfa6b
VZ
1261 else // has label
1262 {
1263 dc->GetTextExtent( s, &lw, &lh );
1264 if (lh < SCROLL_UNIT_Y)
1265 lh = SCROLL_UNIT_Y;
1266 lw += EXTRA_WIDTH;
1267 lh += EXTRA_HEIGHT;
1268
1269 m_gi->m_rectAll.height = spacing + lh;
1270 if (lw > spacing)
1271 m_gi->m_rectAll.width = lw;
1272
1273 m_gi->m_rectLabel.width = lw;
1274 m_gi->m_rectLabel.height = lh;
1275 }
1276
1277 if (item->HasImage())
1278 {
1279 int w, h;
1280 m_owner->GetImageSize( item->GetImage(), w, h );
1281 m_gi->m_rectIcon.width = w + 8;
1282 m_gi->m_rectIcon.height = h + 8;
1283
1284 if ( m_gi->m_rectIcon.width > m_gi->m_rectAll.width )
1285 m_gi->m_rectAll.width = m_gi->m_rectIcon.width;
1286 if ( m_gi->m_rectIcon.height + lh > m_gi->m_rectAll.height - 4 )
1287 m_gi->m_rectAll.height = m_gi->m_rectIcon.height + lh + 4;
1288 }
1289
1290 if ( item->HasText() )
5d25c050 1291 {
b54e41c5
VZ
1292 m_gi->m_rectHighlight.width = m_gi->m_rectLabel.width;
1293 m_gi->m_rectHighlight.height = m_gi->m_rectLabel.height;
cf1dfa6b
VZ
1294 }
1295 else // no text, highlight the icon
1296 {
b54e41c5
VZ
1297 m_gi->m_rectHighlight.width = m_gi->m_rectIcon.width;
1298 m_gi->m_rectHighlight.height = m_gi->m_rectIcon.height;
5d25c050 1299 }
92976ab6
RR
1300 }
1301 break;
cf1dfa6b 1302
92976ab6 1303 case wxLC_LIST:
92976ab6 1304 {
cf1dfa6b 1305 wxString s = item->GetTextForMeasuring();
2c1f73ee 1306
13111b2a 1307 wxCoord lw,lh;
92976ab6 1308 dc->GetTextExtent( s, &lw, &lh );
cf1dfa6b
VZ
1309 if (lh < SCROLL_UNIT_Y)
1310 lh = SCROLL_UNIT_Y;
1311 lw += EXTRA_WIDTH;
1312 lh += EXTRA_HEIGHT;
2c1f73ee 1313
cf1dfa6b
VZ
1314 m_gi->m_rectLabel.width = lw;
1315 m_gi->m_rectLabel.height = lh;
f6bcfd97 1316
cf1dfa6b
VZ
1317 m_gi->m_rectAll.width = lw;
1318 m_gi->m_rectAll.height = lh;
f6bcfd97 1319
0b855868
RR
1320 if (item->HasImage())
1321 {
cf1dfa6b 1322 int w, h;
0b855868 1323 m_owner->GetImageSize( item->GetImage(), w, h );
cf1dfa6b
VZ
1324 m_gi->m_rectIcon.width = w;
1325 m_gi->m_rectIcon.height = h;
f6bcfd97 1326
cf1dfa6b
VZ
1327 m_gi->m_rectAll.width += 4 + w;
1328 if (h > m_gi->m_rectAll.height)
1329 m_gi->m_rectAll.height = h;
bffa1c77 1330 }
f6bcfd97 1331
b54e41c5
VZ
1332 m_gi->m_rectHighlight.width = m_gi->m_rectAll.width;
1333 m_gi->m_rectHighlight.height = m_gi->m_rectAll.height;
92976ab6
RR
1334 }
1335 break;
2c1f73ee 1336
cf1dfa6b
VZ
1337 case wxLC_REPORT:
1338 wxFAIL_MSG( _T("unexpected call to SetSize") );
92976ab6 1339 break;
cf1dfa6b
VZ
1340
1341 default:
1342 wxFAIL_MSG( _T("unknown mode") );
e1e955e1 1343 }
e1e955e1 1344}
c801d85f 1345
cf1dfa6b
VZ
1346void wxListLineData::SetPosition( int x, int y,
1347 int window_width,
1348 int spacing )
c801d85f 1349{
2c1f73ee 1350 wxListItemDataList::Node *node = m_items.GetFirst();
cf1dfa6b 1351 wxCHECK_RET( node, _T("no subitems at all??") );
2c1f73ee 1352
cf1dfa6b 1353 wxListItemData *item = node->GetData();
2c1f73ee 1354
cf1dfa6b 1355 switch ( GetMode() )
0b855868
RR
1356 {
1357 case wxLC_ICON:
cf1dfa6b
VZ
1358 case wxLC_SMALL_ICON:
1359 m_gi->m_rectAll.x = x;
1360 m_gi->m_rectAll.y = y;
1361
1362 if ( item->HasImage() )
0b855868 1363 {
cf1dfa6b
VZ
1364 m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 4
1365 + (spacing - m_gi->m_rectIcon.width)/2;
1366 m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 4;
0b855868 1367 }
cf1dfa6b
VZ
1368
1369 if ( item->HasText() )
0b855868 1370 {
cf1dfa6b
VZ
1371 if (m_gi->m_rectAll.width > spacing)
1372 m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 2;
5d25c050 1373 else
cf1dfa6b
VZ
1374 m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 2 + (spacing/2) - (m_gi->m_rectLabel.width/2);
1375 m_gi->m_rectLabel.y = m_gi->m_rectAll.y + m_gi->m_rectAll.height + 2 - m_gi->m_rectLabel.height;
b54e41c5
VZ
1376 m_gi->m_rectHighlight.x = m_gi->m_rectLabel.x - 2;
1377 m_gi->m_rectHighlight.y = m_gi->m_rectLabel.y - 2;
bffa1c77 1378 }
cf1dfa6b 1379 else // no text, highlight the icon
0b855868 1380 {
b54e41c5
VZ
1381 m_gi->m_rectHighlight.x = m_gi->m_rectIcon.x - 4;
1382 m_gi->m_rectHighlight.y = m_gi->m_rectIcon.y - 4;
bffa1c77 1383 }
0b855868 1384 break;
c801d85f 1385
cf1dfa6b
VZ
1386 case wxLC_LIST:
1387 m_gi->m_rectAll.x = x;
1388 m_gi->m_rectAll.y = y;
c801d85f 1389
b54e41c5
VZ
1390 m_gi->m_rectHighlight.x = m_gi->m_rectAll.x;
1391 m_gi->m_rectHighlight.y = m_gi->m_rectAll.y;
cf1dfa6b 1392 m_gi->m_rectLabel.y = m_gi->m_rectAll.y + 2;
c801d85f 1393
cf1dfa6b
VZ
1394 if (item->HasImage())
1395 {
1396 m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 2;
1397 m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 2;
1398 m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 6 + m_gi->m_rectIcon.width;
1399 }
1400 else
1401 {
1402 m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 2;
1403 }
1404 break;
c801d85f 1405
cf1dfa6b
VZ
1406 case wxLC_REPORT:
1407 wxFAIL_MSG( _T("unexpected call to SetPosition") );
1408 break;
c801d85f 1409
cf1dfa6b
VZ
1410 default:
1411 wxFAIL_MSG( _T("unknown mode") );
1412 }
e1e955e1 1413}
c801d85f 1414
debe6624 1415void wxListLineData::InitItems( int num )
c801d85f 1416{
2c1f73ee 1417 for (int i = 0; i < num; i++)
cf1dfa6b 1418 m_items.Append( new wxListItemData(m_owner) );
e1e955e1 1419}
c801d85f 1420
debe6624 1421void wxListLineData::SetItem( int index, const wxListItem &info )
c801d85f 1422{
2c1f73ee 1423 wxListItemDataList::Node *node = m_items.Item( index );
1370703e
VZ
1424 wxCHECK_RET( node, _T("invalid column index in SetItem") );
1425
1426 wxListItemData *item = node->GetData();
1427 item->SetItem( info );
e1e955e1 1428}
c801d85f 1429
1e6d9499 1430void wxListLineData::GetItem( int index, wxListItem &info )
c801d85f 1431{
2c1f73ee 1432 wxListItemDataList::Node *node = m_items.Item( index );
139adb6a
RR
1433 if (node)
1434 {
2c1f73ee 1435 wxListItemData *item = node->GetData();
139adb6a
RR
1436 item->GetItem( info );
1437 }
e1e955e1 1438}
c801d85f 1439
54442116 1440wxString wxListLineData::GetText(int index) const
c801d85f 1441{
54442116
VZ
1442 wxString s;
1443
2c1f73ee 1444 wxListItemDataList::Node *node = m_items.Item( index );
139adb6a
RR
1445 if (node)
1446 {
2c1f73ee 1447 wxListItemData *item = node->GetData();
54442116 1448 s = item->GetText();
139adb6a 1449 }
54442116
VZ
1450
1451 return s;
e1e955e1 1452}
c801d85f 1453
debe6624 1454void wxListLineData::SetText( int index, const wxString s )
c801d85f 1455{
2c1f73ee 1456 wxListItemDataList::Node *node = m_items.Item( index );
139adb6a
RR
1457 if (node)
1458 {
2c1f73ee 1459 wxListItemData *item = node->GetData();
139adb6a
RR
1460 item->SetText( s );
1461 }
e1e955e1 1462}
c801d85f 1463
cf1dfa6b 1464void wxListLineData::SetImage( int index, int image )
c801d85f 1465{
2c1f73ee 1466 wxListItemDataList::Node *node = m_items.Item( index );
cf1dfa6b
VZ
1467 wxCHECK_RET( node, _T("invalid column index in SetImage()") );
1468
1469 wxListItemData *item = node->GetData();
1470 item->SetImage(image);
1471}
1472
1473int wxListLineData::GetImage( int index ) const
1474{
1475 wxListItemDataList::Node *node = m_items.Item( index );
1476 wxCHECK_MSG( node, -1, _T("invalid column index in GetImage()") );
1477
1478 wxListItemData *item = node->GetData();
1479 return item->GetImage();
e1e955e1 1480}
c801d85f 1481
6c02c329
VZ
1482wxListItemAttr *wxListLineData::GetAttr() const
1483{
1484 wxListItemDataList::Node *node = m_items.GetFirst();
1485 wxCHECK_MSG( node, NULL, _T("invalid column index in GetAttr()") );
1486
1487 wxListItemData *item = node->GetData();
1488 return item->GetAttr();
1489}
1490
1491void wxListLineData::SetAttr(wxListItemAttr *attr)
1492{
1493 wxListItemDataList::Node *node = m_items.GetFirst();
1494 wxCHECK_RET( node, _T("invalid column index in SetAttr()") );
1495
1496 wxListItemData *item = node->GetData();
1497 item->SetAttr(attr);
1498}
1499
0530737d
VZ
1500void wxListLineData::SetAttributes(wxDC *dc,
1501 const wxListItemAttr *attr,
1502 const wxColour& colText,
470caaf9 1503 const wxFont& font,
b54e41c5 1504 bool highlight)
0530737d 1505{
470caaf9
VZ
1506 // don't use foregroud colour for drawing highlighted items - this might
1507 // make them completely invisible (and there is no way to do bit
1508 // arithmetics on wxColour, unfortunately)
b54e41c5 1509 if ( !highlight && attr && attr->HasTextColour() )
0530737d
VZ
1510 {
1511 dc->SetTextForeground(attr->GetTextColour());
1512 }
1513 else
1514 {
1515 dc->SetTextForeground(colText);
1516 }
1517
1518 if ( attr && attr->HasFont() )
1519 {
1520 dc->SetFont(attr->GetFont());
1521 }
1522 else
1523 {
1524 dc->SetFont(font);
1525 }
1526}
1527
5cd89174
VZ
1528void wxListLineData::Draw( wxDC *dc )
1529{
1530 wxListItemDataList::Node *node = m_items.GetFirst();
1531 wxCHECK_RET( node, _T("no subitems at all??") );
1532
1533 wxListItemData *item = node->GetData();
1534 if (item->HasImage())
1535 {
1536 wxRect rectIcon = m_gi->m_rectIcon;
1537 m_owner->DrawImage( item->GetImage(), dc,
1538 rectIcon.x, rectIcon.y );
1539 }
1540
1541 if (item->HasText())
1542 {
1543 wxRect rectLabel = m_gi->m_rectLabel;
1544 dc->DrawText( item->GetText(), rectLabel.x, rectLabel.y );
1545 }
1546}
1547
1548void wxListLineData::DrawInReportMode( wxDC *dc,
938b652b 1549 const wxRect& rect,
5cd89174
VZ
1550 const wxRect& rectHL,
1551 bool highlighted )
c801d85f 1552{
cf1dfa6b 1553 // use our own flag if we maintain it
5cd89174 1554 if ( !IsVirtual() )
b54e41c5 1555 highlighted = m_highlighted;
cf1dfa6b 1556
0530737d 1557 // default foreground colour
5cd89174 1558 wxWindow *listctrl = m_owner->GetParent();
0530737d 1559 wxColour colText;
b54e41c5 1560 if ( highlighted )
0530737d
VZ
1561 {
1562 colText = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT );
1563 }
1564 else
1565 {
1566 colText = listctrl->GetForegroundColour();
1567 }
1568
1569 // default font
1570 wxFont font = listctrl->GetFont();
1571
6c02c329
VZ
1572 // TODO: later we should support setting different attributes for
1573 // different columns - to do it, just add "col" argument to
1574 // GetAttr() and move this code into the loop below
1575 wxListItemAttr *attr = GetAttr();
b54e41c5 1576 SetAttributes(dc, attr, colText, font, highlighted);
0530737d
VZ
1577
1578 bool hasBgCol = attr && attr->HasBackgroundColour();
b54e41c5 1579 if ( highlighted || hasBgCol )
c801d85f 1580 {
b54e41c5 1581 if ( highlighted )
63852e78 1582 {
b54e41c5 1583 dc->SetBrush( *m_owner->m_highlightBrush );
63852e78
RR
1584 }
1585 else
1586 {
0530737d
VZ
1587 if ( hasBgCol )
1588 dc->SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
1589 else
1590 dc->SetBrush( * wxWHITE_BRUSH );
63852e78 1591 }
0530737d
VZ
1592
1593 dc->SetPen( * wxTRANSPARENT_PEN );
5cd89174 1594 dc->DrawRectangle( rectHL );
e1e955e1 1595 }
004fd0c8 1596
2c1f73ee 1597 wxListItemDataList::Node *node = m_items.GetFirst();
5cd89174 1598 wxCHECK_RET( node, _T("no subitems at all??") );
2c1f73ee 1599
5cd89174 1600 size_t col = 0;
938b652b
VZ
1601 wxCoord x = rect.x + HEADER_OFFSET_X,
1602 y = rect.y + (LINE_SPACING + EXTRA_HEIGHT) / 2;
cf1dfa6b 1603
5cd89174
VZ
1604 while ( node )
1605 {
1606 wxListItemData *item = node->GetData();
cf1dfa6b 1607
5cd89174 1608 int xOld = x;
cf1dfa6b 1609
5cd89174
VZ
1610 if ( item->HasImage() )
1611 {
1612 int ix, iy;
938b652b 1613 m_owner->DrawImage( item->GetImage(), dc, x, y );
5cd89174
VZ
1614 m_owner->GetImageSize( item->GetImage(), ix, iy );
1615 x += ix + 5; // FIXME: what is "5"?
1616 }
cf1dfa6b 1617
5cd89174 1618 int width = m_owner->GetColumnWidth(col++);
cf1dfa6b 1619
938b652b 1620 wxDCClipper clipper(*dc, x, y, width, rect.height);
cf1dfa6b 1621
5cd89174
VZ
1622 if ( item->HasText() )
1623 {
938b652b 1624 dc->DrawText( item->GetText(), x, y );
5cd89174 1625 }
cf1dfa6b 1626
5cd89174 1627 x = xOld + width;
cf1dfa6b 1628
5cd89174 1629 node = node->GetNext();
e1e955e1 1630 }
e1e955e1 1631}
c801d85f 1632
b54e41c5 1633bool wxListLineData::Highlight( bool on )
c801d85f 1634{
b54e41c5 1635 wxCHECK_MSG( !m_owner->IsVirtual(), FALSE, _T("unexpected call to Highlight") );
c801d85f 1636
b54e41c5 1637 if ( on == m_highlighted )
cf1dfa6b 1638 return FALSE;
c801d85f 1639
b54e41c5 1640 m_highlighted = on;
c801d85f 1641
cf1dfa6b 1642 return TRUE;
e1e955e1 1643}
c801d85f 1644
b54e41c5 1645void wxListLineData::ReverseHighlight( void )
c801d85f 1646{
b54e41c5 1647 Highlight(!IsHighlighted());
e1e955e1 1648}
c801d85f
KB
1649
1650//-----------------------------------------------------------------------------
1651// wxListHeaderWindow
1652//-----------------------------------------------------------------------------
1653
1654IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow,wxWindow);
1655
1656BEGIN_EVENT_TABLE(wxListHeaderWindow,wxWindow)
63852e78
RR
1657 EVT_PAINT (wxListHeaderWindow::OnPaint)
1658 EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse)
1659 EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus)
c801d85f
KB
1660END_EVENT_TABLE()
1661
1662wxListHeaderWindow::wxListHeaderWindow( void )
1663{
63852e78
RR
1664 m_owner = (wxListMainWindow *) NULL;
1665 m_currentCursor = (wxCursor *) NULL;
1666 m_resizeCursor = (wxCursor *) NULL;
cfb50f14 1667 m_isDragging = FALSE;
e1e955e1 1668}
c801d85f 1669
bd8289c1 1670wxListHeaderWindow::wxListHeaderWindow( wxWindow *win, wxWindowID id, wxListMainWindow *owner,
debe6624
JS
1671 const wxPoint &pos, const wxSize &size,
1672 long style, const wxString &name ) :
c801d85f
KB
1673 wxWindow( win, id, pos, size, style, name )
1674{
63852e78 1675 m_owner = owner;
c801d85f 1676// m_currentCursor = wxSTANDARD_CURSOR;
63852e78
RR
1677 m_currentCursor = (wxCursor *) NULL;
1678 m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
cfb50f14 1679 m_isDragging = FALSE;
f6bcfd97
BP
1680 m_dirty = FALSE;
1681
cfb50f14 1682 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE ) );
e1e955e1 1683}
c801d85f 1684
a367b9b3
JS
1685wxListHeaderWindow::~wxListHeaderWindow( void )
1686{
63852e78 1687 delete m_resizeCursor;
a367b9b3
JS
1688}
1689
1e6d9499 1690void wxListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h )
c801d85f 1691{
3fb435df 1692#ifdef __WXGTK__
b54e41c5
VZ
1693 GtkStateType state = m_parent->IsEnabled() ? GTK_STATE_NORMAL
1694 : GTK_STATE_INSENSITIVE;
2c1f73ee 1695
3fb435df 1696 x = dc->XLOG2DEV( x );
2c1f73ee 1697
b54e41c5
VZ
1698 gtk_paint_box (m_wxwindow->style, GTK_PIZZA(m_wxwindow)->bin_window,
1699 state, GTK_SHADOW_OUT,
1700 (GdkRectangle*) NULL, m_wxwindow, "button",
1701 x-1, y-1, w+2, h+2);
4176fb7d
SC
1702#elif defined( __WXMAC__ )
1703 const int m_corner = 1;
1704
1705 dc->SetBrush( *wxTRANSPARENT_BRUSH );
1706
1707 dc->SetPen( wxPen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW ) , 1 , wxSOLID ) );
1708 dc->DrawLine( x+w-m_corner+1, y, x+w, y+h ); // right (outer)
1709 dc->DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer)
1710
1711 wxPen pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID );
1712
1713 dc->SetPen( pen );
1714 dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner)
1715 dc->DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner)
1716
1717 dc->SetPen( *wxWHITE_PEN );
1718 dc->DrawRectangle( x, y, w-m_corner+1, 1 ); // top (outer)
1719 dc->DrawRectangle( x, y, 1, h ); // left (outer)
1720 dc->DrawLine( x, y+h-1, x+1, y+h-1 );
1721 dc->DrawLine( x+w-1, y, x+w-1, y+1 );
b54e41c5 1722#else // !GTK, !Mac
63852e78 1723 const int m_corner = 1;
c801d85f 1724
63852e78 1725 dc->SetBrush( *wxTRANSPARENT_BRUSH );
c801d85f 1726
63852e78
RR
1727 dc->SetPen( *wxBLACK_PEN );
1728 dc->DrawLine( x+w-m_corner+1, y, x+w, y+h ); // right (outer)
17867d61 1729 dc->DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer)
bd8289c1 1730
63852e78 1731 wxPen pen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID );
004fd0c8 1732
63852e78
RR
1733 dc->SetPen( pen );
1734 dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner)
1735 dc->DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner)
bd8289c1 1736
63852e78
RR
1737 dc->SetPen( *wxWHITE_PEN );
1738 dc->DrawRectangle( x, y, w-m_corner+1, 1 ); // top (outer)
1739 dc->DrawRectangle( x, y, 1, h ); // left (outer)
1740 dc->DrawLine( x, y+h-1, x+1, y+h-1 );
1741 dc->DrawLine( x+w-1, y, x+w-1, y+1 );
3fb435df 1742#endif
e1e955e1 1743}
c801d85f 1744
f6bcfd97
BP
1745// shift the DC origin to match the position of the main window horz
1746// scrollbar: this allows us to always use logical coords
1747void wxListHeaderWindow::AdjustDC(wxDC& dc)
1748{
f6bcfd97
BP
1749 int xpix;
1750 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1751
1752 int x;
1753 m_owner->GetViewStart( &x, NULL );
1754
1755 // account for the horz scrollbar offset
1756 dc.SetDeviceOrigin( -x * xpix, 0 );
f6bcfd97
BP
1757}
1758
c801d85f
KB
1759void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1760{
10bd0724
JS
1761#ifdef __WXGTK__
1762 wxClientDC dc( this );
1763#else
63852e78 1764 wxPaintDC dc( this );
10bd0724
JS
1765#endif
1766
63852e78 1767 PrepareDC( dc );
f6bcfd97 1768 AdjustDC( dc );
bffa1c77 1769
63852e78 1770 dc.BeginDrawing();
bd8289c1 1771
63852e78 1772 dc.SetFont( GetFont() );
bd8289c1 1773
f6bcfd97
BP
1774 // width and height of the entire header window
1775 int w, h;
63852e78 1776 GetClientSize( &w, &h );
f6bcfd97 1777 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
c801d85f 1778
f60d0f94 1779 dc.SetBackgroundMode(wxTRANSPARENT);
70846f0a
VZ
1780
1781 // do *not* use the listctrl colour for headers - one day we will have a
1782 // function to set it separately
37d403aa 1783 //dc.SetTextForeground( *wxBLACK );
cf1dfa6b
VZ
1784 dc.SetTextForeground(wxSystemSettings::
1785 GetSystemColour( wxSYS_COLOUR_WINDOWTEXT ));
1786
1787 int x = HEADER_OFFSET_X;
c801d85f 1788
63852e78
RR
1789 int numColumns = m_owner->GetColumnCount();
1790 wxListItem item;
1791 for (int i = 0; i < numColumns; i++)
1792 {
1793 m_owner->GetColumn( i, item );
f6bcfd97
BP
1794 int wCol = item.m_width;
1795 int cw = wCol - 2; // the width of the rect to draw
1796
1797 int xEnd = x + wCol;
1798
63852e78 1799 dc.SetPen( *wxWHITE_PEN );
c801d85f 1800
cf1dfa6b
VZ
1801 DoDrawRect( &dc, x, HEADER_OFFSET_Y, cw, h-2 );
1802 dc.SetClippingRegion( x, HEADER_OFFSET_Y, cw-5, h-4 );
1803 dc.DrawText( item.GetText(), x + EXTRA_WIDTH, HEADER_OFFSET_Y + EXTRA_HEIGHT );
40c70187 1804 dc.DestroyClippingRegion();
f6bcfd97
BP
1805 x += wCol;
1806
1807 if (xEnd > w+5)
1808 break;
63852e78
RR
1809 }
1810 dc.EndDrawing();
e1e955e1 1811}
c801d85f 1812
0208334d
RR
1813void wxListHeaderWindow::DrawCurrent()
1814{
63852e78
RR
1815 int x1 = m_currentX;
1816 int y1 = 0;
f6bcfd97
BP
1817 ClientToScreen( &x1, &y1 );
1818
63852e78
RR
1819 int x2 = m_currentX-1;
1820 int y2 = 0;
f6bcfd97 1821 m_owner->GetClientSize( NULL, &y2 );
63852e78 1822 m_owner->ClientToScreen( &x2, &y2 );
0208334d 1823
63852e78 1824 wxScreenDC dc;
3c679789 1825 dc.SetLogicalFunction( wxINVERT );
63852e78
RR
1826 dc.SetPen( wxPen( *wxBLACK, 2, wxSOLID ) );
1827 dc.SetBrush( *wxTRANSPARENT_BRUSH );
0208334d 1828
f6bcfd97
BP
1829 AdjustDC(dc);
1830
63852e78 1831 dc.DrawLine( x1, y1, x2, y2 );
0208334d 1832
63852e78 1833 dc.SetLogicalFunction( wxCOPY );
0208334d 1834
63852e78
RR
1835 dc.SetPen( wxNullPen );
1836 dc.SetBrush( wxNullBrush );
0208334d
RR
1837}
1838
c801d85f
KB
1839void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
1840{
f6bcfd97 1841 // we want to work with logical coords
3ca6a5f0
BP
1842 int x;
1843 m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
3ca6a5f0 1844 int y = event.GetY();
f6bcfd97 1845
cfb50f14 1846 if (m_isDragging)
0208334d 1847 {
f6bcfd97
BP
1848 // we don't draw the line beyond our window, but we allow dragging it
1849 // there
1850 int w = 0;
1851 GetClientSize( &w, NULL );
f6bcfd97 1852 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
f6bcfd97
BP
1853 w -= 6;
1854
1855 // erase the line if it was drawn
1856 if ( m_currentX < w )
1857 DrawCurrent();
1858
63852e78
RR
1859 if (event.ButtonUp())
1860 {
1861 ReleaseMouse();
cfb50f14 1862 m_isDragging = FALSE;
f6bcfd97
BP
1863 m_dirty = TRUE;
1864 m_owner->SetColumnWidth( m_column, m_currentX - m_minX );
63852e78
RR
1865 }
1866 else
1867 {
f6bcfd97 1868 if (x > m_minX + 7)
63852e78
RR
1869 m_currentX = x;
1870 else
f6bcfd97 1871 m_currentX = m_minX + 7;
bd8289c1 1872
f6bcfd97
BP
1873 // draw in the new location
1874 if ( m_currentX < w )
1875 DrawCurrent();
bffa1c77 1876 }
0208334d 1877 }
f6bcfd97 1878 else // not dragging
c801d85f 1879 {
f6bcfd97
BP
1880 m_minX = 0;
1881 bool hit_border = FALSE;
1882
1883 // end of the current column
1884 int xpos = 0;
1885
1886 // find the column where this event occured
1887 int countCol = m_owner->GetColumnCount();
cf1dfa6b 1888 for (int col = 0; col < countCol; col++)
bffa1c77 1889 {
cf1dfa6b
VZ
1890 xpos += m_owner->GetColumnWidth( col );
1891 m_column = col;
f6bcfd97
BP
1892
1893 if ( (abs(x-xpos) < 3) && (y < 22) )
1894 {
1895 // near the column border
1896 hit_border = TRUE;
1897 break;
1898 }
1899
1900 if ( x < xpos )
1901 {
1902 // inside the column
1903 break;
1904 }
1905
1906 m_minX = xpos;
bffa1c77 1907 }
63852e78 1908
f6bcfd97 1909 if (event.LeftDown())
63852e78 1910 {
f6bcfd97
BP
1911 if (hit_border)
1912 {
1913 m_isDragging = TRUE;
1914 m_currentX = x;
1915 DrawCurrent();
1916 CaptureMouse();
1917 }
1918 else
1919 {
1920 wxWindow *parent = GetParent();
1921 wxListEvent le( wxEVT_COMMAND_LIST_COL_CLICK, parent->GetId() );
1922 le.SetEventObject( parent );
1923 le.m_col = m_column;
1924 parent->GetEventHandler()->ProcessEvent( le );
1925 }
63852e78 1926 }
f6bcfd97 1927 else if (event.Moving())
63852e78 1928 {
f6bcfd97
BP
1929 bool setCursor;
1930 if (hit_border)
1931 {
1932 setCursor = m_currentCursor == wxSTANDARD_CURSOR;
1933 m_currentCursor = m_resizeCursor;
1934 }
1935 else
1936 {
1937 setCursor = m_currentCursor != wxSTANDARD_CURSOR;
1938 m_currentCursor = wxSTANDARD_CURSOR;
1939 }
1940
1941 if ( setCursor )
1942 SetCursor(*m_currentCursor);
63852e78 1943 }
e1e955e1 1944 }
e1e955e1 1945}
c801d85f
KB
1946
1947void wxListHeaderWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
1948{
63852e78 1949 m_owner->SetFocus();
e1e955e1 1950}
c801d85f
KB
1951
1952//-----------------------------------------------------------------------------
1953// wxListRenameTimer (internal)
1954//-----------------------------------------------------------------------------
1955
bd8289c1
VZ
1956wxListRenameTimer::wxListRenameTimer( wxListMainWindow *owner )
1957{
63852e78 1958 m_owner = owner;
e1e955e1 1959}
c801d85f 1960
bd8289c1
VZ
1961void wxListRenameTimer::Notify()
1962{
63852e78 1963 m_owner->OnRenameTimer();
e1e955e1 1964}
c801d85f 1965
ee7ee469
RR
1966//-----------------------------------------------------------------------------
1967// wxListTextCtrl (internal)
1968//-----------------------------------------------------------------------------
1969
1970IMPLEMENT_DYNAMIC_CLASS(wxListTextCtrl,wxTextCtrl);
bd8289c1 1971
ee7ee469 1972BEGIN_EVENT_TABLE(wxListTextCtrl,wxTextCtrl)
63852e78 1973 EVT_CHAR (wxListTextCtrl::OnChar)
2c1f73ee 1974 EVT_KEY_UP (wxListTextCtrl::OnKeyUp)
63852e78 1975 EVT_KILL_FOCUS (wxListTextCtrl::OnKillFocus)
ee7ee469
RR
1976END_EVENT_TABLE()
1977
674ac8b9
VZ
1978wxListTextCtrl::wxListTextCtrl( wxWindow *parent,
1979 const wxWindowID id,
1980 bool *accept,
1981 wxString *res,
1982 wxListMainWindow *owner,
1983 const wxString &value,
1984 const wxPoint &pos,
1985 const wxSize &size,
1986 int style,
1987 const wxValidator& validator,
1988 const wxString &name )
1989 : wxTextCtrl( parent, id, value, pos, size, style, validator, name )
ee7ee469 1990{
63852e78
RR
1991 m_res = res;
1992 m_accept = accept;
1993 m_owner = owner;
5f1ea0ee
RR
1994 (*m_accept) = FALSE;
1995 (*m_res) = "";
1996 m_startValue = value;
ee7ee469
RR
1997}
1998
1999void wxListTextCtrl::OnChar( wxKeyEvent &event )
2000{
63852e78
RR
2001 if (event.m_keyCode == WXK_RETURN)
2002 {
2003 (*m_accept) = TRUE;
2004 (*m_res) = GetValue();
f6bcfd97 2005
bce1406b
RR
2006 if (!wxPendingDelete.Member(this))
2007 wxPendingDelete.Append(this);
2008
2009 if ((*m_accept) && ((*m_res) != m_startValue))
2010 m_owner->OnRenameAccept();
f6bcfd97 2011
63852e78
RR
2012 return;
2013 }
2014 if (event.m_keyCode == WXK_ESCAPE)
2015 {
2016 (*m_accept) = FALSE;
2017 (*m_res) = "";
f6bcfd97 2018
bce1406b
RR
2019 if (!wxPendingDelete.Member(this))
2020 wxPendingDelete.Append(this);
f6bcfd97 2021
63852e78
RR
2022 return;
2023 }
f6bcfd97 2024
63852e78
RR
2025 event.Skip();
2026}
2027
c13cace1
VS
2028void wxListTextCtrl::OnKeyUp( wxKeyEvent &event )
2029{
2030 // auto-grow the textctrl:
2031 wxSize parentSize = m_owner->GetSize();
2032 wxPoint myPos = GetPosition();
2033 wxSize mySize = GetSize();
2034 int sx, sy;
cf1dfa6b
VZ
2035 GetTextExtent(GetValue() + _T("MM"), &sx, &sy); // FIXME: MM??
2036 if (myPos.x + sx > parentSize.x)
2037 sx = parentSize.x - myPos.x;
2038 if (mySize.x > sx)
2039 sx = mySize.x;
c13cace1 2040 SetSize(sx, -1);
2c1f73ee 2041
c13cace1
VS
2042 event.Skip();
2043}
2044
63852e78
RR
2045void wxListTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
2046{
bce1406b
RR
2047 if (!wxPendingDelete.Member(this))
2048 wxPendingDelete.Append(this);
004fd0c8 2049
5f1ea0ee
RR
2050 if ((*m_accept) && ((*m_res) != m_startValue))
2051 m_owner->OnRenameAccept();
ee7ee469
RR
2052}
2053
c801d85f
KB
2054//-----------------------------------------------------------------------------
2055// wxListMainWindow
2056//-----------------------------------------------------------------------------
2057
2058IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow,wxScrolledWindow);
bd8289c1 2059
c801d85f
KB
2060BEGIN_EVENT_TABLE(wxListMainWindow,wxScrolledWindow)
2061 EVT_PAINT (wxListMainWindow::OnPaint)
c801d85f
KB
2062 EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse)
2063 EVT_CHAR (wxListMainWindow::OnChar)
3dfb93fd 2064 EVT_KEY_DOWN (wxListMainWindow::OnKeyDown)
c801d85f
KB
2065 EVT_SET_FOCUS (wxListMainWindow::OnSetFocus)
2066 EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus)
2fa7c206 2067 EVT_SCROLLWIN (wxListMainWindow::OnScroll)
c801d85f
KB
2068END_EVENT_TABLE()
2069
1370703e 2070void wxListMainWindow::Init()
c801d85f 2071{
139adb6a 2072 m_columns.DeleteContents( TRUE );
139adb6a 2073 m_dirty = TRUE;
cf1dfa6b
VZ
2074 m_countVirt = 0;
2075 m_lineFrom =
b54e41c5 2076 m_lineTo = (size_t)-1;
cf1dfa6b
VZ
2077 m_linesPerPage = 0;
2078
2079 m_headerWidth =
2080 m_lineHeight = 0;
1370703e 2081
139adb6a
RR
2082 m_small_image_list = (wxImageList *) NULL;
2083 m_normal_image_list = (wxImageList *) NULL;
1370703e 2084
139adb6a
RR
2085 m_small_spacing = 30;
2086 m_normal_spacing = 40;
1370703e 2087
139adb6a 2088 m_hasFocus = FALSE;
1370703e
VZ
2089 m_dragCount = 0;
2090 m_isCreated = FALSE;
2091
139adb6a
RR
2092 m_lastOnSame = FALSE;
2093 m_renameTimer = new wxListRenameTimer( this );
1370703e
VZ
2094 m_renameAccept = FALSE;
2095
cf1dfa6b
VZ
2096 m_current =
2097 m_currentEdit =
efbb7287 2098 m_lineLastClicked =
1370703e 2099 m_lineBeforeLastClicked = (size_t)-1;
e1e955e1 2100}
c801d85f 2101
cf1dfa6b
VZ
2102void wxListMainWindow::InitScrolling()
2103{
2104 if ( HasFlag(wxLC_REPORT) )
2105 {
2106 m_xScroll = SCROLL_UNIT_X;
2107 m_yScroll = SCROLL_UNIT_Y;
2108 }
2109 else
2110 {
2111 m_xScroll = SCROLL_UNIT_Y;
2112 m_yScroll = 0;
2113 }
2114}
2115
1370703e 2116wxListMainWindow::wxListMainWindow()
c801d85f 2117{
1370703e
VZ
2118 Init();
2119
b54e41c5 2120 m_highlightBrush = (wxBrush *) NULL;
1370703e
VZ
2121
2122 m_xScroll =
2123 m_yScroll = 0;
2124}
2125
2126wxListMainWindow::wxListMainWindow( wxWindow *parent,
2127 wxWindowID id,
2128 const wxPoint& pos,
2129 const wxSize& size,
2130 long style,
2131 const wxString &name )
2132 : wxScrolledWindow( parent, id, pos, size,
2133 style | wxHSCROLL | wxVSCROLL, name )
2134{
2135 Init();
2136
b54e41c5 2137 m_highlightBrush = new wxBrush( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT), wxSOLID );
139adb6a
RR
2138 wxSize sz = size;
2139 sz.y = 25;
bd8289c1 2140
cf1dfa6b 2141 InitScrolling();
139adb6a 2142 SetScrollbars( m_xScroll, m_yScroll, 0, 0, 0, 0 );
bd8289c1 2143
91fc2bdc 2144 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX ) );
e1e955e1 2145}
c801d85f 2146
fd9811b1 2147wxListMainWindow::~wxListMainWindow()
c801d85f 2148{
12c1b46a
RR
2149 DeleteEverything();
2150
b54e41c5 2151 delete m_highlightBrush;
004fd0c8 2152
139adb6a 2153 delete m_renameTimer;
e1e955e1 2154}
c801d85f 2155
cf1dfa6b 2156void wxListMainWindow::CacheLineData(size_t line)
c801d85f 2157{
cf1dfa6b 2158 wxListCtrl *listctrl = GetListCtrl();
25e3a937 2159
b54e41c5 2160 wxListLineData *ld = GetDummyLine();
f6bcfd97 2161
cf1dfa6b
VZ
2162 size_t countCol = GetColumnCount();
2163 for ( size_t col = 0; col < countCol; col++ )
2164 {
2165 ld->SetText(col, listctrl->OnGetItemText(line, col));
2166 }
2167
5cd89174 2168 ld->SetImage(listctrl->OnGetItemImage(line));
6c02c329 2169 ld->SetAttr(listctrl->OnGetItemAttr(line));
e1e955e1 2170}
c801d85f 2171
b54e41c5 2172wxListLineData *wxListMainWindow::GetDummyLine() const
c801d85f 2173{
cf1dfa6b 2174 wxASSERT_MSG( !IsEmpty(), _T("invalid line index") );
2c1f73ee 2175
cf1dfa6b 2176 if ( m_lines.IsEmpty() )
2c1f73ee 2177 {
cf1dfa6b
VZ
2178 // normal controls are supposed to have something in m_lines
2179 // already if it's not empty
2180 wxASSERT_MSG( IsVirtual(), _T("logic error") );
2181
2182 wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
5cd89174 2183 wxListLineData *line = new wxListLineData(self);
cf1dfa6b 2184 self->m_lines.Add(line);
2c1f73ee
VZ
2185 }
2186
cf1dfa6b
VZ
2187 return &m_lines[0];
2188}
2189
5cd89174
VZ
2190// ----------------------------------------------------------------------------
2191// line geometry (report mode only)
2192// ----------------------------------------------------------------------------
2193
cf1dfa6b
VZ
2194wxCoord wxListMainWindow::GetLineHeight() const
2195{
2196 wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("only works in report mode") );
673dfcfa 2197
cf1dfa6b
VZ
2198 // we cache the line height as calling GetTextExtent() is slow
2199 if ( !m_lineHeight )
2c1f73ee 2200 {
cf1dfa6b 2201 wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
bd8289c1 2202
cf1dfa6b
VZ
2203 wxClientDC dc( self );
2204 dc.SetFont( GetFont() );
c801d85f 2205
cf1dfa6b
VZ
2206 wxCoord y;
2207 dc.GetTextExtent(_T("H"), NULL, &y);
004fd0c8 2208
cf1dfa6b
VZ
2209 if ( y < SCROLL_UNIT_Y )
2210 y = SCROLL_UNIT_Y;
2211 y += EXTRA_HEIGHT;
206b0a67 2212
cf1dfa6b
VZ
2213 self->m_lineHeight = y + LINE_SPACING;
2214 }
bffa1c77 2215
cf1dfa6b
VZ
2216 return m_lineHeight;
2217}
bffa1c77 2218
cf1dfa6b
VZ
2219wxCoord wxListMainWindow::GetLineY(size_t line) const
2220{
2221 wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("only works in report mode") );
1370703e 2222
cf1dfa6b
VZ
2223 return LINE_SPACING + line*GetLineHeight();
2224}
206b0a67 2225
5cd89174
VZ
2226wxRect wxListMainWindow::GetLineRect(size_t line) const
2227{
2228 if ( !InReportView() )
2229 return GetLine(line)->m_gi->m_rectAll;
2230
2231 wxRect rect;
2232 rect.x = HEADER_OFFSET_X;
2233 rect.y = GetLineY(line);
2234 rect.width = GetHeaderWidth();
2235 rect.height = GetLineHeight();
2236
2237 return rect;
2238}
2239
2240wxRect wxListMainWindow::GetLineLabelRect(size_t line) const
2241{
2242 if ( !InReportView() )
2243 return GetLine(line)->m_gi->m_rectLabel;
2244
2245 wxRect rect;
2246 rect.x = HEADER_OFFSET_X;
2247 rect.y = GetLineY(line);
2248 rect.width = GetColumnWidth(0);
2249 rect.height = GetLineHeight();
2250
2251 return rect;
2252}
2253
2254wxRect wxListMainWindow::GetLineIconRect(size_t line) const
2255{
2256 if ( !InReportView() )
2257 return GetLine(line)->m_gi->m_rectIcon;
2258
2259 wxListLineData *ld = GetLine(line);
2260 wxASSERT_MSG( ld->HasImage(), _T("should have an image") );
2261
2262 wxRect rect;
2263 rect.x = HEADER_OFFSET_X;
2264 rect.y = GetLineY(line);
2265 GetImageSize(ld->GetImage(), rect.width, rect.height);
2266
2267 return rect;
2268}
2269
2270wxRect wxListMainWindow::GetLineHighlightRect(size_t line) const
2271{
2272 return InReportView() ? GetLineRect(line)
2273 : GetLine(line)->m_gi->m_rectHighlight;
2274}
2275
2276long wxListMainWindow::HitTestLine(size_t line, int x, int y) const
2277{
2278 wxListLineData *ld = GetLine(line);
2279
2280 if ( ld->HasImage() && GetLineIconRect(line).Inside(x, y) )
2281 return wxLIST_HITTEST_ONITEMICON;
2282
2283 if ( ld->HasText() )
2284 {
2285 wxRect rect = InReportView() ? GetLineRect(line)
2286 : GetLineLabelRect(line);
2287
2288 if ( rect.Inside(x, y) )
2289 return wxLIST_HITTEST_ONITEMLABEL;
2290 }
2291
2292 return 0;
2293}
2294
2295// ----------------------------------------------------------------------------
2296// highlight (selection) handling
2297// ----------------------------------------------------------------------------
2298
b54e41c5 2299bool wxListMainWindow::IsHighlighted(size_t line) const
cf1dfa6b
VZ
2300{
2301 if ( IsVirtual() )
2302 {
b54e41c5 2303 return m_selStore.IsSelected(line);
cf1dfa6b
VZ
2304 }
2305 else // !virtual
2306 {
2307 wxListLineData *ld = GetLine(line);
b54e41c5 2308 wxCHECK_MSG( ld, FALSE, _T("invalid index in IsHighlighted") );
cf1dfa6b 2309
b54e41c5 2310 return ld->IsHighlighted();
cf1dfa6b
VZ
2311 }
2312}
2313
b54e41c5 2314void wxListMainWindow::HighlightLines( size_t lineFrom, size_t lineTo, bool highlight )
cf1dfa6b 2315{
cf1dfa6b
VZ
2316 if ( IsVirtual() )
2317 {
b54e41c5
VZ
2318 m_selStore.SelectRange(lineFrom, lineTo, highlight);
2319 RefreshLines(lineFrom, lineTo);
2320 }
2321 else
2322 {
2323 // do it the dumb way
2324 bool needsRefresh = FALSE;
2325 for ( size_t line = lineFrom; line <= lineTo; line++ )
cf1dfa6b 2326 {
b54e41c5
VZ
2327 if ( HighlightLine(line, highlight) )
2328 needsRefresh = TRUE;
cf1dfa6b 2329 }
b54e41c5
VZ
2330
2331 if ( needsRefresh )
2332 RefreshLines(lineFrom, lineTo);
2333 }
2334}
2335
2336bool wxListMainWindow::HighlightLine( size_t line, bool highlight )
2337{
2338 bool changed;
2339
2340 if ( IsVirtual() )
2341 {
2342 changed = m_selStore.SelectItem(line, highlight);
cf1dfa6b
VZ
2343 }
2344 else // !virtual
2345 {
2346 wxListLineData *ld = GetLine(line);
b54e41c5 2347 wxCHECK_MSG( ld, FALSE, _T("invalid index in IsHighlighted") );
cf1dfa6b 2348
b54e41c5 2349 changed = ld->Highlight(highlight);
cf1dfa6b
VZ
2350 }
2351
2352 if ( changed )
2353 {
b54e41c5 2354 SendNotify( line, highlight ? wxEVT_COMMAND_LIST_ITEM_SELECTED
5cd89174 2355 : wxEVT_COMMAND_LIST_ITEM_DESELECTED );
cf1dfa6b
VZ
2356 }
2357
2358 return changed;
2359}
2360
2361void wxListMainWindow::RefreshLine( size_t line )
2362{
5cd89174 2363 wxRect rect = GetLineRect(line);
cf1dfa6b
VZ
2364
2365 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
2366 RefreshRect( rect );
2367}
2368
2369void wxListMainWindow::RefreshLines( size_t lineFrom, size_t lineTo )
2370{
2371 // we suppose that they are ordered by caller
2372 wxASSERT_MSG( lineFrom <= lineTo, _T("indices in disorder") );
2373
6b4a8d93
VZ
2374 wxASSERT_MSG( lineTo < GetItemCount(), _T("invalid line range") );
2375
cf1dfa6b
VZ
2376 if ( HasFlag(wxLC_REPORT) )
2377 {
b54e41c5
VZ
2378 size_t visibleFrom, visibleTo;
2379 GetVisibleLinesRange(&visibleFrom, &visibleTo);
2380
2381 if ( lineFrom < visibleFrom )
2382 lineFrom = visibleFrom;
2383 if ( lineTo > visibleTo )
2384 lineTo = visibleTo;
cf1dfa6b
VZ
2385
2386 wxRect rect;
2387 rect.x = 0;
2388 rect.y = GetLineY(lineFrom);
2389 rect.width = GetClientSize().x;
2390 rect.height = GetLineY(lineTo) - rect.y;
2391
2392 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
2393 RefreshRect( rect );
2394 }
2395 else // !report
2396 {
2397 // TODO: this should be optimized...
2398 for ( size_t line = lineFrom; line <= lineTo; line++ )
2399 {
2400 RefreshLine(line);
2401 }
2402 }
2403}
2404
6b4a8d93
VZ
2405void wxListMainWindow::RefreshAfter( size_t lineFrom )
2406{
2407 if ( HasFlag(wxLC_REPORT) )
2408 {
2409 size_t visibleFrom;
2410 GetVisibleLinesRange(&visibleFrom, NULL);
2411
2412 if ( lineFrom < visibleFrom )
2413 lineFrom = visibleFrom;
2414
2415 wxRect rect;
2416 rect.x = 0;
2417 rect.y = GetLineY(lineFrom);
2418
2419 wxSize size = GetClientSize();
2420 rect.width = size.x;
2421 // refresh till the bottom of the window
2422 rect.height = size.y - rect.y;
2423
2424 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
2425 RefreshRect( rect );
6b4a8d93
VZ
2426 }
2427 else // !report
2428 {
2429 // TODO: how to do it more efficiently?
2430 m_dirty = TRUE;
2431 }
2432}
2433
cf1dfa6b
VZ
2434void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
2435{
2436 // Note: a wxPaintDC must be constructed even if no drawing is
2437 // done (a Windows requirement).
2438 wxPaintDC dc( this );
2439
cf1dfa6b
VZ
2440 if ( IsEmpty() )
2441 {
2442 // empty control. nothing to draw
2443 return;
2444 }
2445
1e4d446b
VZ
2446 if ( m_dirty )
2447 {
2448 // delay the repainting until we calculate all the items positions
2449 return;
2450 }
2451
cf1dfa6b
VZ
2452 PrepareDC( dc );
2453
2454 int dev_x, dev_y;
2455 CalcScrolledPosition( 0, 0, &dev_x, &dev_y );
2456
2457 dc.BeginDrawing();
2458
2459 dc.SetFont( GetFont() );
2460
2461 if ( HasFlag(wxLC_REPORT) )
2462 {
b54e41c5 2463 int lineHeight = GetLineHeight();
cf1dfa6b 2464
b54e41c5
VZ
2465 size_t visibleFrom, visibleTo;
2466 GetVisibleLinesRange(&visibleFrom, &visibleTo);
b84839ae
VZ
2467
2468 wxRect rectLine;
2469 wxCoord xOrig, yOrig;
2470 CalcUnscrolledPosition(0, 0, &xOrig, &yOrig);
2471
b54e41c5 2472 for ( size_t line = visibleFrom; line <= visibleTo; line++ )
cf1dfa6b 2473 {
b84839ae
VZ
2474 rectLine = GetLineRect(line);
2475
2476 if ( !IsExposed(rectLine.x - xOrig, rectLine.y - yOrig,
2477 rectLine.width, rectLine.height) )
2478 {
2479 // don't redraw unaffected lines to avoid flicker
2480 continue;
2481 }
2482
6c02c329
VZ
2483 printf("Redrawing line %u\n", line);
2484
5cd89174 2485 GetLine(line)->DrawInReportMode( &dc,
b84839ae 2486 rectLine,
5cd89174
VZ
2487 GetLineHighlightRect(line),
2488 IsHighlighted(line) );
cf1dfa6b
VZ
2489 }
2490
2491 if ( HasFlag(wxLC_HRULES) )
2492 {
b54e41c5 2493 wxPen pen(GetRuleColour(), 1, wxSOLID);
cf1dfa6b
VZ
2494 wxSize clientSize = GetClientSize();
2495
b54e41c5 2496 for ( size_t i = visibleFrom; i <= visibleTo; i++ )
cf1dfa6b
VZ
2497 {
2498 dc.SetPen(pen);
2499 dc.SetBrush( *wxTRANSPARENT_BRUSH );
b54e41c5
VZ
2500 dc.DrawLine(0 - dev_x, i*lineHeight,
2501 clientSize.x - dev_x, i*lineHeight);
cf1dfa6b
VZ
2502 }
2503
2504 // Draw last horizontal rule
b54e41c5 2505 if ( visibleTo > visibleFrom )
cf1dfa6b
VZ
2506 {
2507 dc.SetPen(pen);
2508 dc.SetBrush( *wxTRANSPARENT_BRUSH );
b54e41c5
VZ
2509 dc.DrawLine(0 - dev_x, m_lineTo*lineHeight,
2510 clientSize.x - dev_x , m_lineTo*lineHeight );
cf1dfa6b 2511 }
2c1f73ee 2512 }
206b0a67
JS
2513
2514 // Draw vertical rules if required
cf1dfa6b 2515 if ( HasFlag(wxLC_VRULES) && !IsEmpty() )
206b0a67 2516 {
b54e41c5 2517 wxPen pen(GetRuleColour(), 1, wxSOLID);
cf1dfa6b 2518
206b0a67
JS
2519 int col = 0;
2520 wxRect firstItemRect;
2521 wxRect lastItemRect;
2522 GetItemRect(0, firstItemRect);
2523 GetItemRect(GetItemCount() - 1, lastItemRect);
2524 int x = firstItemRect.GetX();
673dfcfa
JS
2525 dc.SetPen(pen);
2526 dc.SetBrush(* wxTRANSPARENT_BRUSH);
206b0a67
JS
2527 for (col = 0; col < GetColumnCount(); col++)
2528 {
2529 int colWidth = GetColumnWidth(col);
cf1dfa6b
VZ
2530 x += colWidth;
2531 dc.DrawLine(x - dev_x, firstItemRect.GetY() - 1 - dev_y,
2532 x - dev_x, lastItemRect.GetBottom() + 1 - dev_y);
206b0a67 2533 }
d786bf87 2534 }
139adb6a 2535 }
cf1dfa6b 2536 else // !report
139adb6a 2537 {
1370703e 2538 size_t count = GetItemCount();
cf1dfa6b
VZ
2539 for ( size_t i = 0; i < count; i++ )
2540 {
2541 GetLine(i)->Draw( &dc );
2542 }
139adb6a 2543 }
004fd0c8 2544
cf1dfa6b
VZ
2545 if ( HasCurrent() && m_hasFocus )
2546 {
4176fb7d
SC
2547#ifdef __WXMAC__
2548 // no rect outline, we already have the background color
2549#else
cf1dfa6b
VZ
2550 dc.SetPen( *wxBLACK_PEN );
2551 dc.SetBrush( *wxTRANSPARENT_BRUSH );
5cd89174 2552 dc.DrawRectangle( GetLineHighlightRect(m_current) );
4176fb7d 2553#endif
cf1dfa6b 2554 }
c801d85f 2555
139adb6a 2556 dc.EndDrawing();
e1e955e1 2557}
c801d85f 2558
b54e41c5 2559void wxListMainWindow::HighlightAll( bool on )
c801d85f 2560{
b54e41c5 2561 if ( IsSingleSel() )
c801d85f 2562 {
b54e41c5
VZ
2563 wxASSERT_MSG( !on, _T("can't do this in a single sel control") );
2564
2565 // we just have one item to turn off
2566 if ( HasCurrent() && IsHighlighted(m_current) )
139adb6a 2567 {
b54e41c5
VZ
2568 HighlightLine(m_current, FALSE);
2569 RefreshLine(m_current);
139adb6a 2570 }
e1e955e1 2571 }
b54e41c5 2572 else // multi sel
cf1dfa6b 2573 {
b54e41c5 2574 HighlightLines(0, GetItemCount() - 1, on);
cf1dfa6b 2575 }
e1e955e1 2576}
c801d85f 2577
cf1dfa6b 2578void wxListMainWindow::SendNotify( size_t line,
05a7f61d
VZ
2579 wxEventType command,
2580 wxPoint point )
c801d85f 2581{
139adb6a
RR
2582 wxListEvent le( command, GetParent()->GetId() );
2583 le.SetEventObject( GetParent() );
cf1dfa6b 2584 le.m_itemIndex = line;
05a7f61d
VZ
2585
2586 // set only for events which have position
2587 if ( point != wxDefaultPosition )
2588 le.m_pointDrag = point;
2589
cf1dfa6b 2590 GetLine(line)->GetItem( 0, le.m_item );
6e228e42 2591 GetParent()->GetEventHandler()->ProcessEvent( le );
e1e955e1 2592}
c801d85f 2593
cf1dfa6b 2594void wxListMainWindow::OnFocusLine( size_t WXUNUSED(line) )
c801d85f
KB
2595{
2596// SendNotify( line, wxEVT_COMMAND_LIST_ITEM_FOCUSSED );
e1e955e1 2597}
c801d85f 2598
cf1dfa6b 2599void wxListMainWindow::OnUnfocusLine( size_t WXUNUSED(line) )
c801d85f
KB
2600{
2601// SendNotify( line, wxEVT_COMMAND_LIST_ITEM_UNFOCUSSED );
e1e955e1 2602}
c801d85f 2603
5f1ea0ee 2604void wxListMainWindow::EditLabel( long item )
c801d85f 2605{
cf1dfa6b
VZ
2606 wxCHECK_RET( (item >= 0) && ((size_t)item < GetItemCount()),
2607 wxT("wrong index in wxListCtrl::EditLabel()") );
004fd0c8 2608
1370703e 2609 m_currentEdit = (size_t)item;
e179bd65 2610
fd9811b1 2611 wxListEvent le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, GetParent()->GetId() );
139adb6a 2612 le.SetEventObject( GetParent() );
1370703e
VZ
2613 le.m_itemIndex = item;
2614 wxListLineData *data = GetLine(m_currentEdit);
2615 wxCHECK_RET( data, _T("invalid index in EditLabel()") );
2616 data->GetItem( 0, le.m_item );
139adb6a 2617 GetParent()->GetEventHandler()->ProcessEvent( le );
004fd0c8 2618
86f975a8 2619 if (!le.IsAllowed())
5f1ea0ee 2620 return;
004fd0c8 2621
cf1dfa6b
VZ
2622 // We have to call this here because the label in question might just have
2623 // been added and no screen update taken place.
2624 if (m_dirty)
2625 wxSafeYield();
004fd0c8 2626
92976ab6
RR
2627 wxClientDC dc(this);
2628 PrepareDC( dc );
bd8289c1 2629
cf1dfa6b 2630 wxString s = data->GetText(0);
5cd89174 2631 wxRect rectLabel = GetLineLabelRect(m_currentEdit);
cf1dfa6b
VZ
2632
2633 rectLabel.x = dc.LogicalToDeviceX( rectLabel.x );
2634 rectLabel.y = dc.LogicalToDeviceY( rectLabel.y );
2635
2636 wxListTextCtrl *text = new wxListTextCtrl
2637 (
2638 this, -1,
2639 &m_renameAccept,
2640 &m_renameRes,
2641 this,
2642 s,
2643 wxPoint(rectLabel.x-4,rectLabel.y-4),
2644 wxSize(rectLabel.width+11,rectLabel.height+8)
2645 );
92976ab6 2646 text->SetFocus();
e1e955e1 2647}
c801d85f 2648
e179bd65
RR
2649void wxListMainWindow::OnRenameTimer()
2650{
cf1dfa6b 2651 wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
004fd0c8 2652
cf1dfa6b 2653 EditLabel( m_current );
e179bd65
RR
2654}
2655
c801d85f
KB
2656void wxListMainWindow::OnRenameAccept()
2657{
e179bd65
RR
2658 wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() );
2659 le.SetEventObject( GetParent() );
1370703e
VZ
2660 le.m_itemIndex = m_currentEdit;
2661
2662 wxListLineData *data = GetLine(m_currentEdit);
2663 wxCHECK_RET( data, _T("invalid index in OnRenameAccept()") );
2664
2665 data->GetItem( 0, le.m_item );
e179bd65
RR
2666 le.m_item.m_text = m_renameRes;
2667 GetParent()->GetEventHandler()->ProcessEvent( le );
004fd0c8 2668
e179bd65 2669 if (!le.IsAllowed()) return;
004fd0c8 2670
5f1ea0ee
RR
2671 wxListItem info;
2672 info.m_mask = wxLIST_MASK_TEXT;
2673 info.m_itemId = le.m_itemIndex;
2674 info.m_text = m_renameRes;
aaa37c0d 2675 info.SetTextColour(le.m_item.GetTextColour());
5f1ea0ee 2676 SetItem( info );
e1e955e1 2677}
c801d85f
KB
2678
2679void wxListMainWindow::OnMouse( wxMouseEvent &event )
2680{
3e1c4e00 2681 event.SetEventObject( GetParent() );
cf1dfa6b
VZ
2682 if ( GetParent()->GetEventHandler()->ProcessEvent( event) )
2683 return;
2684
2685 if ( !HasCurrent() || IsEmpty() )
2686 return;
2687
2688 if (m_dirty)
2689 return;
e3e65dac 2690
cf1dfa6b
VZ
2691 if ( !(event.Dragging() || event.ButtonDown() || event.LeftUp() ||
2692 event.ButtonDClick()) )
2693 return;
c801d85f 2694
aaef15bf
RR
2695 int x = event.GetX();
2696 int y = event.GetY();
2697 CalcUnscrolledPosition( x, y, &x, &y );
004fd0c8 2698
cc734310 2699 // where did we hit it (if we did)?
92976ab6 2700 long hitResult = 0;
1370703e 2701
cf1dfa6b
VZ
2702 size_t count = GetItemCount(),
2703 current;
2704
2705 if ( HasFlag(wxLC_REPORT) )
92976ab6 2706 {
5cd89174 2707 current = y / GetLineHeight();
cc734310
VZ
2708 if ( current < count )
2709 hitResult = HitTestLine(current, x, y);
cf1dfa6b
VZ
2710 }
2711 else // !report
2712 {
2713 // TODO: optimize it too! this is less simple than for report view but
2714 // enumerating all items is still not a way to do it!!
4e3ace65 2715 for ( current = 0; current < count; current++ )
cf1dfa6b 2716 {
5cd89174 2717 hitResult = HitTestLine(current, x, y);
4e3ace65
VZ
2718 if ( hitResult )
2719 break;
cf1dfa6b 2720 }
92976ab6 2721 }
bd8289c1 2722
fd9811b1 2723 if (event.Dragging())
92976ab6 2724 {
fd9811b1 2725 if (m_dragCount == 0)
bffa1c77
VZ
2726 m_dragStart = wxPoint(x,y);
2727
fd9811b1 2728 m_dragCount++;
bffa1c77 2729
cf1dfa6b
VZ
2730 if (m_dragCount != 3)
2731 return;
bffa1c77 2732
05a7f61d
VZ
2733 int command = event.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
2734 : wxEVT_COMMAND_LIST_BEGIN_DRAG;
bffa1c77 2735
fd9811b1 2736 wxListEvent le( command, GetParent()->GetId() );
92976ab6 2737 le.SetEventObject( GetParent() );
bffa1c77
VZ
2738 le.m_pointDrag = m_dragStart;
2739 GetParent()->GetEventHandler()->ProcessEvent( le );
2740
2741 return;
92976ab6 2742 }
fd9811b1
RR
2743 else
2744 {
2745 m_dragCount = 0;
2746 }
bd8289c1 2747
cf1dfa6b
VZ
2748 if ( !hitResult )
2749 {
2750 // outside of any item
2751 return;
2752 }
bd8289c1 2753
efbb7287 2754 bool forceClick = FALSE;
92976ab6
RR
2755 if (event.ButtonDClick())
2756 {
92976ab6 2757 m_renameTimer->Stop();
efbb7287
VZ
2758 m_lastOnSame = FALSE;
2759
cf1dfa6b 2760 if ( current == m_lineBeforeLastClicked )
efbb7287 2761 {
cf1dfa6b 2762 SendNotify( current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
004fd0c8 2763
efbb7287
VZ
2764 return;
2765 }
2766 else
2767 {
2768 // the first click was on another item, so don't interpret this as
2769 // a double click, but as a simple click instead
2770 forceClick = TRUE;
2771 }
92976ab6 2772 }
bd8289c1 2773
92976ab6 2774 if (event.LeftUp() && m_lastOnSame)
c801d85f 2775 {
cf1dfa6b 2776 if ((current == m_current) &&
92976ab6 2777 (hitResult == wxLIST_HITTEST_ONITEMLABEL) &&
cf1dfa6b 2778 HasFlag(wxLC_EDIT_LABELS) )
92976ab6
RR
2779 {
2780 m_renameTimer->Start( 100, TRUE );
2781 }
2782 m_lastOnSame = FALSE;
e1e955e1 2783 }
cf1dfa6b 2784 else if (event.RightDown())
b204641e 2785 {
cf1dfa6b 2786 SendNotify( current, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK,
05a7f61d 2787 event.GetPosition() );
b204641e 2788 }
cf1dfa6b 2789 else if (event.MiddleDown())
b204641e 2790 {
cf1dfa6b 2791 SendNotify( current, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK );
92976ab6 2792 }
cf1dfa6b 2793 else if ( event.LeftDown() || forceClick )
92976ab6 2794 {
efbb7287 2795 m_lineBeforeLastClicked = m_lineLastClicked;
cf1dfa6b
VZ
2796 m_lineLastClicked = current;
2797
2798 size_t oldCurrent = m_current;
efbb7287 2799
b54e41c5 2800 if ( IsSingleSel() || !(event.ControlDown() || event.ShiftDown()) )
b204641e 2801 {
b54e41c5 2802 HighlightAll( FALSE );
cf1dfa6b 2803 m_current = current;
cf1dfa6b 2804
b54e41c5 2805 ReverseHighlight(m_current);
e1e955e1 2806 }
b54e41c5 2807 else // multi sel & either ctrl or shift is down
b204641e 2808 {
473d087e 2809 if (event.ControlDown())
92976ab6 2810 {
cf1dfa6b
VZ
2811 m_current = current;
2812
b54e41c5 2813 ReverseHighlight(m_current);
92976ab6 2814 }
473d087e 2815 else if (event.ShiftDown())
92976ab6 2816 {
cf1dfa6b 2817 m_current = current;
bffa1c77 2818
cf1dfa6b
VZ
2819 size_t lineFrom = oldCurrent,
2820 lineTo = current;
f6bcfd97 2821
cf1dfa6b 2822 if ( lineTo < lineFrom )
92976ab6 2823 {
cf1dfa6b
VZ
2824 lineTo = lineFrom;
2825 lineFrom = m_current;
92976ab6
RR
2826 }
2827
b54e41c5 2828 HighlightLines(lineFrom, lineTo);
92976ab6 2829 }
cf1dfa6b 2830 else // !ctrl, !shift
92976ab6 2831 {
cf1dfa6b
VZ
2832 // test in the enclosing if should make it impossible
2833 wxFAIL_MSG( _T("how did we get here?") );
92976ab6 2834 }
e1e955e1 2835 }
cf1dfa6b 2836
92976ab6
RR
2837 if (m_current != oldCurrent)
2838 {
2839 RefreshLine( oldCurrent );
cf1dfa6b
VZ
2840 OnUnfocusLine( oldCurrent );
2841 OnFocusLine( m_current );
92976ab6 2842 }
efbb7287
VZ
2843
2844 // forceClick is only set if the previous click was on another item
2845 m_lastOnSame = !forceClick && (m_current == oldCurrent);
e1e955e1 2846 }
e1e955e1 2847}
c801d85f 2848
e179bd65 2849void wxListMainWindow::MoveToFocus()
c801d85f 2850{
b54e41c5 2851 if ( !HasCurrent() )
cf1dfa6b 2852 return;
004fd0c8 2853
5cd89174 2854 wxRect rect = GetLineRect(m_current);
cf3da716 2855
cf1dfa6b 2856 int client_w, client_h;
cf3da716 2857 GetClientSize( &client_w, &client_h );
f6bcfd97 2858
cf3da716
RR
2859 int view_x = m_xScroll*GetScrollPos( wxHORIZONTAL );
2860 int view_y = m_yScroll*GetScrollPos( wxVERTICAL );
004fd0c8 2861
cf1dfa6b 2862 if ( HasFlag(wxLC_REPORT) )
92976ab6 2863 {
b54e41c5
VZ
2864 // the next we need the range of lines shown it might be different, so
2865 // recalculate it
2866 ResetVisibleLinesRange();
2867
cf1dfa6b
VZ
2868 if (rect.y < view_y )
2869 Scroll( -1, rect.y/m_yScroll );
2870 if (rect.y+rect.height+5 > view_y+client_h)
2871 Scroll( -1, (rect.y+rect.height-client_h+SCROLL_UNIT_Y)/m_yScroll );
92976ab6 2872 }
b54e41c5 2873 else // !report
92976ab6 2874 {
cf1dfa6b
VZ
2875 if (rect.x-view_x < 5)
2876 Scroll( (rect.x-5)/m_xScroll, -1 );
2877 if (rect.x+rect.width-5 > view_x+client_w)
2878 Scroll( (rect.x+rect.width-client_w+SCROLL_UNIT_X)/m_xScroll, -1 );
92976ab6 2879 }
e1e955e1 2880}
c801d85f 2881
cf1dfa6b
VZ
2882// ----------------------------------------------------------------------------
2883// keyboard handling
2884// ----------------------------------------------------------------------------
2885
2886void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
c801d85f 2887{
cf1dfa6b
VZ
2888 wxCHECK_RET( newCurrent < (size_t)GetItemCount(),
2889 _T("invalid item index in OnArrowChar()") );
2890
2891 size_t oldCurrent = m_current;
2892
2893 // in single selection we just ignore Shift as we can't select several
2894 // items anyhow
b54e41c5 2895 if ( event.ShiftDown() && !IsSingleSel() )
cf1dfa6b
VZ
2896 {
2897 m_current = newCurrent;
2898
2899 // select all the items between the old and the new one
2900 if ( oldCurrent > newCurrent )
2901 {
2902 newCurrent = oldCurrent;
2903 oldCurrent = m_current;
2904 }
2905
b54e41c5 2906 HighlightLines(oldCurrent, newCurrent);
cf1dfa6b
VZ
2907 }
2908 else // !shift
2909 {
b54e41c5
VZ
2910 // all previously selected items are unselected unless ctrl is held
2911 if ( !event.ControlDown() )
2912 HighlightAll(FALSE);
2913
cf1dfa6b
VZ
2914 m_current = newCurrent;
2915
b54e41c5 2916 HighlightLine( oldCurrent, FALSE );
cf1dfa6b
VZ
2917 RefreshLine( oldCurrent );
2918
2919 if ( !event.ControlDown() )
2920 {
b54e41c5 2921 HighlightLine( m_current, TRUE );
cf1dfa6b
VZ
2922 }
2923 }
2924
2925 OnUnfocusLine( oldCurrent );
2926 OnFocusLine( m_current );
92976ab6 2927 RefreshLine( m_current );
cf1dfa6b 2928
cf3da716 2929 MoveToFocus();
e1e955e1 2930}
c801d85f 2931
3dfb93fd
RR
2932void wxListMainWindow::OnKeyDown( wxKeyEvent &event )
2933{
2934 wxWindow *parent = GetParent();
004fd0c8 2935
3dfb93fd
RR
2936 /* we propagate the key event up */
2937 wxKeyEvent ke( wxEVT_KEY_DOWN );
2938 ke.m_shiftDown = event.m_shiftDown;
2939 ke.m_controlDown = event.m_controlDown;
2940 ke.m_altDown = event.m_altDown;
2941 ke.m_metaDown = event.m_metaDown;
2942 ke.m_keyCode = event.m_keyCode;
2943 ke.m_x = event.m_x;
2944 ke.m_y = event.m_y;
2945 ke.SetEventObject( parent );
2946 if (parent->GetEventHandler()->ProcessEvent( ke )) return;
004fd0c8 2947
3dfb93fd
RR
2948 event.Skip();
2949}
004fd0c8 2950
c801d85f
KB
2951void wxListMainWindow::OnChar( wxKeyEvent &event )
2952{
51cc4dad 2953 wxWindow *parent = GetParent();
004fd0c8 2954
51cc4dad 2955 /* we send a list_key event up */
cf1dfa6b 2956 if ( HasCurrent() )
f6bcfd97
BP
2957 {
2958 wxListEvent le( wxEVT_COMMAND_LIST_KEY_DOWN, GetParent()->GetId() );
cf1dfa6b
VZ
2959 le.m_itemIndex = m_current;
2960 GetLine(m_current)->GetItem( 0, le.m_item );
f6bcfd97
BP
2961 le.m_code = (int)event.KeyCode();
2962 le.SetEventObject( parent );
2963 parent->GetEventHandler()->ProcessEvent( le );
2964 }
51cc4dad 2965
3dfb93fd
RR
2966 /* we propagate the char event up */
2967 wxKeyEvent ke( wxEVT_CHAR );
51cc4dad
RR
2968 ke.m_shiftDown = event.m_shiftDown;
2969 ke.m_controlDown = event.m_controlDown;
2970 ke.m_altDown = event.m_altDown;
2971 ke.m_metaDown = event.m_metaDown;
2972 ke.m_keyCode = event.m_keyCode;
2973 ke.m_x = event.m_x;
2974 ke.m_y = event.m_y;
2975 ke.SetEventObject( parent );
2976 if (parent->GetEventHandler()->ProcessEvent( ke )) return;
004fd0c8 2977
012a03e0
RR
2978 if (event.KeyCode() == WXK_TAB)
2979 {
2980 wxNavigationKeyEvent nevent;
c5145d41 2981 nevent.SetWindowChange( event.ControlDown() );
012a03e0 2982 nevent.SetDirection( !event.ShiftDown() );
8253c7fd 2983 nevent.SetEventObject( GetParent()->GetParent() );
012a03e0 2984 nevent.SetCurrentFocus( m_parent );
8253c7fd 2985 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent )) return;
012a03e0 2986 }
004fd0c8 2987
51cc4dad 2988 /* no item -> nothing to do */
cf1dfa6b 2989 if (!HasCurrent())
c801d85f 2990 {
51cc4dad
RR
2991 event.Skip();
2992 return;
e1e955e1 2993 }
51cc4dad
RR
2994
2995 switch (event.KeyCode())
c801d85f 2996 {
51cc4dad 2997 case WXK_UP:
cf1dfa6b
VZ
2998 if ( m_current > 0 )
2999 OnArrowChar( m_current - 1, event );
51cc4dad 3000 break;
cf1dfa6b 3001
51cc4dad 3002 case WXK_DOWN:
cf1dfa6b
VZ
3003 if ( m_current < (size_t)GetItemCount() - 1 )
3004 OnArrowChar( m_current + 1, event );
51cc4dad 3005 break;
cf1dfa6b 3006
51cc4dad 3007 case WXK_END:
1370703e 3008 if (!IsEmpty())
cf1dfa6b 3009 OnArrowChar( GetItemCount() - 1, event );
51cc4dad 3010 break;
cf1dfa6b 3011
51cc4dad 3012 case WXK_HOME:
1370703e 3013 if (!IsEmpty())
cf1dfa6b 3014 OnArrowChar( 0, event );
51cc4dad 3015 break;
cf1dfa6b 3016
51cc4dad 3017 case WXK_PRIOR:
f6bcfd97 3018 {
cf1dfa6b
VZ
3019 int steps = 0;
3020 if ( HasFlag(wxLC_REPORT) )
3021 {
3022 steps = m_linesPerPage - 1;
3023 }
3024 else
3025 {
3026 steps = m_current % m_linesPerPage;
3027 }
3028
3029 int index = m_current - steps;
3030 if (index < 0)
3031 index = 0;
3032
3033 OnArrowChar( index, event );
51cc4dad 3034 }
51cc4dad 3035 break;
cf1dfa6b 3036
51cc4dad 3037 case WXK_NEXT:
bffa1c77 3038 {
cf1dfa6b
VZ
3039 int steps = 0;
3040 if ( HasFlag(wxLC_REPORT) )
3041 {
3042 steps = m_linesPerPage - 1;
3043 }
3044 else
3045 {
3046 steps = m_linesPerPage - (m_current % m_linesPerPage) - 1;
3047 }
f6bcfd97 3048
cf1dfa6b
VZ
3049 size_t index = m_current + steps;
3050 size_t count = GetItemCount();
3051 if ( index >= count )
3052 index = count - 1;
3053
3054 OnArrowChar( index, event );
51cc4dad 3055 }
51cc4dad 3056 break;
cf1dfa6b 3057
51cc4dad 3058 case WXK_LEFT:
cf1dfa6b 3059 if ( !HasFlag(wxLC_REPORT) )
51cc4dad 3060 {
cf1dfa6b
VZ
3061 int index = m_current - m_linesPerPage;
3062 if (index < 0)
3063 index = 0;
3064
3065 OnArrowChar( index, event );
51cc4dad
RR
3066 }
3067 break;
cf1dfa6b 3068
51cc4dad 3069 case WXK_RIGHT:
cf1dfa6b 3070 if ( !HasFlag(wxLC_REPORT) )
51cc4dad 3071 {
cf1dfa6b
VZ
3072 size_t index = m_current + m_linesPerPage;
3073
3074 size_t count = GetItemCount();
3075 if ( index >= count )
3076 index = count - 1;
3077
3078 OnArrowChar( index, event );
51cc4dad
RR
3079 }
3080 break;
cf1dfa6b 3081
51cc4dad 3082 case WXK_SPACE:
b54e41c5 3083 if ( IsSingleSel() )
33d0e17c 3084 {
cf1dfa6b
VZ
3085 wxListEvent le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
3086 GetParent()->GetId() );
33d0e17c 3087 le.SetEventObject( GetParent() );
cf1dfa6b
VZ
3088 le.m_itemIndex = m_current;
3089 GetLine(m_current)->GetItem( 0, le.m_item );
33d0e17c
RR
3090 GetParent()->GetEventHandler()->ProcessEvent( le );
3091 }
3092 else
3093 {
b54e41c5 3094 ReverseHighlight(m_current);
51cc4dad
RR
3095 }
3096 break;
cf1dfa6b 3097
51cc4dad
RR
3098 case WXK_RETURN:
3099 case WXK_EXECUTE:
cf1dfa6b
VZ
3100 {
3101 wxListEvent le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
3102 GetParent()->GetId() );
3103 le.SetEventObject( GetParent() );
3104 le.m_itemIndex = m_current;
3105 GetLine(m_current)->GetItem( 0, le.m_item );
3106 GetParent()->GetEventHandler()->ProcessEvent( le );
3107 }
51cc4dad 3108 break;
cf1dfa6b 3109
51cc4dad 3110 default:
51cc4dad 3111 event.Skip();
e1e955e1 3112 }
e1e955e1 3113}
c801d85f 3114
cf1dfa6b
VZ
3115// ----------------------------------------------------------------------------
3116// focus handling
3117// ----------------------------------------------------------------------------
3118
cae5359f
RR
3119#ifdef __WXGTK__
3120extern wxWindow *g_focusWindow;
3121#endif
3122
c801d85f
KB
3123void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
3124{
63852e78 3125 m_hasFocus = TRUE;
bd8289c1 3126
cf1dfa6b
VZ
3127 if ( HasCurrent() )
3128 RefreshLine( m_current );
3129
3130 if (!GetParent())
3131 return;
004fd0c8 3132
cae5359f
RR
3133#ifdef __WXGTK__
3134 g_focusWindow = GetParent();
3135#endif
bd8289c1 3136
63852e78
RR
3137 wxFocusEvent event( wxEVT_SET_FOCUS, GetParent()->GetId() );
3138 event.SetEventObject( GetParent() );
3139 GetParent()->GetEventHandler()->ProcessEvent( event );
e1e955e1 3140}
c801d85f
KB
3141
3142void wxListMainWindow::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
3143{
63852e78 3144 m_hasFocus = FALSE;
004fd0c8 3145
cf1dfa6b
VZ
3146 if ( HasCurrent() )
3147 RefreshLine( m_current );
e1e955e1 3148}
c801d85f 3149
1e6d9499 3150void wxListMainWindow::DrawImage( int index, wxDC *dc, int x, int y )
c801d85f 3151{
cf1dfa6b 3152 if ( HasFlag(wxLC_ICON) && (m_normal_image_list))
63852e78
RR
3153 {
3154 m_normal_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
63852e78 3155 }
cf1dfa6b 3156 else if ( HasFlag(wxLC_SMALL_ICON) && (m_small_image_list))
63852e78
RR
3157 {
3158 m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
3159 }
cf1dfa6b 3160 else if ( HasFlag(wxLC_LIST) && (m_small_image_list))
0b855868
RR
3161 {
3162 m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
3163 }
cf1dfa6b 3164 else if ( HasFlag(wxLC_REPORT) && (m_small_image_list))
63852e78
RR
3165 {
3166 m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
63852e78 3167 }
e1e955e1 3168}
c801d85f 3169
5cd89174 3170void wxListMainWindow::GetImageSize( int index, int &width, int &height ) const
c801d85f 3171{
cf1dfa6b 3172 if ( HasFlag(wxLC_ICON) && m_normal_image_list )
63852e78
RR
3173 {
3174 m_normal_image_list->GetSize( index, width, height );
63852e78 3175 }
cf1dfa6b 3176 else if ( HasFlag(wxLC_SMALL_ICON) && m_small_image_list )
63852e78
RR
3177 {
3178 m_small_image_list->GetSize( index, width, height );
63852e78 3179 }
cf1dfa6b 3180 else if ( HasFlag(wxLC_LIST) && m_small_image_list )
0b855868
RR
3181 {
3182 m_small_image_list->GetSize( index, width, height );
0b855868 3183 }
cf1dfa6b 3184 else if ( HasFlag(wxLC_REPORT) && m_small_image_list )
63852e78
RR
3185 {
3186 m_small_image_list->GetSize( index, width, height );
63852e78 3187 }
cf1dfa6b
VZ
3188 else
3189 {
3190 width =
3191 height = 0;
3192 }
e1e955e1 3193}
c801d85f 3194
5cd89174 3195int wxListMainWindow::GetTextLength( const wxString &s ) const
c801d85f 3196{
5cd89174 3197 wxClientDC dc( wxConstCast(this, wxListMainWindow) );
cf1dfa6b 3198 dc.SetFont( GetFont() );
c801d85f 3199
cf1dfa6b
VZ
3200 wxCoord lw;
3201 dc.GetTextExtent( s, &lw, NULL );
3202
3203 return lw + AUTOSIZE_COL_MARGIN;
e1e955e1 3204}
c801d85f 3205
debe6624 3206void wxListMainWindow::SetImageList( wxImageList *imageList, int which )
c801d85f 3207{
139adb6a 3208 m_dirty = TRUE;
f6bcfd97
BP
3209
3210 // calc the spacing from the icon size
3211 int width = 0,
3212 height = 0;
3213 if ((imageList) && (imageList->GetImageCount()) )
3214 {
3215 imageList->GetSize(0, width, height);
3216 }
3217
3218 if (which == wxIMAGE_LIST_NORMAL)
3219 {
3220 m_normal_image_list = imageList;
3221 m_normal_spacing = width + 8;
3222 }
3223
3224 if (which == wxIMAGE_LIST_SMALL)
3225 {
3226 m_small_image_list = imageList;
3227 m_small_spacing = width + 14;
3228 }
e1e955e1 3229}
c801d85f 3230
debe6624 3231void wxListMainWindow::SetItemSpacing( int spacing, bool isSmall )
c801d85f 3232{
139adb6a
RR
3233 m_dirty = TRUE;
3234 if (isSmall)
3235 {
3236 m_small_spacing = spacing;
3237 }
3238 else
3239 {
3240 m_normal_spacing = spacing;
3241 }
e1e955e1 3242}
c801d85f 3243
debe6624 3244int wxListMainWindow::GetItemSpacing( bool isSmall )
c801d85f 3245{
f6bcfd97 3246 return isSmall ? m_small_spacing : m_normal_spacing;
e1e955e1 3247}
c801d85f 3248
cf1dfa6b
VZ
3249// ----------------------------------------------------------------------------
3250// columns
3251// ----------------------------------------------------------------------------
3252
debe6624 3253void wxListMainWindow::SetColumn( int col, wxListItem &item )
c801d85f 3254{
24b9f055 3255 wxListHeaderDataList::Node *node = m_columns.Item( col );
f6bcfd97 3256
cf1dfa6b
VZ
3257 wxCHECK_RET( node, _T("invalid column index in SetColumn") );
3258
3259 if ( item.m_width == wxLIST_AUTOSIZE_USEHEADER )
3260 item.m_width = GetTextLength( item.m_text );
3261
3262 wxListHeaderData *column = node->GetData();
3263 column->SetItem( item );
3264
3265 wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin;
f6bcfd97
BP
3266 if ( headerWin )
3267 headerWin->m_dirty = TRUE;
cf1dfa6b
VZ
3268
3269 m_dirty = TRUE;
3270
3271 // invalidate it as it has to be recalculated
3272 m_headerWidth = 0;
e1e955e1 3273}
c801d85f 3274
debe6624 3275void wxListMainWindow::SetColumnWidth( int col, int width )
c801d85f 3276{
cf1dfa6b
VZ
3277 wxCHECK_RET( col >= 0 && col < GetColumnCount(),
3278 _T("invalid column index") );
3279
3280 wxCHECK_RET( HasFlag(wxLC_REPORT),
f6bcfd97 3281 _T("SetColumnWidth() can only be called in report mode.") );
0208334d 3282
63852e78 3283 m_dirty = TRUE;
bd8289c1 3284
cf1dfa6b
VZ
3285 wxListHeaderDataList::Node *node = m_columns.Item( col );
3286 wxCHECK_RET( node, _T("no column?") );
3287
3288 wxListHeaderData *column = node->GetData();
3289
3290 size_t count = GetItemCount();
3291
f6bcfd97
BP
3292 if (width == wxLIST_AUTOSIZE_USEHEADER)
3293 {
cf1dfa6b 3294 width = GetTextLength(column->GetText());
f6bcfd97 3295 }
cf1dfa6b 3296 else if ( width == wxLIST_AUTOSIZE )
0180dad6 3297 {
cf1dfa6b
VZ
3298 if ( IsVirtual() )
3299 {
3300 // TODO: determine the max width somehow...
3301 width = WIDTH_COL_DEFAULT;
3302 }
3303 else // !virtual
0180dad6 3304 {
cf1dfa6b
VZ
3305 wxClientDC dc(this);
3306 dc.SetFont( GetFont() );
3307
3308 int max = AUTOSIZE_COL_MARGIN;
3309
3310 for ( size_t i = 0; i < count; i++ )
0180dad6 3311 {
cf1dfa6b
VZ
3312 wxListLineData *line = GetLine(i);
3313 wxListItemDataList::Node *n = line->m_items.Item( col );
3314
3315 wxCHECK_RET( n, _T("no subitem?") );
3316
2c1f73ee 3317 wxListItemData *item = n->GetData();
cf1dfa6b
VZ
3318 int current = 0;
3319
bffa1c77
VZ
3320 if (item->HasImage())
3321 {
cf1dfa6b 3322 int ix, iy;
0180dad6 3323 GetImageSize( item->GetImage(), ix, iy );
cf1dfa6b 3324 current += ix + 5;
bffa1c77 3325 }
cf1dfa6b 3326
bffa1c77
VZ
3327 if (item->HasText())
3328 {
cf1dfa6b
VZ
3329 wxCoord w;
3330 dc.GetTextExtent( item->GetText(), &w, NULL );
3331 current += w;
bffa1c77 3332 }
cf1dfa6b 3333
2c1f73ee
VZ
3334 if (current > max)
3335 max = current;
0180dad6 3336 }
cf1dfa6b
VZ
3337
3338 width = max + AUTOSIZE_COL_MARGIN;
0180dad6 3339 }
0180dad6
RR
3340 }
3341
cf1dfa6b 3342 column->SetWidth( width );
bd8289c1 3343
cf1dfa6b
VZ
3344 // invalidate it as it has to be recalculated
3345 m_headerWidth = 0;
3346}
3347
3348int wxListMainWindow::GetHeaderWidth() const
3349{
3350 if ( !m_headerWidth )
0208334d 3351 {
cf1dfa6b
VZ
3352 wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
3353
3354 size_t count = GetColumnCount();
3355 for ( size_t col = 0; col < count; col++ )
63852e78 3356 {
cf1dfa6b 3357 self->m_headerWidth += GetColumnWidth(col);
63852e78 3358 }
0208334d 3359 }
bd8289c1 3360
cf1dfa6b 3361 return m_headerWidth;
e1e955e1 3362}
c801d85f 3363
cf1dfa6b 3364void wxListMainWindow::GetColumn( int col, wxListItem &item ) const
c801d85f 3365{
24b9f055 3366 wxListHeaderDataList::Node *node = m_columns.Item( col );
cf1dfa6b
VZ
3367 wxCHECK_RET( node, _T("invalid column index in GetColumn") );
3368
3369 wxListHeaderData *column = node->GetData();
3370 column->GetItem( item );
e1e955e1 3371}
c801d85f 3372
cf1dfa6b 3373int wxListMainWindow::GetColumnWidth( int col ) const
c801d85f 3374{
24b9f055
VZ
3375 wxListHeaderDataList::Node *node = m_columns.Item( col );
3376 wxCHECK_MSG( node, 0, _T("invalid column index") );
3377
3378 wxListHeaderData *column = node->GetData();
3379 return column->GetWidth();
e1e955e1 3380}
c801d85f 3381
cf1dfa6b
VZ
3382// ----------------------------------------------------------------------------
3383// item state
3384// ----------------------------------------------------------------------------
c801d85f
KB
3385
3386void wxListMainWindow::SetItem( wxListItem &item )
3387{
cf1dfa6b
VZ
3388 long id = item.m_itemId;
3389 wxCHECK_RET( id >= 0 && (size_t)id < GetItemCount(),
3390 _T("invalid item index in SetItem") );
3391
6c02c329
VZ
3392 if ( !IsVirtual() )
3393 {
3394 wxListLineData *line = GetLine((size_t)id);
3395 line->SetItem( item.m_col, item );
3396 }
3397
3398 if ( InReportView() )
cf1dfa6b
VZ
3399 {
3400 // just refresh the line to show the new value of the text/image
3401 RefreshLine((size_t)id);
3402 }
6c02c329 3403 else // !report
92976ab6 3404 {
6c02c329 3405 // refresh everything (resulting in horrible flicker - FIXME!)
cf1dfa6b 3406 m_dirty = TRUE;
92976ab6 3407 }
e1e955e1 3408}
c801d85f 3409
cf1dfa6b 3410void wxListMainWindow::SetItemState( long litem, long state, long stateMask )
c801d85f 3411{
cf1dfa6b 3412 wxCHECK_RET( litem >= 0 && (size_t)litem < GetItemCount(),
54442116
VZ
3413 _T("invalid list ctrl item index in SetItem") );
3414
cf1dfa6b
VZ
3415 size_t oldCurrent = m_current;
3416 size_t item = (size_t)litem; // sdafe because of the check above
bd8289c1 3417
54442116 3418 if ( stateMask & wxLIST_STATE_FOCUSED )
c801d85f 3419 {
54442116 3420 if ( state & wxLIST_STATE_FOCUSED )
92976ab6 3421 {
54442116 3422 // don't do anything if this item is already focused
cf1dfa6b 3423 if ( item != m_current )
92976ab6 3424 {
cf1dfa6b
VZ
3425 OnUnfocusLine( m_current );
3426 m_current = item;
3427 OnFocusLine( m_current );
3428
b54e41c5 3429 if ( IsSingleSel() && (oldCurrent != (size_t)-1) )
cf1dfa6b 3430 {
b54e41c5 3431 HighlightLine(oldCurrent, FALSE);
cf1dfa6b
VZ
3432 RefreshLine(oldCurrent);
3433 }
54442116 3434
92976ab6 3435 RefreshLine( m_current );
92976ab6 3436 }
54442116
VZ
3437 }
3438 else // unfocus
3439 {
3440 // don't do anything if this item is not focused
cf1dfa6b 3441 if ( item == m_current )
bffa1c77 3442 {
cf1dfa6b
VZ
3443 OnUnfocusLine( m_current );
3444 m_current = (size_t)-1;
bffa1c77 3445 }
92976ab6 3446 }
e1e955e1 3447 }
54442116
VZ
3448
3449 if ( stateMask & wxLIST_STATE_SELECTED )
3450 {
3451 bool on = (state & wxLIST_STATE_SELECTED) != 0;
54442116 3452
b54e41c5 3453 if ( IsSingleSel() )
54442116 3454 {
cf1dfa6b
VZ
3455 if ( on )
3456 {
3457 // selecting the item also makes it the focused one in the
3458 // single sel mode
3459 if ( m_current != item )
3460 {
3461 OnUnfocusLine( m_current );
3462 m_current = item;
3463 OnFocusLine( m_current );
3464
3465 if ( oldCurrent != (size_t)-1 )
3466 {
b54e41c5 3467 HighlightLine( oldCurrent, FALSE );
cf1dfa6b
VZ
3468 RefreshLine( oldCurrent );
3469 }
3470 }
3471 }
3472 else // off
3473 {
3474 // only the current item may be selected anyhow
3475 if ( item != m_current )
3476 return;
3477 }
54442116
VZ
3478 }
3479
b54e41c5 3480 if ( HighlightLine(item, on) )
54442116 3481 {
cf1dfa6b 3482 RefreshLine(item);
54442116
VZ
3483 }
3484 }
e1e955e1 3485}
c801d85f 3486
debe6624 3487int wxListMainWindow::GetItemState( long item, long stateMask )
c801d85f 3488{
cf1dfa6b
VZ
3489 wxCHECK_MSG( item >= 0 && (size_t)item < GetItemCount(), 0,
3490 _T("invalid list ctrl item index in GetItemState()") );
3491
92976ab6 3492 int ret = wxLIST_STATE_DONTCARE;
cf1dfa6b
VZ
3493
3494 if ( stateMask & wxLIST_STATE_FOCUSED )
c801d85f 3495 {
cf1dfa6b
VZ
3496 if ( (size_t)item == m_current )
3497 ret |= wxLIST_STATE_FOCUSED;
e1e955e1 3498 }
cf1dfa6b
VZ
3499
3500 if ( stateMask & wxLIST_STATE_SELECTED )
c801d85f 3501 {
b54e41c5 3502 if ( IsHighlighted(item) )
cf1dfa6b 3503 ret |= wxLIST_STATE_SELECTED;
e1e955e1 3504 }
cf1dfa6b 3505
92976ab6 3506 return ret;
e1e955e1 3507}
c801d85f
KB
3508
3509void wxListMainWindow::GetItem( wxListItem &item )
3510{
cf1dfa6b
VZ
3511 wxCHECK_RET( item.m_itemId >= 0 && (size_t)item.m_itemId < GetItemCount(),
3512 _T("invalid item index in GetItem") );
3513
3514 wxListLineData *line = GetLine((size_t)item.m_itemId);
3515 line->GetItem( item.m_col, item );
e1e955e1 3516}
c801d85f 3517
cf1dfa6b
VZ
3518// ----------------------------------------------------------------------------
3519// item count
3520// ----------------------------------------------------------------------------
3521
3522size_t wxListMainWindow::GetItemCount() const
1370703e
VZ
3523{
3524 return IsVirtual() ? m_countVirt : m_lines.GetCount();
3525}
3526
3527void wxListMainWindow::SetItemCount(long count)
c801d85f 3528{
b54e41c5 3529 m_selStore.SetItemCount(count);
1370703e
VZ
3530 m_countVirt = count;
3531
3532 Refresh();
e1e955e1 3533}
c801d85f 3534
cf1dfa6b 3535int wxListMainWindow::GetSelectedItemCount()
c801d85f 3536{
cf1dfa6b 3537 // deal with the quick case first
b54e41c5 3538 if ( IsSingleSel() )
92976ab6 3539 {
b54e41c5 3540 return HasCurrent() ? IsHighlighted(m_current) : FALSE;
92976ab6 3541 }
cf1dfa6b
VZ
3542
3543 // virtual controls remmebers all its selections itself
3544 if ( IsVirtual() )
b54e41c5 3545 return m_selStore.GetSelectedCount();
cf1dfa6b
VZ
3546
3547 // TODO: we probably should maintain the number of items selected even for
3548 // non virtual controls as enumerating all lines is really slow...
3549 size_t countSel = 0;
3550 size_t count = GetItemCount();
3551 for ( size_t line = 0; line < count; line++ )
92976ab6 3552 {
b54e41c5 3553 if ( GetLine(line)->IsHighlighted() )
cf1dfa6b 3554 countSel++;
92976ab6 3555 }
c801d85f 3556
cf1dfa6b 3557 return countSel;
e1e955e1 3558}
e3e65dac 3559
cf1dfa6b
VZ
3560// ----------------------------------------------------------------------------
3561// item position/size
3562// ----------------------------------------------------------------------------
3563
3564void wxListMainWindow::GetItemRect( long index, wxRect &rect )
c801d85f 3565{
cf1dfa6b
VZ
3566 wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(),
3567 _T("invalid index in GetItemRect") );
3568
5cd89174 3569 rect = GetLineRect((size_t)index);
b54e41c5 3570
cf1dfa6b 3571 CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
e1e955e1 3572}
c801d85f 3573
cf1dfa6b 3574bool wxListMainWindow::GetItemPosition(long item, wxPoint& pos)
c801d85f 3575{
cf1dfa6b
VZ
3576 wxRect rect;
3577 GetItemRect(item, rect);
bd8289c1 3578
cf1dfa6b
VZ
3579 pos.x = rect.x;
3580 pos.y = rect.y;
bd8289c1 3581
cf1dfa6b 3582 return TRUE;
e1e955e1 3583}
c801d85f 3584
cf1dfa6b
VZ
3585// ----------------------------------------------------------------------------
3586// geometry calculation
3587// ----------------------------------------------------------------------------
3588
b54e41c5 3589void wxListMainWindow::RecalculatePositions()
c801d85f 3590{
1370703e
VZ
3591 if ( IsEmpty() )
3592 return;
e487524e 3593
1e6d9499 3594 wxClientDC dc( this );
92976ab6 3595 dc.SetFont( GetFont() );
c801d85f 3596
cf1dfa6b
VZ
3597 int iconSpacing;
3598 if ( HasFlag(wxLC_ICON) )
3599 iconSpacing = m_normal_spacing;
3600 else if ( HasFlag(wxLC_SMALL_ICON) )
3601 iconSpacing = m_small_spacing;
3602 else
3603 iconSpacing = 0;
004fd0c8 3604
cf1dfa6b
VZ
3605 int clientWidth,
3606 clientHeight;
3607 GetClientSize( &clientWidth, &clientHeight );
004fd0c8 3608
cf1dfa6b
VZ
3609 if ( HasFlag(wxLC_REPORT) )
3610 {
3611 // all lines have the same height
b54e41c5 3612 int lineHeight = GetLineHeight();
c801d85f 3613
cf1dfa6b 3614 // scroll one line per step
b54e41c5 3615 m_yScroll = lineHeight;
bd8289c1 3616
cf1dfa6b 3617 size_t lineCount = GetItemCount();
b54e41c5 3618 int entireHeight = lineCount*lineHeight + LINE_SPACING;
bd8289c1 3619
b54e41c5
VZ
3620 m_linesPerPage = clientHeight / lineHeight;
3621
3622 ResetVisibleLinesRange();
2c1f73ee 3623
cf1dfa6b
VZ
3624 SetScrollbars( m_xScroll, m_yScroll,
3625 (GetHeaderWidth() + m_xScroll - 1)/m_xScroll,
3626 (entireHeight + m_yScroll - 1)/m_yScroll,
3627 GetScrollPos(wxHORIZONTAL),
3628 GetScrollPos(wxVERTICAL),
3629 TRUE );
e1e955e1 3630 }
cf1dfa6b 3631 else // !report
92976ab6
RR
3632 {
3633 // at first we try without any scrollbar. if the items don't
3634 // fit into the window, we recalculate after subtracting an
3635 // approximated 15 pt for the horizontal scrollbar
004fd0c8 3636
bffa1c77 3637 clientHeight -= 4; // sunken frame
bd8289c1 3638
b54e41c5 3639 int entireWidth = 0;
bd8289c1 3640
92976ab6 3641 for (int tries = 0; tries < 2; tries++)
e487524e 3642 {
92976ab6 3643 entireWidth = 0;
5d25c050
RR
3644 int x = 2;
3645 int y = 2;
92976ab6 3646 int maxWidth = 0;
cf1dfa6b
VZ
3647 m_linesPerPage = 0;
3648 int currentlyVisibleLines = 0;
3649
3650 size_t count = GetItemCount();
3651 for (size_t i = 0; i < count; i++)
92976ab6 3652 {
cf1dfa6b
VZ
3653 currentlyVisibleLines++;
3654 wxListLineData *line = GetLine(i);
92976ab6 3655 line->CalculateSize( &dc, iconSpacing );
cf1dfa6b
VZ
3656 line->SetPosition( x, y, clientWidth, iconSpacing );
3657
5cd89174 3658 wxSize sizeLine = GetLineSize(i);
cf1dfa6b
VZ
3659
3660 if ( maxWidth < sizeLine.x )
3661 maxWidth = sizeLine.x;
3662
3663 y += sizeLine.y;
3664 if (currentlyVisibleLines > m_linesPerPage)
3665 m_linesPerPage = currentlyVisibleLines;
3666
3667 // assume that the size of the next one is the same... (FIXME)
3668 if ( y + sizeLine.y - 6 >= clientHeight )
92976ab6 3669 {
cf1dfa6b 3670 currentlyVisibleLines = 0;
e1208c31 3671 y = 2;
8b53e5a2
RR
3672 x += maxWidth+6;
3673 entireWidth += maxWidth+6;
92976ab6
RR
3674 maxWidth = 0;
3675 }
cf1dfa6b
VZ
3676 if ( i == count - 1 )
3677 entireWidth += maxWidth;
92976ab6
RR
3678 if ((tries == 0) && (entireWidth > clientWidth))
3679 {
3680 clientHeight -= 15; // scrollbar height
cf1dfa6b
VZ
3681 m_linesPerPage = 0;
3682 currentlyVisibleLines = 0;
92976ab6
RR
3683 break;
3684 }
cf1dfa6b
VZ
3685 if ( i == count - 1 )
3686 tries = 1; // everything fits, no second try required
92976ab6 3687 }
e487524e 3688 }
bffa1c77 3689
92976ab6 3690 int scroll_pos = GetScrollPos( wxHORIZONTAL );
cf1dfa6b 3691 SetScrollbars( m_xScroll, m_yScroll, (entireWidth+SCROLL_UNIT_X) / m_xScroll, 0, scroll_pos, 0, TRUE );
e1e955e1 3692 }
cf1dfa6b
VZ
3693
3694 // FIXME: why should we call it from here?
3695 UpdateCurrent();
b54e41c5
VZ
3696
3697 RefreshAll();
3698}
3699
3700void wxListMainWindow::RefreshAll()
3701{
3702 m_dirty = FALSE;
3703 Refresh();
3704
3705 wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin;
3706 if ( headerWin )
3707 {
3708 headerWin->m_dirty = FALSE;
3709 headerWin->Refresh();
3710 }
e1e955e1 3711}
c801d85f 3712
cf1dfa6b 3713void wxListMainWindow::UpdateCurrent()
c801d85f 3714{
b54e41c5 3715 if ( !HasCurrent() && !IsEmpty() )
92976ab6 3716 {
cf1dfa6b 3717 m_current = 0;
92976ab6 3718 }
cf1dfa6b
VZ
3719
3720 if ( m_current != (size_t)-1 )
92976ab6 3721 {
cf1dfa6b 3722 OnFocusLine( m_current );
92976ab6 3723 }
e1e955e1 3724}
c801d85f 3725
19695fbd
VZ
3726long wxListMainWindow::GetNextItem( long item,
3727 int WXUNUSED(geometry),
3728 int state )
c801d85f 3729{
d1022fd6
VZ
3730 long ret = item,
3731 max = GetItemCount();
3732 wxCHECK_MSG( (ret == -1) || (ret < max), -1,
13771c08 3733 _T("invalid listctrl index in GetNextItem()") );
19695fbd
VZ
3734
3735 // notice that we start with the next item (or the first one if item == -1)
3736 // and this is intentional to allow writing a simple loop to iterate over
3737 // all selected items
d1022fd6
VZ
3738 ret++;
3739 if ( ret == max )
3740 {
3741 // this is not an error because the index was ok initially, just no
3742 // such item
3743 return -1;
3744 }
3745
cf1dfa6b
VZ
3746 if ( !state )
3747 {
3748 // any will do
3749 return (size_t)ret;
3750 }
3751
3752 size_t count = GetItemCount();
3753 for ( size_t line = (size_t)ret; line < count; line++ )
63852e78 3754 {
cf1dfa6b
VZ
3755 if ( (state & wxLIST_STATE_FOCUSED) && (line == m_current) )
3756 return line;
3757
b54e41c5 3758 if ( (state & wxLIST_STATE_SELECTED) && IsHighlighted(line) )
cf1dfa6b 3759 return line;
63852e78 3760 }
19695fbd 3761
63852e78 3762 return -1;
e1e955e1 3763}
c801d85f 3764
cf1dfa6b
VZ
3765// ----------------------------------------------------------------------------
3766// deleting stuff
3767// ----------------------------------------------------------------------------
3768
b54e41c5 3769void wxListMainWindow::DeleteItem( long lindex )
c801d85f 3770{
cf1dfa6b
VZ
3771 size_t count = GetItemCount();
3772
b54e41c5 3773 wxCHECK_RET( (lindex >= 0) && ((size_t)lindex < count),
cf1dfa6b
VZ
3774 _T("invalid item index in DeleteItem") );
3775
b54e41c5
VZ
3776 size_t index = (size_t)lindex;
3777
63852e78 3778 m_dirty = TRUE;
cf1dfa6b
VZ
3779
3780 // select the next item when the selected one is deleted
b54e41c5 3781 if ( m_current == index )
cf1dfa6b
VZ
3782 {
3783 // the last valid index after deleting the item will be count-2
5cd89174 3784 if ( m_current == count - 1 )
cf1dfa6b 3785 {
5cd89174 3786 m_current--;
cf1dfa6b
VZ
3787 }
3788 }
3789
b54e41c5 3790 SendNotify( index, wxEVT_COMMAND_LIST_DELETE_ITEM );
cf1dfa6b 3791
938b652b 3792 if ( InReportView() )
63852e78 3793 {
6b4a8d93 3794 ResetVisibleLinesRange();
938b652b
VZ
3795 }
3796
938b652b
VZ
3797 if ( IsVirtual() )
3798 {
3799 m_countVirt--;
b54e41c5
VZ
3800
3801 m_selStore.OnItemDelete(index);
3802 }
3803 else
3804 {
3805 m_lines.RemoveAt( index );
63852e78 3806 }
6b4a8d93 3807
b84839ae 3808 m_dirty = TRUE;
6b4a8d93 3809 RefreshAfter(index);
e1e955e1 3810}
c801d85f 3811
debe6624 3812void wxListMainWindow::DeleteColumn( int col )
c801d85f 3813{
24b9f055
VZ
3814 wxListHeaderDataList::Node *node = m_columns.Item( col );
3815
3816 wxCHECK_RET( node, wxT("invalid column index in DeleteColumn()") );
bd8289c1 3817
5b077d48 3818 m_dirty = TRUE;
24b9f055 3819 m_columns.DeleteNode( node );
e1e955e1 3820}
c801d85f 3821
12c1b46a 3822void wxListMainWindow::DeleteAllItems()
c801d85f 3823{
cf1dfa6b
VZ
3824 if ( IsEmpty() )
3825 {
3826 // nothing to do - in particular, don't send the event
3827 return;
3828 }
3829
5b077d48 3830 m_dirty = TRUE;
b54e41c5
VZ
3831
3832 ResetCurrent();
7c0ea335
VZ
3833
3834 // to make the deletion of all items faster, we don't send the
cf1dfa6b
VZ
3835 // notifications for each item deletion in this case but only one event
3836 // for all of them: this is compatible with wxMSW and documented in
3837 // DeleteAllItems() description
bffa1c77 3838
12c1b46a
RR
3839 wxListEvent event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, GetParent()->GetId() );
3840 event.SetEventObject( GetParent() );
3841 GetParent()->GetEventHandler()->ProcessEvent( event );
7c0ea335 3842
b54e41c5
VZ
3843 if ( IsVirtual() )
3844 {
3845 m_countVirt = 0;
3846
3847 ResetVisibleLinesRange();
3848 }
3849
6b4a8d93
VZ
3850 if ( InReportView() )
3851 {
3852 ResetVisibleLinesRange();
3853 }
3854
5b077d48 3855 m_lines.Clear();
cf1dfa6b 3856
b54e41c5 3857 m_selStore.Clear();
e1e955e1 3858}
c801d85f 3859
12c1b46a 3860void wxListMainWindow::DeleteEverything()
c801d85f 3861{
12c1b46a 3862 DeleteAllItems();
f6bcfd97 3863
5b077d48 3864 m_columns.Clear();
e1e955e1 3865}
c801d85f 3866
cf1dfa6b
VZ
3867// ----------------------------------------------------------------------------
3868// scanning for an item
3869// ----------------------------------------------------------------------------
3870
debe6624 3871void wxListMainWindow::EnsureVisible( long index )
c801d85f 3872{
cf1dfa6b
VZ
3873 wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(),
3874 _T("invalid index in EnsureVisible") );
3875
3876 // We have to call this here because the label in question might just have
3877 // been added and no screen update taken place.
3878 if (m_dirty)
3879 wxSafeYield();
dc6c62a9 3880
cf1dfa6b
VZ
3881 size_t oldCurrent = m_current;
3882 m_current = (size_t)index;
3883 MoveToFocus();
5b077d48 3884 m_current = oldCurrent;
e1e955e1 3885}
c801d85f 3886
debe6624 3887long wxListMainWindow::FindItem(long start, const wxString& str, bool WXUNUSED(partial) )
c801d85f 3888{
5b077d48
RR
3889 long pos = start;
3890 wxString tmp = str;
cf1dfa6b
VZ
3891 if (pos < 0)
3892 pos = 0;
54442116 3893
cf1dfa6b
VZ
3894 size_t count = GetItemCount();
3895 for ( size_t i = (size_t)pos; i < count; i++ )
3896 {
3897 wxListLineData *line = GetLine(i);
3898 if ( line->GetText(0) == tmp )
3899 return i;
5b077d48 3900 }
cf1dfa6b
VZ
3901
3902 return wxNOT_FOUND;
e1e955e1 3903}
c801d85f 3904
debe6624 3905long wxListMainWindow::FindItem(long start, long data)
c801d85f 3906{
5b077d48 3907 long pos = start;
cf1dfa6b
VZ
3908 if (pos < 0)
3909 pos = 0;
3910
3911 size_t count = GetItemCount();
3912 for (size_t i = (size_t)pos; i < count; i++)
5b077d48 3913 {
cf1dfa6b 3914 wxListLineData *line = GetLine(i);
5b077d48
RR
3915 wxListItem item;
3916 line->GetItem( 0, item );
cf1dfa6b
VZ
3917 if (item.m_data == data)
3918 return i;
5b077d48 3919 }
cf1dfa6b
VZ
3920
3921 return wxNOT_FOUND;
e1e955e1 3922}
c801d85f 3923
debe6624 3924long wxListMainWindow::HitTest( int x, int y, int &flags )
c801d85f 3925{
aaef15bf 3926 CalcUnscrolledPosition( x, y, &x, &y );
e8741cca 3927
5cd89174 3928 if ( HasFlag(wxLC_REPORT) )
c801d85f 3929 {
5cd89174
VZ
3930 size_t current = y / GetLineHeight();
3931 flags = HitTestLine(current, x, y);
3932 if ( flags )
3933 return current;
3934 }
3935 else // !report
3936 {
3937 // TODO: optimize it too! this is less simple than for report view but
3938 // enumerating all items is still not a way to do it!!
3939 size_t count = GetItemCount();
3940 for ( size_t current = 0; current < count; current++ )
5b077d48 3941 {
5cd89174
VZ
3942 flags = HitTestLine(current, x, y);
3943 if ( flags )
3944 return current;
5b077d48 3945 }
e1e955e1 3946 }
cf1dfa6b
VZ
3947
3948 return wxNOT_FOUND;
e1e955e1 3949}
c801d85f 3950
cf1dfa6b
VZ
3951// ----------------------------------------------------------------------------
3952// adding stuff
3953// ----------------------------------------------------------------------------
3954
c801d85f
KB
3955void wxListMainWindow::InsertItem( wxListItem &item )
3956{
cf1dfa6b
VZ
3957 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") );
3958
3959 size_t count = GetItemCount();
3960 wxCHECK_RET( item.m_itemId >= 0 && (size_t)item.m_itemId <= count,
3961 _T("invalid item index") );
3962
3963 size_t id = item.m_itemId;
3964
5b077d48 3965 m_dirty = TRUE;
cf1dfa6b 3966
5b077d48 3967 int mode = 0;
cf1dfa6b 3968 if ( HasFlag(wxLC_REPORT) )
1370703e 3969 mode = wxLC_REPORT;
cf1dfa6b 3970 else if ( HasFlag(wxLC_LIST) )
1370703e 3971 mode = wxLC_LIST;
cf1dfa6b 3972 else if ( HasFlag(wxLC_ICON) )
1370703e 3973 mode = wxLC_ICON;
cf1dfa6b 3974 else if ( HasFlag(wxLC_SMALL_ICON) )
1370703e
VZ
3975 mode = wxLC_ICON; // no typo
3976 else
3977 {
3978 wxFAIL_MSG( _T("unknown mode") );
3979 }
004fd0c8 3980
5cd89174 3981 wxListLineData *line = new wxListLineData(this);
004fd0c8 3982
5b077d48 3983 line->SetItem( 0, item );
cf1dfa6b
VZ
3984
3985 m_lines.Insert( line, id );
5cd89174 3986
b84839ae 3987 m_dirty = TRUE;
5cd89174 3988 RefreshLines(id, GetItemCount() - 1);
e1e955e1 3989}
c801d85f 3990
debe6624 3991void wxListMainWindow::InsertColumn( long col, wxListItem &item )
c801d85f 3992{
5b077d48 3993 m_dirty = TRUE;
cf1dfa6b 3994 if ( HasFlag(wxLC_REPORT) )
3db7be80 3995 {
54442116
VZ
3996 if (item.m_width == wxLIST_AUTOSIZE_USEHEADER)
3997 item.m_width = GetTextLength( item.m_text );
5b077d48
RR
3998 wxListHeaderData *column = new wxListHeaderData( item );
3999 if ((col >= 0) && (col < (int)m_columns.GetCount()))
4000 {
24b9f055
VZ
4001 wxListHeaderDataList::Node *node = m_columns.Item( col );
4002 m_columns.Insert( node, column );
5b077d48
RR
4003 }
4004 else
4005 {
4006 m_columns.Append( column );
4007 }
3db7be80 4008 }
e1e955e1 4009}
c801d85f 4010
cf1dfa6b
VZ
4011// ----------------------------------------------------------------------------
4012// sorting
4013// ----------------------------------------------------------------------------
4014
c801d85f
KB
4015wxListCtrlCompare list_ctrl_compare_func_2;
4016long list_ctrl_compare_data;
4017
f6bcfd97 4018int LINKAGEMODE list_ctrl_compare_func_1( wxListLineData **arg1, wxListLineData **arg2 )
c801d85f 4019{
f6bcfd97
BP
4020 wxListLineData *line1 = *arg1;
4021 wxListLineData *line2 = *arg2;
5b077d48
RR
4022 wxListItem item;
4023 line1->GetItem( 0, item );
4024 long data1 = item.m_data;
4025 line2->GetItem( 0, item );
4026 long data2 = item.m_data;
4027 return list_ctrl_compare_func_2( data1, data2, list_ctrl_compare_data );
e1e955e1 4028}
c801d85f
KB
4029
4030void wxListMainWindow::SortItems( wxListCtrlCompare fn, long data )
4031{
5b077d48
RR
4032 list_ctrl_compare_func_2 = fn;
4033 list_ctrl_compare_data = data;
4034 m_lines.Sort( list_ctrl_compare_func_1 );
af7c1052 4035 m_dirty = TRUE;
e1e955e1 4036}
c801d85f 4037
cf1dfa6b
VZ
4038// ----------------------------------------------------------------------------
4039// scrolling
4040// ----------------------------------------------------------------------------
4041
7c74e7fe
SC
4042void wxListMainWindow::OnScroll(wxScrollWinEvent& event)
4043{
b54e41c5
VZ
4044 // update our idea of which lines are shown when we redraw the window the
4045 // next time
4046 ResetVisibleLinesRange();
cf1dfa6b 4047
29149a64 4048 // FIXME
3a8c693a 4049#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
29149a64
VZ
4050 wxScrolledWindow::OnScroll(event);
4051#else
1e6feb95 4052 HandleOnScroll( event );
29149a64 4053#endif
30954328 4054
cf1dfa6b 4055 if ( event.GetOrientation() == wxHORIZONTAL && HasHeader() )
7c74e7fe 4056 {
cf1dfa6b
VZ
4057 wxListCtrl* lc = GetListCtrl();
4058 wxCHECK_RET( lc, _T("no listctrl window?") );
4059
4060 lc->m_headerWin->Refresh() ;
7c74e7fe 4061#ifdef __WXMAC__
cf1dfa6b 4062 lc->m_headerWin->MacUpdateImmediately() ;
7c74e7fe 4063#endif
7c74e7fe 4064 }
cf1dfa6b
VZ
4065}
4066
5cd89174
VZ
4067int wxListMainWindow::GetCountPerPage() const
4068{
4069 if ( !m_linesPerPage )
4070 {
4071 wxConstCast(this, wxListMainWindow)->
4072 m_linesPerPage = GetClientSize().y / GetLineHeight();
4073 }
4074
4075 return m_linesPerPage;
4076}
4077
b54e41c5 4078void wxListMainWindow::GetVisibleLinesRange(size_t *from, size_t *to)
cf1dfa6b 4079{
b54e41c5 4080 wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("this is for report mode only") );
cf1dfa6b 4081
b54e41c5
VZ
4082 if ( m_lineFrom == (size_t)-1 )
4083 {
b54e41c5 4084 size_t count = GetItemCount();
6522713c
VZ
4085 if ( count )
4086 {
4087 m_lineFrom = GetScrollPos(wxVERTICAL);
cf1dfa6b 4088
152c57f2
VZ
4089 // this may happen if SetScrollbars() hadn't been called yet
4090 if ( m_lineFrom >= count )
bcc0da5c 4091 m_lineFrom = count - 1;
cf1dfa6b 4092
6522713c
VZ
4093 // we redraw one extra line but this is needed to make the redrawing
4094 // logic work when there is a fractional number of lines on screen
4095 m_lineTo = m_lineFrom + m_linesPerPage;
4096 if ( m_lineTo >= count )
4097 m_lineTo = count - 1;
4098 }
4099 else // empty control
4100 {
4101 m_lineFrom = 0;
4102 m_lineTo = (size_t)-1;
4103 }
cf1dfa6b 4104 }
b54e41c5 4105
ae167d2f
VZ
4106 wxASSERT_MSG( IsEmpty() ||
4107 (m_lineFrom <= m_lineTo && m_lineTo < GetItemCount()),
6b4a8d93
VZ
4108 _T("GetVisibleLinesRange() returns incorrect result") );
4109
b54e41c5
VZ
4110 if ( from )
4111 *from = m_lineFrom;
4112 if ( to )
4113 *to = m_lineTo;
7c74e7fe
SC
4114}
4115
c801d85f
KB
4116// -------------------------------------------------------------------------------------
4117// wxListItem
4118// -------------------------------------------------------------------------------------
4119
4120IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
4121
fd9811b1 4122wxListItem::wxListItem()
c801d85f 4123{
63852e78
RR
4124 m_mask = 0;
4125 m_itemId = 0;
4126 m_col = 0;
4127 m_state = 0;
4128 m_stateMask = 0;
4129 m_image = 0;
4130 m_data = 0;
4131 m_format = wxLIST_FORMAT_CENTRE;
4132 m_width = 0;
aaa37c0d
VZ
4133
4134 m_attr = NULL;
c801d85f
KB
4135}
4136
9b00bb16
RR
4137void wxListItem::Clear()
4138{
4139 m_mask = 0;
4140 m_itemId = 0;
4141 m_col = 0;
4142 m_state = 0;
4143 m_stateMask = 0;
4144 m_image = 0;
4145 m_data = 0;
4146 m_format = wxLIST_FORMAT_CENTRE;
4147 m_width = 0;
54442116 4148 m_text = _T("");
9b00bb16 4149
cf1dfa6b 4150 ClearAttributes();
9b00bb16
RR
4151}
4152
4153void wxListItem::ClearAttributes()
4154{
cf1dfa6b
VZ
4155 if (m_attr)
4156 {
4157 delete m_attr;
4158 m_attr = NULL;
4159 }
9b00bb16
RR
4160}
4161
c801d85f
KB
4162// -------------------------------------------------------------------------------------
4163// wxListEvent
4164// -------------------------------------------------------------------------------------
4165
92976ab6 4166IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
c801d85f 4167
cf1dfa6b
VZ
4168wxListEvent::wxListEvent( wxEventType commandType, int id )
4169 : wxNotifyEvent( commandType, id )
c801d85f 4170{
5b077d48
RR
4171 m_code = 0;
4172 m_itemIndex = 0;
4173 m_oldItemIndex = 0;
4174 m_col = 0;
4175 m_cancelled = FALSE;
4176 m_pointDrag.x = 0;
4177 m_pointDrag.y = 0;
e1e955e1 4178}
c801d85f 4179
72a7edf0
RR
4180void wxListEvent::CopyObject(wxObject& object_dest) const
4181{
4182 wxListEvent *obj = (wxListEvent *)&object_dest;
4183
4184 wxNotifyEvent::CopyObject(object_dest);
4185
4186 obj->m_code = m_code;
4187 obj->m_itemIndex = m_itemIndex;
4188 obj->m_oldItemIndex = m_oldItemIndex;
4189 obj->m_col = m_col;
4190 obj->m_cancelled = m_cancelled;
4191 obj->m_pointDrag = m_pointDrag;
4192 obj->m_item.m_mask = m_item.m_mask;
4193 obj->m_item.m_itemId = m_item.m_itemId;
4194 obj->m_item.m_col = m_item.m_col;
4195 obj->m_item.m_state = m_item.m_state;
4196 obj->m_item.m_stateMask = m_item.m_stateMask;
4197 obj->m_item.m_text = m_item.m_text;
4198 obj->m_item.m_image = m_item.m_image;
4199 obj->m_item.m_data = m_item.m_data;
4200 obj->m_item.m_format = m_item.m_format;
4201 obj->m_item.m_width = m_item.m_width;
aaa37c0d
VZ
4202
4203 if ( m_item.HasAttributes() )
4204 {
4205 obj->m_item.SetTextColour(m_item.GetTextColour());
4206 }
72a7edf0
RR
4207}
4208
c801d85f
KB
4209// -------------------------------------------------------------------------------------
4210// wxListCtrl
4211// -------------------------------------------------------------------------------------
4212
4213IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxControl)
4214
4215BEGIN_EVENT_TABLE(wxListCtrl,wxControl)
cf1dfa6b
VZ
4216 EVT_SIZE(wxListCtrl::OnSize)
4217 EVT_IDLE(wxListCtrl::OnIdle)
c801d85f
KB
4218END_EVENT_TABLE()
4219
fd9811b1 4220wxListCtrl::wxListCtrl()
c801d85f 4221{
5b077d48
RR
4222 m_imageListNormal = (wxImageList *) NULL;
4223 m_imageListSmall = (wxImageList *) NULL;
4224 m_imageListState = (wxImageList *) NULL;
cf1dfa6b
VZ
4225
4226 m_ownsImageListNormal =
4227 m_ownsImageListSmall =
4228 m_ownsImageListState = FALSE;
4229
5b077d48
RR
4230 m_mainWin = (wxListMainWindow*) NULL;
4231 m_headerWin = (wxListHeaderWindow*) NULL;
c801d85f
KB
4232}
4233
fd9811b1 4234wxListCtrl::~wxListCtrl()
c801d85f 4235{
b54e41c5
VZ
4236 if ( m_mainWin )
4237 m_mainWin->ResetCurrent();
4238
cf1dfa6b
VZ
4239 if (m_ownsImageListNormal)
4240 delete m_imageListNormal;
4241 if (m_ownsImageListSmall)
4242 delete m_imageListSmall;
4243 if (m_ownsImageListState)
4244 delete m_imageListState;
4245}
4246
4247void wxListCtrl::CreateHeaderWindow()
4248{
4249 m_headerWin = new wxListHeaderWindow
4250 (
4251 this, -1, m_mainWin,
4252 wxPoint(0, 0),
4253 wxSize(GetClientSize().x, HEADER_HEIGHT),
4254 wxTAB_TRAVERSAL
4255 );
c801d85f
KB
4256}
4257
25e3a937
VZ
4258bool wxListCtrl::Create(wxWindow *parent,
4259 wxWindowID id,
4260 const wxPoint &pos,
4261 const wxSize &size,
4262 long style,
25e3a937 4263 const wxValidator &validator,
25e3a937 4264 const wxString &name)
c801d85f 4265{
cf1dfa6b
VZ
4266 m_imageListNormal =
4267 m_imageListSmall =
5b077d48 4268 m_imageListState = (wxImageList *) NULL;
cf1dfa6b
VZ
4269 m_ownsImageListNormal =
4270 m_ownsImageListSmall =
4271 m_ownsImageListState = FALSE;
4272
5b077d48
RR
4273 m_mainWin = (wxListMainWindow*) NULL;
4274 m_headerWin = (wxListHeaderWindow*) NULL;
bd8289c1 4275
b54e41c5 4276 if ( !(style & wxLC_MASK_TYPE) )
5b077d48 4277 {
25e3a937 4278 style = style | wxLC_LIST;
5b077d48 4279 }
f6bcfd97 4280
cf1dfa6b
VZ
4281 if ( !wxControl::Create( parent, id, pos, size, style, validator, name ) )
4282 return FALSE;
f6bcfd97 4283
b54e41c5
VZ
4284 // don't create the inner window with the border
4285 style &= ~wxSUNKEN_BORDER;
bd8289c1 4286
25e3a937 4287 m_mainWin = new wxListMainWindow( this, -1, wxPoint(0,0), size, style );
bd8289c1 4288
b54e41c5 4289 if ( HasFlag(wxLC_REPORT) )
ea451729 4290 {
cf1dfa6b
VZ
4291 CreateHeaderWindow();
4292
b54e41c5 4293 if ( HasFlag(wxLC_NO_HEADER) )
cf1dfa6b
VZ
4294 {
4295 // VZ: why do we create it at all then?
ea451729 4296 m_headerWin->Show( FALSE );
cf1dfa6b 4297 }
ea451729 4298 }
bd8289c1 4299
cf1dfa6b 4300 return TRUE;
e1e955e1 4301}
c801d85f 4302
debe6624 4303void wxListCtrl::SetSingleStyle( long style, bool add )
c801d85f 4304{
b54e41c5
VZ
4305 wxASSERT_MSG( !(style & wxLC_VIRTUAL),
4306 _T("wxLC_VIRTUAL can't be [un]set") );
4307
f03fc89f 4308 long flag = GetWindowStyle();
bd8289c1 4309
5b077d48
RR
4310 if (add)
4311 {
cf1dfa6b 4312 if (style & wxLC_MASK_TYPE)
b54e41c5 4313 flag &= ~(wxLC_MASK_TYPE | wxLC_VIRTUAL);
cf1dfa6b
VZ
4314 if (style & wxLC_MASK_ALIGN)
4315 flag &= ~wxLC_MASK_ALIGN;
4316 if (style & wxLC_MASK_SORT)
4317 flag &= ~wxLC_MASK_SORT;
5b077d48 4318 }
c801d85f 4319
5b077d48
RR
4320 if (add)
4321 {
4322 flag |= style;
4323 }
4324 else
4325 {
cf1dfa6b 4326 flag &= ~style;
5b077d48 4327 }
bd8289c1 4328
5b077d48 4329 SetWindowStyleFlag( flag );
e1e955e1 4330}
c801d85f 4331
debe6624 4332void wxListCtrl::SetWindowStyleFlag( long flag )
c801d85f 4333{
121a3581
RR
4334 if (m_mainWin)
4335 {
4336 m_mainWin->DeleteEverything();
c801d85f 4337
121a3581
RR
4338 int width = 0;
4339 int height = 0;
4340 GetClientSize( &width, &height );
c801d85f 4341
121a3581 4342 if (flag & wxLC_REPORT)
5b077d48 4343 {
121a3581 4344 if (!HasFlag(wxLC_REPORT))
5b077d48 4345 {
121a3581
RR
4346 if (!m_headerWin)
4347 {
cf1dfa6b
VZ
4348 CreateHeaderWindow();
4349
bffa1c77
VZ
4350 if (HasFlag(wxLC_NO_HEADER))
4351 m_headerWin->Show( FALSE );
121a3581
RR
4352 }
4353 else
004fd0c8 4354 {
bffa1c77
VZ
4355 if (flag & wxLC_NO_HEADER)
4356 m_headerWin->Show( FALSE );
4357 else
8636aed8 4358 m_headerWin->Show( TRUE );
004fd0c8 4359 }
5b077d48
RR
4360 }
4361 }
cf1dfa6b 4362 else // !report
5b077d48 4363 {
cf1dfa6b 4364 if ( m_mainWin->HasHeader() )
121a3581
RR
4365 {
4366 m_headerWin->Show( FALSE );
4367 }
bffa1c77 4368 }
e1e955e1 4369 }
004fd0c8 4370
5b077d48 4371 wxWindow::SetWindowStyleFlag( flag );
e1e955e1 4372}
c801d85f 4373
e487524e 4374bool wxListCtrl::GetColumn(int col, wxListItem &item) const
c801d85f 4375{
5b077d48
RR
4376 m_mainWin->GetColumn( col, item );
4377 return TRUE;
e1e955e1 4378}
c801d85f 4379
debe6624 4380bool wxListCtrl::SetColumn( int col, wxListItem& item )
c801d85f 4381{
5b077d48
RR
4382 m_mainWin->SetColumn( col, item );
4383 return TRUE;
e1e955e1 4384}
c801d85f 4385
e487524e 4386int wxListCtrl::GetColumnWidth( int col ) const
c801d85f 4387{
5b077d48 4388 return m_mainWin->GetColumnWidth( col );
e1e955e1 4389}
c801d85f 4390
debe6624 4391bool wxListCtrl::SetColumnWidth( int col, int width )
c801d85f 4392{
5b077d48
RR
4393 m_mainWin->SetColumnWidth( col, width );
4394 return TRUE;
e1e955e1 4395}
c801d85f 4396
fd9811b1 4397int wxListCtrl::GetCountPerPage() const
c801d85f
KB
4398{
4399 return m_mainWin->GetCountPerPage(); // different from Windows ?
e1e955e1 4400}
c801d85f 4401
e487524e 4402bool wxListCtrl::GetItem( wxListItem &info ) const
c801d85f 4403{
5b077d48
RR
4404 m_mainWin->GetItem( info );
4405 return TRUE;
e1e955e1 4406}
c801d85f
KB
4407
4408bool wxListCtrl::SetItem( wxListItem &info )
4409{
5b077d48
RR
4410 m_mainWin->SetItem( info );
4411 return TRUE;
e1e955e1 4412}
c801d85f 4413
debe6624 4414long wxListCtrl::SetItem( long index, int col, const wxString& label, int imageId )
c801d85f 4415{
5b077d48
RR
4416 wxListItem info;
4417 info.m_text = label;
4418 info.m_mask = wxLIST_MASK_TEXT;
4419 info.m_itemId = index;
4420 info.m_col = col;
4421 if ( imageId > -1 )
4422 {
4423 info.m_image = imageId;
4424 info.m_mask |= wxLIST_MASK_IMAGE;
4425 };
4426 m_mainWin->SetItem(info);
4427 return TRUE;
e1e955e1 4428}
c801d85f 4429
e487524e 4430int wxListCtrl::GetItemState( long item, long stateMask ) const
c801d85f 4431{
5b077d48 4432 return m_mainWin->GetItemState( item, stateMask );
e1e955e1 4433}
c801d85f 4434
debe6624 4435bool wxListCtrl::SetItemState( long item, long state, long stateMask )
c801d85f 4436{
5b077d48
RR
4437 m_mainWin->SetItemState( item, state, stateMask );
4438 return TRUE;
e1e955e1 4439}
c801d85f 4440
debe6624 4441bool wxListCtrl::SetItemImage( long item, int image, int WXUNUSED(selImage) )
c801d85f 4442{
5b077d48
RR
4443 wxListItem info;
4444 info.m_image = image;
4445 info.m_mask = wxLIST_MASK_IMAGE;
4446 info.m_itemId = item;
4447 m_mainWin->SetItem( info );
4448 return TRUE;
e1e955e1 4449}
c801d85f 4450
e487524e 4451wxString wxListCtrl::GetItemText( long item ) const
c801d85f 4452{
5b077d48
RR
4453 wxListItem info;
4454 info.m_itemId = item;
4455 m_mainWin->GetItem( info );
4456 return info.m_text;
e1e955e1 4457}
c801d85f 4458
debe6624 4459void wxListCtrl::SetItemText( long item, const wxString &str )
c801d85f 4460{
5b077d48
RR
4461 wxListItem info;
4462 info.m_mask = wxLIST_MASK_TEXT;
4463 info.m_itemId = item;
4464 info.m_text = str;
4465 m_mainWin->SetItem( info );
e1e955e1 4466}
c801d85f 4467
e487524e 4468long wxListCtrl::GetItemData( long item ) const
c801d85f 4469{
5b077d48
RR
4470 wxListItem info;
4471 info.m_itemId = item;
4472 m_mainWin->GetItem( info );
4473 return info.m_data;
e1e955e1 4474}
c801d85f 4475
debe6624 4476bool wxListCtrl::SetItemData( long item, long data )
c801d85f 4477{
5b077d48
RR
4478 wxListItem info;
4479 info.m_mask = wxLIST_MASK_DATA;
4480 info.m_itemId = item;
4481 info.m_data = data;
4482 m_mainWin->SetItem( info );
4483 return TRUE;
e1e955e1 4484}
c801d85f 4485
0a240683 4486bool wxListCtrl::GetItemRect( long item, wxRect &rect, int WXUNUSED(code) ) const
c801d85f 4487{
5b077d48
RR
4488 m_mainWin->GetItemRect( item, rect );
4489 return TRUE;
e1e955e1 4490}
c801d85f 4491
e487524e 4492bool wxListCtrl::GetItemPosition( long item, wxPoint& pos ) const
c801d85f 4493{
5b077d48
RR
4494 m_mainWin->GetItemPosition( item, pos );
4495 return TRUE;
e1e955e1 4496}
c801d85f 4497
debe6624 4498bool wxListCtrl::SetItemPosition( long WXUNUSED(item), const wxPoint& WXUNUSED(pos) )
c801d85f 4499{
5b077d48 4500 return 0;
e1e955e1 4501}
c801d85f 4502
fd9811b1 4503int wxListCtrl::GetItemCount() const
c801d85f 4504{
5b077d48 4505 return m_mainWin->GetItemCount();
e1e955e1 4506}
c801d85f 4507
fd9811b1 4508int wxListCtrl::GetColumnCount() const
92976ab6 4509{
5b077d48 4510 return m_mainWin->GetColumnCount();
92976ab6
RR
4511}
4512
33d0b396
RR
4513void wxListCtrl::SetItemSpacing( int spacing, bool isSmall )
4514{
5b077d48 4515 m_mainWin->SetItemSpacing( spacing, isSmall );
e1e955e1 4516}
33d0b396 4517
e487524e 4518int wxListCtrl::GetItemSpacing( bool isSmall ) const
c801d85f 4519{
5b077d48 4520 return m_mainWin->GetItemSpacing( isSmall );
e1e955e1 4521}
c801d85f 4522
fd9811b1 4523int wxListCtrl::GetSelectedItemCount() const
c801d85f 4524{
5b077d48 4525 return m_mainWin->GetSelectedItemCount();
e1e955e1 4526}
c801d85f 4527
fd9811b1 4528wxColour wxListCtrl::GetTextColour() const
c801d85f 4529{
0530737d 4530 return GetForegroundColour();
e1e955e1 4531}
c801d85f 4532
0530737d 4533void wxListCtrl::SetTextColour(const wxColour& col)
c801d85f 4534{
0530737d 4535 SetForegroundColour(col);
e1e955e1 4536}
c801d85f 4537
fd9811b1 4538long wxListCtrl::GetTopItem() const
c801d85f 4539{
5b077d48 4540 return 0;
e1e955e1 4541}
c801d85f 4542
6de97a3b 4543long wxListCtrl::GetNextItem( long item, int geom, int state ) const
c801d85f 4544{
5b077d48 4545 return m_mainWin->GetNextItem( item, geom, state );
e1e955e1 4546}
c801d85f 4547
e487524e 4548wxImageList *wxListCtrl::GetImageList(int which) const
c801d85f 4549{
5b077d48
RR
4550 if (which == wxIMAGE_LIST_NORMAL)
4551 {
4552 return m_imageListNormal;
4553 }
4554 else if (which == wxIMAGE_LIST_SMALL)
4555 {
4556 return m_imageListSmall;
4557 }
4558 else if (which == wxIMAGE_LIST_STATE)
4559 {
4560 return m_imageListState;
4561 }
4562 return (wxImageList *) NULL;
e1e955e1 4563}
c801d85f 4564
debe6624 4565void wxListCtrl::SetImageList( wxImageList *imageList, int which )
c801d85f 4566{
2e12c11a
VS
4567 if ( which == wxIMAGE_LIST_NORMAL )
4568 {
4569 if (m_ownsImageListNormal) delete m_imageListNormal;
4570 m_imageListNormal = imageList;
4571 m_ownsImageListNormal = FALSE;
4572 }
4573 else if ( which == wxIMAGE_LIST_SMALL )
4574 {
4575 if (m_ownsImageListSmall) delete m_imageListSmall;
4576 m_imageListSmall = imageList;
4577 m_ownsImageListSmall = FALSE;
4578 }
4579 else if ( which == wxIMAGE_LIST_STATE )
4580 {
4581 if (m_ownsImageListState) delete m_imageListState;
4582 m_imageListState = imageList;
4583 m_ownsImageListState = FALSE;
4584 }
4585
5b077d48 4586 m_mainWin->SetImageList( imageList, which );
e1e955e1 4587}
c801d85f 4588
2e12c11a
VS
4589void wxListCtrl::AssignImageList(wxImageList *imageList, int which)
4590{
4591 SetImageList(imageList, which);
4592 if ( which == wxIMAGE_LIST_NORMAL )
4593 m_ownsImageListNormal = TRUE;
4594 else if ( which == wxIMAGE_LIST_SMALL )
4595 m_ownsImageListSmall = TRUE;
4596 else if ( which == wxIMAGE_LIST_STATE )
4597 m_ownsImageListState = TRUE;
4598}
4599
debe6624 4600bool wxListCtrl::Arrange( int WXUNUSED(flag) )
c801d85f 4601{
5b077d48 4602 return 0;
e1e955e1 4603}
c801d85f 4604
debe6624 4605bool wxListCtrl::DeleteItem( long item )
c801d85f 4606{
5b077d48
RR
4607 m_mainWin->DeleteItem( item );
4608 return TRUE;
e1e955e1 4609}
c801d85f 4610
fd9811b1 4611bool wxListCtrl::DeleteAllItems()
c801d85f 4612{
5b077d48
RR
4613 m_mainWin->DeleteAllItems();
4614 return TRUE;
e1e955e1 4615}
c801d85f 4616
4f22cf8d 4617bool wxListCtrl::DeleteAllColumns()
bd8289c1 4618{
24b9f055
VZ
4619 size_t count = m_mainWin->m_columns.GetCount();
4620 for ( size_t n = 0; n < count; n++ )
bd8289c1 4621 DeleteColumn(n);
bffa1c77 4622
5b077d48 4623 return TRUE;
4f22cf8d
RR
4624}
4625
4626void wxListCtrl::ClearAll()
4627{
5b077d48 4628 m_mainWin->DeleteEverything();
bd8289c1
VZ
4629}
4630
debe6624 4631bool wxListCtrl::DeleteColumn( int col )
c801d85f 4632{
5b077d48
RR
4633 m_mainWin->DeleteColumn( col );
4634 return TRUE;
e1e955e1 4635}
c801d85f 4636
e179bd65 4637void wxListCtrl::Edit( long item )
c801d85f 4638{
cf1dfa6b 4639 m_mainWin->EditLabel( item );
e1e955e1 4640}
c801d85f 4641
debe6624 4642bool wxListCtrl::EnsureVisible( long item )
c801d85f 4643{
5b077d48
RR
4644 m_mainWin->EnsureVisible( item );
4645 return TRUE;
e1e955e1 4646}
c801d85f 4647
debe6624 4648long wxListCtrl::FindItem( long start, const wxString& str, bool partial )
c801d85f 4649{
5b077d48 4650 return m_mainWin->FindItem( start, str, partial );
e1e955e1 4651}
c801d85f 4652
debe6624 4653long wxListCtrl::FindItem( long start, long data )
c801d85f 4654{
5b077d48 4655 return m_mainWin->FindItem( start, data );
e1e955e1 4656}
c801d85f 4657
bd8289c1 4658long wxListCtrl::FindItem( long WXUNUSED(start), const wxPoint& WXUNUSED(pt),
debe6624 4659 int WXUNUSED(direction))
c801d85f 4660{
5b077d48 4661 return 0;
e1e955e1 4662}
c801d85f
KB
4663
4664long wxListCtrl::HitTest( const wxPoint &point, int &flags )
4665{
5b077d48 4666 return m_mainWin->HitTest( (int)point.x, (int)point.y, flags );
e1e955e1 4667}
c801d85f
KB
4668
4669long wxListCtrl::InsertItem( wxListItem& info )
4670{
5b077d48 4671 m_mainWin->InsertItem( info );
2ebcd5f5 4672 return info.m_itemId;
e1e955e1 4673}
c801d85f 4674
debe6624 4675long wxListCtrl::InsertItem( long index, const wxString &label )
c801d85f 4676{
51cc4dad
RR
4677 wxListItem info;
4678 info.m_text = label;
4679 info.m_mask = wxLIST_MASK_TEXT;
4680 info.m_itemId = index;
4681 return InsertItem( info );
e1e955e1 4682}
c801d85f 4683
debe6624 4684long wxListCtrl::InsertItem( long index, int imageIndex )
c801d85f 4685{
51cc4dad
RR
4686 wxListItem info;
4687 info.m_mask = wxLIST_MASK_IMAGE;
4688 info.m_image = imageIndex;
4689 info.m_itemId = index;
4690 return InsertItem( info );
e1e955e1 4691}
c801d85f 4692
debe6624 4693long wxListCtrl::InsertItem( long index, const wxString &label, int imageIndex )
c801d85f 4694{
51cc4dad
RR
4695 wxListItem info;
4696 info.m_text = label;
4697 info.m_image = imageIndex;
4698 info.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_IMAGE;
4699 info.m_itemId = index;
4700 return InsertItem( info );
e1e955e1 4701}
c801d85f 4702
debe6624 4703long wxListCtrl::InsertColumn( long col, wxListItem &item )
c801d85f 4704{
d3e90957 4705 wxASSERT( m_headerWin );
51cc4dad 4706 m_mainWin->InsertColumn( col, item );
d3e90957 4707 m_headerWin->Refresh();
25e3a937 4708
51cc4dad 4709 return 0;
e1e955e1 4710}
c801d85f 4711
debe6624
JS
4712long wxListCtrl::InsertColumn( long col, const wxString &heading,
4713 int format, int width )
c801d85f 4714{
51cc4dad
RR
4715 wxListItem item;
4716 item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
4717 item.m_text = heading;
4718 if (width >= -2)
4719 {
4720 item.m_mask |= wxLIST_MASK_WIDTH;
4721 item.m_width = width;
4722 }
4723 item.m_format = format;
c801d85f 4724
51cc4dad 4725 return InsertColumn( col, item );
e1e955e1 4726}
c801d85f 4727
debe6624 4728bool wxListCtrl::ScrollList( int WXUNUSED(dx), int WXUNUSED(dy) )
c801d85f 4729{
51cc4dad 4730 return 0;
e1e955e1 4731}
c801d85f
KB
4732
4733// Sort items.
4734// fn is a function which takes 3 long arguments: item1, item2, data.
4735// item1 is the long data associated with a first item (NOT the index).
4736// item2 is the long data associated with a second item (NOT the index).
4737// data is the same value as passed to SortItems.
4738// The return value is a negative number if the first item should precede the second
4739// item, a positive number of the second item should precede the first,
4740// or zero if the two items are equivalent.
4741// data is arbitrary data to be passed to the sort function.
4742
4743bool wxListCtrl::SortItems( wxListCtrlCompare fn, long data )
4744{
51cc4dad
RR
4745 m_mainWin->SortItems( fn, data );
4746 return TRUE;
e1e955e1 4747}
c801d85f 4748
cf1dfa6b 4749// ----------------------------------------------------------------------------
b54e41c5 4750// event handlers
cf1dfa6b
VZ
4751// ----------------------------------------------------------------------------
4752
b54e41c5 4753void wxListCtrl::OnSize(wxSizeEvent& event)
53010e52 4754{
b54e41c5 4755 if ( !m_mainWin )
cf1dfa6b 4756 return;
53010e52 4757
b54e41c5 4758 int cw, ch;
51cc4dad 4759 GetClientSize( &cw, &ch );
bd8289c1 4760
cf1dfa6b 4761 if ( m_mainWin->HasHeader() )
51cc4dad 4762 {
cf1dfa6b
VZ
4763 m_headerWin->SetSize( 0, 0, cw, HEADER_HEIGHT );
4764 m_mainWin->SetSize( 0, HEADER_HEIGHT + 1, cw, ch - HEADER_HEIGHT - 1 );
51cc4dad 4765 }
cf1dfa6b 4766 else // no header window
51cc4dad 4767 {
cf1dfa6b 4768 m_mainWin->SetSize( 0, 0, cw, ch );
51cc4dad 4769 }
bd8289c1 4770
b54e41c5
VZ
4771 m_mainWin->RecalculatePositions();
4772}
cf1dfa6b 4773
b54e41c5
VZ
4774void wxListCtrl::OnIdle( wxIdleEvent & event )
4775{
4776 event.Skip();
f6bcfd97 4777
b54e41c5
VZ
4778 // do it only if needed
4779 if ( !m_mainWin->m_dirty )
4780 return;
4781
4782 m_mainWin->RecalculatePositions();
e1e955e1 4783}
53010e52 4784
cf1dfa6b
VZ
4785// ----------------------------------------------------------------------------
4786// font/colours
4787// ----------------------------------------------------------------------------
4788
f03fc89f 4789bool wxListCtrl::SetBackgroundColour( const wxColour &colour )
bd8289c1 4790{
51cc4dad
RR
4791 if (m_mainWin)
4792 {
4793 m_mainWin->SetBackgroundColour( colour );
4794 m_mainWin->m_dirty = TRUE;
4795 }
004fd0c8 4796
f03fc89f 4797 return TRUE;
e4d06860
RR
4798}
4799
f03fc89f 4800bool wxListCtrl::SetForegroundColour( const wxColour &colour )
bd8289c1 4801{
f03fc89f
VZ
4802 if ( !wxWindow::SetForegroundColour( colour ) )
4803 return FALSE;
004fd0c8 4804
51cc4dad
RR
4805 if (m_mainWin)
4806 {
4807 m_mainWin->SetForegroundColour( colour );
4808 m_mainWin->m_dirty = TRUE;
4809 }
004fd0c8 4810
51cc4dad
RR
4811 if (m_headerWin)
4812 {
4813 m_headerWin->SetForegroundColour( colour );
4814 }
f03fc89f
VZ
4815
4816 return TRUE;
e4d06860 4817}
bd8289c1 4818
f03fc89f 4819bool wxListCtrl::SetFont( const wxFont &font )
bd8289c1 4820{
f03fc89f
VZ
4821 if ( !wxWindow::SetFont( font ) )
4822 return FALSE;
004fd0c8 4823
51cc4dad
RR
4824 if (m_mainWin)
4825 {
4826 m_mainWin->SetFont( font );
4827 m_mainWin->m_dirty = TRUE;
4828 }
004fd0c8 4829
51cc4dad
RR
4830 if (m_headerWin)
4831 {
4832 m_headerWin->SetFont( font );
4833 }
f03fc89f
VZ
4834
4835 return TRUE;
e4d06860 4836}
c801d85f 4837
cf1dfa6b
VZ
4838// ----------------------------------------------------------------------------
4839// methods forwarded to m_mainWin
4840// ----------------------------------------------------------------------------
4841
efbb7287
VZ
4842#if wxUSE_DRAG_AND_DROP
4843
4844void wxListCtrl::SetDropTarget( wxDropTarget *dropTarget )
4845{
4846 m_mainWin->SetDropTarget( dropTarget );
4847}
4848
4849wxDropTarget *wxListCtrl::GetDropTarget() const
4850{
4851 return m_mainWin->GetDropTarget();
4852}
4853
4854#endif // wxUSE_DRAG_AND_DROP
4855
4856bool wxListCtrl::SetCursor( const wxCursor &cursor )
4857{
4858 return m_mainWin ? m_mainWin->wxWindow::SetCursor(cursor) : FALSE;
4859}
4860
4861wxColour wxListCtrl::GetBackgroundColour() const
4862{
4863 return m_mainWin ? m_mainWin->GetBackgroundColour() : wxColour();
4864}
4865
4866wxColour wxListCtrl::GetForegroundColour() const
4867{
4868 return m_mainWin ? m_mainWin->GetForegroundColour() : wxColour();
4869}
4870
4871bool wxListCtrl::DoPopupMenu( wxMenu *menu, int x, int y )
4872{
3a8c693a 4873#if wxUSE_MENUS
efbb7287 4874 return m_mainWin->PopupMenu( menu, x, y );
3a8c693a
VZ
4875#else
4876 return FALSE;
4877#endif // wxUSE_MENUS
efbb7287
VZ
4878}
4879
4880void wxListCtrl::SetFocus()
4881{
4882 /* The test in window.cpp fails as we are a composite
4883 window, so it checks against "this", but not m_mainWin. */
4884 if ( FindFocus() != this )
4885 m_mainWin->SetFocus();
4886}
1e6feb95 4887
2c1f73ee
VZ
4888// ----------------------------------------------------------------------------
4889// virtual list control support
4890// ----------------------------------------------------------------------------
4891
4892wxString wxListCtrl::OnGetItemText(long item, long col) const
4893{
4894 // this is a pure virtual function, in fact - which is not really pure
4895 // because the controls which are not virtual don't need to implement it
4896 wxFAIL_MSG( _T("not supposed to be called") );
4897
4898 return wxEmptyString;
4899}
4900
4901int wxListCtrl::OnGetItemImage(long item) const
4902{
4903 // same as above
4904 wxFAIL_MSG( _T("not supposed to be called") );
4905
4906 return -1;
4907}
4908
6c02c329
VZ
4909wxListItemAttr *wxListCtrl::OnGetItemAttr(long item) const
4910{
4911 wxASSERT_MSG( item >= 0 && item < GetItemCount(),
4912 _T("invalid item index in OnGetItemAttr()") );
4913
4914 // no attributes by default
4915 return NULL;
4916}
4917
2c1f73ee
VZ
4918void wxListCtrl::SetItemCount(long count)
4919{
4920 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
4921
4922 m_mainWin->SetItemCount(count);
4923}
4924
1e6feb95 4925#endif // wxUSE_LISTCTRL