1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2008, Blender Foundation
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup bke
22 */
23
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "BLI_string.h"
31
32 #include "BKE_text_suggestions.h" /* Own include. */
33 #include "DNA_text_types.h"
34
35 /**********************/
36 /* Static definitions */
37 /**********************/
38
39 static Text *activeToolText = NULL;
40 static SuggList suggestions = {NULL, NULL, NULL, NULL, NULL};
41 static char *documentation = NULL;
42 // static int doc_lines = 0;
43
txttl_free_suggest(void)44 static void txttl_free_suggest(void)
45 {
46 SuggItem *item, *prev;
47 for (item = suggestions.last; item; item = prev) {
48 prev = item->prev;
49 MEM_freeN(item);
50 }
51 suggestions.first = suggestions.last = NULL;
52 suggestions.firstmatch = suggestions.lastmatch = NULL;
53 suggestions.selected = NULL;
54 suggestions.top = 0;
55 }
56
txttl_free_docs(void)57 static void txttl_free_docs(void)
58 {
59 if (documentation) {
60 MEM_freeN(documentation);
61 documentation = NULL;
62 }
63 }
64
65 /**************************/
66 /* General tool functions */
67 /**************************/
68
free_texttools(void)69 void free_texttools(void)
70 {
71 txttl_free_suggest();
72 txttl_free_docs();
73 }
74
texttool_text_set_active(Text * text)75 void texttool_text_set_active(Text *text)
76 {
77 if (activeToolText == text) {
78 return;
79 }
80 texttool_text_clear();
81 activeToolText = text;
82 }
83
texttool_text_clear(void)84 void texttool_text_clear(void)
85 {
86 free_texttools();
87 activeToolText = NULL;
88 }
89
texttool_text_is_active(Text * text)90 short texttool_text_is_active(Text *text)
91 {
92 return activeToolText == text ? 1 : 0;
93 }
94
95 /***************************/
96 /* Suggestion list methods */
97 /***************************/
98
texttool_suggest_add(const char * name,char type)99 void texttool_suggest_add(const char *name, char type)
100 {
101 const int len = strlen(name);
102 int cmp;
103 SuggItem *newitem, *item;
104
105 newitem = MEM_mallocN(sizeof(SuggItem) + len + 1, "SuggItem");
106 if (!newitem) {
107 printf("Failed to allocate memory for suggestion.\n");
108 return;
109 }
110
111 memcpy(newitem->name, name, len + 1);
112 newitem->type = type;
113 newitem->prev = newitem->next = NULL;
114
115 /* Perform simple linear search for ordered storage */
116 if (!suggestions.first || !suggestions.last) {
117 suggestions.first = suggestions.last = newitem;
118 }
119 else {
120 cmp = -1;
121 for (item = suggestions.last; item; item = item->prev) {
122 cmp = BLI_strncasecmp(name, item->name, len);
123
124 /* Newitem comes after this item, insert here */
125 if (cmp >= 0) {
126 newitem->prev = item;
127 if (item->next) {
128 item->next->prev = newitem;
129 }
130 newitem->next = item->next;
131 item->next = newitem;
132
133 /* At last item, set last pointer here */
134 if (item == suggestions.last) {
135 suggestions.last = newitem;
136 }
137 break;
138 }
139 }
140 /* Reached beginning of list, insert before first */
141 if (cmp < 0) {
142 newitem->next = suggestions.first;
143 suggestions.first->prev = newitem;
144 suggestions.first = newitem;
145 }
146 }
147 suggestions.firstmatch = suggestions.lastmatch = suggestions.selected = NULL;
148 suggestions.top = 0;
149 }
150
texttool_suggest_prefix(const char * prefix,const int prefix_len)151 void texttool_suggest_prefix(const char *prefix, const int prefix_len)
152 {
153 SuggItem *match, *first, *last;
154 int cmp, top = 0;
155
156 if (!suggestions.first) {
157 return;
158 }
159 if (prefix_len == 0) {
160 suggestions.selected = suggestions.firstmatch = suggestions.first;
161 suggestions.lastmatch = suggestions.last;
162 return;
163 }
164
165 first = last = NULL;
166 for (match = suggestions.first; match; match = match->next) {
167 cmp = BLI_strncasecmp(prefix, match->name, prefix_len);
168 if (cmp == 0) {
169 if (!first) {
170 first = match;
171 suggestions.top = top;
172 }
173 }
174 else if (cmp < 0) {
175 if (!last) {
176 last = match->prev;
177 break;
178 }
179 }
180 top++;
181 }
182 if (first) {
183 if (!last) {
184 last = suggestions.last;
185 }
186 suggestions.firstmatch = first;
187 suggestions.lastmatch = last;
188 suggestions.selected = first;
189 }
190 else {
191 suggestions.firstmatch = NULL;
192 suggestions.lastmatch = NULL;
193 suggestions.selected = NULL;
194 suggestions.top = 0;
195 }
196 }
197
texttool_suggest_clear(void)198 void texttool_suggest_clear(void)
199 {
200 txttl_free_suggest();
201 }
202
texttool_suggest_first(void)203 SuggItem *texttool_suggest_first(void)
204 {
205 return suggestions.firstmatch;
206 }
207
texttool_suggest_last(void)208 SuggItem *texttool_suggest_last(void)
209 {
210 return suggestions.lastmatch;
211 }
212
texttool_suggest_select(SuggItem * sel)213 void texttool_suggest_select(SuggItem *sel)
214 {
215 suggestions.selected = sel;
216 }
217
texttool_suggest_selected(void)218 SuggItem *texttool_suggest_selected(void)
219 {
220 return suggestions.selected;
221 }
222
texttool_suggest_top(void)223 int *texttool_suggest_top(void)
224 {
225 return &suggestions.top;
226 }
227
228 /*************************/
229 /* Documentation methods */
230 /*************************/
231
texttool_docs_show(const char * docs)232 void texttool_docs_show(const char *docs)
233 {
234 int len;
235
236 if (!docs) {
237 return;
238 }
239
240 len = strlen(docs);
241
242 if (documentation) {
243 MEM_freeN(documentation);
244 documentation = NULL;
245 }
246
247 /* Ensure documentation ends with a '\n' */
248 if (docs[len - 1] != '\n') {
249 documentation = MEM_mallocN(len + 2, "Documentation");
250 memcpy(documentation, docs, len);
251 documentation[len++] = '\n';
252 }
253 else {
254 documentation = MEM_mallocN(len + 1, "Documentation");
255 memcpy(documentation, docs, len);
256 }
257 documentation[len] = '\0';
258 }
259
texttool_docs_get(void)260 char *texttool_docs_get(void)
261 {
262 return documentation;
263 }
264
texttool_docs_clear(void)265 void texttool_docs_clear(void)
266 {
267 txttl_free_docs();
268 }
269