textbuf.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "textbuf_type.h"
00014 #include "string_func.h"
00015 #include "gfx_type.h"
00016 #include "gfx_func.h"
00017 #include "window_func.h"
00018 
00025 bool GetClipboardContents(char *buffer, size_t buff_len);
00026 
00027 int _caret_timer;
00028 
00029 
00030 /* Delete a character at the caret position in a text buf.
00031  * If backspace is set, delete the character before the caret,
00032  * else delete the character after it. */
00033 void Textbuf::DelChar(bool backspace)
00034 {
00035   WChar c;
00036   char *s = this->buf + this->caretpos;
00037 
00038   if (backspace) s = Utf8PrevChar(s);
00039 
00040   uint16 len = (uint16)Utf8Decode(&c, s);
00041   uint width = GetCharacterWidth(FS_NORMAL, c);
00042 
00043   this->pixels -= width;
00044   if (backspace) {
00045     this->caretpos   -= len;
00046     this->caretxoffs -= width;
00047   }
00048 
00049   /* Move the remaining characters over the marker */
00050   memmove(s, s + len, this->bytes - (s - this->buf) - len);
00051   this->bytes -= len;
00052   this->chars--;
00053 }
00054 
00061 bool Textbuf::DeleteChar(int delmode)
00062 {
00063   if (delmode == WKC_BACKSPACE && this->caretpos != 0) {
00064     this->DelChar(true);
00065     return true;
00066   } else if (delmode == WKC_DELETE && this->caretpos < this->bytes - 1) {
00067     this->DelChar(false);
00068     return true;
00069   }
00070 
00071   return false;
00072 }
00073 
00077 void Textbuf::DeleteAll()
00078 {
00079   memset(this->buf, 0, this->max_bytes);
00080   this->bytes = this->chars = 1;
00081   this->pixels = this->caretpos = this->caretxoffs = 0;
00082 }
00083 
00091 bool Textbuf::InsertChar(WChar key)
00092 {
00093   const byte charwidth = GetCharacterWidth(FS_NORMAL, key);
00094   uint16 len = (uint16)Utf8CharLen(key);
00095   if (this->bytes + len <= this->max_bytes && this->chars + 1 <= this->max_chars) {
00096     memmove(this->buf + this->caretpos + len, this->buf + this->caretpos, this->bytes - this->caretpos);
00097     Utf8Encode(this->buf + this->caretpos, key);
00098     this->chars++;
00099     this->bytes  += len;
00100     this->pixels += charwidth;
00101 
00102     this->caretpos   += len;
00103     this->caretxoffs += charwidth;
00104     return true;
00105   }
00106   return false;
00107 }
00108 
00115 bool Textbuf::InsertClipboard()
00116 {
00117   char utf8_buf[512];
00118 
00119   if (!GetClipboardContents(utf8_buf, lengthof(utf8_buf))) return false;
00120 
00121   uint16 pixels = 0, bytes = 0, chars = 0;
00122   WChar c;
00123   for (const char *ptr = utf8_buf; (c = Utf8Consume(&ptr)) != '\0';) {
00124     if (!IsPrintable(c)) break;
00125 
00126     byte len = Utf8CharLen(c);
00127     if (this->bytes + bytes + len > this->max_bytes) break;
00128     if (this->chars + chars + 1   > this->max_chars) break;
00129 
00130     byte char_pixels = GetCharacterWidth(FS_NORMAL, c);
00131 
00132     pixels += char_pixels;
00133     bytes += len;
00134     chars++;
00135   }
00136 
00137   if (bytes == 0) return false;
00138 
00139   memmove(this->buf + this->caretpos + bytes, this->buf + this->caretpos, this->bytes - this->caretpos);
00140   memcpy(this->buf + this->caretpos, utf8_buf, bytes);
00141   this->pixels += pixels;
00142   this->caretxoffs += pixels;
00143 
00144   this->bytes += bytes;
00145   this->chars += chars;
00146   this->caretpos += bytes;
00147   assert(this->bytes <= this->max_bytes);
00148   assert(this->chars <= this->max_chars);
00149   this->buf[this->bytes - 1] = '\0'; // terminating zero
00150 
00151   return true;
00152 }
00153 
00160 bool Textbuf::MovePos(int navmode)
00161 {
00162   switch (navmode) {
00163     case WKC_LEFT:
00164       if (this->caretpos != 0) {
00165         WChar c;
00166         const char *s = Utf8PrevChar(this->buf + this->caretpos);
00167         Utf8Decode(&c, s);
00168         this->caretpos    = s - this->buf; // -= (this->buf + this->caretpos - s)
00169         this->caretxoffs -= GetCharacterWidth(FS_NORMAL, c);
00170 
00171         return true;
00172       }
00173       break;
00174 
00175     case WKC_RIGHT:
00176       if (this->caretpos < this->bytes - 1) {
00177         WChar c;
00178 
00179         this->caretpos   += (uint16)Utf8Decode(&c, this->buf + this->caretpos);
00180         this->caretxoffs += GetCharacterWidth(FS_NORMAL, c);
00181 
00182         return true;
00183       }
00184       break;
00185 
00186     case WKC_HOME:
00187       this->caretpos = 0;
00188       this->caretxoffs = 0;
00189       return true;
00190 
00191     case WKC_END:
00192       this->caretpos = this->bytes - 1;
00193       this->caretxoffs = this->pixels;
00194       return true;
00195 
00196     default:
00197       break;
00198   }
00199 
00200   return false;
00201 }
00202 
00209 void Textbuf::Initialize(char *buf, uint16 max_bytes)
00210 {
00211   this->Initialize(buf, max_bytes, max_bytes);
00212 }
00213 
00221 void Textbuf::Initialize(char *buf, uint16 max_bytes, uint16 max_chars)
00222 {
00223   assert(max_bytes != 0);
00224   assert(max_chars != 0);
00225 
00226   this->buf        = buf;
00227   this->max_bytes  = max_bytes;
00228   this->max_chars  = max_chars;
00229   this->caret      = true;
00230   this->UpdateSize();
00231 }
00232 
00238 void Textbuf::UpdateSize()
00239 {
00240   const char *buf = this->buf;
00241 
00242   this->pixels = 0;
00243   this->chars = this->bytes = 1; // terminating zero
00244 
00245   WChar c;
00246   while ((c = Utf8Consume(&buf)) != '\0') {
00247     this->pixels += GetCharacterWidth(FS_NORMAL, c);
00248     this->bytes += Utf8CharLen(c);
00249     this->chars++;
00250   }
00251 
00252   assert(this->bytes <= this->max_bytes);
00253   assert(this->chars <= this->max_chars);
00254 
00255   this->caretpos = this->bytes - 1;
00256   this->caretxoffs = this->pixels;
00257 }
00258 
00263 bool Textbuf::HandleCaret()
00264 {
00265   /* caret changed? */
00266   bool b = !!(_caret_timer & 0x20);
00267 
00268   if (b != this->caret) {
00269     this->caret = b;
00270     return true;
00271   }
00272   return false;
00273 }