mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 02:03:12 +02:00
We block events when a modal window is active. But detecting when the modal window is closed is harder on GTK than just counting modal closes because the modal flag can sometimes be unset before the wxEVT_SHOW event fires. Instead, we track the stack of modal windows opened and close the window and subsequent windows when the object pointer matches Fixes https://gitlab.com/kicad/code/kicad/issues/13372
354 lines
9.3 KiB
C++
354 lines
9.3 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2018-2022 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <wx/dcclient.h>
|
|
#include <wx/checkbox.h>
|
|
#include <wx/choice.h>
|
|
#include <wx/listbox.h>
|
|
#include <wx/dataview.h>
|
|
#include <wx/radiobut.h>
|
|
#include <wx/slider.h>
|
|
#include <wx/spinctrl.h>
|
|
#include <wx/srchctrl.h>
|
|
#include <wx/stc/stc.h>
|
|
#include <wx/scrolbar.h>
|
|
#include <wx/grid.h>
|
|
#include <widgets/ui_common.h>
|
|
|
|
#include <algorithm>
|
|
#include <dialog_shim.h>
|
|
#include <pgm_base.h>
|
|
#include <wx/settings.h>
|
|
#include <bitmaps/bitmap_types.h>
|
|
#include <string_utils.h>
|
|
|
|
int KIUI::GetStdMargin()
|
|
{
|
|
// This is the value used in (most) wxFB dialogs
|
|
return 5;
|
|
}
|
|
|
|
|
|
SEVERITY SeverityFromString( const wxString& aSeverity )
|
|
{
|
|
if( aSeverity == wxT( "warning" ) )
|
|
return RPT_SEVERITY_WARNING;
|
|
else if( aSeverity == wxT( "ignore" ) )
|
|
return RPT_SEVERITY_IGNORE;
|
|
else
|
|
return RPT_SEVERITY_ERROR;
|
|
}
|
|
|
|
|
|
wxString SeverityToString( const SEVERITY& aSeverity )
|
|
{
|
|
if( aSeverity == RPT_SEVERITY_IGNORE )
|
|
return wxT( "ignore" );
|
|
else if( aSeverity == RPT_SEVERITY_WARNING )
|
|
return wxT( "warning" );
|
|
else
|
|
return wxT( "error" );
|
|
}
|
|
|
|
|
|
wxSize KIUI::GetTextSize( const wxString& aSingleLine, wxWindow* aWindow )
|
|
{
|
|
wxCoord width;
|
|
wxCoord height;
|
|
|
|
{
|
|
wxClientDC dc( aWindow );
|
|
dc.SetFont( aWindow->GetFont() );
|
|
dc.GetTextExtent( aSingleLine, &width, &height );
|
|
}
|
|
|
|
return wxSize( width, height );
|
|
}
|
|
|
|
|
|
wxFont KIUI::GetMonospacedUIFont()
|
|
{
|
|
static int guiFontSize = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ).GetPointSize();
|
|
|
|
wxFont font( guiFontSize, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL );
|
|
|
|
#ifdef __WXMAC__
|
|
// https://trac.wxwidgets.org/ticket/19210
|
|
if( font.GetFaceName().IsEmpty() )
|
|
font.SetFaceName( "Menlo" );
|
|
#endif
|
|
|
|
return font;
|
|
}
|
|
|
|
|
|
wxFont getGUIFont( wxWindow* aWindow, int aRelativeSize )
|
|
{
|
|
wxFont font = aWindow->GetFont();
|
|
|
|
font.SetPointSize( font.GetPointSize() + aRelativeSize );
|
|
|
|
if( Pgm().GetCommonSettings()->m_Appearance.apply_icon_scale_to_fonts )
|
|
{
|
|
double icon_scale_fourths;
|
|
|
|
if( Pgm().GetCommonSettings()->m_Appearance.icon_scale <= 0 )
|
|
icon_scale_fourths = KiIconScale( aWindow );
|
|
else
|
|
icon_scale_fourths = Pgm().GetCommonSettings()->m_Appearance.icon_scale;
|
|
|
|
font.SetPointSize( KiROUND( icon_scale_fourths * font.GetPointSize() / 4.0 ) );
|
|
}
|
|
|
|
#ifdef __WXMAC__
|
|
// https://trac.wxwidgets.org/ticket/19210
|
|
if( font.GetFaceName().IsEmpty() )
|
|
font.SetFaceName( "San Francisco" );
|
|
// OSX 10.1 .. 10.9: Lucida Grande
|
|
// OSX 10.10: Helvetica Neue
|
|
// OSX 10.11 .. : San Francisco
|
|
#endif
|
|
|
|
return font;
|
|
}
|
|
|
|
|
|
wxFont KIUI::GetStatusFont( wxWindow* aWindow )
|
|
{
|
|
#ifdef __WXMAC__
|
|
int scale = -2;
|
|
#else
|
|
int scale = 0;
|
|
#endif
|
|
|
|
return getGUIFont( aWindow, scale );
|
|
}
|
|
|
|
|
|
wxFont KIUI::GetDockedPaneFont( wxWindow* aWindow )
|
|
{
|
|
#ifdef __WXMAC__
|
|
int scale = -1;
|
|
#else
|
|
int scale = 0;
|
|
#endif
|
|
|
|
return getGUIFont( aWindow, scale );
|
|
}
|
|
|
|
|
|
wxFont KIUI::GetInfoFont( wxWindow* aWindow )
|
|
{
|
|
return getGUIFont( aWindow, -1 );
|
|
}
|
|
|
|
|
|
wxFont KIUI::GetControlFont( wxWindow* aWindow )
|
|
{
|
|
return getGUIFont( aWindow, 0 );
|
|
}
|
|
|
|
|
|
bool KIUI::EnsureTextCtrlWidth( wxTextCtrl* aCtrl, const wxString* aString )
|
|
{
|
|
wxWindow* window = aCtrl->GetParent();
|
|
|
|
if( !window )
|
|
window = aCtrl;
|
|
|
|
wxString ctrlText;
|
|
|
|
if( !aString )
|
|
{
|
|
ctrlText = aCtrl->GetValue();
|
|
aString = &ctrlText;
|
|
}
|
|
|
|
wxSize textz = GetTextSize( *aString, window );
|
|
wxSize ctrlz = aCtrl->GetSize();
|
|
|
|
if( ctrlz.GetWidth() < textz.GetWidth() + 10 )
|
|
{
|
|
ctrlz.SetWidth( textz.GetWidth() + 10 );
|
|
aCtrl->SetSizeHints( ctrlz );
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
wxString KIUI::EllipsizeStatusText( wxWindow* aWindow, const wxString& aString )
|
|
{
|
|
wxString msg = UnescapeString( aString );
|
|
|
|
msg.Replace( wxT( "\n" ), wxT( " " ) );
|
|
msg.Replace( wxT( "\r" ), wxT( " " ) );
|
|
msg.Replace( wxT( "\t" ), wxT( " " ) );
|
|
|
|
wxClientDC dc( aWindow );
|
|
int statusWidth = aWindow->GetSize().GetWidth();
|
|
|
|
// 30% of the first 800 pixels plus 60% of the remaining width
|
|
int textWidth = std::min( statusWidth, 800 ) * 0.3 + std::max( statusWidth - 800, 0 ) * 0.6;
|
|
|
|
return wxControl::Ellipsize( msg, dc, wxELLIPSIZE_END, textWidth );
|
|
}
|
|
|
|
|
|
wxString KIUI::EllipsizeMenuText( const wxString& aString )
|
|
{
|
|
wxString msg = UnescapeString( aString );
|
|
|
|
msg.Replace( wxT( "\n" ), wxT( " " ) );
|
|
msg.Replace( wxT( "\r" ), wxT( " " ) );
|
|
msg.Replace( wxT( "\t" ), wxT( " " ) );
|
|
|
|
if( msg.Length() > 36 )
|
|
msg = msg.Left( 34 ) + wxT( "..." );
|
|
|
|
return msg;
|
|
}
|
|
|
|
|
|
void KIUI::SelectReferenceNumber( wxTextEntry* aTextEntry )
|
|
{
|
|
wxString ref = aTextEntry->GetValue();
|
|
|
|
if( ref.find_first_of( '?' ) != ref.npos )
|
|
{
|
|
aTextEntry->SetSelection( ref.find_first_of( '?' ), ref.find_last_of( '?' ) + 1 );
|
|
}
|
|
else if( ref.find_first_of( '*' ) != ref.npos )
|
|
{
|
|
aTextEntry->SetSelection( ref.find_first_of( '*' ), ref.find_last_of( '*' ) + 1 );
|
|
}
|
|
else
|
|
{
|
|
wxString num = ref;
|
|
|
|
while( !num.IsEmpty() && ( !isdigit( num.Last() ) || !isdigit( num.GetChar( 0 ) ) ) )
|
|
{
|
|
// Trim non-digit from end
|
|
if( !isdigit( num.Last() ) )
|
|
num.RemoveLast();
|
|
|
|
// Trim non-digit from the start
|
|
if( !num.IsEmpty() && !isdigit( num.GetChar( 0 ) ) )
|
|
num = num.Right( num.Length() - 1 );
|
|
}
|
|
|
|
aTextEntry->SetSelection( ref.Find( num ), ref.Find( num ) + num.Length() );
|
|
|
|
if( num.IsEmpty() )
|
|
aTextEntry->SetSelection( -1, -1 );
|
|
}
|
|
}
|
|
|
|
|
|
bool KIUI::IsInputControlFocused( wxWindow* aFocus )
|
|
{
|
|
if( aFocus == nullptr )
|
|
aFocus = wxWindow::FindFocus();
|
|
|
|
if( !aFocus )
|
|
return false;
|
|
|
|
wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( aFocus );
|
|
wxStyledTextCtrl* styledText = dynamic_cast<wxStyledTextCtrl*>( aFocus );
|
|
wxListBox* listBox = dynamic_cast<wxListBox*>( aFocus );
|
|
wxSearchCtrl* searchCtrl = dynamic_cast<wxSearchCtrl*>( aFocus );
|
|
wxCheckBox* checkboxCtrl = dynamic_cast<wxCheckBox*>( aFocus );
|
|
wxChoice* choiceCtrl = dynamic_cast<wxChoice*>( aFocus );
|
|
wxRadioButton* radioBtn = dynamic_cast<wxRadioButton*>( aFocus );
|
|
wxSpinCtrl* spinCtrl = dynamic_cast<wxSpinCtrl*>( aFocus );
|
|
wxSpinCtrlDouble* spinDblCtrl = dynamic_cast<wxSpinCtrlDouble*>( aFocus );
|
|
wxSlider* sliderCtl = dynamic_cast<wxSlider*>( aFocus );
|
|
|
|
// Data view control is annoying, the focus is on a "wxDataViewCtrlMainWindow" class that
|
|
// is not formally exported via the header.
|
|
wxDataViewCtrl* dataViewCtrl = nullptr;
|
|
|
|
wxWindow* parent = aFocus->GetParent();
|
|
|
|
if( parent )
|
|
dataViewCtrl = dynamic_cast<wxDataViewCtrl*>( parent );
|
|
|
|
return ( textEntry || styledText || listBox || searchCtrl || checkboxCtrl || choiceCtrl
|
|
|| radioBtn || spinCtrl || spinDblCtrl || sliderCtl || dataViewCtrl );
|
|
}
|
|
|
|
|
|
bool KIUI::IsInputControlEditable( wxWindow* aFocus )
|
|
{
|
|
wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( aFocus );
|
|
wxStyledTextCtrl* styledText = dynamic_cast<wxStyledTextCtrl*>( aFocus );
|
|
wxSearchCtrl* searchCtrl = dynamic_cast<wxSearchCtrl*>( aFocus );
|
|
|
|
if( textEntry )
|
|
return textEntry->IsEditable();
|
|
else if( styledText )
|
|
return styledText->IsEditable();
|
|
else if( searchCtrl )
|
|
return searchCtrl->IsEditable();
|
|
|
|
return true; // Must return true if we can't determine the state, intentionally true for non inputs as well
|
|
}
|
|
|
|
|
|
bool KIUI::IsModalDialogFocused()
|
|
{
|
|
return !Pgm().m_ModalDialogs.empty();
|
|
}
|
|
|
|
|
|
void KIUI::Disable( wxWindow* aWindow )
|
|
{
|
|
wxScrollBar* scrollBar = dynamic_cast<wxScrollBar*>( aWindow );
|
|
wxGrid* grid = dynamic_cast<wxGrid*>( aWindow );
|
|
wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( aWindow );
|
|
wxControl* control = dynamic_cast<wxControl*>( aWindow );
|
|
|
|
if( scrollBar )
|
|
{
|
|
// Leave a scroll bar active
|
|
}
|
|
else if( grid )
|
|
{
|
|
for( int row = 0; row < grid->GetNumberRows(); ++row )
|
|
{
|
|
for( int col = 0; col < grid->GetNumberCols(); ++col )
|
|
grid->SetReadOnly( row, col );
|
|
}
|
|
}
|
|
else if( scintilla )
|
|
{
|
|
scintilla->SetReadOnly( true );
|
|
}
|
|
else if( control )
|
|
{
|
|
control->Disable();
|
|
}
|
|
else
|
|
{
|
|
for( wxWindow* child : aWindow->GetChildren() )
|
|
Disable( child );
|
|
}
|
|
}
|