2015-08-14 21:50:20 -05:00
|
|
|
// 14 august 2015
|
|
|
|
#import "uipriv_darwin.h"
|
|
|
|
|
2015-08-21 16:16:52 -05:00
|
|
|
// Text fields for entering text have no intrinsic width; we'll use the default Interface Builder width for them.
|
|
|
|
#define textfieldWidth 96
|
|
|
|
|
2015-08-21 19:14:50 -05:00
|
|
|
@interface libui_intrinsicWidthNSTextField : NSTextField
|
|
|
|
@end
|
|
|
|
|
2015-08-21 16:16:52 -05:00
|
|
|
@implementation libui_intrinsicWidthNSTextField
|
|
|
|
|
|
|
|
- (NSSize)intrinsicContentSize
|
|
|
|
{
|
|
|
|
NSSize s;
|
|
|
|
|
|
|
|
s = [super intrinsicContentSize];
|
|
|
|
s.width = textfieldWidth;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
2015-08-14 21:50:20 -05:00
|
|
|
|
2016-06-05 19:39:18 -05:00
|
|
|
// TODO does this have one on its own?
|
|
|
|
@interface libui_intrinsicWidthNSSecureTextField : NSSecureTextField
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation libui_intrinsicWidthNSSecureTextField
|
|
|
|
|
|
|
|
- (NSSize)intrinsicContentSize
|
|
|
|
{
|
|
|
|
NSSize s;
|
|
|
|
|
|
|
|
s = [super intrinsicContentSize];
|
|
|
|
s.width = textfieldWidth;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
// TODO does this have one on its own?
|
|
|
|
@interface libui_intrinsicWidthNSSearchField : NSSearchField
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation libui_intrinsicWidthNSSearchField
|
|
|
|
|
|
|
|
- (NSSize)intrinsicContentSize
|
|
|
|
{
|
|
|
|
NSSize s;
|
|
|
|
|
|
|
|
s = [super intrinsicContentSize];
|
|
|
|
s.width = textfieldWidth;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2015-08-14 21:50:20 -05:00
|
|
|
struct uiEntry {
|
|
|
|
uiDarwinControl c;
|
|
|
|
NSTextField *textfield;
|
|
|
|
void (*onChanged)(uiEntry *, void *);
|
|
|
|
void *onChangedData;
|
|
|
|
};
|
|
|
|
|
2016-06-05 19:39:18 -05:00
|
|
|
static BOOL isSearchField(NSTextField *tf)
|
|
|
|
{
|
|
|
|
return [tf isKindOfClass:[NSSearchField class]];
|
|
|
|
}
|
|
|
|
|
2015-08-14 21:50:20 -05:00
|
|
|
@interface entryDelegateClass : NSObject<NSTextFieldDelegate> {
|
2016-01-07 13:41:20 -06:00
|
|
|
struct mapTable *entries;
|
2015-08-14 21:50:20 -05:00
|
|
|
}
|
|
|
|
- (void)controlTextDidChange:(NSNotification *)note;
|
2016-06-05 19:39:18 -05:00
|
|
|
- (IBAction)onSearch:(id)sender;
|
2015-08-14 21:50:20 -05:00
|
|
|
- (void)registerEntry:(uiEntry *)e;
|
|
|
|
- (void)unregisterEntry:(uiEntry *)e;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation entryDelegateClass
|
|
|
|
|
|
|
|
- (id)init
|
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
if (self)
|
2015-08-17 00:29:34 -05:00
|
|
|
self->entries = newMap();
|
2015-08-14 21:50:20 -05:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)dealloc
|
|
|
|
{
|
2016-01-07 13:41:20 -06:00
|
|
|
mapDestroy(self->entries);
|
2015-08-14 21:50:20 -05:00
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)controlTextDidChange:(NSNotification *)note
|
2016-06-05 19:39:18 -05:00
|
|
|
{
|
|
|
|
[self onSearch:[note object]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (IBAction)onSearch:(id)sender
|
2015-08-14 21:50:20 -05:00
|
|
|
{
|
|
|
|
uiEntry *e;
|
|
|
|
|
2016-06-05 19:39:18 -05:00
|
|
|
e = (uiEntry *) mapGet(self->entries, sender);
|
2015-08-14 21:50:20 -05:00
|
|
|
(*(e->onChanged))(e, e->onChangedData);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)registerEntry:(uiEntry *)e
|
|
|
|
{
|
2015-08-17 00:29:34 -05:00
|
|
|
mapSet(self->entries, e->textfield, e);
|
2016-06-05 19:39:18 -05:00
|
|
|
if (isSearchField(e->textfield)) {
|
|
|
|
[e->textfield setTarget:self];
|
|
|
|
[e->textfield setAction:@selector(onSearch:)];
|
|
|
|
} else
|
|
|
|
[e->textfield setDelegate:self];
|
2015-08-14 21:50:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)unregisterEntry:(uiEntry *)e
|
|
|
|
{
|
2016-06-05 19:39:18 -05:00
|
|
|
if (isSearchField(e->textfield))
|
|
|
|
[e->textfield setTarget:nil];
|
|
|
|
else
|
|
|
|
[e->textfield setDelegate:nil];
|
2016-01-07 13:41:20 -06:00
|
|
|
mapDelete(self->entries, e->textfield);
|
2015-08-14 21:50:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
static entryDelegateClass *entryDelegate = nil;
|
|
|
|
|
2016-04-25 10:54:09 -05:00
|
|
|
uiDarwinControlAllDefaultsExceptDestroy(uiEntry, textfield)
|
|
|
|
|
|
|
|
static void uiEntryDestroy(uiControl *c)
|
|
|
|
{
|
2016-04-25 11:52:54 -05:00
|
|
|
uiEntry *e = uiEntry(c);
|
|
|
|
|
|
|
|
[entryDelegate unregisterEntry:e];
|
|
|
|
[e->textfield release];
|
2016-04-25 12:38:17 -05:00
|
|
|
uiFreeControl(uiControl(e));
|
2016-04-25 10:54:09 -05:00
|
|
|
}
|
2015-08-14 21:50:20 -05:00
|
|
|
|
|
|
|
char *uiEntryText(uiEntry *e)
|
|
|
|
{
|
|
|
|
return uiDarwinNSStringToText([e->textfield stringValue]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void uiEntrySetText(uiEntry *e, const char *text)
|
|
|
|
{
|
2018-05-03 21:38:21 -05:00
|
|
|
[e->textfield setStringValue:uiprivToNSString(text)];
|
2015-08-14 21:50:20 -05:00
|
|
|
// don't queue the control for resize; entry sizes are independent of their contents
|
|
|
|
}
|
|
|
|
|
|
|
|
void uiEntryOnChanged(uiEntry *e, void (*f)(uiEntry *, void *), void *data)
|
|
|
|
{
|
|
|
|
e->onChanged = f;
|
|
|
|
e->onChangedData = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
int uiEntryReadOnly(uiEntry *e)
|
|
|
|
{
|
|
|
|
return [e->textfield isEditable] == NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
void uiEntrySetReadOnly(uiEntry *e, int readonly)
|
|
|
|
{
|
|
|
|
BOOL editable;
|
|
|
|
|
|
|
|
editable = YES;
|
|
|
|
if (readonly)
|
|
|
|
editable = NO;
|
|
|
|
[e->textfield setEditable:editable];
|
|
|
|
}
|
|
|
|
|
2015-08-21 19:14:50 -05:00
|
|
|
static void defaultOnChanged(uiEntry *e, void *data)
|
|
|
|
{
|
|
|
|
// do nothing
|
|
|
|
}
|
|
|
|
|
2015-08-14 21:50:20 -05:00
|
|
|
// these are based on interface builder defaults; my comments in the old code weren't very good so I don't really know what talked about what, sorry :/
|
|
|
|
void finishNewTextField(NSTextField *t, BOOL isEntry)
|
|
|
|
{
|
|
|
|
uiDarwinSetControlFont(t, NSRegularControlSize);
|
|
|
|
|
|
|
|
// THE ORDER OF THESE CALLS IS IMPORTANT; CHANGE IT AND THE BORDERS WILL DISAPPEAR
|
|
|
|
[t setBordered:NO];
|
|
|
|
[t setBezelStyle:NSTextFieldSquareBezel];
|
|
|
|
[t setBezeled:isEntry];
|
|
|
|
|
|
|
|
// we don't need to worry about substitutions/autocorrect here; see window_darwin.m for details
|
|
|
|
|
|
|
|
[[t cell] setLineBreakMode:NSLineBreakByClipping];
|
|
|
|
[[t cell] setScrollable:YES];
|
|
|
|
}
|
|
|
|
|
2016-06-05 19:39:18 -05:00
|
|
|
static NSTextField *realNewEditableTextField(Class class)
|
2015-08-16 22:44:23 -05:00
|
|
|
{
|
2015-08-21 19:14:50 -05:00
|
|
|
NSTextField *tf;
|
|
|
|
|
2016-06-05 19:39:18 -05:00
|
|
|
tf = [[class alloc] initWithFrame:NSZeroRect];
|
2015-08-21 19:14:50 -05:00
|
|
|
[tf setSelectable:YES]; // otherwise the setting is masked by the editable default of YES
|
|
|
|
finishNewTextField(tf, YES);
|
|
|
|
return tf;
|
2015-08-16 22:44:23 -05:00
|
|
|
}
|
|
|
|
|
2016-06-05 19:39:18 -05:00
|
|
|
NSTextField *newEditableTextField(void)
|
|
|
|
{
|
|
|
|
return realNewEditableTextField([libui_intrinsicWidthNSTextField class]);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uiEntry *finishNewEntry(Class class)
|
2015-08-14 21:50:20 -05:00
|
|
|
{
|
|
|
|
uiEntry *e;
|
|
|
|
|
2016-04-25 10:54:09 -05:00
|
|
|
uiDarwinNewControl(uiEntry, e);
|
2015-08-14 21:50:20 -05:00
|
|
|
|
2016-06-05 19:39:18 -05:00
|
|
|
e->textfield = realNewEditableTextField(class);
|
2015-08-14 21:50:20 -05:00
|
|
|
|
2015-08-17 11:57:45 -05:00
|
|
|
if (entryDelegate == nil) {
|
2016-05-24 22:17:08 -05:00
|
|
|
entryDelegate = [[entryDelegateClass new] autorelease];
|
2015-08-17 11:57:45 -05:00
|
|
|
[delegates addObject:entryDelegate];
|
|
|
|
}
|
2015-08-14 21:50:20 -05:00
|
|
|
[entryDelegate registerEntry:e];
|
|
|
|
uiEntryOnChanged(e, defaultOnChanged, NULL);
|
|
|
|
|
|
|
|
return e;
|
|
|
|
}
|
2016-06-05 19:39:18 -05:00
|
|
|
|
|
|
|
uiEntry *uiNewEntry(void)
|
|
|
|
{
|
|
|
|
return finishNewEntry([libui_intrinsicWidthNSTextField class]);
|
|
|
|
}
|
|
|
|
|
|
|
|
uiEntry *uiNewPasswordEntry(void)
|
|
|
|
{
|
|
|
|
return finishNewEntry([libui_intrinsicWidthNSSecureTextField class]);
|
|
|
|
}
|
|
|
|
|
|
|
|
uiEntry *uiNewSearchEntry(void)
|
|
|
|
{
|
|
|
|
uiEntry *e;
|
|
|
|
NSSearchField *s;
|
|
|
|
|
|
|
|
e = finishNewEntry([libui_intrinsicWidthNSSearchField class]);
|
|
|
|
s = (NSSearchField *) (e->textfield);
|
2016-06-13 14:15:40 -05:00
|
|
|
// TODO these are only on 10.10
|
|
|
|
// [s setSendsSearchStringImmediately:NO];
|
|
|
|
// [s setSendsWholeSearchString:NO];
|
2016-06-07 13:35:43 -05:00
|
|
|
[s setBordered:NO];
|
|
|
|
[s setBezelStyle:NSTextFieldRoundedBezel];
|
|
|
|
[s setBezeled:YES];
|
2016-06-05 19:39:18 -05:00
|
|
|
return e;
|
|
|
|
}
|