Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include <stdarg.h>
00014
00015 #include "textbuf_type.h"
00016 #include "string_func.h"
00017 #include "strings_func.h"
00018 #include "gfx_type.h"
00019 #include "gfx_func.h"
00020 #include "window_func.h"
00021 #include "core/alloc_func.hpp"
00022
00029 bool GetClipboardContents(char *buffer, size_t buff_len);
00030
00031 int _caret_timer;
00032
00033
00040 bool Textbuf::CanDelChar(bool backspace)
00041 {
00042 return backspace ? this->caretpos != 0 : this->caretpos < this->bytes - 1;
00043 }
00044
00052 WChar Textbuf::GetNextDelChar(bool backspace)
00053 {
00054 assert(this->CanDelChar(backspace));
00055
00056 const char *s;
00057 if (backspace) {
00058 s = Utf8PrevChar(this->buf + this->caretpos);
00059 } else {
00060 s = this->buf + this->caretpos;
00061 }
00062
00063 WChar c;
00064 Utf8Decode(&c, s);
00065 return c;
00066 }
00067
00074 void Textbuf::DelChar(bool backspace)
00075 {
00076 assert(this->CanDelChar(backspace));
00077
00078 WChar c;
00079 char *s = this->buf + this->caretpos;
00080
00081 if (backspace) s = Utf8PrevChar(s);
00082
00083 uint16 len = (uint16)Utf8Decode(&c, s);
00084 uint width = GetCharacterWidth(FS_NORMAL, c);
00085
00086 this->pixels -= width;
00087 if (backspace) {
00088 this->caretpos -= len;
00089 this->caretxoffs -= width;
00090 }
00091
00092
00093 memmove(s, s + len, this->bytes - (s - this->buf) - len);
00094 this->bytes -= len;
00095 this->chars--;
00096 }
00097
00104 bool Textbuf::DeleteChar(int delmode)
00105 {
00106 if (delmode == WKC_BACKSPACE || delmode == WKC_DELETE) {
00107 bool backspace = delmode == WKC_BACKSPACE;
00108 if (CanDelChar(backspace)) {
00109 this->DelChar(backspace);
00110 return true;
00111 }
00112 return false;
00113 }
00114
00115 if (delmode == (WKC_CTRL | WKC_BACKSPACE) || delmode == (WKC_CTRL | WKC_DELETE)) {
00116 bool backspace = delmode == (WKC_CTRL | WKC_BACKSPACE);
00117
00118 if (!CanDelChar(backspace)) return false;
00119 WChar c = this->GetNextDelChar(backspace);
00120
00121
00122
00123
00124 while (backspace ? IsWhitespace(c) : !IsWhitespace(c)) {
00125 this->DelChar(backspace);
00126 if (!this->CanDelChar(backspace)) return true;
00127 c = this->GetNextDelChar(backspace);
00128 }
00129
00130
00131
00132 while (backspace ? !IsWhitespace(c) : IsWhitespace(c)) {
00133 this->DelChar(backspace);
00134 if (!this->CanDelChar(backspace)) return true;
00135 c = this->GetNextDelChar(backspace);
00136 }
00137 return true;
00138 }
00139
00140 return false;
00141 }
00142
00146 void Textbuf::DeleteAll()
00147 {
00148 memset(this->buf, 0, this->max_bytes);
00149 this->bytes = this->chars = 1;
00150 this->pixels = this->caretpos = this->caretxoffs = 0;
00151 }
00152
00160 bool Textbuf::InsertChar(WChar key)
00161 {
00162 const byte charwidth = GetCharacterWidth(FS_NORMAL, key);
00163 uint16 len = (uint16)Utf8CharLen(key);
00164 if (this->bytes + len <= this->max_bytes && this->chars + 1 <= this->max_chars) {
00165 memmove(this->buf + this->caretpos + len, this->buf + this->caretpos, this->bytes - this->caretpos);
00166 Utf8Encode(this->buf + this->caretpos, key);
00167 this->chars++;
00168 this->bytes += len;
00169 this->pixels += charwidth;
00170
00171 this->caretpos += len;
00172 this->caretxoffs += charwidth;
00173 return true;
00174 }
00175 return false;
00176 }
00177
00184 bool Textbuf::InsertClipboard()
00185 {
00186 char utf8_buf[512];
00187
00188 if (!GetClipboardContents(utf8_buf, lengthof(utf8_buf))) return false;
00189
00190 uint16 pixels = 0, bytes = 0, chars = 0;
00191 WChar c;
00192 for (const char *ptr = utf8_buf; (c = Utf8Consume(&ptr)) != '\0';) {
00193 if (!IsValidChar(c, this->afilter)) break;
00194
00195 byte len = Utf8CharLen(c);
00196 if (this->bytes + bytes + len > this->max_bytes) break;
00197 if (this->chars + chars + 1 > this->max_chars) break;
00198
00199 byte char_pixels = GetCharacterWidth(FS_NORMAL, c);
00200
00201 pixels += char_pixels;
00202 bytes += len;
00203 chars++;
00204 }
00205
00206 if (bytes == 0) return false;
00207
00208 memmove(this->buf + this->caretpos + bytes, this->buf + this->caretpos, this->bytes - this->caretpos);
00209 memcpy(this->buf + this->caretpos, utf8_buf, bytes);
00210 this->pixels += pixels;
00211 this->caretxoffs += pixels;
00212
00213 this->bytes += bytes;
00214 this->chars += chars;
00215 this->caretpos += bytes;
00216 assert(this->bytes <= this->max_bytes);
00217 assert(this->chars <= this->max_chars);
00218 this->buf[this->bytes - 1] = '\0';
00219
00220 return true;
00221 }
00222
00227 bool Textbuf::CanMoveCaretLeft()
00228 {
00229 return this->caretpos != 0;
00230 }
00231
00237 WChar Textbuf::MoveCaretLeft()
00238 {
00239 assert(this->CanMoveCaretLeft());
00240
00241 WChar c;
00242 const char *s = Utf8PrevChar(this->buf + this->caretpos);
00243 Utf8Decode(&c, s);
00244 this->caretpos = s - this->buf;
00245 this->caretxoffs -= GetCharacterWidth(FS_NORMAL, c);
00246
00247 return c;
00248 }
00249
00254 bool Textbuf::CanMoveCaretRight()
00255 {
00256 return this->caretpos < this->bytes - 1;
00257 }
00258
00264 WChar Textbuf::MoveCaretRight()
00265 {
00266 assert(this->CanMoveCaretRight());
00267
00268 WChar c;
00269 this->caretpos += (uint16)Utf8Decode(&c, this->buf + this->caretpos);
00270 this->caretxoffs += GetCharacterWidth(FS_NORMAL, c);
00271
00272 Utf8Decode(&c, this->buf + this->caretpos);
00273 return c;
00274 }
00275
00282 bool Textbuf::MovePos(int navmode)
00283 {
00284 switch (navmode) {
00285 case WKC_LEFT:
00286 if (this->CanMoveCaretLeft()) {
00287 this->MoveCaretLeft();
00288 return true;
00289 }
00290 break;
00291
00292 case WKC_CTRL | WKC_LEFT: {
00293 if (!this->CanMoveCaretLeft()) break;
00294
00295
00296 WChar c = this->MoveCaretLeft();
00297
00298 while (IsWhitespace(c)) {
00299 if (!this->CanMoveCaretLeft()) return true;
00300 c = this->MoveCaretLeft();
00301 }
00302
00303 while (!IsWhitespace(c)) {
00304 if (!this->CanMoveCaretLeft()) return true;
00305 c = this->MoveCaretLeft();
00306 }
00307
00308 this->MoveCaretRight();
00309 return true;
00310 }
00311
00312 case WKC_RIGHT:
00313 if (this->CanMoveCaretRight()) {
00314 this->MoveCaretRight();
00315 return true;
00316 }
00317 break;
00318
00319 case WKC_CTRL | WKC_RIGHT: {
00320 if (!this->CanMoveCaretRight()) break;
00321
00322
00323 WChar c = this->MoveCaretRight();
00324
00325 while (!IsWhitespace(c)) {
00326 if (!this->CanMoveCaretRight()) return true;
00327 c = this->MoveCaretRight();
00328 }
00329
00330 while (IsWhitespace(c)) {
00331 if (!this->CanMoveCaretRight()) return true;
00332 c = this->MoveCaretRight();
00333 }
00334 return true;
00335 }
00336
00337 case WKC_HOME:
00338 this->caretpos = 0;
00339 this->caretxoffs = 0;
00340 return true;
00341
00342 case WKC_END:
00343 this->caretpos = this->bytes - 1;
00344 this->caretxoffs = this->pixels;
00345 return true;
00346
00347 default:
00348 break;
00349 }
00350
00351 return false;
00352 }
00353
00361 Textbuf::Textbuf(uint16 max_bytes, uint16 max_chars)
00362 : buf(MallocT<char>(max_bytes))
00363 {
00364 assert(max_bytes != 0);
00365 assert(max_chars != 0);
00366
00367 this->afilter = CS_ALPHANUMERAL;
00368 this->max_bytes = max_bytes;
00369 this->max_chars = max_chars == UINT16_MAX ? max_bytes : max_chars;
00370 this->caret = true;
00371 this->DeleteAll();
00372 }
00373
00374 Textbuf::~Textbuf()
00375 {
00376 free(this->buf);
00377 }
00378
00383 void Textbuf::Assign(StringID string)
00384 {
00385 GetString(this->buf, string, &this->buf[this->max_bytes - 1]);
00386 this->UpdateSize();
00387 }
00388
00393 void Textbuf::Assign(const char *text)
00394 {
00395 ttd_strlcpy(this->buf, text, this->max_bytes);
00396 this->UpdateSize();
00397 }
00398
00402 void Textbuf::Print(const char *format, ...)
00403 {
00404 va_list va;
00405 va_start(va, format);
00406 vsnprintf(this->buf, this->max_bytes, format, va);
00407 va_end(va);
00408 this->UpdateSize();
00409 }
00410
00411
00417 void Textbuf::UpdateSize()
00418 {
00419 const char *buf = this->buf;
00420
00421 this->pixels = 0;
00422 this->chars = this->bytes = 1;
00423
00424 WChar c;
00425 while ((c = Utf8Consume(&buf)) != '\0') {
00426 this->pixels += GetCharacterWidth(FS_NORMAL, c);
00427 this->bytes += Utf8CharLen(c);
00428 this->chars++;
00429 }
00430
00431 assert(this->bytes <= this->max_bytes);
00432 assert(this->chars <= this->max_chars);
00433
00434 this->caretpos = this->bytes - 1;
00435 this->caretxoffs = this->pixels;
00436 }
00437
00442 bool Textbuf::HandleCaret()
00443 {
00444
00445 bool b = !!(_caret_timer & 0x20);
00446
00447 if (b != this->caret) {
00448 this->caret = b;
00449 return true;
00450 }
00451 return false;
00452 }