libui/redo/darwin/entry.m

169 lines
3.6 KiB
Objective-C

// 14 august 2015
#import "uipriv_darwin.h"
// Text fields for entering text have no intrinsic width; we'll use the default Interface Builder width for them.
#define textfieldWidth 96
@interface libui_intrinsicWidthNSTextField : NSTextField
@end
@implementation libui_intrinsicWidthNSTextField
- (NSSize)intrinsicContentSize
{
NSSize s;
s = [super intrinsicContentSize];
s.width = textfieldWidth;
return s;
}
@end
struct uiEntry {
uiDarwinControl c;
NSTextField *textfield;
void (*onChanged)(uiEntry *, void *);
void *onChangedData;
};
@interface entryDelegateClass : NSObject<NSTextFieldDelegate> {
NSMapTable *entries;
}
- (void)controlTextDidChange:(NSNotification *)note;
- (void)registerEntry:(uiEntry *)e;
- (void)unregisterEntry:(uiEntry *)e;
@end
@implementation entryDelegateClass
- (id)init
{
self = [super init];
if (self)
self->entries = newMap();
return self;
}
- (void)dealloc
{
if ([self->entries count] != 0)
complain("attempt to destroy shared entry delegate but entries are still registered to it");
[self->entries release];
[super dealloc];
}
- (void)controlTextDidChange:(NSNotification *)note
{
uiEntry *e;
e = (uiEntry *) mapGet(self->entries, [note object]);
(*(e->onChanged))(e, e->onChangedData);
}
- (void)registerEntry:(uiEntry *)e
{
mapSet(self->entries, e->textfield, e);
[e->textfield setDelegate:self];
}
- (void)unregisterEntry:(uiEntry *)e
{
[e->textfield setDelegate:nil];
[self->entries removeObjectForKey:e->textfield];
}
@end
static entryDelegateClass *entryDelegate = nil;
uiDarwinDefineControlWithOnDestroy(
uiEntry, // type name
uiEntryType, // type function
textfield, // handle
[entryDelegate unregisterEntry:this]; // on destroy
)
char *uiEntryText(uiEntry *e)
{
return uiDarwinNSStringToText([e->textfield stringValue]);
}
void uiEntrySetText(uiEntry *e, const char *text)
{
[e->textfield setStringValue:toNSString(text)];
// 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];
}
static void defaultOnChanged(uiEntry *e, void *data)
{
// do nothing
}
// 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];
}
NSTextField *newEditableTextField(void)
{
NSTextField *tf;
tf = [[libui_intrinsicWidthNSTextField alloc] initWithFrame:NSZeroRect];
[tf setSelectable:YES]; // otherwise the setting is masked by the editable default of YES
finishNewTextField(tf, YES);
return tf;
}
uiEntry *uiNewEntry(void)
{
uiEntry *e;
e = (uiEntry *) uiNewControl(uiEntryType());
e->textfield = newEditableTextField();
if (entryDelegate == nil) {
entryDelegate = [entryDelegateClass new];
[delegates addObject:entryDelegate];
}
[entryDelegate registerEntry:e];
uiEntryOnChanged(e, defaultOnChanged, NULL);
uiDarwinFinishNewControl(e, uiEntry);
return e;
}