Improve size and handling of in-place editor in wxGenericTreeCtrl

Squash merge the changes from master with some additional tweaks to
preserve ABI-compatibility and allow building with wxUSE_UNICODE==0 in
this branch.

See #23001, #23205.

(cherry picked from commit 3e571ef2535ebaf3fe4ebb5f04fd05708be0458a)
This commit is contained in:
Vadim Zeitlin 2023-02-06 19:47:42 +01:00
parent 94997a44d6
commit 087f0c7742
6 changed files with 96 additions and 33 deletions

View File

@ -272,6 +272,7 @@ wxGTK:
- Fix display artefacts when using AUI without compositor under X11 (#23135). - Fix display artefacts when using AUI without compositor under X11 (#23135).
- Allow selecting and copying text in wxMessageDialog (Ian McInerney, #23039). - Allow selecting and copying text in wxMessageDialog (Ian McInerney, #23039).
- Fix initial size of top-level window on Wayland (#23041). - Fix initial size of top-level window on Wayland (#23041).
- Improve size and behaviour of in-place editor in wxTreeCtrl (taler21, #23001).
wxMSW: wxMSW:

View File

@ -291,7 +291,7 @@ MyFrame::MyFrame(const wxString& title, int x, int y, int w, int h)
tree_menu->Append(TreeTest_DecSpacing, "Reduce spacing by 5 points\tCtrl-R"); tree_menu->Append(TreeTest_DecSpacing, "Reduce spacing by 5 points\tCtrl-R");
item_menu->Append(TreeTest_Dump, "&Dump item children"); item_menu->Append(TreeTest_Dump, "&Dump item children");
item_menu->Append(TreeTest_Rename, "&Rename item..."); item_menu->Append(TreeTest_Rename, "&Rename item...\tF2");
item_menu->AppendSeparator(); item_menu->AppendSeparator();
item_menu->Append(TreeTest_SetBold, "Make item &bold"); item_menu->Append(TreeTest_SetBold, "Make item &bold");

View File

@ -103,6 +103,8 @@ protected:
void OnKeyUp( wxKeyEvent &event ); void OnKeyUp( wxKeyEvent &event );
void OnKillFocus( wxFocusEvent &event ); void OnKillFocus( wxFocusEvent &event );
void IncreaseSizeForText( const wxString& text );
bool AcceptChanges(); bool AcceptChanges();
void Finish( bool setfocus ); void Finish( bool setfocus );
@ -428,6 +430,11 @@ wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner,
m_owner = owner; m_owner = owner;
m_aboutToFinish = false; m_aboutToFinish = false;
// Create the text hidden to show it with the correct size -- which we
// can't determine before creating it.
Hide();
Create(m_owner, wxID_ANY, m_startValue);
wxRect rect; wxRect rect;
m_owner->GetBoundingRect(m_itemEdited, rect, true); m_owner->GetBoundingRect(m_itemEdited, rect, true);
@ -442,8 +449,27 @@ wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner,
rect.height += 4; rect.height += 4;
#endif // platforms #endif // platforms
(void)Create(m_owner, wxID_ANY, m_startValue, const wxSize textSize = rect.GetSize();
rect.GetPosition(), rect.GetSize()); wxSize fullSize = GetSizeFromTextSize(textSize);
if ( fullSize.y > textSize.y )
{
// It's ok to extend the rect to the right horizontally, which happens
// when we just change its size without changing its position below,
// but when extending it vertically, we need to keep it centered.
rect.y -= (fullSize.y - textSize.y + 1) / 2;
}
// Also check that the control fits into the parent window.
const int totalWidth = m_owner->GetClientSize().x;
if ( rect.x + fullSize.x > totalWidth )
{
fullSize.x = totalWidth - rect.x;
}
rect.SetSize(fullSize);
SetSize(rect);
Show();
SelectAll(); SelectAll();
} }
@ -533,30 +559,57 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
break; break;
default: default:
if ( !m_aboutToFinish )
{
#if wxUSE_UNICODE
wxChar ch = event.GetUnicodeKey();
#else
wxChar ch = event.m_keyCode < 256 &&
event.m_keyCode >= 0 &&
wxIsprint(event.m_keyCode)
? (wxChar)event.m_keyCode
: WXK_NONE;
#endif
if ( ch != WXK_NONE )
{
wxString value = GetValue();
long from, to;
GetSelection( &from, &to );
if ( from != to )
{
value.Remove( from, to - from );
}
IncreaseSizeForText( value + ch );
}
}
event.Skip(); event.Skip();
} }
} }
void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event ) void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event )
{ {
if ( !m_aboutToFinish ) // This function is only preserved in 3.2 branch to avoid warnings from the
{ // ABI compatibility checked, as this class (wrongly) uses public visibility
// auto-grow the textctrl: // there, even though it's not public at all -- and so we can't remove any
wxSize parentSize = m_owner->GetSize(); // of its functions, even if they're not needed any longer.
wxPoint myPos = GetPosition();
wxSize mySize = GetSize();
int sx, sy;
GetTextExtent(GetValue() + wxT("M"), &sx, &sy);
if (myPos.x + sx > parentSize.x)
sx = parentSize.x - myPos.x;
if (mySize.x > sx)
sx = mySize.x;
SetSize(sx, wxDefaultCoord);
}
event.Skip(); event.Skip();
} }
void wxTreeTextCtrl::IncreaseSizeForText( const wxString& text )
{
// auto-grow the textctrl:
wxSize parentSize = m_owner->GetClientSize();
wxPoint myPos = GetPosition();
wxSize mySize = GetSize();
int sx = GetSizeFromText(text).x;
if (myPos.x + sx > parentSize.x)
sx = parentSize.x - myPos.x;
if (sx > mySize.x)
SetSize(sx, wxDefaultCoord);
}
void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event ) void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event )
{ {
if ( !m_aboutToFinish ) if ( !m_aboutToFinish )

View File

@ -373,6 +373,13 @@ wxSize wxControl::GTKGetEntryMargins(GtkEntry* entry) const
GtkStyleContext* sc = gtk_widget_get_style_context(GTK_WIDGET(entry)); GtkStyleContext* sc = gtk_widget_get_style_context(GTK_WIDGET(entry));
gtk_style_context_get_padding(sc, gtk_style_context_get_state(sc), &border); gtk_style_context_get_padding(sc, gtk_style_context_get_state(sc), &border);
#else #else
if (gtk_entry_get_has_frame(entry))
{
GtkStyle* style = GTK_WIDGET(entry)->style;
size.x += 2 * style->xthickness;
size.y += 2 * style->ythickness;
}
// Equivalent to the GTK2 private function _gtk_entry_effective_inner_border() // Equivalent to the GTK2 private function _gtk_entry_effective_inner_border()
GtkBorder border = { 2, 2, 2, 2 }; GtkBorder border = { 2, 2, 2, 2 };

View File

@ -2156,14 +2156,13 @@ wxSize wxTextCtrl::DoGetSizeFromTextSize(int xlen, int ylen) const
{ {
wxASSERT_MSG( m_widget, wxS("GetSizeFromTextSize called before creation") ); wxASSERT_MSG( m_widget, wxS("GetSizeFromTextSize called before creation") );
wxSize tsize(xlen, 0);
int cHeight = GetCharHeight(); int cHeight = GetCharHeight();
wxSize tsize(xlen, cHeight);
if ( IsSingleLine() ) if ( IsSingleLine() )
{ {
if ( HasFlag(wxBORDER_NONE) ) if ( HasFlag(wxBORDER_NONE) )
{ {
tsize.y = cHeight;
#ifdef __WXGTK3__ #ifdef __WXGTK3__
tsize.IncBy(9, 0); tsize.IncBy(9, 0);
#else #else
@ -2174,10 +2173,16 @@ wxSize wxTextCtrl::DoGetSizeFromTextSize(int xlen, int ylen) const
{ {
// default height // default height
tsize.y = GTKGetPreferredSize(m_widget).y; tsize.y = GTKGetPreferredSize(m_widget).y;
// Add the margins we have previously set, but only the horizontal border #ifdef __WXGTK3__
// as vertical one has been taken account at GTKGetPreferredSize(). // Add the margins we have previously set.
// Also get other GTK+ margins. tsize.IncBy( GTKGetEntryMargins(GetEntry()) );
tsize.IncBy( GTKGetEntryMargins(GetEntry()).x, 0); #else
// For GTK 2 these margins are too big, so hard code something more
// reasonable, this is not great but should be fine considering
// that it's very unlikely that GTK 2 is going to evolve, making
// this inappropriate.
tsize.IncBy(20, 0);
#endif
} }
} }
@ -2189,7 +2194,6 @@ wxSize wxTextCtrl::DoGetSizeFromTextSize(int xlen, int ylen) const
tsize.IncBy(GTKGetPreferredSize(GTK_WIDGET(m_scrollBar[1])).x + 3, 0); tsize.IncBy(GTKGetPreferredSize(GTK_WIDGET(m_scrollBar[1])).x + 3, 0);
// height // height
tsize.y = cHeight;
if ( ylen <= 0 ) if ( ylen <= 0 )
{ {
tsize.y = 1 + cHeight * wxMax(wxMin(GetNumberOfLines(), 10), 2); tsize.y = 1 + cHeight * wxMax(wxMin(GetNumberOfLines(), 10), 2);
@ -2205,10 +2209,9 @@ wxSize wxTextCtrl::DoGetSizeFromTextSize(int xlen, int ylen) const
} }
} }
// Perhaps the user wants something different from CharHeight, or ylen // We should always use at least the specified height if it's valid.
// is used as the height of a multiline text. if ( ylen > tsize.y )
if ( ylen > 0 ) tsize.y = ylen;
tsize.IncBy(0, ylen - cHeight);
return tsize; return tsize;
} }

View File

@ -2801,10 +2801,9 @@ wxSize wxTextCtrl::DoGetSizeFromTextSize(int xlen, int ylen) const
hText += EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy) - cy; hText += EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy) - cy;
} }
// Perhaps the user wants something different from CharHeight, or ylen // We should always use at least the specified height if it's valid.
// is used as the height of a multiline text. if ( ylen > hText )
if ( ylen > 0 ) hText = ylen;
hText += ylen - GetCharHeight();
return wxSize(wText, hText); return wxSize(wText, hText);
} }