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