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 wxBoxSizer* endingsSizer = new wxBoxSizer( wxVERTICAL );
40
41 wxGridBagSizer* gbSizerEndings = new wxGridBagSizer( 3, 0 );
42 gbSizerEndings->SetFlexibleDirection( wxBOTH );
43 gbSizerEndings->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
44
45 m_startShapeLabel = new wxStaticText( this, wxID_ANY, _( "Start Shape:" ) );
46 m_startShapeLabel->Wrap( -1 );
47 gbSizerEndings->Add( m_startShapeLabel, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL | wxRIGHT,
48 5 );
49
50 m_startShapeChoice = new wxBitmapComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0,
51 nullptr, wxCB_READONLY );
52 gbSizerEndings->Add( m_startShapeChoice, wxGBPosition( 0, 1 ), wxGBSpan( 1, 2 ), wxALIGN_CENTER_VERTICAL | wxEXPAND,
53 5 );
54
55 m_endShapeLabel = new wxStaticText( this, wxID_ANY, _( "End Shape:" ) );
56 m_endShapeLabel->Wrap( -1 );
57 gbSizerEndings->Add( m_endShapeLabel, wxGBPosition( 0, 4 ), wxGBSpan( 1, 1 ),
58 wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 5 );
59
60 m_endShapeChoice = new wxBitmapComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0,
61 nullptr, wxCB_READONLY );
62 gbSizerEndings->Add( m_endShapeChoice, wxGBPosition( 0, 5 ), wxGBSpan( 1, 2 ), wxALIGN_CENTER_VERTICAL | wxEXPAND,
63 5 );
64
65 auto addEndingValue = [&]( int aRow, int aCol, const wxString& aLabel, wxStaticText*& aLabelCtrl,
66 wxTextCtrl*& aValueCtrl, wxStaticText*& aUnitsCtrl, int aFlags )
67 {
68 aLabelCtrl = new wxStaticText( this, wxID_ANY, aLabel );
69 aLabelCtrl->Wrap( -1 );
70 gbSizerEndings->Add( aLabelCtrl, wxGBPosition( aRow, aCol ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL | aFlags,
71 5 );
72
73 aValueCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1, -1 ), 0 );
74 gbSizerEndings->Add( aValueCtrl, wxGBPosition( aRow, aCol + 1 ), wxGBSpan( 1, 1 ),
75 wxALIGN_CENTER_VERTICAL | wxEXPAND, 5 );
76
77 aUnitsCtrl = new wxStaticText( this, wxID_ANY, _( "unit" ) );
78 aUnitsCtrl->Wrap( -1 );
79 aUnitsCtrl->SetMinSize( wxSize( 60, -1 ) );
80 gbSizerEndings->Add( aUnitsCtrl, wxGBPosition( aRow, aCol + 2 ), wxGBSpan( 1, 1 ),
81 wxALIGN_CENTER_VERTICAL | wxLEFT, 3 );
82 };
83
84 addEndingValue( 1, 0, _( "Start Length:" ), m_startLengthLabel, m_startLengthCtrl, m_startLengthUnits, wxRIGHT );
85 addEndingValue( 1, 4, _( "End Length:" ), m_endLengthLabel, m_endLengthCtrl, m_endLengthUnits, wxLEFT | wxRIGHT );
86 addEndingValue( 2, 0, _( "Start Width:" ), m_startWidthLabel, m_startWidthCtrl, m_startWidthUnits, wxRIGHT );
87 addEndingValue( 2, 4, _( "End Width:" ), m_endWidthLabel, m_endWidthCtrl, m_endWidthUnits, wxLEFT | wxRIGHT );
88 addEndingValue( 3, 0, _( "Start Stroke Width:" ), m_startStrokeWidthLabel, m_startStrokeWidthCtrl,
89 m_startStrokeWidthUnits, wxRIGHT );
90 addEndingValue( 3, 4, _( "End Stroke Width:" ), m_endStrokeWidthLabel, m_endStrokeWidthCtrl, m_endStrokeWidthUnits,
91 wxLEFT | wxRIGHT );
92
93 gbSizerEndings->AddGrowableCol( 1 );
94 gbSizerEndings->AddGrowableCol( 5 );
95
96 endingsSizer->Add( gbSizerEndings, 0, wxEXPAND, 0 );
97
98 m_endingsHelpLabel = new wxStaticText( this, wxID_ANY, wxEmptyString );
99 m_endingsHelpLabel->Wrap( -1 );
100 endingsSizer->Add( m_endingsHelpLabel, 0, wxTOP | wxBOTTOM, 5 );
101
102 mainSizer->Insert( 1, endingsSizer, 0, wxEXPAND | wxRIGHT | wxLEFT, 10 );
103
104 wxColour fg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
105 wxColour bg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
106 wxSize iconSize( 80, 24 );
107
108 struct
109 {
110 wxString name;
111 LINE_ENDING_STYLE style;
112 } shapeItems[] = {
113 { _( "None" ), LINE_ENDING_STYLE::NONE },
114 { _( "Arrow" ), LINE_ENDING_STYLE::ARROW },
115 { _( "Open Arrow" ), LINE_ENDING_STYLE::ARROW_OPEN },
116 { _( "Circle" ), LINE_ENDING_STYLE::CIRCLE },
117 { _( "Square" ), LINE_ENDING_STYLE::SQUARE },
118 };
119
120 for( const auto& item : shapeItems )
121 {
122 wxBitmap startBmp = MakeLineEndingBitmap( item.style, iconSize, fg, bg, this, false );
123 wxBitmap endBmp = MakeLineEndingBitmap( item.style, iconSize, fg, bg, this, true );
124 m_startShapeChoice->Append( item.name, startBmp );
125 m_endShapeChoice->Append( item.name, endBmp );
126 }
127
128 m_startShapeChoice->SetSelection( 0 );
129 m_endShapeChoice->SetSelection( 0 );
130
132 std::make_unique<UNIT_BINDER>( aParent, m_startLengthLabel, m_startLengthCtrl, m_startLengthUnits, true );
134 std::make_unique<UNIT_BINDER>( aParent, m_startWidthLabel, m_startWidthCtrl, m_startWidthUnits, true );
135 m_startStrokeWidth = std::make_unique<UNIT_BINDER>( aParent, m_startStrokeWidthLabel, m_startStrokeWidthCtrl,
137 m_endLength = std::make_unique<UNIT_BINDER>( aParent, m_endLengthLabel, m_endLengthCtrl, m_endLengthUnits, true );
138 m_endWidth = std::make_unique<UNIT_BINDER>( aParent, m_endWidthLabel, m_endWidthCtrl, m_endWidthUnits, true );
139 m_endStrokeWidth = std::make_unique<UNIT_BINDER>( aParent, m_endStrokeWidthLabel, m_endStrokeWidthCtrl,
140 m_endStrokeWidthUnits, true );
141}
142
143
145 std::deque<SCH_LINE*>& aLines ) :
147 m_frame( aParent ),
148 m_lines( aLines ),
150{
151 createLineEndingControls( aParent );
152
153 m_colorSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
154
155 KIGFX::COLOR4D canvas = m_frame->GetColorSettings()->GetColor( LAYER_SCHEMATIC_BACKGROUND );
156 m_colorSwatch->SetSwatchBackground( canvas.ToColour() );
157
158 m_helpLabel1->SetFont( KIUI::GetInfoFont( this ).Italic() );
159 m_helpLabel2->SetFont( KIUI::GetInfoFont( this ).Italic() );
160
161 m_endingsHelpLabel->SetFont( KIUI::GetInfoFont( this ).Italic() );
162 m_endingsHelpLabel->SetLabel( wxString::Format( _( "Shape sizes of 0 = auto (%g\u00d7 line width)." ),
164
166
167 for( const auto& [ lineStyle, lineStyleDesc ] : lineTypeNames )
168 m_typeCombo->Append( lineStyleDesc.name, KiBitmapBundle( lineStyleDesc.bitmap ) );
169
170 SetupStandardButtons( { { wxID_APPLY, _( "Default" ) } } );
171
172 // Now all widgets have the size fixed, call FinishDialogSettings
174}
175
176
178{
179 SCH_LINE* first_stroke_item = m_lines.front();
180
181 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
182 [&]( const SCH_LINE* r )
183 {
184 return r->GetPenWidth() == first_stroke_item->GetPenWidth();
185 } ) )
186 {
187 m_width.SetValue( first_stroke_item->GetStroke().GetWidth() );
188 }
189 else
190 {
191 m_width.SetValue( INDETERMINATE_ACTION );
192 }
193
194 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
195 [&]( const SCH_LINE* r )
196 {
197 return r->GetStroke().GetColor() == first_stroke_item->GetStroke().GetColor();
198 } ) )
199 {
200 m_colorSwatch->SetSwatchColor( first_stroke_item->GetStroke().GetColor(), false );
201 }
202 else
203 {
204 m_colorSwatch->SetSwatchColor( COLOR4D::UNSPECIFIED, false );
205 }
206
207 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
208 [&]( const SCH_LINE* r )
209 {
210 return r->GetStroke().GetLineStyle() == first_stroke_item->GetStroke().GetLineStyle();
211 } ) )
212 {
213 int style = static_cast<int>( first_stroke_item->GetStroke().GetLineStyle() );
214
215 if( style >= 0 && style < (int) lineTypeNames.size() )
216 m_typeCombo->SetSelection( style );
217 else
218 m_typeCombo->SetSelection( 0 );
219 }
220 else
221 {
223 m_typeCombo->SetStringSelection( INDETERMINATE_STYLE );
224 }
225
226 // Line endings - Start Shape
227 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
228 [&]( const SCH_LINE* r )
229 {
230 return r->GetStartEndingStyle() == first_stroke_item->GetStartEndingStyle();
231 } ) )
232 {
233 m_startShapeChoice->SetSelection( LINE_ENDING::StyleToChoiceIndex( first_stroke_item->GetStartEndingStyle() ) );
234 }
235 else
236 {
238 m_startShapeChoice->SetStringSelection( INDETERMINATE_STYLE );
239 }
240
241 // End Shape
242 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
243 [&]( const SCH_LINE* r )
244 {
245 return r->GetEndEndingStyle() == first_stroke_item->GetEndEndingStyle();
246 } ) )
247 {
248 m_endShapeChoice->SetSelection( LINE_ENDING::StyleToChoiceIndex( first_stroke_item->GetEndEndingStyle() ) );
249 }
250 else
251 {
253 m_endShapeChoice->SetStringSelection( INDETERMINATE_STYLE );
254 }
255
256 // Start Length
257 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
258 [&]( const SCH_LINE* r )
259 {
260 return r->GetStartEndingLength() == first_stroke_item->GetStartEndingLength();
261 } ) )
262 {
263 m_startLength->SetValue( first_stroke_item->GetStartEndingLength() );
264 }
265 else
266 {
268 }
269
270 // Start Width
271 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
272 [&]( const SCH_LINE* r )
273 {
274 return r->GetStartEndingWidth() == first_stroke_item->GetStartEndingWidth();
275 } ) )
276 {
277 m_startWidth->SetValue( first_stroke_item->GetStartEndingWidth() );
278 }
279 else
280 {
282 }
283
284 // Start Stroke Width
285 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
286 [&]( const SCH_LINE* r )
287 {
288 return r->GetStartEndingStrokeWidth() == first_stroke_item->GetStartEndingStrokeWidth();
289 } ) )
290 {
291 m_startStrokeWidth->SetValue( first_stroke_item->GetStartEndingStrokeWidth() );
292 }
293 else
294 {
296 }
297
298 // End Length
299 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
300 [&]( const SCH_LINE* r )
301 {
302 return r->GetEndEndingLength() == first_stroke_item->GetEndEndingLength();
303 } ) )
304 {
305 m_endLength->SetValue( first_stroke_item->GetEndEndingLength() );
306 }
307 else
308 {
310 }
311
312 // End Width
313 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
314 [&]( const SCH_LINE* r )
315 {
316 return r->GetEndEndingWidth() == first_stroke_item->GetEndEndingWidth();
317 } ) )
318 {
319 m_endWidth->SetValue( first_stroke_item->GetEndEndingWidth() );
320 }
321 else
322 {
323 m_endWidth->SetValue( INDETERMINATE_ACTION );
324 }
325
326 // End Stroke Width
327 if( std::all_of( m_lines.begin() + 1, m_lines.end(),
328 [&]( const SCH_LINE* r )
329 {
330 return r->GetEndEndingStrokeWidth() == first_stroke_item->GetEndEndingStrokeWidth();
331 } ) )
332 {
333 m_endStrokeWidth->SetValue( first_stroke_item->GetEndEndingStrokeWidth() );
334 }
335 else
336 {
338 }
339
340 return true;
341}
342
343
344void DIALOG_LINE_PROPERTIES::resetDefaults( wxCommandEvent& event )
345{
346 m_width.SetValue( 0 );
347 m_colorSwatch->SetSwatchColor( COLOR4D::UNSPECIFIED, false );
348
349 m_typeCombo->SetStringSelection( DEFAULT_LINE_STYLE_LABEL );
350
351 m_startShapeChoice->SetSelection( 0 );
352 m_endShapeChoice->SetSelection( 0 );
353 m_startLength->SetValue( 0 );
354 m_startWidth->SetValue( 0 );
355 m_startStrokeWidth->SetValue( 0 );
356 m_endLength->SetValue( 0 );
357 m_endWidth->SetValue( 0 );
358 m_endStrokeWidth->SetValue( 0 );
359
360 Refresh();
361}
362
363
365{
366 SCH_COMMIT commit( m_frame );
367
368 for( SCH_LINE* line : m_lines )
369 {
370 // Commit the change only if the line is not new. If new this is useless
371 // and can create dangling pointers if the line creation is aborted
372 if( !line->HasFlag( IS_NEW ) )
373 commit.Modify( line, m_frame->GetScreen() );
374
375 if( !m_width.IsIndeterminate() )
376 line->SetLineWidth( std::max( 0, m_width.GetIntValue() ) );
377
378 auto it = lineTypeNames.begin();
379 std::advance( it, m_typeCombo->GetSelection() );
380
381 if( it == lineTypeNames.end() )
382 line->SetLineStyle( LINE_STYLE::DEFAULT );
383 else
384 line->SetLineStyle( it->first );
385
386 line->SetLineColor( m_colorSwatch->GetSwatchColor() );
387
388 // Line endings
389 int startSel = m_startShapeChoice->GetSelection();
390
391 if( startSel >= 0 && startSel < LINE_ENDING::s_defaultChoiceCount )
392 line->SetStartEndingStyle( LINE_ENDING::s_defaultChoiceOrder[startSel] );
393
394 int endSel = m_endShapeChoice->GetSelection();
395
396 if( endSel >= 0 && endSel < LINE_ENDING::s_defaultChoiceCount )
397 line->SetEndEndingStyle( LINE_ENDING::s_defaultChoiceOrder[endSel] );
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_startStrokeWidth->IsIndeterminate() )
406 line->SetStartEndingStrokeWidth( std::max( 0, m_startStrokeWidth->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_endStrokeWidth->IsIndeterminate() )
415 line->SetEndEndingStrokeWidth( std::max( 0, m_endStrokeWidth->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:399
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::deque< SCH_LINE * > m_lines
DIALOG_LINE_PROPERTIES(SCH_EDIT_FRAME *aParent, std::deque< SCH_LINE * > &aLines)
std::unique_ptr< UNIT_BINDER > m_endStrokeWidth
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_startStrokeWidth
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.
virtual void Push(const wxString &aMessage=wxT("A commit"), 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, const wxColour &aBackground, 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