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