Skip to content

Commit

Permalink
Added a new action "panel.show_context_menu" showing the context menu.
Browse files Browse the repository at this point in the history
…fixed #423
  • Loading branch information
mikekazakov committed Oct 19, 2024
1 parent 83f880f commit 136501c
Show file tree
Hide file tree
Showing 26 changed files with 217 additions and 29 deletions.
1 change: 1 addition & 0 deletions Docs/Help.md
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ Available hotkeys are listed below. These are the default values, which can be a
|     Show Tab №10 | |
|     Focus Left Panel | Shift + Cmd + Left |
|     Focus Right Panel | Shift + Cmd + Right |
|     Show Context Menu | Ctrl + Return |
|   _**Viewer**_ | |
|     Toggle Text | Cmd + 1 |
|     Toggle Hex | Cmd + 2 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@
CFC7066B2B4986150045D2C9 /* info.filesmanager.Files.PrivilegedIOHelperV2 in CopyFiles */ = {isa = PBXBuildFile; fileRef = CFC705DF2B497D1A0045D2C9 /* info.filesmanager.Files.PrivilegedIOHelperV2 */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
CFC7066D2B49AF480045D2C9 /* LetsMove.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFC706482B497F6A0045D2C9 /* LetsMove.framework */; };
CFC7066E2B49AF6D0045D2C9 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFC706462B497F5C0045D2C9 /* Sparkle.framework */; };
CFCBA8BB2CC3B1B4009ABD2C /* ShowContextMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = CFCBA8B92CC3B1B4009ABD2C /* ShowContextMenu.h */; };
CFCBA8BC2CC3B1B4009ABD2C /* ShowContextMenu.mm in Sources */ = {isa = PBXBuildFile; fileRef = CFCBA8BA2CC3B1B4009ABD2C /* ShowContextMenu.mm */; };
CFCCFBAE1A5D340000313845 /* SFTPConnectionSheetController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CFCCFBB21A5D340000313845 /* SFTPConnectionSheetController.xib */; };
CFCCFBAF1A5D340000313845 /* SFTPConnectionSheetController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CFCCFBB21A5D340000313845 /* SFTPConnectionSheetController.xib */; };
CFCCFBB81A5D687600313845 /* FTPConnectionSheetController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CFCCFBBC1A5D687600313845 /* FTPConnectionSheetController.xib */; };
Expand Down Expand Up @@ -1215,6 +1217,8 @@
CFC705FA2B497D600045D2C9 /* VFSIcon.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = VFSIcon.xcodeproj; path = ../VFSIcon/VFSIcon.xcodeproj; sourceTree = "<group>"; };
CFC706462B497F5C0045D2C9 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = ../../../3rd_Party/Sparkle/Sparkle.framework; sourceTree = "<group>"; };
CFC706482B497F6A0045D2C9 /* LetsMove.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LetsMove.framework; path = ../../../3rd_Party/LetsMove/LetsMove.framework; sourceTree = "<group>"; };
CFCBA8B92CC3B1B4009ABD2C /* ShowContextMenu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ShowContextMenu.h; path = NimbleCommander/States/FilePanels/Actions/ShowContextMenu.h; sourceTree = "<group>"; };
CFCBA8BA2CC3B1B4009ABD2C /* ShowContextMenu.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = ShowContextMenu.mm; path = NimbleCommander/States/FilePanels/Actions/ShowContextMenu.mm; sourceTree = "<group>"; };
CFCCFBB11A5D340000313845 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SFTPConnectionSheetController.xib; sourceTree = "<group>"; };
CFCCFBBB1A5D687600313845 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/FTPConnectionSheetController.xib; sourceTree = "<group>"; };
CFCCFBC51A5D7F0E00313845 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/GoToFolderSheetController.xib; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1765,6 +1769,8 @@
CF197C4B1FB960CC009F6C59 /* RevealInOppositePanel.mm */,
CF6ECDB41E9F7353008FA79E /* Select.h */,
CF6ECDB51E9F7353008FA79E /* Select.mm */,
CFCBA8B92CC3B1B4009ABD2C /* ShowContextMenu.h */,
CFCBA8BA2CC3B1B4009ABD2C /* ShowContextMenu.mm */,
CF0139B61E9B156500E44F2D /* ShowGoToPopup.h */,
CF0139B71E9B156500E44F2D /* ShowGoToPopup.mm */,
CF5E9A511FCBF57A005608F5 /* ShowQuickLook.h */,
Expand Down Expand Up @@ -2253,6 +2259,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
CFCBA8BB2CC3B1B4009ABD2C /* ShowContextMenu.h in Headers */,
CFCF44012BA2418100B513C7 /* ConfigBinder.h in Headers */,
CFEADD49259CF60D009ECA14 /* ChangePanelsPosition.h in Headers */,
CFEADD54259D01AD009ECA14 /* FocusOverlappedTerminal.h in Headers */,
Expand Down Expand Up @@ -3164,6 +3171,7 @@
CF0A48672BDDA3EB00833160 /* PanelListViewRowView.mm in Sources */,
CF0A48852BDDA57100833160 /* AskForPasswordWindowController.mm in Sources */,
CF0A48842BDDA56400833160 /* TabBarStyle.mm in Sources */,
CFCBA8BC2CC3B1B4009ABD2C /* ShowContextMenu.mm in Sources */,
CFA999F3264F17A800F72E93 /* CLI.cpp in Sources */,
CF0A482E2BDDA0C200833160 /* ChangeAttributes.mm in Sources */,
CF0A48492BDDA29000833160 /* Select.mm in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ - (NCPanelOpenWithMenuDelegate *)panelOpenWithMenuDelegate

- (nc::panel::ContextMenuProvider)makePanelContextMenuProvider
{
auto provider = [self](std::vector<VFSListingItem> _items, PanelController *_panel) -> NSMenu * {
auto provider = [self](std::vector<VFSListingItem> _items, PanelController *_panel) -> NCPanelContextMenu * {
return [[NCPanelContextMenu alloc] initWithItems:std::move(_items)
ofPanel:_panel
withFileOpener:self.fileOpener
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@
{"panel.show_tab_no_10", 100'169},
{"panel.focus_left_panel", 100'170},
{"panel.focus_right_panel", 100'171},
{"panel.show_context_menu", 100'180},

{"viewer.toggle_text", 101'000},
{"viewer.toggle_hex", 101'001},
Expand Down Expand Up @@ -410,6 +411,7 @@
{"panel.show_tab_no_10", u8"" },
{"panel.focus_left_panel", u8"⇧⌘\uF702"}, // shift+cmd+left
{"panel.focus_right_panel", u8"⇧⌘\uF703"}, // shift+cmd+right
{"panel.show_context_menu", u8"^\\r" }, // ctrl+↵

{"viewer.toggle_text", u8"⌘1" }, // cmd+1
{"viewer.toggle_hex", u8"⌘2" }, // cmd+2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ - (void)setSourceType:(SourceType)sourceType

static NSString *ComposeVerboseNonMenuActionTitle(const std::string &_action)
{
[[clang::no_destroy]] static const std::vector<std::pair<const char *, NSString *>> titles = {
[[clang::no_destroy]] static const ankerl::unordered_dense::map<std::string, NSString *> titles = {
{"panel.move_up", NSLocalizedString(@"File Panels ▶ Move Up", "")},
{"panel.move_down", NSLocalizedString(@"File Panels ▶ Move Down", "")},
{"panel.move_left", NSLocalizedString(@"File Panels ▶ Move Left", "")},
Expand Down Expand Up @@ -581,6 +581,7 @@ - (void)setSourceType:(SourceType)sourceType
{"panel.show_tab_no_10", NSLocalizedString(@"File Panels ▶ Show Tab №10", "")},
{"panel.focus_left_panel", NSLocalizedString(@"File Panels ▶ Focus Left Panel", "")},
{"panel.focus_right_panel", NSLocalizedString(@"File Panels ▶ Focus Right Panel", "")},
{"panel.show_context_menu", NSLocalizedString(@"File Panels ▶ Show Context Menu", "")},
{"viewer.toggle_text", NSLocalizedString(@"Viewer ▶ Toggle Text", "")},
{"viewer.toggle_hex", NSLocalizedString(@"Viewer ▶ Toggle Hex", "")},
{"viewer.toggle_preview", NSLocalizedString(@"Viewer ▶ Toggle Preview", "")},
Expand All @@ -589,9 +590,8 @@ - (void)setSourceType:(SourceType)sourceType
{"viewer.refresh", NSLocalizedString(@"Viewer ▶ Refresh", "")},
};

for( auto &i : titles )
if( i.first == _action )
return i.second;
if( const auto it = titles.find(_action); it != titles.end() )
return it->second;

return nil;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (C) 2024 Michael Kazakov. Subject to GNU General Public License version 3.
#pragma once

#include "DefaultAction.h"

namespace nc::panel::actions {

struct ShowContextMenu final : PanelAction {
void Perform(PanelController *_target, id _sender) const override;
};

} // namespace nc::panel::actions
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (C) 2024 Michael Kazakov. Subject to GNU General Public License version 3.
#include "ShowContextMenu.h"
#include "../PanelView.h"
#include <Panel/PanelData.h>
#include "../PanelController.h"
#include "../ContextMenu.h"
#include <fmt/format.h>

namespace nc::panel::actions {

void ShowContextMenu::Perform(PanelController *_target, id /* _sender*/) const
{
PanelView *const view = _target.view;

const int curpos = view.curpos;
if( curpos < 0 ) {
NSBeep();
return;
}

NCPanelContextMenu *const menu = [_target panelView:view requestsContextMenuForItemNo:curpos];
if( menu == nil ) {
NSBeep();
return;
}

const int sort_pos = _target.data.SortPositionOfEntry(menu.items.front());
const std::optional<NSRect> frame = [view frameOfItemAtSortPos:sort_pos];
const NSSize view_size = view.frame.size;
if( frame ) {
// align the top of the menu's chrome with the item's frame and
// clamp by the view's bounds
const NSPoint p = NSMakePoint(std::clamp(frame->origin.x, 0., view_size.width),
std::clamp(frame->origin.y - 5., 0., view_size.height));
[menu popUpMenuPositioningItem:nil atLocation:p inView:view];
}
else {
[menu popUpMenuPositioningItem:nil atLocation:NSMakePoint(0., view_size.height) inView:view];
}
}

} // namespace nc::panel::actions
Original file line number Diff line number Diff line change
Expand Up @@ -673,4 +673,13 @@ - (void)collectionViewDidLayoutItems:(NSCollectionView *) [[maybe_unused]] colle
[m_CollectionView.backgroundView setNeedsDisplay:true];
}

