PageRenderTime 60ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/ExtLibs/wxWidgets/src/generic/listctrl.cpp

https://bitbucket.org/cafu/cafu
C++ | 5477 lines | 3958 code | 974 blank | 545 comment | 729 complexity | f6cb5567847a4bd218f002128d7b0f1f MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0, BSD-3-Clause, LGPL-3.0, LGPL-2.1, AGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: src/generic/listctrl.cpp
  3. // Purpose: generic implementation of wxListCtrl
  4. // Author: Robert Roebling
  5. // Vadim Zeitlin (virtual list control support)
  6. // Copyright: (c) 1998 Robert Roebling
  7. // Licence: wxWindows licence
  8. /////////////////////////////////////////////////////////////////////////////
  9. // TODO
  10. //
  11. // 1. we need to implement searching/sorting for virtual controls somehow
  12. // 2. when changing selection the lines are refreshed twice
  13. // For compilers that support precompilation, includes "wx.h".
  14. #include "wx/wxprec.h"
  15. #ifdef __BORLANDC__
  16. #pragma hdrstop
  17. #endif
  18. #if wxUSE_LISTCTRL
  19. #include "wx/listctrl.h"
  20. #ifndef WX_PRECOMP
  21. #include "wx/scrolwin.h"
  22. #include "wx/timer.h"
  23. #include "wx/settings.h"
  24. #include "wx/dynarray.h"
  25. #include "wx/dcclient.h"
  26. #include "wx/dcscreen.h"
  27. #include "wx/math.h"
  28. #include "wx/settings.h"
  29. #include "wx/sizer.h"
  30. #endif
  31. #include "wx/imaglist.h"
  32. #include "wx/renderer.h"
  33. #include "wx/generic/private/listctrl.h"
  34. #ifdef __WXMAC__
  35. #include "wx/osx/private.h"
  36. #endif
  37. #if defined(__WXMSW__) && !defined(__WXWINCE__) && !defined(__WXUNIVERSAL__)
  38. #define "wx/msw/wrapwin.h"
  39. #endif
  40. // NOTE: If using the wxListBox visual attributes works everywhere then this can
  41. // be removed, as well as the #else case below.
  42. #define _USE_VISATTR 0
  43. // ----------------------------------------------------------------------------
  44. // constants
  45. // ----------------------------------------------------------------------------
  46. // // the height of the header window (FIXME: should depend on its font!)
  47. // static const int HEADER_HEIGHT = 23;
  48. static const int SCROLL_UNIT_X = 15;
  49. // the spacing between the lines (in report mode)
  50. static const int LINE_SPACING = 0;
  51. // extra margins around the text label
  52. #ifdef __WXGTK__
  53. static const int EXTRA_WIDTH = 6;
  54. #else
  55. static const int EXTRA_WIDTH = 4;
  56. #endif
  57. #ifdef __WXGTK__
  58. static const int EXTRA_HEIGHT = 6;
  59. #else
  60. static const int EXTRA_HEIGHT = 4;
  61. #endif
  62. // margin between the window and the items
  63. static const int EXTRA_BORDER_X = 2;
  64. static const int EXTRA_BORDER_Y = 2;
  65. // offset for the header window
  66. static const int HEADER_OFFSET_X = 0;
  67. static const int HEADER_OFFSET_Y = 0;
  68. // margin between rows of icons in [small] icon view
  69. static const int MARGIN_BETWEEN_ROWS = 6;
  70. // when autosizing the columns, add some slack
  71. static const int AUTOSIZE_COL_MARGIN = 10;
  72. // default width for the header columns
  73. static const int WIDTH_COL_DEFAULT = 80;
  74. // the space between the image and the text in the report mode
  75. static const int IMAGE_MARGIN_IN_REPORT_MODE = 5;
  76. // the space between the image and the text in the report mode in header
  77. static const int HEADER_IMAGE_MARGIN_IN_REPORT_MODE = 2;
  78. // ----------------------------------------------------------------------------
  79. // arrays/list implementations
  80. // ----------------------------------------------------------------------------
  81. #include "wx/listimpl.cpp"
  82. WX_DEFINE_LIST(wxListItemDataList)
  83. #include "wx/arrimpl.cpp"
  84. WX_DEFINE_OBJARRAY(wxListLineDataArray)
  85. #include "wx/listimpl.cpp"
  86. WX_DEFINE_LIST(wxListHeaderDataList)
  87. // ----------------------------------------------------------------------------
  88. // wxListItemData
  89. // ----------------------------------------------------------------------------
  90. wxListItemData::~wxListItemData()
  91. {
  92. // in the virtual list control the attributes are managed by the main
  93. // program, so don't delete them
  94. if ( !m_owner->IsVirtual() )
  95. delete m_attr;
  96. delete m_rect;
  97. }
  98. void wxListItemData::Init()
  99. {
  100. m_image = -1;
  101. m_data = 0;
  102. m_attr = NULL;
  103. }
  104. wxListItemData::wxListItemData(wxListMainWindow *owner)
  105. {
  106. Init();
  107. m_owner = owner;
  108. if ( owner->InReportView() )
  109. m_rect = NULL;
  110. else
  111. m_rect = new wxRect;
  112. }
  113. void wxListItemData::SetItem( const wxListItem &info )
  114. {
  115. if ( info.m_mask & wxLIST_MASK_TEXT )
  116. SetText(info.m_text);
  117. if ( info.m_mask & wxLIST_MASK_IMAGE )
  118. m_image = info.m_image;
  119. if ( info.m_mask & wxLIST_MASK_DATA )
  120. m_data = info.m_data;
  121. if ( info.HasAttributes() )
  122. {
  123. if ( m_attr )
  124. m_attr->AssignFrom(*info.GetAttributes());
  125. else
  126. m_attr = new wxListItemAttr(*info.GetAttributes());
  127. }
  128. if ( m_rect )
  129. {
  130. m_rect->x =
  131. m_rect->y =
  132. m_rect->height = 0;
  133. m_rect->width = info.m_width;
  134. }
  135. }
  136. void wxListItemData::SetPosition( int x, int y )
  137. {
  138. wxCHECK_RET( m_rect, wxT("unexpected SetPosition() call") );
  139. m_rect->x = x;
  140. m_rect->y = y;
  141. }
  142. void wxListItemData::SetSize( int width, int height )
  143. {
  144. wxCHECK_RET( m_rect, wxT("unexpected SetSize() call") );
  145. if ( width != -1 )
  146. m_rect->width = width;
  147. if ( height != -1 )
  148. m_rect->height = height;
  149. }
  150. bool wxListItemData::IsHit( int x, int y ) const
  151. {
  152. wxCHECK_MSG( m_rect, false, wxT("can't be called in this mode") );
  153. return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Contains(x, y);
  154. }
  155. int wxListItemData::GetX() const
  156. {
  157. wxCHECK_MSG( m_rect, 0, wxT("can't be called in this mode") );
  158. return m_rect->x;
  159. }
  160. int wxListItemData::GetY() const
  161. {
  162. wxCHECK_MSG( m_rect, 0, wxT("can't be called in this mode") );
  163. return m_rect->y;
  164. }
  165. int wxListItemData::GetWidth() const
  166. {
  167. wxCHECK_MSG( m_rect, 0, wxT("can't be called in this mode") );
  168. return m_rect->width;
  169. }
  170. int wxListItemData::GetHeight() const
  171. {
  172. wxCHECK_MSG( m_rect, 0, wxT("can't be called in this mode") );
  173. return m_rect->height;
  174. }
  175. void wxListItemData::GetItem( wxListItem &info ) const
  176. {
  177. long mask = info.m_mask;
  178. if ( !mask )
  179. // by default, get everything for backwards compatibility
  180. mask = -1;
  181. if ( mask & wxLIST_MASK_TEXT )
  182. info.m_text = m_text;
  183. if ( mask & wxLIST_MASK_IMAGE )
  184. info.m_image = m_image;
  185. if ( mask & wxLIST_MASK_DATA )
  186. info.m_data = m_data;
  187. if ( m_attr )
  188. {
  189. if ( m_attr->HasTextColour() )
  190. info.SetTextColour(m_attr->GetTextColour());
  191. if ( m_attr->HasBackgroundColour() )
  192. info.SetBackgroundColour(m_attr->GetBackgroundColour());
  193. if ( m_attr->HasFont() )
  194. info.SetFont(m_attr->GetFont());
  195. }
  196. }
  197. //-----------------------------------------------------------------------------
  198. // wxListHeaderData
  199. //-----------------------------------------------------------------------------
  200. void wxListHeaderData::Init()
  201. {
  202. m_mask = 0;
  203. m_image = -1;
  204. m_format = 0;
  205. m_width = 0;
  206. m_xpos = 0;
  207. m_ypos = 0;
  208. m_height = 0;
  209. m_state = 0;
  210. }
  211. wxListHeaderData::wxListHeaderData()
  212. {
  213. Init();
  214. }
  215. wxListHeaderData::wxListHeaderData( const wxListItem &item )
  216. {
  217. Init();
  218. SetItem( item );
  219. }
  220. void wxListHeaderData::SetItem( const wxListItem &item )
  221. {
  222. m_mask = item.m_mask;
  223. if ( m_mask & wxLIST_MASK_TEXT )
  224. m_text = item.m_text;
  225. if ( m_mask & wxLIST_MASK_IMAGE )
  226. m_image = item.m_image;
  227. if ( m_mask & wxLIST_MASK_FORMAT )
  228. m_format = item.m_format;
  229. if ( m_mask & wxLIST_MASK_WIDTH )
  230. SetWidth(item.m_width);
  231. if ( m_mask & wxLIST_MASK_STATE )
  232. SetState(item.m_state);
  233. }
  234. void wxListHeaderData::SetPosition( int x, int y )
  235. {
  236. m_xpos = x;
  237. m_ypos = y;
  238. }
  239. void wxListHeaderData::SetHeight( int h )
  240. {
  241. m_height = h;
  242. }
  243. void wxListHeaderData::SetWidth( int w )
  244. {
  245. m_width = w < 0 ? WIDTH_COL_DEFAULT : w;
  246. }
  247. void wxListHeaderData::SetState( int flag )
  248. {
  249. m_state = flag;
  250. }
  251. void wxListHeaderData::SetFormat( int format )
  252. {
  253. m_format = format;
  254. }
  255. bool wxListHeaderData::HasImage() const
  256. {
  257. return m_image != -1;
  258. }
  259. bool wxListHeaderData::IsHit( int x, int y ) const
  260. {
  261. return ((x >= m_xpos) && (x <= m_xpos+m_width) && (y >= m_ypos) && (y <= m_ypos+m_height));
  262. }
  263. void wxListHeaderData::GetItem( wxListItem& item )
  264. {
  265. long mask = item.m_mask;
  266. if ( !mask )
  267. {
  268. // by default, get everything for backwards compatibility
  269. mask = -1;
  270. }
  271. if ( mask & wxLIST_MASK_STATE )
  272. item.m_state = m_state;
  273. if ( mask & wxLIST_MASK_TEXT )
  274. item.m_text = m_text;
  275. if ( mask & wxLIST_MASK_IMAGE )
  276. item.m_image = m_image;
  277. if ( mask & wxLIST_MASK_WIDTH )
  278. item.m_width = m_width;
  279. if ( mask & wxLIST_MASK_FORMAT )
  280. item.m_format = m_format;
  281. }
  282. int wxListHeaderData::GetImage() const
  283. {
  284. return m_image;
  285. }
  286. int wxListHeaderData::GetWidth() const
  287. {
  288. return m_width;
  289. }
  290. int wxListHeaderData::GetFormat() const
  291. {
  292. return m_format;
  293. }
  294. int wxListHeaderData::GetState() const
  295. {
  296. return m_state;
  297. }
  298. //-----------------------------------------------------------------------------
  299. // wxListLineData
  300. //-----------------------------------------------------------------------------
  301. inline int wxListLineData::GetMode() const
  302. {
  303. return m_owner->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE;
  304. }
  305. inline bool wxListLineData::InReportView() const
  306. {
  307. return m_owner->HasFlag(wxLC_REPORT);
  308. }
  309. inline bool wxListLineData::IsVirtual() const
  310. {
  311. return m_owner->IsVirtual();
  312. }
  313. wxListLineData::wxListLineData( wxListMainWindow *owner )
  314. {
  315. m_owner = owner;
  316. if ( InReportView() )
  317. m_gi = NULL;
  318. else // !report
  319. m_gi = new GeometryInfo;
  320. m_highlighted = false;
  321. InitItems( GetMode() == wxLC_REPORT ? m_owner->GetColumnCount() : 1 );
  322. }
  323. void wxListLineData::CalculateSize( wxDC *dc, int spacing )
  324. {
  325. wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
  326. wxCHECK_RET( node, wxT("no subitems at all??") );
  327. wxListItemData *item = node->GetData();
  328. wxString s;
  329. wxCoord lw, lh;
  330. switch ( GetMode() )
  331. {
  332. case wxLC_ICON:
  333. case wxLC_SMALL_ICON:
  334. m_gi->m_rectAll.width = spacing;
  335. s = item->GetText();
  336. if ( s.empty() )
  337. {
  338. lh =
  339. m_gi->m_rectLabel.width =
  340. m_gi->m_rectLabel.height = 0;
  341. }
  342. else // has label
  343. {
  344. dc->GetTextExtent( s, &lw, &lh );
  345. lw += EXTRA_WIDTH;
  346. lh += EXTRA_HEIGHT;
  347. m_gi->m_rectAll.height = spacing + lh;
  348. if (lw > spacing)
  349. m_gi->m_rectAll.width = lw;
  350. m_gi->m_rectLabel.width = lw;
  351. m_gi->m_rectLabel.height = lh;
  352. }
  353. if (item->HasImage())
  354. {
  355. int w, h;
  356. m_owner->GetImageSize( item->GetImage(), w, h );
  357. m_gi->m_rectIcon.width = w + 8;
  358. m_gi->m_rectIcon.height = h + 8;
  359. if ( m_gi->m_rectIcon.width > m_gi->m_rectAll.width )
  360. m_gi->m_rectAll.width = m_gi->m_rectIcon.width;
  361. if ( m_gi->m_rectIcon.height + lh > m_gi->m_rectAll.height - 4 )
  362. m_gi->m_rectAll.height = m_gi->m_rectIcon.height + lh + 4;
  363. }
  364. if ( item->HasText() )
  365. {
  366. m_gi->m_rectHighlight.width = m_gi->m_rectLabel.width;
  367. m_gi->m_rectHighlight.height = m_gi->m_rectLabel.height;
  368. }
  369. else // no text, highlight the icon
  370. {
  371. m_gi->m_rectHighlight.width = m_gi->m_rectIcon.width;
  372. m_gi->m_rectHighlight.height = m_gi->m_rectIcon.height;
  373. }
  374. break;
  375. case wxLC_LIST:
  376. s = item->GetTextForMeasuring();
  377. dc->GetTextExtent( s, &lw, &lh );
  378. lw += EXTRA_WIDTH;
  379. lh += EXTRA_HEIGHT;
  380. m_gi->m_rectLabel.width = lw;
  381. m_gi->m_rectLabel.height = lh;
  382. m_gi->m_rectAll.width = lw;
  383. m_gi->m_rectAll.height = lh;
  384. if (item->HasImage())
  385. {
  386. int w, h;
  387. m_owner->GetImageSize( item->GetImage(), w, h );
  388. m_gi->m_rectIcon.width = w;
  389. m_gi->m_rectIcon.height = h;
  390. m_gi->m_rectAll.width += 4 + w;
  391. if (h > m_gi->m_rectAll.height)
  392. m_gi->m_rectAll.height = h;
  393. }
  394. m_gi->m_rectHighlight.width = m_gi->m_rectAll.width;
  395. m_gi->m_rectHighlight.height = m_gi->m_rectAll.height;
  396. break;
  397. case wxLC_REPORT:
  398. wxFAIL_MSG( wxT("unexpected call to SetSize") );
  399. break;
  400. default:
  401. wxFAIL_MSG( wxT("unknown mode") );
  402. break;
  403. }
  404. }
  405. void wxListLineData::SetPosition( int x, int y, int spacing )
  406. {
  407. wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
  408. wxCHECK_RET( node, wxT("no subitems at all??") );
  409. wxListItemData *item = node->GetData();
  410. switch ( GetMode() )
  411. {
  412. case wxLC_ICON:
  413. case wxLC_SMALL_ICON:
  414. m_gi->m_rectAll.x = x;
  415. m_gi->m_rectAll.y = y;
  416. if ( item->HasImage() )
  417. {
  418. m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 4 +
  419. (m_gi->m_rectAll.width - m_gi->m_rectIcon.width) / 2;
  420. m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 4;
  421. }
  422. if ( item->HasText() )
  423. {
  424. if (m_gi->m_rectAll.width > spacing)
  425. m_gi->m_rectLabel.x = m_gi->m_rectAll.x + (EXTRA_WIDTH/2);
  426. else
  427. m_gi->m_rectLabel.x = m_gi->m_rectAll.x + (EXTRA_WIDTH/2) + (spacing / 2) - (m_gi->m_rectLabel.width / 2);
  428. m_gi->m_rectLabel.y = m_gi->m_rectAll.y + m_gi->m_rectAll.height + 2 - m_gi->m_rectLabel.height;
  429. m_gi->m_rectHighlight.x = m_gi->m_rectLabel.x - 2;
  430. m_gi->m_rectHighlight.y = m_gi->m_rectLabel.y - 2;
  431. }
  432. else // no text, highlight the icon
  433. {
  434. m_gi->m_rectHighlight.x = m_gi->m_rectIcon.x - 4;
  435. m_gi->m_rectHighlight.y = m_gi->m_rectIcon.y - 4;
  436. }
  437. break;
  438. case wxLC_LIST:
  439. m_gi->m_rectAll.x = x;
  440. m_gi->m_rectAll.y = y;
  441. m_gi->m_rectHighlight.x = m_gi->m_rectAll.x;
  442. m_gi->m_rectHighlight.y = m_gi->m_rectAll.y;
  443. m_gi->m_rectLabel.y = m_gi->m_rectAll.y + 2;
  444. if (item->HasImage())
  445. {
  446. m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 2;
  447. m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 2;
  448. m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 4 + (EXTRA_WIDTH/2) + m_gi->m_rectIcon.width;
  449. }
  450. else
  451. {
  452. m_gi->m_rectLabel.x = m_gi->m_rectAll.x + (EXTRA_WIDTH/2);
  453. }
  454. break;
  455. case wxLC_REPORT:
  456. wxFAIL_MSG( wxT("unexpected call to SetPosition") );
  457. break;
  458. default:
  459. wxFAIL_MSG( wxT("unknown mode") );
  460. break;
  461. }
  462. }
  463. void wxListLineData::InitItems( int num )
  464. {
  465. for (int i = 0; i < num; i++)
  466. m_items.Append( new wxListItemData(m_owner) );
  467. }
  468. void wxListLineData::SetItem( int index, const wxListItem &info )
  469. {
  470. wxListItemDataList::compatibility_iterator node = m_items.Item( index );
  471. wxCHECK_RET( node, wxT("invalid column index in SetItem") );
  472. wxListItemData *item = node->GetData();
  473. item->SetItem( info );
  474. }
  475. void wxListLineData::GetItem( int index, wxListItem &info )
  476. {
  477. wxListItemDataList::compatibility_iterator node = m_items.Item( index );
  478. if (node)
  479. {
  480. wxListItemData *item = node->GetData();
  481. item->GetItem( info );
  482. }
  483. }
  484. wxString wxListLineData::GetText(int index) const
  485. {
  486. wxString s;
  487. wxListItemDataList::compatibility_iterator node = m_items.Item( index );
  488. if (node)
  489. {
  490. wxListItemData *item = node->GetData();
  491. s = item->GetText();
  492. }
  493. return s;
  494. }
  495. void wxListLineData::SetText( int index, const wxString& s )
  496. {
  497. wxListItemDataList::compatibility_iterator node = m_items.Item( index );
  498. if (node)
  499. {
  500. wxListItemData *item = node->GetData();
  501. item->SetText( s );
  502. }
  503. }
  504. void wxListLineData::SetImage( int index, int image )
  505. {
  506. wxListItemDataList::compatibility_iterator node = m_items.Item( index );
  507. wxCHECK_RET( node, wxT("invalid column index in SetImage()") );
  508. wxListItemData *item = node->GetData();
  509. item->SetImage(image);
  510. }
  511. int wxListLineData::GetImage( int index ) const
  512. {
  513. wxListItemDataList::compatibility_iterator node = m_items.Item( index );
  514. wxCHECK_MSG( node, -1, wxT("invalid column index in GetImage()") );
  515. wxListItemData *item = node->GetData();
  516. return item->GetImage();
  517. }
  518. wxListItemAttr *wxListLineData::GetAttr() const
  519. {
  520. wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
  521. wxCHECK_MSG( node, NULL, wxT("invalid column index in GetAttr()") );
  522. wxListItemData *item = node->GetData();
  523. return item->GetAttr();
  524. }
  525. void wxListLineData::SetAttr(wxListItemAttr *attr)
  526. {
  527. wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
  528. wxCHECK_RET( node, wxT("invalid column index in SetAttr()") );
  529. wxListItemData *item = node->GetData();
  530. item->SetAttr(attr);
  531. }
  532. void wxListLineData::ApplyAttributes(wxDC *dc,
  533. const wxRect& rectHL,
  534. bool highlighted,
  535. bool current)
  536. {
  537. const wxListItemAttr * const attr = GetAttr();
  538. wxWindow * const listctrl = m_owner->GetParent();
  539. const bool hasFocus = listctrl->HasFocus()
  540. #if defined(__WXMAC__) && !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON
  541. && IsControlActive( (ControlRef)listctrl->GetHandle() )
  542. #endif
  543. ;
  544. // fg colour
  545. // don't use foreground colour for drawing highlighted items - this might
  546. // make them completely invisible (and there is no way to do bit
  547. // arithmetics on wxColour, unfortunately)
  548. wxColour colText;
  549. if ( highlighted )
  550. {
  551. #ifdef __WXMAC__
  552. if ( hasFocus )
  553. colText = *wxWHITE;
  554. else
  555. colText = *wxBLACK;
  556. #else
  557. if ( hasFocus )
  558. colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
  559. else
  560. colText = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT);
  561. #endif
  562. }
  563. else if ( attr && attr->HasTextColour() )
  564. colText = attr->GetTextColour();
  565. else
  566. colText = listctrl->GetForegroundColour();
  567. dc->SetTextForeground(colText);
  568. // font
  569. wxFont font;
  570. if ( attr && attr->HasFont() )
  571. font = attr->GetFont();
  572. else
  573. font = listctrl->GetFont();
  574. dc->SetFont(font);
  575. // background
  576. if ( highlighted )
  577. {
  578. // Use the renderer method to ensure that the selected items use the
  579. // native look.
  580. int flags = wxCONTROL_SELECTED;
  581. if ( hasFocus )
  582. flags |= wxCONTROL_FOCUSED;
  583. if (current)
  584. flags |= wxCONTROL_CURRENT;
  585. wxRendererNative::Get().
  586. DrawItemSelectionRect( m_owner, *dc, rectHL, flags );
  587. }
  588. else if ( attr && attr->HasBackgroundColour() )
  589. {
  590. // Draw the background using the items custom background colour.
  591. dc->SetBrush(attr->GetBackgroundColour());
  592. dc->SetPen(*wxTRANSPARENT_PEN);
  593. dc->DrawRectangle(rectHL);
  594. }
  595. // just for debugging to better see where the items are
  596. #if 0
  597. dc->SetPen(*wxRED_PEN);
  598. dc->SetBrush(*wxTRANSPARENT_BRUSH);
  599. dc->DrawRectangle( m_gi->m_rectAll );
  600. dc->SetPen(*wxGREEN_PEN);
  601. dc->DrawRectangle( m_gi->m_rectIcon );
  602. #endif
  603. }
  604. void wxListLineData::Draw(wxDC *dc, bool current)
  605. {
  606. wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
  607. wxCHECK_RET( node, wxT("no subitems at all??") );
  608. ApplyAttributes(dc, m_gi->m_rectHighlight, IsHighlighted(), current);
  609. wxListItemData *item = node->GetData();
  610. if (item->HasImage())
  611. {
  612. // centre the image inside our rectangle, this looks nicer when items
  613. // ae aligned in a row
  614. const wxRect& rectIcon = m_gi->m_rectIcon;
  615. m_owner->DrawImage(item->GetImage(), dc, rectIcon.x, rectIcon.y);
  616. }
  617. if (item->HasText())
  618. {
  619. const wxRect& rectLabel = m_gi->m_rectLabel;
  620. wxDCClipper clipper(*dc, rectLabel);
  621. dc->DrawText(item->GetText(), rectLabel.x, rectLabel.y);
  622. }
  623. }
  624. void wxListLineData::DrawInReportMode( wxDC *dc,
  625. const wxRect& rect,
  626. const wxRect& rectHL,
  627. bool highlighted,
  628. bool current )
  629. {
  630. // TODO: later we should support setting different attributes for
  631. // different columns - to do it, just add "col" argument to
  632. // GetAttr() and move these lines into the loop below
  633. ApplyAttributes(dc, rectHL, highlighted, current);
  634. wxCoord x = rect.x + HEADER_OFFSET_X,
  635. yMid = rect.y + rect.height/2;
  636. #ifdef __WXGTK__
  637. // This probably needs to be done
  638. // on all platforms as the icons
  639. // otherwise nearly touch the border
  640. x += 2;
  641. #endif
  642. size_t col = 0;
  643. for ( wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
  644. node;
  645. node = node->GetNext(), col++ )
  646. {
  647. wxListItemData *item = node->GetData();
  648. int width = m_owner->GetColumnWidth(col);
  649. int xOld = x;
  650. x += width;
  651. width -= 8;
  652. const int wText = width;
  653. wxDCClipper clipper(*dc, xOld, rect.y, wText, rect.height);
  654. if ( item->HasImage() )
  655. {
  656. int ix, iy;
  657. m_owner->GetImageSize( item->GetImage(), ix, iy );
  658. m_owner->DrawImage( item->GetImage(), dc, xOld, yMid - iy/2 );
  659. ix += IMAGE_MARGIN_IN_REPORT_MODE;
  660. xOld += ix;
  661. width -= ix;
  662. }
  663. if ( item->HasText() )
  664. DrawTextFormatted(dc, item->GetText(), col, xOld, yMid, width);
  665. }
  666. }
  667. void wxListLineData::DrawTextFormatted(wxDC *dc,
  668. const wxString& textOrig,
  669. int col,
  670. int x,
  671. int yMid,
  672. int width)
  673. {
  674. // we don't support displaying multiple lines currently (and neither does
  675. // wxMSW FWIW) so just merge all the lines
  676. wxString text(textOrig);
  677. text.Replace(wxT("\n"), wxT(" "));
  678. wxCoord w, h;
  679. dc->GetTextExtent(text, &w, &h);
  680. const wxCoord y = yMid - (h + 1)/2;
  681. wxDCClipper clipper(*dc, x, y, width, h);
  682. // determine if the string can fit inside the current width
  683. if (w <= width)
  684. {
  685. // it can, draw it using the items alignment
  686. wxListItem item;
  687. m_owner->GetColumn(col, item);
  688. switch ( item.GetAlign() )
  689. {
  690. case wxLIST_FORMAT_LEFT:
  691. // nothing to do
  692. break;
  693. case wxLIST_FORMAT_RIGHT:
  694. x += width - w;
  695. break;
  696. case wxLIST_FORMAT_CENTER:
  697. x += (width - w) / 2;
  698. break;
  699. default:
  700. wxFAIL_MSG( wxT("unknown list item format") );
  701. break;
  702. }
  703. dc->DrawText(text, x, y);
  704. }
  705. else // otherwise, truncate and add an ellipsis if possible
  706. {
  707. // determine the base width
  708. wxString ellipsis(wxT("..."));
  709. wxCoord base_w;
  710. dc->GetTextExtent(ellipsis, &base_w, &h);
  711. // continue until we have enough space or only one character left
  712. wxCoord w_c, h_c;
  713. size_t len = text.length();
  714. wxString drawntext = text.Left(len);
  715. while (len > 1)
  716. {
  717. dc->GetTextExtent(drawntext.Last(), &w_c, &h_c);
  718. drawntext.RemoveLast();
  719. len--;
  720. w -= w_c;
  721. if (w + base_w <= width)
  722. break;
  723. }
  724. // if still not enough space, remove ellipsis characters
  725. while (ellipsis.length() > 0 && w + base_w > width)
  726. {
  727. ellipsis = ellipsis.Left(ellipsis.length() - 1);
  728. dc->GetTextExtent(ellipsis, &base_w, &h);
  729. }
  730. // now draw the text
  731. dc->DrawText(drawntext, x, y);
  732. dc->DrawText(ellipsis, x + w, y);
  733. }
  734. }
  735. bool wxListLineData::Highlight( bool on )
  736. {
  737. wxCHECK_MSG( !IsVirtual(), false, wxT("unexpected call to Highlight") );
  738. if ( on == m_highlighted )
  739. return false;
  740. m_highlighted = on;
  741. return true;
  742. }
  743. void wxListLineData::ReverseHighlight( void )
  744. {
  745. Highlight(!IsHighlighted());
  746. }
  747. //-----------------------------------------------------------------------------
  748. // wxListHeaderWindow
  749. //-----------------------------------------------------------------------------
  750. BEGIN_EVENT_TABLE(wxListHeaderWindow,wxWindow)
  751. EVT_PAINT (wxListHeaderWindow::OnPaint)
  752. EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse)
  753. END_EVENT_TABLE()
  754. void wxListHeaderWindow::Init()
  755. {
  756. m_currentCursor = NULL;
  757. m_isDragging = false;
  758. m_dirty = false;
  759. m_sendSetColumnWidth = false;
  760. }
  761. wxListHeaderWindow::wxListHeaderWindow()
  762. {
  763. Init();
  764. m_owner = NULL;
  765. m_resizeCursor = NULL;
  766. }
  767. bool wxListHeaderWindow::Create( wxWindow *win,
  768. wxWindowID id,
  769. wxListMainWindow *owner,
  770. const wxPoint& pos,
  771. const wxSize& size,
  772. long style,
  773. const wxString &name )
  774. {
  775. if ( !wxWindow::Create(win, id, pos, size, style, name) )
  776. return false;
  777. Init();
  778. m_owner = owner;
  779. m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
  780. #if _USE_VISATTR
  781. wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes();
  782. SetOwnForegroundColour( attr.colFg );
  783. SetOwnBackgroundColour( attr.colBg );
  784. if (!m_hasFont)
  785. SetOwnFont( attr.font );
  786. #else
  787. SetOwnForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
  788. SetOwnBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
  789. if (!m_hasFont)
  790. SetOwnFont( wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT ));
  791. #endif
  792. return true;
  793. }
  794. wxListHeaderWindow::~wxListHeaderWindow()
  795. {
  796. delete m_resizeCursor;
  797. }
  798. #ifdef __WXUNIVERSAL__
  799. #include "wx/univ/renderer.h"
  800. #include "wx/univ/theme.h"
  801. #endif
  802. // shift the DC origin to match the position of the main window horz
  803. // scrollbar: this allows us to always use logical coords
  804. void wxListHeaderWindow::AdjustDC(wxDC& dc)
  805. {
  806. wxGenericListCtrl *parent = m_owner->GetListCtrl();
  807. int xpix;
  808. parent->GetScrollPixelsPerUnit( &xpix, NULL );
  809. int view_start;
  810. parent->GetViewStart( &view_start, NULL );
  811. int org_x = 0;
  812. int org_y = 0;
  813. dc.GetDeviceOrigin( &org_x, &org_y );
  814. // account for the horz scrollbar offset
  815. #ifdef __WXGTK__
  816. if (GetLayoutDirection() == wxLayout_RightToLeft)
  817. {
  818. // Maybe we just have to check for m_signX
  819. // in the DC, but I leave the #ifdef __WXGTK__
  820. // for now
  821. dc.SetDeviceOrigin( org_x + (view_start * xpix), org_y );
  822. }
  823. else
  824. #endif
  825. dc.SetDeviceOrigin( org_x - (view_start * xpix), org_y );
  826. }
  827. void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
  828. {
  829. wxGenericListCtrl *parent = m_owner->GetListCtrl();
  830. wxPaintDC dc( this );
  831. AdjustDC( dc );
  832. dc.SetFont( GetFont() );
  833. // width and height of the entire header window
  834. int w, h;
  835. GetClientSize( &w, &h );
  836. parent->CalcUnscrolledPosition(w, 0, &w, NULL);
  837. dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
  838. dc.SetTextForeground(GetForegroundColour());
  839. int x = HEADER_OFFSET_X;
  840. int numColumns = m_owner->GetColumnCount();
  841. wxListItem item;
  842. for ( int i = 0; i < numColumns && x < w; i++ )
  843. {
  844. m_owner->GetColumn( i, item );
  845. int wCol = item.m_width;
  846. int cw = wCol;
  847. int ch = h;
  848. int flags = 0;
  849. if (!m_parent->IsEnabled())
  850. flags |= wxCONTROL_DISABLED;
  851. // NB: The code below is not really Mac-specific, but since we are close
  852. // to 2.8 release and I don't have time to test on other platforms, I
  853. // defined this only for wxMac. If this behaviour is desired on
  854. // other platforms, please go ahead and revise or remove the #ifdef.
  855. #ifdef __WXMAC__
  856. if ( !m_owner->IsVirtual() && (item.m_mask & wxLIST_MASK_STATE) &&
  857. (item.m_state & wxLIST_STATE_SELECTED) )
  858. flags |= wxCONTROL_SELECTED;
  859. #endif
  860. if (i == 0)
  861. flags |= wxCONTROL_SPECIAL; // mark as first column
  862. wxRendererNative::Get().DrawHeaderButton
  863. (
  864. this,
  865. dc,
  866. wxRect(x, HEADER_OFFSET_Y, cw, ch),
  867. flags
  868. );
  869. // see if we have enough space for the column label
  870. // for this we need the width of the text
  871. wxCoord wLabel;
  872. wxCoord hLabel;
  873. dc.GetTextExtent(item.GetText(), &wLabel, &hLabel);
  874. wLabel += 2 * EXTRA_WIDTH;
  875. // and the width of the icon, if any
  876. int ix = 0, iy = 0; // init them just to suppress the compiler warnings
  877. const int image = item.m_image;
  878. wxImageList *imageList;
  879. if ( image != -1 )
  880. {
  881. imageList = m_owner->GetSmallImageList();
  882. if ( imageList )
  883. {
  884. imageList->GetSize(image, ix, iy);
  885. wLabel += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE;
  886. }
  887. }
  888. else
  889. {
  890. imageList = NULL;
  891. }
  892. // ignore alignment if there is not enough space anyhow
  893. int xAligned;
  894. switch ( wLabel < cw ? item.GetAlign() : wxLIST_FORMAT_LEFT )
  895. {
  896. default:
  897. wxFAIL_MSG( wxT("unknown list item format") );
  898. // fall through
  899. case wxLIST_FORMAT_LEFT:
  900. xAligned = x;
  901. break;
  902. case wxLIST_FORMAT_RIGHT:
  903. xAligned = x + cw - wLabel;
  904. break;
  905. case wxLIST_FORMAT_CENTER:
  906. xAligned = x + (cw - wLabel) / 2;
  907. break;
  908. }
  909. // draw the text and image clipping them so that they
  910. // don't overwrite the column boundary
  911. wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h);
  912. // if we have an image, draw it on the right of the label
  913. if ( imageList )
  914. {
  915. imageList->Draw
  916. (
  917. image,
  918. dc,
  919. xAligned + wLabel - ix - HEADER_IMAGE_MARGIN_IN_REPORT_MODE,
  920. HEADER_OFFSET_Y + (h - iy)/2,
  921. wxIMAGELIST_DRAW_TRANSPARENT
  922. );
  923. }
  924. dc.DrawText( item.GetText(),
  925. xAligned + EXTRA_WIDTH, (h - hLabel) / 2 );
  926. x += wCol;
  927. }
  928. // Fill in what's missing to the right of the columns, otherwise we will
  929. // leave an unpainted area when columns are removed (and it looks better)
  930. if ( x < w )
  931. {
  932. wxRendererNative::Get().DrawHeaderButton
  933. (
  934. this,
  935. dc,
  936. wxRect(x, HEADER_OFFSET_Y, w - x, h),
  937. wxCONTROL_DIRTY // mark as last column
  938. );
  939. }
  940. }
  941. void wxListHeaderWindow::OnInternalIdle()
  942. {
  943. wxWindow::OnInternalIdle();
  944. if (m_sendSetColumnWidth)
  945. {
  946. m_owner->SetColumnWidth( m_colToSend, m_widthToSend );
  947. m_sendSetColumnWidth = false;
  948. }
  949. }
  950. void wxListHeaderWindow::DrawCurrent()
  951. {
  952. #if 1
  953. // m_owner->SetColumnWidth( m_column, m_currentX - m_minX );
  954. m_sendSetColumnWidth = true;
  955. m_colToSend = m_column;
  956. m_widthToSend = m_currentX - m_minX;
  957. #else
  958. int x1 = m_currentX;
  959. int y1 = 0;
  960. m_owner->ClientToScreen( &x1, &y1 );
  961. int x2 = m_currentX;
  962. int y2 = 0;
  963. m_owner->GetClientSize( NULL, &y2 );
  964. m_owner->ClientToScreen( &x2, &y2 );
  965. wxScreenDC dc;
  966. dc.SetLogicalFunction( wxINVERT );
  967. dc.SetPen( wxPen(*wxBLACK, 2) );
  968. dc.SetBrush( *wxTRANSPARENT_BRUSH );
  969. AdjustDC(dc);
  970. dc.DrawLine( x1, y1, x2, y2 );
  971. dc.SetLogicalFunction( wxCOPY );
  972. dc.SetPen( wxNullPen );
  973. dc.SetBrush( wxNullBrush );
  974. #endif
  975. }
  976. void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
  977. {
  978. wxGenericListCtrl *parent = m_owner->GetListCtrl();
  979. // we want to work with logical coords
  980. int x;
  981. parent->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
  982. int y = event.GetY();
  983. if (m_isDragging)
  984. {
  985. SendListEvent(wxEVT_LIST_COL_DRAGGING, event.GetPosition());
  986. // we don't draw the line beyond our window, but we allow dragging it
  987. // there
  988. int w = 0;
  989. GetClientSize( &w, NULL );
  990. parent->CalcUnscrolledPosition(w, 0, &w, NULL);
  991. w -= 6;
  992. // erase the line if it was drawn
  993. if ( m_currentX < w )
  994. DrawCurrent();
  995. if (event.ButtonUp())
  996. {
  997. ReleaseMouse();
  998. m_isDragging = false;
  999. m_dirty = true;
  1000. m_owner->SetColumnWidth( m_column, m_currentX - m_minX );
  1001. SendListEvent(wxEVT_LIST_COL_END_DRAG, event.GetPosition());
  1002. }
  1003. else
  1004. {
  1005. if (x > m_minX + 7)
  1006. m_currentX = x;
  1007. else
  1008. m_currentX = m_minX + 7;
  1009. // draw in the new location
  1010. if ( m_currentX < w )
  1011. DrawCurrent();
  1012. }
  1013. }
  1014. else // not dragging
  1015. {
  1016. m_minX = 0;
  1017. bool hit_border = false;
  1018. // end of the current column
  1019. int xpos = 0;
  1020. // find the column where this event occurred
  1021. int col,
  1022. countCol = m_owner->GetColumnCount();
  1023. for (col = 0; col < countCol; col++)
  1024. {
  1025. xpos += m_owner->GetColumnWidth( col );
  1026. m_column = col;
  1027. if ( (abs(x-xpos) < 3) && (y < 22) )
  1028. {
  1029. // near the column border
  1030. hit_border = true;
  1031. break;
  1032. }
  1033. if ( x < xpos )
  1034. {
  1035. // inside the column
  1036. break;
  1037. }
  1038. m_minX = xpos;
  1039. }
  1040. if ( col == countCol )
  1041. m_column = -1;
  1042. if (event.LeftDown() || event.RightUp())
  1043. {
  1044. if (hit_border && event.LeftDown())
  1045. {
  1046. if ( SendListEvent(wxEVT_LIST_COL_BEGIN_DRAG,
  1047. event.GetPosition()) )
  1048. {
  1049. m_isDragging = true;
  1050. m_currentX = x;
  1051. CaptureMouse();
  1052. DrawCurrent();
  1053. }
  1054. //else: column resizing was vetoed by the user code
  1055. }
  1056. else // click on a column
  1057. {
  1058. // record the selected state of the columns
  1059. if (event.LeftDown())
  1060. {
  1061. for (int i=0; i < m_owner->GetColumnCount(); i++)
  1062. {
  1063. wxListItem colItem;
  1064. m_owner->GetColumn(i, colItem);
  1065. long state = colItem.GetState();
  1066. if (i == m_column)
  1067. colItem.SetState(state | wxLIST_STATE_SELECTED);
  1068. else
  1069. colItem.SetState(state & ~wxLIST_STATE_SELECTED);
  1070. m_owner->SetColumn(i, colItem);
  1071. }
  1072. }
  1073. SendListEvent( event.LeftDown()
  1074. ? wxEVT_LIST_COL_CLICK
  1075. : wxEVT_LIST_COL_RIGHT_CLICK,
  1076. event.GetPosition());
  1077. }
  1078. }
  1079. else if (event.Moving())
  1080. {
  1081. bool setCursor;
  1082. if (hit_border)
  1083. {
  1084. setCursor = m_currentCursor == wxSTANDARD_CURSOR;
  1085. m_currentCursor = m_resizeCursor;
  1086. }
  1087. else
  1088. {
  1089. setCursor = m_currentCursor != wxSTANDARD_CURSOR;
  1090. m_currentCursor = wxSTANDARD_CURSOR;
  1091. }
  1092. if ( setCursor )
  1093. SetCursor(*m_currentCursor);
  1094. }
  1095. }
  1096. }
  1097. bool wxListHeaderWindow::SendListEvent(wxEventType type, const wxPoint& pos)
  1098. {
  1099. wxWindow *parent = GetParent();
  1100. wxListEvent le( type, parent->GetId() );
  1101. le.SetEventObject( parent );
  1102. le.m_pointDrag = pos;
  1103. // the position should be relative to the parent window, not
  1104. // this one for compatibility with MSW and common sense: the
  1105. // user code doesn't know anything at all about this header
  1106. // window, so why should it get positions relative to it?
  1107. le.m_pointDrag.y -= GetSize().y;
  1108. le.m_col = m_column;
  1109. return !parent->GetEventHandler()->ProcessEvent( le ) || le.IsAllowed();
  1110. }
  1111. //-----------------------------------------------------------------------------
  1112. // wxListRenameTimer (internal)
  1113. //-----------------------------------------------------------------------------
  1114. wxListRenameTimer::wxListRenameTimer( wxListMainWindow *owner )
  1115. {
  1116. m_owner = owner;
  1117. }
  1118. void wxListRenameTimer::Notify()
  1119. {
  1120. m_owner->OnRenameTimer();
  1121. }
  1122. //-----------------------------------------------------------------------------
  1123. // wxListFindTimer (internal)
  1124. //-----------------------------------------------------------------------------
  1125. void wxListFindTimer::Notify()
  1126. {
  1127. m_owner->OnFindTimer();
  1128. }
  1129. //-----------------------------------------------------------------------------
  1130. // wxListTextCtrlWrapper (internal)
  1131. //-----------------------------------------------------------------------------
  1132. BEGIN_EVENT_TABLE(wxListTextCtrlWrapper, wxEvtHandler)
  1133. EVT_CHAR (wxListTextCtrlWrapper::OnChar)
  1134. EVT_KEY_UP (wxListTextCtrlWrapper::OnKeyUp)
  1135. EVT_KILL_FOCUS (wxListTextCtrlWrapper::OnKillFocus)
  1136. END_EVENT_TABLE()
  1137. wxListTextCtrlWrapper::wxListTextCtrlWrapper(wxListMainWindow *owner,
  1138. wxTextCtrl *text,
  1139. size_t itemEdit)
  1140. : m_startValue(owner->GetItemText(itemEdit)),
  1141. m_itemEdited(itemEdit)
  1142. {
  1143. m_owner = owner;
  1144. m_text = text;
  1145. m_aboutToFinish = false;
  1146. wxGenericListCtrl *parent = m_owner->GetListCtrl();
  1147. wxRect rectLabel = owner->GetLineLabelRect(itemEdit);
  1148. parent->CalcScrolledPosition(rectLabel.x, rectLabel.y,
  1149. &rectLabel.x, &rectLabel.y);
  1150. m_text->Create(owner, wxID_ANY, m_startValue,
  1151. wxPoint(rectLabel.x-4,rectLabel.y-4),
  1152. wxSize(rectLabel.width+11,rectLabel.height+8));
  1153. m_text->SetFocus();
  1154. m_text->PushEventHandler(this);
  1155. }
  1156. void wxListTextCtrlWrapper::EndEdit(EndReason reason)
  1157. {
  1158. m_aboutToFinish = true;
  1159. switch ( reason )
  1160. {
  1161. case End_Accept:
  1162. // Notify the owner about the changes
  1163. AcceptChanges();
  1164. // Even if vetoed, close the control (consistent with MSW)
  1165. Finish( true );
  1166. break;
  1167. case End_Discard:
  1168. m_owner->OnRenameCancelled(m_itemEdited);
  1169. Finish( true );
  1170. break;
  1171. case End_Destroy:
  1172. // Don't generate any notifications for the control being destroyed
  1173. // and don't set focus to it neither.
  1174. Finish(false);
  1175. break;
  1176. }
  1177. }
  1178. void wxListTextCtrlWrapper::Finish( bool setfocus )
  1179. {
  1180. m_text->RemoveEventHandler(this);
  1181. m_owner->ResetTextControl( m_text );
  1182. wxPendingDelete.Append( this );
  1183. if (setfocus)
  1184. m_owner->SetFocus();
  1185. }
  1186. bool wxListTextCtrlWrapper::AcceptChanges()
  1187. {
  1188. const wxString value = m_text->GetValue();
  1189. // notice that we should always call OnRenameAccept() to generate the "end
  1190. // label editing" event, even if the user hasn't really changed anything
  1191. if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
  1192. {
  1193. // vetoed by the user
  1194. return false;
  1195. }
  1196. // accepted, do rename the item (unless nothing changed)
  1197. if ( value != m_startValue )
  1198. m_owner->SetItemText(m_itemEdited, value);
  1199. return true;
  1200. }
  1201. void wxListTextCtrlWrapper::OnChar( wxKeyEvent &event )
  1202. {
  1203. if ( !CheckForEndEditKey(event) )
  1204. event.Skip();
  1205. }
  1206. bool wxListTextCtrlWrapper::CheckForEndEditKey(const wxKeyEvent& event)
  1207. {
  1208. switch ( event.m_keyCode )
  1209. {
  1210. case WXK_RETURN:
  1211. EndEdit( End_Accept );
  1212. break;
  1213. case WXK_ESCAPE:
  1214. EndEdit( End_Discard );
  1215. break;
  1216. default:
  1217. return false;
  1218. }
  1219. return true;
  1220. }
  1221. void wxListTextCtrlWrapper::OnKeyUp( wxKeyEvent &event )
  1222. {
  1223. if (m_aboutToFinish)
  1224. {
  1225. // auto-grow the textctrl:
  1226. wxSize parentSize = m_owner->GetSize();
  1227. wxPoint myPos = m_text->GetPosition();
  1228. wxSize mySize = m_text->GetSize();
  1229. int sx, sy;
  1230. m_text->GetTextExtent(m_text->GetValue() + wxT("MM"), &sx, &sy);
  1231. if (myPos.x + sx > parentSize.x)
  1232. sx = parentSize.x - myPos.x;
  1233. if (mySize.x > sx)
  1234. sx = mySize.x;
  1235. m_text->SetSize(sx, wxDefaultCoord);
  1236. }
  1237. event.Skip();
  1238. }
  1239. void wxListTextCtrlWrapper::OnKillFocus( wxFocusEvent &event )
  1240. {
  1241. if ( !m_aboutToFinish )
  1242. {
  1243. if ( !AcceptChanges() )
  1244. m_owner->OnRenameCancelled( m_itemEdited );
  1245. Finish( false );
  1246. }
  1247. // We must let the native text control handle focus
  1248. event.Skip();
  1249. }
  1250. //-----------------------------------------------------------------------------
  1251. // wxListMainWindow
  1252. //-----------------------------------------------------------------------------
  1253. BEGIN_EVENT_TABLE(wxListMainWindow, wxWindow)
  1254. EVT_PAINT (wxListMainWindow::OnPaint)
  1255. EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse)
  1256. EVT_CHAR_HOOK (wxListMainWindow::OnCharHook)
  1257. EVT_CHAR (wxListMainWindow::OnChar)
  1258. EVT_KEY_DOWN (wxListMainWindow::OnKeyDown)
  1259. EVT_KEY_UP (wxListMainWindow::OnKeyUp)
  1260. EVT_SET_FOCUS (wxListMainWindow::OnSetFocus)
  1261. EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus)
  1262. EVT_SCROLLWIN (wxListMainWindow::OnScroll)
  1263. EVT_CHILD_FOCUS (wxListMainWindow::OnChildFocus)
  1264. END_EVENT_TABLE()
  1265. void wxListMainWindow::Init()
  1266. {
  1267. m_dirty = true;
  1268. m_countVirt = 0;
  1269. m_lineFrom =
  1270. m_lineTo = (size_t)-1;
  1271. m_linesPerPage = 0;
  1272. m_headerWidth =
  1273. m_lineHeight = 0;
  1274. m_small_image_list = NULL;
  1275. m_normal_image_list = NULL;
  1276. m_small_spacing = 30;
  1277. m_normal_spacing = 40;
  1278. m_hasFocus = false;
  1279. m_dragCount = 0;
  1280. m_isCreated = false;
  1281. m_lastOnSame = false;
  1282. m_renameTimer = new wxListRenameTimer( this );
  1283. m_findTimer = NULL;
  1284. m_findBell = 0; // default is to not ring bell at all
  1285. m_textctrlWrapper = NULL;
  1286. m_current =
  1287. m_lineLastClicked =
  1288. m_lineSelectSingleOnUp =
  1289. m_lineBeforeLastClicked = (size_t)-1;
  1290. }
  1291. wxListMainWindow::wxListMainWindow()
  1292. {
  1293. Init();
  1294. m_highlightBrush =
  1295. m_highlightUnfocusedBrush = NULL;
  1296. }
  1297. wxListMainWindow::wxListMainWindow( wxWindow *parent,
  1298. wxWindowID id,
  1299. const wxPoint& pos,
  1300. const wxSize& size )
  1301. : wxWindow( parent, id, pos, size,
  1302. wxWANTS_CHARS | wxBORDER_NONE )
  1303. {
  1304. Init();
  1305. m_highlightBrush = new wxBrush
  1306. (
  1307. wxSystemSettings::GetColour
  1308. (
  1309. wxSYS_COLOUR_HIGHLIGHT
  1310. ),
  1311. wxBRUSHSTYLE_SOLID
  1312. );
  1313. m_highlightUnfocusedBrush = new wxBrush
  1314. (
  1315. wxSystemSettings::GetColour
  1316. (
  1317. wxSYS_COLOUR_BTNSHADOW
  1318. ),
  1319. wxBRUSHSTYLE_SOLID
  1320. );
  1321. wxVisualAttributes attr = wxGenericListCtrl::GetClassDefaultAttributes();
  1322. SetOwnForegroundColour( attr.colFg );
  1323. SetOwnBackgroundColour( attr.colBg );
  1324. if (!m_hasFont)
  1325. SetOwnFont( attr.font );
  1326. }
  1327. wxListMainWindow::~wxListMainWindow()
  1328. {
  1329. if ( m_textctrlWrapper )
  1330. m_textctrlWrapper->EndEdit(wxListTextCtrlWrapper::End_Destroy);
  1331. DoDeleteAllItems();
  1332. WX_CLEAR_LIST(wxListHeaderDataList, m_columns);
  1333. WX_CLEAR_ARRAY(m_aColWidths);
  1334. delete m_highlightBrush;
  1335. delete m_highlightUnfocusedBrush;
  1336. delete m_renameTimer;
  1337. delete m_findTimer;
  1338. }
  1339. void wxListMainWindow::SetReportView(bool inReportView)
  1340. {
  1341. const size_t count = m_lines.size();
  1342. for ( size_t n = 0; n < count; n++ )
  1343. {
  1344. m_lines[n].SetReportView(inReportView);
  1345. }
  1346. }
  1347. void wxListMainWindow::CacheLineData(size_t line)
  1348. {
  1349. wxGenericListCtrl *listctrl = GetListCtrl();
  1350. wxListLineData *ld = GetDummyLine();
  1351. size_t countCol = GetColumnCount();
  1352. for ( size_t col = 0; col < countCol; col++ )
  1353. {
  1354. ld->SetText(col, listctrl->OnGetItemText(line, col));
  1355. ld->SetImage(col, listctrl->OnGetItemColumnImage(line, col));
  1356. }
  1357. ld->SetAttr(listctrl->OnGetItemAttr(line));
  1358. }
  1359. wxListLineData *wxListMainWindow::GetDummyLine() const
  1360. {
  1361. wxASSERT_MSG( !IsEmpty(), wxT("invalid line index") );
  1362. wxASSERT_MSG( IsVirtual(), wxT("GetDummyLine() shouldn't be called") );
  1363. wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
  1364. // we need to recreate the dummy line if the number of columns in the
  1365. // control changed as it would have the incorrect number of fields
  1366. // otherwise
  1367. if ( !m_lines.IsEmpty() &&
  1368. m_lines[0].m_items.GetCount() != (size_t)GetColumnCount() )
  1369. {
  1370. self->m_lines.Clear();
  1371. }
  1372. if ( m_lines.IsEmpty() )
  1373. {
  1374. wxListLineData *line = new wxListLineData(self);
  1375. self->m_lines.Add(line);
  1376. // don't waste extra memory -- there never going to be anything
  1377. // else/more in this array
  1378. self->m_lines.Shrink();
  1379. }
  1380. return &m_lines[0];
  1381. }
  1382. // ----------------------------------------------------------------------------
  1383. // line geometry (report mode only)
  1384. // ----------------------------------------------------------------------------
  1385. wxCoord wxListMainWindow::GetLineHeight() const
  1386. {
  1387. // we cache the line height as calling GetTextExtent() is slow
  1388. if ( !m_lineHeight )
  1389. {
  1390. wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
  1391. wxClientDC dc( self );
  1392. dc.SetFont( GetFont() );
  1393. wxCoord y;
  1394. dc.GetTextExtent(wxT("H"), NULL, &y);
  1395. if ( m_small_image_list && m_small_image_list->GetImageCount() )
  1396. {
  1397. int iw = 0, ih = 0;
  1398. m_small_image_list->GetSize(0, iw, ih);
  1399. y = wxMax(y, ih);
  1400. }
  1401. y += EXTRA_HEIGHT;
  1402. self->m_lineHeight = y + LINE_SPACING;
  1403. }
  1404. return m_lineHeight;
  1405. }
  1406. wxCoord wxListMainWindow::GetLineY(size_t line) const
  1407. {
  1408. wxASSERT_MSG( InReportView(), wxT("only works in report mode") );
  1409. return LINE_SPACING + line * GetLineHeight();
  1410. }
  1411. wxRect wxListMainWindow::GetLineRect(size_t line) const
  1412. {
  1413. if ( !InReportView() )
  1414. return GetLine(line)->m_gi->m_rectAll;
  1415. wxRect rect;
  1416. rect.x = HEADER_OFFSET_X;
  1417. rect.y = GetLineY(line);
  1418. rect.width = GetHeaderWidth();
  1419. rect.height = GetLineHeight();
  1420. return rect;
  1421. }
  1422. wxRect wxListMainWindow::GetLineLabelRect(size_t line) const
  1423. {
  1424. if ( !InReportView() )
  1425. return GetLine(line)->m_gi->m_rectLabel;
  1426. int image_x = 0;
  1427. wxListLineData *data = GetLine(line);
  1428. wxListItemDataList::compatibility_iterator node = data->m_items.GetFirst();
  1429. if (node)
  1430. {
  1431. wxListItemData *item = node->GetData();
  1432. if ( item->HasImage() )
  1433. {
  1434. int ix, iy;
  1435. GetImageSize( item->GetImage(), ix, iy );
  1436. image_x = 3 + ix + IMAGE_MARGIN_IN_REPORT_MODE;
  1437. }
  1438. }
  1439. wxRect rect;
  1440. rect.x = image_x + HEADER_OFFSET_X;
  1441. rect.y = GetLineY(line);
  1442. rect.width = GetColumnWidth(0) - image_x;
  1443. rect.height = GetLineHeight();
  1444. return rect;
  1445. }
  1446. wxRect wxListMainWindow::GetLineIconRect(size_t line) const
  1447. {
  1448. if ( !InReportView() )
  1449. return GetLine(line)->m_gi->m_rectIcon;
  1450. wxListLineData *ld = GetLine(line);
  1451. wxASSERT_MSG( ld->HasImage(), wxT("should have an image") );
  1452. wxRect rect;
  1453. rect.x = HEADER_OFFSET_X;
  1454. rect.y = GetLineY(line);
  1455. GetImageSize(ld->GetImage(), rect.width, rect.height);
  1456. return rect;
  1457. }
  1458. wxRect wxListMainWindow::GetLineHighlightRect(size_t line) const
  1459. {
  1460. return InReportView() ? GetLineRect(line)
  1461. : GetLine(line)->m_gi->m_rectHighlight;
  1462. }
  1463. long wxListMainWindow::HitTestLine(size_t line, int x, int y) const
  1464. {
  1465. wxASSERT_MSG( line < GetItemCount(), wxT("invalid line in HitTestLine") );
  1466. wxListLineData *ld = GetLine(line);
  1467. if ( ld->HasImage() && GetLineIconRect(line).Contains(x, y) )
  1468. return wxLIST_HITTEST_ONITEMICON;
  1469. // VS: Testing for "ld->HasText() || InReportView()" instead of
  1470. // "ld->HasText()" is needed to make empty lines in report view
  1471. // possible
  1472. if ( ld->HasText() || InReportView() )
  1473. {
  1474. wxRect rect = InReportView() ? GetLineRect(line)
  1475. : GetLineLabelRect(line);
  1476. if ( rect.Contains(x

Large files files are truncated, but you can click here to view the full file