SerialConnect: implement scrollback.

This commit is contained in:
Adrien Destugues
2014-08-12 23:13:37 +02:00
parent d18836726c
commit b59ed15486
4 changed files with 238 additions and 109 deletions
+44 -34
View File
@@ -13,6 +13,7 @@
#include <Menu.h> #include <Menu.h>
#include <MenuBar.h> #include <MenuBar.h>
#include <MenuItem.h> #include <MenuItem.h>
#include <ScrollView.h>
#include <SerialPort.h> #include <SerialPort.h>
#include "SerialApp.h" #include "SerialApp.h"
@@ -41,13 +42,30 @@ SerialWindow::SerialWindow()
B_DOCUMENT_WINDOW, B_QUIT_ON_WINDOW_CLOSE | B_AUTO_UPDATE_SIZE_LIMITS) B_DOCUMENT_WINDOW, B_QUIT_ON_WINDOW_CLOSE | B_AUTO_UPDATE_SIZE_LIMITS)
, fLogFilePanel(NULL) , fLogFilePanel(NULL)
{ {
SetLayout(new BGroupLayout(B_VERTICAL, 0.0f)); BMenuBar* menuBar = new BMenuBar(Bounds(), "menuBar");
menuBar->ResizeToPreferred();
BMenuBar* menuBar = new BMenuBar("menuBar"); BRect r = Bounds();
fTermView = new TermView(); r.top = menuBar->Bounds().bottom + 1;
r.right -= B_V_SCROLL_BAR_WIDTH;
fTermView = new TermView(r);
fTermView->ResizeToPreferred();
r = fTermView->Frame();
r.left = r.right + 1;
r.right = r.left + B_V_SCROLL_BAR_WIDTH;
r.top -= 1;
r.bottom -= B_H_SCROLL_BAR_HEIGHT - 1;
BScrollBar* scrollBar = new BScrollBar(r, "scrollbar", NULL, 0, 0,
B_VERTICAL);
scrollBar->SetTarget(fTermView);
ResizeTo(r.right - 1, r.bottom + B_H_SCROLL_BAR_HEIGHT - 1);
AddChild(menuBar); AddChild(menuBar);
AddChild(fTermView); AddChild(fTermView);
AddChild(scrollBar);
fConnectionMenu = new BMenu("Connection"); fConnectionMenu = new BMenu("Connection");
BMenu* fileMenu = new BMenu("File"); BMenu* fileMenu = new BMenu("File");
@@ -147,7 +165,7 @@ SerialWindow::SerialWindow()
message->AddInt32("baudrate", kBaudrateConstants[i]); message->AddInt32("baudrate", kBaudrateConstants[i]);
char buffer[7]; char buffer[7];
sprintf(buffer,"%d", kBaudrates[i]); sprintf(buffer, "%d", kBaudrates[i]);
BMenuItem* item = new BMenuItem(buffer, message); BMenuItem* item = new BMenuItem(buffer, message);
fBaudrateMenu->AddItem(item); fBaudrateMenu->AddItem(item);
@@ -181,7 +199,6 @@ SerialWindow::SerialWindow()
} }
SerialWindow::~SerialWindow() SerialWindow::~SerialWindow()
{ {
delete fLogFilePanel; delete fLogFilePanel;
@@ -198,7 +215,7 @@ void SerialWindow::MenusBeginning()
int deviceCount = serialPort.CountDevices(); int deviceCount = serialPort.CountDevices();
bool connected = false; bool connected = false;
for(int i = 0; i < deviceCount; i++) for (int i = 0; i < deviceCount; i++)
{ {
char buffer[256]; char buffer[256];
serialPort.GetDeviceName(i, buffer, 256); serialPort.GetDeviceName(i, buffer, 256);
@@ -210,7 +227,7 @@ void SerialWindow::MenusBeginning()
const BString& connectedPort = ((SerialApp*)be_app)->GetPort(); const BString& connectedPort = ((SerialApp*)be_app)->GetPort();
if(connectedPort == buffer) { if (connectedPort == buffer) {
connected = true; connected = true;
portItem->SetMarked(true); portItem->SetMarked(true);
} }
@@ -223,7 +240,7 @@ void SerialWindow::MenusBeginning()
BMenuItem* disconnect = new BMenuItem("Disconnect", BMenuItem* disconnect = new BMenuItem("Disconnect",
new BMessage(kMsgOpenPort), 'Z', B_OPTION_KEY); new BMessage(kMsgOpenPort), 'Z', B_OPTION_KEY);
if(!connected) if (!connected)
disconnect->SetEnabled(false); disconnect->SetEnabled(false);
fConnectionMenu->AddItem(disconnect); fConnectionMenu->AddItem(disconnect);
} else { } else {
@@ -233,6 +250,7 @@ void SerialWindow::MenusBeginning()
} }
} }
void SerialWindow::MessageReceived(BMessage* message) void SerialWindow::MessageReceived(BMessage* message)
{ {
switch(message->what) switch(message->what)
@@ -240,7 +258,7 @@ void SerialWindow::MessageReceived(BMessage* message)
case kMsgOpenPort: case kMsgOpenPort:
{ {
BMenuItem* disconnectMenu; BMenuItem* disconnectMenu;
if(message->FindPointer("source", (void**)&disconnectMenu) == B_OK) if (message->FindPointer("source", (void**)&disconnectMenu) == B_OK)
disconnectMenu->SetMarked(false); disconnectMenu->SetMarked(false);
be_app->PostMessage(new BMessage(*message)); be_app->PostMessage(new BMessage(*message));
break; break;
@@ -257,7 +275,7 @@ void SerialWindow::MessageReceived(BMessage* message)
case kMsgLogfile: case kMsgLogfile:
{ {
// Let's lazy init the file panel // Let's lazy init the file panel
if(fLogFilePanel == NULL) { if (fLogFilePanel == NULL) {
fLogFilePanel = new BFilePanel(B_SAVE_PANEL, &be_app_messenger, fLogFilePanel = new BFilePanel(B_SAVE_PANEL, &be_app_messenger,
NULL, B_FILE_NODE, false); NULL, B_FILE_NODE, false);
fLogFilePanel->SetMessage(message); fLogFilePanel->SetMessage(message);
@@ -273,67 +291,59 @@ void SerialWindow::MessageReceived(BMessage* message)
parity_mode parity; parity_mode parity;
uint32 flowcontrol; uint32 flowcontrol;
if(message->FindInt32("databits", (int32*)&dataBits) == B_OK) if (message->FindInt32("databits", (int32*)&dataBits) == B_OK) {
{ for (int i = 0; i < fDatabitsMenu->CountItems(); i++) {
for(int i = 0; i < fDatabitsMenu->CountItems(); i++)
{
BMenuItem* item = fDatabitsMenu->ItemAt(i); BMenuItem* item = fDatabitsMenu->ItemAt(i);
int32 code; int32 code;
item->Message()->FindInt32("databits", &code); item->Message()->FindInt32("databits", &code);
if(code == dataBits) if (code == dataBits)
item->SetMarked(true); item->SetMarked(true);
} }
} }
if(message->FindInt32("stopbits", (int32*)&stopBits) == B_OK) if (message->FindInt32("stopbits", (int32*)&stopBits) == B_OK) {
{ for (int i = 0; i < fStopbitsMenu->CountItems(); i++) {
for(int i = 0; i < fStopbitsMenu->CountItems(); i++)
{
BMenuItem* item = fStopbitsMenu->ItemAt(i); BMenuItem* item = fStopbitsMenu->ItemAt(i);
int32 code; int32 code;
item->Message()->FindInt32("stopbits", &code); item->Message()->FindInt32("stopbits", &code);
if(code == stopBits) if (code == stopBits)
item->SetMarked(true); item->SetMarked(true);
} }
} }
if(message->FindInt32("parity", (int32*)&parity) == B_OK) if (message->FindInt32("parity", (int32*)&parity) == B_OK)
{
for(int i = 0; i < fParityMenu->CountItems(); i++)
{ {
for (int i = 0; i < fParityMenu->CountItems(); i++) {
BMenuItem* item = fParityMenu->ItemAt(i); BMenuItem* item = fParityMenu->ItemAt(i);
int32 code; int32 code;
item->Message()->FindInt32("parity", &code); item->Message()->FindInt32("parity", &code);
if(code == parity) if (code == parity)
item->SetMarked(true); item->SetMarked(true);
} }
} }
if(message->FindInt32("flowcontrol", (int32*)&flowcontrol) == B_OK) if (message->FindInt32("flowcontrol", (int32*)&flowcontrol)
{ == B_OK) {
for(int i = 0; i < fFlowcontrolMenu->CountItems(); i++) for (int i = 0; i < fFlowcontrolMenu->CountItems(); i++) {
{
BMenuItem* item = fFlowcontrolMenu->ItemAt(i); BMenuItem* item = fFlowcontrolMenu->ItemAt(i);
int32 code; int32 code;
item->Message()->FindInt32("flowcontrol", &code); item->Message()->FindInt32("flowcontrol", &code);
if(code == (int32)flowcontrol) if (code == (int32)flowcontrol)
item->SetMarked(true); item->SetMarked(true);
} }
} }
if(message->FindInt32("baudrate", &baudrate) == B_OK) if (message->FindInt32("baudrate", &baudrate) == B_OK) {
{ for (int i = 0; i < fBaudrateMenu->CountItems(); i++) {
for(int i = 0; i < fBaudrateMenu->CountItems(); i++)
{
BMenuItem* item = fBaudrateMenu->ItemAt(i); BMenuItem* item = fBaudrateMenu->ItemAt(i);
int32 code; int32 code;
item->Message()->FindInt32("baudrate", &code); item->Message()->FindInt32("baudrate", &code);
if(baudrate == code) if (baudrate == code)
item->SetMarked(true); item->SetMarked(true);
} }
} }
+1
View File
@@ -23,6 +23,7 @@ class SerialWindow: public BWindow
private: private:
TermView* fTermView; TermView* fTermView;
BMenu* fConnectionMenu; BMenu* fConnectionMenu;
BMenu* fDatabitsMenu; BMenu* fDatabitsMenu;
BMenu* fStopbitsMenu; BMenu* fStopbitsMenu;
+155 -52
View File
@@ -11,27 +11,30 @@
#include <Entry.h> #include <Entry.h>
#include <File.h> #include <File.h>
#include <Layout.h> #include <Layout.h>
#include <ScrollBar.h>
#include "SerialApp.h" #include "SerialApp.h"
struct ScrollBufferItem {
int cols;
VTermScreenCell cells[];
};
TermView::TermView() TermView::TermView()
: :
BView("TermView", B_WILL_DRAW | B_FRAME_EVENTS) BView("TermView", B_WILL_DRAW | B_FRAME_EVENTS)
{ {
SetFont(be_fixed_font); _Init();
}
font_height height;
GetFontHeight(&height);
fFontHeight = height.ascent + height.descent + height.leading + 1;
fFontWidth = be_fixed_font->StringWidth("X");
fTerm = vterm_new(kDefaultHeight, kDefaultWidth);
fTermScreen = vterm_obtain_screen(fTerm); TermView::TermView(BRect r)
vterm_screen_set_callbacks(fTermScreen, &sScreenCallbacks, this); :
vterm_screen_reset(fTermScreen, 1); BView(r, "TermView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FRAME_EVENTS)
{
vterm_parser_set_utf8(fTerm, 1); _Init();
} }
@@ -41,7 +44,8 @@ TermView::~TermView()
} }
void TermView::AttachedToWindow() void
TermView::AttachedToWindow()
{ {
MakeFocus(); MakeFocus();
@@ -49,7 +53,7 @@ void TermView::AttachedToWindow()
VTermPos firstPos; VTermPos firstPos;
firstPos.row = 0; firstPos.row = 0;
firstPos.col = 0; firstPos.col = 0;
vterm_screen_get_cell(fTermScreen, firstPos, &cell); _GetCell(firstPos, cell);
rgb_color background; rgb_color background;
background.red = cell.bg.red; background.red = cell.bg.red;
@@ -61,17 +65,15 @@ void TermView::AttachedToWindow()
} }
void TermView::Draw(BRect updateRect) void
TermView::Draw(BRect updateRect)
{ {
VTermRect updatedChars = PixelsToGlyphs(updateRect); VTermRect updatedChars = _PixelsToGlyphs(updateRect);
VTermPos pos; VTermPos pos;
font_height height; font_height height;
GetFontHeight(&height); GetFontHeight(&height);
int availableRows, availableCols;
vterm_get_size(fTerm, &availableRows, &availableCols);
for (pos.row = updatedChars.start_row; pos.row <= updatedChars.end_row; for (pos.row = updatedChars.start_row; pos.row <= updatedChars.end_row;
pos.row++) { pos.row++) {
float x = updatedChars.start_col * fFontWidth + kBorderSpacing; float x = updatedChars.start_col * fFontWidth + kBorderSpacing;
@@ -82,19 +84,7 @@ void TermView::Draw(BRect updateRect)
pos.col <= updatedChars.end_col;) { pos.col <= updatedChars.end_col;) {
VTermScreenCell cell; VTermScreenCell cell;
if (pos.col < 0 || pos.row < 0 || pos.col >= availableCols _GetCell(pos, cell);
|| pos.row >= availableRows) {
// All cells outside the used terminal area are drawn with the
// same background color as the top-left one.
VTermPos firstPos;
firstPos.row = 0;
firstPos.col = 0;
vterm_screen_get_cell(fTermScreen, firstPos, &cell);
cell.chars[0] = 0;
cell.width = 1;
} else
vterm_screen_get_cell(fTermScreen, pos, &cell);
rgb_color foreground, background; rgb_color foreground, background;
foreground.red = cell.fg.red; foreground.red = cell.fg.red;
@@ -119,7 +109,7 @@ void TermView::Draw(BRect updateRect)
BPoint penLocation = PenLocation(); BPoint penLocation = PenLocation();
FillRect(BRect(penLocation.x, penLocation.y - height.ascent, FillRect(BRect(penLocation.x, penLocation.y - height.ascent,
penLocation.x + cell.width * fFontWidth - 1, penLocation.x + cell.width * fFontWidth - 1,
penLocation.y + height.descent + height.leading - 1), penLocation.y + height.descent + height.leading),
B_SOLID_LOW); B_SOLID_LOW);
if (cell.chars[0] == 0) { if (cell.chars[0] == 0) {
@@ -138,15 +128,17 @@ void TermView::Draw(BRect updateRect)
} }
void TermView::FrameResized(float width, float height) void
TermView::FrameResized(float width, float height)
{ {
VTermRect newSize = PixelsToGlyphs(BRect(0, 0, width - 2 * kBorderSpacing, VTermRect newSize = _PixelsToGlyphs(BRect(0, 0, width - 2 * kBorderSpacing,
height - 2 * kBorderSpacing)); height - 2 * kBorderSpacing));
vterm_set_size(fTerm, newSize.end_row, newSize.end_col); vterm_set_size(fTerm, newSize.end_row, newSize.end_col);
} }
void TermView::GetPreferredSize(float* width, float* height) void
TermView::GetPreferredSize(float* width, float* height)
{ {
if (width != NULL) if (width != NULL)
*width = kDefaultWidth * fFontWidth + 2 * kBorderSpacing; *width = kDefaultWidth * fFontWidth + 2 * kBorderSpacing;
@@ -155,7 +147,8 @@ void TermView::GetPreferredSize(float* width, float* height)
} }
void TermView::KeyDown(const char* bytes, int32 numBytes) void
TermView::KeyDown(const char* bytes, int32 numBytes)
{ {
BMessage* keyEvent = new BMessage(kMsgDataWrite); BMessage* keyEvent = new BMessage(kMsgDataWrite);
keyEvent->AddData("data", B_RAW_TYPE, bytes, numBytes); keyEvent->AddData("data", B_RAW_TYPE, bytes, numBytes);
@@ -163,7 +156,8 @@ void TermView::KeyDown(const char* bytes, int32 numBytes)
} }
void TermView::MessageReceived(BMessage* message) void
TermView::MessageReceived(BMessage* message)
{ {
switch(message->what) switch(message->what)
{ {
@@ -183,7 +177,8 @@ void TermView::MessageReceived(BMessage* message)
} }
void TermView::PushBytes(const char* bytes, size_t length) void
TermView::PushBytes(const char* bytes, size_t length)
{ {
vterm_push_bytes(fTerm, bytes, length); vterm_push_bytes(fTerm, bytes, length);
} }
@@ -192,7 +187,27 @@ void TermView::PushBytes(const char* bytes, size_t length)
// #pragma mark - // #pragma mark -
VTermRect TermView::PixelsToGlyphs(BRect pixels) const void
TermView::_Init()
{
SetFont(be_fixed_font);
font_height height;
GetFontHeight(&height);
fFontHeight = height.ascent + height.descent + height.leading + 1;
fFontWidth = be_fixed_font->StringWidth("X");
fTerm = vterm_new(kDefaultHeight, kDefaultWidth);
fTermScreen = vterm_obtain_screen(fTerm);
vterm_screen_set_callbacks(fTermScreen, &sScreenCallbacks, this);
vterm_screen_reset(fTermScreen, 1);
vterm_parser_set_utf8(fTerm, 1);
}
VTermRect
TermView::_PixelsToGlyphs(BRect pixels) const
{ {
pixels.OffsetBy(-kBorderSpacing, -kBorderSpacing); pixels.OffsetBy(-kBorderSpacing, -kBorderSpacing);
@@ -201,7 +216,7 @@ VTermRect TermView::PixelsToGlyphs(BRect pixels) const
rect.end_col = (int)ceil(pixels.right / fFontWidth); rect.end_col = (int)ceil(pixels.right / fFontWidth);
rect.start_row = (int)floor(pixels.top / fFontHeight); rect.start_row = (int)floor(pixels.top / fFontHeight);
rect.end_row = (int)ceil(pixels.bottom / fFontHeight); rect.end_row = (int)ceil(pixels.bottom / fFontHeight);
/* #if 0
printf( printf(
"TOP %d ch < %f px\n" "TOP %d ch < %f px\n"
"BTM %d ch < %f px\n" "BTM %d ch < %f px\n"
@@ -212,12 +227,12 @@ VTermRect TermView::PixelsToGlyphs(BRect pixels) const
rect.start_col, pixels.left, rect.start_col, pixels.left,
rect.end_col, pixels.right rect.end_col, pixels.right
); );
*/ #endif
return rect; return rect;
} }
BRect TermView::GlyphsToPixels(const VTermRect& glyphs) const BRect TermView::_GlyphsToPixels(const VTermRect& glyphs) const
{ {
BRect rect; BRect rect;
rect.top = glyphs.start_row * fFontHeight; rect.top = glyphs.start_row * fFontHeight;
@@ -242,40 +257,128 @@ BRect TermView::GlyphsToPixels(const VTermRect& glyphs) const
} }
BRect TermView::GlyphsToPixels(const int width, const int height) const BRect
TermView::_GlyphsToPixels(const int width, const int height) const
{ {
VTermRect rect; VTermRect rect;
rect.start_row = 0; rect.start_row = 0;
rect.start_col = 0; rect.start_col = 0;
rect.end_row = height; rect.end_row = height;
rect.end_col = width; rect.end_col = width;
return GlyphsToPixels(rect); return _GlyphsToPixels(rect);
} }
void TermView::Damage(VTermRect rect) void
TermView::_GetCell(VTermPos pos, VTermScreenCell& cell)
{ {
Invalidate(); int availableRows, availableCols;
// Invalidate(GlyphsToPixels(rect)); vterm_get_size(fTerm, &availableRows, &availableCols);
if (pos.col < 0 || pos.row < -kScrollBackSize || pos.col >= availableCols
|| pos.row >= availableRows) {
// All cells outside the used terminal area are drawn with the same
// background color as the top-left one.
// TODO should they use the attributes of the closest neighbor instead?
VTermPos firstPos;
firstPos.row = 0;
firstPos.col = 0;
vterm_screen_get_cell(fTermScreen, firstPos, &cell);
cell.chars[0] = 0;
cell.width = 1;
} else if (pos.row < 0) {
// This is a cell from the scroll-back buffer
int offset = - pos.row - 1;
ScrollBufferItem* line = (ScrollBufferItem*)fScrollBuffer.ItemAt(offset);
if (line == NULL || pos.col >= line->cols) {
VTermPos firstPos;
firstPos.row = 0;
firstPos.col = 0;
vterm_screen_get_cell(fTermScreen, firstPos, &cell);
cell.chars[0] = 0;
cell.width = 1;
} else
cell = line->cells[pos.col];
} else
vterm_screen_get_cell(fTermScreen, pos, &cell);
} }
/* static */ void
int TermView::Damage(VTermRect rect, void* user) TermView::_Damage(VTermRect rect)
{
// Invalidate();
Invalidate(_GlyphsToPixels(rect));
}
void
TermView::_PushLine(int cols, const VTermScreenCell* cells)
{
ScrollBufferItem* item = (ScrollBufferItem*)malloc(sizeof(int)
+ cols * sizeof(VTermScreenCell));
item->cols = cols;
memcpy(item->cells, cells, cols * sizeof(VTermScreenCell));
fScrollBuffer.AddItem(item, 0);
free(fScrollBuffer.RemoveItem(kScrollBackSize));
int availableRows, availableCols;
vterm_get_size(fTerm, &availableRows, &availableCols);
VTermRect dirty;
dirty.start_col = 0;
dirty.end_col = availableCols;
dirty.end_row = 0;
dirty.start_row = -fScrollBuffer.CountItems();
// FIXME we should rather use CopyRect if possible, and only invalidate the
// newly exposed area here.
Invalidate(_GlyphsToPixels(dirty));
BScrollBar* scrollBar = ScrollBar(B_VERTICAL);
if (scrollBar != NULL) {
// FIXME this is not exactly right, it's off by a few pixels so one step
// isn't exactly equal to one line.
float range = (fScrollBuffer.CountItems() + availableRows) * fFontHeight;
scrollBar->SetRange(availableRows * fFontHeight - range, 0.0f);
// TODO we need to adjust this in FrameResized, as availableRows can
// change
scrollBar->SetProportion(availableRows * fFontHeight / range);
scrollBar->SetSteps(fFontHeight, fFontHeight * 3);
}
}
/* static */ int
TermView::_Damage(VTermRect rect, void* user)
{ {
TermView* view = (TermView*)user; TermView* view = (TermView*)user;
view->Damage(rect); view->_Damage(rect);
return 0; return 0;
} }
const VTermScreenCallbacks TermView::sScreenCallbacks = { /* static */ int
&TermView::Damage, TermView::_PushLine(int cols, const VTermScreenCell* cells, void* user)
{
TermView* view = (TermView*)user;
view->_PushLine(cols, cells);
return 0;
}
const
VTermScreenCallbacks TermView::sScreenCallbacks = {
&TermView::_Damage,
/*.moverect =*/ NULL, /*.moverect =*/ NULL,
/*.movecursor =*/ NULL, /*.movecursor =*/ NULL,
/*.settermprop =*/ NULL, /*.settermprop =*/ NULL,
/*.setmousefunc =*/ NULL, /*.setmousefunc =*/ NULL,
/*.bell =*/ NULL, /*.bell =*/ NULL,
/*.resize =*/ NULL, /*.resize =*/ NULL,
&TermView::_PushLine,
/*.sb_popline =*/ NULL,
}; };
+21 -6
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2012, Adrien Destugues, [email protected] * Copyright 2012-2014, Adrien Destugues, [email protected]
* Distributed under the terms of the MIT licence. * Distributed under the terms of the MIT licence.
*/ */
@@ -10,10 +10,12 @@ extern "C" {
#include <vterm.h> #include <vterm.h>
} }
class TermView: public BView class TermView: public BView
{ {
public: public:
TermView(); TermView();
TermView(BRect bounds);
~TermView(); ~TermView();
void AttachedToWindow(); void AttachedToWindow();
@@ -22,19 +24,31 @@ class TermView: public BView
void GetPreferredSize(float* width, float* height); void GetPreferredSize(float* width, float* height);
void KeyDown(const char* bytes, int32 numBytes); void KeyDown(const char* bytes, int32 numBytes);
void MessageReceived(BMessage* message); void MessageReceived(BMessage* message);
void PushBytes(const char* bytes, const size_t length); void PushBytes(const char* bytes, const size_t length);
private: private:
VTermRect PixelsToGlyphs(BRect pixels) const; void _Init();
BRect GlyphsToPixels(const VTermRect& glyphs) const;
BRect GlyphsToPixels(const int width, const int height) const;
void Damage(VTermRect rect);
static int Damage(VTermRect rect, void* user); VTermRect _PixelsToGlyphs(BRect pixels) const;
BRect _GlyphsToPixels(const VTermRect& glyphs) const;
BRect _GlyphsToPixels(const int width, const int height)
const;
void _GetCell(VTermPos pos, VTermScreenCell& cell);
void _Damage(VTermRect rect);
void _PushLine(int cols, const VTermScreenCell* cells);
static int _Damage(VTermRect rect, void* user);
static int _PushLine(int cols, const VTermScreenCell* cells,
void* user);
static int _PopLine(int cols, const VTermScreenCell* cells,
void* user);
private: private:
VTerm* fTerm; VTerm* fTerm;
VTermScreen* fTermScreen; VTermScreen* fTermScreen;
BList fScrollBuffer;
float fFontWidth; float fFontWidth;
float fFontHeight; float fFontHeight;
@@ -43,4 +57,5 @@ class TermView: public BView
static const int kDefaultWidth = 80; static const int kDefaultWidth = 80;
static const int kDefaultHeight = 25; static const int kDefaultHeight = 25;
static const int kBorderSpacing = 3; static const int kBorderSpacing = 3;
static const int kScrollBackSize = 1000;
}; };