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