// For easy access, we try to show favorites in the menu, similar to a list of // recently opened files. // The first menu items are for currently opened file (up to MAX_FAV_MENUS), based // on the assumption that user is usually interested in navigating current file. // Then we have a submenu for each file for which there are bookmarks (up to // MAX_FAV_SUBMENUS), each having up to MAX_FAV_MENUS menu items. // If not all favorites can be shown, we also enable "Show all favorites" menu which // will provide a way to see all favorites. // Note: not sure if that's the best layout. Maybe we should always use submenu and // put the submenu for current file as the first one (potentially named as "Current file" // or some such, to make it stand out from other submenus) static void AppendFavMenus(HMENU m, const WCHAR* currFilePath) { // To minimize mouse movement when navigating current file via favorites // menu, put favorites for current file first DisplayState* currFileFav = nullptr; if (currFilePath) { currFileFav = gFavorites.GetFavByFilePath(currFilePath); } // sort the files with favorites by base file name of file path Vec<const WCHAR*> filePathsSorted; if (HasPermission(Perm_DiskAccess)) { // only show favorites for other files, if we're allowed to open them GetSortedFilePaths(filePathsSorted, currFileFav); } if (currFileFav && currFileFav->favorites->size() > 0) { filePathsSorted.InsertAt(0, currFileFav->filePath); } if (filePathsSorted.size() == 0) { return; } AppendMenu(m, MF_SEPARATOR, 0, nullptr); gFavorites.ResetMenuIds(); UINT menuId = IDM_FAV_FIRST; size_t menusCount = filePathsSorted.size(); if (menusCount > MAX_FAV_MENUS) { menusCount = MAX_FAV_MENUS; } for (size_t i = 0; i < menusCount; i++) { const WCHAR* filePath = filePathsSorted.at(i); DisplayState* f = gFavorites.GetFavByFilePath(filePath); CrashIf(!f); HMENU sub = m; bool combined = (f->favorites->size() == 1); if (!combined) { sub = CreateMenu(); } AppendFavMenuItems(sub, f, menuId, combined, f == currFileFav); if (!combined) { if (f == currFileFav) { AppendMenu(m, MF_POPUP | MF_STRING, (UINT_PTR)sub, _TR("Current file")); } else { AutoFreeW tmp; tmp.SetCopy(path::GetBaseName(filePath)); auto fileName = win::menu::ToSafeString(tmp); AppendMenuW(m, MF_POPUP | MF_STRING, (UINT_PTR)sub, fileName); } } } }
// For easy access, we try to show favorites in the menu, similar to a list of // recently opened files. // The first menu items are for currently opened file (up to MAX_FAV_MENUS), based // on the assumption that user is usually interested in navigating current file. // Then we have a submenu for each file for which there are bookmarks (up to // MAX_FAV_SUBMENUS), each having up to MAX_FAV_MENUS menu items. // If not all favorites can be shown, we also enable "Show all favorites" menu which // will provide a way to see all favorites. // Note: not sure if that's the best layout. Maybe we should always use submenu and // put the submenu for current file as the first one (potentially named as "Current file" // or some such, to make it stand out from other submenus) static void AppendFavMenus(HMENU m, const WCHAR *currFilePath) { // To minimize mouse movement when navigating current file via favorites // menu, put favorites for current file first DisplayState *currFileFav = NULL; if (currFilePath) { currFileFav = gFavorites.GetFavByFilePath(currFilePath); } // sort the files with favorites by base file name of file path Vec<const WCHAR *> filePathsSorted; if (HasPermission(Perm_DiskAccess)) { // only show favorites for other files, if we're allowed to open them GetSortedFilePaths(filePathsSorted, currFileFav); } if (currFileFav) filePathsSorted.InsertAt(0, currFileFav->filePath); if (filePathsSorted.Count() == 0) return; AppendMenu(m, MF_SEPARATOR, 0, NULL); gFavorites.ResetMenuIds(); UINT menuId = IDM_FAV_FIRST; size_t menusCount = filePathsSorted.Count(); if (menusCount > MAX_FAV_MENUS) menusCount = MAX_FAV_MENUS; for (size_t i = 0; i < menusCount; i++) { const WCHAR *filePath = filePathsSorted.At(i); DisplayState *f = gFavorites.GetFavByFilePath(filePath); HMENU sub = m; bool combined = (f->favorites->Count() == 1); if (!combined) sub = CreateMenu(); AppendFavMenuItems(sub, f, menuId, combined, f == currFileFav); if (!combined) { if (f == currFileFav) { AppendMenu(m, MF_POPUP | MF_STRING, (UINT_PTR)sub, _TR("Current file")); } else { const WCHAR *fileName = path::GetBaseName(filePath); ScopedMem<WCHAR> s(win::menu::ToSafeString(fileName)); AppendMenu(m, MF_POPUP | MF_STRING, (UINT_PTR)sub, s); } } } }
static void VecTest() { Vec<int> ints; assert(ints.Count() == 0); ints.Append(1); ints.Push(2); ints.InsertAt(0, -1); assert(ints.Count() == 3); assert(ints.At(0) == -1 && ints.At(1) == 1 && ints.At(2) == 2); assert(ints.At(0) == -1 && ints.Last() == 2); int last = ints.Pop(); assert(last == 2); assert(ints.Count() == 2); ints.Push(3); ints.RemoveAt(0); assert(ints.Count() == 2); assert(ints.At(0) == 1 && ints.At(1) == 3); ints.Reset(); assert(ints.Count() == 0); for (int i = 0; i < 1000; i++) { ints.Push(i); } assert(ints.Count() == 1000 && ints.At(500) == 500); ints.Remove(500); assert(ints.Count() == 999 && ints.At(500) == 501); last = ints.Pop(); assert(last == 999); ints.Append(last); assert(ints.AtPtr(501) == &ints.At(501)); { Vec<int> ints2(ints); assert(ints2.Count() == 999); assert(ints.LendData() != ints2.LendData()); ints.Remove(600); assert(ints.Count() < ints2.Count()); ints2 = ints; assert(ints2.Count() == 998); } { char buf[2] = {'a', '\0'}; str::Str<char> v(0); for (int i = 0; i < 7; i++) { v.Append(buf, 1); buf[0] = buf[0] + 1; } char *s = v.LendData(); assert(str::Eq("abcdefg", s)); assert(7 == v.Count()); v.Set("helo"); assert(4 == v.Count()); assert(str::Eq("helo", v.LendData())); } { str::Str<char> v(128); v.Append("boo", 3); assert(str::Eq("boo", v.LendData())); assert(v.Count() == 3); v.Append("fop"); assert(str::Eq("boofop", v.LendData())); assert(v.Count() == 6); v.RemoveAt(2, 3); assert(v.Count() == 3); assert(str::Eq("bop", v.LendData())); v.Append('a'); assert(v.Count() == 4); assert(str::Eq("bopa", v.LendData())); char *s = v.StealData(); assert(str::Eq("bopa", s)); free(s); assert(v.Count() == 0); } { str::Str<char> v(0); for (int i = 0; i < 32; i++) { assert(v.Count() == i * 6); v.Append("lambd", 5); if (i % 2 == 0) v.Append('a'); else v.Push('a'); } for (int i=1; i<=16; i++) { v.RemoveAt((16 - i) * 6, 6); assert(v.Count() == (32 - i) * 6); } v.RemoveAt(0, 6 * 15); assert(v.Count() == 6); char *s = v.LendData(); assert(str::Eq(s, "lambda")); s = v.StealData(); assert(str::Eq(s, "lambda")); free(s); assert(v.Count() == 0); v.Append("lambda"); assert(str::Eq(v.LendData(), "lambda")); char c = v.Pop(); assert(c == 'a'); assert(str::Eq(v.LendData(), "lambd")); } VecTestAppendFmt(); { Vec<PointI *> v; srand((unsigned int)time(NULL)); for (int i = 0; i < 128; i++) { v.Append(new PointI(i, i)); size_t pos = rand() % v.Count(); v.InsertAt(pos, new PointI(i, i)); } assert(v.Count() == 128 * 2); size_t idx = 0; for (PointI **p = v.IterStart(); p; p = v.IterNext()) { assert(idx == v.IterIdx()); ++idx; } while (v.Count() > 64) { size_t pos = rand() % v.Count(); PointI *f = v.At(pos); v.Remove(f); delete f; } DeleteVecMembers(v); } { Vec<int> v; v.Append(2); for (int i = 0; i < 500; i++) v.Append(4); v.At(250) = 5; v.Reverse(); assert(v.Count() == 501 && v.At(0) == 4 && v.At(249) == v.At(251) && v.At(250) == 5 && v.At(500) == 2); v.Remove(4); v.Reverse(); assert(v.Count() == 500 && v.At(0) == 2 && v.At(249) == v.At(251) && v.At(250) == 5 && v.At(499) == 4); } }