- (std::optional<NSRect>)frameOfItemAtIndex:(int)_sorted_item_index
{
const auto index_path = [NSIndexPath indexPathForItem:_sorted_item_index inSection:0];
NSCollectionViewLayoutAttributes *const attrs = [m_CollectionView layoutAttributesForItemAtIndexPath:index_path];
if( attrs == nil )
return {};
return [self convertRect:attrs.frame fromView:m_CollectionView];
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include <Cocoa/Cocoa.h>
#include <VFS/VFS.h>
#include <span>

@class PanelController;

namespace nc::utility {
Expand All @@ -19,4 +21,6 @@ class FileOpener;
withFileOpener:(nc::panel::FileOpener &)_file_opener
withUTIDB:(const nc::utility::UTIDB &)_uti_db;

- (std::span<VFSListingItem>)items;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,11 @@ - (void)onTagItem:(id)_sender
});
}

- (std::span<VFSListingItem>)items
{
return m_Items;
}

@end

@implementation NCPanelContextMenuSharingDelegate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1141,6 +1141,14 @@ - (void)dateDidChangeImpl
[m_TableView enumerateAvailableRowViewsUsingBlock:block];
}

- (std::optional<NSRect>)frameOfItemAtIndex:(int)_sorted_item_index
{
const NSRect rc = [m_TableView rectOfRow:_sorted_item_index];
if( rc.size.height == 0. )
return {};
return [self convertRect:rc fromView:m_TableView];
}

