xref: /haiku/src/tests/apps/miniterminal/ViewBuffer.cpp (revision 47a21c5c89fc9fd155a3929e5a8f6056b92a2053)
1160bd2ffSMichael Lotz /*
2160bd2ffSMichael Lotz  * ViewBuffer - Mimicing a frame buffer output - but using a BView.
3160bd2ffSMichael Lotz  * Based on frame_buffer_console.
4160bd2ffSMichael Lotz  *
5160bd2ffSMichael Lotz  * Copyright 2005 Michael Lotz. All rights reserved.
6*47a21c5cSAugustin Cavalier  * Distributed under the MIT License.
7160bd2ffSMichael Lotz  *
8160bd2ffSMichael Lotz  * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
9160bd2ffSMichael Lotz  * Distributed under the terms of the MIT License.
10160bd2ffSMichael Lotz  */
11160bd2ffSMichael Lotz 
128b0aee9fSStephan Aßmus #include <string.h>
138b0aee9fSStephan Aßmus 
14160bd2ffSMichael Lotz #include "ViewBuffer.h"
15160bd2ffSMichael Lotz 
16160bd2ffSMichael Lotz #define CHAR_WIDTH	7
1752e1c3c0SMichael Lotz #define CHAR_HEIGHT	13
18160bd2ffSMichael Lotz 
19160bd2ffSMichael Lotz // Palette is (black and white are swapt like in normal BeOS Terminal)
20160bd2ffSMichael Lotz //	0 - black,
21160bd2ffSMichael Lotz //	1 - blue,
22160bd2ffSMichael Lotz //	2 - green,
23160bd2ffSMichael Lotz //	3 - cyan,
24160bd2ffSMichael Lotz //	4 - red,
25160bd2ffSMichael Lotz //	5 - magenta,
26160bd2ffSMichael Lotz //	6 - yellow,
27160bd2ffSMichael Lotz //	7 - white
28160bd2ffSMichael Lotz //  8-15 - same but bright (we're ignoring those)
29160bd2ffSMichael Lotz 
30160bd2ffSMichael Lotz static uint32 sPalette32[] = {
31160bd2ffSMichael Lotz 	0xffffff,
32160bd2ffSMichael Lotz 	0x0000ff,
33160bd2ffSMichael Lotz 	0x00ff00,
34160bd2ffSMichael Lotz 	0x00ffff,
35160bd2ffSMichael Lotz 	0xff0000,
36160bd2ffSMichael Lotz 	0xff00ff,
37160bd2ffSMichael Lotz 	0xffff00,
38160bd2ffSMichael Lotz 	0x000000,
39160bd2ffSMichael Lotz };
40160bd2ffSMichael Lotz 
41160bd2ffSMichael Lotz 
ViewBuffer(BRect frame)42160bd2ffSMichael Lotz ViewBuffer::ViewBuffer(BRect frame)
438b0aee9fSStephan Aßmus 	:	BView(frame, "ViewBuffer", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS),
448b0aee9fSStephan Aßmus 		fColumns(frame.IntegerWidth() / CHAR_WIDTH),
458b0aee9fSStephan Aßmus 		fRows(frame.IntegerHeight() / CHAR_HEIGHT),
468b0aee9fSStephan Aßmus 		fGlyphGrid(NULL),
478b0aee9fSStephan Aßmus 		fResizeCallback(NULL),
488b0aee9fSStephan Aßmus 		// initially, the cursor is hidden
498b0aee9fSStephan Aßmus 		fCursorX(-1),
508b0aee9fSStephan Aßmus 		fCursorY(-1)
51160bd2ffSMichael Lotz {
52160bd2ffSMichael Lotz 	SetFont(be_fixed_font);
53160bd2ffSMichael Lotz 
54160bd2ffSMichael Lotz 	// initialize private palette
55160bd2ffSMichael Lotz 	for (int i = 0; i < 8; i++) {
56160bd2ffSMichael Lotz 		fPalette[i].red = (sPalette32[i] >> 16) & 0xff;
57160bd2ffSMichael Lotz 		fPalette[i].green = (sPalette32[i] >> 8) & 0xff;
58160bd2ffSMichael Lotz 		fPalette[i].blue = (sPalette32[i] >> 0) & 0xff;
59160bd2ffSMichael Lotz 		fPalette[i].alpha = 0xff;
60160bd2ffSMichael Lotz 	}
618b0aee9fSStephan Aßmus 
628b0aee9fSStephan Aßmus 	// initialize glyph grid
638b0aee9fSStephan Aßmus 	uint32 size = fRows * fColumns;
648b0aee9fSStephan Aßmus 	if (size > 0) {
658b0aee9fSStephan Aßmus 		fGlyphGrid = new uint16[size];
668b0aee9fSStephan Aßmus 		memset(fGlyphGrid, 0, size * sizeof(uint16));
678b0aee9fSStephan Aßmus 	}
68160bd2ffSMichael Lotz }
69160bd2ffSMichael Lotz 
70160bd2ffSMichael Lotz 
~ViewBuffer()71160bd2ffSMichael Lotz ViewBuffer::~ViewBuffer()
72160bd2ffSMichael Lotz {
738b0aee9fSStephan Aßmus 	delete[] fGlyphGrid;
74160bd2ffSMichael Lotz }
75160bd2ffSMichael Lotz 
76160bd2ffSMichael Lotz 
77160bd2ffSMichael Lotz void
FrameResized(float width,float height)78160bd2ffSMichael Lotz ViewBuffer::FrameResized(float width, float height)
79160bd2ffSMichael Lotz {
808b0aee9fSStephan Aßmus 	int32 oldColumns = fColumns;
818b0aee9fSStephan Aßmus 	int32 oldRows = fRows;
828b0aee9fSStephan Aßmus 
83160bd2ffSMichael Lotz 	fColumns = (int32)width / CHAR_WIDTH;
84160bd2ffSMichael Lotz 	fRows = (int32)height / CHAR_HEIGHT;
85160bd2ffSMichael Lotz 
868b0aee9fSStephan Aßmus 	// resize glyph grid
878b0aee9fSStephan Aßmus 	uint16* oldGlyphGrid = fGlyphGrid;
888b0aee9fSStephan Aßmus 	uint32 size = fRows * fColumns;
898b0aee9fSStephan Aßmus 	if (size > 0) {
908b0aee9fSStephan Aßmus 		fGlyphGrid = new uint16[size];
918b0aee9fSStephan Aßmus 		memset(fGlyphGrid, 0, size * sizeof(uint16));
928b0aee9fSStephan Aßmus 	} else
938b0aee9fSStephan Aßmus 		fGlyphGrid = NULL;
948b0aee9fSStephan Aßmus 	// transfer old glyph grid into new one
958b0aee9fSStephan Aßmus 	if (oldGlyphGrid && fGlyphGrid) {
968b0aee9fSStephan Aßmus 		int32 columns	= min_c(oldColumns, fColumns);
978b0aee9fSStephan Aßmus 		int32 rows		= min_c(oldRows, fRows);
988b0aee9fSStephan Aßmus 		for (int32 y = 0; y < rows; y++) {
998b0aee9fSStephan Aßmus 			for (int32 x = 0; x < columns; x++) {
1008b0aee9fSStephan Aßmus 				fGlyphGrid[y * fColumns + x] = oldGlyphGrid[y * oldColumns + x];
1018b0aee9fSStephan Aßmus 			}
1028b0aee9fSStephan Aßmus 		}
1038b0aee9fSStephan Aßmus 	}
1048b0aee9fSStephan Aßmus 	delete[] oldGlyphGrid;
1058b0aee9fSStephan Aßmus 
106160bd2ffSMichael Lotz 	if (fResizeCallback)
107160bd2ffSMichael Lotz 		fResizeCallback(fColumns, fRows, fResizeCallbackData);
108160bd2ffSMichael Lotz }
109160bd2ffSMichael Lotz 
110160bd2ffSMichael Lotz 
111160bd2ffSMichael Lotz status_t
GetSize(int32 * width,int32 * height)112160bd2ffSMichael Lotz ViewBuffer::GetSize(int32 *width, int32 *height)
113160bd2ffSMichael Lotz {
114160bd2ffSMichael Lotz 	*width = fColumns;
115160bd2ffSMichael Lotz 	*height = fRows;
116160bd2ffSMichael Lotz 	return B_OK;
117160bd2ffSMichael Lotz }
118160bd2ffSMichael Lotz 
119160bd2ffSMichael Lotz 
120160bd2ffSMichael Lotz void
SetResizeCallback(resize_callback callback,void * data)121160bd2ffSMichael Lotz ViewBuffer::SetResizeCallback(resize_callback callback, void *data)
122160bd2ffSMichael Lotz {
123160bd2ffSMichael Lotz 	fResizeCallback = callback;
124160bd2ffSMichael Lotz 	fResizeCallbackData = data;
125160bd2ffSMichael Lotz }
126160bd2ffSMichael Lotz 
127160bd2ffSMichael Lotz 
128160bd2ffSMichael Lotz uint8
ForegroundColor(uint8 attr)129160bd2ffSMichael Lotz ViewBuffer::ForegroundColor(uint8 attr)
130160bd2ffSMichael Lotz {
131160bd2ffSMichael Lotz 	return attr & 0x7;
132160bd2ffSMichael Lotz }
133160bd2ffSMichael Lotz 
134160bd2ffSMichael Lotz 
135160bd2ffSMichael Lotz uint8
BackgroundColor(uint8 attr)136160bd2ffSMichael Lotz ViewBuffer::BackgroundColor(uint8 attr)
137160bd2ffSMichael Lotz {
138160bd2ffSMichael Lotz 	return (attr >> 4) & 0x7;
139160bd2ffSMichael Lotz }
140160bd2ffSMichael Lotz 
141160bd2ffSMichael Lotz 
142160bd2ffSMichael Lotz rgb_color
GetPaletteEntry(uint8 index)143160bd2ffSMichael Lotz ViewBuffer::GetPaletteEntry(uint8 index)
144160bd2ffSMichael Lotz {
145160bd2ffSMichael Lotz 	return fPalette[index];
146160bd2ffSMichael Lotz }
147160bd2ffSMichael Lotz 
148160bd2ffSMichael Lotz 
149160bd2ffSMichael Lotz void
PutGlyph(int32 x,int32 y,uint8 glyph,uint8 attr)150160bd2ffSMichael Lotz ViewBuffer::PutGlyph(int32 x, int32 y, uint8 glyph, uint8 attr)
151160bd2ffSMichael Lotz {
152160bd2ffSMichael Lotz 	if (x >= fColumns || y >= fRows)
153160bd2ffSMichael Lotz 		return;
154160bd2ffSMichael Lotz 
155160bd2ffSMichael Lotz 	RenderGlyph(x, y, glyph, attr);
156160bd2ffSMichael Lotz }
157160bd2ffSMichael Lotz 
158160bd2ffSMichael Lotz 
159160bd2ffSMichael Lotz void
FillGlyph(int32 x,int32 y,int32 width,int32 height,uint8 glyph,uint8 attr)160160bd2ffSMichael Lotz ViewBuffer::FillGlyph(int32 x, int32 y, int32 width, int32 height, uint8 glyph, uint8 attr)
161160bd2ffSMichael Lotz {
162160bd2ffSMichael Lotz 	if (x >= fColumns || y >= fRows)
163160bd2ffSMichael Lotz 		return;
164160bd2ffSMichael Lotz 
165160bd2ffSMichael Lotz 	int32 left = x + width;
166160bd2ffSMichael Lotz 	if (left > fColumns)
167160bd2ffSMichael Lotz 		left = fColumns;
168160bd2ffSMichael Lotz 
169160bd2ffSMichael Lotz 	int32 bottom = y + height;
170160bd2ffSMichael Lotz 	if (bottom > fRows)
171160bd2ffSMichael Lotz 		bottom = fRows;
172160bd2ffSMichael Lotz 
173160bd2ffSMichael Lotz 	for (; y < bottom; y++) {
174160bd2ffSMichael Lotz 		for (int32 x2 = x; x2 < left; x2++) {
175160bd2ffSMichael Lotz 			RenderGlyph(x2, y, glyph, attr);
176160bd2ffSMichael Lotz 		}
177160bd2ffSMichael Lotz 	}
178160bd2ffSMichael Lotz }
179160bd2ffSMichael Lotz 
180160bd2ffSMichael Lotz 
181160bd2ffSMichael Lotz void
RenderGlyph(int32 x,int32 y,uint8 glyph,uint8 attr)182160bd2ffSMichael Lotz ViewBuffer::RenderGlyph(int32 x, int32 y, uint8 glyph, uint8 attr)
183160bd2ffSMichael Lotz {
184160bd2ffSMichael Lotz 	char string[2];
185160bd2ffSMichael Lotz 	string[0] = glyph;
186160bd2ffSMichael Lotz 	string[1] = 0;
187160bd2ffSMichael Lotz 
188160bd2ffSMichael Lotz 	if (LockLooper()) {
1898b0aee9fSStephan Aßmus 		_RenderGlyph(x, y, string, attr);
190160bd2ffSMichael Lotz 		Sync();
191160bd2ffSMichael Lotz 		UnlockLooper();
192160bd2ffSMichael Lotz 	}
1938b0aee9fSStephan Aßmus 	// remember the glyph in the grid
1948b0aee9fSStephan Aßmus 	if (fGlyphGrid) {
1958b0aee9fSStephan Aßmus 		fGlyphGrid[y * fColumns + x] = (glyph << 8) | attr;
1968b0aee9fSStephan Aßmus 	}
1978b0aee9fSStephan Aßmus }
1988b0aee9fSStephan Aßmus 
1998b0aee9fSStephan Aßmus 
2008b0aee9fSStephan Aßmus void
Draw(BRect updateRect)2018b0aee9fSStephan Aßmus ViewBuffer::Draw(BRect updateRect)
2028b0aee9fSStephan Aßmus {
2038b0aee9fSStephan Aßmus 	if (fGlyphGrid) {
2048b0aee9fSStephan Aßmus 		int32 startX	= max_c(0, (int32)(updateRect.left / CHAR_WIDTH));
2058b0aee9fSStephan Aßmus 		int32 endX		= min_c(fColumns - 1, (int32)(updateRect.right / CHAR_WIDTH) + 1);
2068b0aee9fSStephan Aßmus 		int32 startY	= max_c(0, (int32)(updateRect.top / CHAR_HEIGHT));
2078b0aee9fSStephan Aßmus 		int32 endY		= min_c(fRows - 1, (int32)(updateRect.bottom / CHAR_HEIGHT) + 1);
2088b0aee9fSStephan Aßmus 
2098b0aee9fSStephan Aßmus 		char string[2];
2108b0aee9fSStephan Aßmus 		string[1] = 0;
2118b0aee9fSStephan Aßmus 
2128b0aee9fSStephan Aßmus 		for (int32 y = startY; y <= endY; y++) {
2138b0aee9fSStephan Aßmus 			for (int32 x = startX; x <= endX; x++) {
2148b0aee9fSStephan Aßmus 				uint16 grid = fGlyphGrid[y * fColumns + x];
2158b0aee9fSStephan Aßmus 				uint8 glyph = grid >> 8;
2168b0aee9fSStephan Aßmus 				uint8 attr = grid & 0x00ff;
2178b0aee9fSStephan Aßmus 				string[0] = glyph;
2188b0aee9fSStephan Aßmus 				_RenderGlyph(x, y, string, attr, false);
2198b0aee9fSStephan Aßmus 			}
2208b0aee9fSStephan Aßmus 		}
2218b0aee9fSStephan Aßmus 	}
2228b0aee9fSStephan Aßmus 
2238b0aee9fSStephan Aßmus 	DrawCursor(fCursorX, fCursorY);
224160bd2ffSMichael Lotz }
225160bd2ffSMichael Lotz 
226160bd2ffSMichael Lotz 
227160bd2ffSMichael Lotz void
DrawCursor(int32 x,int32 y)228160bd2ffSMichael Lotz ViewBuffer::DrawCursor(int32 x, int32 y)
229160bd2ffSMichael Lotz {
230160bd2ffSMichael Lotz 	if (x < 0 || y < 0)
231160bd2ffSMichael Lotz 		return;
232160bd2ffSMichael Lotz 
233160bd2ffSMichael Lotz 	x *= CHAR_WIDTH;
234160bd2ffSMichael Lotz 	y *= CHAR_HEIGHT;
235160bd2ffSMichael Lotz 
236160bd2ffSMichael Lotz 	if (LockLooper()) {
237160bd2ffSMichael Lotz 		InvertRect(BRect(x, y, x + CHAR_WIDTH, y + CHAR_HEIGHT));
238160bd2ffSMichael Lotz 		Sync();
239160bd2ffSMichael Lotz 		UnlockLooper();
240160bd2ffSMichael Lotz 	}
241160bd2ffSMichael Lotz }
242160bd2ffSMichael Lotz 
243160bd2ffSMichael Lotz 
244160bd2ffSMichael Lotz void
MoveCursor(int32 x,int32 y)245160bd2ffSMichael Lotz ViewBuffer::MoveCursor(int32 x, int32 y)
246160bd2ffSMichael Lotz {
247160bd2ffSMichael Lotz 	DrawCursor(fCursorX, fCursorY);
248160bd2ffSMichael Lotz 	DrawCursor(x, y);
249160bd2ffSMichael Lotz 
250160bd2ffSMichael Lotz 	fCursorX = x;
251160bd2ffSMichael Lotz 	fCursorY = y;
252160bd2ffSMichael Lotz }
253160bd2ffSMichael Lotz 
254160bd2ffSMichael Lotz 
255160bd2ffSMichael Lotz void
Blit(int32 srcx,int32 srcy,int32 width,int32 height,int32 destx,int32 desty)256160bd2ffSMichael Lotz ViewBuffer::Blit(int32 srcx, int32 srcy, int32 width, int32 height, int32 destx, int32 desty)
257160bd2ffSMichael Lotz {
2588b0aee9fSStephan Aßmus 	// blit inside the glyph grid
2598b0aee9fSStephan Aßmus 	if (fGlyphGrid) {
2608b0aee9fSStephan Aßmus 		int32 xOffset = destx - srcx;
2618b0aee9fSStephan Aßmus 		int32 yOffset = desty - srcy;
2628b0aee9fSStephan Aßmus 
2638b0aee9fSStephan Aßmus 		int32 xIncrement;
2648b0aee9fSStephan Aßmus 		int32 yIncrement;
2658b0aee9fSStephan Aßmus 
2668b0aee9fSStephan Aßmus 		uint16* src = fGlyphGrid + srcy * fColumns + srcx;
2678b0aee9fSStephan Aßmus 
2688b0aee9fSStephan Aßmus 		if (xOffset > 0) {
2698b0aee9fSStephan Aßmus 			// copy from right to left
2708b0aee9fSStephan Aßmus 			xIncrement = -1;
2718b0aee9fSStephan Aßmus 			src += width - 1;
2728b0aee9fSStephan Aßmus 		} else {
2738b0aee9fSStephan Aßmus 			// copy from left to right
2748b0aee9fSStephan Aßmus 			xIncrement = 1;
2758b0aee9fSStephan Aßmus 		}
2768b0aee9fSStephan Aßmus 
2778b0aee9fSStephan Aßmus 		if (yOffset > 0) {
2788b0aee9fSStephan Aßmus 			// copy from bottom to top
2798b0aee9fSStephan Aßmus 			yIncrement = -fColumns;
2808b0aee9fSStephan Aßmus 			src += (height - 1) * fColumns;
2818b0aee9fSStephan Aßmus 		} else {
2828b0aee9fSStephan Aßmus 			// copy from top to bottom
2838b0aee9fSStephan Aßmus 			yIncrement = fColumns;
2848b0aee9fSStephan Aßmus 		}
2858b0aee9fSStephan Aßmus 
2868b0aee9fSStephan Aßmus 		uint16* dst = src + yOffset * fColumns + xOffset;
2878b0aee9fSStephan Aßmus 
2888b0aee9fSStephan Aßmus 		for (int32 y = 0; y < height; y++) {
2898b0aee9fSStephan Aßmus 			uint16* srcHandle = src;
2908b0aee9fSStephan Aßmus 			uint16* dstHandle = dst;
2918b0aee9fSStephan Aßmus 			for (int32 x = 0; x < width; x++) {
2928b0aee9fSStephan Aßmus 				*dstHandle = *srcHandle;
2938b0aee9fSStephan Aßmus 				srcHandle += xIncrement;
2948b0aee9fSStephan Aßmus 				dstHandle += xIncrement;
2958b0aee9fSStephan Aßmus 			}
2968b0aee9fSStephan Aßmus 			src += yIncrement;
2978b0aee9fSStephan Aßmus 			dst += yIncrement;
2988b0aee9fSStephan Aßmus 		}
2998b0aee9fSStephan Aßmus 	}
3008b0aee9fSStephan Aßmus 
301160bd2ffSMichael Lotz 	height *= CHAR_HEIGHT;
302160bd2ffSMichael Lotz 	width *= CHAR_WIDTH;
303160bd2ffSMichael Lotz 
304160bd2ffSMichael Lotz 	srcx *= CHAR_WIDTH;
305160bd2ffSMichael Lotz 	srcy *= CHAR_HEIGHT;
306160bd2ffSMichael Lotz 	BRect source(srcx, srcy, srcx + width, srcy + height);
307160bd2ffSMichael Lotz 
308160bd2ffSMichael Lotz 	destx *= CHAR_WIDTH;
309160bd2ffSMichael Lotz 	desty *= CHAR_HEIGHT;
310160bd2ffSMichael Lotz 	BRect dest(destx, desty, destx + width, desty + height);
311160bd2ffSMichael Lotz 
312160bd2ffSMichael Lotz 	if (LockLooper()) {
313160bd2ffSMichael Lotz 		CopyBits(source, dest);
314160bd2ffSMichael Lotz 		Sync();
315160bd2ffSMichael Lotz 		UnlockLooper();
316160bd2ffSMichael Lotz 	}
317160bd2ffSMichael Lotz }
318160bd2ffSMichael Lotz 
319160bd2ffSMichael Lotz 
320160bd2ffSMichael Lotz void
Clear(uint8 attr)321160bd2ffSMichael Lotz ViewBuffer::Clear(uint8 attr)
322160bd2ffSMichael Lotz {
323160bd2ffSMichael Lotz 	if (LockLooper()) {
324160bd2ffSMichael Lotz 		SetLowColor(GetPaletteEntry(BackgroundColor(attr)));
325160bd2ffSMichael Lotz 		SetViewColor(LowColor());
326160bd2ffSMichael Lotz 		FillRect(Frame(), B_SOLID_LOW);
327160bd2ffSMichael Lotz 		Sync();
328160bd2ffSMichael Lotz 		UnlockLooper();
329160bd2ffSMichael Lotz 	}
330160bd2ffSMichael Lotz 
331160bd2ffSMichael Lotz 	fCursorX = -1;
332160bd2ffSMichael Lotz 	fCursorY = -1;
3338b0aee9fSStephan Aßmus 
3348b0aee9fSStephan Aßmus 	if (fGlyphGrid)
3358b0aee9fSStephan Aßmus 		memset(fGlyphGrid, 0, fRows * fColumns * sizeof(uint16));
336160bd2ffSMichael Lotz }
3378b0aee9fSStephan Aßmus 
3388b0aee9fSStephan Aßmus 
3398b0aee9fSStephan Aßmus void
_RenderGlyph(int32 x,int32 y,const char * string,uint8 attr,bool fill)3408b0aee9fSStephan Aßmus ViewBuffer::_RenderGlyph(int32 x, int32 y, const char* string, uint8 attr, bool fill)
3418b0aee9fSStephan Aßmus {
3428b0aee9fSStephan Aßmus 	BPoint where(x * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT - 3);
3438b0aee9fSStephan Aßmus 
3448b0aee9fSStephan Aßmus 	SetHighColor(GetPaletteEntry(ForegroundColor(attr)));
3458b0aee9fSStephan Aßmus 	if (fill) {
3468b0aee9fSStephan Aßmus 		SetLowColor(GetPaletteEntry(BackgroundColor(attr)));
3478b0aee9fSStephan Aßmus 		FillRect(BRect(x * CHAR_WIDTH, y * CHAR_HEIGHT,
3488b0aee9fSStephan Aßmus 					   (x + 1) * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT),
3498b0aee9fSStephan Aßmus 				 B_SOLID_LOW);
3508b0aee9fSStephan Aßmus 	}
3518b0aee9fSStephan Aßmus 	DrawString(string, where);
3528b0aee9fSStephan Aßmus }
3538b0aee9fSStephan Aßmus 
354