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 
25 wxColour FOOTPRINT_CHOICE::m_grey( 0x808080 );
26 
27 
28 FOOTPRINT_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 
41 void 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 
57 void 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 
124 wxCoord 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 
133 wxCoord 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 
142 wxCoord 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 
149 void 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 
158 void 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 
179 wxString 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 
188 int FOOTPRINT_CHOICE::GetSelectionEither( bool aInner ) const
189 {
190  if( aInner )
191  return GetVListBoxComboPopup()->wxVListBox::GetSelection();
192  else
193  return GetSelection();
194 }
195 
196 
197 void 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 }
virtual wxCoord OnMeasureItem(size_t aItem) const override
wxString SafeGetString(int aItem) const
Safely get a string for an item, returning wxEmptyString if the item doesn't exist.
virtual void DoSetPopupControl(wxComboPopup *aPopup) override
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.
virtual ~FOOTPRINT_CHOICE()
FOOTPRINT_CHOICE(wxWindow *aParent, int aId)
void TryVetoMouse(wxMouseEvent &aEvent)
Veto a mouseover event if in the separator.
virtual wxCoord OnMeasureItemWidth(size_t aItem) const override
void TryVetoSelect(wxCommandEvent &aEvent, bool aInner)
Veto a select event for the separator.
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
void SetSelectionEither(bool aInner, int aSel)
Safely set selection for either the outer (combo box) or inner (popup) list, doing nothing for invali...
static wxColour m_grey