diff --git a/AppKit/CPMenu/_CPMenuWindow.j b/AppKit/CPMenu/_CPMenuWindow.j index 53237a5a1..cea10aab9 100644 --- a/AppKit/CPMenu/_CPMenuWindow.j +++ b/AppKit/CPMenu/_CPMenuWindow.j @@ -234,6 +234,19 @@ _CPMenuWindowAttachedMenuBackgroundStyle = 2; // FIXME: This gets called far too often. _unconstrainedFrame = CGRectMakeCopy(aFrame); + // If we are a submenu and we are being displayed off the right of the screen, + // we should try and display on the left of our supermenu. + var supermenu = [[self menu] supermenu]; + if (supermenu && (CGRectGetMaxX(_unconstrainedFrame) > CGRectGetMaxX(_constraintRect))) + { + var supermenuWindow = supermenu._menuWindow; + if (supermenuWindow) + { + var supermenuFrame = [supermenuWindow frame]; + _unconstrainedFrame.origin.x = CGRectGetMinX(supermenuFrame) - CGRectGetWidth(_unconstrainedFrame); + } + } + var constrainedFrame = CGRectIntersection(_unconstrainedFrame, _constraintRect), marginInset = [_menuView valueForThemeAttribute:@"menu-window-margin-inset"], scrollIndicatorHeight = [_menuView valueForThemeAttribute:@"menu-window-scroll-indicator-height"]; diff --git a/Tests/Manual/CPMenuSubmenuPlacementConstraints/AppController.j b/Tests/Manual/CPMenuSubmenuPlacementConstraints/AppController.j new file mode 100644 index 000000000..3261959e8 --- /dev/null +++ b/Tests/Manual/CPMenuSubmenuPlacementConstraints/AppController.j @@ -0,0 +1,109 @@ +/* + * AppController.j + * CPMenuTest + * + * Created by Daniel Boehringer 2025 for submenu constraints on the rightmost end of the screen. + */ + + +@import + +@implementation AppController : CPObject +{ + CPWindow theWindow; + BOOL _isEnabled; +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], + contentView = [theWindow contentView]; + + mainMenu = [[CPMenu alloc] initWithTitle:@"MainMenu"], + appMenu = [[CPMenu alloc] initWithTitle:@"App"], + fileMenu = [[CPMenu alloc] initWithTitle:@"File"], + bindingsMenu = [[CPMenu alloc] initWithTitle:@"Bindings Test"]; + + _isEnabled = YES; + + [CPApp setMainMenu:mainMenu]; + + [mainMenu addItemWithTitle:@"App" action:nil keyEquivalent:@""]; + [mainMenu setSubmenu:appMenu forItem:[mainMenu itemWithTitle:@"App"]]; + + [appMenu addItemWithTitle:@"About" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; + [appMenu addItem:[CPMenuItem separatorItem]]; + [appMenu addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"]; + + [mainMenu addItemWithTitle:@"File" action:nil keyEquivalent:@""]; + [mainMenu setSubmenu:fileMenu forItem:[mainMenu itemWithTitle:@"File"]]; + + [fileMenu addItemWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"n"]; + [fileMenu addItemWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"o"]; + [fileMenu addItemWithTitle:@"Close" action:@selector(newDocument:) keyEquivalent:@"w"]; + + // 1. Add some dummy menus to push the test menu further to the right. + var dummyMenu1 = [[CPMenu alloc] initWithTitle:@"Dummy 1"], + dummyMenu2 = [[CPMenu alloc] initWithTitle:@"Dummy 2"]; + + [dummyMenu1 addItemWithTitle:@"Dummy Action A" action:nil keyEquivalent:@""]; + [dummyMenu1 addItemWithTitle:@"Dummy Action B" action:nil keyEquivalent:@""]; + + [dummyMenu2 addItemWithTitle:@"Another Dummy Action" action:nil keyEquivalent:@""]; + + var dummyMenuItem1 = [mainMenu addItemWithTitle:@"Dummy Menu 1" action:nil keyEquivalent:@""]; + [mainMenu setSubmenu:dummyMenu1 forItem:dummyMenuItem1]; + + var dummyMenuItem2 = [mainMenu addItemWithTitle:@"Dummy Menu 2" action:nil keyEquivalent:@""]; + [mainMenu setSubmenu:dummyMenu2 forItem:dummyMenuItem2]; + + + // 2. Create the right-most menu with submenus for testing. + var rightTestMenu = [[CPMenu alloc] initWithTitle:@"Right-Side Test"], + rightTestMenuItem = [mainMenu addItemWithTitle:@"Right-Side Test" action:nil keyEquivalent:@""]; + + [mainMenu setSubmenu:rightTestMenu forItem:rightTestMenuItem]; + + // Add some simple items + [rightTestMenu addItemWithTitle:@"Simple Item (No Submenu)" action:nil keyEquivalent:@""]; + [rightTestMenu addItem:[CPMenuItem separatorItem]]; + + // Create the first level submenu + var submenu1 = [[CPMenu alloc] initWithTitle:@"Submenu 1"], + submenu1Item = [rightTestMenu addItemWithTitle:@"Test First Submenu" action:nil keyEquivalent:@""]; + + [submenu1 addItemWithTitle:@"Sub-item A" action:nil keyEquivalent:@""]; + [submenu1 addItemWithTitle:@"Sub-item B" action:nil keyEquivalent:@""]; + [rightTestMenu setSubmenu:submenu1 forItem:submenu1Item]; + + // Create a nested submenu for deeper testing + var submenu2 = [[CPMenu alloc] initWithTitle:@"Submenu 2"], + submenu2Item = [rightTestMenu addItemWithTitle:@"Test Nested Submenu" action:nil keyEquivalent:@""], + deeperSubmenu = [[CPMenu alloc] initWithTitle:@"Deeper"], + deeperSubmenuItem = [submenu2 addItemWithTitle:@"Deeper Submenu..." action:nil keyEquivalent:@""]; + + [submenu2 addItemWithTitle:@"Another Sub-item" action:nil keyEquivalent:@""]; + [deeperSubmenu addItemWithTitle:@"Deep Item X" action:nil keyEquivalent:@""]; + [deeperSubmenu addItemWithTitle:@"Deep Item Y" action:nil keyEquivalent:@""]; + + [submenu2 setSubmenu:deeperSubmenu forItem:deeperSubmenuItem]; + [rightTestMenu setSubmenu:submenu2 forItem:submenu2Item]; + + [CPMenu setMenuBarVisible:YES]; +} + +- (void)toggleEnabled:(id)sender +{ + _isEnabled = !_isEnabled; + [self didChangeValueForKey:@"isEnabled"]; +} + +- (BOOL)validateMenuItem:(CPMenuItem)anItem +{ + if ([anItem action] == @selector(toggleEnabled:)) + return _isEnabled; + + return YES; +} + +@end diff --git a/Tests/Manual/CPMenuSubmenuPlacementConstraints/Info.plist b/Tests/Manual/CPMenuSubmenuPlacementConstraints/Info.plist new file mode 100644 index 000000000..dd6f547e5 --- /dev/null +++ b/Tests/Manual/CPMenuSubmenuPlacementConstraints/Info.plist @@ -0,0 +1,12 @@ + + + + + CPApplicationDelegateClass + AppController + CPBundleName + CPMenuTest + CPPrincipalClass + CPApplication + + diff --git a/Tests/Manual/CPMenuSubmenuPlacementConstraints/Jakefile b/Tests/Manual/CPMenuSubmenuPlacementConstraints/Jakefile new file mode 100644 index 000000000..0c132c972 --- /dev/null +++ b/Tests/Manual/CPMenuSubmenuPlacementConstraints/Jakefile @@ -0,0 +1,93 @@ +/* + * Jakefile + * CPMenuTest + * + * Created by Alexander Ljungberg on August 31, 2010. + * Copyright 2010, WireLoad, LLC All rights reserved. + */ + +var ENV = require("system").env, + FILE = require("file"), + JAKE = require("jake"), + task = JAKE.task, + FileList = JAKE.FileList, + app = require("cappuccino/jake").app, + configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug", + OS = require("os"); + +app ("CPMenuTest", function(task) +{ + task.setBuildIntermediatesPath(FILE.join("Build", "CPMenuTest.build", configuration)); + task.setBuildPath(FILE.join("Build", configuration)); + + task.setProductName("CPMenuTest"); + task.setIdentifier("com.yourcompany.CPMenuTest"); + task.setVersion("1.0"); + task.setAuthor("WireLoad, LLC"); + task.setEmail("feedback @nospam@ yourcompany.com"); + task.setSummary("CPMenuTest"); + task.setSources((new FileList("**/*.j")).exclude(FILE.join("Build", "**"))); + task.setResources(new FileList("Resources/**")); + task.setIndexFilePath("index.html"); + task.setInfoPlistPath("Info.plist"); + + if (configuration === "Debug") + task.setCompilerFlags("-DDEBUG -g"); + else + task.setCompilerFlags("-O"); +}); + +task ("default", ["CPMenuTest"], function() +{ + printResults(configuration); +}); + +task ("build", ["default"]); + +task ("debug", function() +{ + ENV["CONFIGURATION"] = "Debug"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("release", function() +{ + ENV["CONFIGURATION"] = "Release"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("run", ["debug"], function() +{ + OS.system(["open", FILE.join("Build", "Debug", "CPMenuTest", "index.html")]); +}); + +task ("run-release", ["release"], function() +{ + OS.system(["open", FILE.join("Build", "Release", "CPMenuTest", "index.html")]); +}); + +task ("deploy", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Deployment", "CPMenuTest")); + OS.system(["press", "-f", FILE.join("Build", "Release", "CPMenuTest"), FILE.join("Build", "Deployment", "CPMenuTest")]); + printResults("Deployment") +}); + +task ("desktop", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Desktop", "CPMenuTest")); + require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", "CPMenuTest"), FILE.join("Build", "Desktop", "CPMenuTest", "CPMenuTest.app")); + printResults("Desktop") +}); + +task ("run-desktop", ["desktop"], function() +{ + OS.system([FILE.join("Build", "Desktop", "CPMenuTest", "CPMenuTest.app", "Contents", "MacOS", "NativeHost"), "-i"]); +}); + +function printResults(configuration) +{ + print("----------------------------"); + print(configuration+" app built at path: "+FILE.join("Build", configuration, "CPMenuTest")); + print("----------------------------"); +} diff --git a/Tests/Manual/CPMenuSubmenuPlacementConstraints/Resources/spinner.gif b/Tests/Manual/CPMenuSubmenuPlacementConstraints/Resources/spinner.gif new file mode 100644 index 000000000..a5e705f6c Binary files /dev/null and b/Tests/Manual/CPMenuSubmenuPlacementConstraints/Resources/spinner.gif differ diff --git a/Tests/Manual/CPMenuSubmenuPlacementConstraints/index-debug.html b/Tests/Manual/CPMenuSubmenuPlacementConstraints/index-debug.html new file mode 100644 index 000000000..a36b1d3b9 --- /dev/null +++ b/Tests/Manual/CPMenuSubmenuPlacementConstraints/index-debug.html @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + __project.name__ + + + + + + + + + + + + + + +
+
+
+ +
+
+ +
+ + diff --git a/Tests/Manual/CPMenuSubmenuPlacementConstraints/index.html b/Tests/Manual/CPMenuSubmenuPlacementConstraints/index.html new file mode 100644 index 000000000..ac42c98a7 --- /dev/null +++ b/Tests/Manual/CPMenuSubmenuPlacementConstraints/index.html @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + __project.name__ + + + + + + + + + + + + +
+
+
+ +
+
+ +
+ + diff --git a/Tests/Manual/CPMenuSubmenuPlacementConstraints/main.j b/Tests/Manual/CPMenuSubmenuPlacementConstraints/main.j new file mode 100644 index 000000000..73eebda4b --- /dev/null +++ b/Tests/Manual/CPMenuSubmenuPlacementConstraints/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * CPMenuTest + * + * Created by Alexander Ljungberg on August 31, 2010. + * Copyright 2010, WireLoad, LLC All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +}