mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
UI/AppKit: Create custom popup views for bookmarks bar folders
Unfortunately, the NSMenu-based bookmarks implementation cannot support context menus within arbitrary folders. The NSMenu consumes the right- click events during its own menu tracking, and we are not able to see those events from our interface. This patch replaces the NSMenu for folders with a custom NSPopup. This implementation makes it much easier to handle context menus.
This commit is contained in:
committed by
Alexander Kalenik
parent
d8fb0ed59a
commit
81c2426b03
Notes:
github-actions[bot]
2026-04-01 02:58:29 +00:00
Author: https://github.com/trflynn89 Commit: https://github.com/LadybirdBrowser/ladybird/commit/81c2426b03a Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8715
@@ -3,6 +3,7 @@ add_library(ladybird_impl STATIC
|
||||
Application/ApplicationDelegate.mm
|
||||
Application/EventLoopImplementationMacOS.mm
|
||||
Interface/Autocomplete.mm
|
||||
Interface/BookmarkFolder.mm
|
||||
Interface/BookmarksBar.mm
|
||||
Interface/Event.mm
|
||||
Interface/InfoBar.mm
|
||||
|
||||
28
UI/AppKit/Interface/BookmarkFolder.h
Normal file
28
UI/AppKit/Interface/BookmarkFolder.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWebView/Forward.h>
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class BookmarksBar;
|
||||
|
||||
@interface BookmarkFolderPopover : NSPopover
|
||||
|
||||
- (instancetype)init:(WebView::Menu&)menu
|
||||
bookmarksBar:(BookmarksBar*)bookmarks_bar
|
||||
parentFolder:(BookmarkFolderPopover*)parent_folder;
|
||||
|
||||
- (void)showRelativeToView:(NSView*)view preferredEdge:(NSRectEdge)preferred_edge;
|
||||
|
||||
- (void)openChildFolder:(WebView::Menu&)menu relativeToView:(NSView*)view;
|
||||
- (void)closeChildFolder;
|
||||
|
||||
- (void)close;
|
||||
|
||||
@end
|
||||
358
UI/AppKit/Interface/BookmarkFolder.mm
Normal file
358
UI/AppKit/Interface/BookmarkFolder.mm
Normal file
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Math.h>
|
||||
#include <LibWebView/Menu.h>
|
||||
|
||||
#import <Interface/BookmarkFolder.h>
|
||||
#import <Interface/BookmarksBar.h>
|
||||
#import <Interface/Menu.h>
|
||||
#import <Utilities/Conversions.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#if !__has_feature(objc_arc)
|
||||
# error "This project requires ARC"
|
||||
#endif
|
||||
|
||||
static constexpr CGFloat const BOOKMARK_FOLDER_WIDTH = 200;
|
||||
static constexpr CGFloat const BOOKMARK_FOLDER_MAX_HEIGHT = 360;
|
||||
static constexpr CGFloat const BOOKMARK_FOLDER_ROW_HEIGHT = 26;
|
||||
|
||||
static constexpr CGFloat const BOOKMARK_FOLDER_ICON_SIZE = 16;
|
||||
static constexpr CGFloat const BOOKMARK_FOLDER_CHEVRON_WIDTH = 12;
|
||||
|
||||
static constexpr CGFloat const BOOKMARK_FOLDER_INSET = 8;
|
||||
static constexpr CGFloat const BOOKMARK_FOLDER_HORIZONTAL_PADDING = 4;
|
||||
static constexpr CGFloat const BOOKMARK_FOLDER_VERTICAL_PADDING = 6;
|
||||
|
||||
static constexpr CGFloat const BOOKMARK_FOLDER_HORIZONTAL_OVERLAP = 24;
|
||||
static constexpr CGFloat const BOOKMARK_FOLDER_SUBMENU_LEFT_SHIFT = 18;
|
||||
static constexpr CGFloat const BOOKMARK_FOLDER_ROOT_VERTICAL_SHIFT = 10;
|
||||
|
||||
@interface BookmarkFolderItemView : NSView
|
||||
|
||||
@property (nonatomic, weak) BookmarksBar* bookmarks_bar;
|
||||
@property (nonatomic, weak) BookmarkFolderPopover* parent_folder;
|
||||
|
||||
@property (nonatomic, strong) NSImageView* icon_view;
|
||||
@property (nonatomic, strong) NSTextField* title_label;
|
||||
@property (nonatomic, strong) NSImageView* chevron_view;
|
||||
@property (nonatomic, strong) NSTrackingArea* tracking_area;
|
||||
|
||||
@end
|
||||
|
||||
@implementation BookmarkFolderItemView
|
||||
{
|
||||
WeakPtr<WebView::Action> m_action;
|
||||
WeakPtr<WebView::Menu> m_menu;
|
||||
BOOL m_hovered;
|
||||
}
|
||||
|
||||
- (instancetype)initForBookmark:(WebView::Action&)action
|
||||
bookmarksBar:(BookmarksBar*)bookmarks_bar
|
||||
parentFolder:(BookmarkFolderPopover*)parent_folder
|
||||
{
|
||||
if (self = [super initWithFrame:NSZeroRect]) {
|
||||
self.bookmarks_bar = bookmarks_bar;
|
||||
self.parent_folder = parent_folder;
|
||||
|
||||
m_action = action.make_weak_ptr();
|
||||
m_hovered = NO;
|
||||
|
||||
[self setToolTip:Ladybird::string_to_ns_string(action.tooltip())];
|
||||
|
||||
self.icon_view = Ladybird::create_application_icon(action);
|
||||
[self addSubview:self.icon_view];
|
||||
|
||||
self.title_label = [NSTextField labelWithString:Ladybird::string_to_ns_string(action.text())];
|
||||
[self.title_label setFont:[NSFont menuFontOfSize:0]];
|
||||
[[self.title_label cell] setLineBreakMode:NSLineBreakByTruncatingTail];
|
||||
[self addSubview:self.title_label];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initForSubfolder:(WebView::Menu&)menu
|
||||
bookmarksBar:(BookmarksBar*)bookmarks_bar
|
||||
parentFolder:(BookmarkFolderPopover*)parent_folder
|
||||
{
|
||||
if (self = [super initWithFrame:NSZeroRect]) {
|
||||
self.bookmarks_bar = bookmarks_bar;
|
||||
self.parent_folder = parent_folder;
|
||||
|
||||
m_menu = menu.make_weak_ptr();
|
||||
m_hovered = NO;
|
||||
|
||||
self.icon_view = [[NSImageView alloc] initWithFrame:NSZeroRect];
|
||||
[self.icon_view setImage:[NSImage imageWithSystemSymbolName:@"folder" accessibilityDescription:@""]];
|
||||
[self addSubview:self.icon_view];
|
||||
|
||||
self.title_label = [NSTextField labelWithString:Ladybird::string_to_ns_string(menu.title())];
|
||||
[self.title_label setFont:[NSFont menuFontOfSize:0]];
|
||||
[[self.title_label cell] setLineBreakMode:NSLineBreakByTruncatingTail];
|
||||
[self addSubview:self.title_label];
|
||||
|
||||
self.chevron_view = [[NSImageView alloc] initWithFrame:NSZeroRect];
|
||||
[self.chevron_view setImage:[NSImage imageWithSystemSymbolName:@"chevron.right" accessibilityDescription:@""]];
|
||||
[self.chevron_view setAutoresizingMask:NSViewMinXMargin];
|
||||
[self addSubview:self.chevron_view];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setHovered:(BOOL)hovered
|
||||
{
|
||||
if (m_hovered == hovered)
|
||||
return;
|
||||
|
||||
m_hovered = hovered;
|
||||
|
||||
auto* text_color = m_hovered ? [NSColor alternateSelectedControlTextColor] : [NSColor controlTextColor];
|
||||
[self.title_label setTextColor:text_color];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
#pragma mark - NSView
|
||||
|
||||
- (void)mouseEntered:(NSEvent*)event
|
||||
{
|
||||
[self setHovered:YES];
|
||||
|
||||
if (auto submenu = m_menu.strong_ref())
|
||||
[self.parent_folder openChildFolder:*submenu relativeToView:self];
|
||||
else
|
||||
[self.parent_folder closeChildFolder];
|
||||
}
|
||||
|
||||
- (void)mouseExited:(NSEvent*)event
|
||||
{
|
||||
[self setHovered:NO];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent*)event
|
||||
{
|
||||
if (auto submenu = m_menu.strong_ref(); submenu && submenu->size() > 0) {
|
||||
[self.parent_folder openChildFolder:*submenu relativeToView:self];
|
||||
} else if (auto action = m_action.strong_ref()) {
|
||||
[self.bookmarks_bar closeBookmarkFolders];
|
||||
action->activate();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateTrackingAreas
|
||||
{
|
||||
[super updateTrackingAreas];
|
||||
|
||||
auto mouse_location = [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView:nil];
|
||||
[self setHovered:CGRectContainsPoint([self bounds], mouse_location)];
|
||||
|
||||
if (self.tracking_area)
|
||||
[self removeTrackingArea:self.tracking_area];
|
||||
|
||||
self.tracking_area = [[NSTrackingArea alloc] initWithRect:NSZeroRect
|
||||
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect
|
||||
owner:self
|
||||
userInfo:nil];
|
||||
[self addTrackingArea:self.tracking_area];
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
[super drawRect:dirtyRect];
|
||||
|
||||
if (!m_hovered)
|
||||
return;
|
||||
|
||||
auto* selection_path = [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(self.bounds, 4, 1) xRadius:8 yRadius:8];
|
||||
[[NSColor selectedContentBackgroundColor] setFill];
|
||||
[selection_path fill];
|
||||
}
|
||||
|
||||
- (void)layout
|
||||
{
|
||||
[super layout];
|
||||
|
||||
auto [frame_width, frame_height] = [self bounds].size;
|
||||
|
||||
auto icon_size = AK::min(BOOKMARK_FOLDER_ICON_SIZE, frame_height);
|
||||
auto icon_y = AK::floor((frame_height - icon_size) / 2.0);
|
||||
|
||||
auto label_height = AK::min([self.title_label intrinsicContentSize].height, frame_height);
|
||||
auto label_y = AK::floor((frame_height - label_height) / 2.0);
|
||||
|
||||
auto icon_frame = NSMakeRect(BOOKMARK_FOLDER_INSET, icon_y, icon_size, icon_size);
|
||||
[self.icon_view setFrame:icon_frame];
|
||||
|
||||
auto trailing_width = self.chevron_view
|
||||
? BOOKMARK_FOLDER_HORIZONTAL_PADDING + BOOKMARK_FOLDER_CHEVRON_WIDTH + BOOKMARK_FOLDER_INSET
|
||||
: 0;
|
||||
|
||||
auto title_frame = NSMakeRect(
|
||||
BOOKMARK_FOLDER_INSET + icon_size + BOOKMARK_FOLDER_HORIZONTAL_PADDING,
|
||||
label_y,
|
||||
frame_width - (BOOKMARK_FOLDER_HORIZONTAL_PADDING * 2) - icon_size - trailing_width,
|
||||
label_height);
|
||||
[self.title_label setFrame:title_frame];
|
||||
|
||||
if (self.chevron_view) {
|
||||
auto chevron_frame = NSMakeRect(
|
||||
frame_width - BOOKMARK_FOLDER_INSET - BOOKMARK_FOLDER_CHEVRON_WIDTH,
|
||||
icon_y,
|
||||
BOOKMARK_FOLDER_CHEVRON_WIDTH,
|
||||
icon_size);
|
||||
[self.chevron_view setFrame:chevron_frame];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface BookmarkFolderPopover () <NSPopoverDelegate>
|
||||
|
||||
@property (nonatomic, strong) BookmarkFolderPopover* child_folder;
|
||||
@property (nonatomic, weak) BookmarkFolderPopover* parent_folder;
|
||||
@property (nonatomic, weak) BookmarksBar* bookmarks_bar;
|
||||
|
||||
@end
|
||||
|
||||
@implementation BookmarkFolderPopover
|
||||
{
|
||||
WeakPtr<WebView::Menu> m_menu;
|
||||
}
|
||||
|
||||
- (instancetype)init:(WebView::Menu&)menu
|
||||
bookmarksBar:(BookmarksBar*)bookmarks_bar
|
||||
parentFolder:(BookmarkFolderPopover*)parent_folder
|
||||
{
|
||||
if (self = [super init]) {
|
||||
self.bookmarks_bar = bookmarks_bar;
|
||||
self.parent_folder = parent_folder;
|
||||
self.delegate = self;
|
||||
|
||||
m_menu = menu.make_weak_ptr();
|
||||
|
||||
[self setAnimates:NO];
|
||||
[self setBehavior:NSPopoverBehaviorTransient];
|
||||
[self setValue:[NSNumber numberWithBool:YES] forKeyPath:@"shouldHideAnchor"];
|
||||
|
||||
auto* content_view = [[NSView alloc] initWithFrame:NSZeroRect];
|
||||
auto* scroll_view = [[NSScrollView alloc] initWithFrame:NSZeroRect];
|
||||
[scroll_view setHasVerticalScroller:YES];
|
||||
[scroll_view setDrawsBackground:NO];
|
||||
[scroll_view setBorderType:NSNoBorder];
|
||||
|
||||
auto width = BOOKMARK_FOLDER_WIDTH;
|
||||
auto height = (BOOKMARK_FOLDER_VERTICAL_PADDING * 2) + (BOOKMARK_FOLDER_ROW_HEIGHT * menu.size());
|
||||
|
||||
auto* items_view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, width, height)];
|
||||
auto y = height - BOOKMARK_FOLDER_VERTICAL_PADDING;
|
||||
|
||||
for (auto const& item : menu.items()) {
|
||||
auto* item_view = item.visit(
|
||||
[&](NonnullRefPtr<WebView::Action> const& action) -> NSView* {
|
||||
return [[BookmarkFolderItemView alloc] initForBookmark:*action
|
||||
bookmarksBar:self.bookmarks_bar
|
||||
parentFolder:self];
|
||||
},
|
||||
[&](NonnullRefPtr<WebView::Menu> const& submenu) -> NSView* {
|
||||
return [[BookmarkFolderItemView alloc] initForSubfolder:*submenu
|
||||
bookmarksBar:self.bookmarks_bar
|
||||
parentFolder:self];
|
||||
},
|
||||
[&](WebView::Separator) -> NSView* {
|
||||
VERIFY_NOT_REACHED();
|
||||
});
|
||||
|
||||
y -= BOOKMARK_FOLDER_ROW_HEIGHT;
|
||||
|
||||
[item_view setFrame:NSMakeRect(0, y, width, BOOKMARK_FOLDER_ROW_HEIGHT)];
|
||||
[items_view addSubview:item_view];
|
||||
}
|
||||
|
||||
auto visible_height = AK::min(height, BOOKMARK_FOLDER_MAX_HEIGHT);
|
||||
[content_view setFrame:NSMakeRect(0, 0, width, visible_height)];
|
||||
[scroll_view setFrame:NSMakeRect(0, 0, width, visible_height)];
|
||||
[scroll_view setHasVerticalScroller:(height > visible_height)];
|
||||
[scroll_view setDocumentView:items_view];
|
||||
|
||||
[content_view addSubview:scroll_view];
|
||||
|
||||
auto* controller = [[NSViewController alloc] init];
|
||||
[controller setView:content_view];
|
||||
|
||||
[self setContentViewController:controller];
|
||||
[self setContentSize:NSMakeSize(width, visible_height)];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)showRelativeToView:(NSView*)view preferredEdge:(NSRectEdge)preferred_edge
|
||||
{
|
||||
auto rect = [view bounds];
|
||||
|
||||
if (preferred_edge == NSRectEdgeMaxX) {
|
||||
rect = NSMakeRect(
|
||||
NSWidth(rect) - BOOKMARK_FOLDER_HORIZONTAL_OVERLAP - BOOKMARK_FOLDER_SUBMENU_LEFT_SHIFT,
|
||||
0,
|
||||
BOOKMARK_FOLDER_HORIZONTAL_OVERLAP,
|
||||
NSHeight(rect));
|
||||
}
|
||||
|
||||
[self showRelativeToRect:rect ofView:view preferredEdge:preferred_edge];
|
||||
|
||||
if (preferred_edge == NSRectEdgeMaxY) {
|
||||
if (auto* window = [self.contentViewController.view window]) {
|
||||
auto origin = [window frame].origin;
|
||||
origin.y += BOOKMARK_FOLDER_ROOT_VERTICAL_SHIFT;
|
||||
[window setFrameOrigin:origin];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)openChildFolder:(WebView::Menu&)menu relativeToView:(NSView*)view
|
||||
{
|
||||
if (menu.size() == 0) {
|
||||
[self closeChildFolder];
|
||||
return;
|
||||
}
|
||||
|
||||
[self.child_folder close];
|
||||
|
||||
self.child_folder = [[BookmarkFolderPopover alloc] init:menu bookmarksBar:self.bookmarks_bar parentFolder:self];
|
||||
[self.child_folder showRelativeToView:view preferredEdge:NSRectEdgeMaxX];
|
||||
}
|
||||
|
||||
- (void)closeChildFolder
|
||||
{
|
||||
[self.child_folder close];
|
||||
self.child_folder = nil;
|
||||
}
|
||||
|
||||
- (void)close
|
||||
{
|
||||
[self.child_folder close];
|
||||
self.child_folder = nil;
|
||||
|
||||
[super close];
|
||||
}
|
||||
|
||||
#pragma mark - NSPopoverDelegate
|
||||
|
||||
- (void)popoverDidClose:(NSNotification*)notification
|
||||
{
|
||||
[self.child_folder close];
|
||||
self.child_folder = nil;
|
||||
|
||||
if (self.parent_folder)
|
||||
self.parent_folder.child_folder = nil;
|
||||
else
|
||||
[self.bookmarks_bar bookmarkFolderDidClose:self];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -8,10 +8,15 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class BookmarkFolderPopover;
|
||||
|
||||
@interface BookmarksBar : NSView
|
||||
|
||||
- (instancetype)init;
|
||||
|
||||
- (void)rebuild;
|
||||
|
||||
- (void)closeBookmarkFolders;
|
||||
- (void)bookmarkFolderDidClose:(BookmarkFolderPopover*)folder;
|
||||
|
||||
@end
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
*/
|
||||
|
||||
#include <LibWebView/Application.h>
|
||||
#include <LibWebView/Menu.h>
|
||||
|
||||
#import <Interface/BookmarkFolder.h>
|
||||
#import <Interface/BookmarksBar.h>
|
||||
#import <Interface/Menu.h>
|
||||
#import <Utilities/Conversions.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#if !__has_feature(objc_arc)
|
||||
# error "This project requires ARC"
|
||||
@@ -20,11 +21,31 @@ static constexpr CGFloat const BOOKMARK_ITEM_SPACING = 2;
|
||||
static constexpr CGFloat const BOOKMARK_LEADING_INSET = 8;
|
||||
static constexpr CGFloat const OVERFLOW_TRAILING_INSET = 4;
|
||||
|
||||
static char BOOKMARK_FOLDER_KEY = 0;
|
||||
static Optional<WebView::Menu&> find_bookmark_folder_by_id(WebView::Menu& menu, StringView id)
|
||||
{
|
||||
for (auto& item : menu.items()) {
|
||||
auto* submenu_ptr = item.get_pointer<NonnullRefPtr<WebView::Menu>>();
|
||||
if (!submenu_ptr)
|
||||
continue;
|
||||
|
||||
auto& submenu = **submenu_ptr;
|
||||
|
||||
if (auto submenu_id = submenu.properties().get("id"sv); submenu_id.has_value() && *submenu_id == id)
|
||||
return submenu;
|
||||
|
||||
if (auto descendant = find_bookmark_folder_by_id(submenu, id); descendant.has_value())
|
||||
return descendant;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@interface BookmarksBar ()
|
||||
|
||||
@property (nonatomic, strong) NSStackView* bookmark_items;
|
||||
@property (nonatomic, strong) BookmarkFolderPopover* bookmark_folder_popover;
|
||||
@property (nonatomic, weak) NSButton* active_bookmark_folder_button;
|
||||
|
||||
@property (nonatomic, strong) NSButton* overflow_button;
|
||||
@property (nonatomic, strong) NSMenu* overflow_menu;
|
||||
|
||||
@@ -86,6 +107,7 @@ static char BOOKMARK_FOLDER_KEY = 0;
|
||||
|
||||
- (void)rebuild
|
||||
{
|
||||
[self closeBookmarkFolders];
|
||||
[self.bookmark_items setSubviews:@[]];
|
||||
|
||||
auto set_button_properties = [](NSButton* button, StringView title) {
|
||||
@@ -119,9 +141,6 @@ static char BOOKMARK_FOLDER_KEY = 0;
|
||||
action:@selector(openFolder:)];
|
||||
set_button_properties(button, folder->title());
|
||||
|
||||
auto* submenu = Ladybird::create_application_menu(folder);
|
||||
objc_setAssociatedObject(button, &BOOKMARK_FOLDER_KEY, submenu, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
|
||||
return button;
|
||||
},
|
||||
[](WebView::Separator) -> NSButton* {
|
||||
@@ -189,13 +208,61 @@ static char BOOKMARK_FOLDER_KEY = 0;
|
||||
|
||||
- (void)openFolder:(NSButton*)sender
|
||||
{
|
||||
NSMenu* folder = objc_getAssociatedObject(sender, &BOOKMARK_FOLDER_KEY);
|
||||
if (!folder)
|
||||
auto* item_id = Ladybird::get_control_property(sender, @"id");
|
||||
if (!item_id)
|
||||
return;
|
||||
|
||||
[folder popUpMenuPositioningItem:nil
|
||||
atLocation:NSMakePoint(0, [sender bounds].size.height)
|
||||
inView:sender];
|
||||
auto id = Ladybird::ns_string_to_string(item_id);
|
||||
auto folder = find_bookmark_folder_by_id(WebView::Application::the().bookmarks_menu(), id);
|
||||
if (!folder.has_value())
|
||||
return;
|
||||
|
||||
[self openFolderMenu:*folder anchoredToView:sender preferredEdge:NSRectEdgeMaxY];
|
||||
}
|
||||
|
||||
- (void)openFolderMenu:(WebView::Menu&)menu
|
||||
anchoredToView:(NSView*)view
|
||||
preferredEdge:(NSRectEdge)preferredEdge
|
||||
{
|
||||
if (menu.size() == 0)
|
||||
return;
|
||||
|
||||
[self closeBookmarkFolders];
|
||||
|
||||
if ([view isKindOfClass:[NSButton class]]) {
|
||||
self.active_bookmark_folder_button = (NSButton*)view;
|
||||
[self.active_bookmark_folder_button setShowsBorderOnlyWhileMouseInside:NO];
|
||||
[self.active_bookmark_folder_button highlight:YES];
|
||||
}
|
||||
|
||||
self.bookmark_folder_popover = [[BookmarkFolderPopover alloc] init:menu bookmarksBar:self parentFolder:nil];
|
||||
[self.bookmark_folder_popover showRelativeToView:view preferredEdge:preferredEdge];
|
||||
}
|
||||
|
||||
- (void)closeBookmarkFolders
|
||||
{
|
||||
[self.bookmark_folder_popover close];
|
||||
self.bookmark_folder_popover = nil;
|
||||
|
||||
[self clearActiveBookmarkFolder];
|
||||
}
|
||||
|
||||
- (void)bookmarkFolderDidClose:(BookmarkFolderPopover*)folder
|
||||
{
|
||||
if (self.bookmark_folder_popover == folder)
|
||||
self.bookmark_folder_popover = nil;
|
||||
|
||||
[self clearActiveBookmarkFolder];
|
||||
}
|
||||
|
||||
- (void)clearActiveBookmarkFolder
|
||||
{
|
||||
if (!self.active_bookmark_folder_button)
|
||||
return;
|
||||
|
||||
[self.active_bookmark_folder_button highlight:NO];
|
||||
[self.active_bookmark_folder_button setShowsBorderOnlyWhileMouseInside:YES];
|
||||
self.active_bookmark_folder_button = nil;
|
||||
}
|
||||
|
||||
- (void)layout
|
||||
|
||||
@@ -22,6 +22,7 @@ NSMenu* create_context_menu(LadybirdWebView*, WebView::Menu&);
|
||||
|
||||
NSMenuItem* create_application_menu_item(WebView::Action&);
|
||||
NSButton* create_application_button(WebView::Action&);
|
||||
NSImageView* create_application_icon(WebView::Action&);
|
||||
|
||||
void set_control_image(id control, NSString*);
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ static NSImage* image_from_base64_png(StringView favicon_base64_png)
|
||||
return image;
|
||||
}
|
||||
|
||||
static void initialize_native_control(WebView::Action& action, id control)
|
||||
static void initialize_native_icon(WebView::Action& action, id control)
|
||||
{
|
||||
switch (action.id()) {
|
||||
case WebView::ActionID::NavigateBack:
|
||||
@@ -306,6 +306,11 @@ static void initialize_native_control(WebView::Action& action, id control)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void initialize_native_control(WebView::Action& action, id control)
|
||||
{
|
||||
initialize_native_icon(action, control);
|
||||
|
||||
auto observer = ActionObserver::create(action, control);
|
||||
|
||||
@@ -391,9 +396,17 @@ NSButton* create_application_button(WebView::Action& action)
|
||||
{
|
||||
auto* button = [[NSButton alloc] init];
|
||||
initialize_native_control(action, button);
|
||||
set_properties(button, action);
|
||||
return button;
|
||||
}
|
||||
|
||||
NSImageView* create_application_icon(WebView::Action& action)
|
||||
{
|
||||
auto* icon = [[NSImageView alloc] initWithFrame:NSZeroRect];
|
||||
initialize_native_icon(action, icon);
|
||||
return icon;
|
||||
}
|
||||
|
||||
void set_control_image(id control, NSString* image)
|
||||
{
|
||||
// System symbols are distributed with the San Fransisco (SF) Symbols font. To see all SF Symbols and their names,
|
||||
|
||||
Reference in New Issue
Block a user