Discourage use of wxDataViews. WX_GRID is much less problematic.

This commit is contained in:
Jeff Young 2020-03-26 16:06:37 +00:00
parent 5134856f18
commit 88c4254bb5
5 changed files with 129 additions and 266 deletions

View File

@ -207,7 +207,6 @@ set( COMMON_WIDGET_SRCS
widgets/split_button.cpp widgets/split_button.cpp
widgets/stepped_slider.cpp widgets/stepped_slider.cpp
widgets/text_ctrl_eval.cpp widgets/text_ctrl_eval.cpp
widgets/two_column_tree_list.cpp
widgets/ui_common.cpp widgets/ui_common.cpp
widgets/unit_binder.cpp widgets/unit_binder.cpp
widgets/widget_save_restore.cpp widgets/widget_save_restore.cpp

View File

@ -1,142 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file two_column_tree_list.cpp
*/
#include <wx/dataview.h>
#include <widgets/two_column_tree_list.h>
/**
* Extra margin to compensate for vertical scrollbar
*/
static const int HORIZ_MARGIN = 30;
TWO_COLUMN_TREE_LIST::TWO_COLUMN_TREE_LIST( wxWindow* aParent, wxWindowID aID,
const wxPoint & aPos, const wxSize & aSize, long aStyle, const wxString & aName )
: wxTreeListCtrl( aParent, aID, aPos, aSize, aStyle, aName ),
m_rubber_band_column( 0 ),
m_clamped_min_width( 50 )
{
Bind( wxEVT_SIZE, &TWO_COLUMN_TREE_LIST::OnSize, this );
GetDataView()->SetIndent( 10 );
}
void TWO_COLUMN_TREE_LIST::AutosizeColumns()
{
wxSizeEvent dummy;
OnSize( dummy );
}
void TWO_COLUMN_TREE_LIST::OnSize( wxSizeEvent& aEvent )
{
wxDataViewCtrl* view = GetDataView();
if( !view )
return;
wxRect rect = GetClientRect();
view->SetSize( rect );
#ifdef wxHAS_GENERIC_DATAVIEWCTRL
{
wxWindow* win_view = GetView();
win_view->Refresh();
win_view->Update();
}
#endif
// Find the maximum width of both columns
int clamped_column = ( m_rubber_band_column == 0 ) ? 1 : 0;
int clamped_column_width = 0;
int rubber_max_width = 0;
for( wxTreeListItem item = GetFirstItem(); item.IsOk(); item = GetNextItem( item ) )
{
const wxString& text = GetItemText( item, clamped_column );
int width = WidthFor( text );
if( clamped_column == 0 )
{
width += 4 * view->GetIndent();
}
if( width > clamped_column_width )
clamped_column_width = width;
width = MemoWidthFor( GetItemText( item, m_rubber_band_column ) );
if( width > rubber_max_width )
rubber_max_width = width;
}
if( clamped_column_width < m_clamped_min_width )
clamped_column_width = m_clamped_min_width;
// Rubber column width is only limited if the rubber column is on the LEFT.
// If on the right, let the horiz scrollbar show.
int rubber_width = 0;
if( m_rubber_band_column == 0 )
rubber_width = rect.width - clamped_column_width - HORIZ_MARGIN;
else
rubber_width = rubber_max_width;
if( rubber_width <= 0 )
rubber_width = 1;
wxASSERT( m_rubber_band_column == 0 || m_rubber_band_column == 1 );
if( GetColumnCount() >= 2 )
{
SetColumnWidth( m_rubber_band_column, rubber_width );
SetColumnWidth( clamped_column, clamped_column_width );
}
}
int TWO_COLUMN_TREE_LIST::MemoWidthFor( const wxString& aStr )
{
int width;
auto found = m_width_cache.find( aStr );
if( found == m_width_cache.end() )
{
width = WidthFor( aStr );
m_width_cache[aStr] = width;
}
else
{
width = found->second;
}
return width;
}
std::map<wxString, int> TWO_COLUMN_TREE_LIST::m_width_cache;

View File

@ -25,8 +25,8 @@
#include <cctype> #include <cctype>
#include <widgets/widget_hotkey_list.h> #include <widgets/widget_hotkey_list.h>
#include <wx/statline.h> #include <wx/statline.h>
#include <wx/treelist.h>
#include <tool/tool_action.h> #include <tool/tool_action.h>
#include <eda_draw_frame.h>
#include <dialog_shim.h> #include <dialog_shim.h>
@ -36,6 +36,14 @@
static const int HOTKEY_MIN_WIDTH = 100; static const int HOTKEY_MIN_WIDTH = 100;
/**
* Extra margin to compensate for vertical scrollbar
*/
static const int HORIZ_MARGIN = 30;
std::map<wxString, int> WIDGET_HOTKEY_LIST::m_width_cache;
/** /**
* Menu IDs for the hotkey context menu * Menu IDs for the hotkey context menu
*/ */
@ -312,7 +320,7 @@ void WIDGET_HOTKEY_LIST::UpdateFromClientData()
// Trigger a resize in case column widths have changed // Trigger a resize in case column widths have changed
wxSizeEvent dummy_evt; wxSizeEvent dummy_evt;
TWO_COLUMN_TREE_LIST::OnSize( dummy_evt ); OnSize( dummy_evt );
} }
@ -420,6 +428,92 @@ void WIDGET_HOTKEY_LIST::OnMenu( wxCommandEvent& aEvent )
} }
void WIDGET_HOTKEY_LIST::OnSize( wxSizeEvent& aEvent )
{
wxDataViewCtrl* view = GetDataView();
if( !view )
return;
wxRect rect = GetClientRect();
view->SetSize( rect );
#ifdef wxHAS_GENERIC_DATAVIEWCTRL
{
wxWindow* win_view = GetView();
win_view->Refresh();
win_view->Update();
}
#endif
// Find the maximum width of both columns
int clamped_column = ( m_rubber_band_column == 0 ) ? 1 : 0;
int clamped_column_width = 0;
int rubber_max_width = 0;
for( wxTreeListItem item = GetFirstItem(); item.IsOk(); item = GetNextItem( item ) )
{
const wxString& text = GetItemText( item, clamped_column );
int width = WidthFor( text );
if( clamped_column == 0 )
{
width += 4 * view->GetIndent();
}
if( width > clamped_column_width )
clamped_column_width = width;
width = MemoWidthFor( GetItemText( item, m_rubber_band_column ) );
if( width > rubber_max_width )
rubber_max_width = width;
}
if( clamped_column_width < m_clamped_min_width )
clamped_column_width = m_clamped_min_width;
// Rubber column width is only limited if the rubber column is on the LEFT.
// If on the right, let the horiz scrollbar show.
int rubber_width = 0;
if( m_rubber_band_column == 0 )
rubber_width = rect.width - clamped_column_width - HORIZ_MARGIN;
else
rubber_width = rubber_max_width;
if( rubber_width <= 0 )
rubber_width = 1;
wxASSERT( m_rubber_band_column == 0 || m_rubber_band_column == 1 );
if( GetColumnCount() >= 2 )
{
SetColumnWidth( m_rubber_band_column, rubber_width );
SetColumnWidth( clamped_column, clamped_column_width );
}
}
int WIDGET_HOTKEY_LIST::MemoWidthFor( const wxString& aStr )
{
int width;
auto found = m_width_cache.find( aStr );
if( found == m_width_cache.end() )
{
width = WidthFor( aStr );
m_width_cache[aStr] = width;
}
else
{
width = found->second;
}
return width;
}
bool WIDGET_HOTKEY_LIST::ResolveKeyConflicts( TOOL_ACTION* aAction, long aKey ) bool WIDGET_HOTKEY_LIST::ResolveKeyConflicts( TOOL_ACTION* aAction, long aKey )
{ {
HOTKEY* conflictingHotKey = nullptr; HOTKEY* conflictingHotKey = nullptr;
@ -452,9 +546,11 @@ bool WIDGET_HOTKEY_LIST::ResolveKeyConflicts( TOOL_ACTION* aAction, long aKey )
WIDGET_HOTKEY_LIST::WIDGET_HOTKEY_LIST( wxWindow* aParent, HOTKEY_STORE& aHotkeyStore, WIDGET_HOTKEY_LIST::WIDGET_HOTKEY_LIST( wxWindow* aParent, HOTKEY_STORE& aHotkeyStore,
bool aReadOnly ) bool aReadOnly )
: TWO_COLUMN_TREE_LIST( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTL_SINGLE ), : wxTreeListCtrl( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTL_SINGLE ),
m_hk_store( aHotkeyStore ), m_hk_store( aHotkeyStore ),
m_readOnly( aReadOnly ) m_readOnly( aReadOnly ),
m_rubber_band_column( 0 ),
m_clamped_min_width( HOTKEY_MIN_WIDTH )
{ {
wxString command_header = _( "Command" ); wxString command_header = _( "Command" );
@ -463,8 +559,7 @@ WIDGET_HOTKEY_LIST::WIDGET_HOTKEY_LIST( wxWindow* aParent, HOTKEY_STORE& aHotkey
AppendColumn( command_header ); AppendColumn( command_header );
AppendColumn( _( "Hotkey" ) ); AppendColumn( _( "Hotkey" ) );
SetRubberBandColumn( 0 ); GetDataView()->SetIndent( 10 );
SetClampedMinWidth( HOTKEY_MIN_WIDTH );
if( !m_readOnly ) if( !m_readOnly )
{ {
@ -473,6 +568,8 @@ WIDGET_HOTKEY_LIST::WIDGET_HOTKEY_LIST( wxWindow* aParent, HOTKEY_STORE& aHotkey
Bind( wxEVT_TREELIST_ITEM_CONTEXT_MENU, &WIDGET_HOTKEY_LIST::OnContextMenu, this ); Bind( wxEVT_TREELIST_ITEM_CONTEXT_MENU, &WIDGET_HOTKEY_LIST::OnContextMenu, this );
Bind( wxEVT_MENU, &WIDGET_HOTKEY_LIST::OnMenu, this ); Bind( wxEVT_MENU, &WIDGET_HOTKEY_LIST::OnMenu, this );
} }
Bind( wxEVT_SIZE, &WIDGET_HOTKEY_LIST::OnSize, this );
} }
@ -580,3 +677,4 @@ long WIDGET_HOTKEY_LIST::MapKeypressToKeycode( const wxKeyEvent& aEvent )
return key; return key;
} }
} }

