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