KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pl_properties_panel.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include "pl_properties_panel.h"
21
23#include <dialog_shim.h>
25#include <project.h>
28#include <properties/property.h>
30#include <scintilla_tricks.h>
31#include <tool/tool_manager.h>
32#include <tool/actions.h>
33#include <wx/hyperlink.h>
34#include <wx/propgrid/advprops.h>
35#include <wx/sizer.h>
36#include <wx/stc/stc.h>
37
38#include "pl_editor_frame.h"
39#include "pl_properties.h"
41
42#include <set>
43
44
45namespace
46{
48class PL_TEXT_PROPERTY : public wxLongStringProperty
49{
50public:
51 explicit PL_TEXT_PROPERTY( PL_EDITOR_FRAME* aFrame ) :
52 wxLongStringProperty( _( "Text" ), wxS( "Text" ) ),
53 m_frame( aFrame )
54 {
55 }
56
57protected:
58 bool DisplayEditorDialog( wxPropertyGrid* aGrid, wxVariant& aValue ) override
59 {
60 DIALOG_SHIM dlg( m_frame, wxID_ANY, _( "Edit Text" ), wxDefaultPosition, wxDefaultSize,
61 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER );
62 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
63 wxStyledTextCtrl* editor = new wxStyledTextCtrl( &dlg, wxID_ANY );
64 editor->SetMinSize( dlg.FromDIP( wxSize( 450, 200 ) ) );
65 editor->SetEOLMode( wxSTC_EOL_LF );
66#ifdef _WIN32
67 editor->SetTechnology( wxSTC_TECHNOLOGY_DIRECTWRITE );
68#endif
69 DS_DATA_ITEM_TEXT text( wxEmptyString );
70 text.m_FullText = aValue.IsNull() ? wxString() : aValue.GetString();
71 text.ReplaceAntiSlashSequence();
72 editor->SetText( text.m_FullText );
73 editor->EmptyUndoBuffer();
74 SCINTILLA_TRICKS tricks( editor, wxT( "{}" ), false );
75
76 auto autocomplete = [&]( wxStyledTextEvent& )
77 {
78 wxArrayString tokens;
79 int pos = editor->GetCurrentPos();
80 int start = editor->WordStartPosition( pos, true );
81 wxString partial;
82
83 if( start >= 2 && editor->GetCharAt( start - 2 ) == '$' && editor->GetCharAt( start - 1 ) == '{' )
84 {
86 partial = editor->GetTextRange( start, pos );
87
88 for( const auto& [key, value] : m_frame->Prj().GetTextVars() )
89 tokens.push_back( key );
90 }
91
92 tricks.DoAutocomplete( partial, tokens );
93 };
94
95 editor->Bind( wxEVT_STC_CHARADDED, autocomplete );
96 editor->Bind( wxEVT_STC_AUTOCOMP_CHAR_DELETED, autocomplete );
97 sizer->Add( editor, 1, wxEXPAND | wxALL, 10 );
98
99 wxHyperlinkCtrl* help = new wxHyperlinkCtrl( &dlg, wxID_ANY, _( "Text Variables" ), wxEmptyString );
100 help->Bind( wxEVT_HYPERLINK,
101 [&]( wxHyperlinkEvent& )
102 {
103 HTML_MESSAGE_BOX helpDlg( &dlg, _( "Predefined Keywords" ) );
104 helpDlg.AddHTML_Text( _( "Text can include variables using ${keyword} notation." ) );
105 wxArrayString tokens;
107 wxString list;
108
109 for( const wxString& token : tokens )
110 list += token + wxS( "\n" );
111
112 helpDlg.ListSet( list );
113 helpDlg.ShowModal();
114 } );
115 sizer->Add( help, 0, wxLEFT | wxRIGHT | wxBOTTOM, 10 );
116 sizer->Add( dlg.CreateStdDialogButtonSizer( wxOK | wxCANCEL ), 0, wxEXPAND | wxALL, 10 );
117 dlg.SetSizerAndFit( sizer );
118 dlg.Centre();
119 editor->SetFocus();
120
121 if( dlg.ShowModal() != wxID_OK )
122 return false;
123
124 aValue = editor->GetText();
125 return true;
126 }
127
128private:
129 PL_EDITOR_FRAME* m_frame;
130};
131} // namespace
132
133
135 PROPERTIES_PANEL( aFrame, aFrame ),
136 m_editor( aFrame ),
137 m_unitEditor( nullptr ),
138 m_pageProperties( std::make_unique<PL_PAGE_PROPERTIES>( DS_DATA_MODEL::GetTheInstance() ) )
139{
140 SetMinSize( FromDIP( wxSize( 150, -1 ) ) );
142
143 auto& editors = wxPGGlobalVars->m_mapEditorClasses;
144 auto it = editors.find( PG_UNIT_EDITOR::BuildEditorName( aFrame ) );
145
146 if( it != editors.end() )
147 {
148 m_unitEditor = static_cast<PG_UNIT_EDITOR*>( it->second );
149 m_unitEditor->UpdateFrame( aFrame );
150 }
151 else
152 {
154 static_cast<PG_UNIT_EDITOR*>( wxPropertyGrid::RegisterEditorClass( new PG_UNIT_EDITOR( aFrame ) ) );
155 }
156
157 if( editors.find( PG_CHECKBOX_EDITOR::EDITOR_NAME ) == editors.end() )
158 wxPropertyGrid::RegisterEditorClass( new PG_CHECKBOX_EDITOR() );
159
160 if( editors.find( PG_COLOR_EDITOR::EDITOR_NAME ) == editors.end() )
161 wxPropertyGrid::RegisterEditorClass( new PG_COLOR_EDITOR() );
162
164 _HKI( "Defaults" ), _( "Reset to Defaults" ), BITMAPS::small_refresh,
165 [this]()
166 {
168 },
169 [this]()
170 {
171 return m_itemProperties.empty();
172 } );
173}
174
175
177{
179 m_deferredSelection.Clear();
180 m_unitEditor->UpdateFrame( nullptr );
181}
182
183
185{
186 if( !m_editor->GetToolManager() )
187 return;
188
189 // A deferred grid rebuild must never retain adapters for deleted or reloaded definitions.
191 m_deferredSelection.Clear();
192 m_selection.Clear();
193 m_itemProperties.clear();
194
195 std::set<DS_DATA_ITEM*> seen;
196
197 for( EDA_ITEM* item : m_editor->GetCurrentSelection() )
198 {
199 DS_DATA_ITEM* peer = static_cast<DS_DRAW_ITEM_BASE*>( item )->GetPeer();
200
201 if( peer && seen.insert( peer ).second )
202 {
203 m_itemProperties.push_back( std::make_unique<PL_ITEM_PROPERTIES>( peer ) );
204 m_selection.Add( m_itemProperties.back().get() );
205 }
206 }
207
208 if( m_selection.Empty() )
209 m_selection.Add( m_pageProperties.get() );
210
212}
213
214
216{
217 // The base class may defer a rebuild until a property event has finished. Resolve the
218 // current selection again; rendered drawing-sheet items may have been replaced meanwhile.
219 UpdateData();
220}
221
222
223wxPGProperty* PL_PROPERTIES_PANEL::createPGProperty( const PROPERTY_BASE* aProperty ) const
224{
225 wxPGProperty* property;
226
227 if( aProperty->Name() == wxS( "Text" ) )
228 {
229 property = new PL_TEXT_PROPERTY( m_editor );
230 property->SetClientData( const_cast<PROPERTY_BASE*>( aProperty ) );
231 property->SetHelpString( wxGetTranslation( aProperty->HelpString() ) );
232 }
233 else if( aProperty->Name() == wxS( "Comment" ) )
234 {
235 // Drawing-sheet strings are stored literally, without the schematic escape encoding.
236 property = new wxStringProperty( wxGetTranslation( aProperty->Name() ), aProperty->Name() );
237 property->SetClientData( const_cast<PROPERTY_BASE*>( aProperty ) );
238 }
239 else
240 {
241 property = PGPropertyFactory( aProperty, m_editor );
242 }
243
244 if( auto* color = dynamic_cast<PGPROPERTY_COLOR4D*>( property ) )
245 color->SetBackgroundColor( m_editor->GetDrawBgColor() );
246
247 return property;
248}
249
250
251void PL_PROPERTIES_PANEL::valueChanging( wxPropertyGridEvent& aEvent )
252{
254 return;
255
257
258 for( EDA_ITEM* item : m_selection )
259 {
260 PROPERTY_BASE* property = mgr.GetProperty( item, aEvent.GetPropertyName() );
261
262 if( !property || !property->Available( item ) || !property->Writeable( item ) )
263 {
264 aEvent.Veto();
265 return;
266 }
267
268 if( auto error = property->Validate( aEvent.GetPropertyValue().GetAny(), item ) )
269 {
270 m_editor->ShowInfoBarError( wxString::Format( wxS( "%s: %s" ), wxGetTranslation( property->Name() ),
271 error->get()->Format( m_editor ) ) );
272 aEvent.Veto();
273 return;
274 }
275 }
276
277 aEvent.Skip();
278}
279
280
281void PL_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
282{
284 return;
285
286 m_editor->SaveCopyInUndoList();
288
289 for( EDA_ITEM* item : m_selection )
290 {
291 if( PROPERTY_BASE* property = mgr.GetProperty( item, aEvent.GetPropertyName() ) )
292 item->Set( property, aEvent.GetPropertyValue() );
293 }
294
296}
297
298
300{
301 m_editor->SaveCopyInUndoList();
304 model.m_DefaultLineWidth = 0.15;
305 model.m_DefaultTextThickness = 0.15;
307}
308
309
311{
312 m_editor->OnModify();
313
314 // End point editing before rebuilding the rendered items. Its handles otherwise retain
315 // a pointer to a draw item deleted by DisplayDrawingSheet().
316 m_editor->GetToolManager()->ProcessEvent( EVENTS::UnselectedEvent );
317 m_editor->GetCanvas()->DisplayDrawingSheet();
318
319 // Reducing a repeat count can remove the selected copy. Keep its definition selected
320 // through the first surviving copy so the user can continue editing it.
321 PL_SELECTION_TOOL* selectionTool = m_editor->GetToolManager()->GetTool<PL_SELECTION_TOOL>();
322
323 for( const auto& properties : m_itemProperties )
324 {
325 const auto& items = properties->GetItem()->GetDrawItems();
326
327 if( !items.empty()
328 && std::ranges::none_of( items,
329 []( DS_DRAW_ITEM_BASE* aItem )
330 {
331 return aItem->IsSelected();
332 } ) )
333 {
334 selectionTool->AddItemToSel( items.front(), true );
335 }
336 }
337
338 m_editor->GetCanvas()->Refresh();
339 UpdateData();
340 m_editor->GetToolManager()->PostEvent( EVENTS::SelectedEvent );
341}
Drawing sheet structure type definitions.
Handle the graphic items list to draw/plot the frame and title block.
static DS_DATA_MODEL & GetTheInstance()
Return the instance of DS_DATA_MODEL used in the application.
Base class to handle basic graphic items.
static void GetTextVars(wxArrayString *aVars)
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
static const TOOL_EVENT SelectedEvent
Definition actions.h:346
static const TOOL_EVENT UnselectedEvent
Definition actions.h:347
static const wxString EDITOR_NAME
Definition pg_editors.h:75
static const wxString EDITOR_NAME
Definition pg_editors.h:91
static wxString BuildEditorName(EDA_DRAW_FRAME *aFrame)
The main window used in the drawing sheet editor.
Drawing-sheet defaults and margins, shown when no item is selected.
void valueChanged(wxPropertyGridEvent &aEvent) override
std::vector< std::unique_ptr< PL_ITEM_PROPERTIES > > m_itemProperties
PL_PROPERTIES_PANEL(PL_EDITOR_FRAME *aFrame)
wxPGProperty * createPGProperty(const PROPERTY_BASE *aProperty) const override
void valueChanging(wxPropertyGridEvent &aEvent) override
std::unique_ptr< PL_PAGE_PROPERTIES > m_pageProperties
PL_EDITOR_FRAME * m_editor
PG_UNIT_EDITOR * m_unitEditor
void rebuildProperties(const SELECTION &aSelection) override
Generates the property grid for a given selection of items.
PROPERTIES_PANEL(wxWindow *aParent, EDA_BASE_FRAME *aFrame)
wxTimer m_deferredRebuildTimer
Not CallAfter(): on macOS the pending-event queue is drained from inside tool events,...
SELECTION m_deferredSelection
virtual void rebuildProperties(const SELECTION &aSelection)
Generates the property grid for a given selection of items.
void addCategoryButton(const wxString &aGroupKey, const wxString &aTooltip, BITMAPS aBitmap, std::function< void()> aAction, std::function< bool()> aEnableFunc=nullptr, bool aForceCategory=false)
Registers an overlay button on a category caption row.
const wxString & HelpString() const
Definition property.h:223
const wxString & Name() const
Definition property.h:221
Provide class metadata.
static PROPERTY_MANAGER & Instance()
void Rebuild()
Rebuild the list of all registered properties.
PROPERTY_BASE * GetProperty(TYPE_ID aType, const wxString &aProperty) const
Return a property for a specific type.
int AddItemToSel(const TOOL_EVENT &aEvent)
#define TB_DEFAULT_TEXTSIZE
#define _(s)
STL namespace.
#define _HKI(x)
Definition page_info.cpp:40
wxPGProperty * PGPropertyFactory(const PROPERTY_BASE *aProperty, EDA_DRAW_FRAME *aFrame)
APIIMPORT wxPGGlobalVarsClass * wxPGGlobalVars
KIBIS_MODEL * model
VECTOR2< double > VECTOR2D
Definition vector2d.h:707