From 253401e9eed2ebd36638890804f0ebc291f5f662 Mon Sep 17 00:00:00 2001 From: Daniel Boyd Date: Wed, 21 Oct 2026 13:44:42 -0500 Subject: [PATCH] =?UTF-8?q?Toolbar:=20Undo=20and=20Redo=20keep=20their=20n?= =?UTF-8?q?ames=20in=20the=20=C2=BB=20menu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On GNUstep the icon-only toolbar items have empty labels, and the » menu titles an overflowed item from its label unless it has a menu form of its own. Since #303 Undo and Redo are the first items to overflow, so they showed there as blank rows. Give the icon items a titled menu form, as the labelled items (Save, Copy) already have. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01V8rjzo3Qk8M7WcT9RYfYRW --- Source/AppDelegate.m | 5 +++++ Tests/TitleBarToolbarProbe_test.m | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/Source/AppDelegate.m b/Source/AppDelegate.m index 004ec90..a560e8a 100644 --- a/Source/AppDelegate.m +++ b/Source/AppDelegate.m @@ -3606,6 +3606,11 @@ - (NSToolbarItem *)baselineToolbarItemWithIdentifier:(NSToolbarItemIdentifier)id item.paletteLabel = label ?: @""; #if defined(GNUSTEP) item.label = @""; + // Folded into » the item is a menu item titled from its label, which is empty, so it needs + // its own: Undo and Redo overflow first and showed as blank rows. + NSMenuItem *menuForm = [[NSMenuItem alloc] initWithTitle:item.paletteLabel action:selector keyEquivalent:@""]; + menuForm.target = self; + item.menuFormRepresentation = menuForm; #else item.label = item.paletteLabel; #endif diff --git a/Tests/TitleBarToolbarProbe_test.m b/Tests/TitleBarToolbarProbe_test.m index df4849f..967027b 100644 --- a/Tests/TitleBarToolbarProbe_test.m +++ b/Tests/TitleBarToolbarProbe_test.m @@ -141,6 +141,24 @@ - (void)testSaveAndCopyKeepTheirNamesInTheOverflowMenu { XCTAssertEqual(menuItem.target, (id)_appDelegate, @"%@ goes to the app delegate", identifier); } } + +- (void)testIconItemsKeepTheirNamesInTheOverflowMenu { + XCTSkipIf(_shouldSkip, @"No window server"); + // Icon-only items have empty labels too, and Undo and Redo are the first to go into ». + NSToolbar *toolbar = _appDelegate.window.toolbar; + id delegate = (id)_appDelegate; + NSDictionary *expected = @{@"undo": @"Undo", @"redo": @"Redo"}; + NSDictionary *actions = @{@"undo": @"undo:", @"redo": @"redo:"}; + for (NSString *name in expected) { + NSString *identifier = [@"com.screenshottool.toolbar." stringByAppendingString:name]; + NSToolbarItem *item = [delegate toolbar:toolbar itemForItemIdentifier:identifier willBeInsertedIntoToolbar:YES]; + NSMenuItem *menuItem = item.menuFormRepresentation; + XCTAssertNotNil(menuItem, @"%@ has a menu form", identifier); + XCTAssertEqualObjects(menuItem.title, expected[name], @"%@ is named in »", identifier); + XCTAssertEqualObjects(NSStringFromSelector(menuItem.action), actions[name], @"%@ runs its command from »", identifier); + XCTAssertEqual(menuItem.target, (id)_appDelegate, @"%@ goes to the app delegate", identifier); + } +} #endif #pragma mark - Slim toolbar (#53)