Skip to content

Commit cf826bd

Browse files
committed
Highlighting filename in recent files menu
1 parent 2da999a commit cf826bd

File tree

4 files changed

+141
-6
lines changed

4 files changed

+141
-6
lines changed

external/rlguipp/rlguipp.cpp

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#define RLGUIPP_IMPLEMENTATION
1010
#include <rlguipp/rlguipp.hpp>
1111
#include <ghc/fs_fwd.hpp>
12+
#include <ghc/utf8.hpp>
1213
#include <fmt/format.h>
1314

1415
#include <algorithm>
@@ -2694,6 +2695,40 @@ void System::drawMenu(detail::OpenMenu const& menu) const {
26942695
}
26952696
}
26962697

2698+
struct FilenameResult {
2699+
std::string path;
2700+
std::string filename;
2701+
};
2702+
2703+
FilenameResult truncatePathFilenameWithEllipsis(std::string_view text, std::size_t maxSize) {
2704+
if (maxSize == 0) {
2705+
return {};
2706+
}
2707+
std::filesystem::path fsPath{text};
2708+
std::string filename = fsPath.filename().string();
2709+
std::string parentPath = fsPath.parent_path().string();
2710+
auto filenameLength = static_cast<std::size_t>(ghc::utf8::length(filename));
2711+
auto parentLength = static_cast<std::size_t>(ghc::utf8::length(parentPath));
2712+
bool hasParent = !parentPath.empty();
2713+
std::size_t totalLength = hasParent ? (parentLength + 1 + filenameLength) : filenameLength;
2714+
if (totalLength <= maxSize) {
2715+
if (hasParent) {
2716+
parentPath += std::filesystem::path::preferred_separator;
2717+
}
2718+
return {std::move(parentPath), std::move(filename)};
2719+
}
2720+
if (filenameLength > maxSize) {
2721+
return {{}, ghc::utf8::truncateWithEllipsis(filename, maxSize)};
2722+
}
2723+
std::size_t pathBudget = maxSize - filenameLength;
2724+
if (pathBudget < 2) {
2725+
return {{}, std::move(filename)};
2726+
}
2727+
std::string truncatedPath = ghc::utf8::truncateWithEllipsis(parentPath, pathBudget - 1);
2728+
truncatedPath += std::filesystem::path::preferred_separator;
2729+
return {std::move(truncatedPath), std::move(filename)};
2730+
}
2731+
26972732
void System::drawItem(Item const& item, Rectangle bounds, bool hovered) const {
26982733
// Separator
26992734
if (item.type == Item::Type::Separator) {
@@ -2729,8 +2764,17 @@ void System::drawItem(Item const& item, Rectangle bounds, bool hovered) const {
27292764

27302765
// Label
27312766
int labelXPos = static_cast<int>(bounds.x + style.iconWidth);
2732-
DrawTextClipped(font, item.label.c_str(), Vector2(labelXPos, textYPos), textCol);
2733-
2767+
if (item.type == Item::Type::Filename) {
2768+
auto parts = truncatePathFilenameWithEllipsis(item.label, 64);
2769+
if (!parts.path.empty()) {
2770+
DrawTextClipped(font, parts.path.c_str(), Vector2(labelXPos, textYPos), textCol);
2771+
labelXPos += calculateTextWidth(parts.path);
2772+
}
2773+
DrawTextClipped(font, parts.filename.c_str(), Vector2(labelXPos, textYPos), GetColor(GetStyle(LABEL, TEXT_COLOR_FOCUSED)));
2774+
}
2775+
else {
2776+
DrawTextClipped(font, item.label.c_str(), Vector2(labelXPos, textYPos), textCol);
2777+
}
27342778
// Shortcut hint
27352779
if (!item.shortcut.empty()) {
27362780
int shortcutWidth = calculateTextWidth(item.shortcut);

external/rlguipp/rlguipp.hpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ struct Style {
268268
// ============================================================================
269269

270270
struct Item {
271-
enum class Type { Action, Submenu, Separator, Toggle };
271+
enum class Type { Action, Submenu, Separator, Toggle, Filename };
272272

273273
Type type = Type::Action;
274274
std::string label;
@@ -342,6 +342,18 @@ inline Item Toggle(std::string label, bool* value, std::function<void()> on_chan
342342
};
343343
}
344344

345+
inline Item Filename(std::string label, std::function<void()> action) {
346+
return Item{
347+
.type = Item::Type::Filename,
348+
.label = std::move(label),
349+
.shortcut = {},
350+
.action = std::move(action),
351+
.children = {},
352+
.enabled = true,
353+
.toggleValue = nullptr
354+
};
355+
}
356+
345357
inline Item Disabled(Item item) {
346358
item.enabled = false;
347359
return item;

src/cadmium.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,7 @@ void main()
907907
Cadmium::whenEmuChanged(*_chipEmu);
908908
_debugger.updateCore(_chipEmu.get());
909909
_screen = GenImageColor(emu::SUPPORTED_SCREEN_WIDTH, emu::SUPPORTED_SCREEN_HEIGHT, BLACK);
910+
_overlayTexture = LoadRenderTexture(emu::SUPPORTED_SCREEN_WIDTH,emu::SUPPORTED_SCREEN_HEIGHT);
910911
_screenTexture = LoadTextureFromImage(_screen);
911912
_crt = GenImageColor(256,512,BLACK);
912913
_crtTexture = LoadTextureFromImage(_crt);
@@ -1005,10 +1006,10 @@ void main()
10051006
UnloadImage(_fontImage);
10061007
UnloadImage(_microFont);
10071008
//UnloadRenderTexture(_renderTexture);
1009+
UnloadRenderTexture(_overlayTexture);
10081010
UnloadRenderTexture(_keyboardOverlay);
10091011
UnloadImage(_titleImage);
10101012
UnloadTexture(_titleTexture);
1011-
UnloadTexture(_overlayTexture);
10121013
UnloadTexture(_screenShotTexture);
10131014
UnloadTexture(_crtTexture);
10141015
UnloadTexture(_screenTexture);
@@ -1698,7 +1699,7 @@ void main()
16981699
PopupMenu::close();
16991700
PopupMenu::Menu lruFiles;
17001701
for (auto& recent : _recentFiles) {
1701-
lruFiles.push_back(PopupMenu::Action(ghc::utf8::truncateWithEllipsis(recent, 64), [this, recent]() { loadRom(recent, LoadOptions::None); }));
1702+
lruFiles.push_back(PopupMenu::Filename(ghc::utf8::truncateWithEllipsis(recent, 64), [this, recent]() { loadRom(recent, LoadOptions::None); }));
17021703
}
17031704
if (!lruFiles.empty()) {
17041705
lruFiles.push_back(PopupMenu::Separator());
@@ -3095,12 +3096,12 @@ void main()
30953096
Image _crt{};
30963097
Image _screenShot{};
30973098
Texture2D _titleTexture{};
3098-
Texture2D _overlayTexture{};
30993099
Texture2D _screenTexture{};
31003100
Texture2D _crtTexture{};
31013101
Texture2D _screenShotTexture{};
31023102
Librarian::Screenshot _screenshotData;
31033103
Sha1::Digest _screenShotSha1;
3104+
RenderTexture _overlayTexture{};
31043105
RenderTexture _keyboardOverlay{};
31053106
CircularBuffer<int16_t,1> _audioBuffer;
31063107
int64_t _audioGaps{};

src/recentfiles.hpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//---------------------------------------------------------------------------------------
2+
// src/recentfiles.hpp
3+
//---------------------------------------------------------------------------------------
4+
//
5+
// Copyright (c) 2026, Steffen Schümann <s.schuemann@pobox.com>
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy
8+
// of this software and associated documentation files (the "Software"), to deal
9+
// in the Software without restriction, including without limitation the rights
10+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
// copies of the Software, and to permit persons to whom the Software is
12+
// furnished to do so, subject to the following conditions:
13+
//
14+
// The above copyright notice and this permission notice shall be included in all
15+
// copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
// SOFTWARE.
24+
//
25+
//---------------------------------------------------------------------------------------
26+
#pragma once
27+
28+
#include <algorithm>
29+
#include <cstddef>
30+
#include <list>
31+
#include <string>
32+
#include <nlohmann/json.hpp>
33+
34+
class RecentFiles {
35+
public:
36+
explicit RecentFiles(std::size_t maxSize = 10) : _maxSize{maxSize} {}
37+
38+
void usingFile(std::string file) {
39+
std::erase(_files, file);
40+
_files.push_front(std::move(file));
41+
while (_files.size() > _maxSize) {
42+
_files.pop_back();
43+
}
44+
}
45+
46+
[[nodiscard]] auto begin() const { return _files.begin(); }
47+
[[nodiscard]] auto end() const { return _files.end(); }
48+
[[nodiscard]] std::size_t size() const { return _files.size(); }
49+
[[nodiscard]] bool empty() const { return _files.empty(); }
50+
[[nodiscard]] std::size_t maxSize() const { return _maxSize; }
51+
52+
void clear() { _files.clear(); }
53+
54+
friend void to_json(nlohmann::json& j, const RecentFiles& rf) {
55+
j = rf._files;
56+
}
57+
58+
friend void from_json(const nlohmann::json& j, RecentFiles& rf) {
59+
rf._files.clear();
60+
61+
if (!j.is_array()) {
62+
return;
63+
}
64+
65+
for (const auto& item : j) {
66+
if (item.is_string()) {
67+
rf._files.push_back(item.get<std::string>());
68+
if (rf._files.size() >= rf._maxSize) {
69+
break;
70+
}
71+
}
72+
}
73+
}
74+
75+
private:
76+
std::size_t _maxSize;
77+
std::list<std::string> _files;
78+
};

0 commit comments

Comments
 (0)