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