ClangFormat: apply to source, most of intern
[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 #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)
78     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)
154     return;
155   if (prefix_len == 0) {
156     suggestions.selected = suggestions.firstmatch = suggestions.first;
157     suggestions.lastmatch = suggestions.last;
158     return;
159   }
160
161   first = last = NULL;
162   for (match = suggestions.first; match; match = match->next) {
163     cmp = BLI_strncasecmp(prefix, match->name, prefix_len);
164     if (cmp == 0) {
165       if (!first) {
166         first = match;
167         suggestions.top = top;
168       }
169     }
170     else if (cmp < 0) {
171       if (!last) {
172         last = match->prev;
173         break;
174       }
175     }
176     top++;
177   }
178   if (first) {
179     if (!last)
180       last = suggestions.last;
181     suggestions.firstmatch = first;
182     suggestions.lastmatch = last;
183     suggestions.selected = first;
184   }
185   else {
186     suggestions.firstmatch = NULL;
187     suggestions.lastmatch = NULL;
188     suggestions.selected = NULL;
189     suggestions.top = 0;
190   }
191 }
192
193 void texttool_suggest_clear(void)
194 {
195   txttl_free_suggest();
196 }
197
198 SuggItem *texttool_suggest_first(void)
199 {
200   return suggestions.firstmatch;
201 }
202
203 SuggItem *texttool_suggest_last(void)
204 {
205   return suggestions.lastmatch;
206 }
207
208 void texttool_suggest_select(SuggItem *sel)
209 {
210   suggestions.selected = sel;
211 }
212
213 SuggItem *texttool_suggest_selected(void)
214 {
215   return suggestions.selected;
216 }
217
218 int *texttool_suggest_top(void)
219 {
220   return &suggestions.top;
221 }
222
223 /*************************/
224 /* Documentation methods */
225 /*************************/
226
227 void texttool_docs_show(const char *docs)
228 {
229   int len;
230
231   if (!docs)
232     return;
233
234   len = strlen(docs);
235
236   if (documentation) {
237     MEM_freeN(documentation);
238     documentation = NULL;
239   }
240
241   /* Ensure documentation ends with a '\n' */
242   if (docs[len - 1] != '\n') {
243     documentation = MEM_mallocN(len + 2, "Documentation");
244     memcpy(documentation, docs, len);
245     documentation[len++] = '\n';
246   }
247   else {
248     documentation = MEM_mallocN(len + 1, "Documentation");
249     memcpy(documentation, docs, len);
250   }
251   documentation[len] = '\0';
252 }
253
254 char *texttool_docs_get(void)
255 {
256   return documentation;
257 }
258
259 void texttool_docs_clear(void)
260 {
261   txttl_free_docs();
262 }