Skip to content

Commit 20343e9

Browse files
Merge pull request #1980 from alcomposer/24hourtime
Fix 24 hour time OS setting detection for Windows
2 parents 1daeb92 + 6652b9a commit 20343e9

File tree

16 files changed

+348
-84
lines changed

16 files changed

+348
-84
lines changed

Resources/Fonts/IconFont.ttf

668 Bytes
Binary file not shown.

Source/Canvas.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1647,10 +1647,17 @@ bool Canvas::keyPressed(KeyPress const& key)
16471647
return false;
16481648
}
16491649

1650-
void Canvas::deselectAll()
1650+
void Canvas::deselectAll(bool broadcastChange)
16511651
{
1652+
if (!broadcastChange) selectedComponents.removeChangeListener(this);
1653+
16521654
selectedComponents.deselectAll();
16531655
editor->sidebar->hideParameters();
1656+
1657+
if (!broadcastChange) {
1658+
// Add back the listener, but make sure it's added back 'after' the last event on the message queue
1659+
MessageManager::callAsync([this](){selectedComponents.addChangeListener(this);});
1660+
}
16541661
}
16551662

16561663
void Canvas::hideAllActiveEditors()
@@ -2631,16 +2638,24 @@ void Canvas::hideSuggestions()
26312638
}
26322639

26332640
// Makes component selected
2634-
void Canvas::setSelected(Component* component, bool shouldNowBeSelected, bool updateCommandStatus)
2641+
void Canvas::setSelected(Component* component, bool shouldNowBeSelected, bool updateCommandStatus, bool broadcastChange)
26352642
{
2643+
if (!broadcastChange) { selectedComponents.removeChangeListener(this); }
2644+
26362645
if (!shouldNowBeSelected) {
26372646
selectedComponents.deselect(component);
26382647
} else {
26392648
selectedComponents.addToSelection(component);
26402649
}
2650+
26412651
if (updateCommandStatus) {
26422652
editor->updateCommandStatus();
26432653
}
2654+
2655+
if (!broadcastChange) {
2656+
// Add back the listener, but make sure it's added back 'after' the last event on the message queue
2657+
MessageManager::callAsync([this](){selectedComponents.addChangeListener(this);});
2658+
}
26442659
}
26452660

26462661
SelectedItemSet<WeakReference<Component>>& Canvas::getLassoSelection()

Source/Canvas.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ class Canvas : public Component
156156
bool autoscroll(MouseEvent const& e);
157157

158158
// Multi-dragger functions
159-
void deselectAll();
160-
void setSelected(Component* component, bool shouldNowBeSelected, bool updateCommandStatus = true);
159+
void deselectAll(bool broadcastChange = true);
160+
void setSelected(Component* component, bool shouldNowBeSelected, bool updateCommandStatus = true, bool broadcastChange = true);
161161

162162
SelectedItemSet<WeakReference<Component>>& getLassoSelection() override;
163163

Source/Components/WelcomePanel.h

Lines changed: 125 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class WelcomePanel : public Component
4444
nvgFillColor(nvg, NVGComponent::convertColour(findColour(PlugDataColour::panelTextColourId)));
4545
nvgText(nvg, 96, 138, "Recently Opened", NULL);
4646

47-
nvgFontFace(nvg, "plugdata_icon_font");
47+
nvgFontFace(nvg, "icon_font-Regular");
4848
nvgFontSize(nvg, 14);
4949
nvgFillColor(nvg, NVGComponent::convertColour(findColour(PlugDataColour::panelTextColourId).withAlpha(isHoveringClearButton ? 0.6f : 1.0f)));
5050
nvgText(nvg, clearButtonBounds.getCentreX(), clearButtonBounds.getCentreY(), Icons::Clear.toRawUTF8(), NULL);
@@ -159,7 +159,7 @@ class WelcomePanel : public Component
159159
}
160160

