Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified Resources/Fonts/IconFont.ttf
Binary file not shown.
19 changes: 17 additions & 2 deletions Source/Canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1647,10 +1647,17 @@ bool Canvas::keyPressed(KeyPress const& key)
return false;
}

void Canvas::deselectAll()
void Canvas::deselectAll(bool broadcastChange)
{
if (!broadcastChange) selectedComponents.removeChangeListener(this);

selectedComponents.deselectAll();
editor->sidebar->hideParameters();

if (!broadcastChange) {
// Add back the listener, but make sure it's added back 'after' the last event on the message queue
MessageManager::callAsync([this](){selectedComponents.addChangeListener(this);});
}
}

void Canvas::hideAllActiveEditors()
Expand Down Expand Up @@ -2631,16 +2638,24 @@ void Canvas::hideSuggestions()
}

// Makes component selected
void Canvas::setSelected(Component* component, bool shouldNowBeSelected, bool updateCommandStatus)
void Canvas::setSelected(Component* component, bool shouldNowBeSelected, bool updateCommandStatus, bool broadcastChange)
{
if (!broadcastChange) { selectedComponents.removeChangeListener(this); }

if (!shouldNowBeSelected) {
selectedComponents.deselect(component);
} else {
selectedComponents.addToSelection(component);
}

if (updateCommandStatus) {
editor->updateCommandStatus();
}

if (!broadcastChange) {
// Add back the listener, but make sure it's added back 'after' the last event on the message queue
MessageManager::callAsync([this](){selectedComponents.addChangeListener(this);});
}
}

SelectedItemSet<WeakReference<Component>>& Canvas::getLassoSelection()
Expand Down
4 changes: 2 additions & 2 deletions Source/Canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ class Canvas : public Component
bool autoscroll(MouseEvent const& e);

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

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

Expand Down
165 changes: 125 additions & 40 deletions Source/Components/WelcomePanel.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class WelcomePanel : public Component
nvgFillColor(nvg, NVGComponent::convertColour(findColour(PlugDataColour::panelTextColourId)));
nvgText(nvg, 96, 138, "Recently Opened", NULL);

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

