KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_re_bitmap_overlay_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 (C) 2024 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, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
26
27#include <bitmaps.h>
28
29#include <wx/bmpbndl.h>
30#include <wx/checkbox.h>
31#include <wx/dcclient.h>
32#include <wx/log.h>
33#include <wx/stattext.h>
34
35
37 wxPanel(),
39 m_baseBitmapSize( 0, 0 )
40{
41 // Must set background style BEFORE creating the window
42 SetBackgroundStyle( wxBG_STYLE_PAINT );
43 Create( aParent, aId );
44
45 Bind( wxEVT_PAINT, &DRC_RE_BITMAP_OVERLAY_PANEL::OnPaint, this );
46 Bind( wxEVT_DPI_CHANGED, &DRC_RE_BITMAP_OVERLAY_PANEL::OnDPIChanged, this );
47 Bind( wxEVT_SYS_COLOUR_CHANGED, &DRC_RE_BITMAP_OVERLAY_PANEL::OnThemeChange, this );
48}
49
50
54
55
56void DRC_RE_BITMAP_OVERLAY_PANEL::OnPaint( wxPaintEvent& aEvent )
57{
58 wxPaintDC dc( this );
59
60 if( !m_bitmap.IsOk() )
61 return;
62
63 dc.DrawBitmap( m_bitmap, 0, 0, true );
64}
65
66
67void DRC_RE_BITMAP_OVERLAY_PANEL::OnDPIChanged( wxDPIChangedEvent& aEvent )
68{
69 LoadBitmap();
71 Refresh();
72 aEvent.Skip();
73}
74
75
76void DRC_RE_BITMAP_OVERLAY_PANEL::OnThemeChange( wxSysColourChangedEvent& aEvent )
77{
78 LoadBitmap();
79 Refresh();
80 aEvent.Skip();
81}
82
83
85{
86 // Platform handles focus ring automatically.
87 // Could add custom highlighting here if needed.
88 aEvent.Skip();
89}
90
91
92void DRC_RE_BITMAP_OVERLAY_PANEL::OnFieldBlur( wxFocusEvent& aEvent )
93{
94 // Platform handles focus ring automatically.
95 aEvent.Skip();
96}
97
98
100{
101 if( !aControl )
102 return;
103
104 // Bind focus events to track active field
105 aControl->Bind( wxEVT_SET_FOCUS, &DRC_RE_BITMAP_OVERLAY_PANEL::OnFieldFocus, this );
106 aControl->Bind( wxEVT_KILL_FOCUS, &DRC_RE_BITMAP_OVERLAY_PANEL::OnFieldBlur, this );
107}
108
109
111{
113 return;
114
115 wxBitmapBundle bundle = KiBitmapBundle( m_bitmapId );
116
117 m_bitmap = bundle.GetBitmapFor( this );
118 m_baseBitmapSize = bundle.GetDefaultSize();
119
120 Refresh();
121}
122
123
125{
126 m_bitmapId = aBitmap;
127 LoadBitmap();
128
129 if( m_bitmap.IsOk() )
130 SetMinSize( m_baseBitmapSize );
131}
132
133
135{
136 for( const auto& field : m_fields )
137 {
138 const DRC_RE_FIELD_POSITION& pos = field->GetPosition();
139 wxControl* ctrl = field->GetControl();
140
141 if( !ctrl )
142 continue;
143
144 // Calculate scaled position and size
145 wxPoint scaledPos( pos.xStart, pos.yTop );
146 int width = pos.xEnd - pos.xStart;
147 wxSize scaledSize( width, ctrl->GetBestSize().GetHeight() );
148
149 // Check bounds
150 if( m_bitmap.IsOk() )
151 {
152 wxSize bmpSize = m_bitmap.GetSize();
153
154 if( scaledPos.x + scaledSize.GetWidth() > bmpSize.GetWidth() ||
155 scaledPos.y + scaledSize.GetHeight() > bmpSize.GetHeight() )
156 {
157 wxLogWarning( "Field '%s' position exceeds bitmap bounds", field->GetFieldId() );
158 }
159 }
160
161 ctrl->SetPosition( scaledPos );
162 ctrl->SetSize( scaledSize );
163
164 // Position label if present
165 if( field->HasLabel() )
166 PositionLabel( field.get() );
167 }
168}
169
170
172{
173 wxStaticText* label = aField->GetLabel();
174 wxControl* ctrl = aField->GetControl();
175
176 if( !label || !ctrl )
177 return;
178
179 const DRC_RE_FIELD_POSITION& pos = aField->GetPosition();
180 wxPoint ctrlPos = ctrl->GetPosition();
181 wxSize ctrlSize = ctrl->GetSize();
182 wxSize labelSize = label->GetBestSize();
183
184 wxPoint labelPos;
185 constexpr int GAP = 4;
186
187 switch( pos.labelPosition )
188 {
190 labelPos.x = ctrlPos.x - labelSize.GetWidth() - GAP;
191 labelPos.y = ctrlPos.y + ( ctrlSize.GetHeight() - labelSize.GetHeight() ) / 2;
192 break;
193
195 labelPos.x = ctrlPos.x + ctrlSize.GetWidth() + GAP;
196 labelPos.y = ctrlPos.y + ( ctrlSize.GetHeight() - labelSize.GetHeight() ) / 2;
197 break;
198
200 labelPos.x = ctrlPos.x + ( ctrlSize.GetWidth() - labelSize.GetWidth() ) / 2;
201 labelPos.y = ctrlPos.y - labelSize.GetHeight() - GAP;
202 break;
203
205 labelPos.x = ctrlPos.x + ( ctrlSize.GetWidth() - labelSize.GetWidth() ) / 2;
206 labelPos.y = ctrlPos.y + ctrlSize.GetHeight() + GAP;
207 break;
208
210 default:
211 return;
212 }
213
214 label->SetPosition( labelPos );
215}
216
217
219{
220 // Base implementation does nothing; derived classes override to populate fields
221 return true;
222}
223
224
226{
227 // Base implementation does nothing; derived classes override to read fields
228 return true;
229}
230
231
233{
234 for( const auto& field : m_fields )
235 field->ShowError( false );
236}
237
238
239void DRC_RE_BITMAP_OVERLAY_PANEL::ShowFieldError( const wxString& aFieldId )
240{
241 auto it = m_fieldIdMap.find( aFieldId );
242
243 if( it != m_fieldIdMap.end() )
244 it->second->ShowError( true );
245}
246
247
249 const DRC_RE_FIELD_POSITION& aPosition )
250{
251 wxCheckBox* checkbox = new wxCheckBox( this, wxID_ANY, wxEmptyString );
252
253 auto field = std::make_unique<DRC_RE_OVERLAY_FIELD>( this, aId, checkbox, aPosition );
254 DRC_RE_OVERLAY_FIELD* fieldPtr = field.get();
255
256 SetupFieldStyling( checkbox );
257
258 wxPoint pos( aPosition.xStart, aPosition.yTop );
259 checkbox->SetPosition( pos );
260
261 // Create label if specified
262 fieldPtr->CreateLabel();
263
264 if( fieldPtr->HasLabel() )
265 PositionLabel( fieldPtr );
266
267 m_fieldIdMap[aId] = fieldPtr;
268 m_fields.push_back( std::move( field ) );
269
270 return fieldPtr;
271}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
BITMAPS
A list of all bitmap identifiers.
@ INVALID_BITMAP
DRC_RE_OVERLAY_FIELD * AddCheckbox(const wxString &aId, const DRC_RE_FIELD_POSITION &aPosition)
Create and position a checkbox control on the bitmap overlay.
void LoadBitmap()
Load the appropriate bitmap variant for the current theme and DPI.
void OnThemeChange(wxSysColourChangedEvent &aEvent)
wxBitmap m_bitmap
Current background bitmap.
void OnDPIChanged(wxDPIChangedEvent &aEvent)
void PositionLabel(DRC_RE_OVERLAY_FIELD *aField)
Position a label relative to its field control based on the label position setting.
void ShowFieldError(const wxString &aFieldId)
Show an error indicator on the specified field.
void SetupFieldStyling(wxControl *aControl)
Apply transparent styling to a field control.
std::map< wxString, DRC_RE_OVERLAY_FIELD * > m_fieldIdMap
Field ID to field lookup.
void SetBackgroundBitmap(BITMAPS aBitmap)
Set the background bitmap for this panel.
wxSize m_baseBitmapSize
Bitmap size at 1x scale.
DRC_RE_BITMAP_OVERLAY_PANEL(wxWindow *aParent, wxWindowID aId=wxID_ANY)
void ClearFieldErrors()
Clear error indicators from all fields.
BITMAPS m_bitmapId
BITMAPS enum value.
void PositionFields()
Position all fields based on the current scale factor.
void OnFieldFocus(wxFocusEvent &aEvent)
std::vector< std::unique_ptr< DRC_RE_OVERLAY_FIELD > > m_fields
All overlay fields.
Wraps a wxControl positioned over a bitmap overlay panel.
wxStaticText * GetLabel() const
void CreateLabel()
Create and associate a label with this field.
const DRC_RE_FIELD_POSITION & GetPosition() const
wxControl * GetControl() const
@ BOTTOM
Label below the field.
@ RIGHT
Label to the right of the field.
@ TOP
Label above the field.
@ LEFT
Label to the left of the field.
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
Specifies the position and size of a field overlaid on a constraint bitmap.
LABEL_POSITION labelPosition
Position of label relative to field.
int xEnd
Right edge X coordinate where the field ends.
int xStart
Left edge X coordinate where the field starts.
int yTop
Top edge Y coordinate of the field.