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 foreground.alpha = 255; 90 background.red = cell.bg.red; 91 background.green = cell.bg.green; 92 background.blue = cell.bg.blue; 93 background.alpha = 255; 94 95 if(cell.attrs.reverse) { 96 SetLowColor(foreground); 97 SetViewColor(foreground); 98 SetHighColor(background); 99 } else { 100 SetLowColor(background); 101 SetViewColor(background); 102 SetHighColor(foreground); 103 } 104 105 BPoint penLocation = PenLocation(); 106 FillRect(BRect(penLocation.x, penLocation.y - height.ascent, 107 penLocation.x + cell.width * fFontWidth, penLocation.y + 1), 108 B_SOLID_LOW); 109 110 if (cell.chars[0] == 0) { 111 DrawString(" "); 112 pos.col ++; 113 } else { 114 char buffer[VTERM_MAX_CHARS_PER_CELL]; 115 wcstombs(buffer, (wchar_t*)cell.chars, 116 VTERM_MAX_CHARS_PER_CELL); 117 118 DrawString(buffer); 119 pos.col += cell.width; 120 } 121 } 122 } 123 } 124 125 126 void TermView::FrameResized(float width, float height) 127 { 128 VTermRect newSize = PixelsToGlyphs(BRect(0, 0, width - 2 * kBorderSpacing, 129 height - 2 * kBorderSpacing)); 130 vterm_set_size(fTerm, newSize.end_row, newSize.end_col); 131 } 132 133 134 void TermView::GetPreferredSize(float* width, float* height) 135 { 136 if (width != NULL) 137 *width = kDefaultWidth * fFontWidth + 2 * kBorderSpacing; 138 if (height != NULL) 139 *height = kDefaultHeight * fFontHeight + 2 * kBorderSpacing; 140 } 141 142 143 void TermView::KeyDown(const char* bytes, int32 numBytes) 144 { 145 BMessage* keyEvent = new BMessage(kMsgDataWrite); 146 keyEvent->AddData("data", B_RAW_TYPE, bytes, numBytes); 147 be_app_messenger.SendMessage(keyEvent); 148 } 149 150 151 void TermView::MessageReceived(BMessage* message) 152 { 153 switch(message->what) 154 { 155 case 'DATA': 156 { 157 entry_ref ref; 158 if(message->FindRef("refs", &ref) == B_OK) 159 { 160 // The user just dropped a file on us 161 // TODO send it by XMODEM or so 162 } 163 break; 164 } 165 default: 166 BView::MessageReceived(message); 167 } 168 } 169 170 171 void TermView::PushBytes(const char* bytes, size_t length) 172 { 173 vterm_push_bytes(fTerm, bytes, length); 174 } 175 176 177 //#pragma mark - 178 179 180 VTermRect TermView::PixelsToGlyphs(BRect pixels) const 181 { 182 pixels.OffsetBy(-kBorderSpacing, -kBorderSpacing); 183 184 VTermRect rect; 185 rect.start_col = (int)floor(pixels.left / fFontWidth); 186 rect.end_col = (int)ceil(pixels.right / fFontWidth); 187 rect.start_row = (int)floor(pixels.top / fFontHeight); 188 rect.end_row = (int)ceil(pixels.bottom / fFontHeight); 189 /* 190 printf( 191 "TOP %d ch < %f px\n" 192 "BTM %d ch < %f px\n" 193 "LFT %d ch < %f px\n" 194 "RGH %d ch < %f px\n", 195 rect.start_row, pixels.top, 196 rect.end_row, pixels.bottom, 197 rect.start_col, pixels.left, 198 rect.end_col, pixels.right 199 ); 200 */ 201 return rect; 202 } 203 204 205 BRect TermView::GlyphsToPixels(const VTermRect& glyphs) const 206 { 207 BRect rect; 208 rect.top = glyphs.start_row * fFontHeight; 209 rect.bottom = glyphs.end_row * fFontHeight; 210 rect.left = glyphs.start_col * fFontWidth; 211 rect.right = glyphs.end_col * fFontWidth; 212 213 rect.OffsetBy(kBorderSpacing, kBorderSpacing); 214 /* 215 printf( 216 "TOP %d ch > %f px (%f)\n" 217 "BTM %d ch > %f px\n" 218 "LFT %d ch > %f px (%f)\n" 219 "RGH %d ch > %f px\n", 220 glyphs.start_row, rect.top, fFontHeight, 221 glyphs.end_row, rect.bottom, 222 glyphs.start_col, rect.left, fFontWidth, 223 glyphs.end_col, rect.right 224 ); 225 */ 226 return rect; 227 } 228 229 230 BRect TermView::GlyphsToPixels(const int width, const int height) const 231 { 232 VTermRect rect; 233 rect.start_row = 0; 234 rect.start_col = 0; 235 rect.end_row = height; 236 rect.end_col = width; 237 return GlyphsToPixels(rect); 238 } 239 240 241 void TermView::Damage(VTermRect rect) 242 { 243 Invalidate(); 244 // Invalidate(GlyphsToPixels(rect)); 245 } 246 247 248 /* static */ 249 int TermView::Damage(VTermRect rect, void* user) 250 { 251 TermView* view = (TermView*)user; 252 view->Damage(rect); 253 254 return 0; 255 } 256 257 258 const VTermScreenCallbacks TermView::sScreenCallbacks = { 259 &TermView::Damage, 260 /*.moverect =*/ NULL, 261 /*.movecursor =*/ NULL, 262 /*.settermprop =*/ NULL, 263 /*.setmousefunc =*/ NULL, 264 /*.bell =*/ NULL, 265 /*.resize =*/ NULL, 266 }; 267