Add Scintilla support to WX_GRID.

This commit is contained in:
Jeff Young 2023-02-20 10:11:57 +00:00
parent f6fcae479c
commit 87eb4401e3
4 changed files with 191 additions and 11 deletions

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2020-2022 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 2020-2023 KiCad Developers, see change_log.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -33,7 +33,8 @@
#include <confirm.h> #include <confirm.h>
SCINTILLA_TRICKS::SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, const wxString& aBraces, SCINTILLA_TRICKS::SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, const wxString& aBraces,
bool aSingleLine, std::function<void()> aReturnCallback ) : bool aSingleLine, std::function<void()> aReturnCallback,
std::function<void( wxStyledTextEvent& )> aCharCallback ) :
m_te( aScintilla ), m_te( aScintilla ),
m_braces( aBraces ), m_braces( aBraces ),
m_lastCaretPos( -1 ), m_lastCaretPos( -1 ),
@ -41,7 +42,8 @@ SCINTILLA_TRICKS::SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, const wxString
m_lastSelEnd( -1 ), m_lastSelEnd( -1 ),
m_suppressAutocomplete( false ), m_suppressAutocomplete( false ),
m_singleLine( aSingleLine ), m_singleLine( aSingleLine ),
m_returnCallback( aReturnCallback ) m_returnCallback( aReturnCallback ),
m_charCallback( aCharCallback )
{ {
// Always use LF as eol char, regardless the platform // Always use LF as eol char, regardless the platform
m_te->SetEOLMode( wxSTC_EOL_LF ); m_te->SetEOLMode( wxSTC_EOL_LF );
@ -55,12 +57,18 @@ SCINTILLA_TRICKS::SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, const wxString
// Set up autocomplete // Set up autocomplete
m_te->AutoCompSetIgnoreCase( true ); m_te->AutoCompSetIgnoreCase( true );
m_te->AutoCompSetFillUps( m_braces[1] );
m_te->AutoCompSetMaxHeight( 20 ); m_te->AutoCompSetMaxHeight( 20 );
if( aBraces.Length() >= 2 )
m_te->AutoCompSetFillUps( m_braces[1] );
// Hook up events // Hook up events
m_te->Bind( wxEVT_STC_UPDATEUI, &SCINTILLA_TRICKS::onScintillaUpdateUI, this ); m_te->Bind( wxEVT_STC_UPDATEUI, &SCINTILLA_TRICKS::onScintillaUpdateUI, this );
// Handle autocomplete
m_te->Bind( wxEVT_STC_CHARADDED, &SCINTILLA_TRICKS::onChar, this );
m_te->Bind( wxEVT_STC_AUTOCOMP_CHAR_DELETED, &SCINTILLA_TRICKS::onChar, this );
// Dispatch command-keys in Scintilla control. // Dispatch command-keys in Scintilla control.
m_te->Bind( wxEVT_CHAR_HOOK, &SCINTILLA_TRICKS::onCharHook, this ); m_te->Bind( wxEVT_CHAR_HOOK, &SCINTILLA_TRICKS::onCharHook, this );
@ -155,6 +163,12 @@ bool isCtrlSlash( wxKeyEvent& aEvent )
} }
void SCINTILLA_TRICKS::onChar( wxStyledTextEvent& aEvent )
{
m_charCallback( aEvent );
}
void SCINTILLA_TRICKS::onCharHook( wxKeyEvent& aEvent ) void SCINTILLA_TRICKS::onCharHook( wxKeyEvent& aEvent )
{ {
wxString c = aEvent.GetUnicodeKey(); wxString c = aEvent.GetUnicodeKey();

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
* @author Jon Evans <jon@craftyjon.com> * @author Jon Evans <jon@craftyjon.com>
* *
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
@ -19,9 +19,14 @@
*/ */
#include <string_utils.h> #include <string_utils.h>
#include <wx/stc/stc.h>
#include <widgets/grid_text_helpers.h> #include <widgets/grid_text_helpers.h>
#include <scintilla_tricks.h>
//-------- GRID_CELL_ESCAPED_TEXT_RENDERER ------------------------------------------------------
//
GRID_CELL_ESCAPED_TEXT_RENDERER::GRID_CELL_ESCAPED_TEXT_RENDERER() : GRID_CELL_ESCAPED_TEXT_RENDERER::GRID_CELL_ESCAPED_TEXT_RENDERER() :
wxGridCellStringRenderer() wxGridCellStringRenderer()
{ {
@ -50,3 +55,117 @@ wxSize GRID_CELL_ESCAPED_TEXT_RENDERER::GetBestSize( wxGrid & aGrid, wxGridCellA
wxString unescaped = UnescapeString( aGrid.GetCellValue( aRow, aCol ) ); wxString unescaped = UnescapeString( aGrid.GetCellValue( aRow, aCol ) );
return wxGridCellStringRenderer::DoGetBestSize( aAttr, aDC, unescaped ); return wxGridCellStringRenderer::DoGetBestSize( aAttr, aDC, unescaped );
} }
//-------- GRID_CELL_STC_EDITOR -----------------------------------------------------------------
//
GRID_CELL_STC_EDITOR::GRID_CELL_STC_EDITOR( std::function<void( wxStyledTextEvent&,
SCINTILLA_TRICKS* )> aOnChar ) :
m_onChar( aOnChar )
{ }
void GRID_CELL_STC_EDITOR::Create( wxWindow* aParent, wxWindowID aId, wxEvtHandler* aEventHandler )
{
m_control = new wxStyledTextCtrl( aParent );
stc_ctrl()->SetTabIndents( false );
stc_ctrl()->SetBackSpaceUnIndents( false );
stc_ctrl()->SetViewEOL( false );
stc_ctrl()->SetViewWhiteSpace( false );
stc_ctrl()->SetIndentationGuides( false );
stc_ctrl()->SetMarginWidth( 0, 0 ); // Symbol margin
stc_ctrl()->SetMarginWidth( 1, 0 ); // Line-number margin
stc_ctrl()->SetEOLMode( wxSTC_EOL_LF );
stc_ctrl()->AutoCompSetMaxWidth( 25 );
stc_ctrl()->UsePopUp( 0 );
// A hack which causes Scintilla to auto-size the text editor canvas
// See: https://github.com/jacobslusser/ScintillaNET/issues/216
stc_ctrl()->SetScrollWidth( 1 );
stc_ctrl()->SetScrollWidthTracking( true );
m_scintillaTricks = new SCINTILLA_TRICKS(
stc_ctrl(), wxEmptyString, true,
[this]()
{
stc_ctrl()->AutoCompComplete();
},
[this]( wxStyledTextEvent& aEvent )
{
m_onChar( aEvent, m_scintillaTricks );
} );
stc_ctrl()->Bind( wxEVT_KILL_FOCUS, &GRID_CELL_STC_EDITOR::onFocusLoss, this );
wxGridCellEditor::Create( aParent, aId, aEventHandler );
}
wxStyledTextCtrl* GRID_CELL_STC_EDITOR::stc_ctrl() const
{
return static_cast<wxStyledTextCtrl*>( m_control );
}
wxString GRID_CELL_STC_EDITOR::GetValue() const
{
return stc_ctrl()->GetText();
}
void GRID_CELL_STC_EDITOR::Show( bool aShow, wxGridCellAttr* aAttr )
{
if( !aShow )
stc_ctrl()->AutoCompCancel();
wxGridCellEditor::Show( aShow, aAttr );
}
void GRID_CELL_STC_EDITOR::BeginEdit( int aRow, int aCol, wxGrid* aGrid )
{
auto evtHandler = static_cast<wxGridCellEditorEvtHandler*>( m_control->GetEventHandler()
);
// Don't immediately end if we get a kill focus event within BeginEdit
evtHandler->SetInSetFocus( true );
m_value = aGrid->GetTable()->GetValue( aRow, aCol );
stc_ctrl()->SetFocus();
stc_ctrl()->SetText( m_value );
stc_ctrl()->SelectAll();
}
bool GRID_CELL_STC_EDITOR::EndEdit( int, int, const wxGrid*, const wxString&, wxString *aNewVal )
{
const wxString value = stc_ctrl()->GetText();
if( value == m_value )
return false;
m_value = value;
if( aNewVal )
*aNewVal = value;
return true;
}
void GRID_CELL_STC_EDITOR::ApplyEdit( int aRow, int aCol, wxGrid* aGrid )
{
aGrid->GetTable()->SetValue( aRow, aCol, m_value );
}
void GRID_CELL_STC_EDITOR::onFocusLoss( wxFocusEvent& aEvent )
{
if( stc_ctrl() )
stc_ctrl()->AutoCompCancel();
aEvent.Skip();
}

View File

@ -37,7 +37,14 @@ class SCINTILLA_TRICKS : public wxEvtHandler
public: public:
SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, const wxString& aBraces, bool aSingleLine, SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, const wxString& aBraces, bool aSingleLine,
std::function<void()> m_enterCallback = [](){ } ); std::function<void()> aReturnCallback =
[]()
{ },
std::function<void( wxStyledTextEvent& )> aCharCallback =
[]( wxStyledTextEvent& )
{ } );
wxStyledTextCtrl* Scintilla() const { return m_te; }
void DoAutocomplete( const wxString& aPartial, const wxArrayString& aTokens ); void DoAutocomplete( const wxString& aPartial, const wxArrayString& aTokens );
@ -49,6 +56,7 @@ protected:
int firstNonWhitespace( int aLine, int* aWhitespaceCount = nullptr ); int firstNonWhitespace( int aLine, int* aWhitespaceCount = nullptr );
void onCharHook( wxKeyEvent& aEvent ); void onCharHook( wxKeyEvent& aEvent );
void onChar( wxStyledTextEvent& aEvent );
void onScintillaUpdateUI( wxStyledTextEvent& aEvent ); void onScintillaUpdateUI( wxStyledTextEvent& aEvent );
void onThemeChanged( wxSysColourChangedEvent &aEvent ); void onThemeChanged( wxSysColourChangedEvent &aEvent );
@ -61,8 +69,11 @@ protected:
bool m_suppressAutocomplete; bool m_suppressAutocomplete;
bool m_singleLine; // Treat <return> as OK, and skip special tab bool m_singleLine; // Treat <return> as OK, and skip special tab
// stop handling (including monospaced font). // stop handling (including monospaced font).
std::function<void()> m_returnCallback; // Process <return> in singleLine, and std::function<void()> m_returnCallback; // Process <return> in singleLine, and
// <shift> + <return> irrespective. // <shift> + <return> irrespective.
std::function<void( wxStyledTextEvent& aEvent )> m_charCallback;
}; };
#endif // SCINTILLA_TRICKS_H #endif // SCINTILLA_TRICKS_H

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
* @author Jon Evans <jon@craftyjon.com> * @author Jon Evans <jon@craftyjon.com>
* *
* This program is free software: you can redistribute it and/or modify it * This program is free software: you can redistribute it and/or modify it
@ -24,6 +24,9 @@
#include <wx/generic/gridctrl.h> #include <wx/generic/gridctrl.h>
class wxGrid; class wxGrid;
class wxStyledTextCtrl;
class wxStyledTextEvent;
class SCINTILLA_TRICKS;
/** /**
* A text renderer that can unescape text for display * A text renderer that can unescape text for display
@ -34,11 +37,44 @@ class GRID_CELL_ESCAPED_TEXT_RENDERER : public wxGridCellStringRenderer
public: public:
GRID_CELL_ESCAPED_TEXT_RENDERER(); GRID_CELL_ESCAPED_TEXT_RENDERER();
void Draw( wxGrid& aGrid, wxGridCellAttr& aAttr, wxDC& aDC, void Draw( wxGrid& aGrid, wxGridCellAttr& aAttr, wxDC& aDC, const wxRect& aRect, int aRow,
const wxRect& aRect, int aRow, int aCol, bool isSelected ) override; int aCol, bool isSelected ) override;
wxSize GetBestSize( wxGrid & grid, wxGridCellAttr & attr, wxDC & dc, wxSize GetBestSize( wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, int row, int col ) override;
int row, int col ) override;
}; };
class GRID_CELL_STC_EDITOR : public wxGridCellEditor
{
public:
GRID_CELL_STC_EDITOR( std::function<void( wxStyledTextEvent&, SCINTILLA_TRICKS* )> aOnChar );
void Create( wxWindow* aParent, wxWindowID aId, wxEvtHandler* aEventHandler ) override;
wxGridCellEditor* Clone() const override
{
return new GRID_CELL_STC_EDITOR( m_onChar );
}
wxString GetValue() const override;
void Show( bool aShow, wxGridCellAttr *aAttr = nullptr ) override;
void BeginEdit( int aRow, int aCol, wxGrid* aGrid ) override;
bool EndEdit( int aRow, int aCol, const wxGrid*, const wxString&, wxString* aNewVal ) override;
void ApplyEdit( int aRow, int aCol, wxGrid* aGrid ) override;
void Reset() override {}
protected:
void onFocusLoss( wxFocusEvent& aEvent );
wxStyledTextCtrl* stc_ctrl() const;
protected:
SCINTILLA_TRICKS* m_scintillaTricks;
wxString m_value;
std::function<void( wxStyledTextEvent&, SCINTILLA_TRICKS* )> m_onChar;
};
#endif // KICAD_GRID_TEXT_HELPERS_H #endif // KICAD_GRID_TEXT_HELPERS_H