161161
case Open: {
162-
nvgFontFace(nvg, "plugdata_icon_font");
162+
nvgFontFace(nvg, "icon_font-Regular");
163163
nvgFillColor(nvg, bgCol);
164164
nvgFontSize(nvg, 34);
165165
nvgTextAlign(nvg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
@@ -199,6 +199,9 @@ class WelcomePanel : public Component
199199

200200
void mouseUp(MouseEvent const& e) override
201201
{
202+
if (!getScreenBounds().reduced(12).contains(e.getScreenPosition()))
203+
return;
204+
202205
if (!e.mods.isLeftButtonDown())
203206
return;
204207

@@ -211,6 +214,7 @@ class WelcomePanel : public Component
211214
bool isFavourited;
212215
std::function<void()> onClick = []() { };
213216
std::function<void(bool)> onFavourite = nullptr;
217+
std::function<void()> onRemove = []() { };
214218

215219
private:
216220
WelcomePanel& parent;
@@ -223,17 +227,74 @@ class WelcomePanel : public Component
223227
Image thumbnailImageData;
224228
int lastWidth = -1;
225229
int lastHeight = -1;
226-
230+
231+
String creationTimeDescription = String();
232+
String modifiedTimeDescription = String();
233+
String fileSizeDescription = String();
234+
235+
File patchFile;
236+
227237
public:
238+
WelcomePanelTile(WelcomePanel& welcomePanel, ValueTree subTree, String svgImage, Colour iconColour, float scale, bool favourited, Image const& thumbImage = Image())
239+
: parent(welcomePanel)
240+
, isFavourited(favourited)
241+
, snapshotScale(scale)
242+
, thumbnailImageData(thumbImage)
243+
{
244+
patchFile = File(subTree.getProperty("Path").toString());
245+
tileName = patchFile.getFileNameWithoutExtension();
246+
247+
auto is24Hour = OSUtils::is24HourTimeFormat();
248+
249+
auto formatTimeDescription = [is24Hour](const Time& openTime) {
250+
auto diff = Time::getCurrentTime() - openTime;
251+
252+
String date;
253+
auto days = diff.inDays();
254+
if (days < 1)
255+
date = "Today";
256+
else if (days > 1 && days < 2)
257+
date = "Yesterday";
258+
else
259+
date = openTime.toString(true, false);
260+
261+
String time = openTime.toString(false, true, false, is24Hour);
262+
263+
return date + ", " + time;
264+
};
265+
266+
tileSubtitle = formatTimeDescription(Time(static_cast<int64>(subTree.getProperty("Time"))));
267+
268+
auto const fileSize = patchFile.getSize();
269+
270+
if (fileSize < 1024) {
271+
fileSizeDescription = String(fileSize) + " Bytes"; // Less than 1 KiB
272+
} else if (fileSize < 1024 * 1024) {
273+
fileSizeDescription = String(fileSize / 1024.0, 2) + " KiB"; // Between 1 KiB and 1 MiB
274+
} else {
275+
fileSizeDescription = String(fileSize / (1024.0 * 1024.0), 2) + " MiB"; // 1 MiB or more
276+
}
277+
278+
creationTimeDescription = formatTimeDescription(patchFile.getCreationTime());
279+
modifiedTimeDescription = formatTimeDescription(patchFile.getLastModificationTime());
280+
281+
updateGeneratedThumbnailIfNeeded(thumbImage, svgImage, iconColour);
282+
}
283+
228284
WelcomePanelTile(WelcomePanel& welcomePanel, String name, String subtitle, String svgImage, Colour iconColour, float scale, bool favourited, Image const& thumbImage = Image())
229-
: isFavourited(favourited)
230-
, parent(welcomePanel)
285+
: parent(welcomePanel)
286+
, isFavourited(favourited)
231287
, snapshotScale(scale)
232288
, tileName(name)
233289
, tileSubtitle(subtitle)
234290
, thumbnailImageData(thumbImage)
235291
{
236-
if (!thumbImage.isValid()) {
292+
updateGeneratedThumbnailIfNeeded(thumbImage, svgImage, iconColour);
293+
}
294+
295+
void updateGeneratedThumbnailIfNeeded(Image const& thumbnailImage, String& svgImage, Colour iconColour)
296+
{
297+
if (!thumbnailImage.isValid()) {
237298
snapshot = Drawable::createFromImageData(svgImage.toRawUTF8(), svgImage.getNumBytesAsUTF8());
238299
if (snapshot) {
239300
snapshot->replaceColour(Colours::black, iconColour);
@@ -242,7 +303,47 @@ class WelcomePanel : public Component
242303

243304
resized();
244305
}
245-
306+
307+
void setHovered()
308+
{
309+
isHovered = true;
310+
repaint();
311+
}
312+
313+
void mouseDown(MouseEvent const& e) override {
314+
if (!e.mods.isRightButtonDown())
315+
return;
316+
317+
PopupMenu tileMenu;
318+
319+
tileMenu.addItem(PlatformStrings::getBrowserTip(), [this]() {
320+
if (patchFile.existsAsFile())
321+
patchFile.revealToUser();
322+
});
323+
tileMenu.addSeparator();
324+
tileMenu.addItem(isFavourited ? "Remove from favourites" : "Add to favourites", [this]() {
325+
isFavourited = !isFavourited;
326+
onFavourite(isFavourited);
327+
});
328+
tileMenu.addSeparator();
329+
PopupMenu patchInfoSubMenu;
330+
patchInfoSubMenu.addItem(String("Size: " + fileSizeDescription), false, false, nullptr);
331+
patchInfoSubMenu.addSeparator();
332+
patchInfoSubMenu.addItem(String("Created: " + creationTimeDescription), false, false, nullptr);
333+
patchInfoSubMenu.addItem(String("Modified: " + modifiedTimeDescription), false, false, nullptr);
334+
patchInfoSubMenu.addItem(String("Accessed: " + tileSubtitle), false, false, nullptr);
335+
tileMenu.addSubMenu(String(tileName + ".pd file info"), patchInfoSubMenu, true);
336+
tileMenu.addSeparator();
337+
// TODO: we may want to be clearer about this - that it doesn't delete the file on disk
338+
// Put this at he bottom, so it's not accidentally clicked on
339+
tileMenu.addItem("Remove from recently opened", onRemove);
340+
341+
PopupMenu::Options options;
342+
options.withTargetComponent(this);
343+
344+
tileMenu.showMenuAsync(options);
345+
}
346+
246347
void setSearchQuery(String const& searchQuery)
247348
{
248349
setVisible(tileName.containsIgnoreCase(searchQuery));
@@ -398,6 +499,11 @@ class WelcomePanel : public Component
398499
if (!e.mods.isLeftButtonDown())
399500
return;
400501

502+
// If the cursor is no longer over the tile, don't trigger the tile
503+
// (Standard behaviour for mouse up on object)
504+
if (!getLocalBounds().reduced(12).contains(e.getPosition()))
505+
return;
506+
401507
if (onFavourite && getHeartIconBounds().contains(e.x, e.y)) {
402508
isFavourited = !isFavourited;
403509
onFavourite(isFavourited);
@@ -522,7 +628,7 @@ class WelcomePanel : public Component
522628

523629
auto tilesBounds = Rectangle<int>(24, showNewOpenTiles ? 146 : 24, totalWidth + 24, totalHeight + 24);
524630

525-
contentComponent.setBounds(tiles.size() ? tilesBounds : bounds);
631+
contentComponent.setBounds(tiles.size() ? tilesBounds : getLocalBounds());
526632

527633
viewport.setBounce(!tiles.isEmpty());
528634

@@ -583,24 +689,6 @@ class WelcomePanel : public Component
583689

584690
triggerAsyncUpdate();
585691
}
586-
587-
String getSystemLocalTime(uint64 timestamp) {
588-
StackArray<char, 100> buffer;
589-
std::time_t now = static_cast<std::time_t>(timestamp / 1000);
590-
std::tm* localTime = std::localtime(&now);
591-
592-
// Format the time using the current locale
593-
std::strftime(buffer.data(), buffer.size(), "%X", localTime);
594-
595-
auto result = String::fromUTF8(buffer.data());
596-
597-
// Remove seconds from system time format
598-
auto secondsStart = result.lastIndexOfChar(':');
599-
auto secondsEnd = result.indexOfChar(secondsStart, ' ');
600-
if(secondsEnd < 0) secondsEnd = result.length();
601-
602-
return result.substring(0, secondsStart) + result.substring(secondsEnd);
603-
}
604692

605693
void handleAsyncUpdate() override
606694
{
@@ -648,21 +736,8 @@ class WelcomePanel : public Component
648736
}
649737
}
650738

651-
auto openTimestamp = static_cast<int64>(subTree.getProperty("Time"));
652-
auto openTime = Time(openTimestamp);
653-
auto diff = Time::getCurrentTime() - openTime;
654-
String date;
655-
if (diff.inDays() == 0)
656-
date = "Today";
657-
else if (diff.inDays() == 1)
658-
date = "Yesterday";
659-
else
660-
date = openTime.toString(true, false);
661-
662-
String time = getSystemLocalTime(openTimestamp);
663-
String timeDescription = date + ", " + time;
739+
auto* tile = recentlyOpenedTiles.add(new WelcomePanelTile(*this, subTree, silhoutteSvg, snapshotColour, 1.0f, favourited, thumbImage));
664740

665-
auto* tile = recentlyOpenedTiles.add(new WelcomePanelTile(*this, patchFile.getFileNameWithoutExtension(), timeDescription, silhoutteSvg, snapshotColour, 1.0f, favourited, thumbImage));
666741
tile->onClick = [this, patchFile]() mutable {
667742
if (patchFile.existsAsFile()) {
668743
editor->pd->autosave->checkForMoreRecentAutosave(patchFile, editor, [this, patchFile]() {
@@ -683,6 +758,16 @@ class WelcomePanel : public Component
683758
subTree.setProperty("Pinned", shouldBeFavourite, nullptr);
684759
resized();
685760
};
761+
tile->onRemove = [this, path = subTree.getProperty("Path")]() {
762+
auto settingsTree = SettingsFile::getInstance()->getValueTree();
763+
auto recentlyOpenedTree = settingsTree.getChildWithName("RecentlyOpened");
764+
auto subTree = recentlyOpenedTree.getChildWithProperty("Path", path);
765+
recentlyOpenedTree.removeChild(subTree, nullptr);
766+
// Make sure to clear the recent items in the current welcome panel
767+
if (editor->welcomePanel)
768+
editor->welcomePanel->triggerAsyncUpdate();
769+
};
770+
686771
contentComponent.addAndMakeVisible(tile);
687772
}
688773
}

Source/Constants.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ struct Icons {
9191

9292
inline static String const Reorder = "(";
9393
inline static String const Object = ":";
94+
inline static String const ObjectMulti = CharPointer_UTF8("\xc2\xb9");
9495

9596
inline static String const List = "!";
9697
inline static String const Graph = "<";
@@ -102,7 +103,7 @@ struct Icons {
102103
inline static String const Paste = "1";
103104
inline static String const Duplicate = "2";
104105
inline static String const Cut = "3";
105-
106+
106107
inline static String const PanelExpand = CharPointer_UTF8("\xc3\x8d");
107108
inline static String const PanelContract = CharPointer_UTF8("\xc3\x8c");
108109
inline static String const ItemGrid = " ";
@@ -118,6 +119,9 @@ struct Icons {
118119

119120
inline static String const Home = CharPointer_UTF8 ("\xc3\x8e");
120121

122+
inline static String const ShowIndex = CharPointer_UTF8("\xc2\xbA");
123+
inline static String const ShowXY = CharPointer_UTF8("\xc2\xbb");
124+
121125
// ================== OBJECT ICONS ==================
122126

123127
// generic
@@ -426,3 +430,15 @@ enum Align {
426430
VCentre,
427431
VDistribute
428432
};
433+
434+
namespace PlatformStrings {
435+
inline String getBrowserTip() {
436+
#if JUCE_MAC
437+
return "Reveal in Finder";
438+
#elif JUCE_WINDOWS
439+
return "Reveal in Explorer";
440+
#else
441+
return "Reveal in file browser";
442+
#endif
443+
}
444+
}

Source/NVGSurface.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ void NVGSurface::initialise()
152152
nvgCreateFontMem(nvg, "Inter-Bold", (unsigned char*)BinaryData::InterBold_ttf, BinaryData::InterBold_ttfSize, 0);
153153
nvgCreateFontMem(nvg, "Inter-SemiBold", (unsigned char*)BinaryData::InterSemiBold_ttf, BinaryData::InterSemiBold_ttfSize, 0);
154154
nvgCreateFontMem(nvg, "Inter-Tabular", (unsigned char*)BinaryData::InterTabular_ttf, BinaryData::InterTabular_ttfSize, 0);
155-
nvgCreateFontMem(nvg, "plugdata_icon_font", (unsigned char*)BinaryData::IconFont_ttf, BinaryData::IconFont_ttfSize, 0);
155+
nvgCreateFontMem(nvg, "icon_font-Regular", (unsigned char*)BinaryData::IconFont_ttf, BinaryData::IconFont_ttfSize, 0);
156156

157157
invalidateAll();
158158
}

0 commit comments

Comments
 (0)