From fbba1e712440d2abf9180eae732a8cb8d6f114ba Mon Sep 17 00:00:00 2001 From: "Michael Z. Kadaner" Date: Sat, 12 Aug 2023 21:34:24 -0700 Subject: [PATCH] Work in progress. --- far/vmenu.cpp | 116 +++++++++++++++++++++++++++++--------------------- far/vmenu.hpp | 2 + 2 files changed, 69 insertions(+), 49 deletions(-) diff --git a/far/vmenu.cpp b/far/vmenu.cpp index 861ff72c17..b937d5a004 100644 --- a/far/vmenu.cpp +++ b/far/vmenu.cpp @@ -2088,7 +2088,7 @@ void VMenu::DrawTitles() const void VMenu::ShowMenu() { - const auto ServiceAreaSize = GetServiceAreaSize(); + const auto ServiceAreaSize{ GetServiceAreaSize() }; MaxLineWidth = ServiceAreaSize > static_cast(m_Where.width())? 0 : m_Where.width() - ServiceAreaSize; if (m_Where.right <= m_Where.left || m_Where.bottom <= m_Where.top) @@ -2116,50 +2116,22 @@ void VMenu::ShowMenu() AssignHighlights(CheckFlags(VMENU_REVERSEHIGHLIGHT)); const auto ClientRect{ GetClientRect() }; + const auto VisualTopPos{ AdjustTopPos(ClientRect.height()) }; - int VisualSelectPos = GetVisualPos(SelectPos); - int VisualTopPos = GetVisualPos(TopPos); - - // коррекция Top`а - // 2023-07-09 MZK: What is it? Should it be ClientRect.height() instead of m_Where.height()? - if (VisualTopPos+GetShowItemCount() >= m_Where.height() - 1 && VisualSelectPos == GetShowItemCount()-1) - { - VisualTopPos--; - - if (VisualTopPos<0) - VisualTopPos=0; - } - - VisualTopPos = std::min(VisualTopPos, GetShowItemCount() - (ClientRect.height() - 4)); - - if (VisualSelectPos > VisualTopPos + (ClientRect.height() - 1)) - { - VisualTopPos = VisualSelectPos - (ClientRect.height() - 1); - } - - if (VisualSelectPos < VisualTopPos) - { - TopPos=SelectPos; - VisualTopPos=VisualSelectPos; - } - else - { - TopPos=VisualPosToReal(VisualTopPos); - } - - if (VisualTopPos<0) - VisualTopPos=0; + if (ClientRect.width() <= 0) + return; - if (TopPos<0) - TopPos=0; + string LineBuffer(ClientRect.width(), L' '); for (int Y = ClientRect.top, I = TopPos; Y <= ClientRect.bottom; ++Y, ++I) { if (I >= static_cast(Items.size())) { + LineBuffer.replace(LineBuffer.cbegin(), LineBuffer.cend(), ClientRect.width(), L' '); + SetColor(Colors[VMenuColorText]); GotoXY(ClientRect.left, Y); - Text(string(ClientRect.width(), L' ')); + Text(string(LineBuffer)); continue; } @@ -2183,27 +2155,22 @@ void VMenu::ShowMenu() continue; } + LineBuffer.at(0) = GetItemCheckMark(Items[I]); + LineBuffer.replace(LineBuffer.cbegin() + 1, LineBuffer.cend(), ClientRect.width(), L' '); + + const auto ItemIndent{ Items[I].Indent() }; + const auto ItemHanging{ Items[I].Hanging() }; + + const auto ColorIndices{ GetItemColors(Items[I]) }; GotoXY(m_Where.left + (m_BoxType == NO_BOX? 0 : 1), Y); SetColor(Colors[ColorIndices.Normal]); - wchar_t CheckMark = L' '; - - if (Items[I].Flags & LIF_CHECKED) - { - if (!(Items[I].Flags & 0x0000FFFF)) - CheckMark = 0x221A; - else - CheckMark = static_cast(Items[I].Flags & 0x0000FFFF); - } - - const auto ItemIndent{ Items[I].Indent() }; - const auto ItemHanging{ Items[I].Hanging() }; string strMenuLine{ CheckMark }; - strMenuLine.push_back(L' '); // left scroller (<<) placeholder + // LineBuffer.at(1) = L' '; // left scroller («) placeholder const auto LineWidthPlusLeftMargin{ strMenuLine.size() + MaxLineWidth }; strMenuLine.append(ItemIndent, L' '); const auto PrefixSize = strMenuLine.size(); @@ -2320,6 +2287,46 @@ rectangle VMenu::GetClientRect() const noexcept return { m_Where.left + 1, m_Where.top + 1, m_Where.right - 1, m_Where.bottom - 1 }; } +int VMenu::AdjustTopPos(const int ClientHeight) +{ + int VisualSelectPos = GetVisualPos(SelectPos); + int VisualTopPos = GetVisualPos(TopPos); + + // 2023-07-09 MZK: What is it? Should it be ClientRect.height() instead of m_Where.height()? + if (VisualTopPos + GetShowItemCount() >= m_Where.height() - 1 && VisualSelectPos == GetShowItemCount() - 1) + { + VisualTopPos--; + + if (VisualTopPos < 0) + VisualTopPos = 0; + } + + VisualTopPos = std::min(VisualTopPos, GetShowItemCount() - (ClientHeight - 4)); + + if (VisualSelectPos > VisualTopPos + (ClientHeight - 1)) + { + VisualTopPos = VisualSelectPos - (ClientHeight - 1); + } + + if (VisualSelectPos < VisualTopPos) + { + TopPos = SelectPos; + VisualTopPos = VisualSelectPos; + } + else + { + TopPos = VisualPosToReal(VisualTopPos); + } + + if (VisualTopPos < 0) + VisualTopPos = 0; + + if (TopPos < 0) + TopPos = 0; + + return VisualTopPos; +} + void VMenu::ConnectSeparator(size_t CurItem, string& separator) const { if (CheckFlags(VMENU_NOMERGEBORDER) || separator.size() <= 3) @@ -2366,6 +2373,17 @@ void VMenu::ApplySeparatorName(size_t CurItem, string& separator) const separator.at(NamePos + NameWidth) = L' '; } +wchar_t VMenu::GetItemCheckMark(const MenuItemEx& CurItem) const noexcept +{ + if (!(CurItem.Flags & LIF_CHECKED)) + return L' '; + + if (!(CurItem.Flags & 0x0000FFFF)) + return 0x221A; + + return static_cast(CurItem.Flags & 0x0000FFFF); +} + VMenu::ItemColorIndicies VMenu::GetItemColors(const MenuItemEx& CurItem) const { const auto Selected{ !!(CurItem.Flags & LIF_SELECTED) }; diff --git a/far/vmenu.hpp b/far/vmenu.hpp index c0daa81df6..a6dcdbc2ea 100644 --- a/far/vmenu.hpp +++ b/far/vmenu.hpp @@ -309,8 +309,10 @@ class VMenu final: public Modal void ShowMenu(); rectangle GetClientRect() const noexcept; + int AdjustTopPos(int ClientHeight); void ConnectSeparator(size_t CurItem, string& separator) const; void ApplySeparatorName(size_t CurItem, string& separator) const; + wchar_t GetItemCheckMark(const MenuItemEx& CurItem) const noexcept; ItemColorIndicies GetItemColors(const MenuItemEx& CurItem) const; void DrawTitles() const; int GetItemPosition(int Position) const;