Repository :
https://github.com/FarGroup/FarManager
On branch : master
Link :
https://github.com/FarGroup/FarManager/commit/f69e89af992254ebb2ac1c1864a238320a3e3641
>---------------------------------------------------------------
commit f69e89af992254ebb2ac1c1864a238320a3e3641
Author: Michael Z. Kadaner <
MKad...@users.noreply.github.com>
Date: Sun Jun 28 20:24:10 2026 -0400
Made `menu_item::Name` private and use cached `VisualLength` whenever possible.
>---------------------------------------------------------------
f69e89af992254ebb2ac1c1864a238320a3e3641
far/changelog | 5 +++++
far/codepage_selection.cpp | 4 ++--
far/config.cpp | 38 +++++++++++++++++++-------------------
far/dialog.cpp | 20 ++++++++++----------
far/diskmenu.cpp | 4 ++--
far/editcontrol.cpp | 12 ++++++------
far/filelist.cpp | 10 +++++-----
far/findfile.cpp | 2 +-
far/history.cpp | 7 +++----
far/hotplug.cpp | 12 ++++++------
far/macroapi.cpp | 25 ++++++++++++-------------
far/plugapi.cpp | 2 +-
far/plugins.cpp | 12 ++++++------
far/print.cpp | 2 +-
far/shortcuts.cpp | 12 ++++++------
far/usermenu.cpp | 4 ++--
far/vbuild.m4 | 2 +-
far/vmenu.cpp | 45 +++++++++++++++++++++++++++------------------
far/vmenu.hpp | 30 +++++++++++++++++++++++++-----
far/vmenu2.cpp | 4 ++--
20 files changed, 142 insertions(+), 110 deletions(-)
diff --git a/far/changelog b/far/changelog
index 0f04d18c6..bdd3461d4 100644
--- a/far/changelog
+++ b/far/changelog
@@ -1,3 +1,8 @@
+--------------------------------------------------------------------------------
+MZK 2026-07-06 21:25:25-04:00 - build 6710
+
+1. Made `menu_item::Name` private and use cached `VisualLength` whenever possible.
+
--------------------------------------------------------------------------------
drkns 2026-07-06 17:41:31+01:00 - build 6709
diff --git a/far/codepage_selection.cpp b/far/codepage_selection.cpp
index 7c559114b..3b385e6a4 100644
--- a/far/codepage_selection.cpp
+++ b/far/codepage_selection.cpp
@@ -434,7 +434,7 @@ void codepages::SetFavorite(bool State)
DeleteFavorite(codePage);
// Создаём новый элемент меню
- menu_item_ex newItem{ CodePagesMenu->current().Name };
+ menu_item_ex newItem{ CodePagesMenu->current().GetName() };
newItem.SimpleUserData = codePage;
// Сохраняем позицию курсора
size_t position = CodePagesMenu->GetSelectPos();
@@ -614,7 +614,7 @@ void codepages::EditCodePageName()
const auto Position = CodePagesMenu->GetSelectPos();
if (IsPositionStandard(Position))
return;
- string_view CodePageName = CodePagesMenu->at(Position).Name;
+ string_view CodePageName = CodePagesMenu->at(Position).GetName();
const auto BoxPosition = CodePageName.find(BoxSymbols[BS_V1]);
if (BoxPosition == string_view::npos)
return;
diff --git a/far/config.cpp b/far/config.cpp
index ed21246e8..d95a96eef 100644
--- a/far/config.cpp
+++ b/far/config.cpp
@@ -1162,13 +1162,13 @@ void Options::SetFilePanelModes()
for (const auto i: std::views::iota(0uz, ViewSettings.size()))
{
- ModeListMenu[RealModeToDisplay(i)].Name = ViewSettings[i].Name;
+ ModeListMenu[RealModeToDisplay(i)].SetName(ViewSettings[i].Name);
}
for (const auto i: std::views::iota(0uz, predefined_panel_modes_count))
{
- if (ModeListMenu[i].Name.empty())
- ModeListMenu[i].Name = msg(PredefinedNames[i]);
+ if (ModeListMenu[i].GetName().empty())
+ ModeListMenu[i].SetName(msg(PredefinedNames[i]));
}
if (MenuCount > predefined_panel_modes_count)
@@ -1301,7 +1301,7 @@ void Options::SetFilePanelModes()
auto ModeDlg = MakeDialogItems<MD_COUNT>(
{
- { DI_DOUBLEBOX, {{3, 1 }, {72, 17}}, DIF_NONE, AddNewMode ? L""sv : ModeListMenu[CurMode].Name, },
+ { DI_DOUBLEBOX, {{3, 1 }, {72, 17}}, DIF_NONE, AddNewMode ? L""sv : ModeListMenu[CurMode].GetName(), },
{ DI_TEXT, {{5, 2 }, {0, 2 }}, DIF_NONE, msg(lng::MEditPanelModeName), },
{ DI_EDIT, {{5, 3 }, {70, 3 }}, DIF_FOCUS, },
{ DI_TEXT, {{5, 4 }, {0, 4 }}, DIF_NONE, msg(lng::MEditPanelModeTypes), },
@@ -3076,7 +3076,7 @@ void Options::ShellOptions(bool LastCommand, const MOUSE_EVENT_RECORD *MouseEven
for (const auto i: std::views::iota(0uz, predefined_panel_modes_count))
{
if (!ViewSettings[i].Name.empty())
- Menu[RealModeToDisplay(i)].Name = ViewSettings[i].Name;
+ Menu[RealModeToDisplay(i)].SetName(ViewSettings[i].Name);
}
};
@@ -3094,11 +3094,11 @@ void Options::ShellOptions(bool LastCommand, const MOUSE_EVENT_RECORD *MouseEven
{ msg(lng::MMenuOwnersView), 0, KEY_CTRL8 },
{ msg(lng::MMenuLinksView), 0, KEY_CTRL9 },
{ msg(lng::MMenuAlternativeView), 0, KEY_CTRL0 },
- { {}, LIF_SEPARATOR },
+ { string{}, LIF_SEPARATOR },
{ msg(lng::MMenuInfoPanel), 0, KEY_CTRLL },
{ msg(lng::MMenuTreePanel), no_tree, KEY_CTRLT },
{ msg(lng::MMenuQuickView), 0, KEY_CTRLQ },
- { {}, LIF_SEPARATOR },
+ { string{}, LIF_SEPARATOR, {} },
{ msg(lng::MMenuSortModes), 0, KEY_CTRLF12 },
{ msg(lng::MMenuLongNames), 0, KEY_CTRLN },
{ msg(lng::MMenuTogglePanel), 0, KEY_CTRLF1 },
@@ -3118,15 +3118,15 @@ void Options::ShellOptions(bool LastCommand, const MOUSE_EVENT_RECORD *MouseEven
{ msg(lng::MMenuCreateFolder), 0, KEY_F7 },
{ msg(lng::MMenuDelete), 0, KEY_F8 },
{ msg(lng::MMenuWipe), 0, KEY_ALTDEL },
- { {}, LIF_SEPARATOR },
+ { string{}, LIF_SEPARATOR },
{ msg(lng::MMenuAdd), 0, KEY_SHIFTF1 },
{ msg(lng::MMenuExtract), 0, KEY_SHIFTF2 },
{ msg(lng::MMenuArchiveCommands), 0, KEY_SHIFTF3 },
- { {}, LIF_SEPARATOR },
+ { string{}, LIF_SEPARATOR },
{ msg(lng::MMenuAttributes), 0, KEY_CTRLA },
{ msg(lng::MMenuApplyCommand), 0, KEY_CTRLG },
{ msg(lng::MMenuDescribe), 0, KEY_CTRLZ },
- { {}, LIF_SEPARATOR },
+ { string{}, LIF_SEPARATOR },
{ msg(lng::MMenuSelectGroup), 0, KEY_ADD },
{ msg(lng::MMenuUnselectGroup), 0, KEY_SUBTRACT },
{ msg(lng::MMenuInvertSelection), 0, KEY_MULTIPLY },
@@ -3142,16 +3142,16 @@ void Options::ShellOptions(bool LastCommand, const MOUSE_EVENT_RECORD *MouseEven
{ msg(lng::MMenuFindFolder), no_tree, KEY_ALTF10 },
{ msg(lng::MMenuViewHistory), 0, KEY_ALTF11 },
{ msg(lng::MMenuFoldersHistory), 0, KEY_ALTF12 },
- { {}, LIF_SEPARATOR, 0 },
+ { string{}, LIF_SEPARATOR, 0 },
{ msg(lng::MMenuSwapPanels), 0, KEY_CTRLU },
{ msg(lng::MMenuTogglePanels), 0, KEY_CTRLO },
{ msg(lng::MMenuCompareFolders), 0, 0 },
- { {}, LIF_SEPARATOR, 0 },
+ { string{}, LIF_SEPARATOR, 0 },
{ msg(lng::MMenuUserMenu), 0, 0 },
{ msg(lng::MMenuFileAssociations), 0, 0 },
{ msg(lng::MMenuFolderShortcuts), 0, 0 },
{ msg(lng::MMenuFilter), 0, KEY_CTRLI },
- { {}, LIF_SEPARATOR, 0 },
+ { string{}, LIF_SEPARATOR, 0 },
{ msg(lng::MMenuPluginCommands), 0, KEY_F11 },
{ msg(lng::MMenuWindowsList), 0, KEY_F12 },
{ msg(lng::MMenuProcessList), 0, KEY_CTRLW },
@@ -3174,19 +3174,19 @@ void Options::ShellOptions(bool LastCommand, const MOUSE_EVENT_RECORD *MouseEven
{ msg(lng::MMenuAutoCompleteSettings), 0 },
{ msg(lng::MMenuInfoPanelSettings), 0 },
{ msg(lng::MMenuMaskGroups), 0 },
- { {}, LIF_SEPARATOR },
+ { string{}, LIF_SEPARATOR },
{ msg(lng::MMenuConfirmation), 0 },
{ msg(lng::MMenuFilePanelModes), 0 },
{ msg(lng::MMenuFileDescriptions), 0 },
{ msg(lng::MMenuFolderInfoFiles), 0 },
- { {}, LIF_SEPARATOR },
+ { string{}, LIF_SEPARATOR },
{ msg(lng::MMenuViewer), 0 },
{ msg(lng::MMenuEditor), 0 },
{ msg(lng::MMenuCodePages), 0 },
- { {}, LIF_SEPARATOR },
+ { string{}, LIF_SEPARATOR },
{ msg(lng::MMenuColors), 0 },
{ msg(lng::MMenuFilesHighlighting), 0 },
- { {}, LIF_SEPARATOR },
+ { string{}, LIF_SEPARATOR },
{ msg(lng::MMenuSaveSetup), 0, KEY_SHIFTF9 },
};
const auto OptionsMenuStrings = VMenu::AddHotkeys(OptionsMenu);
@@ -3203,11 +3203,11 @@ void Options::ShellOptions(bool LastCommand, const MOUSE_EVENT_RECORD *MouseEven
{ msg(lng::MMenuOwnersView), 0, KEY_CTRL8 },
{ msg(lng::MMenuLinksView), 0, KEY_CTRL9 },
{ msg(lng::MMenuAlternativeView), 0, KEY_CTRL0 },
- { {}, LIF_SEPARATOR },
+ { string{}, LIF_SEPARATOR },
{ msg(lng::MMenuInfoPanel), 0, KEY_CTRLL },
{ msg(lng::MMenuTreePanel), no_tree, KEY_CTRLT },
{ msg(lng::MMenuQuickView), 0, KEY_CTRLQ },
- { {}, LIF_SEPARATOR },
+ { string{}, LIF_SEPARATOR },
{ msg(lng::MMenuSortModes), 0, KEY_CTRLF12 },
{ msg(lng::MMenuLongNames), 0, KEY_CTRLN },
{ msg(lng::MMenuTogglePanelRight), 0, KEY_CTRLF2 },
diff --git a/far/dialog.cpp b/far/dialog.cpp
index dc500eff4..4574bcd31 100644
--- a/far/dialog.cpp
+++ b/far/dialog.cpp
@@ -214,7 +214,7 @@ static size_t ConvertItemEx2(const DialogItemEx& ItemEx, FarGetDialogItem *Item,
size+=ListBoxSize*sizeof(FarListItem);
for (const auto i: std::views::iota(0uz, ListBoxSize))
{
- size += (ListBox->at(i).Name.size() + 1) * sizeof(wchar_t);
+ size += (ListBox->at(i).GetName().size() + 1) * sizeof(wchar_t);
}
}
}
@@ -246,7 +246,7 @@ static size_t ConvertItemEx2(const DialogItemEx& ItemEx, FarGetDialogItem *Item,
auto& item = ListBox->at(ii);
listItems[ii].Flags = item.Flags;
listItems[ii].Text = text;
- text += item.Name.copy(text, item.Name.npos);
+ text += item.GetName().copy(text, item.GetName().npos);
*text++ = {};
listItems[ii].UserData = item.SimpleUserData;
listItems[ii].Reserved = 0;
@@ -3901,11 +3901,11 @@ int Dialog::SelectFromComboBox(DialogItemEx& CurItem, DlgEdit& EditLine)
if (CurItem.Flags & DIF_LISTNOAMPERSAND)
{
- strStr = remove_highlight(ItemPtr.Name);
+ strStr = remove_highlight(ItemPtr.GetName());
EditLine.SetString(strStr);
}
else
- EditLine.SetString(ItemPtr.Name);
+ EditLine.SetString(ItemPtr.GetName());
EditLine.SetLeftPos(0);
Redraw();
@@ -4895,7 +4895,7 @@ intptr_t Dialog::SendMessage(intptr_t Msg,intptr_t Param1,void* Param2)
auto& Item = ListItems->Item;
Item = {};
Item.Flags=ListMenuItem.Flags;
- Item.Text=ListMenuItem.Name.c_str();
+ Item.Text=ListMenuItem.GetName().c_str();
Item.UserData = ListMenuItem.SimpleUserData;
Item.Reserved = 0;
@@ -5042,9 +5042,9 @@ intptr_t Dialog::SendMessage(intptr_t Msg,intptr_t Param1,void* Param2)
const auto& ListMenuItem = ListBox->at(ListBox->GetSelectPos());
const auto Edit = static_cast<DlgEdit*>(CurItem.ObjPtr);
if (CurItem.Flags & DIF_LISTNOAMPERSAND)
- Edit->SetHiString(ListMenuItem.Name);
+ Edit->SetHiString(ListMenuItem.GetName());
else
- Edit->SetString(ListMenuItem.Name);
+ Edit->SetString(ListMenuItem.GetName());
Edit->RemoveSelection();
}
}
@@ -5529,8 +5529,8 @@ intptr_t Dialog::SendMessage(intptr_t Msg,intptr_t Param1,void* Param2)
if (CurItem.ListPtr->GetShowItemCount())
{
const auto& ListMenuItem = CurItem.ListPtr->current();
- Ptr = ListMenuItem.Name.data();
- Len = ListMenuItem.Name.size();
+ Ptr = ListMenuItem.GetName().data();
+ Len = ListMenuItem.GetName().size();
}
InitItemData();
break;
@@ -5579,7 +5579,7 @@ intptr_t Dialog::SendMessage(intptr_t Msg,intptr_t Param1,void* Param2)
Len=0;
if (CurItem.ListPtr->GetShowItemCount())
{
- Len = CurItem.ListPtr->current().Name.size();
+ Len = CurItem.ListPtr->current().GetName().size();
}
break;
diff --git a/far/diskmenu.cpp b/far/diskmenu.cpp
index 88dce57d0..a506446ef 100644
--- a/far/diskmenu.cpp
+++ b/far/diskmenu.cpp
@@ -791,7 +791,7 @@ static int ChangeDiskMenu(panel_ptr Owner, int Pos, bool FirstCall)
inplace::escape_ampersands(ItemName);
ItemName.insert(0, 1, L'&');
- ChDiskItem.Name = std::move(ItemName);
+ ChDiskItem.SetName(std::move(ItemName));
ChDiskItem.ComplexUserData = item;
ChDisk->AddItem(ChDiskItem);
@@ -956,7 +956,7 @@ static int ChangeDiskMenu(panel_ptr Owner, int Pos, bool FirstCall)
{
[&](plugin_item const& item)
{
- if (Global->CtrlObject->Plugins->SetHotKeyDialog(item.pPlugin, item.Uuid, hotkey_type::drive_menu, trim(string_view(ChDisk->at(SelPos).Name).substr(3))))
+ if (Global->CtrlObject->Plugins->SetHotKeyDialog(item.pPlugin, item.Uuid, hotkey_type::drive_menu, trim(string_view{ ChDisk->at(SelPos).GetName() }.substr(3))))
RetCode = SelPos;
},
[](disk_item const& item)
diff --git a/far/editcontrol.cpp b/far/editcontrol.cpp
index 1f079aa9b..6ea58b442 100644
--- a/far/editcontrol.cpp
+++ b/far/editcontrol.cpp
@@ -444,7 +444,7 @@ int EditControl::AutoCompleteProc(bool Manual,bool DelBlock,Manager::Key& BackKe
{
for (const auto i: std::views::iota(0uz, pList->size()))
{
- const auto& Text = pList->at(i).Name;
+ const auto& Text = pList->at(i).GetName();
if (!starts_with_icase(Text, Str))
continue;
@@ -486,7 +486,7 @@ int EditControl::AutoCompleteProc(bool Manual,bool DelBlock,Manager::Key& BackKe
{
int SelStart = GetLength();
- const auto& FirstItem = ComplMenu->at(0).Name;
+ const auto& FirstItem = ComplMenu->at(0).GetName();
const auto Data = ComplMenu->GetComplexUserDataPtr<cmp_user_data>(0);
// magic
@@ -516,7 +516,7 @@ int EditControl::AutoCompleteProc(bool Manual,bool DelBlock,Manager::Key& BackKe
}
};
- if(ComplMenu->size() > 1 || (ComplMenu->size() == 1 && !equal_icase(CurrentInput, ComplMenu->at(0).Name)))
+ if(ComplMenu->size() > 1 || (ComplMenu->size() == 1 && !equal_icase(CurrentInput, ComplMenu->at(0).GetName())))
{
ComplMenu->SetMenuFlags(VMENU_WRAPMODE | VMENU_SHOWAMPERSAND);
if(!DelBlock && Global->Opt->AutoComplete.AppendCompletion && (!m_Flags.Check(FEDITLINE_PERSISTENTBLOCKS) || Global->Opt->AutoComplete.ShowList))
@@ -555,7 +555,7 @@ int EditControl::AutoCompleteProc(bool Manual,bool DelBlock,Manager::Key& BackKe
{
PrevPos=CurPos;
IsChanged = false;
- SetString(CurPos? ComplMenu->at(CurPos).Name : CurrentInput);
+ SetString(CurPos? ComplMenu->at(CurPos).GetName() : CurrentInput);
Show();
}
@@ -604,7 +604,7 @@ int EditControl::AutoCompleteProc(bool Manual,bool DelBlock,Manager::Key& BackKe
Complete(*ComplMenu, CurrentInput);
- if (ComplMenu->size() > 1 || (ComplMenu->size() == 1 && !equal_icase(CurrentInput, ComplMenu->at(0).Name)))
+ if (ComplMenu->size() > 1 || (ComplMenu->size() == 1 && !equal_icase(CurrentInput, ComplMenu->at(0).GetName())))
{
if(none_of(MenuKey, KEY_BS, KEY_DEL, KEY_NUMDEL) && Global->Opt->AutoComplete.AppendCompletion)
{
@@ -757,7 +757,7 @@ int EditControl::AutoCompleteProc(bool Manual,bool DelBlock,Manager::Key& BackKe
{
if(Global->Opt->AutoComplete.ModalList)
{
- SetString(ComplMenu->at(ExitCode).Name);
+ SetString(ComplMenu->at(ExitCode).GetName());
Show();
}
else
diff --git a/far/filelist.cpp b/far/filelist.cpp
index fb9ffd808..61e418972 100644
--- a/far/filelist.cpp
+++ b/far/filelist.cpp
@@ -4715,7 +4715,7 @@ static int select_sort_layer(std::vector<std::pair<panel_sort, sort_order>> cons
for (const auto& i: SortModes)
{
auto& Item = AvailableSortModesMenuItems[i.MenuPosition];
- Item.Name = msg(i.Label);
+ Item.SetName(msg(i.Label));
if (std::ranges::any_of(SortLayers, [&](std::pair<panel_sort, sort_order> const& Layer) { return Layer.first == static_cast<panel_sort>(&i - SortModes); }))
{
@@ -4803,7 +4803,7 @@ static void edit_sort_layers(int MenuPos)
{
const auto NewSortModeIndex = std::ranges::find(SortModes, Result, &sort_mode::MenuPosition) - SortModes;
const auto Order = SortModes[NewSortModeIndex].DefaultLayers.begin()->second;
- SortLayersMenu->at(Pos).Name = msg(SortModes[NewSortModeIndex].Label);
+ SortLayersMenu->at(Pos).SetName(msg(SortModes[NewSortModeIndex].Label));
SortLayersMenu->at(Pos).SetCustomCheck(order_indicator(Order));
SortLayers[Pos] = { static_cast<panel_sort>(NewSortModeIndex), Order };
SortLayersMenu->Redraw();
@@ -4885,11 +4885,11 @@ void FileList::SelectSortMode()
{
auto& Item = SortMenu[i.MenuPosition];
- Item.Name = msg(i.Label);
+ Item.SetName(msg(i.Label));
Item.AccelKey = i.MenuKey;
}
- static const menu_item MenuSeparator{ {}, LIF_SEPARATOR };
+ static const menu_item MenuSeparator{ string{}, LIF_SEPARATOR };
OpenMacroPluginInfo ompInfo{ MCT_GETCUSTOMSORTMODES };
MacroPluginReturn const* mpr{};
@@ -4907,7 +4907,7 @@ void FileList::SelectSortMode()
SortMenu.emplace_back(MenuSeparator);
for (size_t i=0; i < mpr->Count; i += 3)
{
- SortMenu.emplace_back(menu_item{ mpr->Values[i + 2].String });
+ SortMenu.emplace_back(menu_item{ mpr->Values[i + 2].String, {} });
}
}
else
diff --git a/far/findfile.cpp b/far/findfile.cpp
index 53dabb633..52f130e4b 100644
--- a/far/findfile.cpp
+++ b/far/findfile.cpp
@@ -702,7 +702,7 @@ intptr_t FindFiles::MainDlgProc(Dialog* Dlg, intptr_t Msg, intptr_t Param1, void
const int TitlePosition = 1;
const auto CpEnum = codepages::GetFavoritesEnumerator();
const auto Title = msg(std::ranges::any_of(CpEnum, [](auto const& i){ return i.second & CPST_FIND; })? lng::MFindFileSelectedCodePages : lng::MFindFileAllCodePages);
- Dlg->GetAllItem()[FAD_COMBOBOX_CP].ListPtr->at(TitlePosition).Name = Title;
+ Dlg->GetAllItem()[FAD_COMBOBOX_CP].ListPtr->at(TitlePosition).SetName(Title);
FarListPos Position{ sizeof(Position) };
Dlg->SendMessage(DM_LISTGETCURPOS, FAD_COMBOBOX_CP, &Position);
if (Position.SelectPos == TitlePosition)
diff --git a/far/history.cpp b/far/history.cpp
index d50487836..8fac06f64 100644
--- a/far/history.cpp
+++ b/far/history.cpp
@@ -297,10 +297,9 @@ history_return_type History::ProcessMenu(string& strStr, UUID* const Uuid, strin
LastDay = SavedTime.Day;
LastMonth = SavedTime.Month;
LastYear = SavedTime.Year;
- menu_item_ex Separator{ LIF_SEPARATOR };
- string Time;
- std::tie(Separator.Name, Time) = time_point_to_localtime_string(i.Time, 8, 1);
- HistoryMenu.AddItem(Separator);
+
+ auto [Date, Time] { time_point_to_localtime_string(i.Time, 8, 1) };
+ HistoryMenu.AddItem(menu_item_ex{ std::move(Date), LIF_SEPARATOR });
}
strRecord += i.Name;
diff --git a/far/hotplug.cpp b/far/hotplug.cpp
index 2b100dbc5..3aa86e44c 100644
--- a/far/hotplug.cpp
+++ b/far/hotplug.cpp
@@ -587,7 +587,7 @@ void ShowHotplugDevices()
if (GetDevicePropertyRecursive(i.DevInst, CM_DRP_DEVICEDESC, strDescription) && !strDescription.empty())
{
inplace::trim(strDescription);
- ListItem.Name = strDescription;
+ ListItem.SetName(strDescription);
}
string strFriendlyName;
@@ -599,18 +599,18 @@ void ShowHotplugDevices()
{
if (!equal_icase(strDescription, strFriendlyName))
{
- append(ListItem.Name, L" \""sv, strFriendlyName, L"\""sv);
+ ListItem.SetName(concat(ListItem.GetName(), L" \""sv, strFriendlyName, L"\""sv));
}
}
else
{
- ListItem.Name = strFriendlyName;
+ ListItem.SetName(strFriendlyName);
}
}
- if (ListItem.Name.empty())
+ if (ListItem.GetName().empty())
{
- ListItem.Name = L"UNKNOWN"sv;
+ ListItem.SetName(L"UNKNOWN"s);
}
HotPlugList->AddItem(ListItem);
}
@@ -661,7 +661,7 @@ void ShowHotplugDevices()
msg(lng::MError),
{
msg(lng::MChangeCouldNotEjectHotPlugMedia2),
- HotPlugList->at(I).Name
+ HotPlugList->at(I).GetName()
},
{ lng::MOk });
diff --git a/far/macroapi.cpp b/far/macroapi.cpp
index 722560ae8..5dc09aaf9 100644
--- a/far/macroapi.cpp
+++ b/far/macroapi.cpp
@@ -1971,7 +1971,7 @@ void FarMacroApi::menushowFunc() const
menu_item_ex NewItem{ strItems.substr(CurrentPos, SubstrLen) };
- if (NewItem.Name != L"\n"sv)
+ if (NewItem.GetName() != L"\n"sv)
{
const auto CharToFlag = [](wchar_t c)
{
@@ -1985,22 +1985,21 @@ void FarMacroApi::menushowFunc() const
}
};
- const auto NewBegin = std::ranges::find_if(NewItem.Name, [&](wchar_t i)
+ const auto NewBegin = std::ranges::find_if(NewItem.GetName(), [&](wchar_t i)
{
const auto Flag = CharToFlag(i);
NewItem.Flags |= Flag;
return !Flag;
});
-
- NewItem.Name.erase(NewItem.Name.cbegin(), NewBegin);
+ NewItem.SetName(NewItem.GetName().substr(NewBegin - NewItem.GetName().cbegin()));
}
else
- NewItem.Name.clear();
+ NewItem.SetName(string{});
if (bAutoNumbering && !(bSorting || bPacking) && !(NewItem.Flags & LIF_SEPARATOR))
{
LineCount++;
- NewItem.Name = far::format(L"{:{}} - {}"sv, LineCount, nLeftShift - 3, NewItem.Name);
+ NewItem.SetName(far::format(L"{:{}} - {}"sv, LineCount, nLeftShift - 3, NewItem.GetName()));
}
Menu->AddItem(NewItem);
CurrentPos=PosLF+1;
@@ -2016,10 +2015,10 @@ void FarMacroApi::menushowFunc() const
return false;
const auto
- strName1 = remove_highlight(a.Name),
- strName2 = remove_highlight(b.Name);
+ strName1 = remove_highlight(a.GetName()),
+ strName2 = remove_highlight(b.GetName());
- const auto Less = string_sort::less(string_view(strName1).substr(Param.Offset), string_view(strName2).substr(Param.Offset));
+ const auto Less = string_sort::less(string_view{ strName1 }.substr(Param.Offset), string_view{ strName2 }.substr(Param.Offset));
return Param.Reverse? !Less : Less;
});
}
@@ -2035,7 +2034,7 @@ void FarMacroApi::menushowFunc() const
if (!(Item.Flags & LIF_SEPARATOR))
{
LineCount++;
- Item.Name = far::format(L"{:{}} - {}"sv, LineCount, nLeftShift - 3, Item.Name);
+ Item.SetName(far::format(L"{:{}} - {}"sv, LineCount, nLeftShift - 3, Item.GetName()));
}
}
}
@@ -2151,7 +2150,7 @@ void FarMacroApi::menushowFunc() const
}
else
{
- StrResult += string_view(Menu->at(i).Name).substr(nLeftShift);
+ StrResult += string_view{ Menu->at(i).GetName() }.substr(nLeftShift);
}
StrResult += L"\n"sv;
@@ -2170,12 +2169,12 @@ void FarMacroApi::menushowFunc() const
Result=temp;
}
else
- Result = string_view(Menu->at(SelectedPos).Name).substr(nLeftShift);
+ Result = string_view{ Menu->at(SelectedPos).GetName() }.substr(nLeftShift);
}
}
else
if(!bResultAsIndex)
- Result = string_view(Menu->at(SelectedPos).Name).substr(nLeftShift);
+ Result = string_view{ Menu->at(SelectedPos).GetName() }.substr(nLeftShift);
else
Result=SelectedPos+1;
}
diff --git a/far/plugapi.cpp b/far/plugapi.cpp
index 351a4575c..6f5fffb43 100644
--- a/far/plugapi.cpp
+++ b/far/plugapi.cpp
@@ -809,7 +809,7 @@ intptr_t WINAPI apiMenuFn(
Selected++;
}
- CurItem.Name = NullToEmpty(i.Text);
+ CurItem.SetName(NullToEmpty(i.Text));
if(CurItem.Flags&LIF_SEPARATOR)
{
CurItem.AccelKey=0;
diff --git a/far/plugins.cpp b/far/plugins.cpp
index 698773233..a467f299f 100644
--- a/far/plugins.cpp
+++ b/far/plugins.cpp
@@ -1351,9 +1351,9 @@ void PluginManager::Configure(int StartPos) const
ListItem.Flags=LIF_CHECKED|L'A';
#endif // NO_WRAPPER
if (!HotKeysPresent)
- ListItem.Name = strName;
+ ListItem.SetName(strName);
else
- ListItem.Name = AddHotkey(strName, Hotkey);
+ ListItem.SetName(AddHotkey(strName, Hotkey));
PluginMenuItemData item{ i, Uuid };
@@ -1404,7 +1404,7 @@ void PluginManager::Configure(int StartPos) const
if (item)
{
const auto nOffset = HotKeysPresent? 3 : 0;
- if (SetHotKeyDialog(item->pPlugin, item->Uuid, hotkey_type::config_menu, trim(string_view(PluginList->current().Name).substr(nOffset))))
+ if (SetHotKeyDialog(item->pPlugin, item->Uuid, hotkey_type::config_menu, trim(string_view{ PluginList->current().GetName() }.substr(nOffset))))
{
NeedUpdateItems = true;
StartPos = SelPos;
@@ -1517,9 +1517,9 @@ bool PluginManager::CommandsMenu(int ModalType,int StartPos,const wchar_t *Histo
ListItem.Flags=LIF_CHECKED|L'A';
#endif // NO_WRAPPER
if (!HotKeysPresent)
- ListItem.Name = strName;
+ ListItem.SetName(strName);
else
- ListItem.Name = AddHotkey(strName, Hotkey);
+ ListItem.SetName(AddHotkey(strName, Hotkey));
PluginMenuItemData itemdata;
itemdata.pPlugin = i;
@@ -1564,7 +1564,7 @@ bool PluginManager::CommandsMenu(int ModalType,int StartPos,const wchar_t *Histo
if (ItemPtr)
{
const auto nOffset = HotKeysPresent? 3 : 0;
- if (SetHotKeyDialog(ItemPtr->pPlugin, ItemPtr->Uuid, hotkey_type::plugins_menu, trim(string_view(PluginList->current().Name).substr(nOffset))))
+ if (SetHotKeyDialog(ItemPtr->pPlugin, ItemPtr->Uuid, hotkey_type::plugins_menu, trim(string_view{ PluginList->current().GetName() }.substr(nOffset))))
{
NeedUpdateItems = true;
StartPos = SelPos;
diff --git a/far/print.cpp b/far/print.cpp
index c3155e3c3..d5962ef99 100644
--- a/far/print.cpp
+++ b/far/print.cpp
@@ -91,7 +91,7 @@ static void AddToPrintersMenu(VMenu2 *PrinterList, std::span<PRINTER_INFO_4 cons
Item.SetCheck();
Item.SetSelect(true);
}
- Item.ComplexUserData = Item.Name;
+ Item.ComplexUserData = Item.GetName();
PrinterList->AddItem(Item);
}
diff --git a/far/shortcuts.cpp b/far/shortcuts.cpp
index 9bbf22720..29259c1db 100644
--- a/far/shortcuts.cpp
+++ b/far/shortcuts.cpp
@@ -232,21 +232,21 @@ static void FillMenu(VMenu2& Menu, std::list<Shortcuts::shortcut>& List, bool co
FOR_RANGE(List, i)
{
menu_item_ex ListItem{ MakeName(*i) };
- if (ListItem.Name.empty())
+ if (ListItem.GetName().empty())
continue;
ListItem.ComplexUserData = i;
if (!raw_mode && i->is_service())
{
- if (ListItem.Name != SeparatorToken)
+ if (ListItem.GetName() != SeparatorToken)
{
if (Menu.empty())
- Menu.SetTitle(ListItem.Name);
+ Menu.SetTitle(ListItem.GetName());
continue;
}
- ListItem.Name.clear();
+ ListItem.SetName(string{});
ListItem.Flags = LIF_SEPARATOR;
}
Menu.AddItem(ListItem);
@@ -347,7 +347,7 @@ static bool EditItem(VMenu2& Menu, Shortcuts::shortcut& Item, bool raw)
return false;
auto& MenuItem = Menu.current();
- MenuItem.Name = MakeName(Item);
+ MenuItem.SetName(MakeName(Item));
return true;
}
@@ -506,7 +506,7 @@ bool Shortcuts::Get(size_t Index, data& Data)
static void MakeListName(const std::list<Shortcuts::shortcut>& List, string_view const Key, menu_item_ex& MenuItem)
{
const auto ItemName = List.empty()? msg(lng::MShortcutNone) : MakeName(List.front());
- MenuItem.Name = far::format(L"{}+&{} {} {}"sv, KeyToLocalizedText(KEY_RCTRL), Key, BoxSymbols[BS_V1], ItemName);
+ MenuItem.SetName(far::format(L"{}+&{} {} {}"sv, KeyToLocalizedText(KEY_RCTRL), Key, BoxSymbols[BS_V1], ItemName));
if (List.size() > 1)
{
MenuItem.Flags |= MIF_SUBMENU;
diff --git a/far/usermenu.cpp b/far/usermenu.cpp
index f05fe86c4..2f0c0348c 100644
--- a/far/usermenu.cpp
+++ b/far/usermenu.cpp
@@ -557,7 +557,7 @@ static void FillUserMenu(VMenu2& FarUserMenu, UserMenu::menu_container& Menu, in
if (MenuItem->strHotKey == L"--"sv)
{
FarUserMenuItem.Flags|=LIF_SEPARATOR;
- FarUserMenuItem.Name = MenuItem->strLabel;
+ FarUserMenuItem.SetName(MenuItem->strLabel);
if (NumLines==MenuPos)
{
@@ -576,7 +576,7 @@ static void FillUserMenu(VMenu2& FarUserMenu, UserMenu::menu_container& Menu, in
const auto VisualSize = visual_string_length(strHotKey);
if (Offset > VisualSize)
strHotKey.append(Offset - VisualSize, L' ');
- FarUserMenuItem.Name = concat(have_hotkey && !FuncNum? L"&"sv : L""sv, strHotKey, strLabel);
+ FarUserMenuItem.SetName(concat(have_hotkey && !FuncNum? L"&"sv : L""sv, strHotKey, strLabel));
if (MenuItem->Submenu)
{
diff --git a/far/vbuild.m4 b/far/vbuild.m4
index 0d1dacb4e..e118fbbf5 100644
--- a/far/vbuild.m4
+++ b/far/vbuild.m4
@@ -1 +1 @@
-6709
+6710
diff --git a/far/vmenu.cpp b/far/vmenu.cpp
index b75cbe59e..e3b3758a1 100644
--- a/far/vmenu.cpp
+++ b/far/vmenu.cpp
@@ -524,7 +524,7 @@ namespace
string_view get_item_text(const menu_item_ex& Item)
{
- return Item.Name;
+ return Item.GetName();
}
std::pair<int, int> item_hpos_limits(const int ItemLength, const int TextAreaWidth, const item_hscroll_policy Policy) noexcept
@@ -970,7 +970,7 @@ bool VMenu::UpdateItem(const FarListUpdate *NewItem)
Item.ComplexUserData = {};
}
- Item.Name = NullToEmpty(NewItem->Item.Text);
+ Item.SetName(NullToEmpty(NewItem->Item.Text));
UpdateItemFlags(NewItem->Index, NewItem->Item.Flags);
Item.SimpleUserData = NewItem->Item.UserData;
@@ -1385,7 +1385,7 @@ long long VMenu::VMProcess(int OpCode, void* vParam, long long iParam)
const auto& menuEx = at(iParam);
if (OpCode == MCODE_F_MENU_GETVALUE)
{
- *static_cast<string*>(vParam) = menuEx.Name;
+ *static_cast<string*>(vParam) = menuEx.GetName();
return 1;
}
else
@@ -1422,7 +1422,7 @@ long long VMenu::VMProcess(int OpCode, void* vParam, long long iParam)
{
if (!HasVisible())
return 0;
- *static_cast<string*>(vParam) = at(SelectPos).Name;
+ *static_cast<string*>(vParam) = at(SelectPos).GetName();
return 1;
}
@@ -2073,6 +2073,8 @@ bool VMenu::ClickHandler(window* Menu, int const MenuClick)
bool VMenu::ProcessMouse(const MOUSE_EVENT_RECORD *MouseEvent)
{
+ // Need to use menu_layout instead of hard-coded positions relative to m_Where
+
if (IsMouseButtonEvent(MouseEvent->dwEventFlags) && MouseEvent->dwButtonState && !m_Where.contains(MouseEvent->dwMousePosition))
{
const auto NewButtonState = MouseEvent->dwButtonState & ~IntKeyState.PrevMouseButtonState;
@@ -2815,16 +2817,17 @@ void VMenu::ConnectSeparator(const size_t ItemIndex, string& separator, const in
if (CheckFlags(VMENU_NOMERGEBORDER) || !m_FixedColumns.empty() || separator.size() <= 3)
return;
+ // Bug! The code below does not account for wide characters
for (const auto I : std::views::iota(0uz, separator.size() - 3))
{
const auto AnyPrev = ItemIndex > 0 && Items[ItemIndex - 1].HorizontalPosition == 0;
const auto AnyNext = ItemIndex < Items.size() - 1 && Items[ItemIndex + 1].HorizontalPosition == 0;
- const auto PCorrection = AnyPrev && !CheckFlags(VMENU_SHOWAMPERSAND)? HiFindRealPos(Items[ItemIndex - 1].Name, I) - I : 0;
- const auto NCorrection = AnyNext && !CheckFlags(VMENU_SHOWAMPERSAND)? HiFindRealPos(Items[ItemIndex + 1].Name, I) - I : 0;
+ const auto PCorrection = AnyPrev && !CheckFlags(VMENU_SHOWAMPERSAND)? HiFindRealPos(Items[ItemIndex - 1].GetName(), I) - I : 0;
+ const auto NCorrection = AnyNext && !CheckFlags(VMENU_SHOWAMPERSAND)? HiFindRealPos(Items[ItemIndex + 1].GetName(), I) - I : 0;
- wchar_t PrevItem = (AnyPrev && Items[ItemIndex - 1].Name.size() > I + PCorrection)? Items[ItemIndex - 1].Name[I + PCorrection] : 0;
- wchar_t NextItem = (AnyNext && Items[ItemIndex + 1].Name.size() > I + NCorrection)? Items[ItemIndex + 1].Name[I + NCorrection] : 0;
+ wchar_t PrevItem = (AnyPrev && Items[ItemIndex - 1].GetName().size() > I + PCorrection)? Items[ItemIndex - 1].GetName()[I + PCorrection] : 0;
+ wchar_t NextItem = (AnyNext && Items[ItemIndex + 1].GetName().size() > I + NCorrection)? Items[ItemIndex + 1].GetName()[I + NCorrection] : 0;
if (!PrevItem && !NextItem)
break;
@@ -2845,14 +2848,15 @@ void VMenu::ConnectSeparator(const size_t ItemIndex, string& separator, const in
void VMenu::ApplySeparatorName(const menu_item_ex& Item, string& separator) const
{
- if (Item.Name.empty() || separator.size() <= 3)
+ if (Item.GetName().empty() || separator.size() <= 3)
return;
- auto NameWidth{ std::min(Item.Name.size(), separator.size() - 2) };
+ // Bug! The code below does not account for wide characters
+ auto NameWidth{ std::min(Item.GetName().size(), separator.size() - 2) };
auto NamePos{ (separator.size() - NameWidth) / 2 };
separator[NamePos - 1] = L' ';
- separator.replace(NamePos, NameWidth, fit_to_left(Item.Name, NameWidth));
+ separator.replace(NamePos, NameWidth, fit_to_left(Item.GetName(), NameWidth));
separator[NamePos + NameWidth] = L' ';
}
@@ -3432,7 +3436,7 @@ FarListItem *VMenu::MenuItem2FarList(const menu_item_ex *MItem, FarListItem *FIt
{
*FItem = {};
FItem->Flags = MItem->Flags;
- FItem->Text = MItem->Name.c_str();
+ FItem->Text = MItem->GetName().c_str();
FItem->UserData = MItem->SimpleUserData;
return FItem;
}
@@ -3512,7 +3516,7 @@ bool VMenu::Pack()
if (!(Items[FirstIndex].Flags & LIF_SEPARATOR) && !(Items[LastIndex].Flags & LIF_SEPARATOR))
{
// Not using get_item_text because... just in case
- if (Items[FirstIndex].Name == Items[LastIndex].Name)
+ if (Items[FirstIndex].GetName() == Items[LastIndex].GetName())
{
DeleteItem(static_cast<int>(LastIndex));
}
@@ -3536,11 +3540,13 @@ const UUID& VMenu::Id() const
std::vector<string> VMenu::AddHotkeys(std::span<menu_item> const MenuItems)
{
+ // Does this function properly account for wide characters?
+
std::vector<string> Result(MenuItems.size());
const size_t MaxLength = std::ranges::fold_left(MenuItems, 0uz, [](size_t Value, const auto& i)
{
- return std::max(Value, i.Name.size());
+ return std::max(Value, i.GetName().size());
});
for (const auto& [Item, Str]: zip(MenuItems, Result))
@@ -3549,9 +3555,9 @@ std::vector<string> VMenu::AddHotkeys(std::span<menu_item> const MenuItems)
continue;
const auto Key = KeyToLocalizedText(Item.AccelKey);
- const auto Hl = HiStrlen(Item.Name) != visual_string_length(Item.Name);
- Str = fit_to_left(Item.Name, MaxLength + (Hl? 2 : 1)) + Key;
- Item.Name = Str;
+ const auto Hl = HiStrlen(Item.GetName()) != visual_string_length(Item.GetName());
+ Str = fit_to_left(Item.GetName(), MaxLength + (Hl? 2 : 1)) + Key;
+ Item.SetName(Str);
}
return Result;
@@ -3584,8 +3590,11 @@ int VMenu::CalculateTextAreaWidth() const
int VMenu::GetItemVisualLength(const menu_item_ex& Item) const
{
+ if (Item.VisualLength != Item.InvalidVisualLength)
+ return Item.VisualLength;
+
const auto ItemText{ get_item_text(Item) };
- return static_cast<int>(CheckFlags(VMENU_SHOWAMPERSAND) ? visual_string_length(ItemText) : HiStrlen(ItemText));
+ return Item.VisualLength = static_cast<int>(CheckFlags(VMENU_SHOWAMPERSAND) ? visual_string_length(ItemText) : HiStrlen(ItemText));
}
int VMenu::SafeGetItemAnnotationStart(const menu_item_ex& Item) const
diff --git a/far/vmenu.hpp b/far/vmenu.hpp
index c2bb3e645..27c3850a1 100644
--- a/far/vmenu.hpp
+++ b/far/vmenu.hpp
@@ -88,9 +88,30 @@ enum VMENU_FLAGS
struct menu_item
{
+private:
string Name;
+public:
LISTITEMFLAGS Flags{};
DWORD AccelKey{};
+ mutable int VisualLength{ InvalidVisualLength };
+ static constexpr auto InvalidVisualLength{ std::numeric_limits<decltype(VisualLength)>::min() };
+
+ menu_item() = default;
+
+ menu_item(string Name_, LISTITEMFLAGS Flags_, DWORD AccelKey_ = {})
+ : Name{ std::move(Name_) }, Flags{ Flags_ }, AccelKey{ AccelKey_ }
+ {}
+
+ const string& GetName() const noexcept
+ {
+ return Name;
+ }
+
+ void SetName(string Name_) noexcept
+ {
+ Name = Name_;
+ VisualLength = InvalidVisualLength;
+ }
unsigned long long SetCheck()
{
@@ -128,13 +149,12 @@ struct menu_item_ex: menu_item
: menu_item{ Item }
{}
- explicit menu_item_ex(LISTITEMFLAGS Flags)
- : menu_item{ string{}, Flags }
+ explicit menu_item_ex(LISTITEMFLAGS Flags_)
+ : menu_item{ string{}, Flags_ }
{}
- template<typename T> requires (std::is_constructible_v<menu_item, T, LISTITEMFLAGS>)
- explicit menu_item_ex(T&& Name, LISTITEMFLAGS Flags = 0)
- : menu_item{ std::forward<T>(Name), Flags }
+ explicit menu_item_ex(string Name_, LISTITEMFLAGS Flags_ = {})
+ : menu_item{ std::move(Name_), Flags_ }
{}
std::any ComplexUserData;
diff --git a/far/vmenu2.cpp b/far/vmenu2.cpp
index 8a9738d57..6c2a4d7eb 100644
--- a/far/vmenu2.cpp
+++ b/far/vmenu2.cpp
@@ -351,7 +351,7 @@ vmenu2_ptr VMenu2::create(const string& Title, std::span<const menu_item> const
std::vector<FarListItem> fli;
fli.reserve(Data.size());
- std::ranges::transform(Data, std::back_inserter(fli), [](const auto& i) { return FarListItem{ i.Flags, i.Name.c_str() }; });
+ std::ranges::transform(Data, std::back_inserter(fli), [](const auto& i) { return FarListItem{ i.Flags, i.GetName().c_str() }; });
FarList fl{ sizeof(fl), fli.size(), fli.data() };
@@ -438,7 +438,7 @@ int VMenu2::AddItem(const menu_item_ex& NewItem, int PosAdd)
PosAdd=n;
- FarListInsert fli{ sizeof(fli), PosAdd, { NewItem.Flags, NewItem.Name.c_str(), NewItem.SimpleUserData } };
+ FarListInsert fli{ sizeof(fli), PosAdd, { NewItem.Flags, NewItem.GetName().c_str(), NewItem.SimpleUserData } };
if(SendMessage(DM_LISTINSERT, 0, &fli)<0)
return -1;