Switched from NSPopover for the TextField.Invalid() warning on Mac OS X to a custom window subclass.
This commit is contained in:
parent
83f423a43e
commit
a9961feb2c
|
@ -7,7 +7,7 @@
|
||||||
#define toNSButton(x) ((NSButton *) (x))
|
#define toNSButton(x) ((NSButton *) (x))
|
||||||
#define toNSTextField(x) ((NSTextField *) (x))
|
#define toNSTextField(x) ((NSTextField *) (x))
|
||||||
#define toNSView(x) ((NSView *) (x))
|
#define toNSView(x) ((NSView *) (x))
|
||||||
#define toNSPopover(x) ((NSPopover *) (x))
|
#define toNSWindow(x) ((NSWindow *) (x))
|
||||||
#define toNSBox(x) ((NSBox *) (x))
|
#define toNSBox(x) ((NSBox *) (x))
|
||||||
|
|
||||||
@interface goControlDelegate : NSObject <NSTextFieldDelegate> {
|
@interface goControlDelegate : NSObject <NSTextFieldDelegate> {
|
||||||
|
@ -168,18 +168,18 @@ void textFieldSetText(id t, char *text)
|
||||||
|
|
||||||
id textfieldOpenInvalidPopover(id textfield, char *reason)
|
id textfieldOpenInvalidPopover(id textfield, char *reason)
|
||||||
{
|
{
|
||||||
NSPopover *popover;
|
id popover;
|
||||||
|
|
||||||
popover = (NSPopover *) newWarningPopover(reason);
|
popover = newWarningPopover(reason);
|
||||||
[popover showRelativeToRect:NSZeroRect ofView:toNSView(textfield) preferredEdge:NSMaxYEdge];
|
warningPopoverShow(popover, textfield);
|
||||||
NSBeep();
|
NSBeep();
|
||||||
return (id) popover;
|
return (id) popover;
|
||||||
}
|
}
|
||||||
|
|
||||||
void textfieldCloseInvalidPopover(id popover)
|
void textfieldCloseInvalidPopover(id popover)
|
||||||
{
|
{
|
||||||
[toNSPopover(popover) close];
|
[toNSWindow(popover) orderOut:toNSWindow(popover)];
|
||||||
[toNSPopover(popover) release];
|
[toNSWindow(popover) release];
|
||||||
}
|
}
|
||||||
|
|
||||||
id newLabel(void)
|
id newLabel(void)
|
||||||
|
|
|
@ -145,5 +145,6 @@ extern void openFile(id, void *);
|
||||||
|
|
||||||
/* warningpopover_darwin.m */
|
/* warningpopover_darwin.m */
|
||||||
extern id newWarningPopover(char *);
|
extern id newWarningPopover(char *);
|
||||||
|
extern void warningPopoverShow(id, id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -48,7 +48,6 @@ func (t *textfield) OnChanged(f func()) {
|
||||||
|
|
||||||
func (t *textfield) Invalid(reason string) {
|
func (t *textfield) Invalid(reason string) {
|
||||||
// TODO disable animations if reason is still valid
|
// TODO disable animations if reason is still valid
|
||||||
// TODO don't steal focus
|
|
||||||
if t.invalid != nil {
|
if t.invalid != nil {
|
||||||
C.textfieldCloseInvalidPopover(t.invalid)
|
C.textfieldCloseInvalidPopover(t.invalid)
|
||||||
t.invalid = nil
|
t.invalid = nil
|
||||||
|
|
|
@ -3,6 +3,48 @@
|
||||||
#include "objc_darwin.h"
|
#include "objc_darwin.h"
|
||||||
#include <Cocoa/Cocoa.h>
|
#include <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
// We would be able to just use plain old NSPopover here, but alas that steals focus.
|
||||||
|
// NSPopovers are intended for interactive content, and Apple seems to be diligent in enforcing this rule, as the known techniques for preventing a NSPopover from stealing focus no longer work in 10.9.
|
||||||
|
// Let's just fake it with a window.
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// - doesn't get hidden properly when asked to order out
|
||||||
|
// - doesn't get hidden when changing first responders
|
||||||
|
// - doesn't get hidden when switching between programs/shown again
|
||||||
|
// - doesn't animate or have a transparent background; probably should
|
||||||
|
|
||||||
|
@interface goWarningPopover : NSWindow
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation goWarningPopover
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
self = [super initWithContentRect:NSZeroRect
|
||||||
|
styleMask:NSBorderlessWindowMask
|
||||||
|
backing:NSBackingStoreBuffered
|
||||||
|
defer:YES];
|
||||||
|
[self setOpaque:NO];
|
||||||
|
// [self setAlphaValue:0.1];
|
||||||
|
[self setHasShadow:YES];
|
||||||
|
[self setExcludedFromWindowsMenu:YES];
|
||||||
|
[self setMovableByWindowBackground:NO];
|
||||||
|
[self setLevel:NSPopUpMenuWindowLevel];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canBecomeKeyWindow
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canBecomeMainWindow
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@interface goWarningView : NSView {
|
@interface goWarningView : NSView {
|
||||||
@public
|
@public
|
||||||
NSImageView *icon;
|
NSImageView *icon;
|
||||||
|
@ -65,14 +107,24 @@ id newWarningPopover(char *text)
|
||||||
[wv addSubview:wv->label];
|
[wv addSubview:wv->label];
|
||||||
[wv sizeToFitAndArrange];
|
[wv sizeToFitAndArrange];
|
||||||
|
|
||||||
NSPopover *popover;
|
goWarningPopover *popover;
|
||||||
NSViewController *vc;
|
|
||||||
|
|
||||||
vc = [NSViewController new];
|
popover = [[goWarningPopover alloc] init]; // explicitly use our initializer
|
||||||
[vc setView:wv];
|
[[popover contentView] addSubview:wv];
|
||||||
popover = [NSPopover new];
|
|
||||||
[popover setContentViewController:vc];
|
|
||||||
[popover setContentSize:[wv frame].size];
|
[popover setContentSize:[wv frame].size];
|
||||||
|
|
||||||
return (id) popover;
|
return (id) popover;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void warningPopoverShow(id popover, id control)
|
||||||
|
{
|
||||||
|
goWarningPopover *p = (goWarningPopover *) popover;
|
||||||
|
NSView *v = (NSView *) control;
|
||||||
|
NSRect vr;
|
||||||
|
NSPoint vo;
|
||||||
|
|
||||||
|
vr = [v convertRect:[v frame] toView:nil];
|
||||||
|
vo = [[v window] convertRectToScreen:vr].origin;
|
||||||
|
[p setFrameOrigin:NSMakePoint(vo.x, vo.y - [p frame].size.height)];
|
||||||
|
[p orderFront:p];
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue