1 /* 2 * Copyright 2012, Adrien Destugues, pulkomandy@gmail.com 3 * Distributed under the terms of the MIT licence. 4 */ 5 6 7 #include "TermView.h" 8 9 #include <stdio.h> 10 11 #include <Entry.h> 12 #include <File.h> 13 #include <Layout.h> 14 15 #include "SerialApp.h" 16 17 18 TermView::TermView() 19 : 20 BView("TermView", B_WILL_DRAW | B_FRAME_EVENTS) 21 { 22 SetFont(be_fixed_font); 23 24 font_height height; 25 GetFontHeight(&height); 26 fFontHeight = height.ascent + height.descent + height.leading; 27 fFontWidth = be_fixed_font->StringWidth("X"); 28 fTerm = vterm_new(kDefaultHeight, kDefaultWidth); 29 30 fTermScreen = vterm_obtain_screen(fTerm); 31 vterm_screen_set_callbacks(fTermScreen, &sScreenCallbacks, this); 32 vterm_screen_reset(fTermScreen, 1); 33 34 vterm_parser_set_utf8(fTerm, 1); 35 } 36 37 38 TermView::~TermView() 39 { 40 vterm_free(fTerm); 41 } 42 43 44 void TermView::AttachedToWindow() 45 { 46 MakeFocus(); 47 } 48 49 50 void TermView::Draw(BRect updateRect) 51 { 52 VTermRect updatedChars = PixelsToGlyphs(updateRect); 53 54 VTermPos pos; 55 font_height height; 56 GetFontHeight(&height); 57 58 int availableRows, availableCols; 59 vterm_get_size(fTerm, &availableRows, &availableCols); 60 61 for (pos.row = updatedChars.start_row; pos.row <= updatedChars.end_row; 62 pos.row++) { 63 float x = updatedChars.start_col * fFontWidth + kBorderSpacing; 64 float y = pos.row * fFontHeight + height.ascent + kBorderSpacing + 1; 65 MovePenTo(x, y); 66 67 for (pos.col = updatedChars.start_col; 68 pos.col <= updatedChars.end_col;) { 69 VTermScreenCell cell; 70 71 if (pos.col < 0 || pos.row < 0 || pos.col >= availableCols 72 || pos.row >= availableRows) { 73 74 // All cells outside the used terminal area are drawn with the 75 // same background color as the top-left one. 76 VTermPos firstPos; 77 firstPos.row = 0; 78 firstPos.col = 0; 79 vterm_screen_get_cell(fTermScreen, firstPos, &cell); 80 cell.chars[0] = 0; 81 cell.width = 1; 82 } else 83 vterm_screen_get_cell(fTermScreen, pos, &cell); 84 85 rgb_color foreground, background; 86 foreground.red = cell.fg.red; 87 foreground.green = cell.fg.green; 88 foreground.blue = cell.fg.blue; 89 background.red = cell.bg.red; 90 background.green = cell.bg.green; 91 background.blue = cell.bg.blue; 92 93 if(cell.attrs.reverse) { 94 SetLowColor(foreground); 95 SetViewColor(foreground); 96 SetHighColor(background); 97 } else { 98 SetLowColor(background); 99 SetViewColor(background); 100 SetHighColor(foreground); 101 } 102 103 BPoint penLocation = PenLocation(); 104 FillRect(BRect(penLocation.x, penLocation.y - height.ascent, 105 penLocation.x + cell.width * fFontWidth, penLocation.y + 1), 106 B_SOLID_LOW); 107 108 if (cell.chars[0] == 0) { 109 DrawString(" "); 110 pos.col ++; 111 } else { 112 char buffer[VTERM_MAX_CHARS_PER_CELL]; 113 wcstombs(buffer, (wchar_t*)cell.chars, 114 VTERM_MAX_CHARS_PER_CELL); 115 116 DrawString(buffer); 117 pos.col += cell.width; 118 } 119 } 120 } 121 } 122 123 124 void TermView::FrameResized(float width, float height) 125 { 126 VTermRect newSize = PixelsToGlyphs(BRect(0, 0, width - 2 * kBorderSpacing, 127 height - 2 * kBorderSpacing)); 128 vterm_set_size(fTerm, newSize.end_row, newSize.end_col); 129 } 130 131 132 void TermView::GetPreferredSize(float* width, float* height) 133 { 134 if (width != NULL) 135 *width = kDefaultWidth * fFontWidth + 2 * kBorderSpacing; 136 if (height != NULL) 137 *height = kDefaultHeight * fFontHeight + 2 * kBorderSpacing; 138 } 139 140 141 void TermView::KeyDown(const char* bytes, int32 numBytes) 142 { 143 BMessage* keyEvent = new BMessage(kMsgDataWrite); 144 keyEvent->AddData("data", B_RAW_TYPE, bytes, numBytes); 145 be_app_messenger.SendMessage(keyEvent); 146 } 147 148 149 void TermView::MessageReceived(BMessage* message) 150 { 151 switch(message->what) 152 { 153 case 'DATA': 154 { 155 entry_ref ref; 156 if(message->FindRef("refs", &ref) == B_OK) 157 { 158 // The user just dropped a file on us 159 // TODO send it by XMODEM or so 160 } 161 break; 162 } 163 default: 164 BView::MessageReceived(message); 165 } 166 } 167 168 169 void TermView::PushBytes(const char* bytes, size_t length) 170 { 171 vterm_push_bytes(fTerm, bytes, length); 172 } 173 174 175 //#pragma mark - 176 177 178 VTermRect TermView::PixelsToGlyphs(BRect pixels) const 179 { 180 pixels.OffsetBy(-kBorderSpacing, -kBorderSpacing); 181 182 VTermRect rect; 183 rect.start_col = (int)floor(pixels.left / fFontWidth); 184 rect.end_col = (int)ceil(pixels.right / fFontWidth); 185 rect.start_row = (int)floor(pixels.top / fFontHeight); 186 rect.end_row = (int)ceil(pixels.bottom / fFontHeight); 187 /* 188 printf( 189 "TOP %d ch < %f px\n" 190 "BTM %d ch < %f px\n" 191 "LFT %d ch < %f px\n" 192 "RGH %d ch < %f px\n", 193 rect.start_row, pixels.top, 194 rect.end_row, pixels.bottom, 195 rect.start_col, pixels.left, 196 rect.end_col, pixels.right 197 ); 198 */ 199 return rect; 200 } 201 202 203 BRect TermView::GlyphsToPixels(const VTermRect& glyphs) const 204 { 205 BRect rect; 206 rect.top = glyphs.start_row * fFontHeight; 207 rect.bottom = glyphs.end_row * fFontHeight; 208 rect.left = glyphs.start_col * fFontWidth; 209 rect.right = glyphs.end_col * fFontWidth; 210 211 rect.OffsetBy(kBorderSpacing, kBorderSpacing); 212 /* 213 printf( 214 "TOP %d ch > %f px (%f)\n" 215 "BTM %d ch > %f px\n" 216 "LFT %d ch > %f px (%f)\n" 217 "RGH %d ch > %f px\n", 218 glyphs.start_row, rect.top, fFontHeight, 219 glyphs.end_row, rect.bottom, 220 glyphs.start_col, rect.left, fFontWidth, 221 glyphs.end_col, rect.right 222 ); 223 */ 224 return rect; 225 } 226 227 228 BRect TermView::GlyphsToPixels(const int width, const int height) const 229 { 230 VTermRect rect; 231 rect.start_row = 0; 232 rect.start_col = 0; 233 rect.end_row = height; 234 rect.end_col = width; 235 return GlyphsToPixels(rect); 236 } 237 238 239 void TermView::Damage(VTermRect rect) 240 { 241 Invalidate(); 242 // Invalidate(GlyphsToPixels(rect)); 243 } 244 245 246 /* static */ 247 int TermView::Damage(VTermRect rect, void* user) 248 { 249 TermView* view = (TermView*)user; 250 view->Damage(rect); 251 252 return 0; 253 } 254 255 256 const VTermScreenCallbacks TermView::sScreenCallbacks = { 257 &TermView::Damage, 258 /*.moverect =*/ NULL, 259 /*.movecursor =*/ NULL, 260 /*.settermprop =*/ NULL, 261 /*.setmousefunc =*/ NULL, 262 /*.bell =*/ NULL, 263 /*.resize =*/ NULL, 264 }; 265