2017-11-04 07:03:53 +01:00
|
|
|
|
/***********************************************************************
|
|
|
|
|
* fvterm.cpp - Virtual terminal implementation *
|
|
|
|
|
* *
|
|
|
|
|
* This file is part of the Final Cut widget toolkit *
|
|
|
|
|
* *
|
2019-01-02 03:00:07 +01:00
|
|
|
|
* Copyright 2016-2019 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/>. *
|
|
|
|
|
***********************************************************************/
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-09-11 03:06:02 +02:00
|
|
|
|
#include <queue>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
2017-09-17 21:32:46 +02:00
|
|
|
|
#include "final/fapplication.h"
|
2019-08-04 23:38:47 +02:00
|
|
|
|
#include "final/fc.h"
|
|
|
|
|
#include "final/fcharmap.h"
|
2019-07-21 23:31:21 +02:00
|
|
|
|
#include "final/fcolorpair.h"
|
|
|
|
|
#include "final/fkeyboard.h"
|
|
|
|
|
#include "final/foptiattr.h"
|
|
|
|
|
#include "final/foptimove.h"
|
|
|
|
|
#include "final/fsystem.h"
|
2018-10-29 00:45:45 +01:00
|
|
|
|
#include "final/fterm.h"
|
2019-07-21 23:31:21 +02:00
|
|
|
|
#include "final/ftermdata.h"
|
2019-02-24 00:25:36 +01:00
|
|
|
|
#include "final/ftermbuffer.h"
|
2019-07-21 23:31:21 +02:00
|
|
|
|
#include "final/ftermcap.h"
|
|
|
|
|
#include "final/ftypes.h"
|
2017-09-17 21:32:46 +02:00
|
|
|
|
#include "final/fvterm.h"
|
|
|
|
|
#include "final/fwidget.h"
|
|
|
|
|
#include "final/fwindow.h"
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-09-20 23:59:01 +02:00
|
|
|
|
namespace finalcut
|
|
|
|
|
{
|
|
|
|
|
|
2016-10-11 04:57:36 +02:00
|
|
|
|
// global FVTerm object
|
2019-08-25 22:16:00 +02:00
|
|
|
|
static FVTerm* init_object{nullptr};
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
|
|
|
|
// static class attributes
|
2019-08-25 22:16:00 +02:00
|
|
|
|
bool FVTerm::terminal_update_complete{false};
|
|
|
|
|
bool FVTerm::terminal_update_pending{false};
|
|
|
|
|
bool FVTerm::force_terminal_update{false};
|
|
|
|
|
bool FVTerm::stop_terminal_updates{false};
|
|
|
|
|
int FVTerm::skipped_terminal_update{};
|
|
|
|
|
uInt FVTerm::erase_char_length{};
|
|
|
|
|
uInt FVTerm::repeat_char_length{};
|
|
|
|
|
uInt FVTerm::clr_bol_length{};
|
|
|
|
|
uInt FVTerm::clr_eol_length{};
|
|
|
|
|
uInt FVTerm::cursor_address_length{};
|
|
|
|
|
std::queue<int>* FVTerm::output_buffer{nullptr};
|
|
|
|
|
FPoint* FVTerm::term_pos{nullptr};
|
|
|
|
|
FSystem* FVTerm::fsystem{nullptr};
|
|
|
|
|
FTerm* FVTerm::fterm{nullptr};
|
|
|
|
|
FVTerm::term_area* FVTerm::vterm{nullptr};
|
|
|
|
|
FVTerm::term_area* FVTerm::vdesktop{nullptr};
|
|
|
|
|
FVTerm::term_area* FVTerm::active_area{nullptr};
|
|
|
|
|
FKeyboard* FVTerm::keyboard{nullptr};
|
2019-07-29 02:34:58 +02:00
|
|
|
|
charData FVTerm::term_attribute{};
|
|
|
|
|
charData FVTerm::next_attribute{};
|
|
|
|
|
charData FVTerm::s_ch{};
|
|
|
|
|
charData FVTerm::i_ch{};
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
// class FVTerm
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// constructors and destructor
|
|
|
|
|
//----------------------------------------------------------------------
|
2017-10-27 23:28:37 +02:00
|
|
|
|
FVTerm::FVTerm (bool initialize, bool disable_alt_screen)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2017-10-27 23:28:37 +02:00
|
|
|
|
if ( initialize )
|
2018-10-29 00:45:45 +01:00
|
|
|
|
init (disable_alt_screen);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
FVTerm::~FVTerm() // destructor
|
|
|
|
|
{
|
|
|
|
|
if ( init_object == this )
|
|
|
|
|
finish();
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2019-02-24 00:25:36 +01:00
|
|
|
|
// Overloaded operators
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
FVTerm& FVTerm::operator << (const FTermBuffer& term_buffer)
|
|
|
|
|
{
|
|
|
|
|
print (term_buffer);
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
// public methods of FVTerm
|
2016-10-11 04:57:36 +02:00
|
|
|
|
//----------------------------------------------------------------------
|
2016-11-02 00:37:58 +01:00
|
|
|
|
FPoint FVTerm::getPrintCursor()
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto win = getPrintArea();
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
if ( win )
|
2017-02-25 15:18:29 +01:00
|
|
|
|
return FPoint ( win->offset_left + win->cursor_x
|
|
|
|
|
, win->offset_top + win->cursor_y );
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-11-20 21:11:04 +01:00
|
|
|
|
return FPoint(0, 0);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2018-09-12 22:51:15 +02:00
|
|
|
|
void FVTerm::setTermXY (int x, int y)
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
|
|
|
|
// Sets the hardware cursor to the given (x,y) position
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
if ( term_pos->getX() == x && term_pos->getY() == y )
|
|
|
|
|
return;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
int term_width = int(getColumnNumber());
|
|
|
|
|
int term_height = int(getLineNumber());
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-10-24 08:51:38 +02:00
|
|
|
|
if ( x >= term_width && term_width > 0 )
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
|
|
|
|
y += x / term_width;
|
|
|
|
|
x %= term_width;
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
if ( term_pos->getY() >= term_height )
|
|
|
|
|
term_pos->setY(term_height - 1);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
if ( y >= term_height )
|
|
|
|
|
y = term_height - 1;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
int term_x = term_pos->getX();
|
|
|
|
|
int term_y = term_pos->getY();
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-08-04 23:38:47 +02:00
|
|
|
|
const char* move_str = FTerm::moveCursorString (term_x, term_y, x, y);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
if ( move_str )
|
|
|
|
|
appendOutputBuffer(move_str);
|
|
|
|
|
|
|
|
|
|
flush_out();
|
2017-09-11 03:06:02 +02:00
|
|
|
|
term_pos->setPoint(x, y);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-12-22 23:50:10 +01:00
|
|
|
|
void FVTerm::hideCursor (bool enable)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-11-02 00:37:58 +01:00
|
|
|
|
// Hides or shows the input cursor on the terminal
|
|
|
|
|
|
2019-08-04 23:38:47 +02:00
|
|
|
|
const char* visibility_str = FTerm::cursorsVisibilityString (enable);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-05-20 15:15:42 +02:00
|
|
|
|
if ( visibility_str )
|
|
|
|
|
appendOutputBuffer(visibility_str);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
flush_out();
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2019-01-21 03:42:18 +01:00
|
|
|
|
void FVTerm::setPrintCursor (const FPoint& pos)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2019-01-27 13:44:13 +01:00
|
|
|
|
if ( auto win = getPrintArea() )
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2019-01-27 13:44:13 +01:00
|
|
|
|
win->cursor_x = pos.getX() - win->offset_left;
|
|
|
|
|
win->cursor_y = pos.getY() - win->offset_top;
|
2017-01-15 19:48:27 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-03 01:32:51 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2018-11-13 02:51:41 +01:00
|
|
|
|
FColor FVTerm::rgb2ColorIndex (uInt8 r, uInt8 g, uInt8 b)
|
2018-11-03 01:32:51 +01:00
|
|
|
|
{
|
|
|
|
|
// Converts a 24-bit RGB color to a 256-color compatible approximation
|
|
|
|
|
|
2018-11-13 02:51:41 +01:00
|
|
|
|
FColor ri = (((r * 5) + 127) / 255) * 36;
|
|
|
|
|
FColor gi = (((g * 5) + 127) / 255) * 6;
|
|
|
|
|
FColor bi = (((b * 5) + 127) / 255);
|
2018-11-03 01:32:51 +01:00
|
|
|
|
return 16 + ri + gi + bi;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::clearArea (int fillchar)
|
|
|
|
|
{
|
|
|
|
|
clearArea (vwin, fillchar);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-11 04:57:36 +02:00
|
|
|
|
//----------------------------------------------------------------------
|
2019-01-21 03:42:18 +01:00
|
|
|
|
void FVTerm::createVTerm (const FSize& size)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-11-02 00:37:58 +01:00
|
|
|
|
// initialize virtual terminal
|
2019-01-21 03:42:18 +01:00
|
|
|
|
|
|
|
|
|
const FRect box(0, 0, size.getWidth(), size.getHeight());
|
2019-01-16 16:00:15 +01:00
|
|
|
|
const FSize shadow(0, 0);
|
2019-01-21 03:42:18 +01:00
|
|
|
|
createArea (box, shadow, vterm);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2019-01-21 03:42:18 +01:00
|
|
|
|
void FVTerm::resizeVTerm (const FSize& size)
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2019-01-21 03:42:18 +01:00
|
|
|
|
// resize virtual terminal
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
const FRect box(0, 0, size.getWidth(), size.getHeight());
|
2019-01-16 16:00:15 +01:00
|
|
|
|
const FSize shadow(0, 0);
|
2019-01-21 03:42:18 +01:00
|
|
|
|
resizeArea (box, shadow, vterm);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2016-11-02 00:37:58 +01:00
|
|
|
|
void FVTerm::putVTerm()
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int i{0}; i < vterm->height; i++)
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
|
|
|
|
vterm->changes[i].xmin = 0;
|
|
|
|
|
vterm->changes[i].xmax = uInt(vterm->width - 1);
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
updateTerminal();
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2018-02-03 00:04:24 +01:00
|
|
|
|
void FVTerm::updateTerminal (terminal_update refresh_state)
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2018-02-03 00:04:24 +01:00
|
|
|
|
switch ( refresh_state )
|
|
|
|
|
{
|
|
|
|
|
case stop_refresh:
|
|
|
|
|
stop_terminal_updates = true;
|
|
|
|
|
break;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-02-03 00:04:24 +01:00
|
|
|
|
case continue_refresh:
|
|
|
|
|
case start_refresh:
|
|
|
|
|
stop_terminal_updates = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( refresh_state == start_refresh )
|
2016-11-02 00:37:58 +01:00
|
|
|
|
updateTerminal();
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::updateTerminal()
|
|
|
|
|
{
|
|
|
|
|
// Updates pending changes to the terminal
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
if ( stop_terminal_updates
|
2018-12-24 18:11:16 +01:00
|
|
|
|
|| FApplication::getApplicationObject()->isQuit() )
|
2016-11-02 00:37:58 +01:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ( ! force_terminal_update )
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-11-02 00:37:58 +01:00
|
|
|
|
if ( ! terminal_update_complete )
|
|
|
|
|
return;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-07-15 19:52:59 +02:00
|
|
|
|
if ( keyboard->isInputDataPending() )
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
|
|
|
|
terminal_update_pending = true;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 02:04:44 +02:00
|
|
|
|
auto data = getFTerm().getFTermData();
|
|
|
|
|
|
2019-08-18 21:35:36 +02:00
|
|
|
|
// Checks if the resizing of the terminal is not finished
|
|
|
|
|
if ( data && data->hasTermResized() )
|
2019-08-18 02:04:44 +02:00
|
|
|
|
return;
|
|
|
|
|
|
2019-08-18 21:35:36 +02:00
|
|
|
|
// Monitor whether the terminal size has changed
|
|
|
|
|
if ( isTermSizeChanged() )
|
|
|
|
|
{
|
|
|
|
|
raise (SIGWINCH); // Send SIGWINCH
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-18 23:34:11 +01:00
|
|
|
|
// Update data on VTerm
|
|
|
|
|
updateVTerm();
|
|
|
|
|
|
2019-08-18 21:35:36 +02:00
|
|
|
|
// Checks if VTerm has changes
|
|
|
|
|
if ( ! vterm->has_changes )
|
|
|
|
|
return;
|
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (uInt y{0}; y < uInt(vterm->height); y++)
|
2016-12-11 16:42:50 +01:00
|
|
|
|
updateTerminalLine (y);
|
|
|
|
|
|
2019-08-18 21:35:36 +02:00
|
|
|
|
vterm->has_changes = false;
|
|
|
|
|
|
2016-12-11 16:42:50 +01:00
|
|
|
|
// sets the new input cursor position
|
|
|
|
|
updateTerminalCursor();
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-18 23:37:10 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::addPreprocessingHandler ( FVTerm* instance
|
|
|
|
|
, FPreprocessingHandler handler )
|
|
|
|
|
{
|
|
|
|
|
if ( ! print_area )
|
|
|
|
|
FVTerm::getPrintArea();
|
|
|
|
|
|
|
|
|
|
if ( print_area )
|
|
|
|
|
{
|
2019-08-25 22:16:00 +02:00
|
|
|
|
vterm_preprocessing obj{ instance, handler };
|
2017-02-18 23:37:10 +01:00
|
|
|
|
delPreprocessingHandler (instance);
|
|
|
|
|
print_area->preprocessing_call.push_back(obj);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::delPreprocessingHandler (FVTerm* instance)
|
|
|
|
|
{
|
|
|
|
|
if ( ! print_area )
|
|
|
|
|
FVTerm::getPrintArea();
|
|
|
|
|
|
2017-03-08 23:48:30 +01:00
|
|
|
|
if ( ! print_area || print_area->preprocessing_call.empty() )
|
2017-02-18 23:37:10 +01:00
|
|
|
|
return;
|
|
|
|
|
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto iter = print_area->preprocessing_call.begin();
|
2017-02-18 23:37:10 +01:00
|
|
|
|
|
|
|
|
|
while ( iter != print_area->preprocessing_call.end() )
|
|
|
|
|
{
|
|
|
|
|
if ( iter->instance == instance )
|
|
|
|
|
iter = print_area->preprocessing_call.erase(iter);
|
|
|
|
|
else
|
|
|
|
|
++iter;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2017-03-17 23:22:13 +01:00
|
|
|
|
int FVTerm::print (const FString& s)
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
2019-01-27 13:44:13 +01:00
|
|
|
|
if ( s.isNull() )
|
|
|
|
|
return -1;
|
|
|
|
|
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto area = getPrintArea();
|
2016-12-18 23:34:11 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( ! area )
|
2019-02-24 00:25:36 +01:00
|
|
|
|
return -1;
|
2016-12-18 23:34:11 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return print (area, s);
|
|
|
|
|
}
|
2016-12-18 23:34:11 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2017-03-17 22:59:06 +01:00
|
|
|
|
int FVTerm::print (term_area* area, const FString& s)
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
2019-01-27 13:44:13 +01:00
|
|
|
|
if ( s.isNull() || ! area )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return -1;
|
2016-12-18 23:34:11 +01:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
std::vector<charData> term_string{};
|
2018-12-15 00:50:09 +01:00
|
|
|
|
const wchar_t* p = s.wc_str();
|
2016-12-15 23:11:34 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( p )
|
|
|
|
|
{
|
|
|
|
|
while ( *p )
|
|
|
|
|
{
|
2019-08-04 23:38:47 +02:00
|
|
|
|
charData nc{}; // next character
|
2017-11-22 23:56:21 +01:00
|
|
|
|
nc.code = *p;
|
|
|
|
|
nc.fg_color = next_attribute.fg_color;
|
|
|
|
|
nc.bg_color = next_attribute.bg_color;
|
|
|
|
|
nc.attr.byte[0] = next_attribute.attr.byte[0];
|
|
|
|
|
nc.attr.byte[1] = next_attribute.attr.byte[1];
|
|
|
|
|
nc.attr.byte[2] = 0;
|
|
|
|
|
term_string.push_back(nc);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
p++;
|
2017-09-11 03:06:02 +02:00
|
|
|
|
} // end of while
|
2017-11-22 23:56:21 +01:00
|
|
|
|
|
|
|
|
|
return print (area, term_string);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2017-11-22 23:56:21 +01:00
|
|
|
|
return 0;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-24 00:25:36 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
int FVTerm::print (const FTermBuffer& term_buffer)
|
|
|
|
|
{
|
|
|
|
|
if ( term_buffer.isEmpty() )
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
auto area = getPrintArea();
|
|
|
|
|
|
|
|
|
|
if ( ! area )
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return print (area, term_buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
int FVTerm::print (term_area* area, const FTermBuffer& term_buffer)
|
|
|
|
|
{
|
|
|
|
|
const auto& term_string = term_buffer.getBuffer();
|
|
|
|
|
return print (area, term_string);
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-12 01:16:57 +02:00
|
|
|
|
//----------------------------------------------------------------------
|
2018-06-25 00:14:53 +02:00
|
|
|
|
int FVTerm::print (const std::vector<charData>& term_string)
|
2017-07-12 01:16:57 +02:00
|
|
|
|
{
|
2017-11-22 23:56:21 +01:00
|
|
|
|
if ( term_string.empty() )
|
2017-07-12 01:16:57 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto area = getPrintArea();
|
2017-07-12 01:16:57 +02:00
|
|
|
|
|
|
|
|
|
if ( ! area )
|
2019-02-24 00:25:36 +01:00
|
|
|
|
return -1;
|
2017-07-12 01:16:57 +02:00
|
|
|
|
|
2017-11-22 23:56:21 +01:00
|
|
|
|
return print (area, term_string);
|
2017-07-12 01:16:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-06-25 00:14:53 +02:00
|
|
|
|
int FVTerm::print (term_area* area, const std::vector<charData>& term_string)
|
2017-07-12 01:16:57 +02:00
|
|
|
|
{
|
2019-08-25 22:16:00 +02:00
|
|
|
|
int len{0};
|
2017-07-12 01:16:57 +02:00
|
|
|
|
uInt tabstop = uInt(getTabstop());
|
|
|
|
|
|
|
|
|
|
if ( ! area )
|
|
|
|
|
return -1;
|
|
|
|
|
|
2017-11-22 23:56:21 +01:00
|
|
|
|
if ( term_string.empty() )
|
2017-07-12 01:16:57 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
2018-12-15 00:50:09 +01:00
|
|
|
|
for (auto&& ch : term_string)
|
2017-07-12 01:16:57 +02:00
|
|
|
|
{
|
2019-08-25 22:16:00 +02:00
|
|
|
|
bool printable_character{false};
|
2017-07-12 01:16:57 +02:00
|
|
|
|
|
2018-12-15 00:50:09 +01:00
|
|
|
|
switch ( ch.code )
|
2017-07-12 01:16:57 +02:00
|
|
|
|
{
|
|
|
|
|
case '\n':
|
|
|
|
|
area->cursor_y++;
|
2017-08-11 10:50:39 +02:00
|
|
|
|
// fall through
|
2017-07-12 01:16:57 +02:00
|
|
|
|
case '\r':
|
|
|
|
|
area->cursor_x = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '\t':
|
2018-12-28 22:57:43 +01:00
|
|
|
|
area->cursor_x = int ( uInt(area->cursor_x)
|
|
|
|
|
+ tabstop
|
|
|
|
|
- uInt(area->cursor_x)
|
|
|
|
|
+ 1
|
|
|
|
|
% tabstop );
|
2017-07-12 01:16:57 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '\b':
|
|
|
|
|
area->cursor_x--;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '\a':
|
|
|
|
|
beep();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto nc = ch; // next character
|
2017-11-22 23:56:21 +01:00
|
|
|
|
print (area, nc);
|
|
|
|
|
printable_character = true;
|
2017-07-12 01:16:57 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-10 17:35:09 +01:00
|
|
|
|
if ( ! printable_character && printWrap(area) )
|
|
|
|
|
break; // end of area reached
|
2017-07-12 01:16:57 +02:00
|
|
|
|
|
|
|
|
|
len++;
|
2018-02-10 17:35:09 +01:00
|
|
|
|
}
|
2017-07-12 01:16:57 +02:00
|
|
|
|
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-11 04:57:36 +02:00
|
|
|
|
//----------------------------------------------------------------------
|
2018-12-06 02:28:24 +01:00
|
|
|
|
int FVTerm::print (wchar_t c)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto area = getPrintArea();
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
|
|
|
|
if ( ! area )
|
2019-02-24 00:25:36 +01:00
|
|
|
|
return -1;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return print (area, c);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-12-06 02:28:24 +01:00
|
|
|
|
int FVTerm::print (term_area* area, wchar_t c)
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2019-08-25 22:16:00 +02:00
|
|
|
|
charData nc{}; // next character
|
2017-11-22 23:56:21 +01:00
|
|
|
|
|
|
|
|
|
if ( ! area )
|
|
|
|
|
return -1;
|
|
|
|
|
|
2018-12-06 02:28:24 +01:00
|
|
|
|
nc.code = wchar_t(c);
|
2017-11-22 23:56:21 +01:00
|
|
|
|
nc.fg_color = next_attribute.fg_color;
|
|
|
|
|
nc.bg_color = next_attribute.bg_color;
|
|
|
|
|
nc.attr.byte[0] = next_attribute.attr.byte[0];
|
|
|
|
|
nc.attr.byte[1] = next_attribute.attr.byte[1];
|
|
|
|
|
nc.attr.byte[2] = 0;
|
|
|
|
|
|
|
|
|
|
return print (area, nc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-06-25 00:14:53 +02:00
|
|
|
|
int FVTerm::print (charData& term_char)
|
2017-11-22 23:56:21 +01:00
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto area = getPrintArea();
|
2017-11-22 23:56:21 +01:00
|
|
|
|
|
|
|
|
|
if ( ! area )
|
2019-02-24 00:25:36 +01:00
|
|
|
|
return -1;
|
2017-11-22 23:56:21 +01:00
|
|
|
|
|
|
|
|
|
return print (area, term_char);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-06-25 00:14:53 +02:00
|
|
|
|
int FVTerm::print (term_area* area, charData& term_char)
|
2017-11-22 23:56:21 +01:00
|
|
|
|
{
|
2018-06-25 00:14:53 +02:00
|
|
|
|
charData& nc = term_char; // next character
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( ! area )
|
|
|
|
|
return -1;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
int width = area->width;
|
|
|
|
|
int height = area->height;
|
|
|
|
|
int rsh = area->right_shadow;
|
|
|
|
|
int bsh = area->bottom_shadow;
|
|
|
|
|
int ax = area->cursor_x - 1;
|
|
|
|
|
int ay = area->cursor_y - 1;
|
2019-09-28 03:13:06 +02:00
|
|
|
|
std::size_t char_width = getColumnWidth(nc); // add column width
|
|
|
|
|
|
|
|
|
|
if ( char_width == 0 && ! nc.attr.bit.fullwidth_padding )
|
|
|
|
|
return 0;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( area->cursor_x > 0
|
2017-11-26 22:37:18 +01:00
|
|
|
|
&& area->cursor_y > 0
|
|
|
|
|
&& ax < area->width + area->right_shadow
|
|
|
|
|
&& ay < area->height + area->bottom_shadow )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
int line_len = area->width + area->right_shadow;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto ac = &area->text[ay * line_len + ax]; // area character
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( *ac != nc ) // compare with an overloaded operator
|
|
|
|
|
{
|
2017-11-26 22:37:18 +01:00
|
|
|
|
if ( ( ! ac->attr.bit.transparent && nc.attr.bit.transparent )
|
|
|
|
|
|| ( ! ac->attr.bit.trans_shadow && nc.attr.bit.trans_shadow )
|
|
|
|
|
|| ( ! ac->attr.bit.inherit_bg && nc.attr.bit.inherit_bg ) )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
// add one transparent character form line
|
|
|
|
|
area->changes[ay].trans_count++;
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-11-26 22:37:18 +01:00
|
|
|
|
if ( ( ac->attr.bit.transparent && ! nc.attr.bit.transparent )
|
|
|
|
|
|| ( ac->attr.bit.trans_shadow && ! nc.attr.bit.trans_shadow )
|
|
|
|
|
|| ( ac->attr.bit.inherit_bg && ! nc.attr.bit.inherit_bg ) )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
// remove one transparent character from line
|
|
|
|
|
area->changes[ay].trans_count--;
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// copy character to area
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (ac, &nc, sizeof(*ac));
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-12-28 22:57:43 +01:00
|
|
|
|
if ( ax < int(area->changes[ay].xmin) )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
area->changes[ay].xmin = uInt(ax);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-12-28 22:57:43 +01:00
|
|
|
|
if ( ax > int(area->changes[ay].xmax) )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
area->changes[ay].xmax = uInt(ax);
|
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
area->cursor_x++;
|
|
|
|
|
area->has_changes = true;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-11-22 23:56:21 +01:00
|
|
|
|
// Line break at right margin
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( area->cursor_x > width + rsh )
|
|
|
|
|
{
|
|
|
|
|
area->cursor_x = 1;
|
|
|
|
|
area->cursor_y++;
|
|
|
|
|
}
|
2019-09-28 03:13:06 +02:00
|
|
|
|
else if ( char_width == 2 )
|
|
|
|
|
printPaddingCharacter (area, nc);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-11-22 23:56:21 +01:00
|
|
|
|
// Prevent up scrolling
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( area->cursor_y > height + bsh )
|
|
|
|
|
{
|
|
|
|
|
area->cursor_y--;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return 1;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-27 13:44:13 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::print (const FPoint& p)
|
|
|
|
|
{
|
|
|
|
|
setPrintCursor (p);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-30 12:17:48 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::print (const FColorPair& pair)
|
|
|
|
|
{
|
2019-09-04 23:57:31 +02:00
|
|
|
|
setColor (pair.getForegroundColor(), pair.getBackgroundColor());
|
2019-01-30 12:17:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-27 13:44:13 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// protected methods of FVTerm
|
2017-01-02 08:07:46 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
FVTerm::term_area* FVTerm::getPrintArea()
|
|
|
|
|
{
|
|
|
|
|
// returns the print area of this object
|
|
|
|
|
|
|
|
|
|
if ( print_area )
|
|
|
|
|
return print_area;
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-10-27 23:28:37 +02:00
|
|
|
|
if ( vwin )
|
2017-01-02 08:07:46 +01:00
|
|
|
|
{
|
2017-10-27 23:28:37 +02:00
|
|
|
|
print_area = vwin;
|
2017-01-02 08:07:46 +01:00
|
|
|
|
return print_area;
|
|
|
|
|
}
|
2017-10-27 23:28:37 +02:00
|
|
|
|
else if ( child_print_area )
|
2017-01-07 22:09:09 +01:00
|
|
|
|
{
|
2017-10-27 23:28:37 +02:00
|
|
|
|
print_area = child_print_area;
|
2017-01-07 22:09:09 +01:00
|
|
|
|
return print_area;
|
|
|
|
|
}
|
2017-01-02 08:07:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return vdesktop;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2019-01-21 03:42:18 +01:00
|
|
|
|
void FVTerm::createArea ( const FRect& box
|
|
|
|
|
, const FSize& shadow
|
2016-12-28 16:29:49 +01:00
|
|
|
|
, term_area*& area )
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// initialize virtual window
|
2017-01-02 08:07:46 +01:00
|
|
|
|
|
2017-08-12 22:55:29 +02:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
area = new term_area;
|
|
|
|
|
}
|
|
|
|
|
catch (const std::bad_alloc& ex)
|
|
|
|
|
{
|
2018-11-22 21:51:32 +01:00
|
|
|
|
std::cerr << bad_alloc_str << ex.what() << std::endl;
|
2017-08-12 22:55:29 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-08 02:04:24 +02:00
|
|
|
|
area->widget = reinterpret_cast<FWidget*>(this);
|
2019-01-21 03:42:18 +01:00
|
|
|
|
resizeArea (box, shadow, area);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2019-01-21 03:42:18 +01:00
|
|
|
|
void FVTerm::resizeArea ( const FRect& box
|
|
|
|
|
, const FSize& shadow
|
2016-12-28 16:29:49 +01:00
|
|
|
|
, term_area* area )
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2017-03-08 23:48:30 +01:00
|
|
|
|
// Resize the virtual window to a new size.
|
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
int offset_left = box.getX();
|
2019-08-25 22:16:00 +02:00
|
|
|
|
int offset_top = box.getY();
|
2019-09-28 03:13:06 +02:00
|
|
|
|
int width = int(box.getWidth());
|
|
|
|
|
int height = int(box.getHeight());
|
|
|
|
|
int rsw = int(shadow.getWidth());
|
|
|
|
|
int bsh = int(shadow.getHeight());
|
2019-01-21 03:42:18 +01:00
|
|
|
|
|
2017-01-22 23:04:40 +01:00
|
|
|
|
assert ( offset_top >= 0 );
|
2019-01-21 03:42:18 +01:00
|
|
|
|
assert ( width > 0 && width + rsw > 0 );
|
|
|
|
|
assert ( height > 0 && height + bsh > 0 );
|
2017-01-22 23:04:40 +01:00
|
|
|
|
assert ( rsw >= 0 );
|
|
|
|
|
assert ( bsh >= 0 );
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
|
|
|
|
if ( ! area )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return;
|
|
|
|
|
|
2017-03-19 17:18:07 +01:00
|
|
|
|
if ( width == area->width
|
2017-11-26 22:37:18 +01:00
|
|
|
|
&& height == area->height
|
|
|
|
|
&& rsw == area->right_shadow
|
|
|
|
|
&& bsh == area->bottom_shadow )
|
2017-03-19 17:18:07 +01:00
|
|
|
|
{
|
|
|
|
|
if ( offset_left != area->offset_left )
|
|
|
|
|
area->offset_left = offset_left;
|
|
|
|
|
|
|
|
|
|
if ( offset_top != area->offset_top )
|
|
|
|
|
area->offset_top = offset_top;
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
bool realloc_success{false};
|
2019-09-09 19:13:38 +02:00
|
|
|
|
std::size_t full_width = std::size_t(width) + std::size_t(rsw);
|
|
|
|
|
std::size_t full_height = std::size_t(height) + std::size_t(bsh);
|
|
|
|
|
std::size_t area_size = full_width * full_height;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2019-09-09 19:13:38 +02:00
|
|
|
|
if ( area->height + area->bottom_shadow != int(full_height) )
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2018-10-08 04:14:20 +02:00
|
|
|
|
realloc_success = reallocateTextArea ( area
|
2019-09-09 19:13:38 +02:00
|
|
|
|
, full_height
|
2018-10-08 04:14:20 +02:00
|
|
|
|
, area_size );
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2019-09-09 19:13:38 +02:00
|
|
|
|
else if ( area->width + area->right_shadow != int(full_width) )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
2018-02-04 19:42:30 +01:00
|
|
|
|
realloc_success = reallocateTextArea (area, area_size);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-02-04 19:42:30 +01:00
|
|
|
|
if ( ! realloc_success )
|
|
|
|
|
return;
|
|
|
|
|
|
2019-01-24 00:23:00 +01:00
|
|
|
|
area->offset_left = offset_left;
|
|
|
|
|
area->offset_top = offset_top;
|
|
|
|
|
area->width = width;
|
|
|
|
|
area->height = height;
|
|
|
|
|
area->right_shadow = rsw;
|
|
|
|
|
area->bottom_shadow = bsh;
|
|
|
|
|
area->has_changes = false;
|
2018-02-04 19:42:30 +01:00
|
|
|
|
|
2019-09-09 19:13:38 +02:00
|
|
|
|
FSize size(full_width, full_height);
|
2019-01-21 03:42:18 +01:00
|
|
|
|
setTextToDefault (area, size);
|
2018-02-04 19:42:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
inline void FVTerm::setTextToDefault ( term_area* area
|
2019-01-21 03:42:18 +01:00
|
|
|
|
, const FSize& size )
|
2018-02-04 19:42:30 +01:00
|
|
|
|
{
|
2018-06-25 00:14:53 +02:00
|
|
|
|
charData default_char;
|
2018-02-04 19:42:30 +01:00
|
|
|
|
line_changes unchanged;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-09-15 01:31:02 +02:00
|
|
|
|
default_char.code = ' ';
|
|
|
|
|
default_char.fg_color = fc::Default;
|
|
|
|
|
default_char.bg_color = fc::Default;
|
|
|
|
|
default_char.attr.byte[0] = 0;
|
|
|
|
|
default_char.attr.byte[1] = 0;
|
2017-09-16 01:21:16 +02:00
|
|
|
|
default_char.attr.byte[2] = 0;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
std::fill_n (area->text, size.getArea(), default_char);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
unchanged.xmin = uInt(size.getWidth());
|
2016-12-28 16:29:49 +01:00
|
|
|
|
unchanged.xmax = 0;
|
|
|
|
|
unchanged.trans_count = 0;
|
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
std::fill_n (area->changes, size.getHeight(), unchanged);
|
2018-02-04 19:42:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
inline bool FVTerm::reallocateTextArea ( term_area* area
|
2018-10-08 04:14:20 +02:00
|
|
|
|
, std::size_t height
|
|
|
|
|
, std::size_t size )
|
2018-02-04 19:42:30 +01:00
|
|
|
|
{
|
2019-01-21 03:42:18 +01:00
|
|
|
|
// Reallocate "height" lines for changes
|
|
|
|
|
// and "size" bytes for the text area
|
|
|
|
|
|
2018-02-04 19:42:30 +01:00
|
|
|
|
if ( area->changes != 0 )
|
|
|
|
|
delete[] area->changes;
|
|
|
|
|
|
|
|
|
|
if ( area->text != 0 )
|
|
|
|
|
delete[] area->text;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2018-10-08 04:14:20 +02:00
|
|
|
|
area->changes = new line_changes[height];
|
|
|
|
|
area->text = new charData[size];
|
2018-02-04 19:42:30 +01:00
|
|
|
|
}
|
|
|
|
|
catch (const std::bad_alloc& ex)
|
|
|
|
|
{
|
2018-11-22 21:51:32 +01:00
|
|
|
|
std::cerr << bad_alloc_str << ex.what() << std::endl;
|
2018-02-04 19:42:30 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-10-08 04:14:20 +02:00
|
|
|
|
inline bool FVTerm::reallocateTextArea (term_area* area, std::size_t size)
|
2018-02-04 19:42:30 +01:00
|
|
|
|
{
|
2019-01-21 03:42:18 +01:00
|
|
|
|
// Reallocate "size" bytes for the text area
|
|
|
|
|
|
2018-02-04 19:42:30 +01:00
|
|
|
|
if ( area->text != 0 )
|
|
|
|
|
delete[] area->text;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2018-10-08 04:14:20 +02:00
|
|
|
|
area->text = new charData[size];
|
2018-02-04 19:42:30 +01:00
|
|
|
|
}
|
|
|
|
|
catch (const std::bad_alloc& ex)
|
|
|
|
|
{
|
2018-11-22 21:51:32 +01:00
|
|
|
|
std::cerr << bad_alloc_str << ex.what() << std::endl;
|
2018-02-04 19:42:30 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::removeArea (term_area*& area)
|
|
|
|
|
{
|
|
|
|
|
// remove the virtual window
|
2017-03-08 23:48:30 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( area != 0 )
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( area->changes != 0 )
|
|
|
|
|
{
|
|
|
|
|
delete[] area->changes;
|
2018-12-10 01:48:26 +01:00
|
|
|
|
area->changes = nullptr;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2016-12-18 23:34:11 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( area->text != 0 )
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
delete[] area->text;
|
2018-12-10 01:48:26 +01:00
|
|
|
|
area->text = nullptr;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2016-10-15 03:32:30 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
delete area;
|
2018-12-10 01:48:26 +01:00
|
|
|
|
area = nullptr;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-14 17:37:26 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::restoreVTerm (const FRect& box)
|
|
|
|
|
{
|
2019-01-21 03:42:18 +01:00
|
|
|
|
int x = box.getX() - 1;
|
|
|
|
|
int y = box.getY() - 1;
|
|
|
|
|
int w = int(box.getWidth());
|
|
|
|
|
int h = int(box.getHeight());
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( x < 0 )
|
|
|
|
|
x = 0;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( y < 0 )
|
|
|
|
|
y = 0;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
|
if ( x + w > vterm->width )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
w = vterm->width - x;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( w < 0 )
|
|
|
|
|
return;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
|
if ( y + h > vterm->height )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
h = vterm->height - y;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( h < 0 )
|
|
|
|
|
return;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int ty{0}; ty < h; ty++)
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
2018-01-05 00:49:00 +01:00
|
|
|
|
int ypos = y + ty;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int tx{0}; tx < w; tx++)
|
2018-01-05 00:49:00 +01:00
|
|
|
|
{
|
|
|
|
|
int xpos = x + tx;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto tc = &vterm->text[ypos * vterm->width + xpos]; // terminal character
|
2019-01-21 03:42:18 +01:00
|
|
|
|
auto sc = generateCharacter(FPoint(xpos, ypos)); // shown character
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (tc, &sc, sizeof(*tc));
|
2018-01-05 00:49:00 +01:00
|
|
|
|
}
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2018-12-28 22:57:43 +01:00
|
|
|
|
if ( int(vterm->changes[ypos].xmin) > x )
|
2018-01-05 00:49:00 +01:00
|
|
|
|
vterm->changes[ypos].xmin = uInt(x);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2018-12-28 22:57:43 +01:00
|
|
|
|
if ( int(vterm->changes[ypos].xmax) < x + w - 1 )
|
2018-01-05 00:49:00 +01:00
|
|
|
|
vterm->changes[ypos].xmax = uInt(x + w - 1);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2019-08-18 21:35:36 +02:00
|
|
|
|
|
|
|
|
|
vterm->has_changes = true;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
FVTerm::covered_state FVTerm::isCovered ( const FPoint& pos
|
|
|
|
|
, term_area* area )
|
|
|
|
|
{
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// Determines the covered state for the given position
|
|
|
|
|
|
2016-10-11 04:57:36 +02:00
|
|
|
|
if ( ! area )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return non_covered;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-12-15 22:10:31 +01:00
|
|
|
|
auto is_covered = non_covered;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-09-01 23:29:27 +02:00
|
|
|
|
if ( FWidget::getWindowList() && ! FWidget::getWindowList()->empty() )
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2019-09-29 22:28:58 +02:00
|
|
|
|
bool found( area == vdesktop );
|
|
|
|
|
|
2019-09-01 23:29:27 +02:00
|
|
|
|
for (auto& win_obj : *FWidget::getWindowList())
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2018-12-15 22:10:31 +01:00
|
|
|
|
auto win = win_obj->getVWin();
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( ! win )
|
|
|
|
|
continue;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( ! win->visible )
|
|
|
|
|
continue;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-02-25 15:18:29 +01:00
|
|
|
|
int win_x = win->offset_left;
|
|
|
|
|
int win_y = win->offset_top;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
FRect geometry ( win_x
|
|
|
|
|
, win_y
|
2019-09-09 19:13:38 +02:00
|
|
|
|
, std::size_t(win->width) + std::size_t(win->right_shadow)
|
|
|
|
|
, std::size_t(win->height) + std::size_t(win->bottom_shadow) );
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
if ( found && geometry.contains(pos) )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
2019-01-24 00:23:00 +01:00
|
|
|
|
int width = win->width + win->right_shadow;
|
2019-01-21 03:42:18 +01:00
|
|
|
|
int x = pos.getX();
|
|
|
|
|
int y = pos.getY();
|
2019-01-24 00:23:00 +01:00
|
|
|
|
auto tmp = &win->text[(y - win_y) * width + (x - win_x)];
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2017-08-20 17:30:30 +02:00
|
|
|
|
if ( tmp->attr.bit.trans_shadow )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
is_covered = half_covered;
|
|
|
|
|
}
|
2017-08-20 17:30:30 +02:00
|
|
|
|
else if ( ! tmp->attr.bit.transparent )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
is_covered = fully_covered;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( area == win )
|
|
|
|
|
found = true;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return is_covered;
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-12-02 18:52:51 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::updateOverlappedColor ( term_area* area
|
2019-01-21 03:42:18 +01:00
|
|
|
|
, const FPoint& area_pos
|
|
|
|
|
, const FPoint& terminal_pos )
|
2017-12-02 18:52:51 +01:00
|
|
|
|
{
|
|
|
|
|
// Add the overlapping color to this character
|
|
|
|
|
|
2019-01-24 00:23:00 +01:00
|
|
|
|
int x = area_pos.getX();
|
|
|
|
|
int y = area_pos.getY();
|
|
|
|
|
int tx = terminal_pos.getX();
|
|
|
|
|
int ty = terminal_pos.getY();
|
|
|
|
|
int width = area->width + area->right_shadow;
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// Area character
|
2019-01-24 00:23:00 +01:00
|
|
|
|
auto ac = &area->text[y * width + x];
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// Terminal character
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto tc = &vterm->text[ty * vterm->width + tx];
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// New character
|
2019-08-25 22:16:00 +02:00
|
|
|
|
charData nc{};
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (&nc, ac, sizeof(nc));
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// Overlapped character
|
2019-01-21 03:42:18 +01:00
|
|
|
|
auto oc = getOverlappedCharacter (terminal_pos + FPoint(1, 1), area->widget);
|
2017-12-02 18:52:51 +01:00
|
|
|
|
nc.fg_color = oc.fg_color;
|
|
|
|
|
nc.bg_color = oc.bg_color;
|
|
|
|
|
nc.attr.bit.reverse = false;
|
|
|
|
|
nc.attr.bit.standout = false;
|
|
|
|
|
|
|
|
|
|
if ( nc.code == fc::LowerHalfBlock
|
|
|
|
|
|| nc.code == fc::UpperHalfBlock
|
|
|
|
|
|| nc.code == fc::LeftHalfBlock
|
|
|
|
|
|| nc.code == fc::RightHalfBlock
|
|
|
|
|
|| nc.code == fc::MediumShade
|
|
|
|
|
|| nc.code == fc::FullBlock )
|
|
|
|
|
nc.code = ' ';
|
|
|
|
|
|
|
|
|
|
nc.attr.bit.no_changes = bool(tc->attr.bit.printed && *tc == nc);
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (tc, &nc, sizeof(*tc));
|
2017-12-02 18:52:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2019-01-21 03:42:18 +01:00
|
|
|
|
void FVTerm::updateOverlappedCharacter ( term_area* area
|
|
|
|
|
, const FPoint& terminal_pos )
|
2017-12-02 18:52:51 +01:00
|
|
|
|
{
|
|
|
|
|
// Restore one character on vterm
|
|
|
|
|
|
|
|
|
|
// Terminal character
|
2019-01-21 03:42:18 +01:00
|
|
|
|
int tx = terminal_pos.getX();
|
|
|
|
|
int ty = terminal_pos.getY();
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto tc = &vterm->text[ty * vterm->width + tx];
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// Overlapped character
|
2019-01-21 03:42:18 +01:00
|
|
|
|
auto oc = getCoveredCharacter (terminal_pos + FPoint(1, 1), area->widget);
|
2017-12-02 18:52:51 +01:00
|
|
|
|
oc.attr.bit.no_changes = bool(tc->attr.bit.printed && *tc == oc);
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (tc, &oc, sizeof(*tc));
|
2017-12-02 18:52:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::updateShadedCharacter ( term_area* area
|
2019-01-21 03:42:18 +01:00
|
|
|
|
, const FPoint& area_pos
|
|
|
|
|
, const FPoint& terminal_pos )
|
2017-12-02 18:52:51 +01:00
|
|
|
|
{
|
|
|
|
|
// Get covered character + add the current color
|
|
|
|
|
|
2019-01-24 00:23:00 +01:00
|
|
|
|
int x = area_pos.getX();
|
|
|
|
|
int y = area_pos.getY();
|
|
|
|
|
int tx = terminal_pos.getX();
|
|
|
|
|
int ty = terminal_pos.getY();
|
|
|
|
|
int width = area->width + area->right_shadow;
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// Area character
|
2019-01-24 00:23:00 +01:00
|
|
|
|
auto ac = &area->text[y * width + x];
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// Terminal character
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto tc = &vterm->text[ty * vterm->width + tx];
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// Overlapped character
|
2019-01-21 03:42:18 +01:00
|
|
|
|
auto oc = getCoveredCharacter (terminal_pos + FPoint(1, 1), area->widget);
|
2017-12-02 18:52:51 +01:00
|
|
|
|
oc.fg_color = ac->fg_color;
|
|
|
|
|
oc.bg_color = ac->bg_color;
|
|
|
|
|
oc.attr.bit.reverse = false;
|
|
|
|
|
oc.attr.bit.standout = false;
|
|
|
|
|
|
|
|
|
|
if ( oc.code == fc::LowerHalfBlock
|
|
|
|
|
|| oc.code == fc::UpperHalfBlock
|
|
|
|
|
|| oc.code == fc::LeftHalfBlock
|
|
|
|
|
|| oc.code == fc::RightHalfBlock
|
|
|
|
|
|| oc.code == fc::MediumShade
|
|
|
|
|
|| oc.code == fc::FullBlock )
|
|
|
|
|
oc.code = ' ';
|
|
|
|
|
|
|
|
|
|
oc.attr.bit.no_changes = bool(tc->attr.bit.printed && *tc == oc);
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (tc, &oc, sizeof(*tc));
|
2017-12-02 18:52:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::updateInheritBackground ( term_area* area
|
2019-01-21 03:42:18 +01:00
|
|
|
|
, const FPoint& area_pos
|
|
|
|
|
, const FPoint& terminal_pos )
|
2017-12-02 18:52:51 +01:00
|
|
|
|
{
|
|
|
|
|
// Add the covered background to this character
|
|
|
|
|
|
2019-01-24 00:23:00 +01:00
|
|
|
|
int x = area_pos.getX();
|
|
|
|
|
int y = area_pos.getY();
|
|
|
|
|
int tx = terminal_pos.getX();
|
|
|
|
|
int ty = terminal_pos.getY();
|
|
|
|
|
int width = area->width + area->right_shadow;
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// Area character
|
2019-01-24 00:23:00 +01:00
|
|
|
|
auto ac = &area->text[y * width + x];
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// Terminal character
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto tc = &vterm->text[ty * vterm->width + tx];
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// New character
|
2019-08-25 22:16:00 +02:00
|
|
|
|
charData nc{};
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (&nc, ac, sizeof(nc));
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// Covered character
|
2019-01-21 03:42:18 +01:00
|
|
|
|
auto cc = getCoveredCharacter (terminal_pos + FPoint(1, 1), area->widget);
|
2017-12-02 18:52:51 +01:00
|
|
|
|
nc.bg_color = cc.bg_color;
|
|
|
|
|
nc.attr.bit.no_changes = bool(tc->attr.bit.printed && *tc == nc);
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (tc, &nc, sizeof(*tc));
|
2017-12-02 18:52:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::updateCharacter ( term_area* area
|
2019-01-21 03:42:18 +01:00
|
|
|
|
, const FPoint& area_pos
|
|
|
|
|
, const FPoint& terminal_pos )
|
2017-12-02 18:52:51 +01:00
|
|
|
|
{
|
|
|
|
|
// Copy a area character to the virtual terminal
|
|
|
|
|
|
2019-01-24 00:23:00 +01:00
|
|
|
|
int x = area_pos.getX();
|
|
|
|
|
int y = area_pos.getY();
|
|
|
|
|
int tx = terminal_pos.getX();
|
|
|
|
|
int ty = terminal_pos.getY();
|
|
|
|
|
int width = area->width + area->right_shadow;
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// Area character
|
2019-01-24 00:23:00 +01:00
|
|
|
|
auto ac = &area->text[y * width + x];
|
2017-12-02 18:52:51 +01:00
|
|
|
|
// Terminal character
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto tc = &vterm->text[ty * vterm->width + tx];
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (tc, ac, sizeof(*tc));
|
2017-12-02 18:52:51 +01:00
|
|
|
|
|
|
|
|
|
if ( tc->attr.bit.printed && *tc == *ac )
|
|
|
|
|
tc->attr.bit.no_changes = true;
|
|
|
|
|
else
|
|
|
|
|
tc->attr.bit.no_changes = false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-03 21:06:21 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
bool FVTerm::updateVTermCharacter ( term_area* area
|
2019-01-21 03:42:18 +01:00
|
|
|
|
, const FPoint& area_pos
|
|
|
|
|
, const FPoint& terminal_pos )
|
2017-12-03 21:06:21 +01:00
|
|
|
|
{
|
2019-01-24 00:23:00 +01:00
|
|
|
|
int x = area_pos.getX();
|
|
|
|
|
int y = area_pos.getY();
|
|
|
|
|
int width = area->width + area->right_shadow;
|
2017-12-03 21:06:21 +01:00
|
|
|
|
// Area character
|
2019-01-24 00:23:00 +01:00
|
|
|
|
auto ac = &area->text[y * width + x];
|
2017-12-03 21:06:21 +01:00
|
|
|
|
|
|
|
|
|
// Get covered state
|
2019-01-21 03:42:18 +01:00
|
|
|
|
auto is_covered = isCovered(terminal_pos, area);
|
2017-12-03 21:06:21 +01:00
|
|
|
|
|
|
|
|
|
if ( is_covered == fully_covered )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if ( is_covered == half_covered )
|
|
|
|
|
{
|
2019-01-21 03:42:18 +01:00
|
|
|
|
updateOverlappedColor(area, area_pos, terminal_pos);
|
2017-12-03 21:06:21 +01:00
|
|
|
|
}
|
|
|
|
|
else if ( ac->attr.bit.transparent ) // Transparent
|
|
|
|
|
{
|
2019-01-21 03:42:18 +01:00
|
|
|
|
updateOverlappedCharacter(area, terminal_pos);
|
2017-12-03 21:06:21 +01:00
|
|
|
|
}
|
|
|
|
|
else // Not transparent
|
|
|
|
|
{
|
|
|
|
|
if ( ac->attr.bit.trans_shadow ) // Transparent shadow
|
|
|
|
|
{
|
2019-01-21 03:42:18 +01:00
|
|
|
|
updateShadedCharacter (area, area_pos, terminal_pos);
|
2017-12-03 21:06:21 +01:00
|
|
|
|
}
|
|
|
|
|
else if ( ac->attr.bit.inherit_bg )
|
|
|
|
|
{
|
2019-01-21 03:42:18 +01:00
|
|
|
|
updateInheritBackground (area, area_pos, terminal_pos);
|
2017-12-03 21:06:21 +01:00
|
|
|
|
}
|
|
|
|
|
else // Default
|
|
|
|
|
{
|
2019-01-21 03:42:18 +01:00
|
|
|
|
updateCharacter (area, area_pos, terminal_pos);
|
2017-12-03 21:06:21 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-02 18:52:51 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::callPreprocessingHandler (term_area* area)
|
|
|
|
|
{
|
|
|
|
|
// Call preprocessing handler
|
|
|
|
|
|
|
|
|
|
if ( ! area->preprocessing_call.empty() )
|
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto iter = area->preprocessing_call.begin();
|
|
|
|
|
auto end = area->preprocessing_call.end();
|
2017-12-02 18:52:51 +01:00
|
|
|
|
|
|
|
|
|
while ( iter != end )
|
|
|
|
|
{
|
|
|
|
|
FPreprocessingHandler handler = iter->handler;
|
|
|
|
|
// call the preprocessing handler
|
|
|
|
|
(iter->instance->*handler)();
|
|
|
|
|
++iter;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::updateVTerm()
|
|
|
|
|
{
|
|
|
|
|
// Updates the character data from all areas to VTerm
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( vdesktop && vdesktop->has_changes )
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
updateVTerm(vdesktop);
|
|
|
|
|
vdesktop->has_changes = false;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
FWidget* widget = static_cast<FWidget*>(vterm->widget);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-09-01 23:29:27 +02:00
|
|
|
|
if ( ! widget->getWindowList() || widget->getWindowList()->empty() )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return;
|
|
|
|
|
|
2019-09-01 23:29:27 +02:00
|
|
|
|
auto iter = widget->getWindowList()->begin();
|
|
|
|
|
auto end = widget->getWindowList()->end();
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
|
|
|
|
for (; iter != end; ++iter)
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto win = (*iter)->getVWin();
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( ! win )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if ( ! win->visible )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if ( win->has_changes )
|
|
|
|
|
{
|
|
|
|
|
updateVTerm(win);
|
|
|
|
|
win->has_changes = false;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2017-02-18 23:37:10 +01:00
|
|
|
|
else if ( ! win->preprocessing_call.empty() )
|
2017-01-15 19:48:27 +01:00
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto iter2 = win->preprocessing_call.begin();
|
|
|
|
|
auto end2 = win->preprocessing_call.end();
|
2017-02-18 23:37:10 +01:00
|
|
|
|
|
2017-02-24 23:16:05 +01:00
|
|
|
|
while ( iter2 != end2 )
|
2017-02-18 23:37:10 +01:00
|
|
|
|
{
|
2017-02-24 23:16:05 +01:00
|
|
|
|
if ( iter2->instance->child_print_area
|
2017-11-26 22:37:18 +01:00
|
|
|
|
&& iter2->instance->child_print_area->has_changes )
|
2017-02-18 23:37:10 +01:00
|
|
|
|
{
|
|
|
|
|
updateVTerm(win);
|
2017-02-24 23:16:05 +01:00
|
|
|
|
iter2->instance->child_print_area->has_changes = false;
|
2017-02-18 23:37:10 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-24 23:16:05 +01:00
|
|
|
|
++iter2;
|
2017-02-18 23:37:10 +01:00
|
|
|
|
}
|
2017-01-15 19:48:27 +01:00
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2016-12-28 16:29:49 +01:00
|
|
|
|
void FVTerm::updateVTerm (term_area* area)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// Update area data on VTerm
|
|
|
|
|
|
2017-12-03 21:34:07 +01:00
|
|
|
|
if ( ! area || ! area->visible )
|
|
|
|
|
return;
|
|
|
|
|
|
2019-01-24 00:23:00 +01:00
|
|
|
|
int ax = area->offset_left;
|
|
|
|
|
int ay = area->offset_top;
|
|
|
|
|
int width = area->width + area->right_shadow;
|
|
|
|
|
int height = area->height + area->bottom_shadow;
|
2019-09-28 03:13:06 +02:00
|
|
|
|
int ol{0}; // Outside left
|
|
|
|
|
int y_end{};
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-12-03 21:06:21 +01:00
|
|
|
|
// Call the processing handler methods
|
|
|
|
|
callPreprocessingHandler(area);
|
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( ax < 0 )
|
|
|
|
|
{
|
|
|
|
|
ol = std::abs(ax);
|
|
|
|
|
ax = 0;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
2016-12-15 23:11:34 +01:00
|
|
|
|
|
2019-01-24 00:23:00 +01:00
|
|
|
|
if ( height + ay > vterm->height )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
y_end = vterm->height - ay;
|
2016-12-15 23:11:34 +01:00
|
|
|
|
else
|
2019-01-24 00:23:00 +01:00
|
|
|
|
y_end = height;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int y{0}; y < y_end; y++) // Line loop
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2019-09-28 03:13:06 +02:00
|
|
|
|
bool modified{false};
|
2016-12-28 16:29:49 +01:00
|
|
|
|
int line_xmin = int(area->changes[y].xmin);
|
|
|
|
|
int line_xmax = int(area->changes[y].xmax);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-12-03 21:06:21 +01:00
|
|
|
|
if ( line_xmin > line_xmax )
|
|
|
|
|
continue;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-12-03 21:06:21 +01:00
|
|
|
|
if ( ax == 0 )
|
|
|
|
|
line_xmin = ol;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-24 00:23:00 +01:00
|
|
|
|
if ( width + ax - ol >= vterm->width )
|
2017-12-03 21:06:21 +01:00
|
|
|
|
line_xmax = vterm->width + ol - ax - 1;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-12-03 21:06:21 +01:00
|
|
|
|
if ( ax + line_xmin >= vterm->width )
|
|
|
|
|
continue;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-12-03 21:06:21 +01:00
|
|
|
|
for (int x = line_xmin; x <= line_xmax; x++) // Column loop
|
|
|
|
|
{
|
|
|
|
|
// Global terminal positions
|
2019-01-21 03:42:18 +01:00
|
|
|
|
int tx = ax + x;
|
|
|
|
|
int ty = ay + y;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-12-03 21:06:21 +01:00
|
|
|
|
if ( tx < 0 || ty < 0 )
|
|
|
|
|
continue;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-12-03 21:06:21 +01:00
|
|
|
|
tx -= ol;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
if ( updateVTermCharacter(area, FPoint(x, y), FPoint(tx, ty)) )
|
2017-12-03 21:06:21 +01:00
|
|
|
|
modified = true;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-12-03 21:06:21 +01:00
|
|
|
|
if ( ! modified )
|
|
|
|
|
line_xmin++; // Don't update covered character
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
|
int _xmin = ax + line_xmin - ol;
|
|
|
|
|
int _xmax = ax + line_xmax;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-12-28 22:57:43 +01:00
|
|
|
|
if ( _xmin < int(vterm->changes[ay + y].xmin) )
|
2017-12-03 21:06:21 +01:00
|
|
|
|
vterm->changes[ay + y].xmin = uInt(_xmin);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-12-03 21:06:21 +01:00
|
|
|
|
if ( _xmax >= vterm->width )
|
|
|
|
|
_xmax = vterm->width - 1;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-12-28 22:57:43 +01:00
|
|
|
|
if ( _xmax > int(vterm->changes[ay + y].xmax) )
|
2017-12-03 21:06:21 +01:00
|
|
|
|
vterm->changes[ay + y].xmax = uInt(_xmax);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2019-01-24 00:23:00 +01:00
|
|
|
|
area->changes[y].xmin = uInt(width);
|
2017-12-03 21:06:21 +01:00
|
|
|
|
area->changes[y].xmax = 0;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2019-08-18 21:35:36 +02:00
|
|
|
|
vterm->has_changes = true;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
updateVTermCursor(area);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2016-12-28 16:29:49 +01:00
|
|
|
|
bool FVTerm::updateVTermCursor (term_area* area)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( ! area )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if ( area != active_area )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if ( ! area->visible )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if ( area->input_cursor_visible )
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// area offset
|
2019-08-25 22:16:00 +02:00
|
|
|
|
int ax = area->offset_left;
|
|
|
|
|
int ay = area->offset_top;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// area cursor position
|
2019-08-25 22:16:00 +02:00
|
|
|
|
int cx = area->input_cursor_x;
|
|
|
|
|
int cy = area->input_cursor_y;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// terminal position
|
2019-08-25 22:16:00 +02:00
|
|
|
|
int x = ax + cx;
|
|
|
|
|
int y = ay + cy;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
if ( isInsideArea (FPoint(cx, cy), area)
|
|
|
|
|
&& isInsideTerminal (FPoint(x, y))
|
|
|
|
|
&& isCovered (FPoint(x, y), area) == non_covered )
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
vterm->input_cursor_x = x;
|
|
|
|
|
vterm->input_cursor_y = y;
|
|
|
|
|
vterm->input_cursor_visible = true;
|
2019-08-18 21:35:36 +02:00
|
|
|
|
vterm->has_changes = true;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return true;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
|
|
|
|
vterm->input_cursor_visible = false;
|
|
|
|
|
return false;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2019-01-21 03:42:18 +01:00
|
|
|
|
bool FVTerm::isInsideArea (const FPoint& pos, term_area* area)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// Check whether the coordinates are within the area
|
2017-10-02 07:32:33 +02:00
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
auto aw = std::size_t(area->width);
|
|
|
|
|
auto ah = std::size_t(area->height);
|
|
|
|
|
FRect area_geometry(0, 0, aw, ah);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
if ( area_geometry.contains(pos) )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return true;
|
|
|
|
|
else
|
|
|
|
|
return false;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2016-12-28 16:29:49 +01:00
|
|
|
|
void FVTerm::setAreaCursor ( const FPoint& pos
|
|
|
|
|
, bool visible
|
|
|
|
|
, term_area* area )
|
|
|
|
|
{
|
|
|
|
|
if ( ! area )
|
|
|
|
|
return;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
area->input_cursor_x = pos.getX() - 1;
|
|
|
|
|
area->input_cursor_y = pos.getY() - 1;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
area->input_cursor_visible = visible;
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::getArea (const FPoint& pos, term_area* area)
|
|
|
|
|
{
|
|
|
|
|
// Copies a block from the virtual terminal position to the given area
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( ! area )
|
2016-11-02 00:37:58 +01:00
|
|
|
|
return;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
int ax = pos.getX() - 1;
|
|
|
|
|
int ay = pos.getY() - 1;
|
2019-09-28 03:13:06 +02:00
|
|
|
|
int y_end{}, length{};
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
|
if ( area->height + ay > vterm->height )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
y_end = area->height - ay;
|
|
|
|
|
else
|
|
|
|
|
y_end = area->height;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
|
if ( area->width + ax > vterm->width )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
length = vterm->width - ax;
|
|
|
|
|
else
|
|
|
|
|
length = area->width;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int y{0}; y < y_end; y++) // line loop
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto tc = &vterm->text[(ay + y) * vterm->width + ax]; // terminal character
|
|
|
|
|
auto ac = &area->text[y * area->width]; // area character
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (ac, tc, sizeof(*ac) * unsigned(length));
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2018-12-28 22:57:43 +01:00
|
|
|
|
if ( int(area->changes[y].xmin) > 0 )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
area->changes[y].xmin = 0;
|
2016-10-14 17:37:26 +02:00
|
|
|
|
|
2018-12-28 22:57:43 +01:00
|
|
|
|
if ( int(area->changes[y].xmax) < length - 1 )
|
2017-08-27 09:50:30 +02:00
|
|
|
|
area->changes[y].xmax = uInt(length - 1);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-14 17:37:26 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::getArea (const FRect& box, term_area* area)
|
|
|
|
|
{
|
|
|
|
|
// Copies a block from the virtual terminal rectangle to the given area
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( ! area )
|
|
|
|
|
return;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
int x = box.getX();
|
|
|
|
|
int y = box.getY();
|
|
|
|
|
int w = int(box.getWidth());
|
|
|
|
|
int h = int(box.getHeight());
|
|
|
|
|
int dx = x - area->offset_left + 1;
|
|
|
|
|
int dy = y - area->offset_top + 1;
|
2019-08-25 22:16:00 +02:00
|
|
|
|
int y_end{}, length{};
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( x < 0 || y < 0 )
|
|
|
|
|
return;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
|
if ( y - 1 + h > vterm->height )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
y_end = vterm->height - y + 1;
|
|
|
|
|
else
|
|
|
|
|
y_end = h - 1;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
|
if ( x - 1 + w > vterm->width )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
length = vterm->width - x + 1;
|
|
|
|
|
else
|
|
|
|
|
length = w;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( length < 1 )
|
|
|
|
|
return;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
|
for (int _y = 0; _y < y_end; _y++) // line loop
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
int line_len = area->width + area->right_shadow;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto tc = &vterm->text[(y + _y - 1) * vterm->width + x - 1]; // terminal character
|
|
|
|
|
auto ac = &area->text[(dy + _y) * line_len + dx]; // area character
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (ac, tc, sizeof(*ac) * unsigned(length));
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2018-12-28 22:57:43 +01:00
|
|
|
|
if ( int(area->changes[dy + _y].xmin) > dx )
|
2017-08-27 09:50:30 +02:00
|
|
|
|
area->changes[dy + _y].xmin = uInt(dx);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2018-12-28 22:57:43 +01:00
|
|
|
|
if ( int(area->changes[dy + _y].xmax) < dx + length - 1 )
|
2017-08-27 09:50:30 +02:00
|
|
|
|
area->changes[dy + _y].xmax = uInt(dx + length - 1);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-10-13 02:16:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2016-12-28 16:29:49 +01:00
|
|
|
|
void FVTerm::putArea (const FPoint& pos, term_area* area)
|
2016-10-13 02:16:51 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// Copies the given area block to the virtual terminal position
|
2018-02-08 00:25:51 +01:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
charData* tc{}; // terminal character
|
|
|
|
|
charData* ac{}; // area character
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-24 00:23:00 +01:00
|
|
|
|
if ( ! area || ! area->visible )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-24 00:23:00 +01:00
|
|
|
|
int ax = pos.getX() - 1;
|
|
|
|
|
int ay = pos.getY() - 1;
|
|
|
|
|
int width = area->width + area->right_shadow;
|
|
|
|
|
int height = area->height + area->bottom_shadow;
|
2019-09-28 03:13:06 +02:00
|
|
|
|
int ol{0}; // outside left
|
2019-08-25 22:16:00 +02:00
|
|
|
|
int y_end{}, length{};
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( ax < 0 )
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
ol = std::abs(ax);
|
|
|
|
|
ax = 0;
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-24 00:23:00 +01:00
|
|
|
|
if ( ay + height > vterm->height )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
y_end = vterm->height - ay;
|
|
|
|
|
else
|
2019-01-24 00:23:00 +01:00
|
|
|
|
y_end = height;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-24 00:23:00 +01:00
|
|
|
|
if ( width - ol + ax > vterm->width )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
length = vterm->width - ax;
|
|
|
|
|
else
|
2019-01-24 00:23:00 +01:00
|
|
|
|
length = width - ol;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( length < 1 )
|
|
|
|
|
return;
|
2016-10-14 13:02:35 +02:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int y{0}; y < y_end; y++) // line loop
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
if ( area->changes[y].trans_count == 0 )
|
|
|
|
|
{
|
|
|
|
|
// Line has only covered characters
|
2019-01-24 00:23:00 +01:00
|
|
|
|
ac = &area->text[y * width + ol];
|
2018-12-17 00:50:24 +01:00
|
|
|
|
tc = &vterm->text[(ay + y) * vterm->width + ax];
|
2018-02-08 00:25:51 +01:00
|
|
|
|
putAreaLine (ac, tc, length);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Line has one or more transparent characters
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int x{0}; x < length; x++) // column loop
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2018-02-08 00:25:51 +01:00
|
|
|
|
int cx = ax + x;
|
|
|
|
|
int cy = ay + y;
|
2019-01-24 00:23:00 +01:00
|
|
|
|
ac = &area->text[y * width + ol + x];
|
2018-02-08 00:25:51 +01:00
|
|
|
|
tc = &vterm->text[cy * vterm->width + cx];
|
2019-01-21 03:42:18 +01:00
|
|
|
|
putAreaCharacter (FPoint(cx + 1, cy + 1), area->widget, ac, tc);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-28 22:57:43 +01:00
|
|
|
|
if ( ax < int(vterm->changes[ay + y].xmin) )
|
2017-08-27 09:50:30 +02:00
|
|
|
|
vterm->changes[ay + y].xmin = uInt(ax);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2018-12-28 22:57:43 +01:00
|
|
|
|
if ( ax + length - 1 > int(vterm->changes[ay + y].xmax) )
|
2017-08-27 09:50:30 +02:00
|
|
|
|
vterm->changes[ay + y].xmax = uInt(ax + length - 1);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2019-08-18 21:35:36 +02:00
|
|
|
|
|
|
|
|
|
vterm->has_changes = true;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2016-12-28 16:29:49 +01:00
|
|
|
|
void FVTerm::scrollAreaForward (term_area* area)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// Scrolls the entire area up line down
|
2019-08-25 22:16:00 +02:00
|
|
|
|
charData nc{}; // next character
|
|
|
|
|
charData* lc{}; // last character
|
|
|
|
|
charData* dc{}; // destination character
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( ! area )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ( area->height <= 1 )
|
|
|
|
|
return;
|
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
int length = area->width;
|
|
|
|
|
int total_width = area->width + area->right_shadow;
|
|
|
|
|
int y_max = area->height - 1;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int y{0}; y < y_max; y++)
|
2016-12-18 23:34:11 +01:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
int pos1 = y * total_width;
|
2017-08-27 09:50:30 +02:00
|
|
|
|
int pos2 = (y + 1) * total_width;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto sc = &area->text[pos2]; // source character
|
2016-12-28 16:29:49 +01:00
|
|
|
|
dc = &area->text[pos1];
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (dc, sc, sizeof(*dc) * unsigned(length));
|
2016-12-28 16:29:49 +01:00
|
|
|
|
area->changes[y].xmin = 0;
|
|
|
|
|
area->changes[y].xmax = uInt(area->width - 1);
|
2016-12-18 23:34:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// insert a new line below
|
|
|
|
|
lc = &area->text[(y_max * total_width) - area->right_shadow - 1];
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (&nc, lc, sizeof(nc));
|
2016-12-28 16:29:49 +01:00
|
|
|
|
nc.code = ' ';
|
|
|
|
|
dc = &area->text[y_max * total_width];
|
|
|
|
|
std::fill_n (dc, area->width, nc);
|
|
|
|
|
area->changes[y_max].xmin = 0;
|
|
|
|
|
area->changes[y_max].xmax = uInt(area->width - 1);
|
|
|
|
|
area->has_changes = true;
|
2016-12-18 23:34:11 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( area == vdesktop )
|
|
|
|
|
{
|
2017-09-11 03:06:02 +02:00
|
|
|
|
if ( TCAP(fc::t_scroll_forward) )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
setTermXY (0, vdesktop->height);
|
2018-10-29 23:57:35 +01:00
|
|
|
|
FTerm::scrollTermForward();
|
2019-01-21 03:42:18 +01:00
|
|
|
|
putArea (FPoint(1, 1), vdesktop);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
|
// avoid update lines from 0 to (y_max - 1)
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int y{0}; y < y_max; y++)
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
area->changes[y].xmin = uInt(area->width - 1);
|
|
|
|
|
area->changes[y].xmax = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::scrollAreaReverse (term_area* area)
|
|
|
|
|
{
|
|
|
|
|
// Scrolls the entire area one line down
|
2019-08-25 22:16:00 +02:00
|
|
|
|
|
|
|
|
|
charData nc{}; // next character
|
|
|
|
|
charData* lc{}; // last character
|
|
|
|
|
charData* dc{}; // destination character
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
|
|
|
|
if ( ! area )
|
2016-12-18 23:34:11 +01:00
|
|
|
|
return;
|
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( area->height <= 1 )
|
|
|
|
|
return;
|
2016-12-18 23:34:11 +01:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
int length = area->width;
|
|
|
|
|
int total_width = area->width + area->right_shadow;
|
|
|
|
|
int y_max = area->height - 1;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
|
for (int y = y_max; y > 0; y--)
|
2016-12-18 23:34:11 +01:00
|
|
|
|
{
|
2017-08-27 09:50:30 +02:00
|
|
|
|
int pos1 = (y - 1) * total_width;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
int pos2 = y * total_width;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto sc = &area->text[pos1]; // source character
|
2016-12-28 16:29:49 +01:00
|
|
|
|
dc = &area->text[pos2];
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (dc, sc, sizeof(*dc) * unsigned(length));
|
2016-12-28 16:29:49 +01:00
|
|
|
|
area->changes[y].xmin = 0;
|
|
|
|
|
area->changes[y].xmax = uInt(area->width - 1);
|
|
|
|
|
}
|
2016-12-18 23:34:11 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// insert a new line above
|
|
|
|
|
lc = &area->text[total_width];
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (&nc, lc, sizeof(nc));
|
2016-12-28 16:29:49 +01:00
|
|
|
|
nc.code = ' ';
|
|
|
|
|
dc = &area->text[0];
|
|
|
|
|
std::fill_n (dc, area->width, nc);
|
|
|
|
|
area->changes[0].xmin = 0;
|
|
|
|
|
area->changes[0].xmax = uInt(area->width - 1);
|
|
|
|
|
area->has_changes = true;
|
2016-12-18 23:34:11 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( area == vdesktop )
|
|
|
|
|
{
|
2017-09-11 03:06:02 +02:00
|
|
|
|
if ( TCAP(fc::t_scroll_reverse) )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
setTermXY (0, 0);
|
2018-10-29 23:57:35 +01:00
|
|
|
|
FTerm::scrollTermReverse();
|
2019-01-21 03:42:18 +01:00
|
|
|
|
putArea (FPoint(1, 1), vdesktop);
|
2016-12-18 23:34:11 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// avoid update lines from 1 to y_max
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int y{1}; y <= y_max; y++)
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
area->changes[y].xmin = uInt(area->width - 1);
|
|
|
|
|
area->changes[y].xmax = 0;
|
|
|
|
|
}
|
2016-12-18 23:34:11 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2016-12-28 16:29:49 +01:00
|
|
|
|
void FVTerm::clearArea (term_area* area, int fillchar)
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2018-02-08 00:25:51 +01:00
|
|
|
|
// Clear the area with the current attributes
|
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
charData nc{}; // next character
|
2016-12-18 23:34:11 +01:00
|
|
|
|
|
2018-02-08 00:25:51 +01:00
|
|
|
|
// Current attributes with a space character
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (&nc, &next_attribute, sizeof(nc));
|
2016-12-28 16:29:49 +01:00
|
|
|
|
nc.code = fillchar;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-01-03 05:19:44 +01:00
|
|
|
|
if ( ! (area && area->text) )
|
2018-05-27 19:43:18 +02:00
|
|
|
|
{
|
|
|
|
|
clearTerm (fillchar);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
return;
|
2018-05-27 19:43:18 +02:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-12-15 00:50:09 +01:00
|
|
|
|
uInt w = uInt(area->width + area->right_shadow);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( area->right_shadow == 0 )
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2018-02-08 00:25:51 +01:00
|
|
|
|
if ( clearFullArea(area, nc) )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
2016-12-28 16:29:49 +01:00
|
|
|
|
else
|
2018-02-08 00:25:51 +01:00
|
|
|
|
clearAreaWithShadow(area, nc);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int i{0}; i < area->height; i++)
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
area->changes[i].xmin = 0;
|
|
|
|
|
area->changes[i].xmax = w - 1;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-08-20 17:30:30 +02:00
|
|
|
|
if ( nc.attr.bit.transparent
|
2017-11-26 22:37:18 +01:00
|
|
|
|
|| nc.attr.bit.trans_shadow
|
|
|
|
|
|| nc.attr.bit.inherit_bg )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
area->changes[i].trans_count = w;
|
|
|
|
|
else if ( area->right_shadow != 0 )
|
|
|
|
|
area->changes[i].trans_count = uInt(area->right_shadow);
|
|
|
|
|
else
|
|
|
|
|
area->changes[i].trans_count = 0;
|
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int i{0}; i < area->bottom_shadow; i++)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
int y = area->height + i;
|
|
|
|
|
area->changes[y].xmin = 0;
|
|
|
|
|
area->changes[y].xmax = w - 1;
|
|
|
|
|
area->changes[y].trans_count = w;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
area->has_changes = true;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-05 00:49:00 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2019-07-21 23:31:21 +02:00
|
|
|
|
charData FVTerm::generateCharacter (const FPoint& pos)
|
2018-01-05 00:49:00 +01:00
|
|
|
|
{
|
|
|
|
|
// Generates characters for a given position considering all areas
|
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
int x = pos.getX();
|
2019-08-25 22:16:00 +02:00
|
|
|
|
int y = pos.getY();
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto sc = &vdesktop->text[y * vdesktop->width + x]; // shown character
|
2018-01-05 00:49:00 +01:00
|
|
|
|
|
2019-09-01 23:29:27 +02:00
|
|
|
|
if ( ! FWidget::getWindowList() || FWidget::getWindowList()->empty() )
|
2018-01-05 00:49:00 +01:00
|
|
|
|
return *sc;
|
|
|
|
|
|
2019-09-01 23:29:27 +02:00
|
|
|
|
for (auto& win_obj : *FWidget::getWindowList())
|
2018-01-05 00:49:00 +01:00
|
|
|
|
{
|
2018-12-15 22:10:31 +01:00
|
|
|
|
auto win = win_obj->getVWin();
|
2018-01-05 00:49:00 +01:00
|
|
|
|
|
|
|
|
|
if ( ! win || ! win->visible )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
int win_x = win->offset_left;
|
|
|
|
|
int win_y = win->offset_top;
|
|
|
|
|
FRect geometry ( win_x
|
|
|
|
|
, win_y
|
2019-09-09 19:13:38 +02:00
|
|
|
|
, std::size_t(win->width) + std::size_t(win->right_shadow)
|
|
|
|
|
, std::size_t(win->height) + std::size_t(win->bottom_shadow) );
|
2018-01-05 00:49:00 +01:00
|
|
|
|
|
|
|
|
|
// Window is visible and contains current character
|
|
|
|
|
if ( geometry.contains(x, y) )
|
|
|
|
|
{
|
|
|
|
|
int line_len = win->width + win->right_shadow;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto tmp = &win->text[(y - win_y) * line_len + (x - win_x)];
|
2018-01-05 00:49:00 +01:00
|
|
|
|
|
|
|
|
|
if ( ! tmp->attr.bit.transparent ) // Current character not transparent
|
|
|
|
|
{
|
|
|
|
|
if ( tmp->attr.bit.trans_shadow ) // Transparent shadow
|
|
|
|
|
{
|
|
|
|
|
// Keep the current vterm character
|
2019-07-29 02:34:58 +02:00
|
|
|
|
if ( sc != &s_ch )
|
|
|
|
|
std::memcpy (&s_ch, sc, sizeof(s_ch));
|
|
|
|
|
|
2018-01-05 00:49:00 +01:00
|
|
|
|
s_ch.fg_color = tmp->fg_color;
|
|
|
|
|
s_ch.bg_color = tmp->bg_color;
|
|
|
|
|
s_ch.attr.bit.reverse = false;
|
|
|
|
|
s_ch.attr.bit.standout = false;
|
|
|
|
|
|
|
|
|
|
if ( s_ch.code == fc::LowerHalfBlock
|
|
|
|
|
|| s_ch.code == fc::UpperHalfBlock
|
|
|
|
|
|| s_ch.code == fc::LeftHalfBlock
|
|
|
|
|
|| s_ch.code == fc::RightHalfBlock
|
|
|
|
|
|| s_ch.code == fc::MediumShade
|
|
|
|
|
|| s_ch.code == fc::FullBlock )
|
|
|
|
|
s_ch.code = ' ';
|
|
|
|
|
|
|
|
|
|
sc = &s_ch;
|
|
|
|
|
}
|
|
|
|
|
else if ( tmp->attr.bit.inherit_bg )
|
|
|
|
|
{
|
|
|
|
|
// Add the covered background to this character
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (&i_ch, tmp, sizeof(i_ch));
|
2018-01-05 00:49:00 +01:00
|
|
|
|
i_ch.bg_color = sc->bg_color; // Last background color
|
|
|
|
|
sc = &i_ch;
|
|
|
|
|
}
|
|
|
|
|
else // Default
|
|
|
|
|
sc = tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *sc;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-11 04:57:36 +02:00
|
|
|
|
//----------------------------------------------------------------------
|
2019-07-21 23:31:21 +02:00
|
|
|
|
charData FVTerm::getCharacter ( character_type char_type
|
|
|
|
|
, const FPoint& pos
|
|
|
|
|
, FVTerm* obj )
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// Gets the overlapped or the covered character for a given position
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
int x = pos.getX() - 1;
|
|
|
|
|
int y = pos.getY() - 1;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
int xx = x;
|
|
|
|
|
int yy = y;
|
2016-10-15 03:32:30 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( xx < 0 )
|
|
|
|
|
xx = 0;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( yy < 0 )
|
|
|
|
|
yy = 0;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( xx >= vterm->width )
|
|
|
|
|
xx = vterm->width - 1;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( yy >= vterm->height )
|
|
|
|
|
yy = vterm->height - 1;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto cc = &vdesktop->text[yy * vdesktop->width + xx]; // covered character
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-09-01 23:29:27 +02:00
|
|
|
|
if ( ! FWidget::getWindowList() || FWidget::getWindowList()->empty() )
|
2018-02-10 17:35:09 +01:00
|
|
|
|
return *cc;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-02-10 17:35:09 +01:00
|
|
|
|
// Get the window layer of this object
|
2018-12-22 15:33:23 +01:00
|
|
|
|
auto w = static_cast<FWidget*>(obj);
|
2018-12-15 00:50:09 +01:00
|
|
|
|
int layer = FWindow::getWindowLayer(w);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-09-01 23:29:27 +02:00
|
|
|
|
for (auto&& win_obj : *FWidget::getWindowList())
|
2018-02-10 17:35:09 +01:00
|
|
|
|
{
|
|
|
|
|
bool significant_char;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-02-10 17:35:09 +01:00
|
|
|
|
// char_type can be "overlapped_character"
|
|
|
|
|
// or "covered_character"
|
|
|
|
|
if ( char_type == covered_character )
|
2018-12-15 22:10:31 +01:00
|
|
|
|
significant_char = bool(layer >= FWindow::getWindowLayer(win_obj));
|
2018-02-10 17:35:09 +01:00
|
|
|
|
else
|
2018-12-15 22:10:31 +01:00
|
|
|
|
significant_char = bool(layer < FWindow::getWindowLayer(win_obj));
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-12-15 22:10:31 +01:00
|
|
|
|
if ( obj && win_obj != obj && significant_char )
|
2018-02-10 17:35:09 +01:00
|
|
|
|
{
|
2018-12-15 22:10:31 +01:00
|
|
|
|
auto win = win_obj->getVWin();
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2018-02-10 17:35:09 +01:00
|
|
|
|
if ( ! win || ! win->visible )
|
|
|
|
|
continue;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2018-02-10 17:35:09 +01:00
|
|
|
|
FRect geometry ( win->offset_left
|
|
|
|
|
, win->offset_top
|
2019-09-09 19:13:38 +02:00
|
|
|
|
, std::size_t(win->width) + std::size_t(win->right_shadow)
|
|
|
|
|
, std::size_t(win->height) + std::size_t(win->bottom_shadow) );
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2018-02-10 17:35:09 +01:00
|
|
|
|
// Window visible and contains current character
|
|
|
|
|
if ( geometry.contains(x, y) )
|
2019-01-21 03:42:18 +01:00
|
|
|
|
getAreaCharacter (FPoint(x, y), win, cc);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2018-02-10 17:35:09 +01:00
|
|
|
|
else if ( char_type == covered_character )
|
|
|
|
|
break;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
|
|
|
|
return *cc;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2019-07-21 23:31:21 +02:00
|
|
|
|
charData FVTerm::getCoveredCharacter (const FPoint& pos, FVTerm* obj)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// Gets the covered character for a given position
|
2019-01-21 03:42:18 +01:00
|
|
|
|
return getCharacter (covered_character, pos, obj);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2019-07-21 23:31:21 +02:00
|
|
|
|
charData FVTerm::getOverlappedCharacter (const FPoint& pos, FVTerm* obj)
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
// Gets the overlapped character for a given position
|
2019-01-21 03:42:18 +01:00
|
|
|
|
return getCharacter (overlapped_character, pos, obj);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::processTerminalUpdate()
|
|
|
|
|
{
|
|
|
|
|
// Retains terminal updates if there are unprocessed inputs
|
2018-12-26 23:41:49 +01:00
|
|
|
|
static constexpr int max_skip = 8;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-01-15 19:48:27 +01:00
|
|
|
|
if ( ! terminal_update_pending )
|
|
|
|
|
return;
|
|
|
|
|
|
2018-07-15 19:52:59 +02:00
|
|
|
|
if ( ! keyboard->isInputDataPending() )
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2017-01-15 19:48:27 +01:00
|
|
|
|
updateTerminal();
|
|
|
|
|
terminal_update_pending = false;
|
|
|
|
|
skipped_terminal_update = 0;
|
|
|
|
|
}
|
|
|
|
|
else if ( skipped_terminal_update > max_skip )
|
|
|
|
|
{
|
|
|
|
|
force_terminal_update = true;
|
|
|
|
|
updateTerminal();
|
|
|
|
|
force_terminal_update = false;
|
|
|
|
|
terminal_update_pending = false;
|
|
|
|
|
skipped_terminal_update = 0;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2017-01-15 19:48:27 +01:00
|
|
|
|
else
|
|
|
|
|
skipped_terminal_update++;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2016-12-28 16:29:49 +01:00
|
|
|
|
void FVTerm::startTerminalUpdate()
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// Pauses the terminal updates for the printing phase
|
|
|
|
|
terminal_update_complete = false;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2016-12-28 16:29:49 +01:00
|
|
|
|
void FVTerm::finishTerminalUpdate()
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// After the printing phase is completed, the terminal will be updated
|
|
|
|
|
terminal_update_complete = true;
|
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::flush_out()
|
|
|
|
|
{
|
|
|
|
|
while ( ! output_buffer->empty() )
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2018-10-29 23:57:35 +01:00
|
|
|
|
FTerm::Fputchar(output_buffer->front());
|
2016-12-28 16:29:49 +01:00
|
|
|
|
output_buffer->pop();
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
std::fflush(stdout);
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// private methods of FVTerm
|
2016-10-11 04:57:36 +02:00
|
|
|
|
//----------------------------------------------------------------------
|
2018-10-29 00:45:45 +01:00
|
|
|
|
void FVTerm::init (bool disable_alt_screen)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2018-02-04 19:42:30 +01:00
|
|
|
|
init_object = this;
|
2018-12-10 01:48:26 +01:00
|
|
|
|
vterm = nullptr;
|
|
|
|
|
vdesktop = nullptr;
|
2019-07-01 01:07:54 +02:00
|
|
|
|
fsystem = FTerm::getFSystem();
|
2017-08-12 22:55:29 +02:00
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2018-10-29 00:45:45 +01:00
|
|
|
|
fterm = new FTerm (disable_alt_screen);
|
2017-09-11 03:06:02 +02:00
|
|
|
|
term_pos = new FPoint(-1, -1);
|
2017-08-12 22:55:29 +02:00
|
|
|
|
output_buffer = new std::queue<int>;
|
|
|
|
|
}
|
|
|
|
|
catch (const std::bad_alloc& ex)
|
|
|
|
|
{
|
2018-11-22 21:51:32 +01:00
|
|
|
|
std::cerr << bad_alloc_str << ex.what() << std::endl;
|
2017-08-12 22:55:29 +02:00
|
|
|
|
std::abort();
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// term_attribute stores the current state of the terminal
|
2018-02-04 19:42:30 +01:00
|
|
|
|
term_attribute.code = '\0';
|
|
|
|
|
term_attribute.fg_color = fc::Default;
|
|
|
|
|
term_attribute.bg_color = fc::Default;
|
|
|
|
|
term_attribute.attr.byte[0] = 0;
|
|
|
|
|
term_attribute.attr.byte[0] = 0;
|
|
|
|
|
term_attribute.attr.byte[0] = 0;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// next_attribute contains the state of the next printed character
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (&next_attribute, &term_attribute, sizeof(next_attribute));
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2018-07-01 14:48:53 +02:00
|
|
|
|
// Create virtual terminal
|
2016-12-28 16:29:49 +01:00
|
|
|
|
FRect term_geometry (0, 0, getColumnNumber(), getLineNumber());
|
2019-01-21 03:42:18 +01:00
|
|
|
|
createVTerm (term_geometry.getSize());
|
2016-12-18 23:34:11 +01:00
|
|
|
|
|
2018-07-01 14:48:53 +02:00
|
|
|
|
// Create virtual desktop area
|
2019-01-16 16:00:15 +01:00
|
|
|
|
FSize shadow_size(0, 0);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
createArea (term_geometry, shadow_size, vdesktop);
|
|
|
|
|
vdesktop->visible = true;
|
|
|
|
|
active_area = vdesktop;
|
2016-12-18 23:34:11 +01:00
|
|
|
|
|
2019-05-27 00:50:11 +02:00
|
|
|
|
// Get FKeyboard object
|
|
|
|
|
keyboard = FTerm::getFKeyboard();
|
2018-07-15 19:52:59 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// Hide the input cursor
|
|
|
|
|
hideCursor();
|
2018-07-01 14:48:53 +02:00
|
|
|
|
|
|
|
|
|
// Initialize character lengths
|
2018-10-29 23:57:35 +01:00
|
|
|
|
init_characterLengths (FTerm::getFOptiMove());
|
2018-07-01 14:48:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-09-02 03:57:57 +02:00
|
|
|
|
void FVTerm::init_characterLengths (FOptiMove* optimove)
|
2018-07-01 14:48:53 +02:00
|
|
|
|
{
|
2018-09-02 03:57:57 +02:00
|
|
|
|
if ( optimove )
|
2018-07-01 14:48:53 +02:00
|
|
|
|
{
|
2018-09-02 03:57:57 +02:00
|
|
|
|
cursor_address_length = optimove->getCursorAddressLength();
|
|
|
|
|
erase_char_length = optimove->getEraseCharsLength();
|
|
|
|
|
repeat_char_length = optimove->getRepeatCharLength();
|
|
|
|
|
clr_bol_length = optimove->getClrBolLength();
|
|
|
|
|
clr_eol_length = optimove->getClrEolLength();
|
2018-07-01 14:48:53 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cursor_address_length = INT_MAX;
|
|
|
|
|
erase_char_length = INT_MAX;
|
|
|
|
|
repeat_char_length = INT_MAX;
|
|
|
|
|
clr_bol_length = INT_MAX;
|
|
|
|
|
clr_eol_length = INT_MAX;
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2016-12-28 16:29:49 +01:00
|
|
|
|
void FVTerm::finish()
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// Show the input cursor
|
|
|
|
|
showCursor();
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// Clear the terminal
|
|
|
|
|
setNormal();
|
2017-03-26 20:40:04 +02:00
|
|
|
|
|
2018-10-29 23:57:35 +01:00
|
|
|
|
if ( FTerm::hasAlternateScreen() )
|
2017-03-26 20:40:04 +02:00
|
|
|
|
clearTerm();
|
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
flush_out();
|
|
|
|
|
|
|
|
|
|
if ( output_buffer )
|
|
|
|
|
delete output_buffer;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// remove virtual terminal + virtual desktop area
|
|
|
|
|
removeArea (vdesktop);
|
|
|
|
|
removeArea (vterm);
|
2016-10-14 13:02:35 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( term_pos )
|
|
|
|
|
delete term_pos;
|
2018-10-29 00:45:45 +01:00
|
|
|
|
|
|
|
|
|
if ( fterm )
|
|
|
|
|
delete fterm;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-02-08 00:25:51 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2018-06-25 00:14:53 +02:00
|
|
|
|
void FVTerm::putAreaLine (charData* ac, charData* tc, int length)
|
2018-02-08 00:25:51 +01:00
|
|
|
|
{
|
|
|
|
|
// copy "length" characters from area to terminal
|
|
|
|
|
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (tc, ac, sizeof(*tc) * unsigned(length));
|
2018-02-08 00:25:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2019-01-21 03:42:18 +01:00
|
|
|
|
void FVTerm::putAreaCharacter ( const FPoint& pos, FVTerm* obj
|
2018-06-25 00:14:53 +02:00
|
|
|
|
, charData* ac
|
|
|
|
|
, charData* tc )
|
2018-02-08 00:25:51 +01:00
|
|
|
|
{
|
|
|
|
|
if ( ac->attr.bit.transparent ) // Transparent
|
|
|
|
|
{
|
|
|
|
|
// Restore one character on vterm
|
2019-08-25 22:16:00 +02:00
|
|
|
|
charData ch = getCoveredCharacter (pos, obj);
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (tc, &ch, sizeof(*tc));
|
2018-02-08 00:25:51 +01:00
|
|
|
|
}
|
|
|
|
|
else // Mot transparent
|
|
|
|
|
{
|
|
|
|
|
if ( ac->attr.bit.trans_shadow ) // Transparent shadow
|
|
|
|
|
{
|
|
|
|
|
// Get covered character + add the current color
|
2019-08-25 22:16:00 +02:00
|
|
|
|
charData ch = getCoveredCharacter (pos, obj);
|
2018-02-08 00:25:51 +01:00
|
|
|
|
ch.fg_color = ac->fg_color;
|
|
|
|
|
ch.bg_color = ac->bg_color;
|
|
|
|
|
ch.attr.bit.reverse = false;
|
|
|
|
|
ch.attr.bit.standout = false;
|
|
|
|
|
|
|
|
|
|
if ( ch.code == fc::LowerHalfBlock
|
|
|
|
|
|| ch.code == fc::UpperHalfBlock
|
|
|
|
|
|| ch.code == fc::LeftHalfBlock
|
|
|
|
|
|| ch.code == fc::RightHalfBlock
|
|
|
|
|
|| ch.code == fc::MediumShade
|
|
|
|
|
|| ch.code == fc::FullBlock )
|
|
|
|
|
ch.code = ' ';
|
|
|
|
|
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (tc, &ch, sizeof(*tc));
|
2018-02-08 00:25:51 +01:00
|
|
|
|
}
|
|
|
|
|
else if ( ac->attr.bit.inherit_bg )
|
|
|
|
|
{
|
|
|
|
|
// Add the covered background to this character
|
2019-08-25 22:16:00 +02:00
|
|
|
|
charData ch{};
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (&ch, ac, sizeof(ch));
|
2019-08-25 22:16:00 +02:00
|
|
|
|
charData cc = getCoveredCharacter (pos, obj);
|
2018-02-08 00:25:51 +01:00
|
|
|
|
ch.bg_color = cc.bg_color;
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (tc, &ch, sizeof(*tc));
|
2018-02-08 00:25:51 +01:00
|
|
|
|
}
|
|
|
|
|
else // Default
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (tc, ac, sizeof(*tc));
|
2018-02-08 00:25:51 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-10 17:35:09 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2019-01-21 03:42:18 +01:00
|
|
|
|
void FVTerm::getAreaCharacter ( const FPoint& pos, term_area* area
|
2018-06-25 00:14:53 +02:00
|
|
|
|
, charData*& cc )
|
2018-02-10 17:35:09 +01:00
|
|
|
|
{
|
|
|
|
|
int area_x = area->offset_left;
|
|
|
|
|
int area_y = area->offset_top;
|
|
|
|
|
int line_len = area->width + area->right_shadow;
|
2019-01-21 03:42:18 +01:00
|
|
|
|
int x = pos.getX();
|
|
|
|
|
int y = pos.getY();
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto tmp = &area->text[(y - area_y) * line_len + (x - area_x)];
|
2018-02-10 17:35:09 +01:00
|
|
|
|
|
|
|
|
|
// Current character not transparent
|
|
|
|
|
if ( ! tmp->attr.bit.transparent )
|
|
|
|
|
{
|
|
|
|
|
if ( tmp->attr.bit.trans_shadow ) // transparent shadow
|
|
|
|
|
{
|
|
|
|
|
// Keep the current vterm character
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (&s_ch, cc, sizeof(s_ch));
|
2018-02-10 17:35:09 +01:00
|
|
|
|
s_ch.fg_color = tmp->fg_color;
|
|
|
|
|
s_ch.bg_color = tmp->bg_color;
|
|
|
|
|
s_ch.attr.bit.reverse = false;
|
|
|
|
|
s_ch.attr.bit.standout = false;
|
|
|
|
|
cc = &s_ch;
|
|
|
|
|
}
|
|
|
|
|
else if ( tmp->attr.bit.inherit_bg )
|
|
|
|
|
{
|
|
|
|
|
// Add the covered background to this character
|
2018-11-07 22:06:58 +01:00
|
|
|
|
std::memcpy (&i_ch, tmp, sizeof(i_ch));
|
2018-02-10 17:35:09 +01:00
|
|
|
|
i_ch.bg_color = cc->bg_color; // last background color
|
|
|
|
|
cc = &i_ch;
|
|
|
|
|
}
|
|
|
|
|
else // default
|
|
|
|
|
cc = tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
bool FVTerm::clearTerm (int fillchar)
|
|
|
|
|
{
|
|
|
|
|
// Clear the real terminal and put cursor at home
|
2018-02-08 00:25:51 +01:00
|
|
|
|
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto& cl = TCAP(fc::t_clear_screen);
|
|
|
|
|
auto& cd = TCAP(fc::t_clr_eos);
|
|
|
|
|
auto& cb = TCAP(fc::t_clr_eol);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
bool ut = FTermcap::background_color_erase;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto next = &next_attribute;
|
2018-10-29 23:57:35 +01:00
|
|
|
|
bool normal = FTerm::isNormal(next);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
appendAttributes(next);
|
|
|
|
|
|
|
|
|
|
if ( ! ( (cl || cd || cb) && (normal || ut) )
|
2017-11-26 22:37:18 +01:00
|
|
|
|
|| fillchar != ' ' )
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return false;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-02-08 00:25:51 +01:00
|
|
|
|
if ( cl ) // Clear screen
|
2016-12-18 23:34:11 +01:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
appendOutputBuffer (cl);
|
2018-11-20 21:11:04 +01:00
|
|
|
|
term_pos->setPoint(0, 0);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2018-02-08 00:25:51 +01:00
|
|
|
|
else if ( cd ) // Clear to end of screen
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
setTermXY (0, 0);
|
|
|
|
|
appendOutputBuffer (cd);
|
2017-09-11 03:06:02 +02:00
|
|
|
|
term_pos->setPoint(-1, -1);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2018-02-08 00:25:51 +01:00
|
|
|
|
else if ( cb ) // Clear to end of line
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
2017-09-11 03:06:02 +02:00
|
|
|
|
term_pos->setPoint(-1, -1);
|
2016-12-18 23:34:11 +01:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int i{0}; i < int(getLineNumber()); i++)
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
setTermXY (0, i);
|
|
|
|
|
appendOutputBuffer (cb);
|
2016-12-18 23:34:11 +01:00
|
|
|
|
}
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2018-11-20 21:11:04 +01:00
|
|
|
|
setTermXY (0, 0);
|
2016-12-18 23:34:11 +01:00
|
|
|
|
}
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
|
|
|
|
flush_out();
|
|
|
|
|
return true;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-02-08 00:25:51 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2018-06-25 00:14:53 +02:00
|
|
|
|
bool FVTerm::clearFullArea (term_area* area, charData& nc)
|
2018-02-08 00:25:51 +01:00
|
|
|
|
{
|
|
|
|
|
// Clear area
|
|
|
|
|
int area_size = area->width * area->height;
|
|
|
|
|
std::fill_n (area->text, area_size, nc);
|
|
|
|
|
|
|
|
|
|
if ( area != vdesktop ) // Is the area identical to the desktop?
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Try to clear the terminal rapidly with a control sequence
|
|
|
|
|
if ( clearTerm (nc.code) )
|
|
|
|
|
{
|
|
|
|
|
nc.attr.bit.printed = true;
|
|
|
|
|
std::fill_n (vterm->text, area_size, nc);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int i{0}; i < vdesktop->height; i++)
|
2018-02-08 00:25:51 +01:00
|
|
|
|
{
|
|
|
|
|
vdesktop->changes[i].xmin = 0;
|
|
|
|
|
vdesktop->changes[i].xmax = uInt(vdesktop->width) - 1;
|
|
|
|
|
vdesktop->changes[i].trans_count = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vdesktop->has_changes = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-06-25 00:14:53 +02:00
|
|
|
|
void FVTerm::clearAreaWithShadow (term_area* area, charData& nc)
|
2018-02-08 00:25:51 +01:00
|
|
|
|
{
|
2018-06-25 00:14:53 +02:00
|
|
|
|
charData t_char = nc;
|
2018-02-08 00:25:51 +01:00
|
|
|
|
int total_width = area->width + area->right_shadow;
|
|
|
|
|
t_char.attr.bit.transparent = true;
|
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int y{0}; y < area->height; y++)
|
2018-02-08 00:25:51 +01:00
|
|
|
|
{
|
|
|
|
|
int pos = y * total_width;
|
|
|
|
|
// Clear area
|
|
|
|
|
std::fill_n (&area->text[pos], total_width, nc);
|
|
|
|
|
// Make right shadow transparent
|
|
|
|
|
std::fill_n (&area->text[pos + area->width], area->right_shadow, t_char);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make bottom shadow transparent
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (int y{0}; y < area->bottom_shadow; y++)
|
2018-02-08 00:25:51 +01:00
|
|
|
|
{
|
|
|
|
|
int pos = total_width * (y + area->height);
|
|
|
|
|
std::fill_n (&area->text[pos], total_width, t_char);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2017-11-30 02:38:55 +01:00
|
|
|
|
bool FVTerm::canClearToEOL (uInt xmin, uInt y)
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2017-11-30 02:38:55 +01:00
|
|
|
|
// Is the line from xmin to the end of the line blank?
|
|
|
|
|
// => clear to end of line
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
term_area*& vt = vterm;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto& ce = TCAP(fc::t_clr_eol);
|
|
|
|
|
auto min_char = &vt->text[y * uInt(vt->width) + xmin];
|
2017-11-30 02:38:55 +01:00
|
|
|
|
|
|
|
|
|
if ( ce && min_char->code == ' ' )
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2017-11-30 02:38:55 +01:00
|
|
|
|
uInt beginning_whitespace = 1;
|
2018-10-29 23:57:35 +01:00
|
|
|
|
bool normal = FTerm::isNormal(min_char);
|
2017-12-08 23:51:56 +01:00
|
|
|
|
bool& ut = FTermcap::background_color_erase;
|
2016-11-26 15:18:44 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
for (uInt x = xmin + 1; x < uInt(vt->width); x++)
|
2016-11-26 15:18:44 +01:00
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto ch = &vt->text[y * uInt(vt->width) + x];
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
if ( *min_char == *ch )
|
|
|
|
|
beginning_whitespace++;
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-12-22 02:02:40 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
if ( beginning_whitespace == uInt(vt->width) - xmin
|
|
|
|
|
&& (ut || normal)
|
2018-07-01 14:48:53 +02:00
|
|
|
|
&& clr_eol_length < beginning_whitespace )
|
2017-11-30 02:38:55 +01:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
bool FVTerm::canClearLeadingWS (uInt& xmin, uInt y)
|
|
|
|
|
{
|
|
|
|
|
// Line has leading whitespace
|
|
|
|
|
// => clear from xmin to beginning of line
|
|
|
|
|
|
|
|
|
|
term_area*& vt = vterm;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto& cb = TCAP(fc::t_clr_bol);
|
|
|
|
|
auto first_char = &vt->text[y * uInt(vt->width)];
|
2017-11-30 02:38:55 +01:00
|
|
|
|
|
|
|
|
|
if ( cb && first_char->code == ' ' )
|
|
|
|
|
{
|
|
|
|
|
uInt leading_whitespace = 1;
|
2018-10-29 23:57:35 +01:00
|
|
|
|
bool normal = FTerm::isNormal(first_char);
|
2017-12-14 00:35:10 +01:00
|
|
|
|
bool& ut = FTermcap::background_color_erase;
|
2016-12-22 02:02:40 +01:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (uInt x{1}; x < uInt(vt->width); x++)
|
2017-11-30 02:38:55 +01:00
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto ch = &vt->text[y * uInt(vt->width) + x];
|
2017-11-30 02:38:55 +01:00
|
|
|
|
|
|
|
|
|
if ( *first_char == *ch )
|
|
|
|
|
leading_whitespace++;
|
|
|
|
|
else
|
|
|
|
|
break;
|
2016-11-26 15:18:44 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
if ( leading_whitespace > xmin
|
|
|
|
|
&& (ut || normal)
|
2018-07-01 14:48:53 +02:00
|
|
|
|
&& clr_bol_length < leading_whitespace )
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2017-11-30 02:38:55 +01:00
|
|
|
|
xmin = leading_whitespace - 1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2017-12-19 02:06:27 +01:00
|
|
|
|
bool FVTerm::canClearTrailingWS (uInt& xmax, uInt y)
|
2017-11-30 02:38:55 +01:00
|
|
|
|
{
|
2017-12-19 02:06:27 +01:00
|
|
|
|
// Line has trailing whitespace
|
2017-11-30 02:38:55 +01:00
|
|
|
|
// => clear from xmax to end of line
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
term_area*& vt = vterm;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto& ce = TCAP(fc::t_clr_eol);
|
|
|
|
|
auto last_char = &vt->text[(y + 1) * uInt(vt->width) - 1];
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
if ( ce && last_char->code == ' ' )
|
|
|
|
|
{
|
2017-12-19 02:06:27 +01:00
|
|
|
|
uInt trailing_whitespace = 1;
|
2018-10-29 23:57:35 +01:00
|
|
|
|
bool normal = FTerm::isNormal(last_char);
|
2017-12-14 00:35:10 +01:00
|
|
|
|
bool& ut = FTermcap::background_color_erase;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
for (uInt x = uInt(vt->width) - 1; x > 0 ; x--)
|
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto ch = &vt->text[y * uInt(vt->width) + x];
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
if ( *last_char == *ch )
|
2017-12-19 02:06:27 +01:00
|
|
|
|
trailing_whitespace++;
|
2017-11-30 02:38:55 +01:00
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-12-19 02:06:27 +01:00
|
|
|
|
if ( trailing_whitespace > uInt(vt->width) - xmax
|
2017-11-30 02:38:55 +01:00
|
|
|
|
&& (ut || normal)
|
2018-07-01 14:48:53 +02:00
|
|
|
|
&& clr_bol_length < trailing_whitespace )
|
2017-11-30 02:38:55 +01:00
|
|
|
|
{
|
2017-12-19 02:06:27 +01:00
|
|
|
|
xmax = uInt(vt->width) - trailing_whitespace;
|
2017-11-30 02:38:55 +01:00
|
|
|
|
return true;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2017-11-30 02:38:55 +01:00
|
|
|
|
}
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
bool FVTerm::skipUnchangedCharacters(uInt& x, uInt xmax, uInt y)
|
|
|
|
|
{
|
|
|
|
|
// Skip characters without changes if it is faster than redrawing
|
|
|
|
|
|
|
|
|
|
term_area*& vt = vterm;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto print_char = &vt->text[y * uInt(vt->width) + x];
|
2017-11-30 02:38:55 +01:00
|
|
|
|
print_char->attr.bit.printed = true;
|
|
|
|
|
|
|
|
|
|
if ( print_char->attr.bit.no_changes )
|
|
|
|
|
{
|
2019-08-25 22:16:00 +02:00
|
|
|
|
uInt count{1};
|
2017-11-30 02:38:55 +01:00
|
|
|
|
|
|
|
|
|
for (uInt i = x + 1; i <= xmax; i++)
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto ch = &vt->text[y * uInt(vt->width) + i];
|
2017-11-30 02:38:55 +01:00
|
|
|
|
|
|
|
|
|
if ( ch->attr.bit.no_changes )
|
|
|
|
|
count++;
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-01 14:48:53 +02:00
|
|
|
|
if ( count > cursor_address_length )
|
2017-11-30 02:38:55 +01:00
|
|
|
|
{
|
|
|
|
|
setTermXY (int(x + count), int(y));
|
|
|
|
|
x = x + count - 1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::printRange ( uInt xmin, uInt xmax, uInt y
|
2017-12-19 02:06:27 +01:00
|
|
|
|
, bool draw_trailing_ws )
|
2017-11-30 02:38:55 +01:00
|
|
|
|
{
|
|
|
|
|
for (uInt x = xmin; x <= xmax; x++)
|
|
|
|
|
{
|
|
|
|
|
term_area*& vt = vterm;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto& ec = TCAP(fc::t_erase_chars);
|
|
|
|
|
auto& rp = TCAP(fc::t_repeat_char);
|
|
|
|
|
auto print_char = &vt->text[y * uInt(vt->width) + x];
|
2017-11-30 02:38:55 +01:00
|
|
|
|
print_char->attr.bit.printed = true;
|
2019-09-28 03:13:06 +02:00
|
|
|
|
replaceNonPrintableFullwidth (x, print_char);
|
2017-11-30 02:38:55 +01:00
|
|
|
|
|
|
|
|
|
// skip character with no changes
|
|
|
|
|
if ( skipUnchangedCharacters(x, xmax, y) )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Erase character
|
|
|
|
|
if ( ec && print_char->code == ' ' )
|
|
|
|
|
{
|
|
|
|
|
exit_state erase_state = \
|
2017-12-19 02:06:27 +01:00
|
|
|
|
eraseCharacters(x, xmax, y, draw_trailing_ws);
|
2017-11-30 02:38:55 +01:00
|
|
|
|
|
|
|
|
|
if ( erase_state == line_completely_printed )
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else if ( rp ) // Repeat one character n-fold
|
|
|
|
|
{
|
|
|
|
|
repeatCharacter(x, xmax, y);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2019-09-28 03:13:06 +02:00
|
|
|
|
else // General character output
|
|
|
|
|
{
|
|
|
|
|
bool min_and_not_max( x == xmin && xmin != xmax );
|
|
|
|
|
printCharacter (x, y, min_and_not_max, print_char);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
inline void FVTerm::replaceNonPrintableFullwidth ( uInt x
|
|
|
|
|
, charData*& print_char )
|
|
|
|
|
{
|
|
|
|
|
// Replace non-printable full-width characters that are truncated
|
|
|
|
|
// from the right or left terminal side
|
|
|
|
|
|
|
|
|
|
if ( x == 0 && isFullWidthPaddingChar(print_char) )
|
|
|
|
|
{
|
|
|
|
|
print_char->code = fc::SingleLeftAngleQuotationMark; // ‹
|
|
|
|
|
print_char->attr.bit.fullwidth_padding = false;
|
|
|
|
|
}
|
|
|
|
|
else if ( x == uInt(vterm->width - 1)
|
|
|
|
|
&& isFullWidthChar(print_char) )
|
|
|
|
|
{
|
|
|
|
|
print_char->code = fc::SingleRightAngleQuotationMark; // ›
|
|
|
|
|
print_char->attr.bit.char_width = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::printCharacter ( uInt& x, uInt y, bool min_and_not_max
|
|
|
|
|
, charData*& print_char)
|
|
|
|
|
{
|
|
|
|
|
// General character output on terminal
|
|
|
|
|
|
|
|
|
|
if ( x < uInt(vterm->width - 1) && isFullWidthChar(print_char) )
|
|
|
|
|
{
|
|
|
|
|
printFullWidthCharacter (x, y, print_char);
|
|
|
|
|
}
|
|
|
|
|
else if ( x > 0 && x < uInt(vterm->width - 1)
|
|
|
|
|
&& isFullWidthPaddingChar(print_char) )
|
|
|
|
|
{
|
|
|
|
|
printFullWidthPaddingCharacter (x, y, print_char);
|
|
|
|
|
}
|
|
|
|
|
else if ( x > 0 && min_and_not_max )
|
|
|
|
|
{
|
|
|
|
|
printHalfCovertFullWidthCharacter (x, y, print_char);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Print a half-width character
|
|
|
|
|
appendCharacter (print_char);
|
|
|
|
|
markAsPrinted (x, y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::printFullWidthCharacter ( uInt& x, uInt y
|
|
|
|
|
, charData*& print_char )
|
|
|
|
|
{
|
|
|
|
|
auto vt = vterm;
|
|
|
|
|
auto next_char = &vt->text[y * uInt(vt->width) + x + 1];
|
|
|
|
|
|
|
|
|
|
if ( print_char->attr.byte[0] == next_char->attr.byte[0]
|
|
|
|
|
&& print_char->attr.byte[1] == next_char->attr.byte[1]
|
|
|
|
|
&& print_char->fg_color == next_char->fg_color
|
|
|
|
|
&& print_char->bg_color == next_char->bg_color
|
|
|
|
|
&& isFullWidthChar(print_char)
|
|
|
|
|
&& isFullWidthPaddingChar(next_char) )
|
|
|
|
|
{
|
|
|
|
|
// Print a full-width character
|
|
|
|
|
appendCharacter (print_char);
|
|
|
|
|
markAsPrinted (x, y);
|
|
|
|
|
skipPaddingCharacter (x, y, print_char);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Print ellipses for the 1st full-width character column
|
|
|
|
|
appendAttributes (print_char);
|
|
|
|
|
appendOutputBuffer (fc::HorizontalEllipsis);
|
|
|
|
|
term_pos->x_ref()++;
|
|
|
|
|
markAsPrinted (x, y);
|
|
|
|
|
|
|
|
|
|
if ( isFullWidthPaddingChar(next_char) )
|
|
|
|
|
{
|
|
|
|
|
// Print ellipses for the 2nd full-width character column
|
|
|
|
|
x++;
|
|
|
|
|
appendAttributes (next_char);
|
|
|
|
|
appendOutputBuffer (fc::HorizontalEllipsis);
|
|
|
|
|
term_pos->x_ref()++;
|
|
|
|
|
markAsPrinted (x, y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::printFullWidthPaddingCharacter ( uInt& x, uInt y
|
|
|
|
|
, charData*& print_char)
|
|
|
|
|
{
|
|
|
|
|
auto vt = vterm;
|
|
|
|
|
auto prev_char = &vt->text[y * uInt(vt->width) + x - 1];
|
|
|
|
|
|
|
|
|
|
if ( print_char->attr.byte[0] == prev_char->attr.byte[0]
|
|
|
|
|
&& print_char->attr.byte[1] == prev_char->attr.byte[1]
|
|
|
|
|
&& print_char->fg_color == prev_char->fg_color
|
|
|
|
|
&& print_char->bg_color == prev_char->bg_color
|
|
|
|
|
&& isFullWidthChar(prev_char)
|
|
|
|
|
&& isFullWidthPaddingChar(print_char) )
|
|
|
|
|
{
|
|
|
|
|
// Move cursor one character to the left
|
|
|
|
|
auto& le = TCAP(fc::t_cursor_left);
|
|
|
|
|
auto& RI = TCAP(fc::t_parm_right_cursor);
|
|
|
|
|
|
|
|
|
|
if ( le )
|
|
|
|
|
appendOutputBuffer (le);
|
|
|
|
|
else if ( RI )
|
|
|
|
|
appendOutputBuffer (tparm(RI, 1, 0, 0, 0, 0, 0, 0, 0, 0));
|
2016-12-28 16:29:49 +01:00
|
|
|
|
else
|
|
|
|
|
{
|
2019-09-28 03:13:06 +02:00
|
|
|
|
skipPaddingCharacter (x, y, prev_char);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Print a full-width character
|
|
|
|
|
x--;
|
|
|
|
|
term_pos->x_ref()--;
|
|
|
|
|
appendCharacter (prev_char);
|
|
|
|
|
markAsPrinted (x, y);
|
|
|
|
|
skipPaddingCharacter (x, y, prev_char);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Print ellipses for the 1st full-width character column
|
|
|
|
|
appendAttributes (print_char);
|
|
|
|
|
appendOutputBuffer (fc::HorizontalEllipsis);
|
|
|
|
|
term_pos->x_ref()++;
|
|
|
|
|
markAsPrinted (x, y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::printHalfCovertFullWidthCharacter ( uInt& x, uInt y
|
|
|
|
|
, charData*& print_char )
|
|
|
|
|
{
|
|
|
|
|
auto vt = vterm;
|
|
|
|
|
auto prev_char = &vt->text[y * uInt(vt->width) + x - 1];
|
|
|
|
|
|
|
|
|
|
if ( isFullWidthChar(prev_char) && ! isFullWidthPaddingChar(print_char) )
|
|
|
|
|
{
|
|
|
|
|
// Move cursor one character to the left
|
|
|
|
|
auto& le = TCAP(fc::t_cursor_left);
|
|
|
|
|
auto& RI = TCAP(fc::t_parm_right_cursor);
|
|
|
|
|
|
|
|
|
|
if ( le )
|
|
|
|
|
appendOutputBuffer (le);
|
|
|
|
|
else if ( RI )
|
|
|
|
|
appendOutputBuffer (tparm(RI, 1, 0, 0, 0, 0, 0, 0, 0, 0));
|
|
|
|
|
|
|
|
|
|
if ( le || RI )
|
|
|
|
|
{
|
|
|
|
|
// Print ellipses for the 1st full-width character column
|
|
|
|
|
x--;
|
|
|
|
|
term_pos->x_ref()--;
|
|
|
|
|
appendAttributes (print_char);
|
|
|
|
|
appendOutputBuffer (fc::HorizontalEllipsis);
|
|
|
|
|
term_pos->x_ref()++;
|
2017-11-30 02:38:55 +01:00
|
|
|
|
markAsPrinted (x, y);
|
2019-09-28 03:13:06 +02:00
|
|
|
|
x++;
|
2017-11-30 02:38:55 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-28 03:13:06 +02:00
|
|
|
|
|
|
|
|
|
// Print a half-width character
|
|
|
|
|
appendCharacter (print_char);
|
|
|
|
|
markAsPrinted (x, y);
|
2017-11-30 02:38:55 +01:00
|
|
|
|
}
|
2019-09-28 03:13:06 +02:00
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
inline void FVTerm::skipPaddingCharacter ( uInt& x, uInt y
|
|
|
|
|
, charData*& print_char )
|
|
|
|
|
{
|
|
|
|
|
if ( isFullWidthChar(print_char) ) // full-width character
|
|
|
|
|
{
|
|
|
|
|
x++; // Skip the following padding character
|
|
|
|
|
term_pos->x_ref()++;
|
|
|
|
|
markAsPrinted (x, y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
FVTerm::exit_state FVTerm::eraseCharacters ( uInt& x, uInt xmax, uInt y
|
2017-12-19 02:06:27 +01:00
|
|
|
|
, bool draw_trailing_ws )
|
2017-11-30 02:38:55 +01:00
|
|
|
|
{
|
|
|
|
|
// Erase a number of characters to draw simple whitespaces
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
term_area*& vt = vterm;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto& ec = TCAP(fc::t_erase_chars);
|
|
|
|
|
auto print_char = &vt->text[y * uInt(vt->width) + x];
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
if ( ! ec || print_char->code != ' ' )
|
|
|
|
|
return not_used;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
|
uInt whitespace{1};
|
2018-10-29 23:57:35 +01:00
|
|
|
|
bool normal = FTerm::isNormal(print_char);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
for (uInt i = x + 1; i <= xmax; i++)
|
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto ch = &vt->text[y * uInt(vt->width) + i];
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
if ( *print_char == *ch )
|
|
|
|
|
whitespace++;
|
|
|
|
|
else
|
|
|
|
|
break;
|
2019-09-28 03:13:06 +02:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
if ( whitespace == 1 )
|
|
|
|
|
{
|
|
|
|
|
appendCharacter (print_char);
|
|
|
|
|
markAsPrinted (x, y);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
uInt start_pos = x;
|
2017-12-17 01:06:53 +01:00
|
|
|
|
bool& ut = FTermcap::background_color_erase;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2018-07-01 14:48:53 +02:00
|
|
|
|
if ( whitespace > erase_char_length + cursor_address_length
|
2017-11-30 02:38:55 +01:00
|
|
|
|
&& (ut || normal) )
|
|
|
|
|
{
|
|
|
|
|
appendAttributes (print_char);
|
|
|
|
|
appendOutputBuffer (tparm(ec, whitespace, 0, 0, 0, 0, 0, 0, 0, 0));
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-12-19 02:06:27 +01:00
|
|
|
|
if ( x + whitespace - 1 < xmax || draw_trailing_ws )
|
2017-11-30 02:38:55 +01:00
|
|
|
|
setTermXY (int(x + whitespace), int(y));
|
|
|
|
|
else
|
|
|
|
|
return line_completely_printed;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
x = x + whitespace - 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
x--;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (uInt i{0}; i < whitespace; i++, x++)
|
2017-11-30 02:38:55 +01:00
|
|
|
|
appendCharacter (print_char);
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
markAsPrinted (start_pos, x, y);
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
return used;
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
FVTerm::exit_state FVTerm::repeatCharacter (uInt& x, uInt xmax, uInt y)
|
|
|
|
|
{
|
|
|
|
|
// Repeat one character n-fold
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
term_area*& vt = vterm;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto& rp = TCAP(fc::t_repeat_char);
|
|
|
|
|
auto print_char = &vt->text[y * uInt(vt->width) + x];
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
if ( ! rp )
|
|
|
|
|
return not_used;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
uInt repetitions{1};
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
for (uInt i = x + 1; i <= xmax; i++)
|
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto ch = &vt->text[y * uInt(vt->width) + i];
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
if ( *print_char == *ch )
|
|
|
|
|
repetitions++;
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
if ( repetitions == 1 )
|
|
|
|
|
{
|
|
|
|
|
appendCharacter (print_char);
|
|
|
|
|
markAsPrinted (x, y);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
uInt start_pos = x;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2018-07-01 14:48:53 +02:00
|
|
|
|
if ( repetitions > repeat_char_length
|
2017-11-30 02:38:55 +01:00
|
|
|
|
&& print_char->code < 128 )
|
|
|
|
|
{
|
|
|
|
|
newFontChanges (print_char);
|
|
|
|
|
charsetChanges (print_char);
|
|
|
|
|
appendAttributes (print_char);
|
|
|
|
|
appendOutputBuffer (tparm(rp, print_char->code, repetitions, 0, 0, 0, 0, 0, 0, 0));
|
2018-12-28 22:57:43 +01:00
|
|
|
|
term_pos->x_ref() += int(repetitions);
|
2017-11-30 02:38:55 +01:00
|
|
|
|
x = x + repetitions - 1;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
2017-11-30 02:38:55 +01:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
x--;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
for (uInt i{0}; i < repetitions; i++, x++)
|
2017-11-30 02:38:55 +01:00
|
|
|
|
appendCharacter (print_char);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
markAsPrinted (start_pos, x, y);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
return used;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
inline bool FVTerm::isFullWidthChar (charData*& ch)
|
|
|
|
|
{
|
|
|
|
|
return bool(ch->attr.bit.char_width == 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
inline bool FVTerm::isFullWidthPaddingChar (charData*& ch)
|
|
|
|
|
{
|
|
|
|
|
return ch->attr.bit.fullwidth_padding;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::cursorWrap()
|
|
|
|
|
{
|
|
|
|
|
// Wrap the cursor
|
|
|
|
|
term_area*& vt = vterm;
|
|
|
|
|
|
2018-01-02 20:38:45 +01:00
|
|
|
|
if ( term_pos->getX() >= vt->width )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
2018-01-02 20:38:45 +01:00
|
|
|
|
if ( term_pos->getY() == vt->height - 1 )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
term_pos->x_ref()--;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if ( FTermcap::eat_nl_glitch )
|
|
|
|
|
{
|
2017-09-11 03:06:02 +02:00
|
|
|
|
term_pos->setPoint(-1, -1);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
|
|
|
|
else if ( FTermcap::automatic_right_margin )
|
|
|
|
|
{
|
|
|
|
|
term_pos->setX(0);
|
|
|
|
|
term_pos->y_ref()++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
term_pos->x_ref()--;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-10 17:35:09 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
bool FVTerm::printWrap (term_area* area)
|
|
|
|
|
{
|
2019-08-25 22:16:00 +02:00
|
|
|
|
bool end_of_area{false};
|
|
|
|
|
int width = area->width
|
|
|
|
|
, height = area->height
|
|
|
|
|
, rsh = area->right_shadow
|
|
|
|
|
, bsh = area->bottom_shadow;
|
2018-02-10 17:35:09 +01:00
|
|
|
|
|
|
|
|
|
// Line break at right margin
|
|
|
|
|
if ( area->cursor_x > width + rsh )
|
|
|
|
|
{
|
|
|
|
|
area->cursor_x = 1;
|
|
|
|
|
area->cursor_y++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Prevent up scrolling
|
|
|
|
|
if ( area->cursor_y > height + bsh )
|
|
|
|
|
{
|
|
|
|
|
area->cursor_y--;
|
|
|
|
|
end_of_area = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return end_of_area;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-28 03:13:06 +02:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::printPaddingCharacter (term_area* area, charData& term_char)
|
|
|
|
|
{
|
|
|
|
|
// Creates a padding-character from the current character (term_char)
|
|
|
|
|
// and prints it. It is a placeholder for the column after
|
|
|
|
|
// a full-width character.
|
|
|
|
|
|
|
|
|
|
charData pc; // padding character
|
|
|
|
|
|
|
|
|
|
// Copy character to padding character
|
|
|
|
|
std::memcpy (&pc, &term_char, sizeof(pc));
|
|
|
|
|
|
|
|
|
|
if ( getEncoding() == fc::UTF8 )
|
|
|
|
|
{
|
|
|
|
|
pc.code = 0;
|
|
|
|
|
pc.attr.bit.fullwidth_padding = true;
|
|
|
|
|
pc.attr.bit.char_width = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pc.code = '.';
|
|
|
|
|
pc.attr.bit.char_width = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Print the padding-character
|
|
|
|
|
print (area, pc);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-30 02:38:55 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
void FVTerm::updateTerminalLine (uInt y)
|
|
|
|
|
{
|
|
|
|
|
// Updates pending changes from line y to the terminal
|
|
|
|
|
|
|
|
|
|
term_area*& vt = vterm;
|
|
|
|
|
uInt& xmin = vt->changes[y].xmin;
|
|
|
|
|
uInt& xmax = vt->changes[y].xmax;
|
|
|
|
|
|
2019-08-18 02:04:44 +02:00
|
|
|
|
if ( xmin <= xmax ) // Line has changes
|
2017-11-30 02:38:55 +01:00
|
|
|
|
{
|
|
|
|
|
bool draw_leading_ws = false;
|
2017-12-19 02:06:27 +01:00
|
|
|
|
bool draw_trailing_ws = false;
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto& ce = TCAP(fc::t_clr_eol);
|
|
|
|
|
auto first_char = &vt->text[y * uInt(vt->width)];
|
|
|
|
|
auto last_char = &vt->text[(y + 1) * uInt(vt->width) - 1];
|
|
|
|
|
auto min_char = &vt->text[y * uInt(vt->width) + xmin];
|
2017-11-30 02:38:55 +01:00
|
|
|
|
|
|
|
|
|
// Clear rest of line
|
|
|
|
|
bool is_eol_clean = canClearToEOL (xmin, y);
|
|
|
|
|
|
|
|
|
|
if ( ! is_eol_clean )
|
|
|
|
|
{
|
|
|
|
|
// leading whitespace
|
|
|
|
|
draw_leading_ws = canClearLeadingWS (xmin, y);
|
|
|
|
|
|
2017-12-19 02:06:27 +01:00
|
|
|
|
// trailing whitespace
|
|
|
|
|
draw_trailing_ws = canClearTrailingWS (xmax, y);
|
2017-11-30 02:38:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setTermXY (int(xmin), int(y));
|
|
|
|
|
|
|
|
|
|
if ( is_eol_clean )
|
|
|
|
|
{
|
|
|
|
|
appendAttributes (min_char);
|
|
|
|
|
appendOutputBuffer (ce);
|
|
|
|
|
markAsPrinted (xmin, uInt(vt->width - 1), y);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if ( draw_leading_ws )
|
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto& cb = TCAP(fc::t_clr_bol);
|
2017-11-30 02:38:55 +01:00
|
|
|
|
appendAttributes (first_char);
|
|
|
|
|
appendOutputBuffer (cb);
|
|
|
|
|
markAsPrinted (0, xmin, y);
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-19 02:06:27 +01:00
|
|
|
|
printRange (xmin, xmax, y, draw_trailing_ws);
|
2017-11-30 02:38:55 +01:00
|
|
|
|
|
2017-12-19 02:06:27 +01:00
|
|
|
|
if ( draw_trailing_ws )
|
2017-11-30 02:38:55 +01:00
|
|
|
|
{
|
|
|
|
|
appendAttributes (last_char);
|
|
|
|
|
appendOutputBuffer (ce);
|
|
|
|
|
markAsPrinted (xmax + 1, uInt(vt->width - 1), y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reset line changes
|
|
|
|
|
xmin = uInt(vt->width);
|
|
|
|
|
xmax = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cursorWrap();
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-11 04:57:36 +02:00
|
|
|
|
//----------------------------------------------------------------------
|
2016-12-28 16:29:49 +01:00
|
|
|
|
bool FVTerm::updateTerminalCursor()
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// Updates the input cursor visibility and the position
|
|
|
|
|
if ( vterm && vterm->input_cursor_visible )
|
|
|
|
|
{
|
|
|
|
|
int x = vterm->input_cursor_x;
|
|
|
|
|
int y = vterm->input_cursor_y;
|
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
if ( isInsideTerminal(FPoint(x, y)) )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
2017-09-11 03:06:02 +02:00
|
|
|
|
setTermXY (x, y);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
showCursor();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
hideCursor();
|
|
|
|
|
|
|
|
|
|
return false;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2019-01-21 03:42:18 +01:00
|
|
|
|
bool FVTerm::isInsideTerminal (const FPoint& pos)
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// Check whether the coordinates are within the virtual terminal
|
2019-01-21 03:42:18 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
FRect term_geometry (0, 0, getColumnNumber(), getLineNumber());
|
|
|
|
|
|
2019-01-21 03:42:18 +01:00
|
|
|
|
if ( term_geometry.contains(pos) )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return true;
|
|
|
|
|
else
|
|
|
|
|
return false;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-18 21:35:36 +02:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
inline bool FVTerm::isTermSizeChanged()
|
|
|
|
|
{
|
|
|
|
|
auto data = getFTerm().getFTermData();
|
|
|
|
|
|
|
|
|
|
if ( ! data )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
auto old_term_geometry = data->getTermGeometry();
|
|
|
|
|
getFTerm().detectTermSize();
|
|
|
|
|
auto term_geometry = data->getTermGeometry();
|
|
|
|
|
term_geometry.move (-1, -1);
|
|
|
|
|
|
|
|
|
|
if ( old_term_geometry.getSize() != term_geometry.getSize() )
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-11 04:57:36 +02:00
|
|
|
|
//----------------------------------------------------------------------
|
2016-12-28 16:29:49 +01:00
|
|
|
|
inline void FVTerm::markAsPrinted (uInt pos, uInt line)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// Marks a character as printed
|
|
|
|
|
|
2017-08-20 17:30:30 +02:00
|
|
|
|
vterm->text[line * uInt(vterm->width) + pos].attr.bit.printed = true;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2016-12-28 16:29:49 +01:00
|
|
|
|
inline void FVTerm::markAsPrinted (uInt from, uInt to, uInt line)
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// Marks characters in the specified range [from .. to] as printed
|
|
|
|
|
|
2017-08-27 09:50:30 +02:00
|
|
|
|
for (uInt x = from; x <= to; x++)
|
2017-08-20 17:30:30 +02:00
|
|
|
|
vterm->text[line * uInt(vterm->width) + x].attr.bit.printed = true;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-11-02 00:37:58 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2018-06-25 00:14:53 +02:00
|
|
|
|
inline void FVTerm::newFontChanges (charData*& next_char)
|
2016-11-02 00:37:58 +01:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// NewFont special cases
|
2018-05-06 21:41:55 +02:00
|
|
|
|
if ( isNewFont() )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
switch ( next_char->code )
|
|
|
|
|
{
|
|
|
|
|
case fc::LowerHalfBlock:
|
|
|
|
|
next_char->code = fc::UpperHalfBlock;
|
|
|
|
|
// fall through
|
|
|
|
|
case fc::NF_rev_left_arrow2:
|
|
|
|
|
case fc::NF_rev_right_arrow2:
|
|
|
|
|
case fc::NF_rev_border_corner_upper_right:
|
|
|
|
|
case fc::NF_rev_border_line_right:
|
|
|
|
|
case fc::NF_rev_border_line_vertical_left:
|
|
|
|
|
case fc::NF_rev_border_corner_lower_right:
|
|
|
|
|
case fc::NF_rev_up_arrow2:
|
|
|
|
|
case fc::NF_rev_down_arrow2:
|
|
|
|
|
case fc::NF_rev_up_arrow1:
|
|
|
|
|
case fc::NF_rev_down_arrow1:
|
|
|
|
|
case fc::NF_rev_left_arrow1:
|
|
|
|
|
case fc::NF_rev_right_arrow1:
|
|
|
|
|
case fc::NF_rev_menu_button1:
|
|
|
|
|
case fc::NF_rev_menu_button2:
|
|
|
|
|
case fc::NF_rev_up_pointing_triangle1:
|
|
|
|
|
case fc::NF_rev_down_pointing_triangle1:
|
|
|
|
|
case fc::NF_rev_up_pointing_triangle2:
|
|
|
|
|
case fc::NF_rev_down_pointing_triangle2:
|
|
|
|
|
case fc::NF_rev_menu_button3:
|
|
|
|
|
case fc::NF_rev_border_line_right_and_left:
|
2019-01-02 03:00:07 +01:00
|
|
|
|
// Show in reverse video
|
|
|
|
|
next_char->attr.bit.reverse = true;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-06-25 00:14:53 +02:00
|
|
|
|
inline void FVTerm::charsetChanges (charData*& next_char)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2019-01-02 03:00:07 +01:00
|
|
|
|
wchar_t& code = next_char->code;
|
|
|
|
|
next_char->encoded_code = code;
|
|
|
|
|
|
2018-05-06 21:41:55 +02:00
|
|
|
|
if ( getEncoding() == fc::UTF8 )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
return;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-02 03:00:07 +01:00
|
|
|
|
wchar_t ch_enc = FTerm::charEncode(code);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2018-04-11 21:41:22 +02:00
|
|
|
|
if ( ch_enc == code )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ( ch_enc == 0 )
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2019-01-02 03:00:07 +01:00
|
|
|
|
next_char->encoded_code = wchar_t(FTerm::charEncode(code, fc::ASCII));
|
2018-04-11 21:41:22 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2019-01-02 03:00:07 +01:00
|
|
|
|
next_char->encoded_code = ch_enc;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
|
2018-05-06 21:41:55 +02:00
|
|
|
|
if ( getEncoding() == fc::VT100 )
|
2018-04-11 21:41:22 +02:00
|
|
|
|
next_char->attr.bit.alt_charset = true;
|
2018-05-06 21:41:55 +02:00
|
|
|
|
else if ( getEncoding() == fc::PC )
|
2018-04-11 21:41:22 +02:00
|
|
|
|
{
|
|
|
|
|
next_char->attr.bit.pc_charset = true;
|
2017-11-03 05:04:27 +01:00
|
|
|
|
|
2018-04-11 21:41:22 +02:00
|
|
|
|
if ( isPuttyTerminal() )
|
|
|
|
|
return;
|
2018-01-02 20:38:45 +01:00
|
|
|
|
|
2018-04-11 21:41:22 +02:00
|
|
|
|
if ( isXTerminal() && ch_enc < 0x20 ) // Character 0x00..0x1f
|
|
|
|
|
{
|
|
|
|
|
if ( hasUTF8() )
|
2019-01-02 03:00:07 +01:00
|
|
|
|
next_char->encoded_code = int(FTerm::charEncode(code, fc::ASCII));
|
2018-04-11 21:41:22 +02:00
|
|
|
|
else
|
2017-11-03 05:04:27 +01:00
|
|
|
|
{
|
2019-01-02 03:00:07 +01:00
|
|
|
|
next_char->encoded_code += 0x5f;
|
2018-04-11 21:41:22 +02:00
|
|
|
|
next_char->attr.bit.alt_charset = true;
|
2017-11-03 05:04:27 +01:00
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-06-25 00:14:53 +02:00
|
|
|
|
inline void FVTerm::appendCharacter (charData*& next_char)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2016-12-28 16:29:49 +01:00
|
|
|
|
int term_width = vterm->width - 1;
|
|
|
|
|
int term_height = vterm->height - 1;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( term_pos->getX() == term_width
|
2017-11-26 22:37:18 +01:00
|
|
|
|
&& term_pos->getY() == term_height )
|
2016-12-28 16:29:49 +01:00
|
|
|
|
appendLowerRight (next_char);
|
|
|
|
|
else
|
|
|
|
|
appendChar (next_char);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
term_pos->x_ref()++;
|
|
|
|
|
}
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2018-06-25 00:14:53 +02:00
|
|
|
|
inline void FVTerm::appendChar (charData*& next_char)
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
|
|
|
|
newFontChanges (next_char);
|
|
|
|
|
charsetChanges (next_char);
|
|
|
|
|
appendAttributes (next_char);
|
2019-01-03 07:36:18 +01:00
|
|
|
|
characterFilter (next_char);
|
2019-01-02 03:00:07 +01:00
|
|
|
|
appendOutputBuffer (next_char->encoded_code);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2018-06-25 00:14:53 +02:00
|
|
|
|
inline void FVTerm::appendAttributes (charData*& next_attr)
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto term_attr = &term_attribute;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
// generate attribute string for the next character
|
2018-12-15 00:50:09 +01:00
|
|
|
|
char* attr_str = FTerm::changeAttribute (term_attr, next_attr);
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( attr_str )
|
|
|
|
|
appendOutputBuffer (attr_str);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-06-25 00:14:53 +02:00
|
|
|
|
int FVTerm::appendLowerRight (charData*& screen_char)
|
2016-10-11 04:57:36 +02:00
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto& SA = TCAP(fc::t_enter_am_mode);
|
|
|
|
|
auto& RA = TCAP(fc::t_exit_am_mode);
|
2016-10-11 04:57:36 +02:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( ! FTermcap::automatic_right_margin )
|
|
|
|
|
{
|
|
|
|
|
appendChar (screen_char);
|
|
|
|
|
}
|
|
|
|
|
else if ( SA && RA )
|
|
|
|
|
{
|
|
|
|
|
appendOutputBuffer (RA);
|
|
|
|
|
appendChar (screen_char);
|
|
|
|
|
appendOutputBuffer (SA);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-12-15 00:50:09 +01:00
|
|
|
|
auto& IC = TCAP(fc::t_parm_ich);
|
|
|
|
|
auto& im = TCAP(fc::t_enter_insert_mode);
|
|
|
|
|
auto& ei = TCAP(fc::t_exit_insert_mode);
|
|
|
|
|
auto& ip = TCAP(fc::t_insert_padding);
|
|
|
|
|
auto& ic = TCAP(fc::t_insert_character);
|
2016-11-26 15:18:44 +01:00
|
|
|
|
|
2019-08-25 22:16:00 +02:00
|
|
|
|
int x = int(getColumnNumber()) - 2;
|
|
|
|
|
int y = int(getLineNumber()) - 1;
|
2016-12-28 16:29:49 +01:00
|
|
|
|
setTermXY (x, y);
|
|
|
|
|
appendChar (screen_char);
|
|
|
|
|
term_pos->x_ref()++;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
setTermXY (x, y);
|
|
|
|
|
screen_char--;
|
2016-11-02 00:37:58 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( IC )
|
|
|
|
|
{
|
2017-04-09 20:08:53 +02:00
|
|
|
|
appendOutputBuffer (tparm(IC, 1, 0, 0, 0, 0, 0, 0, 0, 0));
|
2016-12-28 16:29:49 +01:00
|
|
|
|
appendChar (screen_char);
|
|
|
|
|
}
|
|
|
|
|
else if ( im && ei )
|
|
|
|
|
{
|
|
|
|
|
appendOutputBuffer (im);
|
|
|
|
|
appendChar (screen_char);
|
|
|
|
|
|
|
|
|
|
if ( ip )
|
|
|
|
|
appendOutputBuffer (ip);
|
|
|
|
|
|
|
|
|
|
appendOutputBuffer (ei);
|
|
|
|
|
}
|
|
|
|
|
else if ( ic )
|
|
|
|
|
{
|
|
|
|
|
appendOutputBuffer (ic);
|
|
|
|
|
appendChar (screen_char);
|
|
|
|
|
|
|
|
|
|
if ( ip )
|
|
|
|
|
appendOutputBuffer (ip);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return screen_char->code;
|
2016-10-11 04:57:36 +02:00
|
|
|
|
}
|
2016-12-22 02:02:40 +01:00
|
|
|
|
|
2019-01-03 07:36:18 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
inline void FVTerm::characterFilter (charData*& next_char)
|
|
|
|
|
{
|
2019-07-21 23:31:21 +02:00
|
|
|
|
charSubstitution& sub_map = fterm->getCharSubstitutionMap();
|
2019-01-03 07:36:18 +01:00
|
|
|
|
|
2019-06-12 11:37:34 +02:00
|
|
|
|
if ( sub_map.find(next_char->encoded_code) != sub_map.end() )
|
2019-01-03 07:36:18 +01:00
|
|
|
|
next_char->encoded_code = sub_map[next_char->encoded_code];
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-22 02:02:40 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2017-09-11 03:06:02 +02:00
|
|
|
|
inline void FVTerm::appendOutputBuffer (const std::string& s)
|
2016-12-22 02:02:40 +01:00
|
|
|
|
{
|
2017-03-17 22:59:06 +01:00
|
|
|
|
const char* const& c_string = s.c_str();
|
2019-07-01 01:07:54 +02:00
|
|
|
|
fsystem->tputs (c_string, 1, appendOutputBuffer);
|
2016-12-28 16:29:49 +01:00
|
|
|
|
}
|
2016-12-22 02:02:40 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2017-12-19 02:06:27 +01:00
|
|
|
|
inline void FVTerm::appendOutputBuffer (const char s[])
|
2016-12-28 16:29:49 +01:00
|
|
|
|
{
|
2019-07-01 01:07:54 +02:00
|
|
|
|
fsystem->tputs (s, 1, appendOutputBuffer);
|
2017-12-17 01:06:53 +01:00
|
|
|
|
}
|
2018-01-25 09:31:59 +01:00
|
|
|
|
|
2016-12-22 02:02:40 +01:00
|
|
|
|
//----------------------------------------------------------------------
|
2016-12-28 16:29:49 +01:00
|
|
|
|
int FVTerm::appendOutputBuffer (int ch)
|
2016-12-22 02:02:40 +01:00
|
|
|
|
{
|
2018-01-25 09:31:59 +01:00
|
|
|
|
// append method for unicode character
|
2016-12-28 16:29:49 +01:00
|
|
|
|
output_buffer->push(ch);
|
2016-12-22 02:02:40 +01:00
|
|
|
|
|
2016-12-28 16:29:49 +01:00
|
|
|
|
if ( output_buffer->size() >= TERMINAL_OUTPUT_BUFFER_SIZE )
|
|
|
|
|
flush_out();
|
|
|
|
|
|
|
|
|
|
return ch;
|
2016-12-22 02:02:40 +01:00
|
|
|
|
}
|
2018-01-25 09:31:59 +01:00
|
|
|
|
|
2018-09-20 23:59:01 +02:00
|
|
|
|
} // namespace finalcut
|