View File

@ -1,96 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file two_column_tree_list.h
*/
#include <wx/treelist.h>
#include <map>
#ifndef __two_column_tree_list__
#define __two_column_tree_list__
/**
* Modified wxTreeListCtrl designed for use with two columns, with better
* column resizing. wxTreeListCtrl accumulates error as columns resize,
* leading to columns with a totally wrong size.
*/
class TWO_COLUMN_TREE_LIST : public wxTreeListCtrl
{
public:
/**
* Create a TWO_COLUMN_TREE_LIST.
*/
TWO_COLUMN_TREE_LIST( wxWindow* aParent, wxWindowID aID,
const wxPoint & aPos = wxDefaultPosition,
const wxSize & aSize = wxDefaultSize,
long aStyle = wxTL_DEFAULT_STYLE,
const wxString & aName = wxTreeListCtrlNameStr );
/**
* Set the column number that will "rubber-band" (expand with available space).
* As this is a TWO column tree list, this must be zero or one.
*/
void SetRubberBandColumn( int aRubberBandColumn )
{
m_rubber_band_column = aRubberBandColumn;
}
/**
* Set the minimum width of the non-rubber-band column.
*/
void SetClampedMinWidth( int aClampedMinWidth )
{
m_clamped_min_width = aClampedMinWidth;
}
/**
* Recompute column sizes. This should be called after adding columns.
* There is no need to call this in an OnSize handler - this CALLS the
* OnSize handler.
*/
void AutosizeColumns();
/**
* Override buggy wxTreeListCtrl size handler.
*/
void OnSize( wxSizeEvent& aEvent );
protected:
/**
* Memoized version of wx WidthFor(), which returns the width in pixels
* required to display a string. This function is REALLY SLOW on macOS.
*/
int MemoWidthFor( const wxString& aStr );
int m_rubber_band_column;
int m_clamped_min_width;
static std::map<wxString, int> m_width_cache;
};
#endif // __two_column_tree_list__

