Separate modules by subdirectory
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
#ifndef TERMINAL_OVERLAY_HPP
|
||||
#define TERMINAL_OVERLAY_HPP
|
||||
|
||||
#include "terminalframebuffer.h"
|
||||
#include "network.h"
|
||||
#include "parser.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Overlay {
|
||||
using namespace Terminal;
|
||||
using namespace Network;
|
||||
using namespace std;
|
||||
|
||||
enum Validity {
|
||||
Pending,
|
||||
Correct,
|
||||
CorrectNoCredit,
|
||||
IncorrectOrExpired,
|
||||
Inactive
|
||||
};
|
||||
|
||||
class ConditionalOverlay {
|
||||
public:
|
||||
uint64_t expiration_frame;
|
||||
uint64_t expiration_time; /* after frame is hit */
|
||||
int col;
|
||||
bool active; /* represents a prediction at all */
|
||||
uint64_t tentative_until_epoch; /* when to show */
|
||||
|
||||
ConditionalOverlay( uint64_t s_exp, int s_col, uint64_t s_tentative )
|
||||
: expiration_frame( s_exp ), expiration_time( -1 ), col( s_col ),
|
||||
active( false ),
|
||||
tentative_until_epoch( s_tentative )
|
||||
{}
|
||||
|
||||
virtual ~ConditionalOverlay() {}
|
||||
|
||||
bool tentative( uint64_t confirmed_epoch ) const { return tentative_until_epoch > confirmed_epoch; }
|
||||
void reset( void ) { expiration_frame = expiration_time = tentative_until_epoch = -1; active = false; }
|
||||
bool start_clock( uint64_t local_frame_acked, uint64_t now, unsigned int send_interval );
|
||||
void expire( uint64_t s_exp ) { expiration_frame = s_exp; expiration_time = uint64_t(-1); }
|
||||
};
|
||||
|
||||
class ConditionalCursorMove : public ConditionalOverlay {
|
||||
public:
|
||||
int row;
|
||||
|
||||
void apply( Framebuffer &fb, uint64_t confirmed_epoch ) const;
|
||||
|
||||
Validity get_validity( const Framebuffer &fb, uint64_t sent_frame, uint64_t early_ack, uint64_t late_ack, uint64_t now ) const;
|
||||
|
||||
ConditionalCursorMove( uint64_t s_exp, int s_row, int s_col, uint64_t s_tentative )
|
||||
: ConditionalOverlay( s_exp, s_col, s_tentative ), row( s_row )
|
||||
{}
|
||||
};
|
||||
|
||||
class ConditionalOverlayCell : public ConditionalOverlay {
|
||||
public:
|
||||
Cell replacement;
|
||||
bool unknown;
|
||||
|
||||
vector<Cell> original_contents; /* we don't give credit for correct predictions
|
||||
that match the original contents */
|
||||
|
||||
void apply( Framebuffer &fb, uint64_t confirmed_epoch, int row, bool flag ) const;
|
||||
Validity get_validity( const Framebuffer &fb, int row, uint64_t sent_frame, uint64_t early_ack, uint64_t late_ack, uint64_t now ) const;
|
||||
|
||||
ConditionalOverlayCell( uint64_t s_exp, int s_col, uint64_t s_tentative )
|
||||
: ConditionalOverlay( s_exp, s_col, s_tentative ),
|
||||
replacement( 0 ),
|
||||
unknown( false ),
|
||||
original_contents()
|
||||
{}
|
||||
|
||||
void reset( void ) { unknown = false; original_contents.clear(); ConditionalOverlay::reset(); }
|
||||
void reset_with_orig( void ) {
|
||||
if ( (!active) || unknown ) {
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
vector<Cell> new_orig( original_contents );
|
||||
new_orig.push_back( replacement );
|
||||
reset();
|
||||
original_contents = new_orig;
|
||||
}
|
||||
};
|
||||
|
||||
class ConditionalOverlayRow {
|
||||
public:
|
||||
int row_num;
|
||||
|
||||
vector<ConditionalOverlayCell> overlay_cells;
|
||||
|
||||
void apply( Framebuffer &fb, uint64_t confirmed_epoch, bool flag ) const;
|
||||
|
||||
ConditionalOverlayRow( int s_row_num ) : row_num( s_row_num ), overlay_cells() {}
|
||||
};
|
||||
|
||||
/* the various overlays */
|
||||
class NotificationEngine {
|
||||
private:
|
||||
uint64_t last_word_from_server;
|
||||
wstring message;
|
||||
uint64_t message_expiration;
|
||||
|
||||
public:
|
||||
bool need_countup( uint64_t ts ) const { return ts - last_word_from_server > 4500; }
|
||||
void adjust_message( void );
|
||||
void apply( Framebuffer &fb ) const;
|
||||
void set_notification_string( const wstring s_message ) { message = s_message; message_expiration = timestamp() + 1000; }
|
||||
const wstring &get_notification_string( void ) const { return message; }
|
||||
void server_heard( uint64_t s_last_word ) { last_word_from_server = s_last_word; }
|
||||
uint64_t get_message_expiration( void ) const { return message_expiration; }
|
||||
|
||||
NotificationEngine();
|
||||
};
|
||||
|
||||
class PredictionEngine {
|
||||
private:
|
||||
char last_byte;
|
||||
Parser::UTF8Parser parser;
|
||||
|
||||
list<ConditionalOverlayRow> overlays;
|
||||
|
||||
list<ConditionalCursorMove> cursors;
|
||||
|
||||
uint64_t local_frame_sent, local_frame_acked, local_frame_late_acked;
|
||||
|
||||
ConditionalOverlayRow & get_or_make_row( int row_num, int num_cols );
|
||||
|
||||
uint64_t prediction_epoch;
|
||||
uint64_t confirmed_epoch;
|
||||
|
||||
void become_tentative( void );
|
||||
|
||||
void newline_carriage_return( const Framebuffer &fb );
|
||||
|
||||
bool flagging;
|
||||
|
||||
ConditionalCursorMove & cursor( void ) { assert( !cursors.empty() ); return cursors.back(); }
|
||||
|
||||
void kill_epoch( uint64_t epoch, const Framebuffer &fb );
|
||||
|
||||
void init_cursor( const Framebuffer &fb );
|
||||
|
||||
uint64_t last_scheduled_timeout;
|
||||
|
||||
unsigned int send_interval;
|
||||
|
||||
public:
|
||||
void apply( Framebuffer &fb ) const;
|
||||
void new_user_byte( char the_byte, const Framebuffer &fb );
|
||||
void cull( const Framebuffer &fb );
|
||||
|
||||
void reset( void );
|
||||
|
||||
bool active( void ) { return timestamp() <= last_scheduled_timeout; }
|
||||
|
||||
void set_local_frame_sent( uint64_t x ) { local_frame_sent = x; }
|
||||
void set_local_frame_acked( uint64_t x ) { local_frame_acked = x; }
|
||||
void set_local_frame_late_acked( uint64_t x ) { local_frame_late_acked = x; }
|
||||
|
||||
void set_send_interval( unsigned int x ) { send_interval = x; }
|
||||
|
||||
PredictionEngine( void ) : last_byte( 0 ), parser(), overlays(), cursors(),
|
||||
local_frame_sent( 0 ), local_frame_acked( 0 ),
|
||||
local_frame_late_acked( 0 ),
|
||||
prediction_epoch( 1 ), confirmed_epoch( 0 ),
|
||||
flagging( false ), last_scheduled_timeout( 0 ),
|
||||
send_interval( 250 )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class TitleEngine {
|
||||
private:
|
||||
deque<wchar_t> prefix;
|
||||
|
||||
public:
|
||||
void apply( Framebuffer &fb ) const { fb.prefix_window_title( prefix ); }
|
||||
void set_prefix( const wstring s );
|
||||
TitleEngine() : prefix() {}
|
||||
};
|
||||
|
||||
/* the overlay manager */
|
||||
class OverlayManager {
|
||||
private:
|
||||
NotificationEngine notifications;
|
||||
PredictionEngine predictions;
|
||||
TitleEngine title;
|
||||
|
||||
public:
|
||||
void apply( Framebuffer &fb );
|
||||
|
||||
NotificationEngine & get_notification_engine( void ) { return notifications; }
|
||||
PredictionEngine & get_prediction_engine( void ) { return predictions; }
|
||||
|
||||
void set_title_prefix( const wstring s ) { title.set_prefix( s ); }
|
||||
|
||||
OverlayManager() : notifications(), predictions(), title() {}
|
||||
|
||||
int wait_time( void );
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user