KiCad PCB EDA Suite
footprint_choice.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 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <functional>
22#include <wx/dc.h>
23#include <wx/pen.h>
24
25wxColour FOOTPRINT_CHOICE::m_grey( 0x808080 );
26
27
28FOOTPRINT_CHOICE::FOOTPRINT_CHOICE( wxWindow* aParent, int aId ) :
29 wxOwnerDrawnComboBox( aParent, aId, wxEmptyString, wxDefaultPosition, wxDefaultSize,
30 /* n */ 0, /* choices */ nullptr, wxCB_READONLY ),
31 m_last_selection( 0 )
32{
33}
34
35
37{
38}
39
40
41void FOOTPRINT_CHOICE::DoSetPopupControl( wxComboPopup* aPopup )
42{
43 using namespace std::placeholders;
44 wxOwnerDrawnComboBox::DoSetPopupControl( aPopup );
45
46 // Bind events to intercept selections, so the separator can be made nonselectable.
47
48 GetVListBoxComboPopup()->Bind( wxEVT_MOTION, &FOOTPRINT_CHOICE::TryVetoMouse, this );
49 GetVListBoxComboPopup()->Bind( wxEVT_LEFT_DOWN, &FOOTPRINT_CHOICE::TryVetoMouse, this );
50 GetVListBoxComboPopup()->Bind( wxEVT_LEFT_UP, &FOOTPRINT_CHOICE::TryVetoMouse, this );
51 GetVListBoxComboPopup()->Bind( wxEVT_LEFT_DCLICK, &FOOTPRINT_CHOICE::TryVetoMouse, this );
52 GetVListBoxComboPopup()->Bind( wxEVT_LISTBOX, std::bind( &FOOTPRINT_CHOICE::TryVetoSelect, this, _1, true ) );
53 Bind( wxEVT_COMBOBOX, std::bind( &FOOTPRINT_CHOICE::TryVetoSelect, this, _1, false ) );
54}
55
56
57void FOOTPRINT_CHOICE::OnDrawItem( wxDC& aDC, wxRect const& aRect, int aItem, int aFlags ) const
58{
59 wxString text = SafeGetString( aItem );
60
61 if( text == wxEmptyString )
62 {
63 wxPen pen( m_grey, 1, wxPENSTYLE_SOLID );
64
65 aDC.SetPen( pen );
66 aDC.DrawLine( aRect.x, aRect.y + aRect.height / 2, aRect.x + aRect.width,
67 aRect.y + aRect.height / 2 );
68 }
69 else
70 {
71 wxCoord x, y;
72
73 if( aFlags & wxODCB_PAINTING_CONTROL )
74 {
75 x = aRect.x + GetMargins().x;
76 y = ( aRect.height - aDC.GetCharHeight() ) / 2 + aRect.y;
77 }
78 else
79 {
80 x = aRect.x + 2;
81 y = aRect.y;
82 }
83
84 // If this item has a footprint and that footprint has a ":" delimiter, find the
85 // library component, then find that in the display string and grey it out.
86
87 size_t start_grey = 0;
88 size_t end_grey = 0;
89
90 wxString lib = static_cast<wxStringClientData*>( GetClientObject( aItem ) )->GetData();
91 size_t colon_index = lib.rfind( ':' );
92
93 if( colon_index != wxString::npos )
94 {
95 wxString library_part = lib.SubString( 0, colon_index );
96 size_t library_index = text.rfind( library_part );
97
98 if( library_index != wxString::npos )
99 {
100 start_grey = library_index;
101 end_grey = start_grey + library_part.Length();
102 }
103 }
104
105 if( start_grey != end_grey && !( aFlags & wxODCB_PAINTING_SELECTED ) )
106 {
107 x = DrawTextFragment( aDC, x, y, text.SubString( 0, start_grey - 1 ) );
108
109 wxColour standard_color = aDC.GetTextForeground();
110
111 aDC.SetTextForeground( m_grey );
112 x = DrawTextFragment( aDC, x, y, text.SubString( start_grey, end_grey - 1 ) );
113
114 aDC.SetTextForeground( standard_color );
115 x = DrawTextFragment( aDC, x, y, text.SubString( end_grey, text.Length() - 1 ) );
116 }
117 else
118 {
119 aDC.DrawText( text, x, y );
120 }
121 }
122}
123
124wxCoord FOOTPRINT_CHOICE::OnMeasureItem( size_t aItem ) const
125{
126 if( SafeGetString( aItem ) == "" )
127 return 11;
128 else
129 return wxOwnerDrawnComboBox::OnMeasureItem( aItem );
130}
131
132
133wxCoord FOOTPRINT_CHOICE::OnMeasureItemWidth( size_t aItem ) const
134{
135 if( SafeGetString( aItem ) == "" )
136 return GetTextRect().GetWidth() - 2;
137 else
138 return wxOwnerDrawnComboBox::OnMeasureItemWidth( aItem );
139}
140
141
142wxCoord FOOTPRINT_CHOICE::DrawTextFragment( wxDC& aDC, wxCoord x, wxCoord y, wxString const& aText )
143{
144 aDC.DrawText( aText, x, y );
145 return x + aDC.GetTextExtent( aText ).GetWidth();
146}
147
148
149void FOOTPRINT_CHOICE::TryVetoMouse( wxMouseEvent& aEvent )
150{
151 int item = GetVListBoxComboPopup()->VirtualHitTest( aEvent.GetPosition().y );
152
153 if( SafeGetString( item ) != "" )
154 aEvent.Skip();
155}
156
157
158void FOOTPRINT_CHOICE::TryVetoSelect( wxCommandEvent& aEvent, bool aInner )
159{
160 int sel = GetSelectionEither( aInner );
161
162 if( sel >= 0 && sel < (int) GetCount() )
163 {
164 wxString text = SafeGetString( sel );
165
166 if( text == "" )
167 {
169 }
170 else
171 {
172 m_last_selection = sel;
173 aEvent.Skip();
174 }
175 }
176}
177
178
179wxString FOOTPRINT_CHOICE::SafeGetString( int aItem ) const
180{
181 if( aItem >= 0 && aItem < (int) GetCount() )
182 return GetVListBoxComboPopup()->GetString( aItem );
183 else
184 return wxEmptyString;
185}
186
187
189{
190 if( aInner )
191 return GetVListBoxComboPopup()->wxVListBox::GetSelection();
192 else
193 return GetSelection();
194}
195
196
197void FOOTPRINT_CHOICE::SetSelectionEither( bool aInner, int aSel )
198{
199 if( aSel >= 0 && aSel < (int) GetCount() )
200 {
201 if( aInner )
202 return GetVListBoxComboPopup()->wxVListBox::SetSelection( aSel );
203 else
204 return SetSelection( aSel );
205 }
206}
wxString SafeGetString(int aItem) const
Safely get a string for an item, returning wxEmptyString if the item doesn't exist.
virtual wxCoord OnMeasureItem(size_t aItem) const override
void TryVetoSelect(wxCommandEvent &aEvent, bool aInner)
Veto a select event for the separator.
static wxColour m_grey
virtual ~FOOTPRINT_CHOICE()
static wxCoord DrawTextFragment(wxDC &aDC, wxCoord x, wxCoord y, const wxString &aText)
Draw a fragment of text, then return the next x coordinate to continue drawing.
void SetSelectionEither(bool aInner, int aSel)
Safely set selection for either the outer (combo box) or inner (popup) list, doing nothing for invali...
FOOTPRINT_CHOICE(wxWindow *aParent, int aId)
virtual wxCoord OnMeasureItemWidth(size_t aItem) const override
void TryVetoMouse(wxMouseEvent &aEvent)
Veto a mouseover event if in the separator.
virtual void DoSetPopupControl(wxComboPopup *aPopup) override
int GetSelectionEither(bool aInner) const
Get selection from either the outer (combo box) or inner (popup) list.
virtual void OnDrawItem(wxDC &aDC, const wxRect &aRect, int aItem, int aFlags) const override