Implemented TextField.Invalid() on Mac OS X.
This commit is contained in:
parent
35e788aa7f
commit
8b6b8ec06c
|
@ -7,6 +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 toNSBox(x) ((NSBox *) (x))
|
#define toNSBox(x) ((NSBox *) (x))
|
||||||
|
|
||||||
@interface goControlDelegate : NSObject <NSTextFieldDelegate> {
|
@interface goControlDelegate : NSObject <NSTextFieldDelegate> {
|
||||||
|
@ -162,6 +163,54 @@ void textFieldSetText(id t, char *text)
|
||||||
[toNSTextField(t) setStringValue:[NSString stringWithUTF8String:text]];
|
[toNSTextField(t) setStringValue:[NSString stringWithUTF8String:text]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
id textfieldOpenInvalidPopover(id textfield, char *reason)
|
||||||
|
{
|
||||||
|
// step 1: set up the display
|
||||||
|
NSTextField *label;
|
||||||
|
NSTextAttachmentCell *cell;
|
||||||
|
NSTextAttachment *attachment;
|
||||||
|
NSAttributedString *strImage;
|
||||||
|
NSAttributedString *strText;
|
||||||
|
NSFont *font;
|
||||||
|
NSMutableAttributedString *str;
|
||||||
|
|
||||||
|
// method thanks to Anne in http://stackoverflow.com/a/5303517/3408572
|
||||||
|
// TODO improve appearance
|
||||||
|
label = toNSTextField(newLabel());
|
||||||
|
cell = [[NSTextAttachmentCell alloc] initImageCell:[NSImage imageNamed:NSImageNameCaution]];
|
||||||
|
attachment = [NSTextAttachment new];
|
||||||
|
[attachment setAttachmentCell:cell];
|
||||||
|
strImage = [NSAttributedString attributedStringWithAttachment:attachment];
|
||||||
|
font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
|
||||||
|
strText = [[NSAttributedString alloc] initWithString:[NSString stringWithUTF8String:reason] attributes:[[font fontDescriptor] fontAttributes]];
|
||||||
|
str = [[NSMutableAttributedString alloc] initWithAttributedString:strImage];
|
||||||
|
[str appendAttributedString:strText];
|
||||||
|
[label setAttributedStringValue:str];
|
||||||
|
|
||||||
|
// step 2: set up the popover
|
||||||
|
NSPopover *popover;
|
||||||
|
NSViewController *vc;
|
||||||
|
|
||||||
|
vc = [NSViewController new];
|
||||||
|
[vc setView:label];
|
||||||
|
popover = [NSPopover new];
|
||||||
|
[popover setContentViewController:vc];
|
||||||
|
[label sizeToFit];
|
||||||
|
[popover setContentSize:[label frame].size];
|
||||||
|
|
||||||
|
// step 3: show the popover
|
||||||
|
// NSMaxYEdge is the bottom edge when looking (maximum edge in window coordinates)
|
||||||
|
[popover showRelativeToRect:NSZeroRect ofView:toNSView(textfield) preferredEdge:NSMaxYEdge];
|
||||||
|
|
||||||
|
return (id) popover;
|
||||||
|
}
|
||||||
|
|
||||||
|
void textfieldCloseInvalidPopover(id popover)
|
||||||
|
{
|
||||||
|
[toNSPopover(popover) close];
|
||||||
|
[toNSPopover(popover) release];
|
||||||
|
}
|
||||||
|
|
||||||
id newLabel(void)
|
id newLabel(void)
|
||||||
{
|
{
|
||||||
NSTextField *l;
|
NSTextField *l;
|
||||||
|
|
|
@ -71,6 +71,8 @@ extern id newPasswordField(void);
|
||||||
extern void textfieldSetDelegate(id, void *);
|
extern void textfieldSetDelegate(id, void *);
|
||||||
extern const char *textFieldText(id);
|
extern const char *textFieldText(id);
|
||||||
extern void textFieldSetText(id, char *);
|
extern void textFieldSetText(id, char *);
|
||||||
|
extern id textfieldOpenInvalidPopover(id, char *);
|
||||||
|
extern void textfieldCloseInvalidPopover(id);
|
||||||
extern id newLabel(void);
|
extern id newLabel(void);
|
||||||
extern id newGroup(id);
|
extern id newGroup(id);
|
||||||
extern const char *groupText(id);
|
extern const char *groupText(id);
|
||||||
|
|
|
@ -12,6 +12,7 @@ import "C"
|
||||||
type textfield struct {
|
type textfield struct {
|
||||||
_id C.id
|
_id C.id
|
||||||
changed *event
|
changed *event
|
||||||
|
invalid C.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func finishNewTextField(id C.id) *textfield {
|
func finishNewTextField(id C.id) *textfield {
|
||||||
|
@ -24,7 +25,7 @@ func finishNewTextField(id C.id) *textfield {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTextField() *textfield {
|
func newTextField() *textfield {
|
||||||
return finishNewTextField(C.newTextField()
|
return finishNewTextField(C.newTextField())
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPasswordField() *textfield {
|
func newPasswordField() *textfield {
|
||||||
|
@ -46,7 +47,18 @@ func (t *textfield) OnChanged(f func()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *textfield) Invalid(reason string) {
|
func (t *textfield) Invalid(reason string) {
|
||||||
// TODO
|
// TODO disable animations if reason is still valid
|
||||||
|
// TODO don't steal focus
|
||||||
|
if t.invalid != nil {
|
||||||
|
C.textfieldCloseInvalidPopover(t.invalid)
|
||||||
|
t.invalid = nil
|
||||||
|
}
|
||||||
|
if reason == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
creason := C.CString(reason)
|
||||||
|
defer C.free(unsafe.Pointer(creason))
|
||||||
|
t.invalid = C.textfieldOpenInvalidPopover(t._id, creason)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export textfieldChanged
|
//export textfieldChanged
|
||||||
|
|
Loading…
Reference in New Issue