View File

@ -22,10 +22,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
/**
* @file widget_hotkey_list.h
*/
#ifndef __widget_hotkey_list__ #ifndef __widget_hotkey_list__
#define __widget_hotkey_list__ #define __widget_hotkey_list__
@ -33,7 +29,7 @@
#include <vector> #include <vector>
#include <wx/treelist.h> #include <wx/treelist.h>
#include <widgets/two_column_tree_list.h> #include <wx/dataview.h>
#include <hotkeys_basic.h> #include <hotkeys_basic.h>
#include <hotkey_store.h> #include <hotkey_store.h>
@ -41,24 +37,27 @@
class WIDGET_HOTKEY_CLIENT_DATA; class WIDGET_HOTKEY_CLIENT_DATA;
class WIDGET_HOTKEY_LIST : public TWO_COLUMN_TREE_LIST class WIDGET_HOTKEY_LIST : public wxTreeListCtrl
{ {
HOTKEY_STORE& m_hk_store; HOTKEY_STORE& m_hk_store;
bool m_readOnly; bool m_readOnly;
wxTreeListItem m_context_menu_item; wxTreeListItem m_context_menu_item;
int m_rubber_band_column;
int m_clamped_min_width;
static std::map<wxString, int> m_width_cache;
/** /**
* Method GetHKClientData * Method GetHKClientData
* Return the WIDGET_HOTKEY_CLIENT_DATA for the given item, or NULL if the * Return the WIDGET_HOTKEY_CLIENT_DATA for the given item, or NULL if the item is invalid.
* item is invalid.
*/ */
WIDGET_HOTKEY_CLIENT_DATA* GetHKClientData( wxTreeListItem aItem ); WIDGET_HOTKEY_CLIENT_DATA* GetHKClientData( wxTreeListItem aItem );
/** /**
* Get the WIDGET_HOTKEY_CLIENT_DATA form an item and assert if it isn't * Get the WIDGET_HOTKEY_CLIENT_DATA form an item and assert if it isn't found. This is for
* found. This is for use when the data not being present indicates an * use when the data not being present indicates an error.
* error.
*/ */
WIDGET_HOTKEY_CLIENT_DATA* getExpectedHkClientData( wxTreeListItem aItem ); WIDGET_HOTKEY_CLIENT_DATA* getExpectedHkClientData( wxTreeListItem aItem );
@ -80,8 +79,8 @@ class WIDGET_HOTKEY_LIST : public TWO_COLUMN_TREE_LIST
/** /**
* Attempt to change the given hotkey to the given key code. * Attempt to change the given hotkey to the given key code.
* *
* If the hotkey conflicts, the user is prompted to change anyway (and * If the hotkey conflicts, the user is prompted to change anyway (and in doing so, unset
* in doing so, unset the conflicting key), or cancel the attempt. * the conflicting key), or cancel the attempt.
* *
* @param aHotkey the change-able hotkey to try to change * @param aHotkey the change-able hotkey to try to change
* @param aKey the key code to change it to * @param aKey the key code to change it to
@ -89,7 +88,6 @@ class WIDGET_HOTKEY_LIST : public TWO_COLUMN_TREE_LIST
void changeHotkey( HOTKEY& aHotkey, long aKey ); void changeHotkey( HOTKEY& aHotkey, long aKey );
protected: protected:
/** /**
* Method EditItem * Method EditItem
* Prompt the user for a new hotkey given a list item. * Prompt the user for a new hotkey given a list item.
@ -126,15 +124,21 @@ protected:
*/ */
void OnSize( wxSizeEvent& aEvent ); void OnSize( wxSizeEvent& aEvent );
/**
* Memoized version of wxWidthFor(), which returns the width in pixels required to display
* a string. The wx version is REALLY SLOW on macOS.
*/
int MemoWidthFor( const wxString& aStr );
/** /**
* Method ResolveKeyConflicts * Method ResolveKeyConflicts
* Check if we can set a hotkey, and prompt the user if there is a conflict between * Check if we can set a hotkey, and prompt the user if there is a conflict between keys.
* keys. The key code should already have been checked that it's not for the same * The key code should already have been checked that it's not for the same entry as it's
* entry as it's current in, or else this method will prompt for the self-change. * current in, or else this method will prompt for the self-change.
* *
* The method will do conflict resolution depending on aSectionTag. * The method will do conflict resolution depending on aSectionTag.
* g_CommonSectionTag means the key code must only be checkd with the aSectionTag * g_CommonSectionTag means the key code must only be checkd with the aSectionTag section
* section and g_CommonSectionTag section. * and g_CommonSectionTag section.
* *
* @param aKey - key to check * @param aKey - key to check
* @param aActionName - name of the action into which the key is proposed to be installed * @param aActionName - name of the action into which the key is proposed to be installed
@ -165,8 +169,8 @@ public:
/** /**
* Set hotkeys in the control to default or original values. * Set hotkeys in the control to default or original values.
* @param aResetToDefault if true,.reset to the defaults inherent to the * @param aResetToDefault if true, reset to the defaults inherent to the hotkeys, else
* hotkeym, else reset to the value they had when the dialog was invoked. * reset to the value they had when the dialog was invoked.
*/ */
void ResetAllHotkeys( bool aResetToDefault ); void ResetAllHotkeys( bool aResetToDefault );