summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--redo/basicctrls_darwin.m49
-rw-r--r--redo/objc_darwin.h2
-rw-r--r--redo/textfield_darwin.go16
3 files changed, 65 insertions, 2 deletions
diff --git a/redo/basicctrls_darwin.m b/redo/basicctrls_darwin.m
index 8e16eb1..6f2769c 100644
--- a/redo/basicctrls_darwin.m
+++ b/redo/basicctrls_darwin.m
@@ -7,6 +7,7 @@
#define toNSButton(x) ((NSButton *) (x))
#define toNSTextField(x) ((NSTextField *) (x))
#define toNSView(x) ((NSView *) (x))
+#define toNSPopover(x) ((NSPopover *) (x))
#define toNSBox(x) ((NSBox *) (x))
@interface goControlDelegate : NSObject <NSTextFieldDelegate> {
@@ -162,6 +163,54 @@ void textFieldSetText(id t, char *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)
{
NSTextField *l;
diff --git a/redo/objc_darwin.h b/redo/objc_darwin.h
index dca8894..d4a58d0 100644
--- a/redo/objc_darwin.h
+++ b/redo/objc_darwin.h
@@ -71,6 +71,8 @@ extern id newPasswordField(void);
extern void textfieldSetDelegate(id, void *);
extern const char *textFieldText(id);
extern void textFieldSetText(id, char *);
+extern id textfieldOpenInvalidPopover(id, char *);
+extern void textfieldCloseInvalidPopover(id);
extern id newLabel(void);
extern id newGroup(id);
extern const char *groupText(id);
diff --git a/redo/textfield_darwin.go b/redo/textfield_darwin.go
index 1b6ff82..cbe5f8b 100644
--- a/redo/textfield_darwin.go
+++ b/redo/textfield_darwin.go
@@ -12,6 +12,7 @@ import "C"
type textfield struct {
_id C.id
changed *event
+ invalid C.id
}
func finishNewTextField(id C.id) *textfield {
@@ -24,7 +25,7 @@ func finishNewTextField(id C.id) *textfield {
}
func newTextField() *textfield {
- return finishNewTextField(C.newTextField()
+ return finishNewTextField(C.newTextField())
}
func newPasswordField() *textfield {
@@ -46,7 +47,18 @@ func (t *textfield) OnChanged(f func()) {
}
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