diff --git a/LiteEditor/cl_editor.cpp b/LiteEditor/cl_editor.cpp index 2237d83ca8..baa0a325bb 100644 --- a/LiteEditor/cl_editor.cpp +++ b/LiteEditor/cl_editor.cpp @@ -35,6 +35,7 @@ #include "buildtabsettingsdata.h" #include "cc_box_tip_window.h" #include "clEditorStateLocker.h" +#include "clIdleEventThrottler.hpp" #include "clPrintout.h" #include "clResizableTooltip.h" #include "clSFTPManager.hpp" @@ -6515,17 +6516,13 @@ void clEditor::OnIdle(wxIdleEvent& event) } event.Skip(); - std::chrono::milliseconds ms = - std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); - // We allow IDLE event once in 100ms - uint64_t current_ts = ms.count(); - if ((current_ts - m_lastIdleEvent) < 250) { + // The internval between idle events can not be under 250ms + static clIdleEventThrottler event_throttler{ 250 }; + if (!event_throttler.CanHandle()) { return; } - m_lastIdleEvent = current_ts; - if (m_scrollbar_recalc_is_required) { m_scrollbar_recalc_is_required = false; RecalcHorizontalScrollbar(); diff --git a/LiteEditor/mainbook.cpp b/LiteEditor/mainbook.cpp index f1c7e9ca70..fd9c216f8b 100644 --- a/LiteEditor/mainbook.cpp +++ b/LiteEditor/mainbook.cpp @@ -27,6 +27,7 @@ #include "FilesModifiedDlg.h" #include "NotebookNavigationDlg.h" #include "WelcomePage.h" +#include "clIdleEventThrottler.hpp" #include "clImageViewer.h" #include "clWorkspaceManager.h" #include "cl_defs.h" @@ -1785,6 +1786,12 @@ void MainBook::OnIdle(wxIdleEvent& event) { event.Skip(); + // The internval between idle events can not be under 200ms + static clIdleEventThrottler event_throttler{ 200 }; + if (!event_throttler.CanHandle()) { + return; + } + // avoid processing if not really needed if (!m_initDone || (m_book->GetPageCount() == 0)) { return; diff --git a/Plugin/clButtonBase.cpp b/Plugin/clButtonBase.cpp index 351423af93..50af6ad604 100644 --- a/Plugin/clButtonBase.cpp +++ b/Plugin/clButtonBase.cpp @@ -1,5 +1,6 @@ #include "clButtonBase.h" +#include "clIdleEventThrottler.hpp" #include "clSystemSettings.h" #include @@ -94,7 +95,7 @@ bool clButtonBase::Create(wxWindow* parent, wxWindowID id, const wxString& label wxUnusedVar(name); wxUnusedVar(validator); m_buttonStyle = style; - if(!wxControl::Create(parent, id, pos, size, wxTAB_TRAVERSAL | wxNO_BORDER | wxWANTS_CHARS)) { + if (!wxControl::Create(parent, id, pos, size, wxTAB_TRAVERSAL | wxNO_BORDER | wxWANTS_CHARS)) { return false; } SetText(label); @@ -156,7 +157,7 @@ void clButtonBase::OnErasebg(wxEraseEvent& event) { wxUnusedVar(event); } void clButtonBase::OnLeftDown(wxMouseEvent& event) { event.Skip(); - if(!IsEnabled()) { + if (!IsEnabled()) { return; } @@ -168,15 +169,15 @@ void clButtonBase::OnLeftDown(wxMouseEvent& event) void clButtonBase::OnLeftUp(wxMouseEvent& event) { event.Skip(); - if(HasCapture()) { + if (HasCapture()) { ReleaseMouse(); } - if(!IsEnabled()) { + if (!IsEnabled()) { return; } wxRect rect = GetClientRect(); - if(rect.Contains(event.GetPosition())) { + if (rect.Contains(event.GetPosition())) { m_state = eButtonState::kHover; wxCommandEvent eventClick(wxEVT_BUTTON); eventClick.SetEventObject(this); @@ -202,14 +203,14 @@ void clButtonBase::Render(wxDC& dc) wxColour parentbgColour = GetParent() ? GetParent()->GetBackgroundColour() : clSystemSettings::GetDefaultPanelColour(); #ifdef __WXGTK3__ - if(GetParent()) { + if (GetParent()) { GdkRGBA colour; auto hParent = GetParent()->GetHandle(); auto style_context = gtk_widget_get_style_context(GTK_WIDGET(hParent)); - if(style_context) { + if (style_context) { gtk_style_context_get_background_color(style_context, GTK_STATE_FLAG_NORMAL, &colour); wxColour c = wxColour(colour); - if(c.IsOk()) { + if (c.IsOk()) { parentbgColour = c; } } @@ -235,7 +236,7 @@ void clButtonBase::Render(wxDC& dc) wxColour bgColour = clSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); bool isDark = DrawingUtils::IsDark(bgColour); - switch(m_state) { + switch (m_state) { case eButtonState::kNormal: case eButtonState::kHover: bgColour = bgColour.ChangeLightness(isDark ? 80 : 95); @@ -255,15 +256,15 @@ void clButtonBase::Render(wxDC& dc) wxColour btn_hilite_face = btn_face.ChangeLightness(isDark ? 110 : 150); #endif // Draw the background - if(!isDisabled) { - if(IsNormal()) { + if (!isDisabled) { + if (IsNormal()) { // draw the border dc.SetBrush(btn_face); - } else if(IsHover()) { + } else if (IsHover()) { dc.SetBrush(btn_hilite_face); - } else if(m_state == eButtonState::kPressed) { + } else if (m_state == eButtonState::kPressed) { // pressed button is drawns with flat bg colour and border dc.SetBrush(btn_pressed_face); } @@ -276,7 +277,7 @@ void clButtonBase::Render(wxDC& dc) wxColour base_colour = clSystemSettings::GetDefaultPanelColour(); wxColour border_colour = base_colour.ChangeLightness(isDark ? 50 : 70); #ifdef __WXMAC__ - if(isDisabled) { + if (isDisabled) { border_colour = border_colour.ChangeLightness(110); } #endif @@ -298,14 +299,14 @@ void clButtonBase::Render(wxDC& dc) wxRect arrow_rect; wxRect sub_text_rect; - if(GetBitmap().IsOk()) { + if (GetBitmap().IsOk()) { bitmap_rect.SetX(2 * TEXT_SPACER); bitmap_rect.SetWidth(GetBitmap().GetScaledWidth() + TEXT_SPACER); bitmap_rect.SetHeight(GetBitmap().GetScaledHeight()); bitmap_rect.SetY(0); } - if(HasDropDownMenu()) { + if (HasDropDownMenu()) { arrow_rect.SetWidth((2 * TEXT_SPACER) + rect.GetHeight()); arrow_rect.SetX(rect.GetWidth() - arrow_rect.GetWidth()); arrow_rect.SetY(0); @@ -315,7 +316,7 @@ void clButtonBase::Render(wxDC& dc) wxString buttonText = GetText(); wxString subtext = GetSubText(); int sub_text_x_spacer = 0; - if(!buttonText.IsEmpty()) { + if (!buttonText.IsEmpty()) { double factor = 1.2; wxFont font = DrawingUtils::GetDefaultGuiFont(); #ifdef __WXMAC__ @@ -323,13 +324,13 @@ void clButtonBase::Render(wxDC& dc) double default_font_point_size = font.GetFractionalPointSize(); #endif - if(!subtext.empty()) { + if (!subtext.empty()) { font.SetFractionalPointSize(factor * (double)font.GetPointSize()); font.SetWeight(wxFONTWEIGHT_SEMIBOLD); } dc.SetFont(font); - if(!subtext.empty()) { + if (!subtext.empty()) { wxString prefix = RIGHT_ARROW; sub_text_x_spacer = dc.GetTextExtent(prefix).x; buttonText.Prepend(prefix); @@ -345,14 +346,14 @@ void clButtonBase::Render(wxDC& dc) #ifdef __WXMAC__ // restore the real fractional point size which 1.2 - if(!subtext.empty()) { + if (!subtext.empty()) { font.SetFractionalPointSize(1.2 * default_font_point_size); } #endif } // Draw the bitmap first - if(GetBitmap().IsOk()) { + if (GetBitmap().IsOk()) { wxRect bitmapRect = bitmap_rect; bitmapRect = bitmapRect.CenterIn(rect, wxVERTICAL); dc.DrawBitmap(GetBitmap(), bitmapRect.GetTopLeft()); @@ -362,18 +363,18 @@ void clButtonBase::Render(wxDC& dc) wxColour textColour = clSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT); wxColour dropDownColour = textColour.ChangeLightness(isDark ? 80 : 120); - if(isDisabled) { + if (isDisabled) { dropDownColour = textColour = m_colours.GetGrayText(); - } else if(IsPressed()) { + } else if (IsPressed()) { textColour = textColour.ChangeLightness(isDark ? 70 : 110); dropDownColour = dropDownColour.ChangeLightness(isDark ? 70 : 110); } - if(!buttonText.IsEmpty()) { + if (!buttonText.IsEmpty()) { bool has_sub_text = !subtext.empty(); wxRect textBoundingRect = text_rect; textBoundingRect = textBoundingRect.CenterIn(rect, (has_sub_text ? (wxVERTICAL) : (wxVERTICAL | wxHORIZONTAL))); - if(has_sub_text) { + if (has_sub_text) { textBoundingRect.x += TEXT_SPACER; sub_text_rect = textBoundingRect; sub_text_rect.width = dc.GetTextExtent(subtext).x; @@ -386,32 +387,32 @@ void clButtonBase::Render(wxDC& dc) #ifdef __WXMAC__ wxFont font = DrawingUtils::GetDefaultGuiFont(); - if(has_sub_text) { + if (has_sub_text) { font.SetFractionalPointSize((double)font.GetPointSize() * 1.2); } dc.SetFont(font); #endif DrawLabel(dc, textBoundingRect, buttonText, textColour); - if(has_sub_text) { + if (has_sub_text) { wxFont font = DrawingUtils::GetDefaultGuiFont(); dc.SetFont(font); DrawLabel(dc, sub_text_rect, subtext, textColour); } } - if(HasDropDownMenu()) { + if (HasDropDownMenu()) { // Draw an arrow int flags = wxCONTROL_NONE; - if(isDisabled) + if (isDisabled) flags |= wxCONTROL_DISABLED; - if(HasFocus()) + if (HasFocus()) flags |= wxCONTROL_FOCUSED; DrawingUtils::DrawDropDownArrow(this, dc, arrow_rect, flags, textColour); } - if(HasFocus()) { + if (HasFocus()) { wxRect focus_rect = clientRect; focus_rect.Deflate(2); wxRendererNative::Get().DrawFocusRect(this, dc, focus_rect); @@ -427,15 +428,15 @@ void clButtonBase::Render(wxDC& dc) // draw the button int flags = 0; - if(IsPressed()) { + if (IsPressed()) { flags |= wxCONTROL_PRESSED; } - if(IsHover()) { + if (IsHover()) { flags |= wxCONTROL_CURRENT; } - if(m_state == eButtonState::kDisabled) { + if (m_state == eButtonState::kDisabled) { flags |= wxCONTROL_DISABLED; } @@ -453,14 +454,14 @@ void clButtonBase::Render(wxDC& dc) wxRect arrow_rect; wxRect sub_text_rect; - if(GetBitmap().IsOk()) { + if (GetBitmap().IsOk()) { bitmap_rect.SetX(2 * TEXT_SPACER); bitmap_rect.SetWidth(GetBitmap().GetScaledWidth() + TEXT_SPACER); bitmap_rect.SetHeight(GetBitmap().GetScaledHeight()); bitmap_rect.SetY(0); } - if(HasDropDownMenu()) { + if (HasDropDownMenu()) { arrow_rect.SetWidth((2 * TEXT_SPACER) + rect.GetHeight()); arrow_rect.SetX(rect.GetWidth() - arrow_rect.GetWidth()); arrow_rect.SetY(0); @@ -470,7 +471,7 @@ void clButtonBase::Render(wxDC& dc) wxString buttonText = GetText(); wxString subtext = GetSubText(); int sub_text_x_spacer = 0; - if(!buttonText.IsEmpty()) { + if (!buttonText.IsEmpty()) { double factor = 1.2; wxFont font = DrawingUtils::GetDefaultGuiFont(); #ifdef __WXMAC__ @@ -478,13 +479,13 @@ void clButtonBase::Render(wxDC& dc) double default_font_point_size = font.GetFractionalPointSize(); #endif - if(!subtext.empty()) { + if (!subtext.empty()) { font.SetFractionalPointSize(factor * (double)font.GetPointSize()); font.SetWeight(wxFONTWEIGHT_SEMIBOLD); } dc.SetFont(font); - if(!subtext.empty()) { + if (!subtext.empty()) { wxString prefix = RIGHT_ARROW; sub_text_x_spacer = dc.GetTextExtent(prefix).x; buttonText.Prepend(prefix); @@ -500,14 +501,14 @@ void clButtonBase::Render(wxDC& dc) #ifdef __WXMAC__ // restore the real fractional point size which 1.2 - if(!subtext.empty()) { + if (!subtext.empty()) { font.SetFractionalPointSize(1.2 * default_font_point_size); } #endif } // Draw the bitmap first - if(GetBitmap().IsOk()) { + if (GetBitmap().IsOk()) { wxRect bitmapRect = bitmap_rect; bitmapRect = bitmapRect.CenterIn(rect, wxVERTICAL); dc.DrawBitmap(GetBitmap(), bitmapRect.GetTopLeft()); @@ -516,17 +517,17 @@ void clButtonBase::Render(wxDC& dc) // Setup some colours (text and dropdown) wxColour textColour = clSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT); - if(isDisabled) { + if (isDisabled) { textColour = m_colours.GetGrayText(); - } else if(IsPressed()) { + } else if (IsPressed()) { textColour = m_colours.GetItemTextColour().ChangeLightness(isDark ? 70 : 110); } - if(!buttonText.IsEmpty()) { + if (!buttonText.IsEmpty()) { bool has_sub_text = !subtext.empty(); wxRect textBoundingRect = text_rect; textBoundingRect = textBoundingRect.CenterIn(rect, (has_sub_text ? (wxVERTICAL) : (wxVERTICAL | wxHORIZONTAL))); - if(has_sub_text) { + if (has_sub_text) { textBoundingRect.x += TEXT_SPACER; sub_text_rect = textBoundingRect; sub_text_rect.width = dc.GetTextExtent(subtext).x; @@ -539,20 +540,20 @@ void clButtonBase::Render(wxDC& dc) #ifdef __WXMAC__ wxFont font = DrawingUtils::GetDefaultGuiFont(); - if(has_sub_text) { + if (has_sub_text) { font.SetFractionalPointSize((double)font.GetPointSize() * 1.2); } dc.SetFont(font); #endif DrawLabel(dc, textBoundingRect, buttonText, textColour); - if(has_sub_text) { + if (has_sub_text) { wxFont font = DrawingUtils::GetDefaultGuiFont(); dc.SetFont(font); DrawLabel(dc, sub_text_rect, subtext, textColour); } } - if(HasDropDownMenu()) { + if (HasDropDownMenu()) { // Draw an arrow wxRect arrowRect(0, 0, rect.GetHeight(), rect.GetHeight()); arrowRect = arrowRect.CenterIn(arrow_rect); @@ -563,7 +564,7 @@ void clButtonBase::Render(wxDC& dc) wxRendererNative::Get().DrawDropArrow(this, dc, r, 0); } - if(HasFocus()) { + if (HasFocus()) { wxRect focus_rect = clientRect; focus_rect.Deflate(2); wxRendererNative::Get().DrawFocusRect(this, dc, focus_rect); @@ -574,7 +575,7 @@ void clButtonBase::Render(wxDC& dc) void clButtonBase::OnEnter(wxMouseEvent& event) { event.Skip(); - if(!HasCapture()) { + if (!HasCapture()) { m_state = eButtonState::kHover; Refresh(); } @@ -583,7 +584,7 @@ void clButtonBase::OnEnter(wxMouseEvent& event) void clButtonBase::OnLeave(wxMouseEvent& event) { event.Skip(); - if(!HasCapture()) { + if (!HasCapture()) { m_state = eButtonState::kNormal; Refresh(); } @@ -594,7 +595,7 @@ wxSize clButtonBase::GetBestSize() const wxClientDC dc(const_cast(this)); wxFont f = DrawingUtils::GetDefaultGuiFont(); - if(!GetSubText().empty()) { + if (!GetSubText().empty()) { double factor = 1.2; #ifdef __WXMAC__ factor = 1.5; @@ -619,7 +620,7 @@ wxSize clButtonBase::GetBestSize() const } wxString mainText = GetText(); - if(!GetSubText().empty()) { + if (!GetSubText().empty()) { mainText.Prepend(RIGHT_ARROW); } @@ -627,7 +628,7 @@ wxSize clButtonBase::GetBestSize() const wxString sampleText = GetSubText().empty() ? mainText : (mainText.length() > GetSubText().length() ? mainText : GetSubText()); - if(!(m_buttonStyle & wxBU_EXACTFIT) && defaultText.length() > sampleText.length()) { + if (!(m_buttonStyle & wxBU_EXACTFIT) && defaultText.length() > sampleText.length()) { sampleText = defaultText; } @@ -638,7 +639,7 @@ wxSize clButtonBase::GetBestSize() const buttonWidth += TEXT_SPACER; // Add bitmap length - if(GetBitmap().IsOk()) { + if (GetBitmap().IsOk()) { buttonWidth += GetBitmap().GetScaledWidth(); buttonWidth += TEXT_SPACER; } @@ -647,11 +648,11 @@ wxSize clButtonBase::GetBestSize() const buttonWidth += TEXT_SPACER; // Drop down arrow width - if(HasDropDownMenu()) { + if (HasDropDownMenu()) { buttonWidth += buttonHeight; } - if(!GetSubText().empty()) { + if (!GetSubText().empty()) { buttonHeight *= 2; buttonHeight += TEXT_SPACER; } @@ -672,10 +673,10 @@ void clButtonBase::OnFocus(wxFocusEvent& event) void clButtonBase::OnKeyDown(wxKeyEvent& event) { - if((event.GetKeyCode() == WXK_SPACE) || (event.GetKeyCode() == WXK_NUMPAD_ENTER) || - (event.GetKeyCode() == WXK_RETURN)) { + if ((event.GetKeyCode() == WXK_SPACE) || (event.GetKeyCode() == WXK_NUMPAD_ENTER) || + (event.GetKeyCode() == WXK_RETURN)) { PostClickEvent(); - } else if(event.GetKeyCode() == WXK_TAB) { + } else if (event.GetKeyCode() == WXK_TAB) { Navigate(event.ShiftDown() ? wxNavigationKeyEvent::IsBackward : wxNavigationKeyEvent::IsForward); } else { event.Skip(); @@ -692,8 +693,12 @@ void clButtonBase::PostClickEvent() void clButtonBase::OnIdle(wxIdleEvent& event) { event.Skip(); + static clIdleEventThrottler event_throttler{ 200 }; + if (!event_throttler.CanHandle()) { + return; + } size_t flags = GetDrawingFlags(); - if(flags != m_lastPaintFlags) { + if (flags != m_lastPaintFlags) { // We need to refresh the window Refresh(); } @@ -702,7 +707,7 @@ void clButtonBase::OnIdle(wxIdleEvent& event) size_t clButtonBase::GetDrawingFlags() const { size_t flags = 0; - if(IsEnabled()) { + if (IsEnabled()) { flags |= kDrawingFlagEnabled; } return flags; @@ -718,7 +723,7 @@ void clButtonBase::SetBitmap(const wxBitmap& bmp) { m_bitmap = bmp; SetSizeHints(GetBestSize()); - if(GetParent() && GetParent()->GetSizer()) { + if (GetParent() && GetParent()->GetSizer()) { GetParent()->Layout(); } Refresh(); @@ -741,7 +746,7 @@ void clButtonBase::ShowMenu(wxMenu& menu, wxPoint* point) #endif wxPoint menuPos; - if(point) { + if (point) { menuPos = *point; } else { menuPos = GetClientRect().GetBottomLeft(); @@ -768,7 +773,7 @@ void clButtonBase::SetText(const wxString& text) tmp.Replace("@@", "&"); m_text = tmp; SetSizeHints(GetBestSize()); - if(GetParent() && GetParent()->GetSizer()) { + if (GetParent() && GetParent()->GetSizer()) { GetParent()->Layout(); } Refresh(); diff --git a/Plugin/clIdleEventThrottler.hpp b/Plugin/clIdleEventThrottler.hpp new file mode 100644 index 0000000000..c8d1f01edd --- /dev/null +++ b/Plugin/clIdleEventThrottler.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +class clIdleEventThrottler +{ +public: + clIdleEventThrottler(uint64_t interval_ms) + : m_interval_ms(interval_ms) + { + } + + bool CanHandle() + { + uint64_t current_ts = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + .count(); + if ((current_ts - m_last_idle_event) < m_interval_ms) { + return false; + } + m_last_idle_event = current_ts; + return true; + } + +private: + uint64_t m_last_idle_event = 0; + uint64_t m_interval_ms = 0; +}; diff --git a/Plugin/clScrolledPanel.cpp b/Plugin/clScrolledPanel.cpp index ab1e88b084..8336a21a77 100644 --- a/Plugin/clScrolledPanel.cpp +++ b/Plugin/clScrolledPanel.cpp @@ -1,5 +1,6 @@ #include "clScrolledPanel.h" +#include "clIdleEventThrottler.hpp" #include "clScrollBar.h" #include "drawingutils.h" @@ -280,6 +281,10 @@ int clScrolledPanel::GetPageSize() const { return m_pageSize; } void clScrolledPanel::OnIdle(wxIdleEvent& event) { event.Skip(); + static clIdleEventThrottler event_throttler{ 200 }; + if (!event_throttler.CanHandle()) { + return; + } if (m_vsb && m_showSBOnFocus) { wxWindow* focus_win = wxWindow::FindFocus(); bool inOurWindows = IsDescendant(focus_win); diff --git a/Plugin/wxTerminalCtrl/wxTerminalInputCtrl.cpp b/Plugin/wxTerminalCtrl/wxTerminalInputCtrl.cpp index 74cd961f0d..d996c8a81b 100644 --- a/Plugin/wxTerminalCtrl/wxTerminalInputCtrl.cpp +++ b/Plugin/wxTerminalCtrl/wxTerminalInputCtrl.cpp @@ -2,6 +2,7 @@ #include "ColoursAndFontsManager.h" #include "StringUtils.h" +#include "clIdleEventThrottler.hpp" #include "clSystemSettings.h" #include "event_notifier.h" #include "wxTerminalCtrl.h" @@ -60,7 +61,7 @@ wxTerminalInputCtrl::wxTerminalInputCtrl(wxTerminalCtrl* parent) m_ctrl->SetWrapMode(wxSTC_WRAP_WORD); m_ctrl->SetCaretStyle(wxSTC_CARETSTYLE_BLOCK); - for(int i = 0; i < wxSTC_MAX_MARGIN; ++i) { + for (int i = 0; i < wxSTC_MAX_MARGIN; ++i) { m_ctrl->SetMarginWidth(i, 0); } @@ -100,7 +101,7 @@ wxTerminalInputCtrl::wxTerminalInputCtrl(wxTerminalCtrl* parent) V.push_back(wxAcceleratorEntry{ wxACCEL_RAW_CTRL, (int)'W', XRCID("ID_delete_word") }); wxAcceleratorEntry accel_entries[V.size()]; - for(size_t i = 0; i < V.size(); ++i) { + for (size_t i = 0; i < V.size(); ++i) { accel_entries[i] = V[i]; } wxAcceleratorTable accel_table(V.size(), accel_entries); @@ -128,7 +129,7 @@ void wxTerminalInputCtrl::ShowCompletionBox(CompletionType type) wxArrayString words; int length_typed = 0; wxArrayString items; - if(type == CompletionType::COMMANDS) { + if (type == CompletionType::COMMANDS) { m_completionType = CompletionType::COMMANDS; wxString filter = GetText(); items = m_history.ForCompletion(GetText()); @@ -139,20 +140,20 @@ void wxTerminalInputCtrl::ShowCompletionBox(CompletionType type) return; } - if(items.empty()) { + if (items.empty()) { m_completionType = CompletionType::NONE; return; } wxCodeCompletionBoxEntry::Vec_t V; V.reserve(items.size()); - for(const auto& item : items) { + for (const auto& item : items) { V.push_back(wxCodeCompletionBoxEntry::New(item, wxNullBitmap, nullptr)); } // display the box int width = m_ctrl->GetSize().GetWidth() - (clSystemSettings::GetMetric(wxSYS_VSCROLL_X) * 2); - if(width < 0) { + if (width < 0) { width = wxNOT_FOUND; } @@ -165,13 +166,13 @@ void wxTerminalInputCtrl::ShowCompletionBox(CompletionType type) void wxTerminalInputCtrl::ProcessKeyDown(wxKeyEvent& event) { - if(IS_CCBOX_ACTIVE()) { + if (IS_CCBOX_ACTIVE()) { event.Skip(); return; } m_completionType = CompletionType::NONE; - switch(event.GetKeyCode()) { + switch (event.GetKeyCode()) { case WXK_NUMPAD_ENTER: case WXK_RETURN: OnEnter(); @@ -185,7 +186,7 @@ void wxTerminalInputCtrl::ProcessKeyDown(wxKeyEvent& event) OnDown(); break; case WXK_TAB: - if(event.GetModifiers() == 0) { + if (event.GetModifiers() == 0) { OnTabComplete(); } else { event.Skip(); @@ -219,7 +220,7 @@ wxString wxTerminalInputCtrl::GetText() const { return m_ctrl->GetText(); } void wxTerminalInputCtrl::SetCaretPos(wxTerminalInputCtrl::CaretPos pos) { int where = 0; - switch(pos) { + switch (pos) { case wxTerminalInputCtrl::CaretPos::END: where = m_ctrl->GetLastPosition(); break; @@ -241,7 +242,7 @@ void wxTerminalInputCtrl::OnMenu(wxContextMenuEvent& event) wxEVT_MENU, [this](wxCommandEvent& event) { wxUnusedVar(event); - if(!CAN_GO_BACK()) { + if (!CAN_GO_BACK()) { SetCaretPos(CaretPos::END); } int where = m_ctrl->GetLastPosition(); @@ -254,7 +255,7 @@ void wxTerminalInputCtrl::OnMenu(wxContextMenuEvent& event) wxEVT_MENU, [this](wxCommandEvent& event) { wxUnusedVar(event); - if(m_ctrl->CanCopy()) { + if (m_ctrl->CanCopy()) { m_ctrl->Copy(); } }, @@ -264,7 +265,7 @@ void wxTerminalInputCtrl::OnMenu(wxContextMenuEvent& event) void wxTerminalInputCtrl::UpdateTextDeleted(int num) { - if(m_writeStartingPosition < num) { + if (m_writeStartingPosition < num) { return; } m_writeStartingPosition -= num; @@ -286,11 +287,11 @@ void wxTerminalInputCtrl::SwapAndExecuteCommand(const wxString& cmd) void wxTerminalInputCtrl::OnCommandComplete(wxCommandEvent& event) { wxUnusedVar(event); - if(IS_CCBOX_ACTIVE() && m_completionType == CompletionType::COMMANDS) { + if (IS_CCBOX_ACTIVE() && m_completionType == CompletionType::COMMANDS) { // refresh the list ShowCompletionBox(CompletionType::COMMANDS); - } else if(!IS_CCBOX_ACTIVE()) { - if(!CAN_EDIT()) { + } else if (!IS_CCBOX_ACTIVE()) { + if (!CAN_EDIT()) { SetCaretPos(CaretPos::END); } ShowCompletionBox(CompletionType::COMMANDS); @@ -325,7 +326,7 @@ void wxTerminalInputCtrl::OnDeleteWord(wxCommandEvent& event) { wxUnusedVar(event); int word_start_pos = m_ctrl->WordStartPosition(m_ctrl->GetCurrentPos(), true); - if(word_start_pos > m_writeStartingPosition) { + if (word_start_pos > m_writeStartingPosition) { m_ctrl->DelWordLeft(); } else { Clear(); @@ -394,12 +395,12 @@ wxString wxTerminalInputCtrl::GetWordBack() void wxTerminalInputCtrl::NotifyTerminalOutput() { - if(!m_waitingForCompgenOutput) { + if (!m_waitingForCompgenOutput) { return; } wxString prefix = GetWordBack(); - if(prefix.empty()) { + if (prefix.empty()) { return; } @@ -408,16 +409,16 @@ void wxTerminalInputCtrl::NotifyTerminalOutput() int last_line = ctrl->LineFromPosition(ctrl->GetLastPosition()); wxCodeCompletionBoxEntry::Vec_t completions; - while(last_line >= 0) { + while (last_line >= 0) { wxString line = ctrl->GetLine(last_line); --last_line; line.Trim().Trim(false); - if(line.Contains(LINE_PREFIX) || line.empty()) { + if (line.Contains(LINE_PREFIX) || line.empty()) { break; } - if(line.Contains(" ") || line.length() < prefix.length()) { + if (line.Contains(" ") || line.length() < prefix.length()) { // don't present lines with spaces or shorter than the prefix continue; } @@ -425,7 +426,7 @@ void wxTerminalInputCtrl::NotifyTerminalOutput() completions.push_back(wxCodeCompletionBoxEntry::New(line)); } - if(completions.empty()) { + if (completions.empty()) { return; } @@ -437,7 +438,7 @@ void wxTerminalInputCtrl::NotifyTerminalOutput() m_completionType = CompletionType::FOLDERS; // display the box int width = m_ctrl->GetSize().GetWidth() - (clSystemSettings::GetMetric(wxSYS_VSCROLL_X) * 2); - if(width < 0) { + if (width < 0) { width = wxNOT_FOUND; } wxCodeCompletionBoxManager::Get().ShowCompletionBox( @@ -449,12 +450,12 @@ void wxTerminalInputCtrl::NotifyTerminalOutput() void wxTerminalInputCtrl::OnCCBoxSelected(clCodeCompletionEvent& event) { - if(event.GetEventObject() != this) { + if (event.GetEventObject() != this) { event.Skip(); return; } - switch(m_completionType) { + switch (m_completionType) { case CompletionType::COMMANDS: m_ctrl->ClearAll(); // restore the marker @@ -480,8 +481,14 @@ void wxTerminalInputCtrl::OnCCBoxSelected(clCodeCompletionEvent& event) void wxTerminalInputCtrl::OnIdle(wxIdleEvent& event) { event.Skip(); + + static clIdleEventThrottler event_throttler{ 200 }; + if (!event_throttler.CanHandle()) { + return; + } + int curline = m_ctrl->GetCurrentLine(); - if(m_ctrl->IsShown() && m_ctrl->MarkerGet(curline) == 0) { + if (m_ctrl->IsShown() && m_ctrl->MarkerGet(curline) == 0) { m_ctrl->MarkerAdd(curline, MARKER_ARROWS); } } diff --git a/Plugin/wxTerminalCtrl/wxTerminalOutputCtrl.cpp b/Plugin/wxTerminalCtrl/wxTerminalOutputCtrl.cpp index f4b6c7574a..5147a9f518 100644 --- a/Plugin/wxTerminalCtrl/wxTerminalOutputCtrl.cpp +++ b/Plugin/wxTerminalCtrl/wxTerminalOutputCtrl.cpp @@ -4,6 +4,7 @@ #include "FontUtils.hpp" #include "Platform.hpp" #include "StringUtils.h" +#include "clIdleEventThrottler.hpp" #include "clModuleLogger.hpp" #include "clSystemSettings.h" #include "clWorkspaceManager.h" @@ -84,7 +85,7 @@ void wxTerminalOutputCtrl::Initialise(const wxFont& font, const wxColour& bg_col m_bgColour = bg_colour; SetSizer(new wxBoxSizer(wxVERTICAL)); m_ctrl = new wxStyledTextCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); - for(int i = 0; i < wxSTC_MAX_MARGIN; ++i) { + for (int i = 0; i < wxSTC_MAX_MARGIN; ++i) { m_ctrl->SetMarginWidth(i, 0); } @@ -158,7 +159,7 @@ void wxTerminalOutputCtrl::ReloadSettings() { ApplyTheme(); } void wxTerminalOutputCtrl::StyleAndAppend(wxStringView buffer, wxString* window_title) { size_t consumed = m_outputHandler.ProcessBuffer(buffer, m_stcRenderer); - if(window_title) { + if (window_title) { *window_title = m_stcRenderer->GetWindowTitle(); } } @@ -179,7 +180,7 @@ void wxTerminalOutputCtrl::SetCaretEnd() int wxTerminalOutputCtrl::Truncate() { - if(GetNumberOfLines() > 1000) { + if (GetNumberOfLines() > 1000) { // Start removing lines from the top long linesToRemove = (GetNumberOfLines() - 1000); long startPos = 0; @@ -209,7 +210,7 @@ void wxTerminalOutputCtrl::DoScrollToEnd() void wxTerminalOutputCtrl::RequestScrollToEnd() { - if(m_scrollToEndQueued) { + if (m_scrollToEndQueued) { return; } m_scrollToEndQueued = true; @@ -239,12 +240,12 @@ void wxTerminalOutputCtrl::ApplyTheme() void wxTerminalOutputCtrl::OnKeyDown(wxKeyEvent& event) { event.Skip(); - if(event.ControlDown() || event.AltDown() || event.RawControlDown()) { + if (event.ControlDown() || event.AltDown() || event.RawControlDown()) { return; } // pass the focus - if(m_terminal) { + if (m_terminal) { m_terminal->GetInputCtrl()->SimulateKeyEvent(event); } } @@ -252,19 +253,24 @@ void wxTerminalOutputCtrl::OnKeyDown(wxKeyEvent& event) void wxTerminalOutputCtrl::OnIdle(wxIdleEvent& event) { event.Skip(); - if(!m_ctrl->IsShownOnScreen() || !m_ctrl->IsShown()) { + static clIdleEventThrottler event_throttler{ 200 }; + if (!event_throttler.CanHandle()) { + return; + } + + if (!m_ctrl->IsShownOnScreen() || !m_ctrl->IsShown()) { ClearIndicators(); return; } - if(!::wxGetKeyState(WXK_CONTROL)) { + if (!::wxGetKeyState(WXK_CONTROL)) { ClearIndicators(); m_ctrl->SetSTCCursor(wxSTC_CURSORNORMAL); return; } auto client_pt = m_ctrl->ScreenToClient(::wxGetMousePosition()); - if(!m_ctrl->GetRect().Contains(client_pt)) { + if (!m_ctrl->GetRect().Contains(client_pt)) { return; } @@ -272,7 +278,7 @@ void wxTerminalOutputCtrl::OnIdle(wxIdleEvent& event) int word_start_pos = m_ctrl->WordStartPosition(pos, true); int word_end_pos = m_ctrl->WordEndPosition(pos, true); IndicatorRange range{ word_start_pos, word_end_pos }; - if(m_indicatorHyperlink.ok() && m_indicatorHyperlink == range) { + if (m_indicatorHyperlink.ok() && m_indicatorHyperlink == range) { // already marked return; } @@ -289,7 +295,7 @@ void wxTerminalOutputCtrl::OnIdle(wxIdleEvent& event) void wxTerminalOutputCtrl::ClearIndicators() { - if(m_indicatorHyperlink.ok()) { + if (m_indicatorHyperlink.ok()) { m_ctrl->SetIndicatorCurrent(INDICATOR_HYPERLINK); m_ctrl->IndicatorClearRange(m_indicatorHyperlink.start(), m_indicatorHyperlink.length()); m_indicatorHyperlink.reset(); @@ -300,7 +306,7 @@ void wxTerminalOutputCtrl::OnLeftUp(wxMouseEvent& event) { event.Skip(); - if(!m_indicatorHyperlink.ok()) { + if (!m_indicatorHyperlink.ok()) { return; } @@ -324,7 +330,7 @@ void wxTerminalOutputCtrl::OnLeaveWindow(wxMouseEvent& event) void wxTerminalOutputCtrl::DoPatternClicked(const wxString& pattern) { // if the pattern matches a URL, open it - if(pattern.StartsWith("https://") || pattern.StartsWith("http://")) { + if (pattern.StartsWith("https://") || pattern.StartsWith("http://")) { m_indicatorHyperlink.reset(); ::wxLaunchDefaultBrowser(pattern); return; @@ -334,8 +340,8 @@ void wxTerminalOutputCtrl::DoPatternClicked(const wxString& pattern) wxString line_str; wxString col_str; auto parts = ::wxStringTokenize(pattern, ":", wxTOKEN_STRTOK); - if(parts.size() > 1) { - if(parts[0].length() == 1) { + if (parts.size() > 1) { + if (parts[0].length() == 1) { // single char -> volume // assume windows fullpath file = parts[0] + ":" + parts[1]; @@ -344,12 +350,12 @@ void wxTerminalOutputCtrl::DoPatternClicked(const wxString& pattern) file = parts[0]; parts.RemoveAt(0, 1); } - if(!parts.empty()) { + if (!parts.empty()) { // line number line_str = parts[0]; parts.RemoveAt(0, 1); } - if(!parts.empty()) { + if (!parts.empty()) { // column col_str = parts[0]; parts.RemoveAt(0, 1); @@ -368,27 +374,27 @@ void wxTerminalOutputCtrl::DoPatternClicked(const wxString& pattern) event_clicked.SetFileName(file); event_clicked.SetLineNumber(0); long nLine = 0; - if(!line_str.empty() && line_str.ToCLong(&nLine)) { + if (!line_str.empty() && line_str.ToCLong(&nLine)) { event_clicked.SetLineNumber(nLine); } event_clicked.SetProjectName(wxEmptyString); - if(EventNotifier::Get()->ProcessEvent(event_clicked)) { + if (EventNotifier::Get()->ProcessEvent(event_clicked)) { return; } - if(FileUtils::IsBinaryExecutable(file)) { + if (FileUtils::IsBinaryExecutable(file)) { #ifdef __WXMSW__ // if we are running under Windows and the file path is POSIX (e.g. MSYS2) // convert it into Windows native path - if(file.StartsWith("/")) { + if (file.StartsWith("/")) { wxString cygpath; - if(ThePlatform->Which("cygpath", &cygpath)) { + if (ThePlatform->Which("cygpath", &cygpath)) { wxString command; command << StringUtils::WrapWithDoubleQuotes(cygpath) << " -w " << StringUtils::WrapWithDoubleQuotes(file); wxString winpath = ProcUtils::SafeExecuteCommand(command); winpath.Trim().Trim(false); - if(wxFileName::FileExists(winpath)) { + if (wxFileName::FileExists(winpath)) { file = StringUtils::WrapWithDoubleQuotes(winpath); } } @@ -403,7 +409,7 @@ void wxTerminalOutputCtrl::DoPatternClicked(const wxString& pattern) // change dir to the active workspace directory DirSaver ds; auto workspace = clWorkspaceManager::Get().GetWorkspace(); - if(workspace && !workspace->IsRemote()) { + if (workspace && !workspace->IsRemote()) { ::wxSetWorkingDirectory(wxFileName(workspace->GetFileName()).GetPath()); }