Branch data Line data Source code
1 : : #ifndef bqtRenderingScreenHH
2 : : #define bqtRenderingScreenHH
3 : : /** @file rendering/window.hh
4 : : * @brief Defines Window, a renderer and manager of screen contents.
5 : : */
6 : :
7 : : #include <cstdint>
8 : : #include <vector>
9 : : #include <tuple>
10 : : #include <cstring>
11 : :
12 : : #include "cset.hh"
13 : : #include "cell.hh"
14 : :
15 : : /** Window: A two-dimensional storage for cells. */
16 : 407 : struct Window
17 : : {
18 : : std::vector<Cell> cells; ///< Storage for cells. Indexed row-first. Size: xsize*ysize */
19 : : std::size_t xsize; ///< Width of window in cells
20 : : std::size_t ysize; ///< Height of window in cells
21 : : std::size_t cursx=0; ///< Cursor location (horizontal)
22 : : std::size_t cursy=0; ///< Cursor location (vertical)
23 : : bool inverse = false; ///< Whether screen-wide inverse effect is in effect
24 : : bool cursorvis = true; ///< Whether cursor is visible
25 : : unsigned cursorcolor = 0xFFFFFF; ///< Color of cursor
26 : : unsigned mousecolor1 = 0xFFFFFF; ///< Ignored
27 : : unsigned mousecolor2 = 0xFFFFFF; ///< Ignored
28 : : unsigned mouseselectcolor = 0xFFFFFF; ///< Ignored
29 : : Cell blank {}; ///< The current "blank" cell. It is used as the model cell for inserting empty rows.
30 : : private:
31 : : std::size_t lastcursx, lastcursy;
32 : : unsigned lasttimer=0;
33 : : public:
34 : : /** Initializes the window to the given size. Each cell is default-initialized. */
35 : 407 : Window(std::size_t xs, std::size_t ys) : cells(xs*ys), xsize(xs), ysize(ys)
36 : : {
37 [ + - ]: 407 : Dirtify();
38 : 407 : }
39 : :
40 : : /** Used in scrolling: Fills the given region with the blank character. */
41 : 32 : void FillBox(std::size_t x, std::size_t y, std::size_t width, std::size_t height)
42 : : {
43 [ + + ]: 88 : for(std::size_t h=0; h<height; ++h)
44 [ + + ]: 4167 : for(std::size_t w=0; w<width; ++w)
45 : : {
46 : 4111 : auto tx = x+w, ty = y+h;
47 : 4111 : PutCh(tx, ty, blank);
48 : : }
49 : 32 : }
50 : : /** Used in erasing: Fills the given region with the given character,
51 : : * but does not change protected cells.
52 : : */
53 : 416 : void FillBox(std::size_t x, std::size_t y, std::size_t width, std::size_t height, Cell with)
54 : : {
55 [ + + ]: 9424 : for(std::size_t h=0; h<height; ++h)
56 [ + + ]: 713282 : for(std::size_t w=0; w<width; ++w)
57 : : {
58 : 704274 : auto tx = x+w, ty = y+h;
59 [ + + + - ]: 704274 : if(with.ch != blank.ch || !cells[ty*xsize+tx].protect)
60 : 704274 : PutCh(tx, ty, with);
61 : : }
62 : 416 : }
63 : : /** Copies a rectangle from given coordinates to the target coordinates.
64 : : * @param tgtx Target X-coordinate
65 : : * @param tgty Target Y-coordinate
66 : : * @param srcx Source X-coordinate
67 : : * @param srcy Source Y-coordinate
68 : : * @param width Width of region to copy
69 : : * @param height Height of region to copy
70 : : */
71 : 35 : void CopyText(std::size_t tgtx,std::size_t tgty, std::size_t srcx,std::size_t srcy,
72 : : std::size_t width,std::size_t height)
73 : : {
74 : 715 : auto hcopy_oneline = [&](std::size_t ty, std::size_t sy)
75 : : {
76 [ + + ]: 680 : if(tgtx < srcx)
77 [ + + ]: 240 : for(std::size_t w=0; w<width; ++w)
78 : 229 : PutCh(tgtx+w, ty, cells[sy*xsize+(srcx+w)]);
79 : : else
80 [ + + ]: 51293 : for(std::size_t w=width; w-- > 0; )
81 : 50624 : PutCh(tgtx+w, ty, cells[sy*xsize+(srcx+w)]);
82 : 715 : };
83 [ + + ]: 35 : if(tgty < srcy)
84 [ + + ]: 615 : for(std::size_t h=0; h<height; ++h)
85 : 589 : hcopy_oneline(tgty+h, srcy+h);
86 : : else
87 [ + + ]: 100 : for(std::size_t h=height; h-- > 0; )
88 : 91 : hcopy_oneline(tgty+h, srcy+h);
89 : 35 : }
90 : :
91 : : /** Marks the given cell as dirty and places an invalid character there. */
92 : 32 : void Dirtify(std::size_t x, std::size_t y)
93 : : {
94 [ - + ]: 32 : auto& tgt = cells[y*xsize+x];
95 : : // Write an invalid character, to make sure it gets properly
96 : : // cleared when a valid character gets written instead.
97 : : // This glyph must _not_ register as doublewidth.
98 : 32 : tgt.ch = 0xFFFE;
99 [ - + ]: 32 : tgt.dirty = true;
100 : : }
101 : : /** Marks entire screen as dirty (without changing ch)
102 : : * and forgets the cursor's last known position.
103 : : */
104 : : void Dirtify();
105 : :
106 : : /** Places a cell at the given position on screen.
107 : : * If the cell changed, it is marked dirty.
108 : : */
109 : 765374 : void PutCh(std::size_t x, std::size_t y, const Cell& c)
110 : : {
111 [ + + ]: 765374 : auto& tgt = cells[y*xsize+x];
112 [ + + ]: 765374 : if(tgt != c)
113 : : {
114 : 49004 : tgt = c;
115 : 49004 : tgt.dirty = true;
116 : : }
117 : 765374 : }
118 : :
119 : : /** Places a character at the given position on screen.
120 : : * Attributes are copied from the blank cell,
121 : : * except render_size which is kept unchanged.
122 : : */
123 : 6136 : void PutCh(std::size_t x, std::size_t y, char32_t c, int cset = 0)
124 : : {
125 : : /*
126 : : cset options:
127 : : 0 = ascii
128 : : 1 = dec graphics
129 : : */
130 : 6136 : Cell ch = blank;
131 [ + + ]: 6136 : if(cset)
132 : : {
133 : 1 : c = TranslateCSet(c, cset);
134 : : }
135 : 6136 : ch.ch = c;
136 : 6136 : ch.render_size = cells[y*xsize+x].render_size;
137 : : /*if(c != U' ')
138 : : {
139 : : fprintf(stderr, "Ch at (%zu,%zu): <%c>\n", x,y, int(c));
140 : : }*/
141 : 6136 : PutCh(x, y, ch);
142 : 6136 : }
143 : : /** Same as PutCh(x,y,c,cset), but instead of taking attributes from the blank
144 : : * cell, preserves existing attributes on screen.
145 : : */
146 : 1 : void PutCh_KeepAttr(std::size_t x, std::size_t y, char32_t c, int cset = 0)
147 : : {
148 [ - + ]: 1 : auto& cell = cells[y*xsize+x];
149 : 1 : Cell temp = cell;
150 [ - + ]: 1 : if(cset)
151 : 0 : c = TranslateCSet(c, cset);
152 [ - + ]: 1 : if(temp != cell)
153 : : {
154 : 0 : cell = temp;
155 : 0 : cell.dirty = true;
156 : : }
157 : 1 : }
158 : : /** Same as PutCh(x,y,c), but preserves existing character symbol on screen. */
159 : : void PutCh_KeepChar(std::size_t x, std::size_t y, const Cell& c)
160 : : {
161 : : auto& cell = cells[y*xsize+x];
162 : : Cell temp = c;
163 : : temp.ch = cell.ch;
164 : : if(temp != cell)
165 : : {
166 : : cell = temp;
167 : : cell.dirty = true;
168 : : }
169 : : }
170 : :
171 : : /** Renders the screen into a pixel buffer using given font size.
172 : : * Only changed regions are rendered. Variables that are used to optimize
173 : : * the rendering (to save work) are the dirty flag in cells, lastcurs, lastcury and lasttimer.
174 : : *
175 : : * @param fx Font width in pixels.
176 : : * @param fy Font height in pixels.
177 : : * @param pixels Target buffer which must have room for at least fx*xsize*fy*ysize pixels.
178 : : */
179 : : void Render(std::size_t fx, std::size_t fy, std::uint32_t* pixels);
180 : :
181 : : /** Resizes the window to the new size, keeping existing contents.
182 : : * The entire screen is marked dirty. If the cursor is outside
183 : : * the new boundaries of the window, it is placed in the bottom row
184 : : * or rightmost column where necessary to keep it inside the boundaries.
185 : : */
186 : : void Resize(std::size_t newsx, std::size_t newsy);
187 : :
188 : : /** Changes the render_size attribute on current cursor line (cursy)
189 : : * to the specified value.
190 : : * @param val Value to be copied to the render_size attribute on the cells of that row.
191 : : * 0=normal, 1=doublewidth, 2=doublewidth+topline, 3=doublewidth+bottomline
192 : : */
193 : : void LineSetRenderSize(unsigned val);
194 : : };
195 : :
196 : : #endif
|