KiCad PCB EDA Suite
Loading...
Searching...
No Matches
field_warning_icon.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 The 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, see <https://www.gnu.org/licenses/>.
18 */
19
20
22
23#include <algorithm>
24#include <utility>
25#include <vector>
26
27#include <bitmaps.h>
28#include <i18n_utility.h>
29#include <wx/choice.h>
30#include <wx/combo.h>
31#include <wx/combobox.h>
32#include <wx/settings.h>
33
34
36 wxGenericStaticBitmap( aField->GetParent(), wxID_ANY, KiBitmapBundle( BITMAPS::small_warning ) ),
37 m_field( aField )
38{
39 Hide();
40
41 // Without a background of its own the icon shows the page behind the field, or on some ports the text under it
42 SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
43
44 m_field->Bind( wxEVT_SIZE, &FIELD_WARNING_ICON::onFieldChanged, this );
45 m_field->Bind( wxEVT_MOVE, &FIELD_WARNING_ICON::onFieldChanged, this );
46 m_field->Bind( wxEVT_DESTROY, &FIELD_WARNING_ICON::onFieldDestroyed, this );
47}
48
49
51{
52 // The parent destroys the field first, since it was created first
53 if( m_field )
54 {
55 m_field->Unbind( wxEVT_SIZE, &FIELD_WARNING_ICON::onFieldChanged, this );
56 m_field->Unbind( wxEVT_MOVE, &FIELD_WARNING_ICON::onFieldChanged, this );
57 m_field->Unbind( wxEVT_DESTROY, &FIELD_WARNING_ICON::onFieldDestroyed, this );
58 }
59}
60
61
62void FIELD_WARNING_ICON::SetWarnings( const wxArrayString& aMessages )
63{
64 // Identical messages collapse into one line with a count, in the order they first appear
65 std::vector<std::pair<wxString, size_t>> lines;
66
67 for( const wxString& message : aMessages )
68 {
69 auto it = std::find_if( lines.begin(), lines.end(),
70 [&]( const std::pair<wxString, size_t>& aLine )
71 {
72 return aLine.first == message;
73 } );
74
75 if( it != lines.end() )
76 it->second++;
77 else
78 lines.emplace_back( message, 1 );
79 }
80
81 wxString text;
82
83 for( size_t ii = 0; ii < lines.size() && ii < MAX_LINES; ++ii )
84 {
85 if( ii > 0 )
86 text += wxS( "\n" );
87
88 text += lines[ii].first;
89
90 if( lines[ii].second > 1 )
91 text += wxString::Format( _( " (%zu times)" ), lines[ii].second );
92 }
93
94 if( lines.size() > MAX_LINES )
95 text += wxString::Format( _( "\n... and %zu more" ), lines.size() - MAX_LINES );
96
97 SetToolTip( text );
98 Show( !text.IsEmpty() );
99
100 Reposition();
101}
102
103
104void FIELD_WARNING_ICON::SetWarning( const wxString& aMessage )
105{
106 wxArrayString messages;
107
108 if( !aMessage.IsEmpty() )
109 messages.Add( aMessage );
110
111 SetWarnings( messages );
112}
113
114
116{
117 if( !m_field )
118 return;
119
120 const wxSize fieldSize = m_field->GetSize();
121 int buttonWidth = 0;
122
123 // A dropdown button is about as wide as the field is tall, except on Windows where it has the width of a
124 // scrollbar
125 if( dynamic_cast<wxComboBox*>( m_field ) || dynamic_cast<wxChoice*>( m_field )
126 || dynamic_cast<wxComboCtrl*>( m_field ) )
127 {
128#ifdef __WXMSW__
129 buttonWidth = wxSystemSettings::GetMetric( wxSYS_VSCROLL_X, m_field );
130#else
131 buttonWidth = fieldSize.y;
132#endif
133 }
134
135 const wxSize iconSize = GetSize();
136 const int gap = m_field->FromDIP( 3 );
137
138 SetPosition( m_field->GetPosition()
139 + wxPoint( fieldSize.x - buttonWidth - iconSize.x - gap, ( fieldSize.y - iconSize.y ) / 2 ) );
140 Raise();
141}
142
143
145{
146 aEvent.Skip();
147
148 // The field's new geometry is only final once the sizer is done with it
149 CallAfter(
150 [this]()
151 {
152 Reposition();
153 } );
154}
155
156
157void FIELD_WARNING_ICON::onFieldDestroyed( wxWindowDestroyEvent& aEvent )
158{
159 // Only the field's own destruction counts, not a child's that bubbles up
160 if( aEvent.GetEventObject() == m_field )
161 m_field = nullptr;
162
163 aEvent.Skip();
164}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
BITMAPS
A list of all bitmap identifiers.
static constexpr size_t MAX_LINES
The most warnings listed in the tooltip, with a count of the rest.
wxWindow * m_field
Null once the field has been destroyed.
void onFieldChanged(wxEvent &aEvent)
FIELD_WARNING_ICON(wxWindow *aField)
void Reposition()
Moves the icon back over the field after the field has moved or changed size.
void SetWarnings(const wxArrayString &aMessages)
Lists aMessages in the tooltip, once each with a count when repeated, and shows the icon,...
void SetWarning(const wxString &aMessage)
Shows aMessage as the tooltip, or hides the icon when it is empty.
void onFieldDestroyed(wxWindowDestroyEvent &aEvent)
#define _(s)
Some functions to handle hotkeys in KiCad.
std::string message