@end

static PanelListViewColumns IdentifierToKind(char _letter) noexcept
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <fmt/ranges.h>

@class PanelController;
@class NCPanelContextMenu;
@class PanelView;
@class BriefSystemOverview;
@class MainWindowFilePanelState;
Expand Down Expand Up @@ -115,7 +116,8 @@ struct DirectoryChangeRequest {
int LoadingResultCode = 0;
};

using ContextMenuProvider = std::function<NSMenu *(std::vector<VFSListingItem> _items, PanelController *_panel)>;
using ContextMenuProvider =
std::function<NCPanelContextMenu *(std::vector<VFSListingItem> _items, PanelController *_panel)>;

} // namespace panel
} // namespace nc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <Panel/PanelData.h>
#include "PanelView.h"
#include "DragReceiver.h"
#include "ContextMenu.h"
#include <Panel/PanelDataExternalEntryKey.h>
#include "PanelDataPersistency.h"
#include <NimbleCommander/Core/VFSInstanceManager.h>
Expand Down Expand Up @@ -710,7 +711,7 @@ - (void)panelViewCursorChanged:(PanelView *) [[maybe_unused]] _view
[self onCursorChanged];
}

- (NSMenu *)panelView:(PanelView *)_view requestsContextMenuForItemNo:(int)_sort_pos
- (NCPanelContextMenu *)panelView:(PanelView *)_view requestsContextMenuForItemNo:(int)_sort_pos
{
dispatch_assert_main_queue();

Expand All @@ -724,13 +725,13 @@ - (NSMenu *)panelView:(PanelView *)_view requestsContextMenuForItemNo:(int)_sort
if( clicked_item_vd.is_selected() == false )
vfs_items.emplace_back(clicked_item); // only clicked item
else
vfs_items = m_Data.SelectedEntriesUnsorted(); // all selected items
vfs_items = m_Data.SelectedEntriesSorted(); // all selected items

for( auto &i : vfs_items )
m_Data.VolatileDataAtRawPosition(i.Index()).toggle_highlight(true);
[_view volatileDataChanged];

const auto menu = m_ContextMenuProvider(std::move(vfs_items), self);
NCPanelContextMenu *const menu = m_ContextMenuProvider(std::move(vfs_items), self);
return menu;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "Actions/ShowQuickLook.h"
#include "Actions/ShowSystemOverview.h"
#include "Actions/FollowSymlink.h"
#include "Actions/ShowContextMenu.h"

namespace nc::panel {

Expand Down Expand Up @@ -151,6 +152,7 @@ PanelActionsMap BuildPanelActionsMap(nc::config::Config &_global_config,
add(@selector(OnCreateSymbolicLinkCommand:), new CreateSymlink);
add(@selector(OnEditSymbolicLinkCommand:), new AlterSymlink);
add(@selector(OnCreateHardLinkCommand:), new CreateHardlink);
add(@selector(onShowContextMenu:), new ShowContextMenu);

return m;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,6 @@ using PanelActionsMap = ankerl::unordered_dense::map<SEL, std::unique_ptr<const
- (IBAction)OnCreateHardLinkCommand:(id)sender;
- (IBAction)OnFileViewCommand:(id)sender;
- (IBAction)onFollowSymlink:(id)sender;
- (IBAction)onShowContextMenu:(id)sender;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,15 @@ - (int)bidForHandlingKeyDown:(NSEvent *)_event
{
const auto event_data = nc::utility::ActionShortcut::EventData(_event);

static ActionsShortcutsManager::ShortCut hk_file_open, hk_file_open_native, hk_go_root, hk_go_home, hk_preview,
hk_go_into, kh_go_outside;
static ActionsShortcutsManager::ShortCut //
hk_file_open, //
hk_file_open_native, //
hk_go_root, //
hk_go_home, //
hk_preview, //
hk_go_into, //
hk_go_outside, //
hk_show_context_menu; //
[[clang::no_destroy]] static ActionsShortcutsManager::ShortCutsUpdater hotkeys_updater(
std::initializer_list<ActionsShortcutsManager::ShortCutsUpdater::UpdateTarget>{
{.shortcut = &hk_file_open, .action = "menu.file.enter"},
Expand All @@ -60,7 +67,8 @@ - (int)bidForHandlingKeyDown:(NSEvent *)_event
{.shortcut = &hk_go_home, .action = "panel.go_home"},
{.shortcut = &hk_preview, .action = "panel.show_preview"},
{.shortcut = &hk_go_into, .action = "panel.go_into_folder"},
{.shortcut = &kh_go_outside, .action = "panel.go_into_enclosing_folder"}});
{.shortcut = &hk_go_outside, .action = "panel.go_into_enclosing_folder"},
{.shortcut = &hk_show_context_menu, .action = "panel.show_context_menu"}});

if( hk_preview.IsKeyDown(event_data) ) {
if( _handle ) {
Expand Down Expand Up @@ -96,7 +104,7 @@ - (int)bidForHandlingKeyDown:(NSEvent *)_event
return view::BiddingPriority::High;
}

if( kh_go_outside.IsKeyDown(event_data) ) {
if( hk_go_outside.IsKeyDown(event_data) ) {
if( _handle ) {
static auto tag = ActionsShortcutsManager::Instance().TagFromAction("menu.go.enclosing_folder");
[[NSApp menu] performActionForItemWithTagHierarchical:tag];
Expand All @@ -111,13 +119,21 @@ - (int)bidForHandlingKeyDown:(NSEvent *)_event
}
return view::BiddingPriority::High;
}

if( hk_file_open_native.IsKeyDown(event_data) ) {
if( _handle ) {
[self executeBySelectorIfValidOrBeep:@selector(OnOpenNatively:) withSender:self];
}
return view::BiddingPriority::High;
}

if( hk_show_context_menu.IsKeyDown(event_data) ) {
if( _handle ) {
[self executeBySelectorIfValidOrBeep:@selector(onShowContextMenu:) withSender:self];
}
return view::BiddingPriority::High;
}

return view::BiddingPriority::Skip;
}

Expand Down Expand Up @@ -574,6 +590,10 @@ - (IBAction)onFollowSymlink:(id)sender
{
PERFORM;
}
- (IBAction)onShowContextMenu:(id)sender
{
PERFORM;
}
#undef PERFORM

@end
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2013-2020 Michael Kazakov. Subject to GNU General Public License version 3.
// Copyright (C) 2013-2024 Michael Kazakov. Subject to GNU General Public License version 3.
#pragma once

#include <VFS/VFS.h>
Expand Down Expand Up @@ -90,6 +90,10 @@ class Model;
- (std::any)presentationLayout;
- (void)setPresentationLayout:(const nc::panel::PanelViewLayout &)_layout;

// Returns a frame of the view representing the item at the specified sorted position.
// Will return std::nullopt if the position is invalid.
- (std::optional<NSRect>)frameOfItemAtSortPos:(int)_sorted_position;

/*
* PanelView implementation hooks.
* Later: add hit-test info flags here.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "PanelViewDelegate.h"
#include "DragReceiver.h"
#include "DragSender.h"
#include "ContextMenu.h"
#include <Panel/PanelViewFieldEditor.h>
#include <Panel/PanelViewKeystrokeSink.h>
#include "PanelViewDummyPresentation.h"
Expand Down Expand Up @@ -1135,4 +1136,12 @@ - (void)removeKeystrokeSink:(id<NCPanelViewKeystrokeSink>)_sink
std::erase(m_KeystrokeSinks, _sink);
}

- (std::optional<NSRect>)frameOfItemAtSortPos:(int)_sorted_position
{
const std::optional<NSRect> frame = [m_ItemsView frameOfItemAtIndex:_sorted_position];
if( !frame )
return {};
return [self convertRect:*frame fromView:m_ItemsView];
}

@end
Loading

0 comments on commit 136501c

Please sign in to comment.