From c0b83fb849f73c620095ecf374ebe1d97851208b Mon Sep 17 00:00:00 2001 From: "Michael Z. Kadaner" Date: Mon, 15 Jan 2024 19:08:35 -0800 Subject: [PATCH] WIP: Works? --- far/vmenu.cpp | 168 +++++++++++++++++++++++++++++++++----------------- far/vmenu.hpp | 3 + 2 files changed, 116 insertions(+), 55 deletions(-) diff --git a/far/vmenu.cpp b/far/vmenu.cpp index 8e481e6465..060f012351 100644 --- a/far/vmenu.cpp +++ b/far/vmenu.cpp @@ -367,6 +367,19 @@ namespace bool were_right_items() { return MinRightOffset != NonValue; } }; + int adjust_en_bloc_shift(const int Shift, const int EnBlocHScrollDiscriminator, const int TextAreaWidth) + { + assert(TextAreaWidth > 0); + + if (EnBlocHScrollDiscriminator <= 0) + return Shift <= 0 ? 0 : Shift - EnBlocHScrollDiscriminator; + + if (EnBlocHScrollDiscriminator >= TextAreaWidth) + return Shift >= 0 ? 0 : Shift - (EnBlocHScrollDiscriminator - TextAreaWidth); + + return Shift; + } + // Indices in the color array enum class color_indices { @@ -2124,7 +2137,7 @@ int VMenu::VisualPosToReal(int VPos) const */ -bool VMenu::SetAllItemsSmartHPos(int NewHPos) +bool VMenu::SetAllItemsSmartHPos(const int NewHPos) { const auto TextAreaWidth{ CalculateTextAreaWidth() }; if (TextAreaWidth <= 0) return false; @@ -2148,57 +2161,48 @@ bool VMenu::SetAllItemsSmartHPos(int NewHPos) return NeedRedraw; } -bool VMenu::SetCurItemSmartHPos(int NewHPos) -{ - return false; -} - -bool VMenu::ShiftAllItemsHPos(int Shift) +bool VMenu::SetCurItemSmartHPos(const int NewHPos) { - if (!Shift) return false; - const auto TextAreaWidth{ CalculateTextAreaWidth() }; if (TextAreaWidth <= 0) return false; - //return SetItemAbsoluteHPos(Item, Item.HPos + Shift, TextAreaWidth, Policy); - - bool NeedRedraw{}; + const auto Policy{ CheckFlags(VMENU_ENABLEALIGNANNOTATIONS) ? item_hscroll_policy::cling_to_edge : item_hscroll_policy::bound_stick_to_left }; - if (EnBlocHScrollMode && EnBlocHScrollDiscriminator) - { - if (Shift > 0) - { - if (EnBlocHScrollDiscriminator.value() >= TextAreaWidth) - return false; - if (EnBlocHScrollDiscriminator.value() <= 0) - Shift -= EnBlocHScrollDiscriminator.value(); - } - else - { - if (EnBlocHScrollDiscriminator.value() <= 0) - return false; - if (EnBlocHScrollDiscriminator.value() >= TextAreaWidth) - Shift -= EnBlocHScrollDiscriminator.value() - TextAreaWidth; - } + auto& Item{ Items[SelectPos] }; + if (Item.Flags & LIF_SEPARATOR) return false; + if (!SetItemSmartHPos(Item, NewHPos, TextAreaWidth, Policy)) return false; - } + SetMenuFlags(VMENU_UPDATEREQUIRED); + return true; +} - //for (auto& Item : Items) - //{ - // if (Item.Flags & LIF_SEPARATOR) continue; +bool VMenu::ShiftAllItemsHPos(const int Shift) +{ + const auto TextAreaWidth{ CalculateTextAreaWidth() }; + if (TextAreaWidth <= 0) return false; - // if (SetItemSmartHPos(Item, NewHPos, TextAreaWidth, Policy)) - // NeedRedraw = true; - //} + const auto ShiftAllItemsHPosFunc{ EnBlocHScrollMode ? &VMenu::ShiftAllItemsHPosEnBlock : &VMenu::ShiftAllItemsHPosLimited }; + if (!(this->*ShiftAllItemsHPosFunc)(Shift, TextAreaWidth)) return false; - if (NeedRedraw) SetMenuFlags(VMENU_UPDATEREQUIRED); - return NeedRedraw; + SetMenuFlags(VMENU_UPDATEREQUIRED); + return true; } -bool VMenu::ShiftCurItemHPos(int Shift) +bool VMenu::ShiftCurItemHPos(const int Shift) { - return false; + const auto TextAreaWidth{ CalculateTextAreaWidth() }; + if (TextAreaWidth <= 0) return false; + + const auto Policy{ CheckFlags(VMENU_ENABLEALIGNANNOTATIONS) ? item_hscroll_policy::cling_to_edge : item_hscroll_policy::bound_stick_to_left }; + + auto& Item{ Items[SelectPos] }; + if (Item.Flags & LIF_SEPARATOR) return false; + + if (!SetItemAbsoluteHPos(Item, Item.HPos + Shift, TextAreaWidth, Policy)) return false; + + SetMenuFlags(VMENU_UPDATEREQUIRED); + return true; } bool VMenu::AlignAnnotations() @@ -2234,29 +2238,57 @@ bool VMenu::AlignAnnotations() return NeedRedraw; } -// TBD: Temp, not needed -//bool VMenu::SetItemAbsoluteHPos(MenuItemEx& Item, const int NewHPos) -//{ -// if (ItemLength <= 0) return false; -// -// const auto HPosLimits{ item_hpos_limits(Policy, ItemLength, static_cast(m_MaxItemLength), TextAreaWidth) }; -// const auto ClampedHPos = std::clamp(NewHPos, HPosLimits.first, HPosLimits.second); -// -// if (Item.HPos == ClampedHPos) -// return false; -// -// Item.HPos = ClampedHPos; -// SetMenuFlags(VMENU_UPDATEREQUIRED); -// return true; -//} +bool VMenu::ShiftAllItemsHPosEnBlock(const int Shift, const int TextAreaWidth) +{ + const auto AdjustedShift = EnBlocHScrollDiscriminator + ? adjust_en_bloc_shift(Shift, EnBlocHScrollDiscriminator.value(), TextAreaWidth) + : Shift; + if (!AdjustedShift) return false; + bool NeedRedraw{}; + list_hpos_discriminator Discriminator; + for (auto& Item : Items) + { + if (Item.Flags & LIF_SEPARATOR) continue; + + const auto ItemLength{ static_cast(CheckFlags(VMENU_SHOWAMPERSAND) ? visual_string_length(Item.Name) : HiStrlen(Item.Name)) }; + if (ItemLength <= 0) continue; + + const auto NewHPos{ Item.HPos + AdjustedShift }; + + Discriminator.accumulate(NewHPos, ItemLength); + + if (Item.HPos == NewHPos) continue; + + Item.HPos = NewHPos; + NeedRedraw = true; + } + + EnBlocHScrollDiscriminator = Discriminator.classify(); + return NeedRedraw; +} + +bool VMenu::ShiftAllItemsHPosLimited(const int Shift, const int TextAreaWidth) +{ + const auto Policy{ CheckFlags(VMENU_ENABLEALIGNANNOTATIONS) ? item_hscroll_policy::cling_to_edge : item_hscroll_policy::bound_stick_to_left }; + + bool NeedRedraw{}; + + for (auto& Item : Items) + { + if (Item.Flags & LIF_SEPARATOR) continue; + if (SetItemAbsoluteHPos(Item, Item.HPos + Shift, TextAreaWidth, Policy)) + NeedRedraw = true; + } + return NeedRedraw; +} bool VMenu::SetItemAbsoluteHPos(MenuItemEx& Item, const int NewHPos, const int ItemLength, const int TextAreaWidth, const item_hscroll_policy Policy) { - // TBD: Not needed? (TextAreaWidth <= 0) + // TBD: (TextAreaWidth <= 0) not needed? if (ItemLength <= 0 || TextAreaWidth <= 0) return false; const auto HPosLimits{ item_hpos_limits(Policy, ItemLength, static_cast(m_MaxItemLength), TextAreaWidth) }; @@ -3551,4 +3583,30 @@ TEST_CASE("list.hpos.classifier") } } +TEST_CASE("adjust.en.bloc.shift") +{ + static constexpr int TextAreaWidth{ 10 }; + static const struct test_data + { + int EnBlocHScrollDiscriminator; + std::initializer_list> ShiftAndExpectedList; + } TestDataPoints[] = + { + { -5, { { 0, 0 }, { -7, 0 }, { -5, 0 }, { -1, 0 }, { 1, 6 }, { 3, 8 }, { 10, 15 }, { 15, 20 }, } }, + { 0, { { 0, 0 }, { -7, 0 }, { -5, 0 }, { -1, 0 }, { 1, 1 }, { 3, 3 }, { 10, 10 }, { 15, 15 }, } }, + { 1, { { 0, 0 }, { -7, -7 }, { -5, -5 }, { -1, -1 }, { 1, 1 }, { 3, 3 }, { 10, 10 }, { 15, 15 }, } }, + { 5, { { 0, 0 }, { -7, -7 }, { -5, -5 }, { -1, -1 }, { 1, 1 }, { 3, 3 }, { 10, 10 }, { 15, 15 }, } }, + { 10, { { 0, 0 }, { -7, -7 }, { -5, -5 }, { -1, -1 }, { 1, 0 }, { 3, 0 }, { 10, 0 }, { 15, 0 }, } }, + { 15, { { 0, 0 }, { -7, -12 }, { -5, -10 }, { -1, -6 }, { 1, 0 }, { 3, 0 }, { 10, 0 }, { 15, 0 }, } }, + }; + + for (const auto& TestDataPoint : TestDataPoints) + { + for (const auto& ShiftAndExpected : TestDataPoint.ShiftAndExpectedList) + { + REQUIRE(ShiftAndExpected.second == adjust_en_bloc_shift(ShiftAndExpected.first, TestDataPoint.EnBlocHScrollDiscriminator, TextAreaWidth)); + } + } +} + #endif diff --git a/far/vmenu.hpp b/far/vmenu.hpp index 036942d7a7..6a60d37625 100644 --- a/far/vmenu.hpp +++ b/far/vmenu.hpp @@ -304,6 +304,9 @@ class VMenu final: public Modal [[nodiscard]] bool ShiftCurItemHPos(int Shift); [[nodiscard]] bool AlignAnnotations(); + [[nodiscard]] bool ShiftAllItemsHPosEnBlock(int Shift, int TextAreaWidth); + [[nodiscard]] bool ShiftAllItemsHPosLimited(int Shift, int TextAreaWidth); + [[nodiscard]] bool SetItemAbsoluteHPos(MenuItemEx& Item, int NewHPos, int ItemLength, int TextAreaWidth, item_hscroll_policy Policy);