KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_global_edit_teardrops.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, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <algorithm>
25
26#include <widgets/unit_binder.h>
27#include <pcb_edit_frame.h>
28#include <board.h>
31#include <pcb_track.h>
32#include <pcb_group.h>
33#include <footprint.h>
34#include <teardrop/teardrop.h>
35#include <zone_filler.h>
38#include <tool/tool_manager.h>
41
42// Globals to remember filters during a session
43static wxString g_netclassFilter;
44static wxString g_netFilter;
45
46
48{
49public:
52
53protected:
54 void onSpecifiedValuesUpdateUi( wxUpdateUIEvent& event ) override
55 {
56 event.Enable( m_specifiedValues->GetValue() );
57 }
58 void onFilterUpdateUi( wxUpdateUIEvent& event ) override
59 {
60 event.Enable( !m_trackToTrack->GetValue() );
61 }
62
63 // Track-to-track teardrops always follow the document-wide settings (there are no teardrop
64 // properties on individual track segments as they're too ephemeral). Therefore we disable
65 // Set-to-specified-values when track-to-track is selected.
66 void onTrackToTrack( wxCommandEvent& event ) override
67 {
68 if( event.IsChecked() && m_specifiedValues->GetValue() )
69 {
70 m_specifiedValues->SetValue( false );
71 m_addTeardrops->SetValue( true );
72 }
73 }
74
75 // These just improve usability so that you don't have to click twice to enable a filter.
76 void OnNetclassFilterSelect( wxCommandEvent& event ) override
77 {
78 m_netclassFilterOpt->SetValue( true );
79 }
80 void OnLayerFilterSelect( wxCommandEvent& event ) override
81 {
82 m_layerFilterOpt->SetValue( true );
83 }
84 void OnNetFilterSelect( wxCommandEvent& event )
85 {
86 m_netFilterOpt->SetValue( true );
87 }
88
89 // Remove "add" terminology when updating only existing teardrops.
90 void OnExistingFilterSelect( wxCommandEvent& event ) override
91 {
92 if( event.IsChecked() )
93 {
94 m_addTeardrops->SetLabel( _( "Set teardrops to default values for shape" ) );
95 m_specifiedValues->SetLabel( _( "Set teardrops to specified values:" ) );
96 }
97 else
98 {
99 m_addTeardrops->SetLabel( _( "Add teardrops with default values for shape" ) );
100 m_specifiedValues->SetLabel( _( "Add teardrops with specified values:" ) );
101 }
102 }
103
104 void setSpecifiedParams( TEARDROP_PARAMETERS* targetParams );
105 void visitItem( BOARD_COMMIT* aCommit, BOARD_CONNECTED_ITEM* aItem,bool aSelectAlways );
106 void processItem( BOARD_COMMIT* aCommit, BOARD_CONNECTED_ITEM* aItem );
107
108 bool TransferDataToWindow() override;
109 bool TransferDataFromWindow() override;
110
111
112 void onShowBoardSetup( wxHyperlinkEvent& event ) override
113 {
114 m_parent->ShowBoardSetupDialog( _( "Teardrops" ) );
115 }
116
117 void buildFilterLists();
118
119private:
123
129};
130
131
139{
140 m_parent = aParent;
141 m_brd = m_parent->GetBoard();
142
144
148
149 m_minTrackWidthHint->SetFont( KIUI::GetStatusFont( this ).Italic() );
150
152
153 SetupStandardButtons( { { wxID_OK, _( "Apply and Close" ) },
154 { wxID_CANCEL, _( "Close" ) } } );
155
156 m_netFilter->Connect( FILTERED_ITEM_SELECTED,
158 nullptr, this );
159
161}
162
163
165{
166 g_netclassFilter = m_netclassFilter->GetStringSelection();
167 g_netFilter = m_netFilter->GetSelectedNetname();
168
169 m_netFilter->Disconnect( FILTERED_ITEM_SELECTED,
171 nullptr, this );
172}
173
174
176{
177 // Populate the net filter list with net names
178 m_netFilter->SetNetInfo( &m_brd->GetNetInfo() );
179
180 if( !m_brd->GetHighLightNetCodes().empty() )
181 m_netFilter->SetSelectedNetcode( *m_brd->GetHighLightNetCodes().begin() );
182
183 // Populate the netclass filter list with netclass names
184 wxArrayString netclassNames;
185 std::shared_ptr<NET_SETTINGS>& settings = m_brd->GetDesignSettings().m_NetSettings;
186
187 netclassNames.push_back( settings->GetDefaultNetclass()->GetName() );
188
189 for( const auto& [name, netclass] : settings->GetNetclasses() )
190 netclassNames.push_back( name );
191
192 m_netclassFilter->Set( netclassNames );
193 m_netclassFilter->SetStringSelection( m_brd->GetDesignSettings().GetCurrentNetClassName() );
194
195 // Populate the layer filter list
196 m_layerFilter->SetBoardFrame( m_parent );
197 m_layerFilter->SetLayersHotkeys( false );
198 m_layerFilter->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
199 m_layerFilter->Resync();
200 m_layerFilter->SetLayerSelection( m_parent->GetActiveLayer() );
201}
202
203
205{
206 BOARD_DESIGN_SETTINGS& bds = m_brd->GetDesignSettings();
207
212
213 m_netclassFilter->SetStringSelection( g_netclassFilter );
214 m_netFilter->SetSelectedNet( g_netFilter );
215
216 m_cbPreferZoneConnection->Set3StateValue( wxCHK_UNDETERMINED );
217 m_cbTeardropsUseNextTrack->Set3StateValue( wxCHK_UNDETERMINED );
223 m_curvedEdges->Set3StateValue( wxCHK_UNDETERMINED );
224
225 return true;
226}
227
228
230{
231 if( m_cbPreferZoneConnection->Get3StateValue() != wxCHK_UNDETERMINED )
232 targetParams->m_TdOnPadsInZones = !m_cbPreferZoneConnection->GetValue();
233
234 if( m_cbTeardropsUseNextTrack->Get3StateValue() != wxCHK_UNDETERMINED )
235 targetParams->m_AllowUseTwoTracks = m_cbTeardropsUseNextTrack->GetValue();
236
237 if( !m_teardropHDPercent.IsIndeterminate() )
238 targetParams->m_WidthtoSizeFilterRatio = m_teardropHDPercent.GetDoubleValue() / 100.0;
239
240 if( !m_teardropLenPercent.IsIndeterminate() )
241 targetParams->m_BestLengthRatio = m_teardropLenPercent.GetDoubleValue() / 100.0;
242
243 if( !m_teardropMaxLen.IsIndeterminate() )
244 targetParams->m_TdMaxLen = m_teardropMaxLen.GetIntValue();
245
246 if( !m_teardropHeightPercent.IsIndeterminate() )
247 targetParams->m_BestWidthRatio = m_teardropHeightPercent.GetDoubleValue() / 100.0;
248
249 if( !m_teardropMaxHeight.IsIndeterminate() )
250 targetParams->m_TdMaxWidth = m_teardropMaxHeight.GetIntValue();
251
252 if( m_curvedEdges->Get3StateValue() != wxCHK_UNDETERMINED )
253 targetParams->m_CurvedEdges = m_curvedEdges->GetValue();
254}
255
256
258{
259 BOARD_DESIGN_SETTINGS& brdSettings = m_brd->GetDesignSettings();
260 TEARDROP_PARAMETERS* targetParams = nullptr;
261
262 if( aItem->Type() == PCB_PAD_T )
263 targetParams = &static_cast<PAD*>( aItem )->GetTeardropParams();
264 else if( aItem->Type() == PCB_VIA_T )
265 targetParams = &static_cast<PCB_VIA*>( aItem )->GetTeardropParams();
266 else
267 return;
268
269 aCommit->Stage( aItem, CHT_MODIFY );
270
271 if( m_removeTeardrops->GetValue() || m_removeAllTeardrops->GetValue() )
272 {
273 targetParams->m_Enabled = false;
274 }
275 else if( m_addTeardrops->GetValue() )
276 {
277 // NOTE: This ignores possible padstack shape variation.
279 *targetParams = *brdSettings.GetTeadropParamsList()->GetParameters( TARGET_ROUND );
280 else
281 *targetParams = *brdSettings.GetTeadropParamsList()->GetParameters( TARGET_RECT );
282
283 targetParams->m_Enabled = true;
284 }
285 else if( m_specifiedValues->GetValue() )
286 {
287 setSpecifiedParams( targetParams );
288
289 if( !m_existingFilter->GetValue() )
290 targetParams->m_Enabled = true;
291 }
292}
293
294
296 bool aSelectAlways )
297{
298 if( m_selectedItemsFilter->GetValue() )
299 {
300 if( !aItem->IsSelected() )
301 {
302 EDA_GROUP* group = aItem->GetParentGroup();
303
304 while( group && !group->AsEdaItem()->IsSelected() )
305 group = group->AsEdaItem()->GetParentGroup();
306
307 if( !group )
308 return;
309 }
310 }
311
312 if( aSelectAlways )
313 {
314 processItem( aCommit, aItem );
315 return;
316 }
317
318
319 if( m_netFilterOpt->GetValue() && m_netFilter->GetSelectedNetcode() >= 0 )
320 {
321 if( aItem->GetNetCode() != m_netFilter->GetSelectedNetcode() )
322 return;
323 }
324
325 if( m_netclassFilterOpt->GetValue() && !m_netclassFilter->GetStringSelection().IsEmpty() )
326 {
327 wxString filterNetclass = m_netclassFilter->GetStringSelection();
328 NETCLASS* netclass = aItem->GetEffectiveNetClass();
329
330 if( !netclass->ContainsNetclassWithName( filterNetclass ) )
331 return;
332 }
333
334 if( m_layerFilterOpt->GetValue() && m_layerFilter->GetLayerSelection() != UNDEFINED_LAYER )
335 {
336 if( aItem->GetLayer() != m_layerFilter->GetLayerSelection() )
337 return;
338 }
339
340 if( m_roundPadsFilter->GetValue() )
341 {
342 // TODO(JE) padstacks -- teardrops needs to support per-layer pad handling
344 return;
345 }
346
347 if( m_existingFilter->GetValue() )
348 {
349 if( aItem->Type() == PCB_PAD_T )
350 {
351 if( !static_cast<PAD*>( aItem )->GetTeardropParams().m_Enabled )
352 return;
353 }
354 else if( aItem->Type() == PCB_VIA_T )
355 {
356 if( !static_cast<PCB_VIA*>( aItem )->GetTeardropParams().m_Enabled )
357 return;
358 }
359 }
360
361 processItem( aCommit, aItem );
362}
363
364
366{
367 m_brd->SetLegacyTeardrops( false );
368
369 BOARD_COMMIT commit( m_parent );
370 wxBusyCursor dummy;
371
372 // Save some dialog options
373 BOARD_DESIGN_SETTINGS& bds = m_brd->GetDesignSettings();
374
375 bds.m_TeardropParamsList.m_TargetVias = m_vias->GetValue();
380
381 bool remove_all = m_removeAllTeardrops->GetValue();
382
383 if( m_vias->GetValue() || remove_all )
384 {
385 for( PCB_TRACK* track : m_brd->Tracks() )
386 {
387 if ( track->Type() == PCB_VIA_T )
388 visitItem( &commit, track, remove_all );
389 }
390 }
391
392 for( FOOTPRINT* footprint : m_brd->Footprints() )
393 {
394 for( PAD* pad : footprint->Pads() )
395 {
396 if( remove_all )
397 {
398 visitItem( &commit, pad, true );
399 continue;
400 }
401
402 if( m_pthPads->GetValue() && pad->GetAttribute() == PAD_ATTRIB::PTH )
403 {
404 visitItem( &commit, pad, false );
405 }
406 else if( m_smdPads->GetValue() && ( pad->GetAttribute() == PAD_ATTRIB::SMD
407 || pad->GetAttribute() == PAD_ATTRIB::CONN ) )
408 {
409 visitItem( &commit, pad, false );
410 }
411 }
412 }
413
414 if( m_trackToTrack->GetValue() )
415 {
416 TEARDROP_PARAMETERS_LIST* paramsList = m_brd->GetDesignSettings().GetTeadropParamsList();
417 TEARDROP_PARAMETERS* targetParams = paramsList->GetParameters( TARGET_TRACK );
418 TEARDROP_MANAGER teardropManager( m_brd, m_parent->GetToolManager() );
419
420 teardropManager.DeleteTrackToTrackTeardrops( commit );
421 teardropManager.BuildTrackCaches();
422
423 if( m_removeTeardrops->GetValue() || m_removeAllTeardrops->GetValue() )
424 {
425 targetParams->m_Enabled = false;
426 }
427 else if( m_addTeardrops->GetValue() )
428 {
429 targetParams->m_Enabled = true;
430 teardropManager.AddTeardropsOnTracks( commit, nullptr, true );
431 }
432 }
433
434 // If there are no filters then a force-full-update is equivalent, and will be faster.
435 if( !m_netFilterOpt->GetValue()
436 && !m_netclassFilterOpt->GetValue()
437 && !m_layerFilterOpt->GetValue()
438 && !m_roundPadsFilter->GetValue()
439 && !m_existingFilter->GetValue()
440 && !m_selectedItemsFilter->GetValue() )
441 {
442 commit.Push( _( "Edit Teardrops" ), SKIP_TEARDROPS );
443
444 TEARDROP_MANAGER teardropMgr( m_brd, m_parent->GetToolManager() );
445 teardropMgr.UpdateTeardrops( commit, nullptr, nullptr, true /* forceFullUpdate */ );
446 commit.Push( _( "Edit Teardrops" ), SKIP_TEARDROPS | APPEND_UNDO );
447 }
448 else
449 {
450 commit.Push( _( "Edit Teardrops" ) );
451 }
452
453 // Showing the unfilled, fully cross-hatched teardrops seems to be working fairly well, and
454 // accurate fills can then be manually generated by doing a zone fill.
455 //
456 // But here's the old code which allowed for either "draft" fills or an automatic full zone
457 // fill in case we decide the current situation isn't good enough:
458#if 0
459 if( aFillAfter )
460 {
461 ZONE_FILLER filler( m_board, aCommit );
462
463 if( m_reporter )
464 filler.SetProgressReporter( m_reporter );
465
466 filler.Fill( m_board->Zones() );
467
468 if( aCommit )
469 aCommit->Push( _( "Edit Teardrops" ), APPEND_UNDO );
470 }
471 else
472 {
473 // Fill raw teardrop shapes. This is a rough calculation, just to show a filled
474 // shape on screen without the (potentially large) performance hit of a zone refill
475 int epsilon = pcbIUScale.mmToIU( 0.001 );
476 int allowed_error = pcbIUScale.mmToIU( 0.005 );
477
478 for( ZONE* zone: m_createdTdList )
479 {
480 int half_min_width = zone->GetMinThickness() / 2;
481 int numSegs = GetArcToSegmentCount( half_min_width, allowed_error, FULL_CIRCLE );
482 SHAPE_POLY_SET filledPolys = *zone->Outline();
483
484 filledPolys.Deflate( half_min_width - epsilon, numSegs );
485
486 // Re-inflate after pruning of areas that don't meet minimum-width criteria
487 if( half_min_width - epsilon > epsilon )
488 filledPolys.Inflate( half_min_width - epsilon, numSegs );
489
490 zone->SetFilledPolysList( zone->GetFirstLayer(), filledPolys );
491 }
492 }
493#endif
494
495 m_parent->Refresh();
496 return true;
497}
498
499
501{
503 DIALOG_GLOBAL_EDIT_TEARDROPS dlg( editFrame );
504
505 dlg.ShowQuasiModal(); // QuasiModal required for NET_SELECTOR
506 return 0;
507}
508
const char * name
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
#define SKIP_TEARDROPS
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE) override
Add a change of the item aItem of type aChangeType to the change list.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Container for design settings for a BOARD object.
TEARDROP_PARAMETERS_LIST * GetTeadropParamsList()
TEARDROP_PARAMETERS_LIST m_TeardropParamsList
The parameters of teardrops for the different teardrop targets (via/pad, track end).
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
DIALOG_GLOBAL_EDIT_TEARDROPS_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Set Teardrops"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
void processItem(BOARD_COMMIT *aCommit, BOARD_CONNECTED_ITEM *aItem)
void visitItem(BOARD_COMMIT *aCommit, BOARD_CONNECTED_ITEM *aItem, bool aSelectAlways)
void OnNetFilterSelect(wxCommandEvent &event)
void setSpecifiedParams(TEARDROP_PARAMETERS *targetParams)
void OnNetclassFilterSelect(wxCommandEvent &event) override
DIALOG_GLOBAL_EDIT_TEARDROPS(PCB_EDIT_FRAME *aParent)
void onTrackToTrack(wxCommandEvent &event) override
void onSpecifiedValuesUpdateUi(wxUpdateUIEvent &event) override
void OnExistingFilterSelect(wxCommandEvent &event) override
void onShowBoardSetup(wxHyperlinkEvent &event) override
void onFilterUpdateUi(wxUpdateUIEvent &event) override
void OnLayerFilterSelect(wxCommandEvent &event) override
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:46
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:117
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:111
bool IsSelected() const
Definition eda_item.h:128
int EditTeardrops(const TOOL_EVENT &aEvent)
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition lset.cpp:627
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:45
bool ContainsNetclassWithName(const wxString &netclass) const
Determines if the given netclass name is a constituent of this (maybe aggregate) netclass.
Definition netclass.cpp:284
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:177
Definition pad.h:55
The main frame for Pcbnew.
Represent a set of closed polygons.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
TEARDROP_MANAGER manage and build teardrop areas A teardrop area is a polygonal area (a copper ZONE) ...
Definition teardrop.h:95
static bool IsRound(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer)
void UpdateTeardrops(BOARD_COMMIT &aCommit, const std::vector< BOARD_ITEM * > *dirtyPadsAndVias, const std::set< PCB_TRACK * > *dirtyTracks, bool aForceFullUpdate=false)
Update teardrops on a list of items.
Definition teardrop.cpp:230
void AddTeardropsOnTracks(BOARD_COMMIT &aCommit, const std::set< PCB_TRACK * > *aTracks, bool aForceFullUpdate=false)
Add teardrop on tracks of different sizes connected by their end.
Definition teardrop.cpp:429
void DeleteTrackToTrackTeardrops(BOARD_COMMIT &aCommit)
Definition teardrop.cpp:377
TEARDROP_PARAMETERS_LIST is a helper class to handle the list of TEARDROP_PARAMETERS needed to build ...
bool m_UseRoundShapesOnly
True to create teardrops for round shapes only.
bool m_TargetVias
True to create teardrops for vias.
bool m_TargetPTHPads
True to create teardrops for pads with holes.
bool m_TargetTrack2Track
True to create teardrops at the end of a track connected to the end of another track having a differe...
TEARDROP_PARAMETERS * GetParameters(TARGET_TD aTdType)
bool m_TargetSMDPads
True to create teardrops for pads SMD, edge connectors,.
TEARDROP_PARAMETARS is a helper class to handle parameters needed to build teardrops for a board thes...
double m_BestWidthRatio
The height of a teardrop as ratio between height and size of pad/via.
int m_TdMaxLen
max allowed length for teardrops in IU. <= 0 to disable
bool m_AllowUseTwoTracks
True to create teardrops using 2 track segments if the first in too small.
int m_TdMaxWidth
max allowed height for teardrops in IU. <= 0 to disable
double m_BestLengthRatio
The length of a teardrop as ratio between length and size of pad/via.
double m_WidthtoSizeFilterRatio
The ratio (H/D) between the via/pad size and the track width max value to create a teardrop 1....
bool m_TdOnPadsInZones
A filter to exclude pads inside zone fills.
bool m_Enabled
Flag to enable teardrops.
bool m_CurvedEdges
True if the teardrop should be curved.
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:186
Generic, UI-independent tool event.
Definition tool_event.h:171
void SetProgressReporter(PROGRESS_REPORTER *aReporter)
bool Fill(const std::vector< ZONE * > &aZones, bool aCheck=false, wxWindow *aParent=nullptr)
Fills the given list of zones.
Handle a list of polygons defining a copper zone.
Definition zone.h:73
@ CHT_MODIFY
Definition commit.h:44
static wxString g_netclassFilter
static wxString g_netFilter
#define _(s)
static constexpr EDA_ANGLE FULL_CIRCLE
Definition eda_angle.h:409
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
@ UNDEFINED_LAYER
Definition layer_ids.h:61
KICOMMON_API wxFont GetStatusFont(wxWindow *aWindow)
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:99
@ PTH
Plated through hole pad.
Definition padstack.h:98
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:100
Class to handle a set of BOARD_ITEMs.
const double epsilon
#define APPEND_UNDO
Definition sch_commit.h:41
std::vector< FAB_LAYER_COLOR > dummy
@ TARGET_ROUND
@ TARGET_RECT
@ TARGET_TRACK
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:87
#define INDETERMINATE_ACTION
Definition ui_common.h:47