mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2024-11-22 00:35:00 +00:00
457 lines
11 KiB
C++
457 lines
11 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2020 Ian McInerney <ian.s.mcinerney@ieee.org>
|
|
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation, either version 3 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <id.h>
|
|
#include <kiplatform/ui.h>
|
|
#include <widgets/wx_infobar.h>
|
|
#include "wx/artprov.h"
|
|
#include <wx/aui/framemanager.h>
|
|
#include <wx/debug.h>
|
|
#include <wx/infobar.h>
|
|
#include <wx/sizer.h>
|
|
#include <wx/timer.h>
|
|
#include <wx/hyperlink.h>
|
|
#include <wx/bmpbuttn.h>
|
|
#include <eda_base_frame.h>
|
|
|
|
#ifdef __WXMSW__
|
|
#include <dpi_scaling_common.h>
|
|
#endif
|
|
|
|
|
|
wxDEFINE_EVENT( KIEVT_SHOW_INFOBAR, wxCommandEvent );
|
|
wxDEFINE_EVENT( KIEVT_DISMISS_INFOBAR, wxCommandEvent );
|
|
|
|
BEGIN_EVENT_TABLE( WX_INFOBAR, wxInfoBarGeneric )
|
|
EVT_COMMAND( wxID_ANY, KIEVT_SHOW_INFOBAR, WX_INFOBAR::onShowInfoBar )
|
|
EVT_COMMAND( wxID_ANY, KIEVT_DISMISS_INFOBAR, WX_INFOBAR::onDismissInfoBar )
|
|
|
|
EVT_BUTTON( ID_CLOSE_INFOBAR, WX_INFOBAR::onCloseButton )
|
|
EVT_TIMER( ID_CLOSE_INFOBAR, WX_INFOBAR::onTimer )
|
|
END_EVENT_TABLE()
|
|
|
|
|
|
WX_INFOBAR::WX_INFOBAR( wxWindow* aParent, wxAuiManager* aMgr, wxWindowID aWinid )
|
|
: wxInfoBarGeneric( aParent, aWinid ),
|
|
m_showTime( 0 ),
|
|
m_updateLock( false ),
|
|
m_showTimer( nullptr ),
|
|
m_auiManager( aMgr ),
|
|
m_type( MESSAGE_TYPE::GENERIC )
|
|
{
|
|
m_showTimer = new wxTimer( this, ID_CLOSE_INFOBAR );
|
|
|
|
#ifdef __WXMAC__
|
|
// wxWidgets hard-codes wxSYS_COLOUR_INFOBK to { 0xFF, 0xFF, 0xD3 } on Mac.
|
|
if( KIPLATFORM::UI::IsDarkTheme() )
|
|
SetBackgroundColour( wxColour( 28, 27, 20 ) );
|
|
else
|
|
SetBackgroundColour( wxColour( 255, 249, 189 ) );
|
|
|
|
// Infobar is broken on Mac without the effects
|
|
SetShowHideEffects( wxSHOW_EFFECT_ROLL_TO_BOTTOM, wxSHOW_EFFECT_ROLL_TO_TOP );
|
|
SetEffectDuration( 200 );
|
|
#else
|
|
// Infobar freezes canvas on Windows with the effect, and GTK looks bad with it
|
|
SetShowHideEffects( wxSHOW_EFFECT_NONE, wxSHOW_EFFECT_NONE );
|
|
#endif
|
|
|
|
|
|
// The infobar seems to start too small, so increase its height
|
|
int sx, sy;
|
|
GetSize( &sx, &sy );
|
|
sy = 1.5 * sy;
|
|
|
|
// The bitmap gets cutoff sometimes with the default size, so force it to be the same
|
|
// height as the infobar.
|
|
wxSizer* sizer = GetSizer();
|
|
wxSize iconSize = wxArtProvider::GetSizeHint( wxART_BUTTON );
|
|
|
|
#ifdef __WXMSW__
|
|
DPI_SCALING_COMMON dpi( nullptr, aParent );
|
|
iconSize.x *= dpi.GetContentScaleFactor();
|
|
sx *= dpi.GetContentScaleFactor();
|
|
sy *= dpi.GetContentScaleFactor();
|
|
#endif
|
|
|
|
SetSize( sx, sy );
|
|
|
|
sizer->SetItemMinSize( (size_t) 0, iconSize.x, sy );
|
|
|
|
// Forcefully remove all existing buttons added by the wx constructors.
|
|
// The default close button doesn't work with the AUI manager update scheme, so this
|
|
// ensures any close button displayed is ours.
|
|
RemoveAllButtons();
|
|
|
|
Layout();
|
|
|
|
m_parent->Bind( wxEVT_SIZE, &WX_INFOBAR::onSize, this );
|
|
}
|
|
|
|
|
|
WX_INFOBAR::~WX_INFOBAR()
|
|
{
|
|
delete m_showTimer;
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::SetShowTime( int aTime )
|
|
{
|
|
m_showTime = aTime;
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::QueueShowMessage( const wxString& aMessage, int aFlags )
|
|
{
|
|
wxCommandEvent* evt = new wxCommandEvent( KIEVT_SHOW_INFOBAR );
|
|
|
|
evt->SetString( aMessage.c_str() );
|
|
evt->SetInt( aFlags );
|
|
|
|
GetEventHandler()->QueueEvent( evt );
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::QueueDismiss()
|
|
{
|
|
wxCommandEvent* evt = new wxCommandEvent( KIEVT_DISMISS_INFOBAR );
|
|
|
|
GetEventHandler()->QueueEvent( evt );
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::ShowMessageFor( const wxString& aMessage, int aTime, int aFlags,
|
|
MESSAGE_TYPE aType )
|
|
{
|
|
// Don't do anything if we requested the UI update
|
|
if( m_updateLock )
|
|
return;
|
|
|
|
m_showTime = aTime;
|
|
ShowMessage( aMessage, aFlags );
|
|
|
|
m_type = aType;
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::ShowMessage( const wxString& aMessage, int aFlags )
|
|
{
|
|
// Don't do anything if we requested the UI update
|
|
if( m_updateLock )
|
|
return;
|
|
|
|
m_updateLock = true;
|
|
|
|
wxString msg = aMessage;
|
|
msg.Trim();
|
|
|
|
wxInfoBarGeneric::ShowMessage( msg, aFlags );
|
|
|
|
if( m_auiManager )
|
|
updateAuiLayout( true );
|
|
|
|
if( m_showTime > 0 )
|
|
m_showTimer->StartOnce( m_showTime );
|
|
|
|
m_type = MESSAGE_TYPE::GENERIC;
|
|
m_updateLock = false;
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::ShowMessage( const wxString& aMessage, int aFlags, MESSAGE_TYPE aType )
|
|
{
|
|
// Don't do anything if we requested the UI update
|
|
if( m_updateLock )
|
|
return;
|
|
|
|
ShowMessage( aMessage, aFlags );
|
|
|
|
m_type = aType;
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::Dismiss()
|
|
{
|
|
if( !IsShownOnScreen() )
|
|
return;
|
|
|
|
// Don't do anything if we requested the UI update
|
|
if( m_updateLock )
|
|
return;
|
|
|
|
m_updateLock = true;
|
|
|
|
wxInfoBarGeneric::Dismiss();
|
|
|
|
if( m_auiManager )
|
|
updateAuiLayout( false );
|
|
|
|
if( m_callback )
|
|
(*m_callback)();
|
|
|
|
m_updateLock = false;
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::onSize( wxSizeEvent& aEvent )
|
|
{
|
|
int barWidth = GetSize().GetWidth();
|
|
|
|
// Calculate the horizontal size: because the infobar is shown on top of the draw canvas
|
|
// it is adjusted to the canvas width.
|
|
// On Mac, the canvas is the parent
|
|
// On other OS the parent is EDA_BASE_FRAME that contains the canvas
|
|
int parentWidth = m_parent->GetClientSize().GetWidth();
|
|
EDA_BASE_FRAME* frame = dynamic_cast<EDA_BASE_FRAME*>( m_parent );
|
|
|
|
if( frame && frame->GetToolCanvas() )
|
|
parentWidth = frame->GetToolCanvas()->GetSize().GetWidth();
|
|
|
|
|
|
if( barWidth != parentWidth )
|
|
SetSize( parentWidth, GetSize().GetHeight() );
|
|
|
|
aEvent.Skip();
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::updateAuiLayout( bool aShow )
|
|
{
|
|
wxASSERT( m_auiManager );
|
|
|
|
wxAuiPaneInfo& pane = m_auiManager->GetPane( this );
|
|
|
|
// If the infobar is in a pane, then show/hide the pane
|
|
if( pane.IsOk() )
|
|
{
|
|
if( aShow )
|
|
pane.Show();
|
|
else
|
|
pane.Hide();
|
|
}
|
|
|
|
// Update the AUI manager regardless
|
|
m_auiManager->Update();
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::AddButton( wxWindowID aId, const wxString& aLabel )
|
|
{
|
|
wxButton* button = new wxButton( this, aId, aLabel );
|
|
|
|
AddButton( button );
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::AddButton( wxButton* aButton )
|
|
{
|
|
wxSizer* sizer = GetSizer();
|
|
|
|
wxASSERT( aButton );
|
|
|
|
#ifdef __WXMAC__
|
|
// Based on the code in the original class:
|
|
// smaller buttons look better in the (narrow) info bar under OS X
|
|
aButton->SetWindowVariant( wxWINDOW_VARIANT_SMALL );
|
|
#endif // __WXMAC__
|
|
sizer->Add( aButton, wxSizerFlags().Centre().Border( wxRIGHT ) );
|
|
|
|
if( IsShownOnScreen() )
|
|
sizer->Layout();
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::AddButton( wxHyperlinkCtrl* aHypertextButton )
|
|
{
|
|
wxSizer* sizer = GetSizer();
|
|
|
|
wxASSERT( aHypertextButton );
|
|
|
|
sizer->Add( aHypertextButton, wxSizerFlags().Centre().Border( wxRIGHT ) );
|
|
|
|
if( IsShownOnScreen() )
|
|
sizer->Layout();
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::AddCloseButton( const wxString& aTooltip )
|
|
{
|
|
wxBitmapButton* button = wxBitmapButton::NewCloseButton( this, ID_CLOSE_INFOBAR );
|
|
|
|
button->SetToolTip( aTooltip );
|
|
|
|
AddButton( button );
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::RemoveAllButtons()
|
|
{
|
|
wxSizer* sizer = GetSizer();
|
|
|
|
if( sizer->GetItemCount() == 0 )
|
|
return;
|
|
|
|
// The last item is already the spacer
|
|
if( sizer->GetItem( sizer->GetItemCount() - 1 )->IsSpacer() )
|
|
return;
|
|
|
|
for( int i = sizer->GetItemCount() - 1; i >= 0; i-- )
|
|
{
|
|
wxSizerItem* sItem = sizer->GetItem( i );
|
|
|
|
// The spacer is the end of the custom buttons
|
|
if( sItem->IsSpacer() )
|
|
break;
|
|
|
|
delete sItem->GetWindow();
|
|
}
|
|
}
|
|
|
|
|
|
bool WX_INFOBAR::HasCloseButton() const
|
|
{
|
|
wxSizer* sizer = GetSizer();
|
|
|
|
if( sizer->GetItemCount() == 0 )
|
|
return false;
|
|
|
|
if( sizer->GetItem( sizer->GetItemCount() - 1 )->IsSpacer() )
|
|
return false;
|
|
|
|
wxSizerItem* item = sizer->GetItem( sizer->GetItemCount() - 1 );
|
|
|
|
return ( item->GetWindow()->GetId() == ID_CLOSE_INFOBAR );
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::onShowInfoBar( wxCommandEvent& aEvent )
|
|
{
|
|
RemoveAllButtons();
|
|
AddCloseButton();
|
|
ShowMessage( aEvent.GetString(), aEvent.GetInt() );
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::onDismissInfoBar( wxCommandEvent& aEvent )
|
|
{
|
|
Dismiss();
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::onCloseButton( wxCommandEvent& aEvent )
|
|
{
|
|
Dismiss();
|
|
}
|
|
|
|
|
|
void WX_INFOBAR::onTimer( wxTimerEvent& aEvent )
|
|
{
|
|
// Reset and clear the timer
|
|
m_showTimer->Stop();
|
|
m_showTime = 0;
|
|
|
|
Dismiss();
|
|
}
|
|
|
|
|
|
EDA_INFOBAR_PANEL::EDA_INFOBAR_PANEL( wxWindow* aParent, wxWindowID aId, const wxPoint& aPos,
|
|
const wxSize& aSize, long aStyle, const wxString& aName )
|
|
: wxPanel( aParent, aId, aPos, aSize, aStyle, aName )
|
|
{
|
|
m_mainSizer = new wxFlexGridSizer( 1, 0, 0 );
|
|
|
|
m_mainSizer->SetFlexibleDirection( wxBOTH );
|
|
m_mainSizer->AddGrowableCol( 0, 1 );
|
|
|
|
SetSizer( m_mainSizer );
|
|
}
|
|
|
|
|
|
void EDA_INFOBAR_PANEL::AddInfoBar( WX_INFOBAR* aInfoBar )
|
|
{
|
|
wxASSERT( aInfoBar );
|
|
|
|
aInfoBar->Reparent( this );
|
|
m_mainSizer->Add( aInfoBar, 1, wxEXPAND, 0 );
|
|
m_mainSizer->Layout();
|
|
}
|
|
|
|
|
|
void EDA_INFOBAR_PANEL::AddOtherItem( wxWindow* aOtherItem )
|
|
{
|
|
wxASSERT( aOtherItem );
|
|
|
|
aOtherItem->Reparent( this );
|
|
m_mainSizer->Add( aOtherItem, 1, wxEXPAND, 0 );
|
|
|
|
m_mainSizer->AddGrowableRow( 1, 1 );
|
|
m_mainSizer->Layout();
|
|
}
|
|
|
|
|
|
REPORTER& INFOBAR_REPORTER::Report( const wxString& aText, SEVERITY aSeverity )
|
|
{
|
|
m_message.reset( new wxString( aText ) );
|
|
m_severity = aSeverity;
|
|
m_messageSet = true;
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
bool INFOBAR_REPORTER::HasMessage() const
|
|
{
|
|
return m_message && !m_message->IsEmpty();
|
|
}
|
|
|
|
|
|
void INFOBAR_REPORTER::Finalize()
|
|
{
|
|
// Don't do anything if no message was ever given
|
|
if( !m_infoBar || !m_messageSet )
|
|
return;
|
|
|
|
// Short circuit if the message is empty and it is already hidden
|
|
if( !HasMessage() && !m_infoBar->IsShownOnScreen() )
|
|
return;
|
|
|
|
int icon = wxICON_NONE;
|
|
|
|
switch( m_severity )
|
|
{
|
|
case RPT_SEVERITY_UNDEFINED: icon = wxICON_INFORMATION; break;
|
|
case RPT_SEVERITY_INFO: icon = wxICON_INFORMATION; break;
|
|
case RPT_SEVERITY_EXCLUSION: icon = wxICON_WARNING; break;
|
|
case RPT_SEVERITY_ACTION: icon = wxICON_WARNING; break;
|
|
case RPT_SEVERITY_WARNING: icon = wxICON_WARNING; break;
|
|
case RPT_SEVERITY_ERROR: icon = wxICON_ERROR; break;
|
|
case RPT_SEVERITY_IGNORE: icon = wxICON_INFORMATION; break;
|
|
case RPT_SEVERITY_DEBUG: icon = wxICON_INFORMATION; break;
|
|
}
|
|
|
|
if( m_message->EndsWith( wxS( "\n" ) ) )
|
|
*m_message = m_message->Left( m_message->Length() - 1 );
|
|
|
|
if( HasMessage() )
|
|
m_infoBar->QueueShowMessage( *m_message, icon );
|
|
else
|
|
m_infoBar->QueueDismiss();
|
|
}
|