FINAL CUT
foptimove.h
1 /***********************************************************************
2 * foptimove.h - Cursor movement optimization *
3 * *
4 * This file is part of the FINAL CUT widget toolkit *
5 * *
6 * Copyright 2015-2026 Markus Gans *
7 * *
8 * FINAL CUT is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Lesser General Public License as *
10 * published by the Free Software Foundation; either version 3 of *
11 * the License, or (at your option) any later version. *
12 * *
13 * FINAL CUT is distributed in the hope that it will be useful, but *
14 * WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this program. If not, see *
20 * <http://www.gnu.org/licenses/>. *
21 ***********************************************************************/
22 
23 /* Standalone class
24  * ════════════════
25  *
26  * ▕▔▔▔▔▔▔▔▔▔▔▔▏
27  * ▕ FOptiMove ▏
28  * ▕▁▁▁▁▁▁▁▁▁▁▁▏
29  */
30 
31 // The cursor optimization based on ncurses lib_mvcur.c
32 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
33 
34 #ifndef FOPTIMOVE_H
35 #define FOPTIMOVE_H
36 
37 #if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT)
38  #error "Only <final/final.h> can be included directly."
39 #endif
40 
41 #include <cassert>
42 #include <cctype>
43 #include <climits>
44 #include <cstdlib>
45 #include <cstring>
46 #include <iostream>
47 #include <string>
48 
49 #include "final/output/tty/ftermcap.h"
50 #include "final/util/fstring.h"
51 
52 namespace finalcut
53 {
54 
55 //----------------------------------------------------------------------
56 // class FOptiMove
57 //----------------------------------------------------------------------
58 
59 class FOptiMove final
60 {
61  public:
63  {
64  const FTermcap::TermcapString& t_cursor_up;
65  const FTermcap::TermcapString& t_cursor_down;
66  const FTermcap::TermcapString& t_cursor_left;
67  const FTermcap::TermcapString& t_cursor_right;
68  const FTermcap::TermcapString& t_cursor_home;
69  const FTermcap::TermcapString& t_cursor_to_ll;
70  const FTermcap::TermcapString& t_carriage_return;
71  const FTermcap::TermcapString& t_tab;
72  const FTermcap::TermcapString& t_back_tab;
73  };
74 
76  {
77  const FTermcap::TermcapString& t_parm_up_cursor;
78  const FTermcap::TermcapString& t_parm_down_cursor;
79  const FTermcap::TermcapString& t_parm_left_cursor;
80  const FTermcap::TermcapString& t_parm_right_cursor;
81  const FTermcap::TermcapString& t_cursor_address;
82  const FTermcap::TermcapString& t_column_address;
83  const FTermcap::TermcapString& t_row_address;
84  };
85 
86  struct TermEnvEdit
87  {
88  const FTermcap::TermcapString& t_erase_chars;
89  const FTermcap::TermcapString& t_repeat_char;
90  const FTermcap::TermcapString& t_repeat_last_char;
91  const FTermcap::TermcapString& t_clr_bol;
92  const FTermcap::TermcapString& t_clr_eol;
93  };
94 
95  struct TermEnv
96  {
97  TermEnvCursor cursor;
98  TermEnvParamCursor param_cursor;
99  TermEnvEdit edit;
100  int tabstop;
101  bool automatic_left_margin;
102  bool eat_nl_glitch;
103  };
104 
105  // Constructor
106  explicit FOptiMove (int = 0);
107 
108  // Accessors
109  auto getClassName() const -> FString;
110  static auto getInstance() -> FOptiMove&;
111  auto getCursorHomeLength() const noexcept -> uInt;
112  auto getCarriageReturnLength() const noexcept -> uInt;
113  auto getCursorToLLLength() const noexcept -> uInt;
114  auto getTabLength() const noexcept -> uInt;
115  auto getBackTabLength() const noexcept -> uInt;
116  auto getCursorUpLength() const noexcept -> uInt;
117  auto getCursorDownLength() const noexcept -> uInt;
118  auto getCursorLeftLength() const noexcept -> uInt;
119  auto getCursorRightLength() const noexcept -> uInt;
120  auto getCursorAddressLength() const noexcept -> uInt;
121  auto getColumnAddressLength() const noexcept -> uInt;
122  auto getRowAddressLength() const noexcept -> uInt;
123  auto getParmUpCursorLength() const noexcept -> uInt;
124  auto getParmDownCursorLength() const noexcept -> uInt;
125  auto getParmLeftCursorLength() const noexcept -> uInt;
126  auto getParmRightCursorLength() const noexcept -> uInt;
127  auto getEraseCharsLength() const noexcept -> uInt;
128  auto getRepeatCharLength() const noexcept -> uInt;
129  auto getClrBolLength() const noexcept -> uInt;
130  auto getClrEolLength() const noexcept -> uInt;
131 
132  // Mutators
133  void setBaudRate (int);
134  void setTabStop (int);
135  void setTermSize (std::size_t, std::size_t);
136  void setTermEnvironment (const TermEnv&);
137  void set_cursor_home (const FTermcap::TermcapString&);
138  void set_cursor_to_ll (const FTermcap::TermcapString&);
139  void set_carriage_return (const FTermcap::TermcapString&);
140  void set_tabular (const FTermcap::TermcapString&);
141  void set_back_tab (const FTermcap::TermcapString&);
142  void set_cursor_up (const FTermcap::TermcapString&);
143  void set_cursor_down (const FTermcap::TermcapString&);
144  void set_cursor_left (const FTermcap::TermcapString&);
145  void set_cursor_right (const FTermcap::TermcapString&);
146  void set_cursor_address (const FTermcap::TermcapString&);
147  void set_column_address (const FTermcap::TermcapString&);
148  void set_row_address (const FTermcap::TermcapString&);
149  void set_parm_up_cursor (const FTermcap::TermcapString&);
150  void set_parm_down_cursor (const FTermcap::TermcapString&);
151  void set_parm_left_cursor (const FTermcap::TermcapString&);
152  void set_parm_right_cursor (const FTermcap::TermcapString&);
153  void set_erase_chars (const FTermcap::TermcapString&);
154  void set_repeat_char (const FTermcap::TermcapString&);
155  void set_repeat_last_char (const FTermcap::TermcapString&);
156  void set_clr_bol (const FTermcap::TermcapString&);
157  void set_clr_eol (const FTermcap::TermcapString&);
158  void set_auto_left_margin (bool = true) noexcept;
159  void set_eat_newline_glitch (bool = true) noexcept;
160 
161  // Methods
162  void check_boundaries (int&, int&, int&, int&) const noexcept;
163  auto moveCursor (int, int, int, int) -> FTermcap::TermcapString;
164 
165  private:
166  struct Capability
167  {
169  int duration;
170  int length;
171  };
172 
173  struct Cursor
174  {
175  Capability up{};
176  Capability down{};
177  Capability left{};
178  Capability right{};
179  Capability home{};
180  Capability to_ll{};
181  Capability carriage_return{};
182  Capability tab{};
183  Capability back_tab{};
184  };
185 
186  struct ParamCursor
187  {
188  Capability up{};
189  Capability down{};
190  Capability left{};
191  Capability right{};
192  Capability column_address{};
193  Capability row_address{};
194  Capability address{};
195  };
196 
197  struct Edit
198  {
199  Capability erase_chars{};
200  Capability repeat_char{};
201  Capability repeat_last_char{};
202  Capability clr_bol{};
203  Capability clr_eol{};
204  };
205 
206  struct Dimension
207  {
208  std::size_t width{};
209  std::size_t height{};
210  };
211 
212  // Constant
213  static constexpr std::string::size_type BUF_SIZE{512u};
214 
215  // Constants
216  static constexpr int LONG_DURATION{INT_MAX};
217  // value for a long capability waiting time
218  static constexpr int MOVE_LIMIT{7};
219  // maximum character distance to avoid direct cursor addressing
220 
221  // Methods
222  void calculateCharDuration() noexcept;
223  auto capDuration (const FTermcap::TermcapString&, int) const noexcept -> int;
224  auto capDurationToLength (int) const noexcept -> int;
225  auto repeatedAppend (std::string&, const Capability&, int) const -> int;
226  auto relativeMove (std::string&, int, int, int, int) const -> int;
227  auto verticalMove (std::string&, int, int) const -> int;
228  void downMove (std::string&, int&, int, int) const;
229  void upMove (std::string&, int&, int, int) const;
230  auto horizontalMove (std::string&, int, int) const -> int;
231  void moveWithParmRightCursor (std::string&, int&, int) const;
232  void moveWithRightCursor (std::string&, int&, int, int, int) const;
233  void rightMove (std::string&, int&, int, int) const;
234  void moveWithParmLeftCursor (std::string&, int&, int) const;
235  void moveWithLeftCursor (std::string&, int&, int, int, int) const;
236  void leftMove (std::string&, int&, int, int) const;
237 
238  auto isWideMove (int, int, int, int) const noexcept -> bool;
239  auto isMethod0Faster (int&, int, int) -> bool;
240  auto isMethod1Faster (int&, int, int, int, int) -> bool;
241  auto isMethod2Faster (int&, int, int, int) -> bool;
242  auto isMethod3Faster (int&, int, int) -> bool;
243  auto isMethod4Faster (int&, int, int) -> bool;
244  auto isMethod5Faster (int&, int, int, int) -> bool;
245  void moveByMethod (int, int, int, int, int);
246  void moveWithCarriageReturn (int, int, int);
247  void moveWithHome (int, int);
248  void moveWithToLL (int, int);
249  void moveWithCRAndWrapToLeft (int, int, int, int);
250 
251  // Data members
252  Cursor cursor{};
253  ParamCursor parm_cursor{};
254  Edit edit{};
255  Dimension screen{80, 24};
256  int char_duration{1};
257  int baudrate{9600};
258  int tabstop{0};
259  std::string move_buf{};
260  std::string temp_result{};
261  bool automatic_left_margin{false};
262  bool eat_nl_glitch{false};
263 
264  // Friend function
265  friend void printDurations (const FOptiMove&);
266 };
267 
268 
269 // FOptiMove inline functions
270 //----------------------------------------------------------------------
271 inline auto FOptiMove::getClassName() const -> FString
272 { return "FOptiMove"; }
273 
274 //----------------------------------------------------------------------
275 inline auto FOptiMove::getCursorHomeLength() const noexcept -> uInt
276 { return static_cast<uInt>(cursor.home.length); }
277 
278 //----------------------------------------------------------------------
279 inline auto FOptiMove::getCarriageReturnLength() const noexcept -> uInt
280 { return static_cast<uInt>(cursor.carriage_return.length); }
281 
282 //----------------------------------------------------------------------
283 inline auto FOptiMove::getCursorToLLLength() const noexcept -> uInt
284 { return static_cast<uInt>(cursor.to_ll.length); }
285 
286 //----------------------------------------------------------------------
287 inline auto FOptiMove::getTabLength() const noexcept -> uInt
288 { return static_cast<uInt>(cursor.tab.length); }
289 
290 //----------------------------------------------------------------------
291 inline auto FOptiMove::getBackTabLength() const noexcept -> uInt
292 { return static_cast<uInt>(cursor.back_tab.length); }
293 
294 //----------------------------------------------------------------------
295 inline auto FOptiMove::getCursorUpLength() const noexcept -> uInt
296 { return static_cast<uInt>(cursor.up.length); }
297 
298 //----------------------------------------------------------------------
299 inline auto FOptiMove::getCursorDownLength() const noexcept -> uInt
300 { return static_cast<uInt>(cursor.down.length); }
301 
302 //----------------------------------------------------------------------
303 inline auto FOptiMove::getCursorLeftLength() const noexcept -> uInt
304 { return static_cast<uInt>(cursor.left.length); }
305 
306 //----------------------------------------------------------------------
307 inline auto FOptiMove::getCursorRightLength() const noexcept -> uInt
308 { return static_cast<uInt>(cursor.right.length); }
309 
310 //----------------------------------------------------------------------
311 inline auto FOptiMove::getCursorAddressLength() const noexcept -> uInt
312 { return static_cast<uInt>(parm_cursor.address.length); }
313 
314 //----------------------------------------------------------------------
315 inline auto FOptiMove::getColumnAddressLength() const noexcept -> uInt
316 { return static_cast<uInt>(parm_cursor.column_address.length); }
317 
318 //----------------------------------------------------------------------
319 inline auto FOptiMove::getRowAddressLength() const noexcept -> uInt
320 { return static_cast<uInt>(parm_cursor.row_address.length); }
321 
322 //----------------------------------------------------------------------
323 inline auto FOptiMove::getParmUpCursorLength() const noexcept -> uInt
324 { return static_cast<uInt>(parm_cursor.up.length); }
325 
326 //----------------------------------------------------------------------
327 inline auto FOptiMove::getParmDownCursorLength() const noexcept -> uInt
328 { return static_cast<uInt>(parm_cursor.down.length); }
329 
330 //----------------------------------------------------------------------
331 inline auto FOptiMove::getParmLeftCursorLength() const noexcept -> uInt
332 { return static_cast<uInt>(parm_cursor.left.length); }
333 
334 //----------------------------------------------------------------------
335 inline auto FOptiMove::getParmRightCursorLength() const noexcept -> uInt
336 { return static_cast<uInt>(parm_cursor.right.length); }
337 
338 //----------------------------------------------------------------------
339 inline auto FOptiMove::getEraseCharsLength() const noexcept -> uInt
340 { return static_cast<uInt>(edit.erase_chars.length); }
341 
342 //----------------------------------------------------------------------
343 inline auto FOptiMove::getRepeatCharLength() const noexcept -> uInt
344 { return static_cast<uInt>(edit.repeat_char.length); }
345 
346 //----------------------------------------------------------------------
347 inline auto FOptiMove::getClrBolLength() const noexcept -> uInt
348 { return static_cast<uInt>(edit.clr_bol.length); }
349 
350 //----------------------------------------------------------------------
351 inline auto FOptiMove::getClrEolLength() const noexcept -> uInt
352 { return static_cast<uInt>(edit.clr_eol.length); }
353 
354 //----------------------------------------------------------------------
355 inline void FOptiMove::set_auto_left_margin (bool bcap) noexcept
356 { automatic_left_margin = bcap; }
357 
358 //----------------------------------------------------------------------
359 inline void FOptiMove::set_eat_newline_glitch (bool bcap) noexcept
360 { eat_nl_glitch = bcap; }
361 
362 
363 // FOptiMove non-member function forward declaration
364 //----------------------------------------------------------------------
365 void printDurations (const FOptiMove&);
366 
367 } // namespace finalcut
368 
369 #endif // FOPTIMOVE_H
Definition: foptimove.h:75
Definition: ftermcap.h:72
Definition: foptimove.h:95
Definition: foptimove.h:59
Definition: class_template.cpp:25
Definition: foptimove.h:86
Definition: fstring.h:82
Definition: foptimove.h:62