OSDN Git Service

Merge pull request #3532 from sikabane-works/release/3.0.0.87-alpha
[hengbandforosx/hengbandosx.git] / src / term / screen-processor.cpp
1 #include "term/screen-processor.h"
2 #include "io/input-key-acceptor.h"
3 #include "locale/japanese.h"
4 #include "term/term-color-types.h"
5 #include "view/display-messages.h"
6 #include "world/world.h"
7
8 /*
9  * Hack -- prevent "accidents" in "screen_save()" or "screen_load()"
10  */
11 static int screen_depth = 0;
12
13 /*
14  * Move the cursor
15  */
16 void move_cursor(int row, int col)
17 {
18     term_gotoxy(col, row);
19 }
20
21 /*
22  * Flush all input chars.  Actually, remember the flush,
23  * and do a "special flush" before the next "inkey()".
24  *
25  * This is not only more efficient, but also necessary to make sure
26  * that various "inkey()" codes are not "lost" along the way.
27  */
28 void flush(void)
29 {
30     inkey_xtra = true;
31 }
32
33 /*
34  * Save the screen, and increase the "icky" depth.
35  *
36  * This function must match exactly one call to "screen_load()".
37  */
38 void screen_save()
39 {
40     msg_print(nullptr);
41
42     term_save();
43
44     w_ptr->character_icky_depth++;
45     screen_depth++;
46 }
47
48 /*
49  * Load the screen, and decrease the "icky" depth.
50  *
51  * This function must match exactly one call to "screen_save()".
52  */
53 void screen_load(ScreenLoadOptType opt)
54 {
55     msg_print(nullptr);
56
57     switch (opt) {
58     case ScreenLoadOptType::ONE:
59         term_load(false);
60         w_ptr->character_icky_depth--;
61         screen_depth--;
62         break;
63
64     case ScreenLoadOptType::ALL:
65         term_load(true);
66         w_ptr->character_icky_depth -= static_cast<byte>(screen_depth);
67         screen_depth = 0;
68         break;
69
70     default:
71         break;
72     }
73 }
74
75 /*
76  * Display a string on the screen using an attribute.
77  *
78  * At the given location, using the given attribute, if allowed,
79  * add the given string.  Do not clear the line.
80  */
81 void c_put_str(TERM_COLOR attr, std::string_view sv, TERM_LEN row, TERM_LEN col)
82 {
83     term_putstr(col, row, -1, attr, sv);
84 }
85
86 /*
87  * As above, but in "white"
88  */
89 void put_str(std::string_view sv, TERM_LEN row, TERM_LEN col)
90 {
91     term_putstr(col, row, -1, TERM_WHITE, sv);
92 }
93
94 /*
95  * Display a string on the screen using an attribute, and clear
96  * to the end of the line.
97  */
98 void c_prt(TERM_COLOR attr, std::string_view sv, TERM_LEN row, TERM_LEN col)
99 {
100     term_erase(col, row, 255);
101     term_addstr(-1, attr, sv);
102 }
103
104 /*
105  * As above, but in "white"
106  */
107 void prt(std::string_view sv, TERM_LEN row, TERM_LEN col)
108 {
109     /* Spawn */
110     c_prt(TERM_WHITE, sv, row, col);
111 }
112
113 static std::vector<std::pair<TERM_COLOR, char>> c_roff_wrap(int x, int y, int w, const char *s)
114 {
115     if (x >= w) {
116         return {};
117     }
118
119     std::vector<std::pair<TERM_COLOR, char>> wrap_chars;
120     auto wrap_col = w;
121
122     if (_(iskanji(*s), false)) {
123         /* 現在が全角文字の場合 */
124         /* 行頭が行頭禁則文字になるときは、その1つ前の語で改行 */
125         if (is_kinsoku({ s, 2 })) {
126             TERM_COLOR a;
127             char c;
128             term_what(x - 2, y, &a, &c);
129             wrap_chars.emplace_back(a, c);
130             term_what(x - 1, y, &a, &c);
131             wrap_chars.emplace_back(a, c);
132             wrap_col = x - 2;
133         }
134     } else {
135         /* 現在が半角文字の場合 */
136         for (auto i = 0; i < x; i++) {
137             TERM_COLOR a;
138             char c;
139             term_what(i, y, &a, &c);
140
141             if (c == ' ') {
142                 wrap_col = i + 1;
143                 wrap_chars.clear();
144             } else if (_(iskanji(c), false)) {
145                 wrap_col = i + 2;
146                 i++;
147                 wrap_chars.clear();
148             } else {
149                 wrap_chars.emplace_back(a, c);
150             }
151         }
152     }
153
154     term_erase(wrap_col, y, 255);
155     return wrap_chars;
156 }
157
158 /*
159  * Print some (colored) text to the screen at the current cursor position,
160  * automatically "wrapping" existing text (at spaces) when necessary to
161  * avoid placing any text into the last column, and clearing every line
162  * before placing any text in that line.  Also, allow "newline" to force
163  * a "wrap" to the next line.  Advance the cursor as needed so sequential
164  * calls to this function will work correctly.
165  *
166  * Once this function has been called, the cursor should not be moved
167  * until all the related "c_roff()" calls to the window are complete.
168  *
169  * This function will correctly handle any width up to the maximum legal
170  * value of 256, though it works best for a standard 80 character width.
171  */
172 void c_roff(TERM_COLOR a, std::string_view str)
173 {
174     int w, h;
175     (void)term_get_size(&w, &h);
176
177     int x, y;
178     (void)term_locate(&x, &y);
179
180     if (y == h - 1 && x > w - 3) {
181         return;
182     }
183
184     for (auto s = str.begin(); s != str.end(); ++s) {
185         const auto is_kanji = _(iskanji(*s), false);
186
187         if (*s == '\n') {
188             if (y + 1 < h) {
189                 term_erase(0, y + 1, 255);
190             }
191
192             return;
193         }
194
195         const auto ch = (is_kanji || isprint(*s)) ? *s : ' ';
196
197         if ((x >= ((is_kanji) ? w - 2 : w - 1)) && (ch != ' ')) {
198             const auto wrap_chars = c_roff_wrap(x, y, w, &*s);
199
200             y++;
201             if (y == h) {
202                 return;
203             }
204
205             term_erase(0, y, 255);
206             for (const auto &[ca, cv] : wrap_chars) {
207                 term_addch(ca, cv);
208             }
209             x = wrap_chars.size();
210         }
211
212         term_addch(_((a | 0x10), a), ch);
213         if (is_kanji) {
214             s++;
215             x++;
216             term_addch((a | 0x20), *s);
217         }
218
219         if (++x > w) {
220             x = w;
221         }
222     }
223 }
224
225 /*
226  * As above, but in "white"
227  */
228 void roff(std::string_view str)
229 {
230     /* Spawn */
231     c_roff(TERM_WHITE, str);
232 }
233
234 /*
235  * Clear part of the screen
236  */
237 void clear_from(int row)
238 {
239     for (int y = row; y < game_term->hgt; y++) {
240         TermOffsetSetter tos(0, std::nullopt);
241         term_erase(0, y, 255);
242     }
243 }