1 /***************************************************************************
2  *   Copyright (C) 2011~2012 by CSSlayer                                   *
3  *   wengxt@gmail.com                                                      *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
19  ***************************************************************************/
20 
21 #include "candidate-internal.h"
22 
23 static const UT_icd cand_icd = {
24     sizeof(FcitxCandidateWord), NULL, NULL, FcitxCandidateWordFree
25 };
26 
27 FCITX_EXPORT_API
FcitxCandidateWordNewList()28 FcitxCandidateWordList* FcitxCandidateWordNewList()
29 {
30     FcitxCandidateWordList* candList = fcitx_utils_new(FcitxCandidateWordList);
31 
32     utarray_init(&candList->candWords, &cand_icd);
33     utarray_reserve(&candList->candWords, 128);
34     candList->wordPerPage = 5; /* anyway put a default value for safety */
35     candList->layoutHint = CLH_NotSet;
36     strncpy(candList->strChoose, DIGIT_STR_CHOOSE, MAX_CAND_WORD);
37 
38     return candList;
39 }
40 
41 FCITX_EXPORT_API
FcitxCandidateWordFreeList(FcitxCandidateWordList * list)42 void FcitxCandidateWordFreeList(FcitxCandidateWordList* list)
43 {
44     utarray_done(&list->candWords);
45     free(list);
46 }
47 
48 FCITX_EXPORT_API
FcitxCandidateWordInsert(FcitxCandidateWordList * candList,FcitxCandidateWord * candWord,int position)49 void FcitxCandidateWordInsert(FcitxCandidateWordList* candList,
50                               FcitxCandidateWord* candWord, int position)
51 {
52     fcitx_array_insert(&candList->candWords, candWord, position);
53 }
54 
55 FCITX_EXPORT_API
56 void
FcitxCandidateWordMerge(FcitxCandidateWordList * candList,FcitxCandidateWordList * newList,int position)57 FcitxCandidateWordMerge(FcitxCandidateWordList* candList,
58                         FcitxCandidateWordList* newList, int position)
59 {
60     void *p;
61     if (!newList)
62         return;
63     if (position >= 0) {
64         fcitx_array_inserta(&candList->candWords, &newList->candWords,
65                             position);
66     } else {
67         utarray_concat(&candList->candWords, &newList->candWords);
68     }
69     utarray_steal(&newList->candWords, p);
70     newList->currentPage = 0;
71     free(p);
72 }
73 
DummyHandler(void * arg,FcitxCandidateWord * candWord)74 INPUT_RETURN_VALUE DummyHandler(void* arg, FcitxCandidateWord* candWord)
75 {
76     FCITX_UNUSED(arg);
77     FCITX_UNUSED(candWord);
78     return IRV_DO_NOTHING;
79 }
80 
81 FCITX_EXPORT_API
FcitxCandidateWordInsertPlaceHolder(FcitxCandidateWordList * candList,int position)82 void FcitxCandidateWordInsertPlaceHolder(FcitxCandidateWordList* candList,
83                                          int position)
84 {
85     FcitxCandidateWord candWord;
86     memset(&candWord, 0, sizeof(FcitxCandidateWord));
87     candWord.callback = DummyHandler;
88     fcitx_array_insert(&candList->candWords, &candWord, position);
89 }
90 
91 FCITX_EXPORT_API
FcitxCandidateWordMove(FcitxCandidateWordList * candList,int from,int to)92 void FcitxCandidateWordMove(FcitxCandidateWordList* candList, int from, int to)
93 {
94     fcitx_array_move(&candList->candWords, from, to);
95 }
96 
97 FCITX_EXPORT_API void
FcitxCandidateWordMoveByWord(FcitxCandidateWordList * candList,FcitxCandidateWord * candWord,int to)98 FcitxCandidateWordMoveByWord(FcitxCandidateWordList *candList,
99                              FcitxCandidateWord *candWord, int to)
100 {
101     int from = utarray_eltidx(&candList->candWords, candWord);
102     FcitxCandidateWordMove(candList, from, to);
103 }
104 
105 FCITX_EXPORT_API void
FcitxCandidateWordRemoveByIndex(FcitxCandidateWordList * candList,int idx)106 FcitxCandidateWordRemoveByIndex(FcitxCandidateWordList *candList, int idx)
107 {
108     fcitx_array_erase(&candList->candWords, idx, 1);
109 }
110 
111 FCITX_EXPORT_API void
FcitxCandidateWordRemove(FcitxCandidateWordList * candList,FcitxCandidateWord * candWord)112 FcitxCandidateWordRemove(FcitxCandidateWordList *candList,
113                          FcitxCandidateWord *candWord)
114 {
115     int idx = utarray_eltidx(&candList->candWords, candWord);
116     FcitxCandidateWordRemoveByIndex(candList, idx);
117 }
118 
119 FCITX_EXPORT_API void
FcitxCandidateWordSetPage(FcitxCandidateWordList * candList,int index)120 FcitxCandidateWordSetPage(FcitxCandidateWordList *candList, int index)
121 {
122     if (index >= 0 && index < FcitxCandidateWordPageCount(candList)) {
123         candList->currentPage = index;
124     }
125 }
126 
127 FCITX_EXPORT_API void
FcitxCandidateWordSetFocus(FcitxCandidateWordList * candList,int index)128 FcitxCandidateWordSetFocus(FcitxCandidateWordList* candList, int index)
129 {
130     FcitxCandidateWordSetPage(candList, index / candList->wordPerPage);
131 }
132 
133 FCITX_EXPORT_API
FcitxCandidateWordReset(FcitxCandidateWordList * candList)134 void FcitxCandidateWordReset(FcitxCandidateWordList* candList)
135 {
136     utarray_clear(&candList->candWords);
137     if (candList->override) {
138         candList->override = false;
139         candList->hasPrev = false;
140         candList->hasNext = false;
141         candList->paging = NULL;
142         if (candList->overrideDestroyNotify)
143             candList->overrideDestroyNotify(candList->overrideArg);
144         candList->overrideArg = NULL;
145         candList->overrideDestroyNotify = NULL;
146     }
147     candList->overrideHighlight = false;
148     candList->overrideHighlightValue = false;
149     candList->currentPage = 0;
150     candList->hasGonePrevPage = false;
151     candList->hasGoneNextPage = false;
152     candList->layoutHint = CLH_NotSet;
153 }
154 
155 FCITX_EXPORT_API
FcitxCandidateWordGetCurrentIndex(FcitxCandidateWordList * candList)156 int FcitxCandidateWordGetCurrentIndex(FcitxCandidateWordList* candList)
157 {
158     return candList->currentPage * candList->wordPerPage;
159 }
160 
161 FCITX_EXPORT_API FcitxCandidateWord*
FcitxCandidateWordGetCurrentWindow(FcitxCandidateWordList * candList)162 FcitxCandidateWordGetCurrentWindow(FcitxCandidateWordList* candList)
163 {
164     return FcitxCandidateWordGetByTotalIndex(
165         candList, candList->currentPage * candList->wordPerPage);
166 }
167 
168 FCITX_EXPORT_API FcitxCandidateWord*
FcitxCandidateWordGetCurrentWindowNext(FcitxCandidateWordList * candList,FcitxCandidateWord * candWord)169 FcitxCandidateWordGetCurrentWindowNext(FcitxCandidateWordList* candList,
170                                        FcitxCandidateWord* candWord)
171 {
172     FcitxCandidateWord *nextCandWord = (FcitxCandidateWord*)utarray_next(&candList->candWords, candWord);
173     if (nextCandWord == NULL)
174         return NULL;
175     FcitxCandidateWord *startCandWord = FcitxCandidateWordGetCurrentWindow(candList);
176     if (nextCandWord < startCandWord ||
177         nextCandWord >= startCandWord + candList->wordPerPage)
178         return NULL;
179     return nextCandWord;
180 }
181 
182 FCITX_EXPORT_API FcitxCandidateWord*
FcitxCandidateWordGetCurrentWindowPrev(FcitxCandidateWordList * candList,FcitxCandidateWord * candWord)183 FcitxCandidateWordGetCurrentWindowPrev(FcitxCandidateWordList* candList,
184                                        FcitxCandidateWord* candWord)
185 {
186     FcitxCandidateWord *prevWord = utarray_prev(&candList->candWords, candWord);
187     if (prevWord == NULL)
188         return NULL;
189     FcitxCandidateWord *startWord = FcitxCandidateWordGetCurrentWindow(candList);
190     if (prevWord < startWord ||
191         prevWord >= startWord + candList->wordPerPage)
192         return NULL;
193     return prevWord;
194 }
195 
196 FCITX_EXPORT_API FcitxCandidateWord*
FcitxCandidateWordGetByTotalIndex(FcitxCandidateWordList * candList,int index)197 FcitxCandidateWordGetByTotalIndex(FcitxCandidateWordList* candList, int index)
198 {
199     return fcitx_array_eltptr(&candList->candWords, index);
200 }
201 
202 FCITX_EXPORT_API int
FcitxCandidateWordGetIndex(FcitxCandidateWordList * candList,FcitxCandidateWord * word)203 FcitxCandidateWordGetIndex(FcitxCandidateWordList *candList,
204                            FcitxCandidateWord *word)
205 {
206     return utarray_eltidx(&candList->candWords, word);
207 }
208 
209 FCITX_EXPORT_API FcitxCandidateWord*
FcitxCandidateWordGetByIndex(FcitxCandidateWordList * candList,int index)210 FcitxCandidateWordGetByIndex(FcitxCandidateWordList* candList, int index)
211 {
212     if (index < candList->wordPerPage && index >= 0)
213         return FcitxCandidateWordGetByTotalIndex(
214             candList, candList->currentPage * candList->wordPerPage + index);
215     return NULL;
216 }
217 
218 FCITX_EXPORT_API INPUT_RETURN_VALUE
FcitxCandidateWordChooseByIndex(FcitxCandidateWordList * candList,int index)219 FcitxCandidateWordChooseByIndex(FcitxCandidateWordList* candList, int index)
220 {
221     FcitxCandidateWord* candWord = FcitxCandidateWordGetByIndex(candList, index);
222     if (candWord == NULL) {
223         if (FcitxCandidateWordGetListSize(candList) > 0)
224             return IRV_DO_NOTHING;
225         else
226             return IRV_TO_PROCESS;
227     } else
228         return candWord->callback(candWord->owner, candWord);
229 }
230 
231 FCITX_EXPORT_API
FcitxCandidateWordChooseByTotalIndex(FcitxCandidateWordList * candList,int index)232 INPUT_RETURN_VALUE FcitxCandidateWordChooseByTotalIndex(FcitxCandidateWordList* candList, int index)
233 {
234     FcitxCandidateWord* candWord = FcitxCandidateWordGetByTotalIndex(candList, index);
235     if (candWord == NULL) {
236         if (FcitxCandidateWordGetListSize(candList) > 0)
237             return IRV_DO_NOTHING;
238         else
239             return IRV_TO_PROCESS;
240     } else
241         return candWord->callback(candWord->owner, candWord);
242 }
243 
244 FCITX_EXPORT_API
FcitxCandidateWordHasPrev(FcitxCandidateWordList * candList)245 boolean FcitxCandidateWordHasPrev(FcitxCandidateWordList* candList)
246 {
247     if (candList->override)
248         return candList->hasPrev;
249 
250     if (candList->currentPage > 0)
251         return true;
252     else
253         return false;
254 }
255 
256 FCITX_EXPORT_API
FcitxCandidateWordHasNext(FcitxCandidateWordList * candList)257 boolean FcitxCandidateWordHasNext(FcitxCandidateWordList* candList)
258 {
259     if (candList->override)
260         return candList->hasNext;
261 
262     if (candList->currentPage + 1 < FcitxCandidateWordPageCount(candList))
263         return true;
264     else
265         return false;
266 }
267 
268 FCITX_EXPORT_API int
FcitxCandidateWordPageCount(FcitxCandidateWordList * candList)269 FcitxCandidateWordPageCount(FcitxCandidateWordList* candList)
270 {
271     return (utarray_len(&candList->candWords) + candList->wordPerPage - 1) / candList->wordPerPage;
272 }
273 
274 FCITX_EXPORT_API
FcitxCandidateWordFree(void * arg)275 void FcitxCandidateWordFree(void* arg)
276 {
277     FcitxCandidateWord* candWord = (FcitxCandidateWord*) arg;
278     if (candWord->strWord)
279         free(candWord->strWord);
280     if (candWord->strExtra)
281         free(candWord->strExtra);
282     if (candWord->priv)
283         free(candWord->priv);
284 }
285 
286 FCITX_EXPORT_API
FcitxCandidateWordAppend(FcitxCandidateWordList * candList,FcitxCandidateWord * candWord)287 void FcitxCandidateWordAppend(FcitxCandidateWordList* candList, FcitxCandidateWord* candWord)
288 {
289     utarray_push_back(&candList->candWords, candWord);
290 }
291 
292 FCITX_EXPORT_API
FcitxCandidateWordGoPrevPage(FcitxCandidateWordList * candList)293 boolean FcitxCandidateWordGoPrevPage(FcitxCandidateWordList* candList)
294 {
295     if (candList->override) {
296         if (candList->paging) {
297             return candList->paging(candList->overrideArg, true);
298         } else {
299             return true;
300         }
301     }
302 
303     if (!FcitxCandidateWordPageCount(candList))
304         return false;
305     if (FcitxCandidateWordHasPrev(candList)) {
306         candList->currentPage -- ;
307         candList->hasGonePrevPage = true;
308         return true;
309     }
310     return false;
311 }
312 
313 FCITX_EXPORT_API
FcitxCandidateWordGoNextPage(FcitxCandidateWordList * candList)314 boolean FcitxCandidateWordGoNextPage(FcitxCandidateWordList* candList)
315 {
316     if (candList->override) {
317         if (candList->paging) {
318             return candList->paging(candList->overrideArg, false);
319         } else {
320             return true;
321         }
322     }
323 
324     if (!FcitxCandidateWordPageCount(candList))
325         return false;
326     if (FcitxCandidateWordHasNext(candList)) {
327         candList->currentPage ++ ;
328         candList->hasGoneNextPage = true;
329         return true;
330     }
331     return false;
332 }
333 
334 FCITX_EXPORT_API
FcitxCandidateWordSetChoose(FcitxCandidateWordList * candList,const char * strChoose)335 void FcitxCandidateWordSetChoose(FcitxCandidateWordList* candList, const char* strChoose)
336 {
337     FcitxCandidateWordSetChooseAndModifier(candList, strChoose, FcitxKeyState_None);
338 }
339 
340 FCITX_EXPORT_API
FcitxCandidateWordSetChooseAndModifier(FcitxCandidateWordList * candList,const char * strChoose,unsigned int state)341 void FcitxCandidateWordSetChooseAndModifier(FcitxCandidateWordList* candList, const char* strChoose, unsigned int state)
342 {
343     strncpy(candList->strChoose, strChoose, MAX_CAND_WORD);
344     candList->candiateModifier = state;
345 }
346 
347 FCITX_EXPORT_API
FcitxCandidateWordGetModifier(FcitxCandidateWordList * candList)348 unsigned int FcitxCandidateWordGetModifier(FcitxCandidateWordList* candList)
349 {
350     return candList->candiateModifier;
351 }
352 
353 FCITX_EXPORT_API
FcitxCandidateWordGetChoose(FcitxCandidateWordList * candList)354 const char* FcitxCandidateWordGetChoose(FcitxCandidateWordList* candList)
355 {
356     return candList->strChoose;
357 }
358 
359 FCITX_EXPORT_API
FcitxCandidateWordGetCurrentPage(FcitxCandidateWordList * candList)360 int FcitxCandidateWordGetCurrentPage(FcitxCandidateWordList* candList)
361 {
362     return candList->currentPage;
363 }
364 
365 FCITX_EXPORT_API
FcitxCandidateWordResize(FcitxCandidateWordList * candList,int length)366 void FcitxCandidateWordResize(FcitxCandidateWordList* candList, int length)
367 {
368     fcitx_array_resize(&candList->candWords, length);
369 }
370 
371 FCITX_EXPORT_API
FcitxCandidateWordGetPageSize(FcitxCandidateWordList * candList)372 int FcitxCandidateWordGetPageSize(FcitxCandidateWordList* candList)
373 {
374     return candList->wordPerPage;
375 }
376 
377 FCITX_EXPORT_API
FcitxCandidateWordSetPageSize(FcitxCandidateWordList * candList,int size)378 void FcitxCandidateWordSetPageSize(FcitxCandidateWordList* candList, int size)
379 {
380     if (size <= 0 || size > 10)
381         size = 5;
382 
383     candList->wordPerPage = size;
384 }
385 
386 FCITX_EXPORT_API
FcitxCandidateWordGetCurrentWindowSize(FcitxCandidateWordList * candList)387 int FcitxCandidateWordGetCurrentWindowSize(FcitxCandidateWordList* candList)
388 {
389     if (utarray_len(&candList->candWords) == 0)
390         return 0;
391     /* last page */
392     if (candList->currentPage + 1 == FcitxCandidateWordPageCount(candList)) {
393         int size = utarray_len(&candList->candWords) % candList->wordPerPage;
394         if (size != 0)
395             return size;
396     }
397     return candList->wordPerPage;
398 }
399 
400 FCITX_EXPORT_API
FcitxCandidateWordGetListSize(FcitxCandidateWordList * candList)401 int FcitxCandidateWordGetListSize(FcitxCandidateWordList* candList)
402 {
403     return utarray_len(&candList->candWords);
404 }
405 
406 FCITX_EXPORT_API
FcitxCandidateWordGetHasGoneToPrevPage(FcitxCandidateWordList * candList)407 boolean FcitxCandidateWordGetHasGoneToPrevPage(FcitxCandidateWordList* candList)
408 {
409     return candList->hasGonePrevPage;
410 }
411 
412 FCITX_EXPORT_API
FcitxCandidateWordGetHasGoneToNextPage(FcitxCandidateWordList * candList)413 boolean FcitxCandidateWordGetHasGoneToNextPage(FcitxCandidateWordList* candList)
414 {
415     return candList->hasGoneNextPage;
416 }
417 
418 FCITX_EXPORT_API
FcitxCandidateWordGetFirst(FcitxCandidateWordList * candList)419 FcitxCandidateWord* FcitxCandidateWordGetFirst(FcitxCandidateWordList* candList)
420 {
421     return (FcitxCandidateWord*)utarray_front(&candList->candWords);
422 }
423 
424 FCITX_EXPORT_API
FcitxCandidateWordGetLast(FcitxCandidateWordList * candList)425 FcitxCandidateWord* FcitxCandidateWordGetLast(FcitxCandidateWordList* candList)
426 {
427     return (FcitxCandidateWord*)utarray_back(&candList->candWords);
428 }
429 
430 FCITX_EXPORT_API
FcitxCandidateWordGetNext(FcitxCandidateWordList * candList,FcitxCandidateWord * candWord)431 FcitxCandidateWord* FcitxCandidateWordGetNext(FcitxCandidateWordList* candList, FcitxCandidateWord* candWord)
432 {
433     return (FcitxCandidateWord*)utarray_next(&candList->candWords, candWord);
434 }
435 
436 FCITX_EXPORT_API FcitxCandidateWord*
FcitxCandidateWordGetPrev(FcitxCandidateWordList * candList,FcitxCandidateWord * candWord)437 FcitxCandidateWordGetPrev(FcitxCandidateWordList *candList,
438                           FcitxCandidateWord *candWord)
439 {
440     return utarray_prev(&candList->candWords, candWord);
441 }
442 
443 FCITX_EXPORT_API
444 int
FcitxCandidateWordCheckChooseKey(FcitxCandidateWordList * candList,FcitxKeySym sym,unsigned int state)445 FcitxCandidateWordCheckChooseKey(FcitxCandidateWordList *candList,
446                                  FcitxKeySym sym, unsigned int state)
447 {
448     return FcitxHotkeyCheckChooseKeyAndModifier(sym, state,
449                                                 candList->strChoose,
450                                                 candList->candiateModifier);
451 }
452 
453 FCITX_EXPORT_API
FcitxCandidateWordGetLayoutHint(FcitxCandidateWordList * candList)454 FcitxCandidateLayoutHint FcitxCandidateWordGetLayoutHint(FcitxCandidateWordList* candList)
455 {
456     return candList->layoutHint;
457 }
458 
459 FCITX_EXPORT_API
FcitxCandidateWordSetLayoutHint(FcitxCandidateWordList * candList,FcitxCandidateLayoutHint hint)460 void FcitxCandidateWordSetLayoutHint(FcitxCandidateWordList* candList, FcitxCandidateLayoutHint hint)
461 {
462     candList->layoutHint = hint;
463 }
464 
465 FCITX_EXPORT_API
FcitxCandidateWordSetOverridePaging(FcitxCandidateWordList * candList,boolean hasPrev,boolean hasNext,FcitxPaging paging,void * arg,FcitxDestroyNotify destroyNotify)466 void FcitxCandidateWordSetOverridePaging(FcitxCandidateWordList* candList, boolean hasPrev, boolean hasNext, FcitxPaging paging, void* arg, FcitxDestroyNotify destroyNotify)
467 {
468     if (candList->override && candList->overrideDestroyNotify) {
469         candList->overrideDestroyNotify(candList->overrideArg);
470     }
471 
472     candList->override = true;
473     candList->hasPrev = hasPrev;
474     candList->hasNext = hasNext;
475     candList->paging = paging;
476     candList->overrideArg = arg;
477     candList->overrideDestroyNotify = destroyNotify;
478 }
479 
480 FCITX_EXPORT_API
FcitxCandidateWordSetOverrideDefaultHighlight(FcitxCandidateWordList * candList,boolean overrideValue)481 void FcitxCandidateWordSetOverrideDefaultHighlight(FcitxCandidateWordList* candList, boolean overrideValue)
482 {
483     candList->overrideHighlight = true;
484     candList->overrideHighlightValue = overrideValue;
485 }
486 
487 FCITX_EXPORT_API FcitxCandidateWord*
FcitxCandidateWordGetFocus(FcitxCandidateWordList * cand_list,boolean clear)488 FcitxCandidateWordGetFocus(FcitxCandidateWordList *cand_list, boolean clear)
489 {
490     FcitxCandidateWord *res = NULL;
491     FcitxCandidateWord *cand_word;
492     for (cand_word = FcitxCandidateWordGetCurrentWindow(cand_list);
493          cand_word;cand_word = FcitxCandidateWordGetCurrentWindowNext(
494              cand_list, cand_word)) {
495         if (FcitxCandidateWordCheckFocus(cand_word, clear)) {
496             res = cand_word;
497         }
498     }
499     if (!res)
500         return FcitxCandidateWordGetCurrentWindow(cand_list);
501     return res;
502 }
503 
504 // kate: indent-mode cstyle; space-indent on; indent-width 0;
505