38#include <wx/display.h>
39#include <wx/evtloop.h>
44#include <wx/propgrid/propgrid.h>
45#include <wx/checklst.h>
46#include <wx/dataview.h>
47#include <wx/bmpbuttn.h>
48#include <wx/textctrl.h>
49#include <wx/stc/stc.h>
50#include <wx/combobox.h>
51#include <wx/odcombo.h>
53#include <wx/checkbox.h>
54#include <wx/spinctrl.h>
55#include <wx/splitter.h>
56#include <wx/radiobox.h>
57#include <wx/radiobut.h>
58#include <wx/datectrl.h>
60#include <wx/timectrl.h>
62#include <wx/variant.h>
63#include <wx/weakref.h>
67#include <nlohmann/json.hpp>
84 std::string title = aTitle.ToStdString();
85 size_t parenPos = title.rfind(
'(' );
87 if( parenPos != std::string::npos && parenPos > 0 )
89 size_t end = parenPos;
91 while(
end > 0 && title[
end - 1] ==
' ' )
94 return title.substr( 0,
end );
112#if wxUSE_DATEPICKCTRL
113 if(
dynamic_cast<const wxDatePickerCtrl*
>( aWin ) !=
nullptr )
117#if wxUSE_TIMEPICKCTRL
118 if(
dynamic_cast<const wxTimePickerCtrl*
>( aWin ) !=
nullptr )
127 const wxSize& size,
long style,
const wxString&
name ) :
128 wxDialog( aParent, id, title, pos, size, style,
name ),
151 while( !kiwayHolder && aParent->GetParent() )
153 aParent = aParent->GetParent();
167 m_parentFrame = static_cast<EDA_BASE_FRAME*>( kiwayHolder );
168 TOOL_MANAGER* toolMgr = m_parentFrame->GetToolManager();
170 if( toolMgr && toolMgr->IsContextMenuActive() )
171 toolMgr->VetoContextMenuMouseWarp();
179 Kiway().SetBlockingDialog(
this );
197 wxString msg = wxString::Format(
"Opening dialog %s", GetTitle() );
213 std::function<void( wxWindowList& )> clearOptOuts =
214 [&]( wxWindowList& children )
216 for( wxWindow* child : children )
219 child->SetClientData(
nullptr );
224 SetClientData(
nullptr );
225 clearOptOuts( GetChildren() );
227 std::function<void( wxWindowList& )> disconnectFocusHandlers =
228 [&]( wxWindowList& children )
230 for( wxWindow* child : children )
235 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( child ) )
240 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( child ) )
247 disconnectFocusHandlers( child->GetChildren() );
252 disconnectFocusHandlers( GetChildren() );
254 std::function<void( wxWindowList& )> disconnectUndoRedoHandlers =
255 [&]( wxWindowList& children )
257 for( wxWindow* child : children )
262 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( child ) )
266 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( child ) )
270 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( child ) )
275 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( child ) )
279 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( child ) )
283 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( child ) )
288 else if( wxSpinCtrlDouble* spinD =
dynamic_cast<wxSpinCtrlDouble*
>( child ) )
293 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( child ) )
297 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( child ) )
301 else if( wxGrid*
grid =
dynamic_cast<wxGrid*
>( child ) )
305 else if( wxPropertyGrid* propGrid =
dynamic_cast<wxPropertyGrid*
>( child ) )
309 else if( wxCheckListBox* checkList =
dynamic_cast<wxCheckListBox*
>( child ) )
313 else if( wxDataViewListCtrl* dataList =
dynamic_cast<wxDataViewListCtrl*
>( child ) )
319 disconnectUndoRedoHandlers( child->GetChildren() );
324 disconnectUndoRedoHandlers( GetChildren() );
329 binder->DetachFromDialogShim();
348 if( wxSizer* sz = GetSizer() )
365 GetSizer()->SetSizeHints(
this );
374 rect.width = std::min( rect.width, aClientArea.width );
375 rect.height = std::min( rect.height, aClientArea.height );
377 rect.x = std::clamp( rect.x, aClientArea.x, aClientArea.GetRight() - rect.width + 1 );
378 rect.y = std::clamp( rect.y, aClientArea.y, aClientArea.GetBottom() - rect.height + 1 );
388 int displayIdx = wxDisplay::GetFromWindow(
this );
390 if( displayIdx == wxNOT_FOUND && m_parent )
391 displayIdx = wxDisplay::GetFromWindow( m_parent );
393 if( displayIdx == wxNOT_FOUND )
396 wxRect clientArea = wxDisplay( (
unsigned int) displayIdx ).GetClientArea();
398 if( clientArea.width <= 0 || clientArea.height <= 0 )
404 wxSize clampedMin( std::min(
minSize.x, clientArea.width ),
405 std::min(
minSize.y, clientArea.height ) );
408 SetMinSize( clampedMin );
412 wxRect current( GetPosition(), GetSize() );
415 if( clamped != current )
416 SetSize( clamped.x, clamped.y, clamped.width, clamped.height, 0 );
423 SetSize( ConvertDialogToPixels( sz ) );
430 return ConvertDialogToPixels( sz ).x;
437 return ConvertDialogToPixels( sz ).y;
449 wxDialog::SetPosition( aNewPosition );
456 wxWindow* target = toolCanvas ? toolCanvas : m_parent;
463 if( !aDeferUntilFrameActive || !toolCanvas )
499 ret = wxDialog::Show( show );
501 wxRect savedDialogRect;
506 auto dlgIt = settings->CsInternals().m_dialogControlValues.find( key );
508 if( dlgIt != settings->CsInternals().m_dialogControlValues.end() )
510 auto geoIt = dlgIt->second.find(
"__geometry" );
512 if( geoIt != dlgIt->second.end() && geoIt->second.is_object() )
514 const nlohmann::json& g = geoIt->second;
515 savedDialogRect.SetPosition( wxPoint( g.value(
"x", 0 ), g.value(
"y", 0 ) ) );
516 savedDialogRect.SetSize( wxSize( g.value(
"w", 500 ), g.value(
"h", 300 ) ) );
521 if( savedDialogRect.GetSize().x != 0 && savedDialogRect.GetSize().y != 0 )
524 wxSize restoredSize = FromDIP( savedDialogRect.GetSize() );
528 SetSize( savedDialogRect.GetPosition().x, savedDialogRect.GetPosition().y,
529 wxDialog::GetSize().x, wxDialog::GetSize().y, 0 );
533 SetSize( savedDialogRect.GetPosition().x, savedDialogRect.GetPosition().y,
534 std::max( wxDialog::GetSize().x, restoredSize.x ),
535 std::max( wxDialog::GetSize().y, restoredSize.y ), 0 );
541 SetMinSize( wxDefaultSize );
542 InvalidateBestSize();
543 SetMinSize( GetBestSize() );
547 if( m_parent !=
nullptr )
549 if( wxDisplay::GetFromPoint( m_parent->GetPosition() )
550 != wxDisplay::GetFromPoint( savedDialogRect.GetPosition() ) )
566 wxPoint grabPoint = GetPosition();
567 grabPoint.x += GetSize().x / 2;
568 grabPoint.y += FromDIP( 15 );
570 if( wxDisplay::GetFromPoint( grabPoint ) == wxNOT_FOUND )
587 m_eventLoop->Exit( GetReturnCode() );
590 ret = wxDialog::Show( show );
606 auto dlgIt = settings->CsInternals().m_dialogControlValues.find( key );
608 if( dlgIt == settings->CsInternals().m_dialogControlValues.end() )
611 dlgIt->second.erase(
"__geometry" );
630 int parentDisplay = wxDisplay::GetFromWindow( m_parent );
631 int myDisplay = wxDisplay::GetFromWindow(
this );
633 if( parentDisplay != wxNOT_FOUND && myDisplay != wxNOT_FOUND )
658 return wxDialog::Enable( enable );
664 auto getSiblingIndex =
665 [](
const wxWindow* parent,
const wxWindow* child )
667 wxString childClass = child->GetClassInfo()->GetClassName();
670 for(
const wxWindow* sibling : parent->GetChildren() )
672 if( sibling->GetClassInfo()->GetClassName() != childClass )
675 if( sibling == child )
685 [&](
const wxWindow* window )
687 std::string key = wxString( window->GetClassInfo()->GetClassName() ).ToStdString();
689 if( window->GetParent() )
690 key +=
"_" + std::to_string( getSiblingIndex( window->GetParent(), window ) );
695 std::string key =
makeKey( aWin );
697 for(
const wxWindow* parent = aWin->GetParent(); parent && parent !=
this; parent = parent->GetParent() )
714 wxPoint pos = GetPosition();
715 wxSize dipSize = ToDIP( GetSize() );
719 geom[
"w" ] = dipSize.x;
720 geom[
"h" ] = dipSize.y;
721 dlgMap[
"__geometry" ] = geom;
723 std::function<void( wxWindow* )> saveFn =
728 if( !props->GetPropertyOr(
"persist",
false ) )
743 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( win ) )
745 dlgMap[ key ] = combo->GetValue();
747 else if( wxOwnerDrawnComboBox* od_combo =
dynamic_cast<wxOwnerDrawnComboBox*
>( win ) )
749 dlgMap[ key ] = od_combo->GetSelection();
751 else if( wxTextEntry* textEntry =
dynamic_cast<wxTextEntry*
>( win ) )
753 dlgMap[ key ] = textEntry->GetValue();
755 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( win ) )
757 dlgMap[ key ] = choice->GetSelection();
759 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( win ) )
761 dlgMap[ key ] = check->GetValue();
763 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( win ) )
765 dlgMap[ key ] = spin->GetValue();
767 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( win ) )
769 dlgMap[ key ] = radio->GetValue();
771 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( win ) )
773 dlgMap[ key ] = radioBox->GetSelection();
775 else if( wxSplitterWindow* splitter =
dynamic_cast<wxSplitterWindow*
>( win ) )
777 dlgMap[ key ] = splitter->GetSashPosition();
779 else if( wxScrolledWindow* scrolled =
dynamic_cast<wxScrolledWindow*
>( win ) )
781 dlgMap[ key ] = scrolled->GetScrollPos( wxVERTICAL );
783 else if( wxNotebook* notebook =
dynamic_cast<wxNotebook*
>( win ) )
785 int index = notebook->GetSelection();
787 if(
index >= 0 &&
index < (
int) notebook->GetPageCount() )
788 dlgMap[ key ] = notebook->GetPageText( notebook->GetSelection() );
790 else if( wxAuiNotebook* auiNotebook =
dynamic_cast<wxAuiNotebook*
>( win ) )
792 int index = auiNotebook->GetSelection();
794 if(
index >= 0 &&
index < (
int) auiNotebook->GetPageCount() )
795 dlgMap[ key ] = auiNotebook->GetPageText( auiNotebook->GetSelection() );
799 dlgMap[ key ] =
grid->GetShownColumnsAsString();
803 for( wxWindow* child : win->GetChildren() )
809 if( !props->GetPropertyOr(
"persist",
false ) )
813 for( wxWindow* child : GetChildren() )
831 const std::map<std::string, nlohmann::json>& dlgMap = dlgIt->second;
833 std::function<void( wxWindow* )> loadFn =
838 if( !props->GetPropertyOr(
"persist",
false ) )
849 auto it = dlgMap.find( key );
851 if( it != dlgMap.end() )
853 const nlohmann::json& j = it->second;
857 if( j.is_number_integer() )
861 else if( j.is_string() )
863 if( wxTextEntry* textEntry =
dynamic_cast<wxTextEntry*
>( win ) )
864 textEntry->ChangeValue( wxString::FromUTF8( j.get<std::string>().c_str() ) );
867 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( win ) )
870 combo->SetValue( wxString::FromUTF8( j.get<std::string>().c_str() ) );
872 else if( wxOwnerDrawnComboBox* od_combo =
dynamic_cast<wxOwnerDrawnComboBox*
>( win ) )
874 if( j.is_number_integer() )
876 int index = j.get<
int>();
878 if(
index >= 0 &&
index < (
int) od_combo->GetCount() )
879 od_combo->SetSelection(
index );
882 else if( wxTextEntry* textEntry =
dynamic_cast<wxTextEntry*
>( win ) )
885 textEntry->ChangeValue( wxString::FromUTF8( j.get<std::string>().c_str() ) );
887 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( win ) )
889 if( j.is_number_integer() )
891 int index = j.get<
int>();
893 if(
index >= 0 &&
index < (
int) choice->GetCount() )
894 choice->SetSelection(
index );
897 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( win ) )
900 check->SetValue( j.get<
bool>() );
902 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( win ) )
904 if( j.is_number_integer() )
905 spin->SetValue( j.get<
int>() );
907 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( win ) )
915 radio->SetValue(
true );
918 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( win ) )
920 if( j.is_number_integer() )
922 int index = j.get<
int>();
924 if(
index >= 0 &&
index < (
int) radioBox->GetCount() )
925 radioBox->SetSelection(
index );
928 else if( wxSplitterWindow* splitter =
dynamic_cast<wxSplitterWindow*
>( win ) )
930 if( j.is_number_integer() )
931 splitter->SetSashPosition( j.get<
int>() );
933 else if( wxScrolledWindow* scrolled =
dynamic_cast<wxScrolledWindow*
>( win ) )
935 if( j.is_number_integer() )
936 scrolled->SetScrollPos( wxVERTICAL, j.get<
int>() );
938 else if( wxNotebook* notebook =
dynamic_cast<wxNotebook*
>( win ) )
942 wxString pageTitle = wxString::FromUTF8( j.get<std::string>().c_str() );
944 for(
int page = 0; page < (int) notebook->GetPageCount(); ++page )
946 if( notebook->GetPageText( page ) == pageTitle )
947 notebook->ChangeSelection( page );
951 else if( wxAuiNotebook* auiNotebook =
dynamic_cast<wxAuiNotebook*
>( win ) )
955 wxString pageTitle = wxString::FromUTF8( j.get<std::string>().c_str() );
957 for(
int page = 0; page < (int) auiNotebook->GetPageCount(); ++page )
959 if( auiNotebook->GetPageText( page ) == pageTitle )
960 auiNotebook->ChangeSelection( page );
967 grid->ShowHideColumns( wxString::FromUTF8( j.get<std::string>().c_str() ) );
972 for( wxWindow* child : win->GetChildren() )
978 if( !props->GetPropertyOr(
"persist",
false ) )
982 for( wxWindow* child : GetChildren() )
991 aWindow->SetClientData( props );
1012 [aUnitBinder](
const auto& aEntry )
1014 return aEntry.second == aUnitBinder;
1024 for( wxWindow* child : children )
1029 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( child ) )
1038#if defined( __WXMAC__ ) || defined( __WXMSW__ )
1039 if( !textCtrl->GetStringSelection().IsEmpty() )
1043 else if( textCtrl->IsEditable() )
1045 textCtrl->SelectAll();
1051 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( child ) )
1054 scintilla->Connect( wxEVT_SET_FOCUS,
1058 if( !scintilla->GetSelectedText().IsEmpty() )
1062 else if( scintilla->GetMarginWidth( 0 ) > 0 )
1066 else if( scintilla->IsEditable() )
1068 scintilla->SelectAll();
1074 else if(
dynamic_cast<wxBitmapButton*
>( child ) !=
nullptr )
1077 wxRect rect = child->GetRect();
1079 child->ConvertDialogToPixels(
minSize );
1081 rect.Inflate( std::max( 0,
minSize.x - rect.GetWidth() ),
1082 std::max( 0,
minSize.y - rect.GetHeight() ) );
1084 child->SetMinSize( rect.GetSize() );
1085 child->SetSize( rect );
1098 for( wxWindow* child : children )
1106 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( child ) )
1111 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( child ) )
1116 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( child ) )
1122 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( child ) )
1125 m_currentValues[ choice ] =
static_cast<long>( choice->GetSelection() );
1127 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( child ) )
1132 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( child ) )
1138 else if( wxSpinCtrlDouble* spinD =
dynamic_cast<wxSpinCtrlDouble*
>( child ) )
1144 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( child ) )
1149 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( child ) )
1152 m_currentValues[ radioBox ] =
static_cast<long>( radioBox->GetSelection() );
1154 else if( wxGrid*
grid =
dynamic_cast<wxGrid*
>( child ) )
1159 else if( wxPropertyGrid* propGrid =
dynamic_cast<wxPropertyGrid*
>( child ) )
1164 else if( wxCheckListBox* checkList =
dynamic_cast<wxCheckListBox*
>( child ) )
1169 else if( wxDataViewListCtrl* dataList =
dynamic_cast<wxDataViewListCtrl*
>( child ) )
1209 if( before != after )
1288 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( aCtrl ) )
1289 return wxVariant( textCtrl->GetValue() );
1290 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( aCtrl ) )
1291 return wxVariant( scintilla->GetText() );
1292 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( aCtrl ) )
1293 return wxVariant( combo->GetValue() );
1294 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( aCtrl ) )
1295 return wxVariant( (
long) choice->GetSelection() );
1296 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( aCtrl ) )
1297 return wxVariant( check->GetValue() );
1298 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( aCtrl ) )
1299 return wxVariant( (
long) spin->GetValue() );
1300 else if( wxSpinCtrlDouble* spinD =
dynamic_cast<wxSpinCtrlDouble*
>( aCtrl ) )
1301 return wxVariant( spinD->GetValue() );
1302 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( aCtrl ) )
1303 return wxVariant( radio->GetValue() );
1304 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( aCtrl ) )
1305 return wxVariant( (
long) radioBox->GetSelection() );
1306 else if( wxGrid*
grid =
dynamic_cast<wxGrid*
>( aCtrl ) )
1310 table &&
table->HasUndoStateSerialization() )
1312 return wxVariant(
table->SerializeUndoState() );
1315 nlohmann::json j = nlohmann::json::array();
1316 int rows =
grid->GetNumberRows();
1317 int cols =
grid->GetNumberCols();
1319 for(
int r = 0; r < rows; ++r )
1321 nlohmann::json row = nlohmann::json::array();
1323 for(
int c = 0; c < cols; ++c )
1324 row.push_back( std::string(
grid->GetCellValue( r, c ).ToUTF8() ) );
1329 return wxVariant( wxString( j.dump() ) );
1331 else if( wxPropertyGrid* propGrid =
dynamic_cast<wxPropertyGrid*
>( aCtrl ) )
1335 for( wxPropertyGridIterator it = propGrid->GetIterator(); !it.AtEnd(); ++it )
1337 wxPGProperty* prop = *it;
1338 j[ prop->GetName().ToStdString() ] = prop->GetValueAsString().ToStdString();
1341 return wxVariant( wxString( j.dump() ) );
1343 else if( wxCheckListBox* checkList =
dynamic_cast<wxCheckListBox*
>( aCtrl ) )
1345 nlohmann::json j = nlohmann::json::array();
1346 unsigned int count = checkList->GetCount();
1348 for(
unsigned int i = 0; i < count; ++i )
1350 if( checkList->IsChecked( i ) )
1354 return wxVariant( wxString( j.dump() ) );
1356 else if( wxDataViewListCtrl* dataList =
dynamic_cast<wxDataViewListCtrl*
>( aCtrl ) )
1358 nlohmann::json j = nlohmann::json::array();
1359 unsigned int rows = dataList->GetItemCount();
1360 unsigned int cols = dataList->GetColumnCount();
1362 for(
unsigned int r = 0; r < rows; ++r )
1364 nlohmann::json row = nlohmann::json::array();
1366 for(
unsigned int c = 0; c < cols; ++c )
1369 dataList->GetValue( val, r, c );
1370 row.push_back( std::string( val.GetString().ToUTF8() ) );
1376 return wxVariant( wxString( j.dump() ) );
1385 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( aCtrl ) )
1386 textCtrl->SetValue( aValue.GetString() );
1387 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( aCtrl ) )
1388 scintilla->SetText( aValue.GetString() );
1389 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( aCtrl ) )
1390 combo->SetValue( aValue.GetString() );
1391 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( aCtrl ) )
1392 choice->SetSelection( (
int) aValue.GetLong() );
1393 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( aCtrl ) )
1394 check->SetValue( aValue.GetBool() );
1395 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( aCtrl ) )
1396 spin->SetValue( (
int) aValue.GetLong() );
1397 else if( wxSpinCtrlDouble* spinD =
dynamic_cast<wxSpinCtrlDouble*
>( aCtrl ) )
1398 spinD->SetValue( aValue.GetDouble() );
1399 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( aCtrl ) )
1400 radio->SetValue( aValue.GetBool() );
1401 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( aCtrl ) )
1402 radioBox->SetSelection( (
int) aValue.GetLong() );
1403 else if( wxGrid*
grid =
dynamic_cast<wxGrid*
>( aCtrl ) )
1406 table &&
table->HasUndoStateSerialization() )
1408 table->RestoreUndoState( aValue.GetString() );
1412 nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(),
nullptr,
false );
1416 int rows = std::min( (
int) j.size(),
grid->GetNumberRows() );
1418 std::vector<std::pair<int, int>> changedCells;
1420 for(
int r = 0; r < rows; ++r )
1422 nlohmann::json row = j[r];
1423 int cols = std::min( (
int) row.size(),
grid->GetNumberCols() );
1425 for(
int c = 0; c < cols; ++c )
1427 wxString value = wxString( row[c].get<std::string>() );
1429 if(
grid->GetCellValue( r, c ) != value )
1431 grid->SetCellValue( r, c, value );
1432 changedCells.emplace_back( r, c );
1437 for(
const auto& [row, col] : changedCells )
1439 wxGridEvent evt(
grid->GetId(), wxEVT_GRID_CELL_CHANGED,
grid, row, col );
1440 evt.SetString(
grid->GetCellValue( row, col ) );
1441 grid->GetEventHandler()->ProcessEvent( evt );
1445 else if( wxPropertyGrid* propGrid =
dynamic_cast<wxPropertyGrid*
>( aCtrl ) )
1447 nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(),
nullptr,
false );
1451 for(
auto it = j.begin(); it != j.end(); ++it )
1452 propGrid->SetPropertyValue( wxString( it.key() ), wxString( it.value().get<std::string>() ) );
1455 else if( wxCheckListBox* checkList =
dynamic_cast<wxCheckListBox*
>( aCtrl ) )
1457 nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(),
nullptr,
false );
1461 unsigned int count = checkList->GetCount();
1463 for(
unsigned int i = 0; i < count; ++i )
1464 checkList->Check( i,
false );
1466 for(
auto& idx : j )
1468 unsigned int i = idx.get<
unsigned int>();
1471 checkList->Check( i,
true );
1475 else if( wxDataViewListCtrl* dataList =
dynamic_cast<wxDataViewListCtrl*
>( aCtrl ) )
1477 nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(),
nullptr,
false );
1481 unsigned int rows = std::min(
static_cast<unsigned int>( j.size() ),
1482 static_cast<unsigned int>( dataList->GetItemCount() ) );
1484 for(
unsigned int r = 0; r < rows; ++r )
1486 nlohmann::json row = j[r];
1487 unsigned int cols = std::min( (
unsigned int) row.size(), dataList->GetColumnCount() );
1489 for(
unsigned int c = 0; c < cols; ++c )
1491 wxVariant val( wxString( row[c].get<std::string>() ) );
1492 dataList->SetValue( val, r, c );
1573 wxWeakRef<DIALOG_SHIM> self(
this );
1581 && wxWindow::FindFocus() ==
nullptr )
1594 if( !GetTitle().StartsWith( wxS(
"*" ) ) )
1595 SetTitle( wxS(
"*" ) + GetTitle() );
1601 if( GetTitle().StartsWith( wxS(
"*" ) ) )
1602 SetTitle( GetTitle().AfterFirst(
'*' ) );
1616 return wxDialog::ShowModal();
1652 if( wxWindow* win = wxWindow::GetCapture() )
1653 win->ReleaseMouse();
1656 wxWindow* parent = GetParentForModalDialog( GetParent(), GetWindowStyle() );
1673 wxGUIEventLoop event_loop;
1682 return GetReturnCode();
1704 if( ( retCode == wxID_OK ) && ( !Validate() || !TransferDataFromWindow() ) )
1707 SetReturnCode( retCode );
1711 wxFAIL_MSG( wxT(
"Either DIALOG_SHIM::EndQuasiModal was called twice, or ShowQuasiModal wasn't called" ) );
1746 for( wxWindow* child : aWindow->GetChildren() )
1753 wxString msg = wxString::Format(
"Closing dialog %s", GetTitle() );
1771 const int id = aEvent.GetId();
1775 if(
id == GetAffirmativeId() )
1779 else if(
id == wxID_APPLY )
1788 else if(
id == wxID_CANCEL )
1811 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( aEvent.GetEventObject() ) )
1813 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( aEvent.GetEventObject() ) )
1823 int key = aEvt.GetKeyCode();
1826 if( aEvt.ControlDown() )
1828 if( aEvt.ShiftDown() )
1830 if( aEvt.AltDown() )
1833 int hotkey = key | mods;
1836 if( hotkey == (
MD_CTRL +
'Z') )
1847 if( aEvt.GetKeyCode() ==
'U' && aEvt.GetModifiers() == wxMOD_CONTROL )
1856 else if( ( aEvt.GetKeyCode() == WXK_RETURN || aEvt.GetKeyCode() == WXK_NUMPAD_ENTER ) && aEvt.ShiftDown() )
1858 wxObject* eventSource = aEvt.GetEventObject();
1860 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( eventSource ) )
1863 if( !textCtrl->IsMultiLine() )
1865 wxPostEvent(
this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
1869#if defined( __WXMAC__ ) || defined( __WXMSW__ )
1870 wxString eol =
"\r\n";
1872 wxString eol =
"\n";
1875 long pos = textCtrl->GetInsertionPoint();
1876 textCtrl->WriteText( eol );
1877 textCtrl->SetInsertionPoint( pos + eol.length() );
1880 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( eventSource ) )
1882 wxString eol =
"\n";
1884 switch( scintilla->GetEOLMode() )
1886 case wxSTC_EOL_CRLF: eol =
"\r\n";
break;
1887 case wxSTC_EOL_CR: eol =
"\r";
break;
1888 case wxSTC_EOL_LF: eol =
"\n";
break;
1891 long pos = scintilla->GetCurrentPos();
1892 scintilla->InsertText( pos, eol );
1893 scintilla->GotoPos( pos + eol.length() );
1899 else if( ( aEvt.GetKeyCode() == WXK_RETURN || aEvt.GetKeyCode() == WXK_NUMPAD_ENTER ) && aEvt.ControlDown() )
1901 wxPostEvent(
this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
1904 else if( aEvt.GetKeyCode() == WXK_TAB && !aEvt.ControlDown() )
1906 wxWindow* currentWindow = wxWindow::FindFocus();
1907 int currentIdx = -1;
1908 int delta = aEvt.ShiftDown() ? -1 : 1;
1915 idx = ( ( idx +
delta ) % size + size ) % size;
1918 for(
size_t i = 0; i <
m_tabOrder.size(); ++i )
1923 || ( currentWindow &&
m_tabOrder[i]->IsDescendant( currentWindow ) ) )
1925 currentIdx = (int) i;
1930 if( currentIdx >= 0 )
1932 advance( currentIdx );
1935 int startIdx = currentIdx;
1939 advance( currentIdx );
1941 if( currentIdx == startIdx )
1948 while(
dynamic_cast<wxTextEntry*
>(
m_tabOrder[ currentIdx ] ) ==
nullptr )
1949 advance( currentIdx );
1956 else if( aEvt.GetKeyCode() == WXK_ESCAPE )
1958 wxObject* eventSource = aEvt.GetEventObject();
1960 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( eventSource ) )
1966 textCtrl->SelectAll();
1970 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( eventSource ) )
1976 scintilla->SelectAll();
1988 wxStdDialogButtonSizer* sdbSizer =
dynamic_cast<wxStdDialogButtonSizer*
>( aSizer );
1991 [&]( wxButton* aButton )
1993 if( aLabels.count( aButton->GetId() ) > 0 )
1995 aButton->SetLabel( aLabels[ aButton->GetId() ] );
2001 switch( aButton->GetId() )
2003 case wxID_OK: aButton->SetLabel(
_(
"&OK" ) );
break;
2004 case wxID_CANCEL: aButton->SetLabel(
_(
"&Cancel" ) );
break;
2005 case wxID_YES: aButton->SetLabel(
_(
"&Yes" ) );
break;
2006 case wxID_NO: aButton->SetLabel(
_(
"&No" ) );
break;
2007 case wxID_APPLY: aButton->SetLabel(
_(
"&Apply" ) );
break;
2008 case wxID_SAVE: aButton->SetLabel(
_(
"&Save" ) );
break;
2009 case wxID_HELP: aButton->SetLabel(
_(
"&Help" ) );
break;
2010 case wxID_CONTEXT_HELP: aButton->SetLabel(
_(
"&Help" ) );
break;
2017 if( sdbSizer->GetAffirmativeButton() )
2018 setupButton( sdbSizer->GetAffirmativeButton() );
2020 if( sdbSizer->GetApplyButton() )
2021 setupButton( sdbSizer->GetApplyButton() );
2023 if( sdbSizer->GetNegativeButton() )
2024 setupButton( sdbSizer->GetNegativeButton() );
2026 if( sdbSizer->GetCancelButton() )
2027 setupButton( sdbSizer->GetCancelButton() );
2029 if( sdbSizer->GetHelpButton() )
2030 setupButton( sdbSizer->GetHelpButton() );
2034 if( sdbSizer->GetAffirmativeButton() )
2035 sdbSizer->GetAffirmativeButton()->SetDefault();
2038 for( wxSizerItem* item : aSizer->GetChildren() )
2040 if( item->GetSizer() )
2057 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 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*.
EDA_UNITS GetUserUnits() const
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