Fcitx
candidatelist.h
1 /*
2  * SPDX-FileCopyrightText: 2016-2016 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 #ifndef _FCITX_CANDIDATELIST_H_
8 #define _FCITX_CANDIDATELIST_H_
9 
10 #include <cstddef>
11 #include <functional>
12 #include <memory>
13 #include <string>
14 #include <utility>
15 #include <vector>
16 #include <fcitx-utils/key.h>
17 #include <fcitx-utils/macros.h>
18 #include <fcitx/candidateaction.h>
19 #include <fcitx/fcitxcore_export.h>
20 #include <fcitx/text.h>
21 #include <span>
22 
23 namespace fcitx {
24 
25 class InputContext;
26 class PageableCandidateList;
27 class BulkCandidateList;
28 class ModifiableCandidateList;
29 class CursorMovableCandidateList;
30 class CursorModifiableCandidateList;
31 class BulkCursorCandidateList;
32 class ActionableCandidateList;
33 class TabbedCandidateList;
34 
35 class CandidateListPrivate;
36 
37 enum class CandidateLayoutHint { NotSet, Vertical, Horizontal };
38 
39 class CandidateWordPrivate;
40 
41 /// Base class of candidate word.
42 class FCITXCORE_EXPORT CandidateWord {
43 public:
44  CandidateWord(Text text = {});
45  virtual ~CandidateWord();
46  /**
47  * Called when candidate is selected by user.
48  *
49  * @param inputContext the associated input context for the candidate.
50  */
51  virtual void select(InputContext *inputContext) const = 0;
52 
53  const Text &text() const;
54  /**
55  * Whether the candidate is only a place holder.
56  *
57  * If candidate is a place holder, it will not be displayed by UI, but it
58  * will still take one place in the candidate list.
59  */
60  bool isPlaceHolder() const;
61  bool hasCustomLabel() const;
62  const Text &customLabel() const;
63  /**
64  * Return comment corresponding to the candidate.
65  *
66  * @return value of comment.
67  * @since 5.1.9
68  */
69  const Text &comment() const;
70  /**
71  * Return text with comment.
72  *
73  * @param separator separator between text and comment.
74  * @return value of comment.
75  * @since 5.1.9
76  */
77  Text textWithComment(std::string separator = " ") const;
78 
79  /**
80  * Whether there should be no space between text and comment.
81  *
82  * This is optional and may not be used if UI doesn't support it.
83  * By default the value is true.
84  *
85  * This doesn't change the behavior of textWithComment. The caller of
86  * textWithComment should check this function and decide whether to add
87  * space or not.
88  *
89  * @return true if there should be space, false otherwise.
90  * @since 5.1.20
91  */
92  bool spaceBetweenComment() const;
93 
94 protected:
95  void setText(Text text);
96  void setPlaceHolder(bool placeHolder);
97  void resetCustomLabel();
98  void setCustomLabel(Text text);
99  void setComment(Text comment);
100  void setSpaceBetweenComment(bool space);
101 
102 private:
103  std::unique_ptr<CandidateWordPrivate> d_ptr;
104  FCITX_DECLARE_PRIVATE(CandidateWord);
105 };
106 
107 // basic stuff
108 class FCITXCORE_EXPORT CandidateList {
109 public:
110  CandidateList();
111  virtual ~CandidateList();
112 
113  virtual const Text &label(int idx) const = 0;
114  virtual const CandidateWord &candidate(int idx) const = 0;
115  virtual int size() const = 0;
116  virtual int cursorIndex() const = 0;
117  virtual CandidateLayoutHint layoutHint() const = 0;
118 
119  bool empty() const;
120 
121  PageableCandidateList *toPageable() const;
122  BulkCandidateList *toBulk() const;
123  ModifiableCandidateList *toModifiable() const;
124  CursorMovableCandidateList *toCursorMovable() const;
125  CursorModifiableCandidateList *toCursorModifiable() const;
126  BulkCursorCandidateList *toBulkCursor() const;
127  ActionableCandidateList *toActionable() const;
128 
129  /**
130  * Cast to TabbedCandidateList if available.
131  *
132  * @return TabbedCandidateList pointer or nullptr.
133  * @since 5.1.20
134  */
135  TabbedCandidateList *toTabbed() const;
136 
137 protected:
138  void setPageable(PageableCandidateList *list);
139  void setBulk(BulkCandidateList *list);
140  void setModifiable(ModifiableCandidateList *list);
141  void setCursorMovable(CursorMovableCandidateList *list);
142  void setCursorModifiable(CursorModifiableCandidateList *list);
143  void setBulkCursor(BulkCursorCandidateList *list);
144  void setActionable(ActionableCandidateList *list);
145 
146  /**
147  * Set the TabbedCandidateList implementation.
148  *
149  * @param list pointer to TabbedCandidateList.
150  * @since 5.1.20
151  */
152  void setTabbed(TabbedCandidateList *list);
153 
154 private:
155  std::unique_ptr<CandidateListPrivate> d_ptr;
156  FCITX_DECLARE_PRIVATE(CandidateList);
157 };
158 
159 // useful for regular input method
160 class FCITXCORE_EXPORT PageableCandidateList {
161 public:
162  // Need for paging
163  virtual bool hasPrev() const = 0;
164  virtual bool hasNext() const = 0;
165  virtual void prev() = 0;
166  virtual void next() = 0;
167 
168  virtual bool usedNextBefore() const = 0;
169 
170  // Following are optional.
171  virtual int totalPages() const { return -1; }
172  virtual int currentPage() const { return -1; }
173  virtual void setPage(int /*unused*/) {}
174 };
175 
176 class FCITXCORE_EXPORT CursorMovableCandidateList {
177 public:
178  virtual void prevCandidate() = 0;
179  virtual void nextCandidate() = 0;
180 };
181 
182 class FCITXCORE_EXPORT CursorModifiableCandidateList {
183 public:
184  virtual void setCursorIndex(int index) = 0;
185 };
186 
187 // useful for virtual keyboard
188 class FCITXCORE_EXPORT BulkCandidateList {
189 public:
190  /**
191  * If idx is out of range, it may raise exception. Catching the exception is
192  * useful to iterate over all candidate list for candidate list has no total
193  * size.
194  */
195  virtual const CandidateWord &candidateFromAll(int idx) const = 0;
196  /**
197  * It's possible for this function to return -1 if the implement has no
198  * clear number how many candidates are available.
199  */
200  virtual int totalSize() const = 0;
201 };
202 
203 // useful for module other than input method
204 class FCITXCORE_EXPORT ModifiableCandidateList : public BulkCandidateList {
205 public:
206  // All index used there are global index
207  virtual void insert(int idx, std::unique_ptr<CandidateWord> word) = 0;
208  virtual void remove(int idx) = 0;
209  virtual void replace(int idx, std::unique_ptr<CandidateWord> word) = 0;
210  virtual void move(int from, int to) = 0;
211 
212  void append(std::unique_ptr<CandidateWord> word) {
213  insert(totalSize(), std::move(word));
214  }
215 
216  template <typename CandidateWordType, typename... Args>
217  void append(Args &&...args) {
218  append(
219  std::make_unique<CandidateWordType>(std::forward<Args>(args)...));
220  }
221 };
222 
223 class FCITXCORE_EXPORT DisplayOnlyCandidateWord : public CandidateWord {
224 public:
225  DisplayOnlyCandidateWord(Text text) : CandidateWord(std::move(text)) {}
226  DisplayOnlyCandidateWord(Text text, Text comment)
227  : CandidateWord(std::move(text)) {
228  setComment(std::move(comment));
229  }
230 
231  void select(InputContext * /*inputContext*/) const override {}
232 };
233 
234 class FCITXCORE_EXPORT BulkCursorCandidateList {
235 public:
236  virtual int globalCursorIndex() const = 0;
237  virtual void setGlobalCursorIndex(int index) = 0;
238 };
239 
240 /**
241  * Interface for trigger actions on candidates.
242  *
243  * @since 5.1.10
244  */
245 class FCITXCORE_EXPORT ActionableCandidateList {
246 public:
247  virtual ~ActionableCandidateList();
248 
249  /**
250  * Check whether this candidate has action.
251  *
252  * This function should be fast and guarantee that candidateActions return a
253  * not empty vector.
254  */
255  virtual bool hasAction(const CandidateWord &candidate) const = 0;
256 
257  /**
258  * Return a list of actions.
259  */
260  virtual std::vector<CandidateAction>
261  candidateActions(const CandidateWord &candidate) const = 0;
262 
263  /**
264  * Trigger the action based on the index returned from candidateActions.
265  */
266  virtual void triggerAction(const CandidateWord &candidate, int id) = 0;
267 };
268 
269 /**
270  * Interface for tab-related actions on candidate list.
271  *
272  * @since 5.1.20
273  */
274 class FCITXCORE_EXPORT TabbedCandidateList {
275 public:
276  virtual ~TabbedCandidateList();
277 
278  /**
279  * Return a list of tab actions.
280  *
281  * From UI perspective, the returned vector is expected to be small (less
282  * than 10). The text should at most be 6 latin-letters or 2 Chinese
283  * characters.
284  *
285  * The return value is only valid at the time the function is called. The
286  * caller should not keep reference.
287  *
288  * The implementatino can choose lazily construct the return value upon
289  * calling the function.
290  *
291  * @return vector of CandidateAction.
292  * @since 5.1.20
293  */
294  virtual std::span<const CandidateAction> tabActions() = 0;
295 
296  /**
297  * Trigger the tab action based on the index returned from tabActions.
298  *
299  * @param id action index.
300  * @since 5.1.20
301  */
302  virtual void triggerTabAction(int id) = 0;
303 };
304 
306 
307 class FCITXCORE_EXPORT DisplayOnlyCandidateList : public CandidateList {
308 public:
311 
312  void setContent(const std::vector<std::string> &content);
313  void setContent(std::vector<Text> content);
314  void setLayoutHint(CandidateLayoutHint hint);
315  void setCursorIndex(int index);
316 
317  // CandidateList
318  const fcitx::Text &label(int idx) const override;
319  const CandidateWord &candidate(int idx) const override;
320  int cursorIndex() const override;
321  int size() const override;
322  CandidateLayoutHint layoutHint() const override;
323 
324 private:
325  std::unique_ptr<DisplayOnlyCandidateListPrivate> d_ptr;
326  FCITX_DECLARE_PRIVATE(DisplayOnlyCandidateList);
327 };
328 
330 
331 enum class CursorPositionAfterPaging { SameAsLast, DonotChange, ResetToFirst };
332 
333 /**
334  * A common simple candidate list that serves most of the purpose.
335  */
336 class FCITXCORE_EXPORT CommonCandidateList : public CandidateList,
337  public PageableCandidateList,
340 public:
343 
344  void clear();
345 
346  /**
347  * Set the label of candidate list.
348  *
349  * The labels less than 10 will be automatically filled with to empty ones
350  * up to 10 to be more error prone.
351  *
352  * @param labels list of labels.
353  *
354  * @since 5.0.4
355  */
356  void setLabels(const std::vector<std::string> &labels = {});
357 
358  /**
359  * Set the label of candidate list by key.
360  *
361  * @param keyList list of selection key
362  */
363  void setSelectionKey(const KeyList &keyList);
364 
365  void setPageSize(int size);
366  int pageSize() const;
367  void setLayoutHint(CandidateLayoutHint hint);
368  void setGlobalCursorIndex(int index);
369  /**
370  * Return Global cursor index.
371  *
372  * -1 means it is not selected.
373  *
374  * @return cursor index.
375  * @since 5.0.4
376  */
377  int globalCursorIndex() const;
378 
379  /**
380  * Set cursor index on current page.
381  *
382  * @param index index on current page;
383  * @since 5.1.9
384  */
385  void setCursorIndex(int index);
386 
387  // CandidateList
388  const fcitx::Text &label(int idx) const override;
389  const CandidateWord &candidate(int idx) const override;
390  int cursorIndex() const override;
391  int size() const override;
392 
393  // PageableCandidateList
394  bool hasPrev() const override;
395  bool hasNext() const override;
396  void prev() override;
397  void next() override;
398 
399  bool usedNextBefore() const override;
400 
401  int totalPages() const override;
402  int currentPage() const override;
403  void setPage(int page) override;
404 
405  CandidateLayoutHint layoutHint() const override;
406 
407  // BulkCandidateList
408  const CandidateWord &candidateFromAll(int idx) const override;
409  int totalSize() const override;
410 
411  // ModifiableCandidateList
412  void insert(int idx, std::unique_ptr<CandidateWord> word) override;
413  void remove(int idx) override;
414  void replace(int idx, std::unique_ptr<CandidateWord> word) override;
415  void move(int from, int to) override;
416 
417  // CursorMovableCandidateList
418  void prevCandidate() override;
419  void nextCandidate() override;
420 
421  // A simple switch to change the behavior of prevCandidate and nextCandidate
422  void setCursorIncludeUnselected(bool);
423  void setCursorKeepInSamePage(bool);
424  void setCursorPositionAfterPaging(CursorPositionAfterPaging afterPaging);
425 
426  /**
427  * Set an optional implementation of actionable candidate list
428  *
429  * @since 5.1.10
430  */
431  void setActionableImpl(std::unique_ptr<ActionableCandidateList> actionable);
432 
433  /**
434  * Set an optional implementation of tabbed candidate list.
435  *
436  * @param tabbed pointer to TabbedCandidateList.
437  * @since 5.1.20
438  */
439  void setTabbedImpl(std::unique_ptr<TabbedCandidateList> tabbed);
440 
441  /**
442  * Set a filter function for the candidate list.
443  *
444  * Any modification to the candidate list may clear the filter, so it's
445  * better to set filter after all modification is done.
446  *
447  * @param filterFunc A function that takes a CandidateWord and returns a
448  * boolean. Only candidates for which the function returns true will be
449  * included.
450  *
451  * @since 5.1.20
452  */
453  void
454  setFilter(const std::function<bool(const CandidateWord &)> &filterFunc);
455 
456  /**
457  * Clear the filter function for the candidate list.
458  *
459  * @since 5.1.20
460  * @see CommonCandidateList::setFilter
461  */
462  void clearFilter();
463 
464  /**
465  * Return the candidate at the specified index, ignore filter.
466  *
467  * @param idx Index of the candidate.
468  * @return Reference to the candidate.
469  * @since 5.1.20
470  */
471  const CandidateWord &originCandidate(size_t idx) const;
472 
473  /**
474  * Return the total number of candidates, ignore filter.
475  *
476  * @return Total number of candidates.
477  * @since 5.1.20
478  * @see totalSize
479  */
480  size_t originSize() const;
481 
482 private:
483  void fixAfterUpdate();
484  void moveCursor(bool prev);
485 
486  std::unique_ptr<CommonCandidateListPrivate> d_ptr;
487  FCITX_DECLARE_PRIVATE(CommonCandidateList);
488 };
489 } // namespace fcitx
490 
491 #endif // _FCITX_CANDIDATELIST_H_
Formatted string commonly used in user interface.
Definition: action.cpp:17
A class represents a formatted string.
Definition: text.h:27
void select(InputContext *) const override
Called when candidate is selected by user.
Interface for tab-related actions on candidate list.
Interface for trigger actions on candidates.
Base class of candidate word.
Definition: candidatelist.h:42
A common simple candidate list that serves most of the purpose.
An input context represents a client of Fcitx.
Definition: inputcontext.h:50
Class to represent a key.