Skip to content

Commit

Permalink
Ensure autocomplete menu is on top.
Browse files Browse the repository at this point in the history
The menu should appear above other normal windows and controls like a regular CPMenu. To do this, put the pop up in its own window with the `CPPopUpMenuWindowLevel` window level.
  • Loading branch information
aljungberg committed Jun 16, 2012
1 parent 2574fac commit 33fe157
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 43 deletions.
37 changes: 8 additions & 29 deletions AppKit/CPTokenField.j
Expand Up @@ -63,7 +63,7 @@ var CPScrollDestinationNone = 0,

CPRange _selectedRange;

_CPAutocompleteMenu _autocompleteMenu @accessors;
_CPAutocompleteMenu _autocompleteMenu;

CPTimeInterval _completionDelay;

Expand Down Expand Up @@ -119,8 +119,13 @@ var CPScrollDestinationNone = 0,
[_tokenScrollView setDocumentView:contentView];

[self addSubview:_tokenScrollView];
}

_autocompleteMenu = [[_CPAutocompleteMenu alloc] initWithTextField:self];
- (_CPAutocompleteMenu)_autocompleteMenu
{
if (!_autocompleteMenu)
_autocompleteMenu = [[_CPAutocompleteMenu alloc] initWithTextField:self];
return _autocompleteMenu;
}

- (void)_autocompleteWithDOMEvent:(JSObject)DOMEvent
Expand Down Expand Up @@ -352,8 +357,6 @@ var CPScrollDestinationNone = 0,

- (BOOL)resignFirstResponder
{
CPLog("%@ resignFirstResponder", self);

if (_preventResign)
return NO;

Expand Down Expand Up @@ -566,25 +569,6 @@ var CPScrollDestinationNone = 0,
{
}

// ========
// = VIEW =
// ========
- (void)viewDidMoveToWindow
{
// TODO Switch to a window.
[[[self window] contentView] addSubview:[_autocompleteMenu contentView]];

#if PLATFORM(DOM)
[_autocompleteMenu contentView]._DOMElement.style.zIndex = 1000; // Anything else doesn't seem to work
#endif
}

- (void)removeFromSuperview
{
// TODO
[[_autocompleteMenu contentView] removeFromSuperview];
}

// =============
// = TEXTFIELD =
// =============
Expand Down Expand Up @@ -1014,11 +998,6 @@ var CPScrollDestinationNone = 0,
return [[_tokenScrollView documentView] scrollRectToVisible:[aToken frame]];
}

- (CPTableView)_autocompleteView
{
return _autocompleteView;
}

@end

@implementation CPTokenField (CPTokenFieldDelegate)
Expand Down Expand Up @@ -1125,7 +1104,7 @@ var CPScrollDestinationNone = 0,

- (void)_delayedShowCompletions
{
[_autocompleteMenu _delayedShowCompletions];
[[self _autocompleteMenu] _delayedShowCompletions];
}

- (void)_hideCompletions
Expand Down
37 changes: 23 additions & 14 deletions AppKit/_CPAutocompleteMenu.j
Expand Up @@ -34,7 +34,7 @@
CPTextField textField @accessors;
CPArray contentArray @accessors;

CPView contentView @accessors;
CPWindow _menuWindow;
CPScrollView scrollView;
CPTableView tableView;

Expand All @@ -47,9 +47,15 @@
{
textField = aTextField;

contentView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
_menuWindow = [[CPWindow alloc] initWithContentRect:CGRectMake(0, 0, 100, 100) styleMask:CPBorderlessWindowMask];

[contentView setBackgroundColor:[_CPMenuWindow backgroundColorForBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle]];
[_menuWindow setLevel:CPPopUpMenuWindowLevel];
[_menuWindow setHasShadow:YES];
[_menuWindow setShadowStyle:CPMenuWindowShadowStyle];
[_menuWindow setAcceptsMouseMovedEvents:NO];
[_menuWindow setBackgroundColor:[_CPMenuWindow backgroundColorForBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle]];

var contentView = [_menuWindow contentView];

scrollView = [[CPScrollView alloc] initWithFrame:CGRectMakeZero()];
[scrollView setAutohidesScrollers:YES];
Expand Down Expand Up @@ -107,11 +113,14 @@
- (void)layoutSubviews
{
// TODO
// The autocompletion menu should be underneath the current token, it should at least be wide enough to fit the widest
// option but no wider than the width of the token field. It might stick out on the right side, so that if the token
// is small enough to fit on the right side the menu might extend a full token field width more into space on the right
// side. It should not stick out outside of the screen. The height should be the smallest possible to fit all options
// or at most ~307px (based on Cocoa). If the options don't fit horizontally they should be truncated with an ellipsis.
/*
The autocompletion menu should be underneath the word/text being autocompleted. It should at least be wide enough to
fit the widest
option but no wider than the width of the text field. It might stick out on the right side, so that if the edited text
is on the right of the text field the menu might extend a full text field width more into space on the right
side. It should not stick out outside of the screen. The height should be the smallest possible to fit all options
or at most ~307px (based on Cocoa). If the options don't fit horizontally they should be truncated with an ellipsis.
*/

var frame = [textField frame];

Expand All @@ -120,10 +129,10 @@
[[[tableView tableColumns] firstObject] setWidth:[[scrollView contentView] frame].size.width];

// Manually sizeToFit because CPTableView's sizeToFit doesn't work properly
var frameOrigin = [textField convertPoint:[textField bounds].origin toView:[contentView superview]],
var frameOrigin = [textField convertPoint:[textField bounds].origin toView:nil],
newFrame = CGRectMake(frameOrigin.x, frameOrigin.y + frame.size.height, CPRectGetWidth([textField bounds]), 92.0);
[contentView setFrame:newFrame];
[scrollView setFrame:CGRectInset([contentView bounds], 1.0, 1.0)];
[_menuWindow setFrame:[_menuWindow frameRectForContentRect:newFrame]];
[scrollView setFrame:CGRectInset([[_menuWindow contentView] bounds], 1.0, 1.0)];
}

- (void)_showCompletions:(CPTimer)timer
Expand All @@ -136,7 +145,7 @@
[self setIndexOfSelectedItem:indexOfSelectedItem];

[textField setThemeState:CPThemeStateAutocompleting];
[contentView setHidden:NO];
[_menuWindow orderFront:self];

[self layoutSubviews];
}
Expand All @@ -161,7 +170,7 @@
_showCompletionsTimer = nil;

[textField unsetThemeState:CPThemeStateAutocompleting];
[contentView setHidden:YES];
[_menuWindow orderOut:self];
[self layoutSubviews];
}

Expand Down Expand Up @@ -201,7 +210,7 @@
// make sure a mouse click in the tableview doesn't steal first responder state
window.setTimeout(function()
{
[[contentView window] makeFirstResponder:textField];
[[textField window] makeFirstResponder:textField];
}, 2.0);
}

Expand Down

0 comments on commit 33fe157

Please sign in to comment.