Actually call on_reset callback
[lsnes.git] / src / platform / wxwidgets / textrender.cpp
blob876fdd3cbc03b5f3ed88c54131ad56b3516544cc
1 #include "platform/wxwidgets/textrender.hpp"
2 #include "platform/wxwidgets/platform.hpp"
3 #include "fonts/wrapper.hpp"
4 #include "library/utf8.hpp"
5 #include "library/string.hpp"
6 #include <wx/dc.h>
7 #include <wx/dcclient.h>
8 #include <wx/image.h>
10 extern const uint32_t text_framebuffer::element::white = 0xFFFFFF;
11 extern const uint32_t text_framebuffer::element::black = 0x000000;
13 text_framebuffer::text_framebuffer()
15 width = 0;
16 height = 0;
19 text_framebuffer::text_framebuffer(size_t w, size_t h)
21 width = 0;
22 height = 0;
23 set_size(w, h);
26 void text_framebuffer::set_size(size_t w, size_t h)
28 if(w == width && h == height)
29 return;
30 std::vector<element> newfb;
31 newfb.resize(w * h);
32 for(size_t i = 0; i < h && i < height; i++)
33 for(size_t j = 0; j < w && j < width; j++)
34 newfb[i * w + j] = buffer[i * width + j];
35 buffer.swap(newfb);
36 width = w;
37 height = h;
40 std::pair<size_t, size_t> text_framebuffer::get_cell()
42 return std::make_pair(8, 16);
45 std::pair<size_t, size_t> text_framebuffer::get_pixels()
47 auto x = get_cell();
48 return std::make_pair(x.first * width, x.second * height);
51 void text_framebuffer::render(char* tbuffer)
53 size_t stride = 24 * width;
54 size_t cellstride = 24;
55 for(size_t y = 0; y < height; y++) {
56 size_t xp = 0;
57 for(size_t x = 0; x < width; x++) {
58 if(xp >= width)
59 break; //No more space in row.
60 char* cellbase = tbuffer + y * (16 * stride) + xp * cellstride;
61 const element& e = buffer[y * width + x];
62 const framebuffer::font::glyph& g = main_font.get_glyph(e.ch);
63 char bgb = (e.bg >> 16);
64 char bgg = (e.bg >> 8);
65 char bgr = (e.bg >> 0);
66 char fgb = (e.fg >> 16);
67 char fgg = (e.fg >> 8);
68 char fgr = (e.fg >> 0);
70 uint32_t cells = g.get_width() / 8;
71 uint32_t drawc = 8 * std::min(cells, (uint32_t)((xp < width - 1) ? 2 : 1));
72 for(size_t y2 = 0; y2 < g.get_height(); y2++) {
73 for(size_t j = 0; j < drawc; j++) {
74 if(g.read_pixel(j, y2)) {
75 cellbase[3 * j + 0] = fgr;
76 cellbase[3 * j + 1] = fgg;
77 cellbase[3 * j + 2] = fgb;
78 } else {
79 cellbase[3 * j + 0] = bgr;
80 cellbase[3 * j + 1] = bgg;
81 cellbase[3 * j + 2] = bgb;
84 cellbase += stride;
86 xp += cells;
91 size_t text_framebuffer::text_width(const std::string& text)
93 auto x = main_font.get_metrics(text, 0, false, false);
94 return x.first / 8;
97 size_t text_framebuffer::write(const std::string& str, size_t w, size_t x, size_t y, uint32_t fg, uint32_t bg)
99 return write(utf8::to32(str), w, x, y, fg, bg);
102 size_t text_framebuffer::write(const std::u32string& str, size_t w, size_t x, size_t y, uint32_t fg, uint32_t bg)
104 if(y >= height)
105 return 0;
106 size_t pused = 0;
107 for(auto u : str) {
108 if(u == 9) {
109 //TAB.
110 do {
111 if(x + pused < width) {
112 element& e = buffer[y * width + x + pused];
113 e.ch = 32; //Space.
114 e.fg = fg;
115 e.bg = bg;
117 pused++;
118 } while(pused % 8);
119 continue;
121 const framebuffer::font::glyph& g = main_font.get_glyph(u);
122 if(x + pused < width) {
123 element& e = buffer[y * width + x + pused];
124 e.ch = u;
125 e.fg = fg;
126 e.bg = bg;
128 pused += g.get_width() / 8;
130 while(pused < w) {
131 //Pad with spaces.
132 if(x + pused < width) {
133 element& e = buffer[y * width + x + pused];
134 e.ch = 32;
135 e.fg = fg;
136 e.bg = bg;
138 pused++;
140 return x + pused;
143 text_framebuffer_panel::text_framebuffer_panel(wxWindow* parent, size_t w, size_t h, wxWindowID id,
144 wxWindow* _redirect)
145 : wxPanel(parent, id), text_framebuffer(w, h)
147 CHECK_UI_THREAD;
148 redirect = _redirect;
149 auto psize = get_pixels();
150 size_changed = false;
151 locked = false;
152 paint_requested = false;
153 SetMinSize(wxSize(psize.first, psize.second));
154 this->Connect(wxEVT_PAINT, wxPaintEventHandler(text_framebuffer_panel::on_paint), NULL, this);
155 this->Connect(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(text_framebuffer_panel::on_erase), NULL, this);
156 this->Connect(wxEVT_SET_FOCUS, wxFocusEventHandler(text_framebuffer_panel::on_focus), NULL, this);
159 text_framebuffer_panel::~text_framebuffer_panel()
163 void text_framebuffer_panel::set_size(size_t _width, size_t _height)
165 CHECK_UI_THREAD;
166 text_framebuffer::set_size(_width, _height);
167 auto psize = get_pixels();
168 buffer.resize(psize.first * psize.second * 3);
169 if(!locked) {
170 SetMinSize(wxSize(psize.first, psize.second));
171 } else
172 size_changed = true;
173 request_paint();
176 void text_framebuffer_panel::request_paint()
178 CHECK_UI_THREAD;
179 if(size_changed) {
180 auto psize = get_pixels();
181 SetMinSize(wxSize(psize.first, psize.second));
182 size_changed = false;
183 paint_requested = true;
184 Refresh();
185 } else if(!paint_requested) {
186 paint_requested = true;
187 Refresh();
191 void text_framebuffer_panel::on_erase(wxEraseEvent& e)
195 void text_framebuffer_panel::on_paint(wxPaintEvent& e)
197 CHECK_UI_THREAD;
198 locked = true;
199 auto size = GetSize();
200 text_framebuffer::set_size((size.x + 7) / 8, (size.y + 15) / 16);
201 auto psize = get_pixels();
202 buffer.resize(psize.first * psize.second * 3);
203 prepare_paint();
204 locked = false;
205 psize = get_pixels();
206 wxPaintDC dc(this);
207 render(&buffer[0]);
208 wxBitmap bmp1(wxImage(psize.first, psize.second, reinterpret_cast<unsigned char*>(&buffer[0]),
209 true));
210 dc.DrawBitmap(bmp1, 0, 0, false);
211 paint_requested = false;
214 void text_framebuffer_panel::on_focus(wxFocusEvent& e)
216 CHECK_UI_THREAD;
217 if(redirect)
218 redirect->SetFocus();