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