KiCad PCB EDA Suite
Loading...
Searching...
No Matches
std_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) 2016 Anil8735(https://stackoverflow.com/users/3659387/anil8753)
5 * from https://stackoverflow.com/a/37274011
6 * Copyright (C) 2020-2023 Kicad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
27#include <wx/button.h>
28#include <wx/dcclient.h>
29#include <wx/menu.h>
30#include <wx/renderer.h>
31#include <wx/settings.h>
32#include <wx/textctrl.h>
33#include <wx/version.h>
34#include <kiplatform/ui.h>
35
36
37STD_BITMAP_BUTTON::STD_BITMAP_BUTTON( wxWindow* aParent, wxWindowID aId,
38 const wxBitmap& aDummyBitmap, const wxPoint& aPos,
39 const wxSize& aSize, int aStyle ) :
40 wxPanel( aParent, aId, aPos, aSize, aStyle, wxS( "StdBitmapButton" ) )
41{
42 if( aSize == wxDefaultSize )
43 {
44 wxSize defaultSize = wxButton::GetDefaultSize( aParent );
45#ifndef __WXMSW__
46 defaultSize.IncBy( 1 );
47#endif
48 SetMinSize( defaultSize );
49 }
50
51 Bind( wxEVT_PAINT, &STD_BITMAP_BUTTON::OnPaint, this );
52 Bind( wxEVT_LEFT_UP, &STD_BITMAP_BUTTON::OnLeftButtonUp, this );
53 Bind( wxEVT_LEFT_DOWN, &STD_BITMAP_BUTTON::OnLeftButtonDown, this );
54 Bind( wxEVT_KILL_FOCUS, &STD_BITMAP_BUTTON::OnKillFocus, this );
55 Bind( wxEVT_LEAVE_WINDOW, &STD_BITMAP_BUTTON::OnMouseLeave, this );
56 Bind( wxEVT_ENTER_WINDOW, &STD_BITMAP_BUTTON::OnMouseEnter, this );
57
58 Bind( wxEVT_SYS_COLOUR_CHANGED,
59 wxSysColourChangedEventHandler( STD_BITMAP_BUTTON::onThemeChanged ),
60 this );
61}
62
63
65{
66 Unbind( wxEVT_PAINT, &STD_BITMAP_BUTTON::OnPaint, this );
67 Unbind( wxEVT_LEFT_UP, &STD_BITMAP_BUTTON::OnLeftButtonUp, this );
68 Unbind( wxEVT_LEFT_DOWN, &STD_BITMAP_BUTTON::OnLeftButtonDown, this );
69 Unbind( wxEVT_KILL_FOCUS, &STD_BITMAP_BUTTON::OnKillFocus, this );
70 Unbind( wxEVT_LEAVE_WINDOW, &STD_BITMAP_BUTTON::OnMouseLeave, this );
71 Unbind( wxEVT_ENTER_WINDOW, &STD_BITMAP_BUTTON::OnMouseEnter, this );
72
73 Unbind( wxEVT_SYS_COLOUR_CHANGED,
74 wxSysColourChangedEventHandler( STD_BITMAP_BUTTON::onThemeChanged ), this );
75}
76
77
78void STD_BITMAP_BUTTON::onThemeChanged( wxSysColourChangedEvent &aEvent )
79{
80 Refresh();
81}
82
83
84void STD_BITMAP_BUTTON::SetBitmap( const wxBitmapBundle& aBmp )
85{
86 m_bitmap = aBmp;
87
88#ifndef __WXMSW__
89 wxSize size = m_bitmap.GetDefaultSize();
90
91 SetMinSize( wxSize( size.GetWidth() + 8, size.GetHeight() + 8 ) );
92#else
93 wxSize size = m_bitmap.GetPreferredBitmapSizeFor( this );
94 size.IncBy( 8 ); // padding
95
96 // Now adjust the min size but don't reduce it
97 wxSize minSize = GetMinSize();
98
99 // only change the width
100 // we want to keep the height at the original determined button height
101 // or else forms will get funny
102 // additionally we prefer to make the button square
103 if( size.GetWidth() > minSize.GetHeight() )
104 minSize.SetWidth( size.GetWidth() );
105 else
106 minSize.SetWidth( minSize.GetHeight() );
107
108 SetMinSize( minSize );
109#endif
110}
111
112
113void STD_BITMAP_BUTTON::OnKillFocus( wxFocusEvent& aEvent )
114{
115 if( m_stateButton != 0 )
116 {
117 m_stateButton = 0;
118 Refresh();
119 }
120
121 aEvent.Skip();
122}
123
124
125void STD_BITMAP_BUTTON::OnMouseLeave( wxMouseEvent& aEvent )
126{
127 if( m_stateButton != 0 )
128 {
129 m_stateButton = 0;
130 Refresh();
131 }
132
133 aEvent.Skip();
134}
135
136
137void STD_BITMAP_BUTTON::OnMouseEnter( wxMouseEvent& aEvent )
138{
139 if( m_stateButton != wxCONTROL_CURRENT )
140 {
141 m_stateButton = wxCONTROL_CURRENT;
142 Refresh();
143 }
144
145 aEvent.Skip();
146}
147
148
149void STD_BITMAP_BUTTON::OnLeftButtonUp( wxMouseEvent& aEvent )
150{
151 m_stateButton = 0;
152
153 Refresh();
154
155 wxEvtHandler* pEventHandler = GetEventHandler();
156 wxASSERT( pEventHandler );
157
158 pEventHandler->CallAfter(
159 [this]()
160 {
161 wxCommandEvent evt( wxEVT_BUTTON, GetId() );
162 evt.SetEventObject( this );
163 GetEventHandler()->ProcessEvent( evt );
164 } );
165
166 aEvent.Skip();
167}
168
169
170void STD_BITMAP_BUTTON::OnLeftButtonDown( wxMouseEvent& aEvent )
171{
172 m_stateButton = wxCONTROL_PRESSED;
173 Refresh();
174
175 aEvent.Skip();
176}
177
178
179void STD_BITMAP_BUTTON::OnPaint( wxPaintEvent& WXUNUSED( aEvent ) )
180{
181 wxPaintDC dc( this );
182 wxSize size = GetSize();
183
184#ifdef __WXMAC__
185 auto drawBackground =
186 [&]( wxRect aRect )
187 {
188 // wxWidgets doesn't have much support for dark mode on OSX; none of the
189 // system colours return the right values, nor does wxRendererNative draw
190 // the borders correctly. So we add some empirically chosen hacks here.
191
192 // NOTE: KEEP THESE HACKS IN SYNC WITH SPLIT_BUTTON
193
194 wxColor fg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT );
195 wxColor bg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
196
197 aRect.width += 1;
198 aRect.height += 1;
199
201 {
202 bg = bg.ChangeLightness( m_bIsEnable ? 130 : 120 );
203 dc.SetBrush( bg );
204 dc.SetPen( bg );
205 }
206 else
207 {
208 bg = bg.ChangeLightness( m_bIsEnable ? 200 : 160 );
209 dc.SetBrush( bg );
210 fg = fg.ChangeLightness( 180 );
211 dc.SetPen( fg );
212 }
213
214 dc.DrawRoundedRectangle( aRect, aRect.height / 4.0 );
215 };
216#endif
217
218 wxRect r1;
219 r1.x = 0;
220 r1.y = 0;
221 r1.width = size.GetWidth();
222 r1.height = size.GetHeight();
223
224#ifdef __WXMAC__
225 // wxRendereNative doesn't handle dark mode on OSX.
226 drawBackground( r1 );
227#else
228 #ifdef __WXMSW__
229 r1.width += 1;
230 #endif
231
232 wxRendererNative::Get().DrawPushButton( this, dc, r1, m_stateButton );
233#endif
234
235 if( m_bitmap.IsOk() )
236 {
237#ifndef __WXMSW__
238 wxSize bmpSize = m_bitmap.GetDefaultSize();
239#else
240 wxSize bmpSize = m_bitmap.GetPreferredBitmapSizeFor( this );
241#endif
242
243 r1.x = ( size.GetWidth() - bmpSize.GetWidth() ) / 2;
244
245 if( r1.x < 0 )
246 r1.x = 0;
247
248 r1.y += ( size.GetHeight() - bmpSize.GetHeight() ) / 2;
249
250 wxBitmap bm = m_bitmap.GetBitmapFor( this );
251
252 if( !m_bIsEnable )
253 bm.ConvertToDisabled();
254
255 dc.DrawBitmap( bm, r1.x, r1.y, true );
256 }
257}
258
259
260bool STD_BITMAP_BUTTON::Enable( bool aEnable )
261{
262 m_bIsEnable = aEnable;
263 wxPanel::Enable( m_bIsEnable );
264
265 if( m_bIsEnable && m_stateButton == wxCONTROL_DISABLED )
266 {
267 m_stateButton = 0;
268 Refresh();
269 }
270
271 if( !m_bIsEnable && m_stateButton != wxCONTROL_DISABLED )
272 {
273 m_stateButton = wxCONTROL_DISABLED;
274 Refresh();
275 }
276
277 return aEnable;
278}
void OnPaint(wxPaintEvent &WXUNUSED(aEvent))
void OnKillFocus(wxFocusEvent &aEvent)
void OnLeftButtonDown(wxMouseEvent &aEvent)
wxBitmapBundle m_bitmap
bool Enable(bool aEnable=true) override
void OnMouseEnter(wxMouseEvent &aEvent)
void SetBitmap(const wxBitmapBundle &aBmp)
void onThemeChanged(wxSysColourChangedEvent &aEvent)
STD_BITMAP_BUTTON(wxWindow *aParent, wxWindowID aId, const wxBitmap &aDummyBitmap, const wxPoint &aPos=wxDefaultPosition, const wxSize &aSize=wxDefaultSize, int aStyle=0)
void OnLeftButtonUp(wxMouseEvent &aEvent)
void OnMouseLeave(wxMouseEvent &aEvent)
const int minSize
Push and Shove router track width and via size dialog.
static const wxSize defaultSize(FRAME_T aFrameType, wxWindow *aWindow)
bool IsDarkTheme()
Determine if the desktop interface is currently using a dark theme or a light theme.
Definition: wxgtk/ui.cpp:48
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...