Skip to content

Commit

Permalink
WIP: Somewhat unified.
Browse files Browse the repository at this point in the history
  • Loading branch information
MKadaner committed Jan 16, 2024
1 parent c0b83fb commit 74fde14
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 79 deletions.
172 changes: 99 additions & 73 deletions far/vmenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ struct menu_layout
// Must be in the TU scope because it is forward-declared in VMenu.hpp
enum class item_hscroll_policy
{
unbound,
cling_to_edge,
bound,
bound_stick_to_left
Expand Down Expand Up @@ -292,18 +291,13 @@ namespace
return !(Item.Flags & (LIF_HIDDEN | LIF_FILTERED));
}

std::pair<int, int> item_hpos_limits(const item_hscroll_policy Policy, const int ItemLength, const int MaxItemLength, const int TextAreaWidth) noexcept
std::pair<int, int> item_hpos_limits(const item_hscroll_policy Policy, const int ItemLength, const int TextAreaWidth) noexcept
{
assert(ItemLength > 0);
assert(MaxItemLength > 0);
assert(TextAreaWidth > 0);
assert(ItemLength <= MaxItemLength);

switch (Policy)
{
case item_hscroll_policy::unbound:
return{ 1 - MaxItemLength, TextAreaWidth - 1 + (MaxItemLength - ItemLength) };

case item_hscroll_policy::cling_to_edge:
return{ 1 - ItemLength, TextAreaWidth - 1 };

Expand Down Expand Up @@ -380,6 +374,25 @@ namespace
return Shift;
}

bool set_item_hpos(MenuItemEx& Item, std::regular_invocable<int /*ItemLength*/> auto const GetNewHPos, const bool ShowAmpersand, const int TextAreaWidth, const item_hscroll_policy Policy)
{
const auto ItemLength{ static_cast<int>(ShowAmpersand ? visual_string_length(Item.Name) : HiStrlen(Item.Name)) };

// 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(GetNewHPos(ItemLength), HPosLimits.first, HPosLimits.second);

if (Item.HPos == ClampedHPos)
return false;

Item.HPos = ClampedHPos;
return true;
}

// Indices in the color array
enum class color_indices
{
Expand Down Expand Up @@ -2131,6 +2144,7 @@ int VMenu::VisualPosToReal(int VPos) const


/*
* TBD: Remove
HScrollEnBlocMode
? item_hscroll_policy::unbound
: CheckFlags(VMENU_ENABLEALIGNANNOTATIONS) ? item_hscroll_policy::cling_to_edge : item_hscroll_policy::bound_stick_to_left))
Expand All @@ -2151,10 +2165,15 @@ bool VMenu::SetAllItemsSmartHPos(const int NewHPos)

for (auto& Item : Items)
{
if (Item.Flags & LIF_SEPARATOR) continue;

if (SetItemSmartHPos(Item, NewHPos, TextAreaWidth, Policy))
if (set_item_hpos(
Item,
[=](int ItemLength) { return NewHPos >= 0 ? NewHPos : TextAreaWidth - ItemLength + NewHPos + 1; },
CheckFlags(VMENU_SHOWAMPERSAND),
TextAreaWidth,
Policy))
{
NeedRedraw = true;
}
}

if (NeedRedraw) SetMenuFlags(VMENU_UPDATEREQUIRED);
Expand All @@ -2169,9 +2188,16 @@ bool VMenu::SetCurItemSmartHPos(const int NewHPos)
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 (!SetItemSmartHPos(Item, NewHPos, TextAreaWidth, Policy)) return false;
if (!set_item_hpos(
Item,
[=](int ItemLength) { return NewHPos >= 0 ? NewHPos : TextAreaWidth - ItemLength + NewHPos + 1; },
CheckFlags(VMENU_SHOWAMPERSAND),
TextAreaWidth,
Policy))
{
return false;
}

SetMenuFlags(VMENU_UPDATEREQUIRED);
return true;
Expand All @@ -2197,9 +2223,9 @@ bool VMenu::ShiftCurItemHPos(const int Shift)
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;
if (!set_item_hpos(Item, [&](int) { return Item.HPos + Shift; }, CheckFlags(VMENU_SHOWAMPERSAND), TextAreaWidth, Policy))
return false;

SetMenuFlags(VMENU_UPDATEREQUIRED);
return true;
Expand Down Expand Up @@ -2277,57 +2303,58 @@ bool VMenu::ShiftAllItemsHPosLimited(const int Shift, const int TextAreaWidth)

for (auto& Item : Items)
{
if (Item.Flags & LIF_SEPARATOR) continue;

if (SetItemAbsoluteHPos(Item, Item.HPos + Shift, TextAreaWidth, Policy))
if (set_item_hpos(Item, [&](int) { return Item.HPos + Shift; }, CheckFlags(VMENU_SHOWAMPERSAND), 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: (TextAreaWidth <= 0) not needed?
if (ItemLength <= 0 || TextAreaWidth <= 0) return false;

const auto HPosLimits{ item_hpos_limits(Policy, ItemLength, static_cast<int>(m_MaxItemLength), 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)
{
const auto ItemLength{ static_cast<int>(CheckFlags(VMENU_SHOWAMPERSAND) ? visual_string_length(Item.Name) : HiStrlen(Item.Name)) };
return SetItemAbsoluteHPos(Item, NewHPos, ItemLength, TextAreaWidth, Policy);
}

bool VMenu::SetItemSmartHPos(MenuItemEx& Item, const int NewHPos, const int TextAreaWidth, const item_hscroll_policy Policy)
{
const auto ItemLength{ static_cast<int>(CheckFlags(VMENU_SHOWAMPERSAND) ? visual_string_length(Item.Name) : HiStrlen(Item.Name)) };
return SetItemAbsoluteHPos(Item, NewHPos >= 0 ? NewHPos : TextAreaWidth - ItemLength + NewHPos + 1, ItemLength, TextAreaWidth, Policy);
}

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;
});
}
// 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()
{
Expand Down Expand Up @@ -3501,32 +3528,31 @@ TEST_CASE("item.hpos.limits")
static const struct test_data
{
int ItemLength;
int MaxItemLength;
int TextAreaWidth;
// unbound, cling_to_edge, bound, bound_stick_to_left
std::initializer_list<std::pair<int, int>> Expected;
} TestDataPoints[] =
{
{ 1, 10, 5, { { -9, 13 }, { 0, 4 }, { 0, 4 }, { 0, 0 } } },
{ 3, 10, 5, { { -9, 11 }, { -2, 4 }, { 0, 2 }, { 0, 0 } } },
{ 5, 10, 5, { { -9, 9 }, { -4, 4 }, { 0, 0 }, { 0, 0 } } },
{ 7, 10, 5, { { -9, 7 }, { -6, 4 }, { -2, 0 }, { -2, 0 } } },
{ 10, 10, 5, { { -9, 4 }, { -9, 4 }, { -5, 0 }, { -5, 0 } } },
{ 1, 5, 5, { { -4, 8 }, { 0, 4 }, { 0, 4 }, { 0, 0 } } },
{ 3, 5, 5, { { -4, 6 }, { -2, 4 }, { 0, 2 }, { 0, 0 } } },
{ 5, 5, 5, { { -4, 4 }, { -4, 4 }, { 0, 0 }, { 0, 0 } } },
{ 1, 5, 10, { { -4, 13 }, { 0, 9 }, { 0, 9 }, { 0, 0 } } },
{ 3, 5, 10, { { -4, 11 }, { -2, 9 }, { 0, 7 }, { 0, 0 } } },
{ 5, 5, 10, { { -4, 9 }, { -4, 9 }, { 0, 5 }, { 0, 0 } } },
{ 1, 5, { { 0, 4 }, { 0, 4 }, { 0, 0 } } },
{ 3, 5, { { -2, 4 }, { 0, 2 }, { 0, 0 } } },
{ 5, 5, { { -4, 4 }, { 0, 0 }, { 0, 0 } } },
{ 7, 5, { { -6, 4 }, { -2, 0 }, { -2, 0 } } },
{ 10, 5, { { -9, 4 }, { -5, 0 }, { -5, 0 } } },
{ 1, 5, { { 0, 4 }, { 0, 4 }, { 0, 0 } } },
{ 3, 5, { { -2, 4 }, { 0, 2 }, { 0, 0 } } },
{ 5, 5, { { -4, 4 }, { 0, 0 }, { 0, 0 } } },
{ 1, 10, { { 0, 9 }, { 0, 9 }, { 0, 0 } } },
{ 3, 10, { { -2, 9 }, { 0, 7 }, { 0, 0 } } },
{ 5, 10, { { -4, 9 }, { 0, 5 }, { 0, 0 } } },
};

for (const auto& TestDataPoint : TestDataPoints)
{
for (const auto& Policy :
{ item_hscroll_policy::unbound, item_hscroll_policy::cling_to_edge, item_hscroll_policy::bound, item_hscroll_policy::bound_stick_to_left })
{ item_hscroll_policy::cling_to_edge, item_hscroll_policy::bound, item_hscroll_policy::bound_stick_to_left })
{
REQUIRE(std::ranges::data(TestDataPoint.Expected)[std::to_underlying(Policy)]
== item_hpos_limits(Policy, TestDataPoint.ItemLength, TestDataPoint.MaxItemLength, TestDataPoint.TextAreaWidth));
== item_hpos_limits(Policy, TestDataPoint.ItemLength, TestDataPoint.TextAreaWidth));
}
}
}
Expand Down
9 changes: 3 additions & 6 deletions far/vmenu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,13 +309,10 @@ class VMenu final: public Modal



[[nodiscard]] bool SetItemAbsoluteHPos(MenuItemEx& Item, int NewHPos, int ItemLength, int TextAreaWidth, item_hscroll_policy Policy);
[[nodiscard]] bool SetItemAbsoluteHPos(MenuItemEx& Item, int NewHPos, int TextAreaWidth, item_hscroll_policy Policy);
//[[nodiscard]] bool SetItemAbsoluteHPos(MenuItemEx& Item, int NewHPos, int ItemLength, int TextAreaWidth, item_hscroll_policy Policy);
//[[nodiscard]] bool SetItemAbsoluteHPos(MenuItemEx& Item, int NewHPos, int TextAreaWidth, item_hscroll_policy Policy);
// Negative NewHPos is relative to the right edge, e.i., -1 aligns the item to the right
[[nodiscard]] bool SetItemSmartHPos(MenuItemEx& Item, int NewHPos, int TextAreaWidth, item_hscroll_policy Policy);
// Shifts item's HPos; if Shift is positive, the item visually moves right
[[nodiscard]] bool ShiftItemHPos(MenuItemEx& Item, int Shift, int TextAreaWidth, item_hscroll_policy Policy);
[[nodiscard]] bool ShiftAllItemsHPos(int Shift, item_hscroll_policy Policy);
//[[nodiscard]] bool SetItemSmartHPos(MenuItemEx& Item, int NewHPos, int TextAreaWidth, item_hscroll_policy Policy);

void UpdateMaxLengthFromTitles();
void UpdateMaxLength(size_t Length);
Expand Down

0 comments on commit 74fde14

Please sign in to comment.