KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_line_properties.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 (C) 2017 Seth Hillbrand <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <sch_line.h>
26#include <sch_edit_frame.h>
27#include <stroke_params.h>
30#include <sch_commit.h>
31#include <line_ending.h>
32
33
35{
36 wxSizer* mainSizer = GetSizer();
37 wxCHECK_RET( mainSizer, wxT( "Line properties dialog has no main sizer" ) );
38
39 wxGridBagSizer* gbSizerEndings = new wxGridBagSizer( 3, 0 );
40 gbSizerEndings->SetFlexibleDirection( wxBOTH );
41 gbSizerEndings->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
42 gbSizerEndings->SetEmptyCellSize( wxSize( 20, -1 ) );
43
44 m_startShapeLabel = new wxStaticText( this, wxID_ANY, _( "Start Shape:" ) );
45 gbSizerEndings->Add( m_startShapeLabel, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ),
46 wxALIGN_CENTER_VERTICAL | wxRIGHT, 5 );
47
48 m_startShapeChoice = new wxBitmapComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0,
49 nullptr, wxCB_READONLY );
50 gbSizerEndings->Add( m_startShapeChoice, wxGBPosition( 0, 1 ), wxGBSpan( 1, 2 ),
51 wxALIGN_CENTER_VERTICAL | wxEXPAND, 5 );
52
53 m_endShapeLabel = new wxStaticText( this, wxID_ANY, _( "End Shape:" ) );
54 gbSizerEndings->Add( m_endShapeLabel, wxGBPosition( 0, 4 ), wxGBSpan( 1, 1 ),
55 wxALIGN_CENTER_VERTICAL | wxRIGHT, 5 );
56
57 m_endShapeChoice = new wxBitmapComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0,
58 nullptr, wxCB_READONLY );
59 gbSizerEndings->Add( m_endShapeChoice, wxGBPosition( 0, 5 ), wxGBSpan( 1, 2 ),
60 wxALIGN_CENTER_VERTICAL | wxEXPAND, 5 );
61
62 auto addEndingValue =
63 [&]( int aRow, int aCol, const wxString& aLabel, wxStaticText*& aLabelCtrl, wxTextCtrl*& aValueCtrl,
64 wxStaticText*& aUnitsCtrl, int aFlags )
65 {
66 aLabelCtrl = new wxStaticText( this, wxID_ANY, aLabel );
67 gbSizerEndings->Add( aLabelCtrl, wxGBPosition( aRow, aCol ), wxGBSpan( 1, 1 ),
68 wxALIGN_CENTER_VERTICAL | wxLEFT | aFlags, 15 );
69
70 aValueCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1, -1 ), 0 );
71 gbSizerEndings->Add( aValueCtrl, wxGBPosition( aRow, aCol + 1 ), wxGBSpan( 1, 1 ),
72 wxALIGN_CENTER_VERTICAL | wxLEFT | wxEXPAND, 15 );
73
74 aUnitsCtrl = new wxStaticText( this, wxID_ANY, _( "unit" ) );
75 gbSizerEndings->Add( aUnitsCtrl, wxGBPosition( aRow, aCol + 2 ), wxGBSpan( 1, 1 ),
76 wxALIGN_CENTER_VERTICAL | wxLEFT, 3 );
77 };
78
79 addEndingValue( 1, 0, _( "Length:" ), m_startLengthLabel, m_startLengthCtrl, m_startLengthUnits, wxRIGHT );
80 addEndingValue( 1, 4, _( "Length:" ), m_endLengthLabel, m_endLengthCtrl, m_endLengthUnits, wxLEFT | wxRIGHT );
81 addEndingValue( 2, 0, _( "Width:" ), m_startWidthLabel, m_startWidthCtrl, m_startWidthUnits, wxRIGHT );
82 addEndingValue( 2, 4, _( "Width:" ), m_endWidthLabel, m_endWidthCtrl, m_endWidthUnits, wxLEFT | wxRIGHT );
83 addEndingValue( 3, 0, _( "Thickness:" ), m_startThicknessLabel, m_startThicknessCtrl, m_startThicknessUnits,
84 wxRIGHT );
85 addEndingValue( 3, 4, _( "Thickness:" ), m_endThicknessLabel, m_endThicknessCtrl, m_endThicknessUnits,
86 wxLEFT | wxRIGHT );
87
88 gbSizerEndings->AddGrowableCol( 1 );
89 gbSizerEndings->AddGrowableCol( 5 );
90
91 m_endingsSizer->Add( gbSizerEndings, 0, wxEXPAND, 0 );
92
93 m_endingsHelpLabel = new wxStaticText( this, wxID_ANY, wxEmptyString );
94 m_endingsSizer->Add( m_endingsHelpLabel, 0, wxLEFT | wxRIGHT | wxTOP | wxBOTTOM, 10 );
95
96 wxColour fg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
97 wxSize iconSize = GetTextExtent( wxT( "XXXXXX" ) );
98
99 struct
100 {
101 wxString name;
102 LINE_ENDING_STYLE style;
103 } shapeItems[] = {
104 { _( "None" ), LINE_ENDING_STYLE::NONE },
105 { _( "Arrow" ), LINE_ENDING_STYLE::ARROW },
106 { _( "Open Arrow" ), LINE_ENDING_STYLE::ARROW_OPEN },
107 { _( "Circle" ), LINE_ENDING_STYLE::CIRCLE },
108 { _( "Square" ), LINE_ENDING_STYLE::SQUARE },
109 };
110
111 for( const auto& item : shapeItems )
112 {
113 wxBitmap startBmp = MakeLineEndingBitmap( item.style, iconSize, fg, this, false );
114 wxBitmap endBmp = MakeLineEndingBitmap( item.style, iconSize, fg, this, true );
115 m_startShapeChoice->Append( item.name, startBmp );
116 m_endShapeChoice->Append( item.name, endBmp );
117 }
118
119 m_startShapeChoice->SetSelection( 0 );
120 m_endShapeChoice->SetSelection( 0 );
121
122 m_startLength = std::make_unique<UNIT_BINDER>( aParent, m_startLengthLabel, m_startLengthCtrl, m_startLengthUnits,
123 true );
124 m_startWidth = std::make_unique<UNIT_BINDER>( aParent, m_startWidthLabel, m_startWidthCtrl, m_startWidthUnits,
125 true );
126 m_startThickness = std::make_unique<UNIT_BINDER>( aParent, m_startThicknessLabel, m_startThicknessCtrl,
127 m_startThicknessUnits, true );
128 m_endLength = std::make_unique<UNIT_BINDER>( aParent, m_endLengthLabel, m_endLengthCtrl, m_endLengthUnits, true );
129 m_endWidth = std::make_unique<UNIT_BINDER>( aParent, m_endWidthLabel, m_endWidthCtrl, m_endWidthUnits, true );
130 m_endThickness = std::make_unique<UNIT_BINDER>( aParent, m_endThicknessLabel, m_endThicknessCtrl,
131 m_endThicknessUnits, true );
132}
133
134
135DIALOG_LINE_PROPERTIES::DIALOG_LINE_PROPERTIES( SCH_EDIT_FRAME* aParent, std::deque<SCH_LINE*>& aLines ) :
137 m_frame( aParent ),
138 m_lines( aLines ),
140{
141 createLineEndingControls( aParent );
142
143 m_colorSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
144
145 KIGFX::COLOR4D canvas = m_frame->GetColorSettings()->GetColor( LAYER_SCHEMATIC_BACKGROUND );
146 m_colorSwatch->SetSwatchBackground( canvas.ToColour() );
147
148 m_helpLabel1->SetFont( KIUI::GetInfoFont( this ).Italic() );
149 m_helpLabel2->SetFont( KIUI::GetInfoFont( this ).Italic() );
150
151 m_endingsHelpLabel->SetFont( KIUI::GetInfoFont( this ).Italic() );
152 m_endingsHelpLabel->SetLabel( wxString::Format( _( "Set line ending sizes to 0 for automatic (%g\u00d7 line width)." ),
154
156
157 for( const auto& [ lineStyle, lineStyleDesc ] : lineTypeNames )
158 m_typeCombo->Append( lineStyleDesc.name, KiBitmapBundle( lineStyleDesc.bitmap ) );
159
161
162 // Now all widgets have the size fixed, call FinishDialogSettings
164}
165
166
168{
169 SCH_LINE* first_stroke_item = m_lines.front();
170
171 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
172 [&]( const SCH_LINE* r )
173 {
174 return r->GetStroke().GetWidth() == first_stroke_item->GetStroke().GetWidth();
175 } ) )
176 {
177 m_width.SetValue( first_stroke_item->GetStroke().GetWidth() );
178 }
179 else
180 {
181 m_width.SetValue( INDETERMINATE_ACTION );
182 }
183
184 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
185 [&]( const SCH_LINE* r )
186 {
187 return r->GetStroke().GetColor() == first_stroke_item->GetStroke().GetColor();
188 } ) )
189 {
190 m_colorSwatch->SetSwatchColor( first_stroke_item->GetStroke().GetColor(), false );
191 }
192 else
193 {
194 m_colorSwatch->SetSwatchColor( COLOR4D::UNSPECIFIED, false );
195 }
196
197 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
198 [&]( const SCH_LINE* r )
199 {
200 return r->GetStroke().GetLineStyle() == first_stroke_item->GetStroke().GetLineStyle();
201 } ) )
202 {
203 int style = static_cast<int>( first_stroke_item->GetStroke().GetLineStyle() );
204
205 if( style >= 0 && style < (int) lineTypeNames.size() )
206 m_typeCombo->SetSelection( style );
207 else
208 m_typeCombo->SetSelection( 0 );
209 }
210 else
211 {
213 m_typeCombo->SetStringSelection( INDETERMINATE_STYLE );
214 }
215
216 // Line endings - Start Shape
217 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
218 [&]( const SCH_LINE* r )
219 {
220 return r->GetStartEndingStyle() == first_stroke_item->GetStartEndingStyle();
221 } ) )
222 {
223 m_startShapeChoice->SetSelection( LINE_ENDING::StyleToChoiceIndex( first_stroke_item->GetStartEndingStyle() ) );
224 }
225 else
226 {
228 m_startShapeChoice->SetStringSelection( INDETERMINATE_STYLE );
229 }
230
231 // End Shape
232 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
233 [&]( const SCH_LINE* r )
234 {
235 return r->GetEndEndingStyle() == first_stroke_item->GetEndEndingStyle();
236 } ) )
237 {
238 m_endShapeChoice->SetSelection( LINE_ENDING::StyleToChoiceIndex( first_stroke_item->GetEndEndingStyle() ) );
239 }
240 else
241 {
243 m_endShapeChoice->SetStringSelection( INDETERMINATE_STYLE );
244 }
245
246 // Start Length
247 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
248 [&]( const SCH_LINE* r )
249 {
250 return r->GetStartEndingLength() == first_stroke_item->GetStartEndingLength();
251 } ) )
252 {
253 m_startLength->SetValue( first_stroke_item->GetStartEndingLength() );
254 }
255 else
256 {
258 }
259
260 // Start Width
261 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
262 [&]( const SCH_LINE* r )
263 {
264 return r->GetStartEndingWidth() == first_stroke_item->GetStartEndingWidth();
265 } ) )
266 {
267 m_startWidth->SetValue( first_stroke_item->GetStartEndingWidth() );
268 }
269 else
270 {
272 }
273
274 // Start Stroke Width
275 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
276 [&]( const SCH_LINE* r )
277 {
278 return r->GetStartEndingStrokeWidth() == first_stroke_item->GetStartEndingStrokeWidth();
279 } ) )
280 {
281 m_startThickness->SetValue( first_stroke_item->GetStartEndingStrokeWidth() );
282 }
283 else
284 {
286 }
287
288 // End Length
289 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
290 [&]( const SCH_LINE* r )
291 {
292 return r->GetEndEndingLength() == first_stroke_item->GetEndEndingLength();
293 } ) )
294 {
295 m_endLength->SetValue( first_stroke_item->GetEndEndingLength() );
296 }
297 else
298 {
300 }
301
302 // End Width
303 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
304 [&]( const SCH_LINE* r )
305 {
306 return r->GetEndEndingWidth() == first_stroke_item->GetEndEndingWidth();
307 } ) )
308 {
309 m_endWidth->SetValue( first_stroke_item->GetEndEndingWidth() );
310 }
311 else
312 {
313 m_endWidth->SetValue( INDETERMINATE_ACTION );
314 }
315
316 // End Stroke Width
317 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
318 [&]( const SCH_LINE* r )
319 {
320 return r->GetEndEndingStrokeWidth() == first_stroke_item->GetEndEndingStrokeWidth();
321 } ) )
322 {
323 m_endThickness->SetValue( first_stroke_item->GetEndEndingStrokeWidth() );
324 }
325 else
326 {
328 }
329
330 return true;
331}
332
333
334void DIALOG_LINE_PROPERTIES::resetDefaults( wxCommandEvent& event )
335{
336 m_width.SetValue( 0 );
337 m_colorSwatch->SetSwatchColor( COLOR4D::UNSPECIFIED, false );
338
339 m_typeCombo->SetStringSelection( DEFAULT_LINE_STYLE_LABEL );
340
341 m_startShapeChoice->SetSelection( 0 );
342 m_endShapeChoice->SetSelection( 0 );
343 m_startLength->SetValue( 0 );
344 m_startWidth->SetValue( 0 );
345 m_startThickness->SetValue( 0 );
346 m_endLength->SetValue( 0 );
347 m_endWidth->SetValue( 0 );
348 m_endThickness->SetValue( 0 );
349
350 Refresh();
351}
352
353
355{
356 SCH_COMMIT commit( m_frame );
357
358 for( SCH_LINE* line : m_lines )
359 {
360 // Commit the change only if the line is not new. If new this is useless
361 // and can create dangling pointers if the line creation is aborted
362 if( !line->HasFlag( IS_NEW ) )
363 commit.Modify( line, m_frame->GetScreen() );
364
365 if( !m_width.IsIndeterminate() )
366 line->SetLineWidth( std::max( 0, m_width.GetIntValue() ) );
367
368 if( m_typeCombo->GetStringSelection() != INDETERMINATE_STYLE )
369 {
370 auto it = lineTypeNames.begin();
371 std::advance( it, m_typeCombo->GetSelection() );
372
373 if( it == lineTypeNames.end() )
374 line->SetLineStyle( LINE_STYLE::DEFAULT );
375 else
376 line->SetLineStyle( it->first );
377 }
378
379 if( m_colorSwatch->GetSwatchColor() != COLOR4D::UNSPECIFIED )
380 line->SetLineColor( m_colorSwatch->GetSwatchColor() );
381
382 // Line endings
383 if( m_startShapeChoice->GetStringSelection() != INDETERMINATE_STYLE )
384 {
385 int startSel = m_startShapeChoice->GetSelection();
386
387 if( startSel >= 0 && startSel < LINE_ENDING::s_defaultChoiceCount )
388 line->SetStartEndingStyle( LINE_ENDING::s_defaultChoiceOrder[startSel] );
389 }
390
391 if( m_endShapeChoice->GetStringSelection() != INDETERMINATE_STYLE )
392 {
393 int endSel = m_endShapeChoice->GetSelection();
394
395 if( endSel >= 0 && endSel < LINE_ENDING::s_defaultChoiceCount )
396 line->SetEndEndingStyle( LINE_ENDING::s_defaultChoiceOrder[endSel] );
397 }
398
399 if( !m_startLength->IsIndeterminate() )
400 line->SetStartEndingLength( std::max( 0, m_startLength->GetIntValue() ) );
401
402 if( !m_startWidth->IsIndeterminate() )
403 line->SetStartEndingWidth( std::max( 0, m_startWidth->GetIntValue() ) );
404
405 if( !m_startThickness->IsIndeterminate() )
406 line->SetStartEndingStrokeWidth( std::max( 0, m_startThickness->GetIntValue() ) );
407
408 if( !m_endLength->IsIndeterminate() )
409 line->SetEndEndingLength( std::max( 0, m_endLength->GetIntValue() ) );
410
411 if( !m_endWidth->IsIndeterminate() )
412 line->SetEndEndingWidth( std::max( 0, m_endWidth->GetIntValue() ) );
413
414 if( !m_endThickness->IsIndeterminate() )
415 line->SetEndEndingStrokeWidth( std::max( 0, m_endThickness->GetIntValue() ) );
416 }
417
418 commit.Push( m_lines.size() == 1 ? _( "Edit Line" ) : _( "Edit Lines" ) );
419 return true;
420}
const char * name
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:400
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:102
DIALOG_LINE_PROPERTIES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Line Properties"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
std::unique_ptr< UNIT_BINDER > m_endLength
std::unique_ptr< UNIT_BINDER > m_endThickness
std::deque< SCH_LINE * > m_lines
DIALOG_LINE_PROPERTIES(SCH_EDIT_FRAME *aParent, std::deque< SCH_LINE * > &aLines)
void resetDefaults(wxCommandEvent &event) override
std::unique_ptr< UNIT_BINDER > m_endWidth
void createLineEndingControls(SCH_EDIT_FRAME *aParent)
std::unique_ptr< UNIT_BINDER > m_startLength
wxBitmapComboBox * m_endShapeChoice
std::unique_ptr< UNIT_BINDER > m_startWidth
std::unique_ptr< UNIT_BINDER > m_startThickness
wxBitmapComboBox * m_startShapeChoice
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:94
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
wxColour ToColour() const
Definition color4d.cpp:221
static constexpr double DEFAULT_RATIO_LENGTH
static const int s_defaultChoiceCount
static const LINE_ENDING_STYLE s_defaultChoiceOrder[]
Dropdown display order for line ending style choosers.
Definition line_ending.h:38
static int StyleToChoiceIndex(LINE_ENDING_STYLE aStyle)
Return the dropdown index for the given style, or 0 (NONE) if not found.
Commit for the schematic and symbol editors.
Definition sch_commit.h:54
void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
Schematic editor (Eeschema) main window.
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:39
int GetStartEndingStrokeWidth() const
Definition sch_line.h:223
int GetEndEndingLength() const
Definition sch_line.h:218
virtual STROKE_PARAMS GetStroke() const override
Definition sch_line.h:198
int GetEndEndingWidth() const
Definition sch_line.h:220
int GetStartEndingWidth() const
Definition sch_line.h:215
LINE_ENDING_STYLE GetEndEndingStyle() const
Definition sch_line.h:210
int GetEndEndingStrokeWidth() const
Definition sch_line.h:225
LINE_ENDING_STYLE GetStartEndingStyle() const
Definition sch_line.h:207
int GetStartEndingLength() const
Definition sch_line.h:213
int GetWidth() const
KIGFX::COLOR4D GetColor() const
#define _(s)
#define IS_NEW
New item, just created.
@ LAYER_SCHEMATIC_BACKGROUND
Definition layer_ids.h:510
LINE_ENDING_STYLE
Line ending styles for graphic lines, arcs, and beziers.
Definition line_ending.h:44
wxBitmap MakeLineEndingBitmap(LINE_ENDING_STYLE aStyle, const wxSize &aSize, const wxColour &aForeground, wxWindow *aWindow, bool aShapeOnRight)
Generate a DPI-aware bitmap icon showing a line ending style.
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
const std::map< LINE_STYLE, struct LINE_STYLE_DESC > lineTypeNames
Conversion map between LINE_STYLE values and style names displayed.
#define INDETERMINATE_STYLE
#define DEFAULT_LINE_STYLE_LABEL
#define INDETERMINATE_ACTION
Definition ui_common.h:47