/*
Mosh: the mobile shell
Copyright 2012 Keith Winstein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef TERMINALFB_HPP
#define TERMINALFB_HPP
#include
#include
#include
#include
#include
/* Terminal framebuffer */
namespace Terminal {
class Renditions {
public:
bool bold, underlined, blink, inverse, invisible;
int foreground_color;
int background_color;
Renditions( int s_background );
void set_rendition( int num );
std::string sgr( void ) const;
bool operator==( const Renditions &x ) const
{
return (bold == x.bold) && (underlined == x.underlined)
&& (blink == x.blink) && (inverse == x.inverse)
&& (invisible == x.invisible) && (foreground_color == x.foreground_color)
&& (background_color == x.background_color);
}
};
class Cell {
public:
std::vector contents;
char fallback; /* first character is combining character */
int width;
Renditions renditions;
Cell( int background_color )
: contents(),
fallback( false ),
width( 1 ),
renditions( background_color )
{}
Cell() /* default constructor required by C++11 STL */
: contents(),
fallback( false ),
width( 1 ),
renditions( 0 )
{
assert( false );
}
void reset( int background_color );
bool operator==( const Cell &x ) const
{
return ( (contents == x.contents)
&& (fallback == x.fallback)
&& (width == x.width)
&& (renditions == x.renditions) );
}
wchar_t debug_contents( void ) const;
bool is_blank( void ) const
{
return ( contents.empty()
|| ( (contents.size() == 1) && ( (contents.front() == 0x20)
|| (contents.front() == 0xA0) ) ) );
}
};
class Row {
public:
std::vector cells;
bool wrap;
Row( size_t s_width, int background_color )
: cells( s_width, Cell( background_color ) ), wrap( false )
{}
Row() /* default constructor required by C++11 STL */
: cells( 1, Cell() ), wrap( false )
{
assert( false );
}
void insert_cell( int col, int background_color );
void delete_cell( int col, int background_color );
void reset( int background_color );
bool operator==( const Row &x ) const
{
return ( (cells == x.cells) && (wrap == x.wrap) );
}
};
class SavedCursor {
public:
int cursor_col, cursor_row;
Renditions renditions;
/* not implemented: character set shift state */
bool auto_wrap_mode;
bool origin_mode;
/* not implemented: state of selective erase */
SavedCursor();
};
class DrawState {
private:
int width, height;
void new_grapheme( void );
void snap_cursor_to_border( void );
int cursor_col, cursor_row;
int combining_char_col, combining_char_row;
std::vector tabs;
int scrolling_region_top_row, scrolling_region_bottom_row;
Renditions renditions;
SavedCursor save;
public:
bool next_print_will_wrap;
bool origin_mode;
bool auto_wrap_mode;
bool insert_mode;
bool cursor_visible;
bool reverse_video;
bool application_mode_cursor_keys;
/* bold, etc. */
void move_row( int N, bool relative = false );
void move_col( int N, bool relative = false, bool implicit = false );
int get_cursor_col( void ) const { return cursor_col; }
int get_cursor_row( void ) const { return cursor_row; }
int get_combining_char_col( void ) const { return combining_char_col; }
int get_combining_char_row( void ) const { return combining_char_row; }
int get_width( void ) const { return width; }
int get_height( void ) const { return height; }
void set_tab( void );
void clear_tab( int col );
int get_next_tab( void );
std::vector get_tabs( void );
void set_scrolling_region( int top, int bottom );
int get_scrolling_region_top_row( void ) const { return scrolling_region_top_row; }
int get_scrolling_region_bottom_row( void ) const { return scrolling_region_bottom_row; }
int limit_top( void );
int limit_bottom( void );
void add_rendition( int x ) { renditions.set_rendition( x ); }
Renditions get_renditions( void ) const { return renditions; }
int get_background_rendition( void ) { return renditions.background_color; }
void save_cursor( void );
void restore_cursor( void );
void clear_saved_cursor( void ) { save = SavedCursor(); }
void resize( int s_width, int s_height );
DrawState( int s_width, int s_height );
bool operator==( const DrawState &x ) const
{
/* only compare fields that affect display */
return ( width == x.width ) && ( height == x.height ) && ( cursor_col == x.cursor_col )
&& ( cursor_row == x.cursor_row ) && ( cursor_visible == x.cursor_visible ) &&
( reverse_video == x.reverse_video ) && ( renditions == x.renditions );
}
};
class Framebuffer {
private:
std::deque rows;
std::deque window_title;
unsigned int bell_count;
Row newrow( void ) { return Row( ds.get_width(), ds.get_background_rendition() ); }
public:
Framebuffer( int s_width, int s_height );
DrawState ds;
void scroll( int N );
void move_rows_autoscroll( int rows );
const Row *get_row( int row ) const
{
if ( row == -1 ) row = ds.get_cursor_row();
return &rows[ row ];
}
inline const Cell *get_cell( void ) const
{
return &rows[ ds.get_cursor_row() ].cells[ ds.get_cursor_col() ];
}
inline const Cell *get_cell( int row, int col ) const
{
if ( row == -1 ) row = ds.get_cursor_row();
if ( col == -1 ) col = ds.get_cursor_col();
return &rows[ row ].cells[ col ];
}
Row *get_mutable_row( int row )
{
if ( row == -1 ) row = ds.get_cursor_row();
return &rows[ row ];
}
inline Cell *get_mutable_cell( void )
{
return &rows[ ds.get_cursor_row() ].cells[ ds.get_cursor_col() ];
}
inline Cell *get_mutable_cell( int row, int col )
{
if ( row == -1 ) row = ds.get_cursor_row();
if ( col == -1 ) col = ds.get_cursor_col();
return &rows[ row ].cells[ col ];
}
Cell *get_combining_cell( void );
void apply_renditions_to_current_cell( void );
void insert_line( int before_row );
void delete_line( int row );
void insert_cell( int row, int col );
void delete_cell( int row, int col );
void reset( void );
void soft_reset( void );
void set_window_title( const std::deque &s ) { window_title = s; }
const std::deque & get_window_title( void ) const { return window_title; }
void prefix_window_title( const std::deque &s );
void resize( int s_width, int s_height );
void reset_cell( Cell *c ) { c->reset( ds.get_background_rendition() ); }
void reset_row( Row *r ) { r->reset( ds.get_background_rendition() ); }
void ring_bell( void ) { bell_count++; }
unsigned int get_bell_count( void ) const { return bell_count; }
bool operator==( const Framebuffer &x ) const
{
return ( rows == x.rows ) && ( window_title == x.window_title ) && ( bell_count == x.bell_count ) && ( ds == x.ds );
}
};
}
#endif
|