diff --git a/far/vmenu.cpp b/far/vmenu.cpp index 17f7972aae..1d1823d4e2 100644 --- a/far/vmenu.cpp +++ b/far/vmenu.cpp @@ -177,15 +177,6 @@ struct menu_layout } }; -// TBD: Remove it -// Must be in the TU scope because it is forward-declared in VMenu.hpp -enum class item_hscroll_policy -{ - cling_to_edge, - bound, - bound_stick_to_left -}; - namespace { MenuItemEx far_list_to_menu_item(const FarListItem& FItem) @@ -291,6 +282,13 @@ namespace return !(Item.Flags & (LIF_HIDDEN | LIF_FILTERED)); } + enum class item_hscroll_policy + { + cling_to_edge, + bound, + bound_stick_to_left + }; + std::pair item_hpos_limits(const item_hscroll_policy Policy, const int ItemLength, const int TextAreaWidth) noexcept { assert(ItemLength > 0); @@ -361,6 +359,33 @@ namespace bool were_right_items() { return MinRightOffset != NonValue; } }; + int get_item_smart_hpos(const int NewHPos, const int ItemLength, const int TextAreaWidth) + { + return NewHPos >= 0 ? NewHPos : TextAreaWidth - ItemLength + NewHPos + 1; + } + + bool set_item_hpos( + MenuItemEx& Item, + std::regular_invocable auto const GetNewHPos, + const bool ShowAmpersand, + const int TextAreaWidth, + const item_hscroll_policy Policy) + { + if (Item.Flags & LIF_SEPARATOR) return false; + + const auto ItemLength{ static_cast(ShowAmpersand ? visual_string_length(Item.Name) : HiStrlen(Item.Name)) }; + if (ItemLength <= 0) return false; + + const auto HPosLimits{ item_hpos_limits(Policy, ItemLength, TextAreaWidth) }; + const auto ClampedHPos = std::clamp(GetNewHPos(ItemLength), HPosLimits.first, HPosLimits.second); + + if (Item.HPos == ClampedHPos) + return false; + + Item.HPos = ClampedHPos; + return true; + } + int adjust_en_bloc_shift(const int Shift, const int EnBlocHScrollDiscriminator, const int TextAreaWidth) { assert(TextAreaWidth > 0); @@ -374,23 +399,32 @@ namespace return Shift; } - bool set_item_hpos(MenuItemEx& Item, std::regular_invocable auto const GetNewHPos, const bool ShowAmpersand, const int TextAreaWidth, const item_hscroll_policy Policy) + auto set_all_items_en_bloc_hpos( + std::vector& Items, + std::regular_invocable auto const GetNewHPos, + const bool ShowAmpersand) { - const auto ItemLength{ static_cast(ShowAmpersand ? visual_string_length(Item.Name) : HiStrlen(Item.Name)) }; + bool NeedRedraw{}; + list_hpos_discriminator Discriminator; - // TBD: (TextAreaWidth <= 0) not needed? - if (ItemLength <= 0 || TextAreaWidth <= 0) return false; + for (auto& Item : Items) + { + if (Item.Flags & LIF_SEPARATOR) continue; - if (Item.Flags & LIF_SEPARATOR) return false; + const auto ItemLength{ static_cast(ShowAmpersand ? visual_string_length(Item.Name) : HiStrlen(Item.Name)) }; + if (ItemLength <= 0) continue; - const auto HPosLimits{ item_hpos_limits(Policy, ItemLength, TextAreaWidth) }; - const auto ClampedHPos = std::clamp(GetNewHPos(ItemLength), HPosLimits.first, HPosLimits.second); + const auto NewHPos{ GetNewHPos(Item) }; - if (Item.HPos == ClampedHPos) - return false; + Discriminator.accumulate(NewHPos, ItemLength); - Item.HPos = ClampedHPos; - return true; + if (Item.HPos == NewHPos) continue; + + Item.HPos = NewHPos; + NeedRedraw = true; + } + + return std::tuple{ NeedRedraw, Discriminator.classify() }; } // Indices in the color array @@ -2141,16 +2175,6 @@ int VMenu::VisualPosToReal(int VPos) const return ItemIterator != Items.cend()? ItemIterator - Items.cbegin() : -1; } - - -/* -* TBD: Remove - HScrollEnBlocMode - ? item_hscroll_policy::unbound - : CheckFlags(VMENU_ENABLEALIGNANNOTATIONS) ? item_hscroll_policy::cling_to_edge : item_hscroll_policy::bound_stick_to_left)) -*/ - - bool VMenu::SetAllItemsSmartHPos(const int NewHPos) { const auto TextAreaWidth{ CalculateTextAreaWidth() }; @@ -2167,7 +2191,7 @@ bool VMenu::SetAllItemsSmartHPos(const int NewHPos) { if (set_item_hpos( Item, - [=](int ItemLength) { return NewHPos >= 0 ? NewHPos : TextAreaWidth - ItemLength + NewHPos + 1; }, + [=](int ItemLength) { return get_item_smart_hpos(NewHPos, ItemLength, TextAreaWidth); }, CheckFlags(VMENU_SHOWAMPERSAND), TextAreaWidth, Policy)) @@ -2180,6 +2204,28 @@ bool VMenu::SetAllItemsSmartHPos(const int NewHPos) 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 (set_item_hpos( + Item, + [&](int) { return Item.HPos + Shift; }, + CheckFlags(VMENU_SHOWAMPERSAND), + TextAreaWidth, + Policy)) + { + NeedRedraw = true; + } + } + + return NeedRedraw; +} + bool VMenu::SetCurItemSmartHPos(const int NewHPos) { const auto TextAreaWidth{ CalculateTextAreaWidth() }; @@ -2189,30 +2235,18 @@ bool VMenu::SetCurItemSmartHPos(const int NewHPos) auto& Item{ Items[SelectPos] }; - if (!set_item_hpos( + if (set_item_hpos( Item, - [=](int ItemLength) { return NewHPos >= 0 ? NewHPos : TextAreaWidth - ItemLength + NewHPos + 1; }, + [=](int ItemLength) { return get_item_smart_hpos(NewHPos, ItemLength, TextAreaWidth); }, CheckFlags(VMENU_SHOWAMPERSAND), TextAreaWidth, Policy)) { - return false; + SetMenuFlags(VMENU_UPDATEREQUIRED); + return true; } - SetMenuFlags(VMENU_UPDATEREQUIRED); - return true; -} - -bool VMenu::ShiftAllItemsHPos(const int Shift) -{ - const auto TextAreaWidth{ CalculateTextAreaWidth() }; - if (TextAreaWidth <= 0) return false; - - const auto ShiftAllItemsHPosFunc{ EnBlocHScrollMode ? &VMenu::ShiftAllItemsHPosEnBlock : &VMenu::ShiftAllItemsHPosLimited }; - if (!(this->*ShiftAllItemsHPosFunc)(Shift, TextAreaWidth)) return false; - - SetMenuFlags(VMENU_UPDATEREQUIRED); - return true; + return false; } bool VMenu::ShiftCurItemHPos(const int Shift) @@ -2224,11 +2258,18 @@ bool VMenu::ShiftCurItemHPos(const int Shift) auto& Item{ Items[SelectPos] }; - if (!set_item_hpos(Item, [&](int) { return Item.HPos + Shift; }, CheckFlags(VMENU_SHOWAMPERSAND), TextAreaWidth, Policy)) - return false; + if (set_item_hpos( + Item, + [&](int) { return Item.HPos + Shift; }, + CheckFlags(VMENU_SHOWAMPERSAND), + TextAreaWidth, + Policy)) + { + SetMenuFlags(VMENU_UPDATEREQUIRED); + return true; + } - SetMenuFlags(VMENU_UPDATEREQUIRED); - return true; + return false; } bool VMenu::AlignAnnotations() @@ -2237,28 +2278,13 @@ bool VMenu::AlignAnnotations() if (TextAreaWidth <= 0 || TextAreaWidth + 2 <= 0) return false; const auto AlignPos{ (TextAreaWidth + 2) / 4 }; - 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.Annotations.empty() ? 0 : AlignPos - Item.Annotations.front().first }; - - Discriminator.accumulate(NewHPos, ItemLength); - - if (Item.HPos == NewHPos) continue; - - Item.HPos = NewHPos; - NeedRedraw = true; - } + const auto[NeedRedraw, HScrollDiscriminator] = set_all_items_en_bloc_hpos( + Items, + [=](const auto& Item) { return Item.Annotations.empty() ? 0 : AlignPos - Item.Annotations.front().first; }, + CheckFlags(VMENU_SHOWAMPERSAND)); EnBlocHScrollMode = true; - EnBlocHScrollDiscriminator = Discriminator.classify(); + EnBlocHScrollDiscriminator = HScrollDiscriminator; if (NeedRedraw) SetMenuFlags(VMENU_UPDATEREQUIRED); return NeedRedraw; @@ -2271,91 +2297,30 @@ bool VMenu::ShiftAllItemsHPosEnBlock(const int Shift, const int 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 [NeedRedraw, HScrollDiscriminator] = set_all_items_en_bloc_hpos( + Items, + [=](const auto& Item) { return Item.HPos + AdjustedShift; }, + CheckFlags(VMENU_SHOWAMPERSAND)); - const auto NewHPos{ Item.HPos + AdjustedShift }; - - Discriminator.accumulate(NewHPos, ItemLength); - - if (Item.HPos == NewHPos) continue; - - Item.HPos = NewHPos; - NeedRedraw = true; - } - - EnBlocHScrollDiscriminator = Discriminator.classify(); + EnBlocHScrollDiscriminator = HScrollDiscriminator; return NeedRedraw; } -bool VMenu::ShiftAllItemsHPosLimited(const int Shift, const int TextAreaWidth) +bool VMenu::ShiftAllItemsHPos(const int Shift) { - const auto Policy{ CheckFlags(VMENU_ENABLEALIGNANNOTATIONS) ? item_hscroll_policy::cling_to_edge : item_hscroll_policy::bound_stick_to_left }; - - bool NeedRedraw{}; + const auto TextAreaWidth{ CalculateTextAreaWidth() }; + if (TextAreaWidth <= 0) return false; - for (auto& Item : Items) + const auto ShiftAllItemsHPosFunc{ EnBlocHScrollMode ? &VMenu::ShiftAllItemsHPosEnBlock : &VMenu::ShiftAllItemsHPosLimited }; + if ((this->*ShiftAllItemsHPosFunc)(Shift, TextAreaWidth)) { - if (set_item_hpos(Item, [&](int) { return Item.HPos + Shift; }, CheckFlags(VMENU_SHOWAMPERSAND), TextAreaWidth, Policy)) - NeedRedraw = true; + SetMenuFlags(VMENU_UPDATEREQUIRED); + return true; } - return NeedRedraw; + return false; } -// TBD: Remove -//bool VMenu::SetItemAbsoluteHPos(MenuItemEx& Item, const int NewHPos, const int ItemLength, const int TextAreaWidth, const item_hscroll_policy Policy) -//{ -// // TBD: (TextAreaWidth <= 0) not needed? -// if (ItemLength <= 0 || TextAreaWidth <= 0) return false; -// -// if (Item.Flags & LIF_SEPARATOR) return false; -// -// const auto HPosLimits{ item_hpos_limits(Policy, ItemLength, TextAreaWidth) }; -// const auto ClampedHPos = std::clamp(NewHPos, HPosLimits.first, HPosLimits.second); -// -// if (Item.HPos == ClampedHPos) -// return false; -// -// Item.HPos = ClampedHPos; -// return true; -//} - -//bool VMenu::SetItemAbsoluteHPos(MenuItemEx& Item, const int NewHPos, const int TextAreaWidth, const item_hscroll_policy Policy) -//{ -// return set_item_hpos(Item, [=](int) { return NewHPos; }, CheckFlags(VMENU_SHOWAMPERSAND), TextAreaWidth, Policy); -// //return set_item_hpos(Item, NewHPos, CheckFlags(VMENU_SHOWAMPERSAND), TextAreaWidth, Policy); -//} - -//bool VMenu::SetItemSmartHPos(MenuItemEx& Item, const int NewHPos, const int TextAreaWidth, const item_hscroll_policy Policy) -//{ -// return set_item_hpos(Item, [=](int ItemLength) { return NewHPos >= 0 ? NewHPos : TextAreaWidth - ItemLength + NewHPos + 1; }, CheckFlags(VMENU_SHOWAMPERSAND), TextAreaWidth, Policy); -//} - -// TBD: Remove -//bool VMenu::ShiftItemHPos(MenuItemEx& Item, const int Shift, const int TextAreaWidth, const item_hscroll_policy Policy) -//{ -// return SetItemAbsoluteHPos(Item, Item.HPos + Shift, TextAreaWidth, Policy); -//} -// -//bool VMenu::ShiftAllItemsHPos(const int Shift, const item_hscroll_policy Policy) -//{ -// const auto TextAreaWidth{ CalculateTextAreaWidth() }; -// -// return std::accumulate(Items.begin(), Items.end(), false, [&](const bool NeedRedraw, MenuItemEx& Item) -// { -// return ShiftItemHPos(Item, Shift, TextAreaWidth, Policy) -// || NeedRedraw; -// }); -//} - void VMenu::Show() { const auto BoxType{ menu_layout::get_box_type(*this) }; diff --git a/far/vmenu.hpp b/far/vmenu.hpp index 8d9a46036f..cfc1176d92 100644 --- a/far/vmenu.hpp +++ b/far/vmenu.hpp @@ -153,7 +153,6 @@ struct MenuItemEx: menu_item }; struct menu_layout; -enum class item_hscroll_policy; struct SortItemParam {