xref: /haiku/src/apps/serialconnect/TermView.cpp (revision 3b07762c548ec4016dea480d1061577cd15ec614)
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