27#include <Objectively/String.h>
31#define _Class _TextView
42 free(this->defaultText);
46 release(this->attributedText);
83 $(self,
bind, inlets, dictionary);
100 const char *text = this->attributedText->string.chars;
102 if (text == NULL || strlen(text) == 0) {
104 text = this->defaultText;
111 if (this->text->text) {
112 if (strcmp(text, this->text->text)) {
133 const char *text = this->text->text ?:
"";
136 if (this->position == strlen(text)) {
139 char *chars = calloc(this->position + 1,
sizeof(
char));
140 strncpy(chars, text, this->position);
148 const SDL_Point points[] = {
149 { frame.x + w, frame.y },
150 { frame.x + w, frame.y + h }
157#pragma mark - Control
164 _Bool didEdit =
false, didCaptureEvent =
false;
167 if (this->isEditable) {
168 if (event->type == SDL_MOUSEBUTTONDOWN) {
172 SDL_StartTextInput();
173 if (this->delegate.didBeginEditing) {
174 this->delegate.didBeginEditing(
this);
177 didCaptureEvent =
true;
180 self->state &= ~ControlStateFocused;
182 if (this->delegate.didEndEditing) {
183 this->delegate.didEndEditing(
this);
185 didCaptureEvent =
true;
188 }
else if (event->type == SDL_TEXTINPUT) {
190 if (this->position == this->attributedText->string.length) {
191 $(this->attributedText, appendCharacters, event->text.text);
193 $(this->attributedText, insertCharactersAtIndex, event->text.text, this->position);
195 this->position += strlen(event->text.text);
196 didEdit = didCaptureEvent =
true;
198 }
else if (event->type == SDL_KEYDOWN) {
200 didCaptureEvent =
true;
202 const char *chars = this->attributedText->string.chars;
203 const size_t len = this->attributedText->string.length;
205 switch (event->key.keysym.sym) {
212 self->
state &= ~ControlStateFocused;
214 if (this->delegate.didEndEditing) {
215 this->delegate.didEndEditing(
this);
220 case SDLK_KP_BACKSPACE:
221 if (this->position > 0) {
222 const Range range = { .location = this->position - 1, .length = 1 };
223 $(this->attributedText, deleteCharactersInRange, range);
230 if (this->position < len) {
231 const Range range = { .location = this->position, .length = 1 };
232 $(this->attributedText, deleteCharactersInRange, range);
238 if (SDL_GetModState() & KMOD_CTRL) {
239 while (this->position > 0 && chars[this->position] ==
' ') {
242 while (this->position > 0 && chars[this->position] !=
' ') {
245 }
else if (this->position > 0) {
251 if (SDL_GetModState() & KMOD_CTRL) {
252 while (this->position < len && chars[this->position] ==
' ') {
255 while (this->position < len && chars[this->position] !=
' ') {
258 if (this->position < len) {
261 }
else if (this->position < len) {
271 this->position = len;
275 if (SDL_GetModState() & KMOD_CTRL) {
280 if (SDL_GetModState() & KMOD_CTRL) {
281 this->position = len;
286 if ((SDL_GetModState() & (KMOD_CTRL | KMOD_GUI)) && SDL_HasClipboardText()) {
287 const char *text = SDL_GetClipboardText();
288 if (this->position == len) {
289 $(this->attributedText, appendCharacters, text);
291 $(this->attributedText, insertCharactersAtIndex, text, this->position);
293 this->position += strlen(text);
306 if (this->delegate.didEdit) {
307 this->delegate.didEdit(
this);
312 return didCaptureEvent;
315#pragma mark - TextView
347 if (strcmp(self->
defaultText ?:
"", defaultText ?:
"")) {
361#pragma mark - Class lifecycle
368 ((ObjectInterface *) clazz->interface)->dealloc =
dealloc;
370 ((ViewInterface *) clazz->interface)->applyStyle =
applyStyle;
372 ((ViewInterface *) clazz->interface)->init =
init;
374 ((ViewInterface *) clazz->interface)->render =
render;
376 ((ControlInterface *) clazz->interface)->captureEvent =
captureEvent;
378 ((TextViewInterface *) clazz->interface)->initWithFrame =
initWithFrame;
379 ((TextViewInterface *) clazz->interface)->setDefaultText =
setDefaultText;
391 clazz = _initialize(&(
const ClassDef) {
395 .interfaceOffset = offsetof(
TextView, interface),
396 .interfaceSize =
sizeof(TextViewInterface),
static void dealloc(Object *self)
static void initialize(Class *clazz)
A Control for presenting and capturing user-provied Text.
#define MakeInlets(...)
Creates a null-termianted array of Inlets.
#define MakeInlet(name, type, dest, data)
Creates an Inlet with the specified parameters.
Box * initWithFrame(Box *self, const SDL_Rect *frame)
Initializes this Box with the given frame.
CollectionView * init(CollectionView *self, const SDL_Rect *frame)
Initializes this CollectionView with the specified frame and style.
Controls are Views which capture events and dispatch Actions.
_Bool captureEvent(Control *self, const SDL_Event *event)
Captures a given event, potentially altering the state of this Control.
Class * _Control(void)
The Control archetype.
unsigned int state
The bit mask of ControlState.
_Bool isFocused(const Control *self)
void sizeCharacters(const Font *self, const char *chars, int *w, int *h)
Inlets enable inbound data binding of View attributes through JSON.
Label * initWithText(Label *self, const char *text, Font *font)
Initializes this Label with the given text and Font.
The Renderer is responsible for rasterizing the View hierarchy of a WindowController.
void drawLine(const Renderer *self, const SDL_Point *points)
Draws a line segment between two points using GL_LINE_STRIP.
Text rendered with TrueType fonts.
void setText(Text *self, const char *text)
Sets this Text's text.
A Control for presenting and capturing user-provied Text.
MutableString * attributedText
The user-provided text.
void setDefaultText(TextView *self, const char *defaultText)
Sets the default text for this TextView.
char * defaultText
The default text, displayed when no user-provided text is available.
_Bool isEditable
True if this TextView supports editing, false otherwise.
Control control
The superclass.
Class * _TextView(void)
The TextView archetype.
Views are the fundamental building blocks of ObjectivelyMVC user interfaces.
_Bool bind(View *self, const Inlet *inlets, const Dictionary *dictionary)
Performs data binding for the Inlets described in dictionary.
_Bool clipsSubviews
If true, subviews will be clipped to this View's frame.
_Bool needsLayout
If true, this View will layout its subviews before it is drawn.
void addSubview(View *self, View *subview)
Adds a subview to this view, to be drawn above its siblings.
void applyStyle(View *self, const Style *style)
Applies the given Style to this View.
_Bool didReceiveEvent(const View *self, const SDL_Event *event)
void awakeWithDictionary(View *self, const Dictionary *dictionary)
Wakes this View with the specified Dictionary.
SDL_Rect renderFrame(const View *self)
layoutSubviews(View *self)
Performs layout for this View's immediate subviews.
void render(View *self, Renderer *renderer)
Renders this View using the given renderer.