SerialConnect: implement scrollback.
This commit is contained in:
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user