case Open: {
nvgFontFace(nvg, "plugdata_icon_font");
nvgFontFace(nvg, "icon_font-Regular");
nvgFillColor(nvg, bgCol);
nvgFontSize(nvg, 34);
nvgTextAlign(nvg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
Expand Down Expand Up @@ -199,6 +199,9 @@ class WelcomePanel : public Component

void mouseUp(MouseEvent const& e) override
{
if (!getScreenBounds().reduced(12).contains(e.getScreenPosition()))
return;

if (!e.mods.isLeftButtonDown())
return;

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

private:
WelcomePanel& parent;
Expand All @@ -223,17 +227,74 @@ class WelcomePanel : public Component
Image thumbnailImageData;
int lastWidth = -1;
int lastHeight = -1;


String creationTimeDescription = String();
String modifiedTimeDescription = String();
String fileSizeDescription = String();

File patchFile;

public:
WelcomePanelTile(WelcomePanel& welcomePanel, ValueTree subTree, String svgImage, Colour iconColour, float scale, bool favourited, Image const& thumbImage = Image())
: parent(welcomePanel)
, isFavourited(favourited)
, snapshotScale(scale)
, thumbnailImageData(thumbImage)
{
patchFile = File(subTree.getProperty("Path").toString());
tileName = patchFile.getFileNameWithoutExtension();

auto is24Hour = OSUtils::is24HourTimeFormat();

auto formatTimeDescription = [is24Hour](const Time& openTime) {
auto diff = Time::getCurrentTime() - openTime;

String date;
auto days = diff.inDays();
if (days < 1)
date = "Today";
else if (days > 1 && days < 2)
date = "Yesterday";
else
date = openTime.toString(true, false);

String time = openTime.toString(false, true, false, is24Hour);

return date + ", " + time;
};

tileSubtitle = formatTimeDescription(Time(static_cast<int64>(subTree.getProperty("Time"))));

auto const fileSize = patchFile.getSize();

if (fileSize < 1024) {
fileSizeDescription = String(fileSize) + " Bytes"; // Less than 1 KiB
} else if (fileSize < 1024 * 1024) {
fileSizeDescription = String(fileSize / 1024.0, 2) + " KiB"; // Between 1 KiB and 1 MiB
} else {
fileSizeDescription = String(fileSize / (1024.0 * 1024.0), 2) + " MiB"; // 1 MiB or more
}

creationTimeDescription = formatTimeDescription(patchFile.getCreationTime());
modifiedTimeDescription = formatTimeDescription(patchFile.getLastModificationTime());

updateGeneratedThumbnailIfNeeded(thumbImage, svgImage, iconColour);
}

WelcomePanelTile(WelcomePanel& welcomePanel, String name, String subtitle, String svgImage, Colour iconColour, float scale, bool favourited, Image const& thumbImage = Image())
: isFavourited(favourited)
, parent(welcomePanel)
: parent(welcomePanel)
, isFavourited(favourited)
, snapshotScale(scale)
, tileName(name)
, tileSubtitle(subtitle)
, thumbnailImageData(thumbImage)
{
if (!thumbImage.isValid()) {
updateGeneratedThumbnailIfNeeded(thumbImage, svgImage, iconColour);
}

void updateGeneratedThumbnailIfNeeded(Image const& thumbnailImage, String& svgImage, Colour iconColour)
{
if (!thumbnailImage.isValid()) {
snapshot = Drawable::createFromImageData(svgImage.toRawUTF8(), svgImage.getNumBytesAsUTF8());
if (snapshot) {
snapshot->replaceColour(Colours::black, iconColour);
Expand All @@ -242,7 +303,47 @@ class WelcomePanel : public Component

resized();
}


void setHovered()
{
isHovered = true;
repaint();
}

void mouseDown(MouseEvent const& e) override {
if (!e.mods.isRightButtonDown())
return;

PopupMenu tileMenu;

tileMenu.addItem(PlatformStrings::getBrowserTip(), [this]() {
if (patchFile.existsAsFile())
patchFile.revealToUser();
});
tileMenu.addSeparator();
tileMenu.addItem(isFavourited ? "Remove from favourites" : "Add to favourites", [this]() {
isFavourited = !isFavourited;
onFavourite(isFavourited);
});
tileMenu.addSeparator();
PopupMenu patchInfoSubMenu;
patchInfoSubMenu.addItem(String("Size: " + fileSizeDescription), false, false, nullptr);
patchInfoSubMenu.addSeparator();
patchInfoSubMenu.addItem(String("Created: " + creationTimeDescription), false, false, nullptr);
patchInfoSubMenu.addItem(String("Modified: " + modifiedTimeDescription), false, false, nullptr);
patchInfoSubMenu.addItem(String("Accessed: " + tileSubtitle), false, false, nullptr);
tileMenu.addSubMenu(String(tileName + ".pd file info"), patchInfoSubMenu, true);
tileMenu.addSeparator();
// TODO: we may want to be clearer about this - that it doesn't delete the file on disk
// Put this at he bottom, so it's not accidentally clicked on
tileMenu.addItem("Remove from recently opened", onRemove);

PopupMenu::Options options;
options.withTargetComponent(this);

tileMenu.showMenuAsync(options);
}

void setSearchQuery(String const& searchQuery)
{
setVisible(tileName.containsIgnoreCase(searchQuery));
Expand Down Expand Up @@ -398,6 +499,11 @@ class WelcomePanel : public Component
if (!e.mods.isLeftButtonDown())
return;

// If the cursor is no longer over the tile, don't trigger the tile
// (Standard behaviour for mouse up on object)
if (!getLocalBounds().reduced(12).contains(e.getPosition()))
return;

if (onFavourite && getHeartIconBounds().contains(e.x, e.y)) {
isFavourited = !isFavourited;
onFavourite(isFavourited);
Expand Down Expand Up @@ -522,7 +628,7 @@ class WelcomePanel : public Component

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

contentComponent.setBounds(tiles.size() ? tilesBounds : bounds);
contentComponent.setBounds(tiles.size() ? tilesBounds : getLocalBounds());

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

Expand Down Expand Up @@ -583,24 +689,6 @@ class WelcomePanel : public Component

triggerAsyncUpdate();
}

String getSystemLocalTime(uint64 timestamp) {
StackArray<char, 100> buffer;
std::time_t now = static_cast<std::time_t>(timestamp / 1000);
std::tm* localTime = std::localtime(&now);

// Format the time using the current locale
std::strftime(buffer.data(), buffer.size(), "%X", localTime);

auto result = String::fromUTF8(buffer.data());

// Remove seconds from system time format
auto secondsStart = result.lastIndexOfChar(':');
auto secondsEnd = result.indexOfChar(secondsStart, ' ');
if(secondsEnd < 0) secondsEnd = result.length();

return result.substring(0, secondsStart) + result.substring(secondsEnd);
}

void handleAsyncUpdate() override
{
Expand Down Expand Up @@ -648,21 +736,8 @@ class WelcomePanel : public Component
}
}

auto openTimestamp = static_cast<int64>(subTree.getProperty("Time"));
auto openTime = Time(openTimestamp);
auto diff = Time::getCurrentTime() - openTime;
String date;
if (diff.inDays() == 0)
date = "Today";
else if (diff.inDays() == 1)
date = "Yesterday";
else
date = openTime.toString(true, false);

String time = getSystemLocalTime(openTimestamp);
String timeDescription = date + ", " + time;
auto* tile = recentlyOpenedTiles.add(new WelcomePanelTile(*this, subTree, silhoutteSvg, snapshotColour, 1.0f, favourited, thumbImage));

auto* tile = recentlyOpenedTiles.add(new WelcomePanelTile(*this, patchFile.getFileNameWithoutExtension(), timeDescription, silhoutteSvg, snapshotColour, 1.0f, favourited, thumbImage));
tile->onClick = [this, patchFile]() mutable {
if (patchFile.existsAsFile()) {
editor->pd->autosave->checkForMoreRecentAutosave(patchFile, editor, [this, patchFile]() {
Expand All @@ -683,6 +758,16 @@ class WelcomePanel : public Component
subTree.setProperty("Pinned", shouldBeFavourite, nullptr);
resized();
};
tile->onRemove = [this, path = subTree.getProperty("Path")]() {
auto settingsTree = SettingsFile::getInstance()->getValueTree();
auto recentlyOpenedTree = settingsTree.getChildWithName("RecentlyOpened");
auto subTree = recentlyOpenedTree.getChildWithProperty("Path", path);
recentlyOpenedTree.removeChild(subTree, nullptr);
// Make sure to clear the recent items in the current welcome panel
if (editor->welcomePanel)
editor->welcomePanel->triggerAsyncUpdate();
};

contentComponent.addAndMakeVisible(tile);
}
}
Expand Down
18 changes: 17 additions & 1 deletion Source/Constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ struct Icons {

inline static String const Reorder = "(";
inline static String const Object = ":";
inline static String const ObjectMulti = CharPointer_UTF8("\xc2\xb9");

inline static String const List = "!";
inline static String const Graph = "<";
Expand All @@ -102,7 +103,7 @@ struct Icons {
inline static String const Paste = "1";
inline static String const Duplicate = "2";
inline static String const Cut = "3";

inline static String const PanelExpand = CharPointer_UTF8("\xc3\x8d");
inline static String const PanelContract = CharPointer_UTF8("\xc3\x8c");
inline static String const ItemGrid = " ";
Expand All @@ -118,6 +119,9 @@ struct Icons {

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

inline static String const ShowIndex = CharPointer_UTF8("\xc2\xbA");
inline static String const ShowXY = CharPointer_UTF8("\xc2\xbb");

// ================== OBJECT ICONS ==================

// generic
Expand Down Expand Up @@ -426,3 +430,15 @@ enum Align {
VCentre,
VDistribute
};

namespace PlatformStrings {
inline String getBrowserTip() {
#if JUCE_MAC
return "Reveal in Finder";
#elif JUCE_WINDOWS
return "Reveal in Explorer";
#else
return "Reveal in file browser";
#endif
}
}
2 changes: 1 addition & 1 deletion Source/NVGSurface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ void NVGSurface::initialise()
nvgCreateFontMem(nvg, "Inter-Bold", (unsigned char*)BinaryData::InterBold_ttf, BinaryData::InterBold_ttfSize, 0);
nvgCreateFontMem(nvg, "Inter-SemiBold", (unsigned char*)BinaryData::InterSemiBold_ttf, BinaryData::InterSemiBold_ttfSize, 0);
nvgCreateFontMem(nvg, "Inter-Tabular", (unsigned char*)BinaryData::InterTabular_ttf, BinaryData::InterTabular_ttfSize, 0);
nvgCreateFontMem(nvg, "plugdata_icon_font", (unsigned char*)BinaryData::IconFont_ttf, BinaryData::IconFont_ttfSize, 0);
nvgCreateFontMem(nvg, "icon_font-Regular", (unsigned char*)BinaryData::IconFont_ttf, BinaryData::IconFont_ttfSize, 0);

invalidateAll();
}
Expand Down
Loading