Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
CSE3150_Project/ECTextViewImp.h
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
214 lines (177 sloc)
8.16 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ECTextViewImp.h | |
// | |
// | |
// Created by Yufeng Wu on 2/27/20. | |
// | |
// | |
#ifndef ECTextViewImp_h | |
#define ECTextViewImp_h | |
#include <string> | |
#include <vector> | |
#include "ECObserver.h" | |
//*********************************************************** | |
// TextView version 0.0.1 alpha | |
// Feb 27, 2020 | |
// By Yufeng Wu (all rights reserved) | |
// Disclaimer: the following code is largely a porting of | |
// the Kilo editor in C to C++ | |
//*********************************************************** | |
//*********************************************************** | |
// Key code. Use this to match the keycode you get from ECTextViewImp | |
enum KEY_ACTION{ | |
KEY_NULL = 0, /* NULL */ | |
CTRL_A = 1, /* Ctrl-a */ | |
CTRL_B = 2, /* Ctrl-b */ | |
CTRL_C = 3, /* Ctrl-c */ | |
CTRL_D = 4, /* Ctrl-d */ | |
CTRL_E = 5, /* Ctrl-e */ | |
CTRL_F = 6, /* Ctrl-f */ | |
CTRL_G = 7, /* Ctrl-g */ | |
CTRL_H = 8, /* Ctrl-h */ | |
TAB = 9, /* Tab */ | |
CTRL_L = 12, /* Ctrl+l */ | |
ENTER = 13, /* Enter */ | |
CTRL_Q = 17, /* Ctrl-q */ | |
CTRL_R = 18, /* Ctrl-r */ | |
CTRL_S = 19, /* Ctrl-s */ | |
CTRL_U = 21, /* Ctrl-u */ | |
CTRL_V = 22, /* Ctrl-u */ | |
CTRL_Y = 25, /* Ctrl-y */ | |
CTRL_Z = 26, /* Ctrl-z */ | |
ESC = 27, /* Escape */ | |
BACKSPACE = 127, /* Backspace */ | |
/* The following are just soft codes, not really reported by the | |
* terminal directly. */ | |
ARROW_LEFT = 1000, | |
ARROW_RIGHT, | |
ARROW_UP, | |
ARROW_DOWN, | |
DEL_KEY, | |
HOME_KEY, | |
END_KEY, | |
PAGE_UP, | |
PAGE_DOWN | |
}; | |
//*********************************************************** | |
// Text view configuration | |
// This is the internal status of ECTextViewImp. You don't need to use this in your code. | |
class ECTextViewConfig { | |
public: | |
ECTextViewConfig(); | |
int GetWndRowNum() const { return screenrows-(int)listStatusMsgsLeft.size(); } | |
int GetWndColNum() const { return screencols; } | |
int GetCursorX() const { return cx; } | |
int GetCursorY() const { return cy; } | |
void SetCursorX(int pos) { cx = pos; } | |
void SetCursorY(int pos) { cy = pos; } | |
int GetNumStatusRows() const { return listStatusMsgsLeft.size(); } | |
std::string GetStatusRowLeft(int r) const { return listStatusMsgsLeft[r]; } | |
std::string GetStatusRowRight(int r) const { return listStatusMsgsRight[r]; } | |
bool IsStatusRowBlkBackground(int r) const { return listStatusBlackBackground[r]; } | |
void ClearStatusRows() { listStatusMsgsLeft.clear(); listStatusMsgsRight.clear(); listStatusBlackBackground.clear(); } | |
void AddStatusRow( const std::string &statusMsgLeft, const std::string &statusMsgRight, bool fBlackBackground ); | |
void Dump() const; | |
private: | |
void InitParams(); | |
void InitWndSize(); | |
int GetCursorPosition(int ifd, int ofd, int *rows, int *cols); | |
int cx; | |
int cy; /* Cursor x and y position in characters */ | |
int screenrows; /* Number of rows that we can show */ | |
int screencols; /* Number of cols that we can show */ | |
std::vector<std::string> listStatusMsgsLeft; // status msgs (left aligned) | |
std::vector<std::string> listStatusMsgsRight; // right aligned | |
std::vector<bool> listStatusBlackBackground; // set to true if use black background | |
}; | |
//*********************************************************** | |
// A textview implementation | |
// This is based on the simple Kilo code from GitHub | |
// | |
// ECTextViewImp provides basci functionalities for a text view | |
// (1) Display a number of rows onto scrreen (and refresh the current view after updates) | |
// (2) Cursor management: display cursor, and allow cursor movement | |
// (3) Key stroke event handling: notify clients (observers) that a key has been pressed (see below) | |
// | |
// Please note: ECTextViewImp only provides very basic error handling | |
// Also note: you are responsible for what text to show on the screen and where to place cursor | |
// ECTextViewImp has no concerns about formatting at all. You need to figure out how many | |
// rows you are going to show on the screen | |
// | |
// Note: ECTextViewImp implements *** Observer *** pattern | |
// It is the subject that accepts observers. | |
// Whenver something happens (i.e., a key is pressed), all observers | |
// are notified through Observer's Notify function | |
// then an observer would check for update (in this case, what key is pressed) | |
class ECTextViewImp : public ECObserverSubject | |
{ | |
public: | |
ECTextViewImp(); | |
virtual ~ECTextViewImp(); | |
// Show the view. This would enter a forever loop, until quit is set | |
void Show(); | |
// Write the text for the entire wiindow including cursor onto console | |
// Invoke this function after you make changes to your document. | |
// Refreshing entire window for any document update seems excessive; but this is how the code works | |
void Refresh(); | |
// Get the key last pressed. Note: call this after getting a notification from observer | |
int GetPressedKey(); | |
// Call when you want to quit from the program | |
void Quit(); | |
// Clear out the content of the screen | |
// A view consists multiple number of rows, where the maximum number of rows is equal | |
// to the number of rows in the window of the view, minus the number of status rows (by default, none) | |
// You don't have to specify all rows; ECTextViewImp aautomatically fills the remaining rows | |
// with special characters | |
void InitRows() { listRows.clear(); } | |
// Add an entire row to the view | |
void AddRow(const std::string &strRow); | |
// Get/set | |
// Get number of rows in view | |
int GetRowNumInView() const { return status.GetWndRowNum(); } | |
// Get number of columns in view | |
int GetColNumInView() const { return status.GetWndColNum(); } | |
// Get position of the cursor: x coordinate (horonzontal); position starts from 0 | |
int GetCursorX() const { return status.GetCursorX(); } | |
// Get position of the cursor: y coordinate (vertical) | |
int GetCursorY() const { return status.GetCursorY(); } | |
// Set the cursor position x and y coordinate | |
// Be careful: ECTextViewImp doesn't check whether the coordinates you specified | |
// is valid or not; the code may CRASH if you provide an invalid cursor position | |
// A cursor position is valid if the position is within the text range | |
// Suppose the current line has 3 characters. Then the cursor can be at positions 0, 1, 2 and 3 | |
// where 3 is to the right of the last character. | |
// You are responsible to ensure the cursor position is properly set | |
void SetCursorX(int pos) { status.SetCursorX(pos); } | |
void SetCursorY(int pos) { status.SetCursorY(pos); } | |
// status rows | |
// call this function to disable status rows | |
void ClearStatusRows() { status.ClearStatusRows(); } | |
// call to show a status row. A status row consists of two parts: the left message and the right message | |
// set fBlackBackground to be true if you want to show a darkened background (for highlight) | |
void AddStatusRow( const std::string &statusMsgLeft, const std::string &statusMsgRight, bool fBlackBackground ) { status.AddStatusRow(statusMsgLeft, statusMsgRight, fBlackBackground); } | |
private: | |
// These are implementation specific functions; you don't need to call these functions | |
// You can read the code if you want to know what they do | |
// Must call Init before using ECTextViewImp | |
void Init(); | |
void ClearBuffer(); | |
void AppendRowBuffer(const std::string &strRow); | |
void FinishRowsBuffer(); | |
int GetNumRows() const { return listRows.size(); } | |
const char *GetRow(int r) const { return listRows[r].c_str(); } | |
void AppendStatusMsg(int rs); | |
bool ShouldQuit() const { return fQuit; } | |
int ReadKey(int fd); | |
// This is the buffer for the window that is used to refresh the view | |
std::string bufferWnd; | |
// List of rows being requested | |
std::vector<std::string> listRows; | |
// Status of the view | |
ECTextViewConfig status; | |
// if set to true, would quit from loop of Show() | |
bool fQuit; | |
// what key is pressed? The value must be one of KEY_ACTION entries | |
int keyLastPressed; | |
}; | |
#endif /* ECTextViewImp_h */ |