xref: /haiku/src/tests/apps/miniterminal/ViewBuffer.cpp (revision f2b4344867e97c3f4e742a1b4a15e6879644601a)
1 /*
2  * ViewBuffer - Mimicing a frame buffer output - but using a BView.
3  * Based on frame_buffer_console.
4  *
5  * Copyright 2005 Michael Lotz. All rights reserved.
6  * Distributed under the Haiku License.
7  *
8  * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
9  * Distributed under the terms of the MIT License.
10  */
11 
12 #include <string.h>
13 
14 #include "ViewBuffer.h"
15 
16 #define CHAR_WIDTH	7
17 #define CHAR_HEIGHT	13
18 
19 // Palette is (black and white are swapt like in normal BeOS Terminal)
20 //	0 - black,
21 //	1 - blue,
22 //	2 - green,
23 //	3 - cyan,
24 //	4 - red,
25 //	5 - magenta,
26 //	6 - yellow,
27 //	7 - white
28 //  8-15 - same but bright (we're ignoring those)
29 
30 static uint32 sPalette32[] = {
31 	0xffffff,
32 	0x0000ff,
33 	0x00ff00,
34 	0x00ffff,
35 	0xff0000,
36 	0xff00ff,
37 	0xffff00,
38 	0x000000,
39 };
40 
41 
42 ViewBuffer::ViewBuffer(BRect frame)
43 	:	BView(frame, "ViewBuffer", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS),
44 		fColumns(frame.IntegerWidth() / CHAR_WIDTH),
45 		fRows(frame.IntegerHeight() / CHAR_HEIGHT),
46 		fGlyphGrid(NULL),
47 		fResizeCallback(NULL),
48 		// initially, the cursor is hidden
49 		fCursorX(-1),
50 		fCursorY(-1)
51 {
52 	SetFont(be_fixed_font);
53 
54 	// initialize private palette
55 	for (int i = 0; i < 8; i++) {
56 		fPalette[i].red = (sPalette32[i] >> 16) & 0xff;
57 		fPalette[i].green = (sPalette32[i] >> 8) & 0xff;
58 		fPalette[i].blue = (sPalette32[i] >> 0) & 0xff;
59 		fPalette[i].alpha = 0xff;
60 	}
61 
62 	// initialize glyph grid
63 	uint32 size = fRows * fColumns;
64 	if (size > 0) {
65 		fGlyphGrid = new uint16[size];
66 		memset(fGlyphGrid, 0, size * sizeof(uint16));
67 	}
68 }
69 
70 
71 ViewBuffer::~ViewBuffer()
72 {
73 	delete[] fGlyphGrid;
74 }
75 
76 
77 void
78 ViewBuffer::FrameResized(float width, float height)
79 {
80 	int32 oldColumns = fColumns;
81 	int32 oldRows = fRows;
82 
83 	fColumns = (int32)width / CHAR_WIDTH;
84 	fRows = (int32)height / CHAR_HEIGHT;
85 
86 	// resize glyph grid
87 	uint16* oldGlyphGrid = fGlyphGrid;
88 	uint32 size = fRows * fColumns;
89 	if (size > 0) {
90 		fGlyphGrid = new uint16[size];
91 		memset(fGlyphGrid, 0, size * sizeof(uint16));
92 	} else
93 		fGlyphGrid = NULL;
94 	// transfer old glyph grid into new one
95 	if (oldGlyphGrid && fGlyphGrid) {
96 		int32 columns	= min_c(oldColumns, fColumns);
97 		int32 rows		= min_c(oldRows, fRows);
98 		for (int32 y = 0; y < rows; y++) {
99 			for (int32 x = 0; x < columns; x++) {
100 				fGlyphGrid[y * fColumns + x] = oldGlyphGrid[y * oldColumns + x];
101 			}
102 		}
103 	}
104 	delete[] oldGlyphGrid;
105 
106 	if (fResizeCallback)
107 		fResizeCallback(fColumns, fRows, fResizeCallbackData);
108 }
109 
110 
111 status_t
112 ViewBuffer::GetSize(int32 *width, int32 *height)
113 {
114 	*width = fColumns;
115 	*height = fRows;
116 	return B_OK;
117 }
118 
119 
120 void
121 ViewBuffer::SetResizeCallback(resize_callback callback, void *data)
122 {
123 	fResizeCallback = callback;
124 	fResizeCallbackData = data;
125 }
126 
127 
128 uint8
129 ViewBuffer::ForegroundColor(uint8 attr)
130 {
131 	return attr & 0x7;
132 }
133 
134 
135 uint8
136 ViewBuffer::BackgroundColor(uint8 attr)
137 {
138 	return (attr >> 4) & 0x7;
139 }
140 
141 
142 rgb_color
143 ViewBuffer::GetPaletteEntry(uint8 index)
144 {
145 	return fPalette[index];
146 }
147 
148 
149 void
150 ViewBuffer::PutGlyph(int32 x, int32 y, uint8 glyph, uint8 attr)
151 {
152 	if (x >= fColumns || y >= fRows)
153 		return;
154 
155 	RenderGlyph(x, y, glyph, attr);
156 }
157 
158 
159 void
160 ViewBuffer::FillGlyph(int32 x, int32 y, int32 width, int32 height, uint8 glyph, uint8 attr)
161 {
162 	if (x >= fColumns || y >= fRows)
163 		return;
164 
165 	int32 left = x + width;
166 	if (left > fColumns)
167 		left = fColumns;
168 
169 	int32 bottom = y + height;
170 	if (bottom > fRows)
171 		bottom = fRows;
172 
173 	for (; y < bottom; y++) {
174 		for (int32 x2 = x; x2 < left; x2++) {
175 			RenderGlyph(x2, y, glyph, attr);
176 		}
177 	}
178 }
179 
180 
181 void
182 ViewBuffer::RenderGlyph(int32 x, int32 y, uint8 glyph, uint8 attr)
183 {
184 	char string[2];
185 	string[0] = glyph;
186 	string[1] = 0;
187 
188 	if (LockLooper()) {
189 		_RenderGlyph(x, y, string, attr);
190 		Sync();
191 		UnlockLooper();
192 	}
193 	// remember the glyph in the grid
194 	if (fGlyphGrid) {
195 		fGlyphGrid[y * fColumns + x] = (glyph << 8) | attr;
196 	}
197 }
198 
199 
200 void
201 ViewBuffer::Draw(BRect updateRect)
202 {
203 	if (fGlyphGrid) {
204 		int32 startX	= max_c(0, (int32)(updateRect.left / CHAR_WIDTH));
205 		int32 endX		= min_c(fColumns - 1, (int32)(updateRect.right / CHAR_WIDTH) + 1);
206 		int32 startY	= max_c(0, (int32)(updateRect.top / CHAR_HEIGHT));
207 		int32 endY		= min_c(fRows - 1, (int32)(updateRect.bottom / CHAR_HEIGHT) + 1);
208 
209 		char string[2];
210 		string[1] = 0;
211 
212 		for (int32 y = startY; y <= endY; y++) {
213 			for (int32 x = startX; x <= endX; x++) {
214 				uint16 grid = fGlyphGrid[y * fColumns + x];
215 				uint8 glyph = grid >> 8;
216 				uint8 attr = grid & 0x00ff;
217 				string[0] = glyph;
218 				_RenderGlyph(x, y, string, attr, false);
219 			}
220 		}
221 	}
222 
223 	DrawCursor(fCursorX, fCursorY);
224 }
225 
226 
227 void
228 ViewBuffer::DrawCursor(int32 x, int32 y)
229 {
230 	if (x < 0 || y < 0)
231 		return;
232 
233 	x *= CHAR_WIDTH;
234 	y *= CHAR_HEIGHT;
235 
236 	if (LockLooper()) {
237 		InvertRect(BRect(x, y, x + CHAR_WIDTH, y + CHAR_HEIGHT));
238 		Sync();
239 		UnlockLooper();
240 	}
241 }
242 
243 
244 void
245 ViewBuffer::MoveCursor(int32 x, int32 y)
246 {
247 	DrawCursor(fCursorX, fCursorY);
248 	DrawCursor(x, y);
249 
250 	fCursorX = x;
251 	fCursorY = y;
252 }
253 
254 
255 void
256 ViewBuffer::Blit(int32 srcx, int32 srcy, int32 width, int32 height, int32 destx, int32 desty)
257 {
258 	// blit inside the glyph grid
259 	if (fGlyphGrid) {
260 		int32 xOffset = destx - srcx;
261 		int32 yOffset = desty - srcy;
262 
263 		int32 xIncrement;
264 		int32 yIncrement;
265 
266 		uint16* src = fGlyphGrid + srcy * fColumns + srcx;
267 
268 		if (xOffset > 0) {
269 			// copy from right to left
270 			xIncrement = -1;
271 			src += width - 1;
272 		} else {
273 			// copy from left to right
274 			xIncrement = 1;
275 		}
276 
277 		if (yOffset > 0) {
278 			// copy from bottom to top
279 			yIncrement = -fColumns;
280 			src += (height - 1) * fColumns;
281 		} else {
282 			// copy from top to bottom
283 			yIncrement = fColumns;
284 		}
285 
286 		uint16* dst = src + yOffset * fColumns + xOffset;
287 
288 		for (int32 y = 0; y < height; y++) {
289 			uint16* srcHandle = src;
290 			uint16* dstHandle = dst;
291 			for (int32 x = 0; x < width; x++) {
292 				*dstHandle = *srcHandle;
293 				srcHandle += xIncrement;
294 				dstHandle += xIncrement;
295 			}
296 			src += yIncrement;
297 			dst += yIncrement;
298 		}
299 	}
300 
301 	height *= CHAR_HEIGHT;
302 	width *= CHAR_WIDTH;
303 
304 	srcx *= CHAR_WIDTH;
305 	srcy *= CHAR_HEIGHT;
306 	BRect source(srcx, srcy, srcx + width, srcy + height);
307 
308 	destx *= CHAR_WIDTH;
309 	desty *= CHAR_HEIGHT;
310 	BRect dest(destx, desty, destx + width, desty + height);
311 
312 	if (LockLooper()) {
313 		CopyBits(source, dest);
314 		Sync();
315 		UnlockLooper();
316 	}
317 }
318 
319 
320 void
321 ViewBuffer::Clear(uint8 attr)
322 {
323 	if (LockLooper()) {
324 		SetLowColor(GetPaletteEntry(BackgroundColor(attr)));
325 		SetViewColor(LowColor());
326 		FillRect(Frame(), B_SOLID_LOW);
327 		Sync();
328 		UnlockLooper();
329 	}
330 
331 	fCursorX = -1;
332 	fCursorY = -1;
333 
334 	if (fGlyphGrid)
335 		memset(fGlyphGrid, 0, fRows * fColumns * sizeof(uint16));
336 }
337 
338 
339 void
340 ViewBuffer::_RenderGlyph(int32 x, int32 y, const char* string, uint8 attr, bool fill)
341 {
342 	BPoint where(x * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT - 3);
343 
344 	SetHighColor(GetPaletteEntry(ForegroundColor(attr)));
345 	if (fill) {
346 		SetLowColor(GetPaletteEntry(BackgroundColor(attr)));
347 		FillRect(BRect(x * CHAR_WIDTH, y * CHAR_HEIGHT,
348 					   (x + 1) * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT),
349 				 B_SOLID_LOW);
350 	}
351 	DrawString(string, where);
352 }
353 
354