KiCad PCB EDA Suite
bitmap_button.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) 2020 Ian McInerney <ian.s.mcinerney at ieee dot org>
5  * Copyright (C) 2020-2021 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, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <kiplatform/ui.h>
26 #include <widgets/bitmap_button.h>
27 #include <wx/button.h>
28 #include <wx/dcclient.h>
29 #include <wx/renderer.h>
30 #include <wx/settings.h>
31 
32 
33 BITMAP_BUTTON::BITMAP_BUTTON( wxWindow* aParent, wxWindowID aId, const wxPoint& aPos,
34  const wxSize& aSize, int aStyles ) :
35  wxPanel( aParent, aId, aPos, aSize, aStyles ),
36  m_buttonState( 0 ),
37  m_padding( 0 ),
38  m_acceptDraggedInClicks( false )
39 {
40  if( aSize == wxDefaultSize )
41  SetMinSize( wxButton::GetDefaultSize() );
42 
43  Bind( wxEVT_PAINT, &BITMAP_BUTTON::OnPaint, this );
44  Bind( wxEVT_LEFT_UP, &BITMAP_BUTTON::OnLeftButtonUp, this );
45  Bind( wxEVT_LEFT_DOWN, &BITMAP_BUTTON::OnLeftButtonDown, this );
46  Bind( wxEVT_LEAVE_WINDOW, &BITMAP_BUTTON::OnMouseLeave, this );
47  Bind( wxEVT_ENTER_WINDOW, &BITMAP_BUTTON::OnMouseEnter, this );
48  Bind( wxEVT_KILL_FOCUS, &BITMAP_BUTTON::OnKillFocus, this );
49  Bind( wxEVT_SET_FOCUS, &BITMAP_BUTTON::OnSetFocus, this );
50 }
51 
52 
54 {
55 }
56 
57 
58 void BITMAP_BUTTON::SetPadding( int aPadding )
59 {
60  m_padding = aPadding;
61  SetMinSize( m_unadjustedMinSize + wxSize( aPadding * 2, aPadding * 2) );
62 }
63 
64 
65 void BITMAP_BUTTON::SetBitmap( const wxBitmap& aBmp )
66 {
67  m_normalBitmap = aBmp;
68  m_unadjustedMinSize = aBmp.GetSize();
69 
70  SetMinSize( wxSize( aBmp.GetWidth() + ( m_padding * 2 ), aBmp.GetHeight() + ( m_padding * 2 ) ) );
71 }
72 
73 
74 void BITMAP_BUTTON::SetDisabledBitmap( const wxBitmap& aBmp )
75 {
76  m_disabledBitmap = aBmp;
77 }
78 
79 
80 void BITMAP_BUTTON::AcceptDragInAsClick( bool aAcceptDragIn )
81 {
82  m_acceptDraggedInClicks = aAcceptDragIn;
83 }
84 
85 
86 void BITMAP_BUTTON::OnMouseLeave( wxEvent& aEvent )
87 {
88  clearFlag( wxCONTROL_CURRENT | wxCONTROL_PRESSED );
89  Refresh();
90  aEvent.Skip();
91 }
92 
93 
94 void BITMAP_BUTTON::OnMouseEnter( wxEvent& aEvent )
95 {
96  setFlag( wxCONTROL_CURRENT );
97  Refresh();
98  aEvent.Skip();
99 }
100 
101 
102 void BITMAP_BUTTON::OnKillFocus( wxEvent& aEvent )
103 {
104  clearFlag( wxCONTROL_FOCUSED );
105  Refresh();
106  aEvent.Skip();
107 }
108 
109 
110 void BITMAP_BUTTON::OnSetFocus( wxEvent& aEvent )
111 {
112  setFlag( wxCONTROL_FOCUSED );
113  Refresh();
114  aEvent.Skip();
115 }
116 
117 
118 void BITMAP_BUTTON::OnLeftButtonUp( wxMouseEvent& aEvent )
119 {
120  // Only create a button event when the control is enabled
121  // and only accept clicks that came without prior mouse-down if configured
122  if( !hasFlag( wxCONTROL_DISABLED ) &&
123  ( m_acceptDraggedInClicks || hasFlag( wxCONTROL_PRESSED | wxCONTROL_FOCUSED ) ) )
124  {
125  wxEvtHandler* pEventHandler = GetEventHandler();
126  wxASSERT( pEventHandler );
127 
128  pEventHandler->CallAfter(
129  [=]()
130  {
131  wxCommandEvent evt( wxEVT_BUTTON, GetId() );
132  evt.SetEventObject( this );
133  GetEventHandler()->ProcessEvent( evt );
134  } );
135  }
136 
137  clearFlag( wxCONTROL_PRESSED );
138  Refresh();
139 
140  aEvent.Skip();
141 }
142 
143 
144 void BITMAP_BUTTON::OnLeftButtonDown( wxMouseEvent& aEvent )
145 {
146  setFlag( wxCONTROL_PRESSED );
147  Refresh();
148 
149  aEvent.Skip();
150 }
151 
152 
153 void BITMAP_BUTTON::OnPaint( wxPaintEvent& aEvent )
154 {
155  bool darkMode = KIPLATFORM::UI::IsDarkTheme();
156  wxColor highlightColor = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT );
157 
158  // The drawing rectangle
159  wxRect rect( wxPoint( 0, 0 ), GetSize() );
160  wxPaintDC dc( this );
161 
162  // This drawing is done so the button looks the same as an AUI toolbar button
163  if( !hasFlag( wxCONTROL_DISABLED ) )
164  {
165  if( hasFlag( wxCONTROL_PRESSED ) )
166  {
167  dc.SetPen( wxPen( highlightColor ) );
168  dc.SetBrush( wxBrush( highlightColor.ChangeLightness( darkMode ? 20 : 150 ) ) );
169  dc.DrawRectangle( rect );
170  }
171  else if( hasFlag( wxCONTROL_CURRENT | wxCONTROL_FOCUSED ) )
172  {
173  dc.SetPen( wxPen( highlightColor ) );
174  dc.SetBrush( wxBrush( highlightColor.ChangeLightness( darkMode ? 40 : 170 ) ) );
175 
176  // Checked items need a lighter hover rectangle
177  if( hasFlag( wxCONTROL_CHECKED ) )
178  dc.SetBrush( wxBrush( highlightColor.ChangeLightness( darkMode ? 50 : 180 ) ) );
179 
180  dc.DrawRectangle( rect );
181  }
182  else if( hasFlag( wxCONTROL_CHECKED ) )
183  {
184  dc.SetPen( wxPen( highlightColor ) );
185  dc.SetBrush( wxBrush( highlightColor.ChangeLightness( darkMode ? 40 : 170 ) ) );
186  dc.DrawRectangle( rect );
187  }
188  }
189 
190  const wxBitmap& bmp = hasFlag( wxCONTROL_DISABLED ) ? m_disabledBitmap : m_normalBitmap;
191 
192  // Draw the bitmap with the upper-left corner offset by the padding
193  if( bmp.IsOk() )
194  dc.DrawBitmap( bmp, m_padding, m_padding, true );
195 }
196 
197 
198 bool BITMAP_BUTTON::Enable( bool aEnable )
199 {
200  // If the requested state is already the current state, don't do anything
201  if( aEnable != hasFlag( wxCONTROL_DISABLED ) )
202  return false;
203 
204  wxPanel::Enable( aEnable );
205 
206  if( aEnable )
207  clearFlag( wxCONTROL_DISABLED );
208  else
209  setFlag( wxCONTROL_DISABLED );
210 
211  Refresh();
212 
213  return true;
214 }
215 
216 
217 void BITMAP_BUTTON::Check( bool aCheck )
218 {
219  if( aCheck )
220  setFlag( wxCONTROL_CHECKED );
221  else
222  clearFlag( wxCONTROL_CHECKED );
223 
224  Refresh();
225 }
void OnLeftButtonUp(wxMouseEvent &aEvent)
void OnMouseLeave(wxEvent &aEvent)
wxSize m_unadjustedMinSize
Accept mouse-up as click even if mouse-down happened outside of the control.
void OnMouseEnter(wxEvent &aEvent)
bool m_acceptDraggedInClicks
bool IsDarkTheme()
Determine if the desktop interface is currently using a dark theme or a light theme.
Definition: gtk/ui.cpp:31
bool Enable(bool aEnable=true) override
Enable the button.
void OnSetFocus(wxEvent &aEvent)
void setFlag(int aFlag)
Definition: bitmap_button.h:99
int m_padding
Size without the padding.
void Check(bool aCheck=true)
Check the control.
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
void clearFlag(int aFlag)
void SetPadding(int aPadding)
Set the amount of padding present on each side of the bitmap.
wxBitmap m_disabledBitmap
Current state of the button.
void OnKillFocus(wxEvent &aEvent)
void SetBitmap(const wxBitmap &aBmp)
Set the bitmap shown when the button is enabled.
wxBitmap m_normalBitmap
< Bitmap shown when button is enabled
void AcceptDragInAsClick(bool aAcceptDragIn=true)
Accept mouse-up as click even if mouse-down happened outside of the control.
BITMAP_BUTTON(wxWindow *aParent, wxWindowID aId, const wxPoint &aPos=wxDefaultPosition, const wxSize &aSize=wxDefaultSize, int aStyles=wxBORDER_NONE|wxTAB_TRAVERSAL)
void OnPaint(wxPaintEvent &aEvent)
void SetDisabledBitmap(const wxBitmap &aBmp)
Set the bitmap shown when the button is disabled.
bool hasFlag(int aFlag)
void OnLeftButtonDown(wxMouseEvent &aEvent)