1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2014 Olaf Wintermann. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #import <stdio.h>
30 #import <stdlib.h>
31 #import <string.h>
32
33 #import "text.h"
34 #import "container.h"
35
36 @implementation TextChangeMgr
37
38 - (TextChangeMgr*)initWithValue:(UiText*)text context:(UiContext*)ctx {
39 value = text;
40 context = ctx;
41 last_length = 0;
42 return self;
43 }
44
45 - (NSUndoManager*)undoManagerForTextView:(NSTextView*)textview {
46 return (NSUndoManager*)value->undomgr;
47 }
48
49 - (NSRange)textView:(NSTextView *)textview
50 willChangeSelectionFromCharacterRange:(NSRange)oldrange
51 toCharacterRange:(NSRange)newrange
52 {
53 if(newrange.length != last_length) {
54 if(newrange.length == 0) {
55 ui_unset_group(context, UI_GROUP_SELECTION);
56 } else {
57 ui_set_group(context, UI_GROUP_SELECTION);
58 }
59 }
60
61 last_length = newrange.length;
62 return newrange;
63 }
64
65 @end
66
67
68 UIWIDGET ui_textarea(UiObject *obj, UiText *value) {
69 UiContainer *ct = uic_get_current_container(obj);
70
71 NSRect frame = ct->getframe(ct);
72
73 NSScrollView *scrollview = [[NSScrollView alloc] initWithFrame:frame];
74 [scrollview setHasVerticalScroller:YES];
75 //[scrollvew setHasHorizontalScroller:YES];
76 [scrollview setBorderType:NSNoBorder];
77 //[scrollview setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
78
79 //frame.size.width = frame.size.width - 15;
80 NSTextView *textview = [[NSTextView alloc]initWithFrame:frame];
81 [textview setAllowsUndo:TRUE];
82 [textview setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
83
84 [textview setFont:[NSFont fontWithName:@"Menlo" size:12]];
85
86 [scrollview setDocumentView:textview];
87
88 ct->add(ct, scrollview);
89
90 // bind value
91 if(value) {
92 value->get = ui_textarea_get;
93 value->set = ui_textarea_set;
94 value->getsubstr = ui_textarea_getsubstr;
95 value->insert = ui_textarea_insert;
96 value->position = ui_textarea_position;
97 value->selection = ui_textarea_selection;
98 value->length = ui_textarea_length;
99 value->value = NULL;
100 value->obj = textview;
101
102 TextChangeMgr *delegate = [[TextChangeMgr alloc]initWithValue:value context:obj->ctx];
103 [textview setDelegate:delegate];
104
105 NSUndoManager *undomgr = [[NSUndoManager alloc]init];
106 value->undomgr = undomgr;
107 }
108
109 return textview;
110 }
111
112 char* ui_textarea_get(UiText *text) {
113 if(text->value) {
114 free(text->value);
115 }
116 NSTextView *textview = (NSTextView*)text->obj;
117 NSString *str = [[textview textStorage]string];
118 size_t length = [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
119 const char *cstr = [str UTF8String];
120 char *value = malloc(length + 1);
121 memcpy(value, cstr, length);
122 value[length] = '\0';
123 text->value = value;
124 return value;
125 }
126
127 void ui_textarea_set(UiText *text, char *str) {
128 if(text->value) {
129 free(text->value);
130 }
131 NSTextView *textview = (NSTextView*)text->obj;
132 NSString *s = [[NSString alloc]initWithUTF8String:str];
133 NSAttributedString *as = [[NSAttributedString alloc]initWithString:s];
134 [[textview textStorage] setAttributedString:as];
135 text->value = NULL;
136 }
137
138 char* ui_textarea_getsubstr(UiText *text, int begin, int end) {
139 if(text->value) {
140 free(text->value);
141 }
142 NSTextView *textview = (NSTextView*)text->obj;
143 NSString *str = [[textview textStorage]string];
144 NSRange range;
145 range.location = begin;
146 range.length = end - begin;
147
148 NSString *substr = [str substringWithRange:range];
149 size_t length = [substr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
150 const char *cstr = [substr UTF8String];
151 char *value = malloc(length + 1);
152 memcpy(value, cstr, length);
153 value[length] = '\0';
154 text->value = value;
155 return value;
156 }
157
158 void ui_textarea_insert(UiText *text, int pos, char *str) {
159 if(text->value) {
160 free(text->value);
161 }
162 NSTextView *textview = (NSTextView*)text->obj;
163 NSString *s = [[NSString alloc]initWithUTF8String:str];
164 NSAttributedString *as = [[NSAttributedString alloc]initWithString:s];
165 [[textview textStorage] insertAttributedString:as atIndex: pos];
166 text->value = NULL;
167 }
168
169 int ui_textarea_position(UiText *text) {
170 return [[[(NSTextView*)text->obj selectedRanges] objectAtIndex:0] rangeValue].location;
171 }
172
173 void ui_textarea_selection(UiText *text, int *begin, int *end) {
174 NSRange range = [[[(NSTextView*)text->obj selectedRanges] objectAtIndex:0] rangeValue];
175 *begin = range.location;
176 *end = range.location + range.length;
177 }
178
179 int ui_textarea_length(UiText *text) {
180 return [[(NSTextView*)text->obj textStorage] length];
181 }
182
183 void ui_text_undo(UiText *text) {
184 [(NSUndoManager*)text->undomgr undo];
185 }
186
187 void ui_text_redo(UiText *text) {
188 [(NSUndoManager*)text->undomgr redo];
189 }
190
191