finalcut/src/foptimove.cpp

1147 lines
31 KiB
C++
Raw Normal View History

2017-11-04 07:03:53 +01:00
/***********************************************************************
* foptimove.cpp - Cursor movement optimization *
* *
* This file is part of the Final Cut widget toolkit *
* *
* Copyright 2015-2020 Markus Gans *
2017-11-04 07:03:53 +01:00
* *
* The Final Cut is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public License *
* as published by the Free Software Foundation; either version 3 of *
* the License, or (at your option) any later version. *
* *
* The Final Cut is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this program. If not, see *
* <http://www.gnu.org/licenses/>. *
***********************************************************************/
2015-05-23 13:35:12 +02:00
2017-09-11 03:06:02 +02:00
#include <cstring>
2018-03-28 00:03:57 +02:00
#include "final/fc.h"
#include "final/foptimove.h"
#include "final/ftermcap.h"
2017-09-11 03:06:02 +02:00
namespace finalcut
{
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
// class FOptiMove
//----------------------------------------------------------------------
// constructors and destructor
//----------------------------------------------------------------------
FOptiMove::FOptiMove (int baud)
: baudrate(baud)
2015-05-23 13:35:12 +02:00
{
assert ( baud >= 0 );
2015-05-23 13:35:12 +02:00
calculateCharDuration();
2018-03-28 00:03:57 +02:00
// ANSI set cursor address preset for undefined terminals
2020-04-25 02:32:33 +02:00
set_cursor_address (CSI "%i%p1%d;%p2%dH");
2018-03-28 00:03:57 +02:00
// Set carriage return preset
2020-04-25 02:32:33 +02:00
set_carriage_return ("\r");
2018-03-29 01:27:57 +02:00
// Set cursor down preset
2020-04-25 02:32:33 +02:00
set_cursor_down ("\n");
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
2017-09-11 03:06:02 +02:00
FOptiMove::~FOptiMove() // destructor
2015-09-22 04:18:20 +02:00
{ }
2015-05-23 13:35:12 +02:00
// public methods of FOptiMove
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
void FOptiMove::setBaudRate (int baud)
2015-05-23 13:35:12 +02:00
{
assert ( baud >= 0 );
baudrate = baud;
calculateCharDuration();
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::setTabStop (int t)
2015-05-23 13:35:12 +02:00
{
assert ( t > 0 );
tabstop = t;
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::setTermSize (std::size_t w, std::size_t h)
{
assert ( w > 0 );
assert ( h > 0 );
screen_width = w;
screen_height = h;
}
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
2020-04-13 12:40:11 +02:00
void FOptiMove::setTermEnvironment (const termEnv& term_env)
{
// Set all required termcap values at once
set_cursor_home (term_env.t_cursor_home);
set_cursor_to_ll (term_env.t_cursor_to_ll);
set_carriage_return (term_env.t_carriage_return);
set_tabular (term_env.t_tab);
set_back_tab (term_env.t_back_tab);
set_cursor_up (term_env.t_cursor_up);
set_cursor_down (term_env.t_cursor_down);
set_cursor_left (term_env.t_cursor_left);
set_cursor_right (term_env.t_cursor_right);
set_cursor_address (term_env.t_cursor_address);
set_column_address (term_env.t_column_address);
set_row_address (term_env.t_row_address);
set_parm_up_cursor (term_env.t_parm_up_cursor);
set_parm_down_cursor (term_env.t_parm_down_cursor);
set_parm_left_cursor (term_env.t_parm_left_cursor);
set_parm_right_cursor (term_env.t_parm_right_cursor);
set_erase_chars (term_env.t_erase_chars);
set_repeat_char (term_env.t_repeat_char);
set_clr_bol (term_env.t_clr_bol);
set_clr_eol (term_env.t_clr_eol);
2019-09-08 02:04:24 +02:00
setTabStop (term_env.tabstop);
set_auto_left_margin (term_env.automatic_left_margin);
set_eat_newline_glitch (term_env.eat_nl_glitch);
}
//----------------------------------------------------------------------
void FOptiMove::set_cursor_home (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
F_cursor_home.cap = cap;
F_cursor_home.duration = capDuration (cap, 0);
F_cursor_home.length = capDurationToLength (F_cursor_home.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_cursor_home.cap = nullptr;
F_cursor_home.duration = \
F_cursor_home.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_cursor_to_ll (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
F_cursor_to_ll.cap = cap;
F_cursor_to_ll.duration = capDuration (cap, 0);
F_cursor_to_ll.length = capDurationToLength (F_cursor_to_ll.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_cursor_to_ll.cap = nullptr;
F_cursor_to_ll.duration = \
F_cursor_to_ll.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_carriage_return (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
F_carriage_return.cap = cap;
F_carriage_return.duration = capDuration (cap, 0);
F_carriage_return.length = capDurationToLength (F_carriage_return.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_carriage_return.cap = nullptr;
F_carriage_return.duration = \
F_carriage_return.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_tabular (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
F_tab.cap = cap;
F_tab.duration = capDuration (cap, 0);
F_tab.length = capDurationToLength (F_tab.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_tab.cap = nullptr;
F_tab.duration = \
F_tab.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_back_tab (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
F_back_tab.cap = cap;
F_back_tab.duration = capDuration (cap, 0);
F_back_tab.length = capDurationToLength (F_back_tab.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_back_tab.cap = nullptr;
F_back_tab.duration = \
F_back_tab.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_cursor_up (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
F_cursor_up.cap = cap;
F_cursor_up.duration = capDuration (cap, 0);
F_cursor_up.length = capDurationToLength (F_cursor_up.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_cursor_up.cap = nullptr;
F_cursor_up.duration = \
F_cursor_up.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_cursor_down (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
F_cursor_down.cap = cap;
F_cursor_down.duration = capDuration (cap, 0);
F_cursor_down.length = capDurationToLength (F_cursor_down.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_cursor_down.cap = nullptr;
F_cursor_down.duration = \
F_cursor_down.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_cursor_left (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
F_cursor_left.cap = cap;
F_cursor_left.duration = capDuration (cap, 0);
F_cursor_left.length = capDurationToLength (F_cursor_left.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_cursor_left.cap = nullptr;
F_cursor_left.duration = \
F_cursor_left.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_cursor_right (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
F_cursor_right.cap = cap;
F_cursor_right.duration = capDuration (cap, 0);
F_cursor_right.length = capDurationToLength (F_cursor_right.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_cursor_right.cap = nullptr;
F_cursor_right.duration = \
F_cursor_right.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_cursor_address (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
const char* temp = FTermcap::encodeMotionParameter(cap, 23, 23);
2015-10-01 03:48:58 +02:00
F_cursor_address.cap = cap;
F_cursor_address.duration = capDuration (temp, 1);
F_cursor_address.length = capDurationToLength (F_cursor_address.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_cursor_address.cap = nullptr;
F_cursor_address.duration = \
F_cursor_address.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_column_address (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
const char* temp = FTermcap::encodeParameter(cap, 23);
2015-10-01 03:48:58 +02:00
F_column_address.cap = cap;
F_column_address.duration = capDuration (temp, 1);
F_column_address.length = capDurationToLength (F_column_address.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_column_address.cap = nullptr;
F_column_address.duration = \
F_column_address.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_row_address (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
const char* temp = FTermcap::encodeParameter(cap, 23);
2015-10-01 03:48:58 +02:00
F_row_address.cap = cap;
F_row_address.duration = capDuration (temp, 1);
F_row_address.length = capDurationToLength (F_row_address.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_row_address.cap = nullptr;
F_row_address.duration = \
F_row_address.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_parm_up_cursor (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
const char* temp = FTermcap::encodeParameter(cap, 23);
2015-10-01 03:48:58 +02:00
F_parm_up_cursor.cap = cap;
F_parm_up_cursor.duration = capDuration (temp, 1);
F_parm_up_cursor.length = capDurationToLength (F_parm_up_cursor.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_parm_up_cursor.cap = nullptr;
F_parm_up_cursor.duration = \
F_parm_up_cursor.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_parm_down_cursor (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
const char* temp = FTermcap::encodeParameter(cap, 23);
2015-10-01 03:48:58 +02:00
F_parm_down_cursor.cap = cap;
F_parm_down_cursor.duration = capDuration (temp, 1);
F_parm_down_cursor.length = capDurationToLength (F_parm_down_cursor.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_parm_down_cursor.cap = nullptr;
F_parm_down_cursor.duration = \
F_parm_down_cursor.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_parm_left_cursor (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
const char* temp = FTermcap::encodeParameter(cap, 23);
2015-10-01 03:48:58 +02:00
F_parm_left_cursor.cap = cap;
F_parm_left_cursor.duration = capDuration (temp, 1);
F_parm_left_cursor.length = capDurationToLength (F_parm_left_cursor.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_parm_left_cursor.cap = nullptr;
F_parm_left_cursor.duration = \
F_parm_left_cursor.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FOptiMove::set_parm_right_cursor (const char cap[])
2015-05-23 13:35:12 +02:00
{
2015-10-01 03:48:58 +02:00
if ( cap )
{
const char* temp = FTermcap::encodeParameter(cap, 23);
2015-10-01 03:48:58 +02:00
F_parm_right_cursor.cap = cap;
F_parm_right_cursor.duration = capDuration (temp, 1);
F_parm_right_cursor.length = capDurationToLength (F_parm_right_cursor.duration);
}
else
{
F_parm_right_cursor.cap = nullptr;
F_parm_right_cursor.duration = \
F_parm_right_cursor.length = LONG_DURATION;
}
}
//----------------------------------------------------------------------
void FOptiMove::set_erase_chars (const char cap[])
{
if ( cap )
{
const char* temp = FTermcap::encodeParameter(cap, 23);
F_erase_chars.cap = cap;
F_erase_chars.duration = capDuration (temp, 1);
F_erase_chars.length = capDurationToLength (F_erase_chars.duration);
}
else
{
F_erase_chars.cap = nullptr;
F_erase_chars.duration = \
F_erase_chars.length = LONG_DURATION;
}
}
//----------------------------------------------------------------------
void FOptiMove::set_repeat_char (const char cap[])
{
if ( cap )
{
const char* temp = FTermcap::encodeParameter(cap, ' ', 23);
F_repeat_char.cap = cap;
F_repeat_char.duration = capDuration (temp, 1);
F_repeat_char.length = capDurationToLength (F_repeat_char.duration);
}
else
{
F_repeat_char.cap = nullptr;
F_repeat_char.duration = \
F_repeat_char.length = LONG_DURATION;
}
}
//----------------------------------------------------------------------
void FOptiMove::set_clr_bol (const char cap[])
{
if ( cap )
{
F_clr_bol.cap = cap;
F_clr_bol.duration = capDuration (cap, 0);
F_clr_bol.length = capDurationToLength (F_clr_bol.duration);
}
else
{
F_clr_bol.cap = nullptr;
F_clr_bol.duration = \
F_clr_bol.length = LONG_DURATION;
}
}
//----------------------------------------------------------------------
void FOptiMove::set_clr_eol (const char cap[])
{
if ( cap )
{
F_clr_eol.cap = cap;
F_clr_eol.duration = capDuration (cap, 0);
F_clr_eol.length = capDurationToLength (F_clr_eol.duration);
2015-10-01 03:48:58 +02:00
}
else
{
F_clr_eol.cap = nullptr;
F_clr_eol.duration = \
F_clr_eol.length = LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
}
2018-03-28 00:03:57 +02:00
//----------------------------------------------------------------------
void FOptiMove::check_boundaries ( int& xold, int& yold
, int& xnew, int& ynew )
{
if ( xold < 0 || xold >= int(screen_width) )
2018-03-28 00:03:57 +02:00
xold = -1;
if ( yold < 0 || yold >= int(screen_height) )
2018-03-28 00:03:57 +02:00
yold = -1;
if ( xnew < 0 )
xnew = 0;
if ( ynew < 0 )
ynew = 0;
if ( xnew >= int(screen_width) )
xnew = int(screen_width) - 1;
2018-03-28 00:03:57 +02:00
if ( ynew >= int(screen_height) )
ynew = int(screen_height) - 1;
2018-03-28 00:03:57 +02:00
}
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
const char* FOptiMove::moveCursor (int xold, int yold, int xnew, int ynew)
2015-05-23 13:35:12 +02:00
{
2019-08-25 22:16:00 +02:00
int method{0};
int move_time{LONG_DURATION};
2018-03-28 00:03:57 +02:00
check_boundaries (xold, yold, xnew, ynew);
2015-05-23 13:35:12 +02:00
// Method 0: direct cursor addressing
2020-04-19 20:38:52 +02:00
if ( isMethod0Faster(move_time, xnew, ynew)
&& ( xold < 0
2017-11-26 22:37:18 +01:00
|| yold < 0
2020-04-19 20:38:52 +02:00
|| isWideMove (xold, yold, xnew, ynew) ) )
{
return ( move_time < LONG_DURATION ) ? move_buf : nullptr;
}
// Method 1: local movement
if ( isMethod1Faster(move_time, xold, yold, xnew, ynew) )
method = 1;
// Method 2: carriage-return + local movement
if ( isMethod2Faster(move_time, yold, xnew, ynew) )
method = 2;
// Method 3: home-cursor + local movement
if ( isMethod3Faster(move_time, xnew, ynew) )
method = 3;
// Method 4: home-down + local movement
if ( isMethod4Faster(move_time, xnew, ynew) )
method = 4;
// Method 5: left margin for wrap to right-hand side
if ( isMethod5Faster(move_time, yold, xnew, ynew) )
method = 5;
// Copy the escape sequence for the chosen method in move_buf
moveByMethod (method, xold, yold, xnew, ynew);
if ( move_time < LONG_DURATION )
return move_buf;
else
2020-02-19 21:59:13 +01:00
return nullptr;
2015-05-23 13:35:12 +02:00
}
// private methods of FApplication
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
void FOptiMove::calculateCharDuration()
2015-05-23 13:35:12 +02:00
{
if ( baudrate != 0 )
{
2018-12-26 23:41:49 +01:00
static constexpr int baudbyte = 9; // = 7 bit + 1 parity + 1 stop
char_duration = (baudbyte * 1000 * 10)
/ (baudrate > 0 ? baudrate : 9600); // milliseconds
if ( char_duration <= 0 )
char_duration = 1;
}
else
char_duration = 1;
}
//----------------------------------------------------------------------
2020-04-13 12:40:11 +02:00
int FOptiMove::capDuration (const char cap[], int affcnt)
{
// calculate the duration in milliseconds of a given operation
// cap - the term capability
// affcnt - the number of lines affected
if ( ! cap )
return LONG_DURATION;
2019-08-25 22:16:00 +02:00
float ms{0};
2020-04-13 12:40:11 +02:00
const char* p = cap;
2020-04-13 12:40:11 +02:00
while ( *p )
{
// check for delay with padding character
if ( p[0] == '$' && p[1] == '<' && std::strchr(p, '>') )
{
float num = 0;
2020-04-14 23:46:42 +02:00
p += 2;
2020-04-14 23:46:42 +02:00
while ( *p != '>' )
{
if ( std::isdigit(uChar(*p)) )
num = num * 10 + float(*p - '0');
else if ( *p == '*' )
num *= float(affcnt);
2020-04-13 12:40:11 +02:00
else if ( *p == '.' )
{
2020-04-14 23:46:42 +02:00
p++;
2020-04-13 12:40:11 +02:00
if ( *p != '>' && std::isdigit(uChar(*p)) )
num += float((*p - '0') / 10.0);
}
2020-04-14 23:46:42 +02:00
p++;
}
ms += num * 10;
}
else
ms += float(char_duration);
2020-04-13 12:40:11 +02:00
p++;
}
return int(ms);
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
int FOptiMove::capDurationToLength (int duration)
{
if ( duration != LONG_DURATION )
return (duration + char_duration - 1) / char_duration;
else
return LONG_DURATION;
}
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
int FOptiMove::repeatedAppend ( const capability& o
, volatile int count
, char* dst )
2015-05-23 13:35:12 +02:00
{
const std::size_t src_len = std::strlen(o.cap);
const std::size_t dst_len = ( dst != nullptr ) ? std::strlen(dst) : 0;
2019-08-25 22:16:00 +02:00
int total{0};
2015-05-23 13:35:12 +02:00
2018-01-05 00:49:00 +01:00
if ( (dst_len + uInt(count) * src_len) < BUF_SIZE - 1 )
2015-05-23 13:35:12 +02:00
{
total += count * o.duration;
2015-05-23 13:35:12 +02:00
if ( dst )
{
dst += dst_len;
2019-09-08 02:04:24 +02:00
std::size_t free = BUF_SIZE - dst_len - 2;
2015-05-23 13:35:12 +02:00
while ( count-- > 0 )
{
std::strncpy (dst, o.cap, free);
2015-05-23 13:35:12 +02:00
dst += src_len;
free -= src_len;
2015-05-23 13:35:12 +02:00
}
}
}
else
total = LONG_DURATION;
return total;
}
//----------------------------------------------------------------------
2017-12-19 02:06:27 +01:00
int FOptiMove::relativeMove ( char move[]
, int from_x, int from_y
, int to_x, int to_y )
2015-05-23 13:35:12 +02:00
{
2019-08-25 22:16:00 +02:00
int vtime{0};
int htime{0};
2015-05-23 13:35:12 +02:00
if ( move )
move[0] = '\0';
if ( to_y != from_y ) // vertical move
{
2018-01-03 22:58:07 +01:00
vtime = verticalMove (move, from_y, to_y);
2015-05-23 13:35:12 +02:00
2018-01-03 22:58:07 +01:00
if ( vtime >= LONG_DURATION )
return LONG_DURATION;
}
if ( to_x != from_x ) // horizontal move
{
2019-08-25 22:16:00 +02:00
char hmove[BUF_SIZE]{};
2018-01-03 22:58:07 +01:00
htime = horizontalMove (hmove, from_x, to_x);
if ( htime >= LONG_DURATION )
return LONG_DURATION;
if ( move )
{
if ( *move )
2018-11-07 22:06:58 +01:00
std::strncat (move, hmove, BUF_SIZE - std::strlen(move));
2018-01-03 22:58:07 +01:00
else
2018-11-07 22:06:58 +01:00
std::strncpy (move, hmove, BUF_SIZE);
2018-09-02 00:43:27 +02:00
move[BUF_SIZE - 1] = '\0';
2018-01-03 22:58:07 +01:00
}
}
return vtime + htime;
}
//----------------------------------------------------------------------
inline int FOptiMove::verticalMove (char move[], int from_y, int to_y)
{
2019-08-25 22:16:00 +02:00
int vtime{LONG_DURATION};
2018-01-03 22:58:07 +01:00
if ( F_row_address.cap )
{
if ( move )
{
2018-01-03 22:58:07 +01:00
std::strncpy ( move
, FTermcap::encodeParameter(F_row_address.cap, to_y)
, BUF_SIZE );
move[BUF_SIZE - 1] = '\0';
}
2018-01-03 22:58:07 +01:00
vtime = F_row_address.duration;
}
if ( to_y > from_y )
downMove (move, vtime, from_y, to_y);
else // to_y < from_y
upMove (move, vtime, from_y, to_y);
2018-01-03 22:58:07 +01:00
return vtime;
}
//----------------------------------------------------------------------
inline void FOptiMove::downMove ( char move[], int& vtime
, int from_y, int to_y )
{
const int num = to_y - from_y;
2015-05-23 13:35:12 +02:00
if ( F_parm_down_cursor.cap && F_parm_down_cursor.duration < vtime )
{
if ( move )
{
std::strncpy ( move
, FTermcap::encodeParameter(F_parm_down_cursor.cap, num)
, BUF_SIZE );
move[BUF_SIZE - 1] = '\0';
}
vtime = F_parm_down_cursor.duration;
2018-01-03 22:58:07 +01:00
}
if ( F_cursor_down.cap && (num * F_cursor_down.duration < vtime) )
2018-01-03 22:58:07 +01:00
{
if ( move )
move[0] = '\0';
2015-05-23 13:35:12 +02:00
vtime = repeatedAppend (F_cursor_down, num, move);
}
}
//----------------------------------------------------------------------
inline void FOptiMove::upMove ( char move[], int& vtime
, int from_y, int to_y )
{
const int num = from_y - to_y;
2015-05-23 13:35:12 +02:00
if ( F_parm_up_cursor.cap && F_parm_up_cursor.duration < vtime )
{
if ( move )
{
std::strncpy ( move
, FTermcap::encodeParameter(F_parm_up_cursor.cap, num)
, BUF_SIZE );
move[BUF_SIZE - 1] = '\0';
}
vtime = F_parm_up_cursor.duration;
2018-01-03 22:58:07 +01:00
}
2015-05-23 13:35:12 +02:00
if ( F_cursor_up.cap && (num * F_cursor_up.duration < vtime) )
{
if ( move )
move[0] = '\0';
vtime = repeatedAppend (F_cursor_up, num, move);
}
2018-01-03 22:58:07 +01:00
}
2018-01-03 22:58:07 +01:00
//----------------------------------------------------------------------
inline int FOptiMove::horizontalMove (char hmove[], int from_x, int to_x)
{
2019-08-25 22:16:00 +02:00
int htime{LONG_DURATION};
2015-05-23 13:35:12 +02:00
2018-01-03 22:58:07 +01:00
if ( F_column_address.cap )
{
// Move to fixed column position1
2018-01-03 22:58:07 +01:00
std::strncat ( hmove
, FTermcap::encodeParameter(F_column_address.cap, to_x)
, BUF_SIZE - std::strlen(hmove) - 1 );
hmove[BUF_SIZE - 1] = '\0';
2018-01-03 22:58:07 +01:00
htime = F_column_address.duration;
2015-05-23 13:35:12 +02:00
}
2018-01-03 22:58:07 +01:00
if ( to_x > from_x )
rightMove (hmove, htime, from_x, to_x);
else // to_x < from_x
leftMove (hmove, htime, from_x, to_x);
return htime;
}
//----------------------------------------------------------------------
inline void FOptiMove::rightMove ( char hmove[], int& htime
, int from_x, int to_x )
{
int num = to_x - from_x;
if ( F_parm_right_cursor.cap && F_parm_right_cursor.duration < htime )
2015-05-23 13:35:12 +02:00
{
std::strncpy ( hmove
, FTermcap::encodeParameter(F_parm_right_cursor.cap, num)
2018-12-01 21:28:25 +01:00
, BUF_SIZE - 1);
hmove[BUF_SIZE - 1] = '\0';
htime = F_parm_right_cursor.duration;
}
2015-05-23 13:35:12 +02:00
if ( F_cursor_right.cap )
{
2019-08-25 22:16:00 +02:00
char str[BUF_SIZE]{};
int htime_r{0};
str[0] = '\0';
2015-05-23 13:35:12 +02:00
// try to use tab
if ( tabstop > 0 && F_tab.cap )
2015-05-23 13:35:12 +02:00
{
int pos = from_x;
2015-05-23 13:35:12 +02:00
while ( true )
2015-05-23 13:35:12 +02:00
{
const int tab_pos = pos + tabstop - (pos % tabstop);
2015-05-23 13:35:12 +02:00
if ( tab_pos > to_x )
break;
htime_r += repeatedAppend (F_tab, 1, str);
if ( htime_r >= LONG_DURATION )
break;
pos = tab_pos;
2018-01-03 22:58:07 +01:00
}
2015-05-23 13:35:12 +02:00
num = to_x - pos;
}
2018-01-03 22:58:07 +01:00
htime_r += repeatedAppend (F_cursor_right, num, str);
if ( htime_r < htime )
{
2018-11-07 22:06:58 +01:00
std::strncpy (hmove, str, BUF_SIZE);
2018-09-02 00:43:27 +02:00
hmove[BUF_SIZE - 1] = '\0';
htime = htime_r;
2015-05-23 13:35:12 +02:00
}
2018-01-03 22:58:07 +01:00
}
}
//----------------------------------------------------------------------
inline void FOptiMove::leftMove ( char hmove[], int& htime
, int from_x, int to_x )
{
int num = from_x - to_x;
if ( F_parm_left_cursor.cap && F_parm_left_cursor.duration < htime )
2018-01-03 22:58:07 +01:00
{
std::strncpy ( hmove
, FTermcap::encodeParameter(F_parm_left_cursor.cap, num)
2018-09-24 04:02:35 +02:00
, BUF_SIZE - 1);
hmove[BUF_SIZE - 1] = '\0';
htime = F_parm_left_cursor.duration;
}
2018-01-03 22:58:07 +01:00
if ( F_cursor_left.cap )
{
2019-08-25 22:16:00 +02:00
char str[BUF_SIZE]{};
int htime_l{0};
str[0] = '\0';
2015-05-23 13:35:12 +02:00
// try to use backward tab
if ( tabstop > 0 && F_back_tab.cap )
2018-01-03 22:58:07 +01:00
{
int pos = from_x;
2015-05-23 13:35:12 +02:00
while ( true )
2015-05-23 13:35:12 +02:00
{
const int tab_pos = ( pos > 0 ) ? ((pos - 1) / tabstop) * tabstop : -1;
2015-05-23 13:35:12 +02:00
if ( tab_pos < to_x )
break;
htime_l += repeatedAppend (F_back_tab, 1, str);
if ( htime_l >= LONG_DURATION )
break;
pos = tab_pos;
2015-05-23 13:35:12 +02:00
}
num = pos - to_x;
}
2015-05-23 13:35:12 +02:00
htime_l += repeatedAppend (F_cursor_left, num, str);
if ( htime_l < htime )
{
2018-09-02 00:43:27 +02:00
std::strncpy (hmove, str, BUF_SIZE);
hmove[BUF_SIZE - 1] = '\0';
htime = htime_l;
2015-10-07 02:36:38 +02:00
}
2015-05-23 13:35:12 +02:00
}
}
//----------------------------------------------------------------------
2015-10-10 04:01:22 +02:00
inline bool FOptiMove::isWideMove ( int xold, int yold
, int xnew, int ynew ) const
2015-05-23 13:35:12 +02:00
{
2017-09-11 03:06:02 +02:00
return bool ( xnew > MOVE_LIMIT
&& xnew < int(screen_width) - 1 - MOVE_LIMIT
2017-11-26 22:37:18 +01:00
&& std::abs(xnew - xold) + std::abs(ynew - yold)
> MOVE_LIMIT );
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
inline bool FOptiMove::isMethod0Faster ( int& move_time
, int xnew, int ynew )
{
// Test method 0: direct cursor addressing
const char* move_xy = \
FTermcap::encodeMotionParameter(F_cursor_address.cap, xnew, ynew);
if ( move_xy )
{
std::strncpy ( reinterpret_cast<char*>(move_buf)
, move_xy, BUF_SIZE - 1 );
move_buf[BUF_SIZE - 1] = '\0';
move_time = F_cursor_address.duration;
return true;
}
return false;
}
//----------------------------------------------------------------------
inline bool FOptiMove::isMethod1Faster ( int& move_time
, int xold, int yold
, int xnew, int ynew )
{
// Test method 1: local movement
if ( xold >= 0 && yold >= 0 )
{
2019-09-08 02:04:24 +02:00
char null_result[BUF_SIZE];
const int new_time = relativeMove (null_result, xold, yold, xnew, ynew);
if ( new_time < LONG_DURATION && new_time < move_time )
{
move_time = new_time;
return true;
}
}
return false;
}
//----------------------------------------------------------------------
inline bool FOptiMove::isMethod2Faster ( int& move_time
, int yold
, int xnew, int ynew )
{
// Test method 2: carriage-return + local movement
if ( yold >= 0 && F_carriage_return.cap )
{
2019-09-08 02:04:24 +02:00
char null_result[BUF_SIZE];
const int new_time = relativeMove (null_result, 0, yold, xnew, ynew);
if ( new_time < LONG_DURATION
2017-11-26 22:37:18 +01:00
&& F_carriage_return.duration + new_time < move_time )
{
move_time = F_carriage_return.duration + new_time;
return true;
}
}
return false;
}
//----------------------------------------------------------------------
inline bool FOptiMove::isMethod3Faster ( int& move_time
, int xnew, int ynew )
{
// Test method 3: home-cursor + local movement
if ( F_cursor_home.cap )
{
2019-09-08 02:04:24 +02:00
char null_result[BUF_SIZE];
const int new_time = relativeMove (null_result, 0, 0, xnew, ynew);
if ( new_time < LONG_DURATION
2017-11-26 22:37:18 +01:00
&& F_cursor_home.duration + new_time < move_time )
{
move_time = F_cursor_home.duration + new_time;
return true;
}
}
return false;
}
//----------------------------------------------------------------------
inline bool FOptiMove::isMethod4Faster ( int& move_time
, int xnew, int ynew )
{
// Test method 4: home-down + local movement
if ( F_cursor_to_ll.cap )
{
2019-09-08 02:04:24 +02:00
char null_result[BUF_SIZE];
const int new_time = relativeMove ( null_result
, 0, int(screen_height) - 1
, xnew, ynew );
if ( new_time < LONG_DURATION
2017-11-26 22:37:18 +01:00
&& F_cursor_to_ll.duration + new_time < move_time )
{
move_time = F_cursor_to_ll.duration + new_time;
return true;
}
}
return false;
}
//----------------------------------------------------------------------
inline bool FOptiMove::isMethod5Faster ( int& move_time
, int yold
, int xnew, int ynew )
{
// Test method 5: left margin for wrap to right-hand side
if ( automatic_left_margin
2017-11-26 22:37:18 +01:00
&& ! eat_nl_glitch
&& yold > 0
&& F_cursor_left.cap )
{
2019-09-08 02:04:24 +02:00
char null_result[BUF_SIZE];
const int new_time = relativeMove ( null_result
, int(screen_width) - 1, yold - 1
, xnew, ynew );
if ( new_time < LONG_DURATION
2017-11-26 22:37:18 +01:00
&& F_carriage_return.cap
&& F_carriage_return.duration
+ F_cursor_left.duration + new_time < move_time )
{
move_time = F_carriage_return.duration
+ F_cursor_left.duration + new_time;
2019-09-08 02:04:24 +02:00
return true;
}
}
return false;
}
//----------------------------------------------------------------------
void FOptiMove::moveByMethod ( int method
, int xold, int yold
, int xnew, int ynew )
{
char* move_ptr = move_buf;
switch ( method )
{
case 1:
relativeMove (move_ptr, xold, yold, xnew, ynew);
break;
case 2:
if ( F_carriage_return.cap )
{
2018-09-24 04:02:35 +02:00
std::strncpy (move_ptr, F_carriage_return.cap, BUF_SIZE - 1);
2018-09-18 03:37:44 +02:00
move_ptr[BUF_SIZE - 1] ='\0';
move_ptr += F_carriage_return.length;
relativeMove (move_ptr, 0, yold, xnew, ynew);
}
break;
case 3:
2018-09-24 04:02:35 +02:00
std::strncpy (move_ptr, F_cursor_home.cap, BUF_SIZE - 1);
2018-09-18 03:37:44 +02:00
move_ptr[BUF_SIZE - 1] ='\0';
move_ptr += F_cursor_home.length;
relativeMove (move_ptr, 0, 0, xnew, ynew);
break;
case 4:
2018-09-24 04:02:35 +02:00
std::strncpy (move_ptr, F_cursor_to_ll.cap, BUF_SIZE - 1);
2018-09-18 03:37:44 +02:00
move_ptr[BUF_SIZE - 1] ='\0';
move_ptr += F_cursor_to_ll.length;
relativeMove (move_ptr, 0, int(screen_height) - 1, xnew, ynew);
break;
case 5:
move_buf[0] = '\0';
if ( xold >= 0 )
std::strncat ( move_ptr
, F_carriage_return.cap
2018-10-22 01:26:24 +02:00
, BUF_SIZE - std::strlen(move_ptr) - 1 );
std::strncat ( move_ptr
, F_cursor_left.cap
2018-10-22 01:26:24 +02:00
, BUF_SIZE - std::strlen(move_ptr) - 1);
2018-09-18 03:37:44 +02:00
move_ptr[BUF_SIZE - 1] ='\0';
move_ptr += std::strlen(move_buf);
relativeMove (move_ptr, int(screen_width) - 1, yold - 1, xnew, ynew);
break;
default:
break;
}
}
// FOptiMove non-member function
//----------------------------------------------------------------------
void printDurations (const FOptiMove& om)
{
std::cout << " speed: "
<< om.baudrate << " baud\r\n";
std::cout << " char_duration: "
<< om.char_duration << " ms\r\n";
std::cout << " cursor_home: "
<< om.F_cursor_home.duration << " ms\r\n";
std::cout << " cursor_to_ll: "
<< om.F_cursor_to_ll.duration << " ms\r\n";
std::cout << " carriage_return: "
<< om.F_carriage_return.duration << " ms\r\n";
std::cout << " tab: "
<< om.F_tab.duration << " ms\r\n";
std::cout << " back_tab: "
<< om.F_back_tab.duration << " ms\r\n";
std::cout << " cursor_up: "
<< om.F_cursor_up.duration << " ms\r\n";
std::cout << " cursor_down: "
<< om.F_cursor_down.duration << " ms\r\n";
std::cout << " cursor_left: "
<< om.F_cursor_left.duration << " ms\r\n";
std::cout << " cursor_right: "
<< om.F_cursor_right.duration << " ms\r\n";
std::cout << " cursor_address: "
<< om.F_cursor_address.duration << " ms\r\n";
std::cout << " column_address: "
<< om.F_column_address.duration << " ms\r\n";
std::cout << " row_address: "
<< om.F_row_address.duration << " ms\r\n";
std::cout << " parm_up_cursor: "
<< om.F_parm_up_cursor.duration << " ms\r\n";
std::cout << " parm_down_cursor: "
<< om.F_parm_down_cursor.duration << " ms\r\n";
std::cout << " parm_left_cursor: "
<< om.F_parm_left_cursor.duration << " ms\r\n";
std::cout << "parm_right_cursor: "
<< om.F_parm_right_cursor.duration << " ms\r\n";
}
} // namespace finalcut