37#include <wx/display.h>
38#include <wx/evtloop.h>
43#include <wx/propgrid/propgrid.h>
44#include <wx/checklst.h>
45#include <wx/dataview.h>
46#include <wx/bmpbuttn.h>
47#include <wx/textctrl.h>
48#include <wx/stc/stc.h>
49#include <wx/combobox.h>
50#include <wx/odcombo.h>
52#include <wx/checkbox.h>
53#include <wx/spinctrl.h>
54#include <wx/splitter.h>
55#include <wx/radiobox.h>
56#include <wx/radiobut.h>
57#include <wx/datectrl.h>
59#include <wx/timectrl.h>
61#include <wx/variant.h>
65#include <nlohmann/json.hpp>
81 std::string title = aTitle.ToStdString();
82 size_t parenPos = title.rfind(
'(' );
84 if( parenPos != std::string::npos && parenPos > 0 )
86 size_t end = parenPos;
88 while(
end > 0 && title[
end - 1] ==
' ' )
91 return title.substr( 0,
end );
109#if wxUSE_DATEPICKCTRL
110 if(
dynamic_cast<const wxDatePickerCtrl*
>( aWin ) !=
nullptr )
114#if wxUSE_TIMEPICKCTRL
115 if(
dynamic_cast<const wxTimePickerCtrl*
>( aWin ) !=
nullptr )
124 const wxSize& size,
long style,
const wxString&
name ) :
125 wxDialog( aParent, id, title, pos, size, style,
name ),
148 while( !kiwayHolder && aParent->GetParent() )
150 aParent = aParent->GetParent();
164 m_parentFrame = static_cast<EDA_BASE_FRAME*>( kiwayHolder );
165 TOOL_MANAGER* toolMgr = m_parentFrame->GetToolManager();
167 if( toolMgr && toolMgr->IsContextMenuActive() )
168 toolMgr->VetoContextMenuMouseWarp();
176 Kiway().SetBlockingDialog(
this );
194 wxString msg = wxString::Format(
"Opening dialog %s", GetTitle() );
210 std::function<void( wxWindowList& )> disconnectFocusHandlers =
211 [&]( wxWindowList& children )
213 for( wxWindow* child : children )
218 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( child ) )
223 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( child ) )
230 disconnectFocusHandlers( child->GetChildren() );
235 disconnectFocusHandlers( GetChildren() );
237 std::function<void( wxWindowList& )> disconnectUndoRedoHandlers =
238 [&]( wxWindowList& children )
240 for( wxWindow* child : children )
245 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( child ) )
249 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( child ) )
253 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( child ) )
258 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( child ) )
262 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( child ) )
266 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( child ) )
271 else if( wxSpinCtrlDouble* spinD =
dynamic_cast<wxSpinCtrlDouble*
>( child ) )
276 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( child ) )
280 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( child ) )
284 else if( wxGrid*
grid =
dynamic_cast<wxGrid*
>( child ) )
288 else if( wxPropertyGrid* propGrid =
dynamic_cast<wxPropertyGrid*
>( child ) )
292 else if( wxCheckListBox* checkList =
dynamic_cast<wxCheckListBox*
>( child ) )
296 else if( wxDataViewListCtrl* dataList =
dynamic_cast<wxDataViewListCtrl*
>( child ) )
302 disconnectUndoRedoHandlers( child->GetChildren() );
307 disconnectUndoRedoHandlers( GetChildren() );
312 binder->DetachFromDialogShim();
331 if( wxSizer* sz = GetSizer() )
348 GetSizer()->SetSizeHints(
this );
357 rect.width = std::min( rect.width, aClientArea.width );
358 rect.height = std::min( rect.height, aClientArea.height );
360 rect.x = std::clamp( rect.x, aClientArea.x, aClientArea.GetRight() - rect.width + 1 );
361 rect.y = std::clamp( rect.y, aClientArea.y, aClientArea.GetBottom() - rect.height + 1 );
371 int displayIdx = wxDisplay::GetFromWindow(
this );
373 if( displayIdx == wxNOT_FOUND && m_parent )
374 displayIdx = wxDisplay::GetFromWindow( m_parent );
376 if( displayIdx == wxNOT_FOUND )
379 wxRect clientArea = wxDisplay( (
unsigned int) displayIdx ).GetClientArea();
381 if( clientArea.width <= 0 || clientArea.height <= 0 )
387 wxSize clampedMin( std::min(
minSize.x, clientArea.width ),
388 std::min(
minSize.y, clientArea.height ) );
391 SetMinSize( clampedMin );
395 wxRect current( GetPosition(), GetSize() );
398 if( clamped != current )
399 SetSize( clamped.x, clamped.y, clamped.width, clamped.height, 0 );
406 SetSize( ConvertDialogToPixels( sz ) );
413 return ConvertDialogToPixels( sz ).x;
420 return ConvertDialogToPixels( sz ).y;
432 wxDialog::SetPosition( aNewPosition );
439 wxWindow* target = toolCanvas ? toolCanvas : m_parent;
446 if( !aDeferUntilFrameActive || !toolCanvas )
482 ret = wxDialog::Show( show );
484 wxRect savedDialogRect;
489 auto dlgIt = settings->CsInternals().m_dialogControlValues.find( key );
491 if( dlgIt != settings->CsInternals().m_dialogControlValues.end() )
493 auto geoIt = dlgIt->second.find(
"__geometry" );
495 if( geoIt != dlgIt->second.end() && geoIt->second.is_object() )
497 const nlohmann::json& g = geoIt->second;
498 savedDialogRect.SetPosition( wxPoint( g.value(
"x", 0 ), g.value(
"y", 0 ) ) );
499 savedDialogRect.SetSize( wxSize( g.value(
"w", 500 ), g.value(
"h", 300 ) ) );
504 if( savedDialogRect.GetSize().x != 0 && savedDialogRect.GetSize().y != 0 )
507 wxSize restoredSize = FromDIP( savedDialogRect.GetSize() );
511 SetSize( savedDialogRect.GetPosition().x, savedDialogRect.GetPosition().y,
512 wxDialog::GetSize().x, wxDialog::GetSize().y, 0 );
516 SetSize( savedDialogRect.GetPosition().x, savedDialogRect.GetPosition().y,
517 std::max( wxDialog::GetSize().x, restoredSize.x ),
518 std::max( wxDialog::GetSize().y, restoredSize.y ), 0 );
524 SetMinSize( wxDefaultSize );
525 InvalidateBestSize();
526 SetMinSize( GetBestSize() );
530 if( m_parent !=
nullptr )
532 if( wxDisplay::GetFromPoint( m_parent->GetPosition() )
533 != wxDisplay::GetFromPoint( savedDialogRect.GetPosition() ) )
549 wxPoint grabPoint = GetPosition();
550 grabPoint.x += GetSize().x / 2;
551 grabPoint.y += FromDIP( 15 );
553 if( wxDisplay::GetFromPoint( grabPoint ) == wxNOT_FOUND )
570 m_eventLoop->Exit( GetReturnCode() );
573 ret = wxDialog::Show( show );
589 auto dlgIt = settings->CsInternals().m_dialogControlValues.find( key );
591 if( dlgIt == settings->CsInternals().m_dialogControlValues.end() )
594 dlgIt->second.erase(
"__geometry" );
613 int parentDisplay = wxDisplay::GetFromWindow( m_parent );
614 int myDisplay = wxDisplay::GetFromWindow(
this );
616 if( parentDisplay != wxNOT_FOUND && myDisplay != wxNOT_FOUND )
641 return wxDialog::Enable( enable );
647 auto getSiblingIndex =
648 [](
const wxWindow* parent,
const wxWindow* child )
650 wxString childClass = child->GetClassInfo()->GetClassName();
653 for(
const wxWindow* sibling : parent->GetChildren() )
655 if( sibling->GetClassInfo()->GetClassName() != childClass )
658 if( sibling == child )
668 [&](
const wxWindow* window )
670 std::string key = wxString( window->GetClassInfo()->GetClassName() ).ToStdString();
672 if( window->GetParent() )
673 key +=
"_" + std::to_string( getSiblingIndex( window->GetParent(), window ) );
678 std::string key =
makeKey( aWin );
680 for(
const wxWindow* parent = aWin->GetParent(); parent && parent !=
this; parent = parent->GetParent() )
697 wxPoint pos = GetPosition();
698 wxSize dipSize = ToDIP( GetSize() );
702 geom[
"w" ] = dipSize.x;
703 geom[
"h" ] = dipSize.y;
704 dlgMap[
"__geometry" ] = geom;
706 std::function<void( wxWindow* )> saveFn =
711 if( !props->GetPropertyOr(
"persist",
false ) )
726 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( win ) )
728 dlgMap[ key ] = combo->GetValue();
730 else if( wxOwnerDrawnComboBox* od_combo =
dynamic_cast<wxOwnerDrawnComboBox*
>( win ) )
732 dlgMap[ key ] = od_combo->GetSelection();
734 else if( wxTextEntry* textEntry =
dynamic_cast<wxTextEntry*
>( win ) )
736 dlgMap[ key ] = textEntry->GetValue();
738 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( win ) )
740 dlgMap[ key ] = choice->GetSelection();
742 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( win ) )
744 dlgMap[ key ] = check->GetValue();
746 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( win ) )
748 dlgMap[ key ] = spin->GetValue();
750 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( win ) )
752 dlgMap[ key ] = radio->GetValue();
754 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( win ) )
756 dlgMap[ key ] = radioBox->GetSelection();
758 else if( wxSplitterWindow* splitter =
dynamic_cast<wxSplitterWindow*
>( win ) )
760 dlgMap[ key ] = splitter->GetSashPosition();
762 else if( wxScrolledWindow* scrolled =
dynamic_cast<wxScrolledWindow*
>( win ) )
764 dlgMap[ key ] = scrolled->GetScrollPos( wxVERTICAL );
766 else if( wxNotebook* notebook =
dynamic_cast<wxNotebook*
>( win ) )
768 int index = notebook->GetSelection();
770 if(
index >= 0 &&
index < (
int) notebook->GetPageCount() )
771 dlgMap[ key ] = notebook->GetPageText( notebook->GetSelection() );
773 else if( wxAuiNotebook* auiNotebook =
dynamic_cast<wxAuiNotebook*
>( win ) )
775 int index = auiNotebook->GetSelection();
777 if(
index >= 0 &&
index < (
int) auiNotebook->GetPageCount() )
778 dlgMap[ key ] = auiNotebook->GetPageText( auiNotebook->GetSelection() );
782 dlgMap[ key ] =
grid->GetShownColumnsAsString();
786 for( wxWindow* child : win->GetChildren() )
792 if( !props->GetPropertyOr(
"persist",
false ) )
796 for( wxWindow* child : GetChildren() )
814 const std::map<std::string, nlohmann::json>& dlgMap = dlgIt->second;
816 std::function<void( wxWindow* )> loadFn =
821 if( !props->GetPropertyOr(
"persist",
false ) )
832 auto it = dlgMap.find( key );
834 if( it != dlgMap.end() )
836 const nlohmann::json& j = it->second;
840 if( j.is_number_integer() )
844 else if( j.is_string() )
846 if( wxTextEntry* textEntry =
dynamic_cast<wxTextEntry*
>( win ) )
847 textEntry->ChangeValue( wxString::FromUTF8( j.get<std::string>().c_str() ) );
850 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( win ) )
853 combo->SetValue( wxString::FromUTF8( j.get<std::string>().c_str() ) );
855 else if( wxOwnerDrawnComboBox* od_combo =
dynamic_cast<wxOwnerDrawnComboBox*
>( win ) )
857 if( j.is_number_integer() )
859 int index = j.get<
int>();
861 if(
index >= 0 &&
index < (
int) od_combo->GetCount() )
862 od_combo->SetSelection(
index );
865 else if( wxTextEntry* textEntry =
dynamic_cast<wxTextEntry*
>( win ) )
868 textEntry->ChangeValue( wxString::FromUTF8( j.get<std::string>().c_str() ) );
870 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( win ) )
872 if( j.is_number_integer() )
874 int index = j.get<
int>();
876 if(
index >= 0 &&
index < (
int) choice->GetCount() )
877 choice->SetSelection(
index );
880 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( win ) )
883 check->SetValue( j.get<
bool>() );
885 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( win ) )
887 if( j.is_number_integer() )
888 spin->SetValue( j.get<
int>() );
890 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( win ) )
898 radio->SetValue(
true );
901 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( win ) )
903 if( j.is_number_integer() )
905 int index = j.get<
int>();
907 if(
index >= 0 &&
index < (
int) radioBox->GetCount() )
908 radioBox->SetSelection(
index );
911 else if( wxSplitterWindow* splitter =
dynamic_cast<wxSplitterWindow*
>( win ) )
913 if( j.is_number_integer() )
914 splitter->SetSashPosition( j.get<
int>() );
916 else if( wxScrolledWindow* scrolled =
dynamic_cast<wxScrolledWindow*
>( win ) )
918 if( j.is_number_integer() )
919 scrolled->SetScrollPos( wxVERTICAL, j.get<
int>() );
921 else if( wxNotebook* notebook =
dynamic_cast<wxNotebook*
>( win ) )
925 wxString pageTitle = wxString::FromUTF8( j.get<std::string>().c_str() );
927 for(
int page = 0; page < (int) notebook->GetPageCount(); ++page )
929 if( notebook->GetPageText( page ) == pageTitle )
930 notebook->ChangeSelection( page );
934 else if( wxAuiNotebook* auiNotebook =
dynamic_cast<wxAuiNotebook*
>( win ) )
938 wxString pageTitle = wxString::FromUTF8( j.get<std::string>().c_str() );
940 for(
int page = 0; page < (int) auiNotebook->GetPageCount(); ++page )
942 if( auiNotebook->GetPageText( page ) == pageTitle )
943 auiNotebook->ChangeSelection( page );
950 grid->ShowHideColumns( wxString::FromUTF8( j.get<std::string>().c_str() ) );
955 for( wxWindow* child : win->GetChildren() )
961 if( !props->GetPropertyOr(
"persist",
false ) )
965 for( wxWindow* child : GetChildren() )
974 aWindow->SetClientData( props );
995 [aUnitBinder](
const auto& aEntry )
997 return aEntry.second == aUnitBinder;
1007 for( wxWindow* child : children )
1012 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( child ) )
1021#if defined( __WXMAC__ ) || defined( __WXMSW__ )
1022 if( !textCtrl->GetStringSelection().IsEmpty() )
1026 else if( textCtrl->IsEditable() )
1028 textCtrl->SelectAll();
1034 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( child ) )
1037 scintilla->Connect( wxEVT_SET_FOCUS,
1041 if( !scintilla->GetSelectedText().IsEmpty() )
1045 else if( scintilla->GetMarginWidth( 0 ) > 0 )
1049 else if( scintilla->IsEditable() )
1051 scintilla->SelectAll();
1057 else if(
dynamic_cast<wxBitmapButton*
>( child ) !=
nullptr )
1060 wxRect rect = child->GetRect();
1062 child->ConvertDialogToPixels(
minSize );
1064 rect.Inflate( std::max( 0,
minSize.x - rect.GetWidth() ),
1065 std::max( 0,
minSize.y - rect.GetHeight() ) );
1067 child->SetMinSize( rect.GetSize() );
1068 child->SetSize( rect );
1081 for( wxWindow* child : children )
1089 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( child ) )
1094 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( child ) )
1099 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( child ) )
1105 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( child ) )
1108 m_currentValues[ choice ] =
static_cast<long>( choice->GetSelection() );
1110 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( child ) )
1115 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( child ) )
1121 else if( wxSpinCtrlDouble* spinD =
dynamic_cast<wxSpinCtrlDouble*
>( child ) )
1127 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( child ) )
1132 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( child ) )
1135 m_currentValues[ radioBox ] =
static_cast<long>( radioBox->GetSelection() );
1137 else if( wxGrid*
grid =
dynamic_cast<wxGrid*
>( child ) )
1142 else if( wxPropertyGrid* propGrid =
dynamic_cast<wxPropertyGrid*
>( child ) )
1147 else if( wxCheckListBox* checkList =
dynamic_cast<wxCheckListBox*
>( child ) )
1152 else if( wxDataViewListCtrl* dataList =
dynamic_cast<wxDataViewListCtrl*
>( child ) )
1170 if( before != after )
1172 m_undoStack.push_back( { aCtrl, before, after } );
1241 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( aCtrl ) )
1242 return wxVariant( textCtrl->GetValue() );
1243 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( aCtrl ) )
1244 return wxVariant( scintilla->GetText() );
1245 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( aCtrl ) )
1246 return wxVariant( combo->GetValue() );
1247 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( aCtrl ) )
1248 return wxVariant( (
long) choice->GetSelection() );
1249 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( aCtrl ) )
1250 return wxVariant( check->GetValue() );
1251 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( aCtrl ) )
1252 return wxVariant( (
long) spin->GetValue() );
1253 else if( wxSpinCtrlDouble* spinD =
dynamic_cast<wxSpinCtrlDouble*
>( aCtrl ) )
1254 return wxVariant( spinD->GetValue() );
1255 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( aCtrl ) )
1256 return wxVariant( radio->GetValue() );
1257 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( aCtrl ) )
1258 return wxVariant( (
long) radioBox->GetSelection() );
1259 else if( wxGrid*
grid =
dynamic_cast<wxGrid*
>( aCtrl ) )
1263 table &&
table->HasUndoStateSerialization() )
1265 return wxVariant(
table->SerializeUndoState() );
1268 nlohmann::json j = nlohmann::json::array();
1269 int rows =
grid->GetNumberRows();
1270 int cols =
grid->GetNumberCols();
1272 for(
int r = 0; r < rows; ++r )
1274 nlohmann::json row = nlohmann::json::array();
1276 for(
int c = 0; c < cols; ++c )
1277 row.push_back( std::string(
grid->GetCellValue( r, c ).ToUTF8() ) );
1282 return wxVariant( wxString( j.dump() ) );
1284 else if( wxPropertyGrid* propGrid =
dynamic_cast<wxPropertyGrid*
>( aCtrl ) )
1288 for( wxPropertyGridIterator it = propGrid->GetIterator(); !it.AtEnd(); ++it )
1290 wxPGProperty* prop = *it;
1291 j[ prop->GetName().ToStdString() ] = prop->GetValueAsString().ToStdString();
1294 return wxVariant( wxString( j.dump() ) );
1296 else if( wxCheckListBox* checkList =
dynamic_cast<wxCheckListBox*
>( aCtrl ) )
1298 nlohmann::json j = nlohmann::json::array();
1299 unsigned int count = checkList->GetCount();
1301 for(
unsigned int i = 0; i < count; ++i )
1303 if( checkList->IsChecked( i ) )
1307 return wxVariant( wxString( j.dump() ) );
1309 else if( wxDataViewListCtrl* dataList =
dynamic_cast<wxDataViewListCtrl*
>( aCtrl ) )
1311 nlohmann::json j = nlohmann::json::array();
1312 unsigned int rows = dataList->GetItemCount();
1313 unsigned int cols = dataList->GetColumnCount();
1315 for(
unsigned int r = 0; r < rows; ++r )
1317 nlohmann::json row = nlohmann::json::array();
1319 for(
unsigned int c = 0; c < cols; ++c )
1322 dataList->GetValue( val, r, c );
1323 row.push_back( std::string( val.GetString().ToUTF8() ) );
1329 return wxVariant( wxString( j.dump() ) );
1338 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( aCtrl ) )
1339 textCtrl->SetValue( aValue.GetString() );
1340 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( aCtrl ) )
1341 scintilla->SetText( aValue.GetString() );
1342 else if( wxComboBox* combo =
dynamic_cast<wxComboBox*
>( aCtrl ) )
1343 combo->SetValue( aValue.GetString() );
1344 else if( wxChoice* choice =
dynamic_cast<wxChoice*
>( aCtrl ) )
1345 choice->SetSelection( (
int) aValue.GetLong() );
1346 else if( wxCheckBox* check =
dynamic_cast<wxCheckBox*
>( aCtrl ) )
1347 check->SetValue( aValue.GetBool() );
1348 else if( wxSpinCtrl* spin =
dynamic_cast<wxSpinCtrl*
>( aCtrl ) )
1349 spin->SetValue( (
int) aValue.GetLong() );
1350 else if( wxSpinCtrlDouble* spinD =
dynamic_cast<wxSpinCtrlDouble*
>( aCtrl ) )
1351 spinD->SetValue( aValue.GetDouble() );
1352 else if( wxRadioButton* radio =
dynamic_cast<wxRadioButton*
>( aCtrl ) )
1353 radio->SetValue( aValue.GetBool() );
1354 else if( wxRadioBox* radioBox =
dynamic_cast<wxRadioBox*
>( aCtrl ) )
1355 radioBox->SetSelection( (
int) aValue.GetLong() );
1356 else if( wxGrid*
grid =
dynamic_cast<wxGrid*
>( aCtrl ) )
1359 table &&
table->HasUndoStateSerialization() )
1361 table->RestoreUndoState( aValue.GetString() );
1365 nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(),
nullptr,
false );
1369 int rows = std::min( (
int) j.size(),
grid->GetNumberRows() );
1371 for(
int r = 0; r < rows; ++r )
1373 nlohmann::json row = j[r];
1374 int cols = std::min( (
int) row.size(),
grid->GetNumberCols() );
1376 for(
int c = 0; c < cols; ++c )
1377 grid->SetCellValue( r, c, wxString( row[c].get<std::string>() ) );
1381 else if( wxPropertyGrid* propGrid =
dynamic_cast<wxPropertyGrid*
>( aCtrl ) )
1383 nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(),
nullptr,
false );
1387 for(
auto it = j.begin(); it != j.end(); ++it )
1388 propGrid->SetPropertyValue( wxString( it.key() ), wxString( it.value().get<std::string>() ) );
1391 else if( wxCheckListBox* checkList =
dynamic_cast<wxCheckListBox*
>( aCtrl ) )
1393 nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(),
nullptr,
false );
1397 unsigned int count = checkList->GetCount();
1399 for(
unsigned int i = 0; i < count; ++i )
1400 checkList->Check( i,
false );
1402 for(
auto& idx : j )
1404 unsigned int i = idx.get<
unsigned int>();
1407 checkList->Check( i,
true );
1411 else if( wxDataViewListCtrl* dataList =
dynamic_cast<wxDataViewListCtrl*
>( aCtrl ) )
1413 nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(),
nullptr,
false );
1417 unsigned int rows = std::min(
static_cast<unsigned int>( j.size() ),
1418 static_cast<unsigned int>( dataList->GetItemCount() ) );
1420 for(
unsigned int r = 0; r < rows; ++r )
1422 nlohmann::json row = j[r];
1423 unsigned int cols = std::min( (
unsigned int) row.size(), dataList->GetColumnCount() );
1425 for(
unsigned int c = 0; c < cols; ++c )
1427 wxVariant val( wxString( row[c].get<std::string>() ) );
1428 dataList->SetValue( val, r, c );
1489 if( !GetTitle().StartsWith( wxS(
"*" ) ) )
1490 SetTitle( wxS(
"*" ) + GetTitle() );
1496 if( GetTitle().StartsWith( wxS(
"*" ) ) )
1497 SetTitle( GetTitle().AfterFirst(
'*' ) );
1511 return wxDialog::ShowModal();
1547 if( wxWindow* win = wxWindow::GetCapture() )
1548 win->ReleaseMouse();
1551 wxWindow* parent = GetParentForModalDialog( GetParent(), GetWindowStyle() );
1568 wxGUIEventLoop event_loop;
1577 return GetReturnCode();
1599 if( ( retCode == wxID_OK ) && ( !Validate() || !TransferDataFromWindow() ) )
1602 SetReturnCode( retCode );
1606 wxFAIL_MSG( wxT(
"Either DIALOG_SHIM::EndQuasiModal was called twice, or ShowQuasiModal wasn't called" ) );
1640 for( wxWindow* child : aWindow->GetChildren() )
1647 wxString msg = wxString::Format(
"Closing dialog %s", GetTitle() );
1665 const int id = aEvent.GetId();
1669 if(
id == GetAffirmativeId() )
1673 else if(
id == wxID_APPLY )
1682 else if(
id == wxID_CANCEL )
1705 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( aEvent.GetEventObject() ) )
1707 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( aEvent.GetEventObject() ) )
1717 int key = aEvt.GetKeyCode();
1720 if( aEvt.ControlDown() )
1722 if( aEvt.ShiftDown() )
1724 if( aEvt.AltDown() )
1727 int hotkey = key | mods;
1730 if( hotkey == (
MD_CTRL +
'Z') )
1741 if( aEvt.GetKeyCode() ==
'U' && aEvt.GetModifiers() == wxMOD_CONTROL )
1750 else if( ( aEvt.GetKeyCode() == WXK_RETURN || aEvt.GetKeyCode() == WXK_NUMPAD_ENTER ) && aEvt.ShiftDown() )
1752 wxObject* eventSource = aEvt.GetEventObject();
1754 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( eventSource ) )
1757 if( !textCtrl->IsMultiLine() )
1759 wxPostEvent(
this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
1763#if defined( __WXMAC__ ) || defined( __WXMSW__ )
1764 wxString eol =
"\r\n";
1766 wxString eol =
"\n";
1769 long pos = textCtrl->GetInsertionPoint();
1770 textCtrl->WriteText( eol );
1771 textCtrl->SetInsertionPoint( pos + eol.length() );
1774 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( eventSource ) )
1776 wxString eol =
"\n";
1778 switch( scintilla->GetEOLMode() )
1780 case wxSTC_EOL_CRLF: eol =
"\r\n";
break;
1781 case wxSTC_EOL_CR: eol =
"\r";
break;
1782 case wxSTC_EOL_LF: eol =
"\n";
break;
1785 long pos = scintilla->GetCurrentPos();
1786 scintilla->InsertText( pos, eol );
1787 scintilla->GotoPos( pos + eol.length() );
1793 else if( ( aEvt.GetKeyCode() == WXK_RETURN || aEvt.GetKeyCode() == WXK_NUMPAD_ENTER ) && aEvt.ControlDown() )
1795 wxPostEvent(
this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
1798 else if( aEvt.GetKeyCode() == WXK_TAB && !aEvt.ControlDown() )
1800 wxWindow* currentWindow = wxWindow::FindFocus();
1801 int currentIdx = -1;
1802 int delta = aEvt.ShiftDown() ? -1 : 1;
1809 idx = ( ( idx +
delta ) % size + size ) % size;
1812 for(
size_t i = 0; i <
m_tabOrder.size(); ++i )
1817 || ( currentWindow &&
m_tabOrder[i]->IsDescendant( currentWindow ) ) )
1819 currentIdx = (int) i;
1824 if( currentIdx >= 0 )
1826 advance( currentIdx );
1829 int startIdx = currentIdx;
1833 advance( currentIdx );
1835 if( currentIdx == startIdx )
1842 while(
dynamic_cast<wxTextEntry*
>(
m_tabOrder[ currentIdx ] ) ==
nullptr )
1843 advance( currentIdx );
1850 else if( aEvt.GetKeyCode() == WXK_ESCAPE )
1852 wxObject* eventSource = aEvt.GetEventObject();
1854 if( wxTextCtrl* textCtrl =
dynamic_cast<wxTextCtrl*
>( eventSource ) )
1860 textCtrl->SelectAll();
1864 else if( wxStyledTextCtrl* scintilla =
dynamic_cast<wxStyledTextCtrl*
>( eventSource ) )
1870 scintilla->SelectAll();
1882 wxStdDialogButtonSizer* sdbSizer =
dynamic_cast<wxStdDialogButtonSizer*
>( aSizer );
1885 [&]( wxButton* aButton )
1887 if( aLabels.count( aButton->GetId() ) > 0 )
1889 aButton->SetLabel( aLabels[ aButton->GetId() ] );
1895 switch( aButton->GetId() )
1897 case wxID_OK: aButton->SetLabel(
_(
"&OK" ) );
break;
1898 case wxID_CANCEL: aButton->SetLabel(
_(
"&Cancel" ) );
break;
1899 case wxID_YES: aButton->SetLabel(
_(
"&Yes" ) );
break;
1900 case wxID_NO: aButton->SetLabel(
_(
"&No" ) );
break;
1901 case wxID_APPLY: aButton->SetLabel(
_(
"&Apply" ) );
break;
1902 case wxID_SAVE: aButton->SetLabel(
_(
"&Save" ) );
break;
1903 case wxID_HELP: aButton->SetLabel(
_(
"&Help" ) );
break;
1904 case wxID_CONTEXT_HELP: aButton->SetLabel(
_(
"&Help" ) );
break;
1911 if( sdbSizer->GetAffirmativeButton() )
1912 setupButton( sdbSizer->GetAffirmativeButton() );
1914 if( sdbSizer->GetApplyButton() )
1915 setupButton( sdbSizer->GetApplyButton() );
1917 if( sdbSizer->GetNegativeButton() )
1918 setupButton( sdbSizer->GetNegativeButton() );
1920 if( sdbSizer->GetCancelButton() )
1921 setupButton( sdbSizer->GetCancelButton() );
1923 if( sdbSizer->GetHelpButton() )
1924 setupButton( sdbSizer->GetHelpButton() );
1928 if( sdbSizer->GetAffirmativeButton() )
1929 sdbSizer->GetAffirmativeButton()->SetDefault();
1932 for( wxSizerItem* item : aSizer->GetChildren() )
1934 if( item->GetSizer() )
1951 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.
void recordControlChange(wxWindow *aCtrl)
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 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 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)
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