Cleanup: remove redundant doxygen \file argument
[blender.git] / source / blender / blenkernel / intern / suggestions.c
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 \ingroup bke
21  */
22
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "BLI_string.h"
31
32 #include "DNA_text_types.h"
33 #include "BKE_suggestions.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
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
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
69 void free_texttools(void)
70 {
71         txttl_free_suggest();
72         txttl_free_docs();
73 }
74
75 void texttool_text_set_active(Text *text)
76 {
77         if (activeToolText == text) return;
78         texttool_text_clear();
79         activeToolText = text;
80 }
81
82 void texttool_text_clear(void)
83 {
84         free_texttools();
85         activeToolText = NULL;
86 }
87
88 short texttool_text_is_active(Text *text)
89 {
90         return activeToolText == text ? 1 : 0;
91 }
92
93 /***************************/
94 /* Suggestion list methods */
95 /***************************/
96
97 void texttool_suggest_add(const char *name, char type)
98 {
99         const int len = strlen(name);
100         int cmp;
101         SuggItem *newitem, *item;
102
103         newitem = MEM_mallocN(sizeof(SuggItem) + len + 1, "SuggItem");
104         if (!newitem) {
105                 printf("Failed to allocate memory for suggestion.\n");
106                 return;
107         }
108
109         memcpy(newitem->name, name, len + 1);
110         newitem->type = type;
111         newitem->prev = newitem->next = NULL;
112
113         /* Perform simple linear search for ordered storage */
114         if (!suggestions.first || !suggestions.last) {
115                 suggestions.first = suggestions.last = newitem;
116         }
117         else {
118                 cmp = -1;
119                 for (item = suggestions.last; item; item = item->prev) {
120                         cmp = BLI_strncasecmp(name, item->name, len);
121
122                         /* Newitem comes after this item, insert here */
123                         if (cmp >= 0) {
124                                 newitem->prev = item;
125                                 if (item->next)
126                                         item->next->prev = newitem;
127                                 newitem->next = item->next;
128                                 item->next = newitem;
129
130                                 /* At last item, set last pointer here */
131                                 if (item == suggestions.last)
132                                         suggestions.last = newitem;
133                                 break;
134                         }
135                 }
136                 /* Reached beginning of list, insert before first */
137                 if (cmp < 0) {
138                         newitem->next = suggestions.first;
139                         suggestions.first->prev = newitem;
140                         suggestions.first = newitem;
141                 }
142         }
143         suggestions.firstmatch = suggestions.lastmatch = suggestions.selected = NULL;
144         suggestions.top = 0;
145 }
146
147 void texttool_suggest_prefix(const char *prefix, const int prefix_len)
148 {
149         SuggItem *match, *first, *last;
150         int cmp, top = 0;
151
152         if (!suggestions.first) return;
153         if (prefix_len == 0) {
154                 suggestions.selected = suggestions.firstmatch = suggestions.first;
155                 suggestions.lastmatch = suggestions.last;
156                 return;
157         }
158
159         first = last = NULL;
160         for (match = suggestions.first; match; match = match->next) {
161                 cmp = BLI_strncasecmp(prefix, match->name, prefix_len);
162                 if (cmp == 0) {
163                         if (!first) {
164                                 first = match;
165                                 suggestions.top = top;
166                         }
167                 }
168                 else if (cmp < 0) {
169                         if (!last) {
170                                 last = match->prev;
171                                 break;
172                         }
173                 }
174                 top++;
175         }
176         if (first) {
177                 if (!last) last = suggestions.last;
178                 suggestions.firstmatch = first;
179                 suggestions.lastmatch = last;
180                 suggestions.selected = first;
181         }
182         else {
183                 suggestions.firstmatch = NULL;
184                 suggestions.lastmatch = NULL;
185                 suggestions.selected = NULL;
186                 suggestions.top = 0;
187         }
188 }
189
190 void texttool_suggest_clear(void)
191 {
192         txttl_free_suggest();
193 }
194
195 SuggItem *texttool_suggest_first(void)
196 {
197         return suggestions.firstmatch;
198 }
199
200 SuggItem *texttool_suggest_last(void)
201 {
202         return suggestions.lastmatch;
203 }
204
205 void texttool_suggest_select(SuggItem *sel)
206 {
207         suggestions.selected = sel;
208 }
209
210 SuggItem *texttool_suggest_selected(void)
211 {
212         return suggestions.selected;
213 }
214
215 int *texttool_suggest_top(void)
216 {
217         return &suggestions.top;
218 }
219
220 /*************************/
221 /* Documentation methods */
222 /*************************/
223
224 void texttool_docs_show(const char *docs)
225 {
226         int len;
227
228         if (!docs) return;
229
230         len = strlen(docs);
231
232         if (documentation) {
233                 MEM_freeN(documentation);
234                 documentation = NULL;
235         }
236
237         /* Ensure documentation ends with a '\n' */
238         if (docs[len - 1] != '\n') {
239                 documentation = MEM_mallocN(len + 2, "Documentation");
240                 memcpy(documentation, docs, len);
241                 documentation[len++] = '\n';
242         }
243         else {
244                 documentation = MEM_mallocN(len + 1, "Documentation");
245                 memcpy(documentation, docs, len);
246         }
247         documentation[len] = '\0';
248 }
249
250 char *texttool_docs_get(void)
251 {
252         return documentation;
253 }
254
255 void texttool_docs_clear(void)
256 {
257         txttl_free_docs();
258 }