sdlterm/src/sdlterm.h
author Radek Brich <radek.brich@devl.cz>
Sat, 05 Jan 2013 16:47:30 +0100
changeset 49 1611c462c3e3
parent 48 1f00e90fd72a
child 50 c5b8b9d2da95
permissions -rw-r--r--
Update sdlterm: Optimize commit() - use two cell buffers, redraw only dirty cells, not everything. Fix keypress event, filter mousemove.

#include "SDL.h"
#include "SDL_ttf.h"

#include <map>
#include <vector>


class GlyphCache
{
public:
	SDL_Surface *lookup_glyph(Uint16 ch);
	void put_glyph(Uint16 ch, SDL_Surface *srf);
	void flush();

private:
	std::map<Uint16, SDL_Surface*> _glyph_map;
};


class GlyphRenderer
{
public:
	GlyphRenderer();
	~GlyphRenderer();

	void open_font(const char *fname_regular, const char *fname_bold, int ptsize);
	void close_font();

	// do not free surface returned!
	SDL_Surface *render_glyph(Uint16 ch);

	int get_cell_width() { return _cell_width; };
	int get_cell_height() { return _cell_height; };

private:
	TTF_Font *_font_regular;
	TTF_Font *_font_bold;
	int _cell_width;
	int _cell_height;
	GlyphCache _cache;
};


struct TerminalCell
{
	Uint16 ch;
	Uint16 attr;
	bool operator !=(const TerminalCell &rhs) const { return ch != rhs.ch || attr != rhs.attr; };
};


class TerminalScreen
{
public:
	TerminalScreen(): _screen_surface(NULL), _render() {};
	~TerminalScreen() {};

	void select_font(const char *fname_regular, const char *fname_bold, int ptsize);
	void resize(int pxwidth, int pxheight);

	void erase();
	void putch(int x, int y, Uint16 ch, Uint16 attr);
	void commit();

	int get_width() { return _width; };
	int get_height() { return _height; };
	int get_cell_width() { return _cell_width; };
	int get_cell_height() { return _cell_height; };

private:
	SDL_Surface *_screen_surface;
	std::vector<TerminalCell> _cells_front;
	std::vector<TerminalCell> _cells_back;
	GlyphRenderer _render;

	int _pixel_width;  // terminal window width in pixels
	int _pixel_height;
	int _width;  // width in characters
	int _height; // height in characters
	int _cell_width;  // character cell width in pixels
	int _cell_height;

	void _reset_cells();
};


struct Event
{
	enum { QUIT, RESIZE, KEYPRESS, MOUSEDOWN, MOUSEUP, MOUSEMOVE, MOUSEWHEEL };
	int type;

	union
	{
		struct
		{
			char keyname[10];
			Uint16 unicode;
		} key;
		struct
		{
			int x, y;
			int button;
		} mouse;
	};
};


class Terminal
{
public:
	Terminal();
	~Terminal();

	void select_font(const char *fname_regular, const char *fname_bold, int ptsize)
		{ _screen.select_font(fname_regular, fname_bold, ptsize); };
	void resize(int pxwidth, int pxheight) { _screen.resize(pxwidth, pxheight); };

	void erase() { _screen.erase(); };
	void putch(int x, int y, Uint16 ch) { _screen.putch(x, y, ch, _attr); };
	void commit() { _screen.commit(); };

	Uint16 prepare_attr(Uint8 fg, Uint8 bg, Uint8 style) { return fg | bg << 8 | style << 16; };
	void set_attr(Uint16 value) { _attr = value; };

	void set_cursor(int x, int y) { _cursor_x = x; _cursor_y = y; };
	void show_cursor(bool visible) { _cursor_visible = visible; };

	void get_next_event(Event &event);

	int get_width() { return _screen.get_width(); };
	int get_height() { return _screen.get_height(); };

private:
	TerminalScreen _screen;
	Uint16 _attr;
	int _cursor_x;
	int _cursor_y;
	bool _cursor_visible;

	int _mousemove_last_x;
	int _mousemove_last_y;

	const char *_translate_keyname(SDLKey sym);
};