39#include <wx/display.h>
40#include <wx/evtloop.h>
45#include <wx/propgrid/propgrid.h>
46#include <wx/checklst.h>
47#include <wx/dataview.h>
48#include <wx/bmpbuttn.h>
49#include <wx/textctrl.h>
50#include <wx/stc/stc.h>
51#include <wx/combobox.h>
52#include <wx/odcombo.h>
54#include <wx/checkbox.h>
55#include <wx/spinctrl.h>
56#include <wx/splitter.h>
57#include <wx/radiobox.h>
58#include <wx/radiobut.h>
59#include <wx/datectrl.h>
61#include <wx/timectrl.h>
63#include <wx/variant.h>
64#include <wx/weakref.h>
68#include <nlohmann/json.hpp>
85 std::string title = aTitle.ToStdString();
86 size_t parenPos = title.rfind(
'(' );
88 if( parenPos != std::string::npos && parenPos > 0 )
90 size_t end = parenPos;
92 while(
end > 0 && title[
end - 1] ==
' ' )
95 return title.substr( 0,
end );
113#if wxUSE_DATEPICKCTRL
114 if(
dynamic_cast<const wxDatePickerCtrl*
>( aWin ) !=
nullptr )
118#if wxUSE_TIMEPICKCTRL
119 if(
dynamic_cast<const wxTimePickerCtrl*
>( aWin ) !=
nullptr )
128 const wxSize& size,
long style,
const wxString&
name ) :
129 wxDialog( aParent, id, title, pos, size, style,
name ),
152 while( !kiwayHolder && aParent->GetParent() )
154 aParent = aParent->GetParent();
168 m_parentFrame = static_cast<EDA_BASE_FRAME*>( kiwayHolder );
169 TOOL_MANAGER* toolMgr = m_parentFrame->GetToolManager();
171 if( toolMgr && toolMgr->IsContextMenuActive() )
172 toolMgr->VetoContextMenuMouseWarp();
180 Kiway().SetBlockingDialog(
this );
198 wxString msg = wxString::Format(
"Opening dialog %s", GetTitle() );
214 std::function<void( wxWindowList& )> clearOptOuts =
215 [&]( wxWindowList& children )
217 for( wxWindow* child : children )
220 child->SetClientData(
nullptr );
225 SetClientData(
nullptr );
226 clearOptOuts( GetChildren() );
228 std::function<void( wxWindowList& )> disconnectFocusHandlers =
229 [&]( wxWindowList& children )
231 for( wxWindow* child : children )
236 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( child ) )
241 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( child ) )
248 disconnectFocusHandlers( child->GetChildren() );
253 disconnectFocusHandlers( GetChildren() );
255 std::function<void( wxWindowList& )> disconnectUndoRedoHandlers =
256 [&]( wxWindowList& children )
258 for( wxWindow* child : children )
263 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( child ) )
267 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( child ) )
271 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( child ) )
276 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( child ) )
280 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( child ) )
284 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( child ) )
289 else if( wxSpinCtrlDouble* spinD =
dynamic_cast<wxSpinCtrlDouble*
>( child ) )
294 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( child ) )
298 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( child ) )
302 else if( wxGrid*
grid =
dynamic_cast<wxGrid*
>( child ) )
306 else if( wxPropertyGrid* propGrid =
dynamic_cast<wxPropertyGrid*
>( child ) )
310 else if( wxCheckListBox* checkList =
dynamic_cast<wxCheckListBox*
>( child ) )
314 else if( wxDataViewListCtrl* dataList =
dynamic_cast<wxDataViewListCtrl*
>( child ) )
320 disconnectUndoRedoHandlers( child->GetChildren() );
325 disconnectUndoRedoHandlers( GetChildren() );
330 binder->DetachFromDialogShim();
349 if( wxSizer* sz = GetSizer() )
366 GetSizer()->SetSizeHints(
this );
375 rect.width = std::min( rect.width, aClientArea.width );
376 rect.height = std::min( rect.height, aClientArea.height );
378 rect.x = std::clamp( rect.x, aClientArea.x, aClientArea.GetRight() - rect.width + 1 );
379 rect.y = std::clamp( rect.y, aClientArea.y, aClientArea.GetBottom() - rect.height + 1 );
389 int displayIdx = wxDisplay::GetFromWindow(
this );
391 if( displayIdx == wxNOT_FOUND && m_parent )
392 displayIdx = wxDisplay::GetFromWindow( m_parent );
394 if( displayIdx == wxNOT_FOUND )
397 wxRect clientArea = wxDisplay( (
unsigned int) displayIdx ).GetClientArea();
399 if( clientArea.width <= 0 || clientArea.height <= 0 )
405 wxSize clampedMin( std::min(
minSize.x, clientArea.width ),
406 std::min(
minSize.y, clientArea.height ) );
409 SetMinSize( clampedMin );
413 wxRect current( GetPosition(), GetSize() );
416 if( clamped != current )
417 SetSize( clamped.x, clamped.y, clamped.width, clamped.height, 0 );
424 SetSize( ConvertDialogToPixels( sz ) );
431 return ConvertDialogToPixels( sz ).x;
438 return ConvertDialogToPixels( sz ).y;
450 wxDialog::SetPosition( aNewPosition );
462 wxWindow* target = toolCanvas ? toolCanvas : m_parent;
469 if( !aDeferUntilFrameActive || !toolCanvas )
505 ret = wxDialog::Show( show );
507 wxRect savedDialogRect;
512 auto dlgIt = settings->CsInternals().m_dialogControlValues.find( key );
514 if( dlgIt != settings->CsInternals().m_dialogControlValues.end() )
516 auto geoIt = dlgIt->second.find(
"__geometry" );
518 if( geoIt != dlgIt->second.end() && geoIt->second.is_object() )
520 const nlohmann::json& g = geoIt->second;
521 savedDialogRect.SetPosition( wxPoint( g.value(
"x", 0 ), g.value(
"y", 0 ) ) );
522 savedDialogRect.SetSize( wxSize( g.value(
"w", 500 ), g.value(
"h", 300 ) ) );
527 if( savedDialogRect.GetSize().x != 0 && savedDialogRect.GetSize().y != 0
528 && ( GetWindowStyleFlag() & wxRESIZE_BORDER ) != 0 )
531 wxSize restoredSize = FromDIP( savedDialogRect.GetSize() );
535 SetSize( savedDialogRect.GetPosition().x, savedDialogRect.GetPosition().y,
536 wxDialog::GetSize().x, wxDialog::GetSize().y, 0 );
540 SetSize( savedDialogRect.GetPosition().x, savedDialogRect.GetPosition().y,
541 std::max( wxDialog::GetSize().x, restoredSize.x ),
542 std::max( wxDialog::GetSize().y, restoredSize.y ), 0 );
548 SetMinSize( wxDefaultSize );
549 InvalidateBestSize();
550 SetMinSize( GetBestSize() );
554 if( m_parent !=
nullptr )
556 if( wxDisplay::GetFromPoint( m_parent->GetPosition() )
557 != wxDisplay::GetFromPoint( savedDialogRect.GetPosition() ) )
576 wxPoint grabPoint = GetPosition();
577 grabPoint.x += GetSize().x / 2;
578 grabPoint.y += FromDIP( 15 );
580 if( wxDisplay::GetFromPoint( grabPoint ) == wxNOT_FOUND )
597 m_eventLoop->Exit( GetReturnCode() );
600 ret = wxDialog::Show( show );
616 auto dlgIt = settings->CsInternals().m_dialogControlValues.find( key );
618 if( dlgIt == settings->CsInternals().m_dialogControlValues.end() )
621 dlgIt->second.erase(
"__geometry" );
640 int parentDisplay = wxDisplay::GetFromWindow( m_parent );
641 int myDisplay = wxDisplay::GetFromWindow(
this );
643 if( parentDisplay != wxNOT_FOUND && myDisplay != wxNOT_FOUND )
668 return wxDialog::Enable( enable );
674 auto getSiblingIndex =
675 [](
const wxWindow* parent,
const wxWindow* child )
677 wxString childClass = child->GetClassInfo()->GetClassName();
680 for(
const wxWindow* sibling : parent->GetChildren() )
682 if( sibling->GetClassInfo()->GetClassName() != childClass )
685 if( sibling == child )
695 [&](
const wxWindow* window )
697 std::string key = wxString( window->GetClassInfo()->GetClassName() ).ToStdString();
699 if( window->GetParent() )
700 key +=
"_" + std::to_string( getSiblingIndex( window->GetParent(), window ) );
705 std::string key =
makeKey( aWin );
707 for(
const wxWindow* parent = aWin->GetParent(); parent && parent !=
this; parent = parent->GetParent() )
724 wxPoint pos = GetPosition();
725 wxSize dipSize = ToDIP( GetSize() );
729 geom[
"w" ] = dipSize.x;
730 geom[
"h" ] = dipSize.y;
731 dlgMap[
"__geometry" ] = geom;
733 std::function<void( wxWindow* )> saveFn =
738 if( !props->GetPropertyOr(
"persist",
false ) )
750 wxString formula = binder ? binder->
GetFormula() : wxString();
756 if( formula.IsEmpty() )
762 nlohmann::json state;
763 state[
"value" ] = binder->
GetValue();
764 state[
"formula" ] = formula;
765 dlgMap[ key ] = state;
768 else if( !formula.IsEmpty() )
770 dlgMap[ key ] = formula;
774 dlgMap[ key ] = evalCtrl->GetFormula();
776 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( win ) )
778 dlgMap[ key ] = combo->GetValue();
780 else if( wxOwnerDrawnComboBox* od_combo =
dynamic_cast<wxOwnerDrawnComboBox*
>( win ) )
782 dlgMap[ key ] = od_combo->GetSelection();
784 else if( wxTextEntry* textEntry =
dynamic_cast<wxTextEntry*
>( win ) )
786 dlgMap[ key ] = textEntry->GetValue();
788 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( win ) )
790 dlgMap[ key ] = choice->GetSelection();
792 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( win ) )
794 dlgMap[ key ] = check->GetValue();
796 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( win ) )
798 dlgMap[ key ] = spin->GetValue();
800 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( win ) )
802 dlgMap[ key ] = radio->GetValue();
804 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( win ) )
806 dlgMap[ key ] = radioBox->GetSelection();
808 else if( wxSplitterWindow* splitter =
dynamic_cast<wxSplitterWindow*
>( win ) )
810 dlgMap[ key ] = splitter->GetSashPosition();
812 else if( wxScrolledWindow* scrolled =
dynamic_cast<wxScrolledWindow*
>( win ) )
814 dlgMap[ key ] = scrolled->GetScrollPos( wxVERTICAL );
816 else if( wxNotebook* notebook =
dynamic_cast<wxNotebook*
>( win ) )
818 int index = notebook->GetSelection();
820 if(
index >= 0 &&
index < (
int) notebook->GetPageCount() )
821 dlgMap[ key ] = notebook->GetPageText( notebook->GetSelection() );
823 else if( wxAuiNotebook* auiNotebook =
dynamic_cast<wxAuiNotebook*
>( win ) )
825 int index = auiNotebook->GetSelection();
827 if(
index >= 0 &&
index < (
int) auiNotebook->GetPageCount() )
828 dlgMap[ key ] = auiNotebook->GetPageText( auiNotebook->GetSelection() );
832 dlgMap[ key ] =
grid->GetShownColumnsAsString();
836 for( wxWindow* child : win->GetChildren() )
842 if( !props->GetPropertyOr(
"persist",
false ) )
846 for( wxWindow* child : GetChildren() )
864 const std::map<std::string, nlohmann::json>& dlgMap = dlgIt->second;
866 std::function<void( wxWindow* )> loadFn =
871 if( !props->GetPropertyOr(
"persist",
false ) )
882 auto it = dlgMap.find( key );
884 if( it != dlgMap.end() )
886 const nlohmann::json& j = it->second;
892 if( j.is_number_integer() )
896 else if( j.is_object() && j.contains(
"value" ) && j[
"value" ].is_number_integer() )
900 if( j.contains(
"formula" ) && j[
"formula" ].is_string() )
901 formula = wxString::FromUTF8( j[
"formula" ].get<std::string>().c_str() );
903 binder->
RestoreValue( j[
"value" ].get<int>(), formula );
905 else if( j.is_string() )
907 wxString
text = wxString::FromUTF8( j.get<std::string>().c_str() );
911 if( wxTextEntry* textEntry =
dynamic_cast<wxTextEntry*
>( win ) )
912 textEntry->ChangeValue(
text );
920 wxString
text = wxString::FromUTF8( j.get<std::string>().c_str() );
922 if( !evalCtrl->RestoreFormula(
text ) )
923 evalCtrl->ChangeValue(
text );
926 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( win ) )
929 combo->SetValue( wxString::FromUTF8( j.get<std::string>().c_str() ) );
931 else if( wxOwnerDrawnComboBox* od_combo =
dynamic_cast<wxOwnerDrawnComboBox*
>( win ) )
933 if( j.is_number_integer() )
935 int index = j.get<
int>();
937 if(
index >= 0 &&
index < (
int) od_combo->GetCount() )
938 od_combo->SetSelection(
index );
941 else if( wxTextEntry* textEntry =
dynamic_cast<wxTextEntry*
>( win ) )
944 textEntry->ChangeValue( wxString::FromUTF8( j.get<std::string>().c_str() ) );
946 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( win ) )
948 if( j.is_number_integer() )
950 int index = j.get<
int>();
952 if(
index >= 0 &&
index < (
int) choice->GetCount() )
953 choice->SetSelection(
index );
956 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( win ) )
959 check->SetValue( j.get<
bool>() );
961 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( win ) )
963 if( j.is_number_integer() )
964 spin->SetValue( j.get<
int>() );
966 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( win ) )
974 radio->SetValue(
true );
977 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( win ) )
979 if( j.is_number_integer() )
981 int index = j.get<
int>();
983 if(
index >= 0 &&
index < (
int) radioBox->GetCount() )
984 radioBox->SetSelection(
index );
987 else if( wxSplitterWindow* splitter =
dynamic_cast<wxSplitterWindow*
>( win ) )
989 if( j.is_number_integer() )
990 splitter->SetSashPosition( j.get<
int>() );
992 else if( wxScrolledWindow* scrolled =
dynamic_cast<wxScrolledWindow*
>( win ) )
994 if( j.is_number_integer() )
995 scrolled->SetScrollPos( wxVERTICAL, j.get<
int>() );
997 else if( wxNotebook* notebook =
dynamic_cast<wxNotebook*
>( win ) )
1001 wxString pageTitle = wxString::FromUTF8( j.get<std::string>().c_str() );
1003 for(
int page = 0; page < (int) notebook->GetPageCount(); ++page )
1005 if( notebook->GetPageText( page ) == pageTitle )
1006 notebook->ChangeSelection( page );
1010 else if( wxAuiNotebook* auiNotebook =
dynamic_cast<wxAuiNotebook*
>( win ) )
1014 wxString pageTitle = wxString::FromUTF8( j.get<std::string>().c_str() );
1016 for(
int page = 0; page < (int) auiNotebook->GetPageCount(); ++page )
1018 if( auiNotebook->GetPageText( page ) == pageTitle )
1019 auiNotebook->ChangeSelection( page );
1026 grid->ShowHideColumns( wxString::FromUTF8( j.get<std::string>().c_str() ) );
1031 for( wxWindow* child : win->GetChildren() )
1037 if( !props->GetPropertyOr(
"persist",
false ) )
1041 for( wxWindow* child : GetChildren() )
1059 const std::map<std::string, nlohmann::json>& dlgMap = dlgIt->second;
1061 std::function<void( wxWindow* )> loadFn =
1062 [&]( wxWindow* win )
1066 if( !props->GetPropertyOr(
"persist",
false ) )
1074 auto it = dlgMap.find( key );
1076 if( it != dlgMap.end() )
1078 const nlohmann::json& j = it->second;
1080 if( wxSplitterWindow* splitter =
dynamic_cast<wxSplitterWindow*
>( win ) )
1082 if( j.is_number_integer() )
1083 splitter->SetSashPosition( j.get<
int>() );
1088 for( wxWindow* child : win->GetChildren() )
1094 if( !props->GetPropertyOr(
"persist",
false ) )
1098 for( wxWindow* child : GetChildren() )
1107 aWindow->SetClientData( props );
1109 if( aWindow ==
this )
1120 std::erase_if( dlgIt->second,
1121 [](
const auto& aEntry )
1123 return aEntry.first !=
"__geometry";
1148 [aUnitBinder](
const auto& aEntry )
1150 return aEntry.second == aUnitBinder;
1160 for( wxWindow* child : children )
1165 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( child ) )
1174#if defined( __WXMAC__ ) || defined( __WXMSW__ )
1175 if( !textCtrl->GetStringSelection().IsEmpty() )
1179 else if( textCtrl->IsEditable() )
1181 textCtrl->SelectAll();
1187 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( child ) )
1190 scintilla->Connect( wxEVT_SET_FOCUS,
1194 if( !scintilla->GetSelectedText().IsEmpty() )
1198 else if( scintilla->GetMarginWidth( 0 ) > 0 )
1202 else if( scintilla->IsEditable() )
1204 scintilla->SelectAll();
1210 else if(
dynamic_cast<wxBitmapButton*
>( child ) !=
nullptr )
1213 wxRect rect = child->GetRect();
1215 child->ConvertDialogToPixels(
minSize );
1217 rect.Inflate( std::max( 0,
minSize.x - rect.GetWidth() ),
1218 std::max( 0,
minSize.y - rect.GetHeight() ) );
1220 child->SetMinSize( rect.GetSize() );
1221 child->SetSize( rect );
1234 for( wxWindow* child : children )
1242 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( child ) )
1247 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( child ) )
1252 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( child ) )
1258 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( child ) )
1261 m_currentValues[ choice ] =
static_cast<long>( choice->GetSelection() );
1263 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( child ) )
1268 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( child ) )
1274 else if( wxSpinCtrlDouble* spinD =
dynamic_cast<wxSpinCtrlDouble*
>( child ) )
1280 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( child ) )
1285 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( child ) )
1288 m_currentValues[ radioBox ] =
static_cast<long>( radioBox->GetSelection() );
1290 else if( wxGrid*
grid =
dynamic_cast<wxGrid*
>( child ) )
1295 else if( wxPropertyGrid* propGrid =
dynamic_cast<wxPropertyGrid*
>( child ) )
1300 else if( wxCheckListBox* checkList =
dynamic_cast<wxCheckListBox*
>( child ) )
1305 else if( wxDataViewListCtrl* dataList =
dynamic_cast<wxDataViewListCtrl*
>( child ) )
1345 if( before != after )
1424 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( aCtrl ) )
1425 return wxVariant( textCtrl->GetValue() );
1426 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( aCtrl ) )
1427 return wxVariant( scintilla->GetText() );
1428 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( aCtrl ) )
1429 return wxVariant( combo->GetValue() );
1430 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( aCtrl ) )
1431 return wxVariant( (
long) choice->GetSelection() );
1432 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( aCtrl ) )
1433 return wxVariant( check->GetValue() );
1434 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( aCtrl ) )
1435 return wxVariant( (
long) spin->GetValue() );
1436 else if( wxSpinCtrlDouble* spinD =
dynamic_cast<wxSpinCtrlDouble*
>( aCtrl ) )
1437 return wxVariant( spinD->GetValue() );
1438 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( aCtrl ) )
1439 return wxVariant( radio->GetValue() );
1440 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( aCtrl ) )
1441 return wxVariant( (
long) radioBox->GetSelection() );
1442 else if( wxGrid*
grid =
dynamic_cast<wxGrid*
>( aCtrl ) )
1446 table &&
table->HasUndoStateSerialization() )
1448 return wxVariant(
table->SerializeUndoState() );
1451 nlohmann::json j = nlohmann::json::array();
1452 int rows =
grid->GetNumberRows();
1453 int cols =
grid->GetNumberCols();
1455 for(
int r = 0; r < rows; ++r )
1457 nlohmann::json row = nlohmann::json::array();
1459 for(
int c = 0; c < cols; ++c )
1460 row.push_back( std::string(
grid->GetCellValue( r, c ).ToUTF8() ) );
1465 return wxVariant( wxString( j.dump() ) );
1467 else if( wxPropertyGrid* propGrid =
dynamic_cast<wxPropertyGrid*
>( aCtrl ) )
1471 for( wxPropertyGridIterator it = propGrid->GetIterator(); !it.AtEnd(); ++it )
1473 wxPGProperty* prop = *it;
1474 j[ prop->GetName().ToStdString() ] = prop->GetValueAsString().ToStdString();
1477 return wxVariant( wxString( j.dump() ) );
1479 else if( wxCheckListBox* checkList =
dynamic_cast<wxCheckListBox*
>( aCtrl ) )
1481 nlohmann::json j = nlohmann::json::array();
1482 unsigned int count = checkList->GetCount();
1484 for(
unsigned int i = 0; i < count; ++i )
1486 if( checkList->IsChecked( i ) )
1490 return wxVariant( wxString( j.dump() ) );
1492 else if( wxDataViewListCtrl* dataList =
dynamic_cast<wxDataViewListCtrl*
>( aCtrl ) )
1494 nlohmann::json j = nlohmann::json::array();
1495 unsigned int rows = dataList->GetItemCount();
1496 unsigned int cols = dataList->GetColumnCount();
1498 for(
unsigned int r = 0; r < rows; ++r )
1500 nlohmann::json row = nlohmann::json::array();
1502 for(
unsigned int c = 0; c < cols; ++c )
1505 dataList->GetValue( val, r, c );
1506 row.push_back( std::string( val.GetString().ToUTF8() ) );
1512 return wxVariant( wxString( j.dump() ) );
1521 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( aCtrl ) )
1522 textCtrl->SetValue( aValue.GetString() );
1523 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( aCtrl ) )
1524 scintilla->SetText( aValue.GetString() );
1525 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( aCtrl ) )
1526 combo->SetValue( aValue.GetString() );
1527 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( aCtrl ) )
1528 choice->SetSelection( (
int) aValue.GetLong() );
1529 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( aCtrl ) )
1530 check->SetValue( aValue.GetBool() );
1531 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( aCtrl ) )
1532 spin->SetValue( (
int) aValue.GetLong() );
1533 else if( wxSpinCtrlDouble* spinD =
dynamic_cast<wxSpinCtrlDouble*
>( aCtrl ) )
1534 spinD->SetValue( aValue.GetDouble() );
1535 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( aCtrl ) )
1536 radio->SetValue( aValue.GetBool() );
1537 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( aCtrl ) )
1538 radioBox->SetSelection( (
int) aValue.GetLong() );
1539 else if( wxGrid*
grid =
dynamic_cast<wxGrid*
>( aCtrl ) )
1542 table &&
table->HasUndoStateSerialization() )
1544 table->RestoreUndoState( aValue.GetString() );
1548 nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(),
nullptr,
false );
1552 int rows = std::min( (
int) j.size(),
grid->GetNumberRows() );
1554 std::vector<std::pair<int, int>> changedCells;
1556 for(
int r = 0; r < rows; ++r )
1558 nlohmann::json row = j[r];
1559 int cols = std::min( (
int) row.size(),
grid->GetNumberCols() );
1561 for(
int c = 0; c < cols; ++c )
1563 wxString value = wxString( row[c].get<std::string>() );
1565 if(
grid->GetCellValue( r, c ) != value )
1567 grid->SetCellValue( r, c, value );
1568 changedCells.emplace_back( r, c );
1573 for(
const auto& [row, col] : changedCells )
1575 wxGridEvent evt(
grid->GetId(), wxEVT_GRID_CELL_CHANGED,
grid, row, col );
1576 evt.SetString(
grid->GetCellValue( row, col ) );
1577 grid->GetEventHandler()->ProcessEvent( evt );
1581 else if( wxPropertyGrid* propGrid =
dynamic_cast<wxPropertyGrid*
>( aCtrl ) )
1583 nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(),
nullptr,
false );
1587 for(
auto it = j.begin(); it != j.end(); ++it )
1588 propGrid->SetPropertyValue( wxString( it.key() ), wxString( it.value().get<std::string>() ) );
1591 else if( wxCheckListBox* checkList =
dynamic_cast<wxCheckListBox*
>( aCtrl ) )
1593 nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(),
nullptr,
false );
1597 unsigned int count = checkList->GetCount();
1599 for(
unsigned int i = 0; i < count; ++i )
1600 checkList->Check( i,
false );
1602 for(
auto& idx : j )
1604 unsigned int i = idx.get<
unsigned int>();
1607 checkList->Check( i,
true );
1611 else if( wxDataViewListCtrl* dataList =
dynamic_cast<wxDataViewListCtrl*
>( aCtrl ) )
1613 nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(),
nullptr,
false );
1617 unsigned int rows = std::min(
static_cast<unsigned int>( j.size() ),
1618 static_cast<unsigned int>( dataList->GetItemCount() ) );
1620 for(
unsigned int r = 0; r < rows; ++r )
1622 nlohmann::json row = j[r];
1623 unsigned int cols = std::min( (
unsigned int) row.size(), dataList->GetColumnCount() );
1625 for(
unsigned int c = 0; c < cols; ++c )
1627 wxVariant val( wxString( row[c].get<std::string>() ) );
1628 dataList->SetValue( val, r, c );
1709 wxWeakRef<DIALOG_SHIM> self(
this );
1717 && wxWindow::FindFocus() ==
nullptr )
1730 if( !GetTitle().StartsWith( wxS(
"*" ) ) )
1731 SetTitle( wxS(
"*" ) + GetTitle() );
1737 if( GetTitle().StartsWith( wxS(
"*" ) ) )
1738 SetTitle( GetTitle().AfterFirst(
'*' ) );
1752 return wxDialog::ShowModal();
1788 if( wxWindow* win = wxWindow::GetCapture() )
1789 win->ReleaseMouse();
1792 wxWindow* parent = GetParentForModalDialog( GetParent(), GetWindowStyle() );
1809 wxGUIEventLoop event_loop;
1818 return GetReturnCode();
1840 if( ( retCode == wxID_OK ) && ( !Validate() || !TransferDataFromWindow() ) )
1843 SetReturnCode( retCode );
1847 wxFAIL_MSG( wxT(
"Either DIALOG_SHIM::EndQuasiModal was called twice, or ShowQuasiModal wasn't called" ) );
1882 for( wxWindow* child : aWindow->GetChildren() )
1889 wxString msg = wxString::Format(
"Closing dialog %s", GetTitle() );
1907 const int id = aEvent.GetId();
1911 if(
id == GetAffirmativeId() )
1915 else if(
id == wxID_APPLY )
1924 else if(
id == wxID_CANCEL )
1947 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( aEvent.GetEventObject() ) )
1949 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( aEvent.GetEventObject() ) )
1959 int key = aEvt.GetKeyCode();
1962 if( aEvt.ControlDown() )
1964 if( aEvt.ShiftDown() )
1966 if( aEvt.AltDown() )
1969 int hotkey = key | mods;
1972 if( hotkey == (
MD_CTRL +
'Z') )
1983 if( aEvt.GetKeyCode() ==
'U' && aEvt.GetModifiers() == wxMOD_CONTROL )
1992 else if( ( aEvt.GetKeyCode() == WXK_RETURN || aEvt.GetKeyCode() == WXK_NUMPAD_ENTER ) && aEvt.ShiftDown() )
1994 wxObject* eventSource = aEvt.GetEventObject();
1996 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( eventSource ) )
1999 if( !textCtrl->IsMultiLine() )
2001 wxPostEvent(
this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
2005#if defined( __WXMAC__ ) || defined( __WXMSW__ )
2006 wxString eol =
"\r\n";
2008 wxString eol =
"\n";
2011 long pos = textCtrl->GetInsertionPoint();
2012 textCtrl->WriteText( eol );
2013 textCtrl->SetInsertionPoint( pos + eol.length() );
2016 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( eventSource ) )
2018 wxString eol =
"\n";
2020 switch( scintilla->GetEOLMode() )
2022 case wxSTC_EOL_CRLF: eol =
"\r\n";
break;
2023 case wxSTC_EOL_CR: eol =
"\r";
break;
2024 case wxSTC_EOL_LF: eol =
"\n";
break;
2027 long pos = scintilla->GetCurrentPos();
2028 scintilla->InsertText( pos, eol );
2029 scintilla->GotoPos( pos + eol.length() );
2035 else if( ( aEvt.GetKeyCode() == WXK_RETURN || aEvt.GetKeyCode() == WXK_NUMPAD_ENTER ) && aEvt.ControlDown() )
2037 wxPostEvent(
this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
2040 else if( aEvt.GetKeyCode() == WXK_TAB && !aEvt.ControlDown() )
2042 wxWindow* currentWindow = wxWindow::FindFocus();
2043 int currentIdx = -1;
2044 int delta = aEvt.ShiftDown() ? -1 : 1;
2051 idx = ( ( idx +
delta ) % size + size ) % size;
2054 for(
size_t i = 0; i <
m_tabOrder.size(); ++i )
2059 || ( currentWindow &&
m_tabOrder[i]->IsDescendant( currentWindow ) ) )
2061 currentIdx = (int) i;
2066 if( currentIdx >= 0 )
2068 advance( currentIdx );
2071 int startIdx = currentIdx;
2075 advance( currentIdx );
2077 if( currentIdx == startIdx )
2084 while(
dynamic_cast<wxTextEntry*
>(
m_tabOrder[ currentIdx ] ) ==
nullptr )
2085 advance( currentIdx );
2092 else if( aEvt.GetKeyCode() == WXK_ESCAPE )
2094 wxObject* eventSource = aEvt.GetEventObject();
2096 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( eventSource ) )
2102 textCtrl->SelectAll();
2106 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( eventSource ) )
2112 scintilla->SelectAll();
2124 wxStdDialogButtonSizer* sdbSizer =
dynamic_cast<wxStdDialogButtonSizer*
>( aSizer );
2127 [&]( wxButton* aButton )
2129 if( aLabels.count( aButton->GetId() ) > 0 )
2131 aButton->SetLabel( aLabels[ aButton->GetId() ] );
2137 switch( aButton->GetId() )
2139 case wxID_OK: aButton->SetLabel(
_(
"&OK" ) );
break;
2140 case wxID_CANCEL: aButton->SetLabel(
_(
"&Cancel" ) );
break;
2141 case wxID_YES: aButton->SetLabel(
_(
"&Yes" ) );
break;
2142 case wxID_NO: aButton->SetLabel(
_(
"&No" ) );
break;
2143 case wxID_APPLY: aButton->SetLabel(
_(
"&Apply" ) );
break;
2144 case wxID_SAVE: aButton->SetLabel(
_(
"&Save" ) );
break;
2145 case wxID_HELP: aButton->SetLabel(
_(
"&Help" ) );
break;
2146 case wxID_CONTEXT_HELP: aButton->SetLabel(
_(
"&Help" ) );
break;
2153 if( sdbSizer->GetAffirmativeButton() )
2154 setupButton( sdbSizer->GetAffirmativeButton() );
2156 if( sdbSizer->GetApplyButton() )
2157 setupButton( sdbSizer->GetApplyButton() );
2159 if( sdbSizer->GetNegativeButton() )
2160 setupButton( sdbSizer->GetNegativeButton() );
2162 if( sdbSizer->GetCancelButton() )
2163 setupButton( sdbSizer->GetCancelButton() );
2165 if( sdbSizer->GetHelpButton() )
2166 setupButton( sdbSizer->GetHelpButton() );
2170 if( sdbSizer->GetAffirmativeButton() )
2171 sdbSizer->GetAffirmativeButton()->SetDefault();
2174 for( wxSizerItem* item : aSizer->GetChildren() )
2176 if( item->GetSizer() )
2193 EndDialog( aReturnCode );
COMMON_SETTINGS_INTERNALS & CsInternals()
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
void SelectAllInTextCtrls(wxWindowList &children)
wxVariant getControlValue(wxWindow *aCtrl)
void onPropertyGridChanged(wxPropertyGridEvent &aEvent)
std::set< wxWindow * > m_noControlUndoRedo
std::vector< wxWindow * > m_tabOrder
void OnPaint(wxPaintEvent &event)
virtual void TearDownQuasiModal()
Override this method to perform dialog tear down actions not suitable for object dtor.
std::set< wxWindow * > m_controlsWithPendingChanges
void recordControlChange(wxWindow *aCtrl)
Tell the undo mechanism to snapshot the current value of a control and record it as an undo step when...
int vertPixelsFromDU(int y) const
Convert an integer number of dialog units to pixels, vertically.
bool Show(bool show) override
std::vector< UNDO_STEP > m_redoStack
void setControlValue(wxWindow *aCtrl, const wxVariant &aValue)
wxGUIEventLoop * m_qmodal_loop
void onChildSetFocus(wxFocusEvent &aEvent)
void LoadControlState()
Load persisted control values from the current project's local settings.
void ExcludeFromControlUndoRedo(wxWindow *aWindow)
Opt a control out of the dialog's generic Ctrl+Z/Ctrl+Y undo/redo.
void UnregisterUnitBinder(UNIT_BINDER *aUnitBinder)
Remove a UNIT_BINDER from the control-state save/restore map.
void OptOut(wxWindow *aWindow)
Opt out of control state saving.
void SaveControlState()
Save control values and geometry to the current project's local settings.
void SetupStandardButtons(std::map< int, wxString > aLabels={})
WINDOW_DISABLER * m_qmodal_parent_disabler
void clampToWorkArea()
Constrain the dialog's minimum size, size and position to the work area of the display it occupies,...
void onInitDialog(wxInitDialogEvent &aEvent)
void OnActivate(wxActivateEvent &aEvent)
void onSpinDoubleEvent(wxSpinDoubleEvent &aEvent)
void resetUndoRedoForNewContent(wxWindowList &aChildren)
Reset undo/redo tracking after dynamically replacing child panels.
int horizPixelsFromDU(int x) const
Convert an integer number of dialog units to pixels, horizontally.
void resetSize()
Clear the existing dialog size and position.
std::map< wxWindow *, wxString > m_beforeEditValues
void setSizeInDU(int x, int y)
Set the dialog to the given dimensions in "dialog units".
void onDataViewListChanged(wxDataViewEvent &aEvent)
void unregisterUnitBinders(wxWindow *aWindow)
Remove UNIT_BINDER registrations for a window and all its descendants.
bool IsQuasiModal() const
std::map< wxWindow *, UNIT_BINDER * > m_unitBinders
void ReloadSashPositions()
While we did this in LoadControlState(), we need to re-apply if after setting the dialog size.
void EndQuasiModal(int retCode)
void RegisterUnitBinder(UNIT_BINDER *aUnitBinder, wxWindow *aWindow)
Register a UNIT_BINDER so that it can handle units in control-state save/restore.
void OnMove(wxMoveEvent &aEvent)
void EndDialogShim(int aReturnCode)
A mode agnostic way to close a dialog.
void onCommandEvent(wxCommandEvent &aEvent)
void CleanupAfterModalSubDialog()
std::string generateKey(const wxWindow *aWin) const
void PrepareForModalSubDialog()
void OnButton(wxCommandEvent &aEvent)
Properly handle the default button events when in the quasimodal mode when not calling EndQuasiModal ...
void forceInitialFocus()
Focus the requested initial target if it is visible, otherwise focus the dialog itself so keyboard ev...
void onGridCellChanged(wxGridEvent &aEvent)
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
void registerUndoRedoHandlers(wxWindowList &aChildren)
wxWindow * m_initialFocusTarget
void OnSize(wxSizeEvent &aEvent)
bool Enable(bool enable) override
DIALOG_SHIM(wxWindow *aParent, wxWindowID id, const wxString &title, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER, const wxString &name=wxDialogNameStr)
void focusParentCanvas(bool aDeferUntilFrameActive=false)
Set focus back to the parent frame's tool canvas if available, otherwise to the parent window.
void SetPosition(const wxPoint &aNewPosition)
Force the position of the dialog to a new position.
void onSpinEvent(wxSpinEvent &aEvent)
void OnCloseWindow(wxCloseEvent &aEvent)
Properly handle the wxCloseEvent when in the quasimodal mode when not calling EndQuasiModal which is ...
std::map< wxWindow *, wxVariant > m_currentValues
EDA_BASE_FRAME * m_parentFrame
virtual void OnCharHook(wxKeyEvent &aEvt)
std::vector< UNDO_STEP > m_undoStack
void onStyledTextChanged(wxStyledTextEvent &aEvent)
void flushPendingControlChanges()
Apply outstanding control changes to the undo stack, and clear the pending list.
The base frame for deriving all KiCad main window classes.
KIWAY_HOLDER(KIWAY *aKiway, HOLDER_TYPE aType)
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
void SetKiway(wxWindow *aDest, KIWAY *aKiway)
It is only used for debugging, since "this" is not a wxWindow*.
bool HasKiway() const
Safety check before asking for the Kiway reference.
HOLDER_TYPE GetType() const
void SetBlockingDialog(wxWindow *aWin)
virtual COMMON_SETTINGS * GetCommonSettings() const
virtual wxApp & App()
Return a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
bool SetProperty(const std::string &aKey, T &&aValue)
Set a property with the given key and value.
static PROPERTY_HOLDER * SafeCast(void *aPtr) noexcept
Safely cast a void pointer to PROPERTY_HOLDER*.
wxTextCtrl wrapper to handle math expression evaluation.
EDA_UNITS GetUserUnits() const
virtual wxString GetFormula() const
Return the expression the user entered if it is more than a plain number, otherwise an empty string.
virtual long long int GetValue() const
Return the current value in Internal Units.
virtual void RestoreValue(int aValue, const wxString &aFormula)
Set a value (in Internal Units) as ChangeValue() does and reinstate the expression that produced it.
virtual bool RestoreFormula(const wxString &aFormula)
Show the result of an expression returned by GetFormula() and retain the expression so that it reappe...
bool UnitsInvariant() const
virtual void ChangeValue(int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion WITHOUT trigger...
Temporarily disable a window, and then re-enable on destruction.
static std::string getDialogKeyFromTitle(const wxString &aTitle)
Strip parenthetical suffixes from dialog titles to create stable persistence keys.
static void recursiveDescent(wxSizer *aSizer, std::map< int, wxString > &aLabels)
static bool isCompoundDateTimePicker(const wxWindow *aWin)
Return true when the given window is a compound date/time picker whose internal children should be op...
wxRect ClampRectToDisplay(const wxRect &aRect, const wxRect &aClientArea)
Constrain a window rectangle so it fits entirely within a display's client area.
KICOMMON_API wxRect ClampRectToDisplay(const wxRect &aRect, const wxRect &aClientArea)
Constrain a window rectangle so it fits entirely within a display's client area.
const int minSize
Push and Shove router track width and via size dialog.
void ignore_unused(const T &)
void AddNavigationBreadcrumb(const wxString &aMsg, const wxString &aCategory)
Add a navigation breadcrumb.
static wxString makeKey(const wxString &aFirst, const wxString &aSecond)
Assemble a two part key as a simple concatenation of aFirst and aSecond parts, using a separator.
PGM_BASE & Pgm()
The global program "get" accessor.
std::map< std::string, std::map< std::string, nlohmann::json > > m_dialogControlValues
static const long long MM