Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIrie Shinsuke <irieshinsuke@yahoo.co.jp>2013-03-12 11:25:53 +0400
committerIrie Shinsuke <irieshinsuke@yahoo.co.jp>2013-03-12 11:25:53 +0400
commit5792e77239c43aea0afc21b2df96153ba31c5399 (patch)
tree47eb20f56f932f984800329781f2e75e38e7eb78
parent6669ee4784ac6591711298eb01f8e0b06793c60a (diff)
Patch [#34373] Use i18n monospace font in Text editor and Python console
This patch allows Blender to display i18n monospace font in the text editor and the Python interactive console. Wide characters that occupy multiple columns such as CJK characters can be displayed correctly. Furthermore, wrapping, selection, suggestion, cursor drawing, and syntax highlighting should work. Also fixes a bug [#34543]: In Text Editor false color in comment on cyrillic To estimate how many columns each character occupies, this patch uses wcwidth.c written by Markus Kuhn and distributed under MIT-style license: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c wcwidth.c is stored in extern/wcwidth and used as a static library. This patch adds new API to blenfont, blenlib and blenkernel: BLF_get_unifont_mono() BLF_free_unifont_mono() BLF_draw_mono() BLI_wcwidth() BLI_wcswidth() BLI_str_utf8_char_width() BLI_str_utf8_char_width_safe() txt_utf8_offset_to_column() txt_utf8_column_to_offset()
-rw-r--r--extern/CMakeLists.txt1
-rw-r--r--extern/SConscript1
-rw-r--r--extern/wcwidth/CMakeLists.txt38
-rw-r--r--extern/wcwidth/SConscript9
-rw-r--r--extern/wcwidth/wcwidth.c309
-rw-r--r--extern/wcwidth/wcwidth.h36
-rw-r--r--source/blender/blenfont/BLF_api.h1
-rw-r--r--source/blender/blenfont/BLF_translation.h2
-rw-r--r--source/blender/blenfont/intern/blf.c15
-rw-r--r--source/blender/blenfont/intern/blf_font.c34
-rw-r--r--source/blender/blenfont/intern/blf_internal.h1
-rw-r--r--source/blender/blenfont/intern/blf_translation.c38
-rw-r--r--source/blender/blenkernel/BKE_text.h2
-rw-r--r--source/blender/blenkernel/intern/text.c46
-rw-r--r--source/blender/blenlib/BLI_string_utf8.h9
-rw-r--r--source/blender/blenlib/CMakeLists.txt1
-rw-r--r--source/blender/blenlib/SConscript2
-rw-r--r--source/blender/blenlib/intern/string_utf8.c37
-rw-r--r--source/blender/editors/interface/interface_style.c24
-rw-r--r--source/blender/editors/space_console/console_draw.c42
-rw-r--r--source/blender/editors/space_info/textview.c119
-rw-r--r--source/blender/editors/space_text/text_draw.c215
-rw-r--r--source/blender/editors/space_text/text_ops.c85
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c1
-rw-r--r--source/blenderplayer/CMakeLists.txt1
-rw-r--r--source/creator/CMakeLists.txt1
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_ghost.cpp1
27 files changed, 888 insertions, 183 deletions
diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt
index 6ad6bdc316f..941f69e9047 100644
--- a/extern/CMakeLists.txt
+++ b/extern/CMakeLists.txt
@@ -28,6 +28,7 @@ remove_strict_flags()
add_subdirectory(colamd)
add_subdirectory(rangetree)
+add_subdirectory(wcwidth)
if(WITH_BULLET)
if(NOT WITH_SYSTEM_BULLET)
diff --git a/extern/SConscript b/extern/SConscript
index 6a0ffa3f588..e2bb1dc1f31 100644
--- a/extern/SConscript
+++ b/extern/SConscript
@@ -5,6 +5,7 @@ Import('env')
SConscript(['glew/SConscript'])
SConscript(['colamd/SConscript'])
SConscript(['rangetree/SConscript'])
+SConscript(['wcwidth/SConscript'])
if env['WITH_BF_GAMEENGINE']:
SConscript(['recastnavigation/SConscript'])
diff --git a/extern/wcwidth/CMakeLists.txt b/extern/wcwidth/CMakeLists.txt
new file mode 100644
index 00000000000..cf8d7d6d15e
--- /dev/null
+++ b/extern/wcwidth/CMakeLists.txt
@@ -0,0 +1,38 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program 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; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program 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. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2013, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ wcwidth.c
+)
+
+blender_add_lib(extern_wcwidth "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/wcwidth/SConscript b/extern/wcwidth/SConscript
new file mode 100644
index 00000000000..14fdaf3f738
--- /dev/null
+++ b/extern/wcwidth/SConscript
@@ -0,0 +1,9 @@
+#!/usr/bin/python
+
+Import('env')
+
+sources = env.Glob('*.c')
+
+incs = '.'
+
+env.BlenderLib ( 'extern_wcwidth', sources, Split(incs), [], libtype=['extern','player'], priority=[10, 185])
diff --git a/extern/wcwidth/wcwidth.c b/extern/wcwidth/wcwidth.c
new file mode 100644
index 00000000000..61e822ad679
--- /dev/null
+++ b/extern/wcwidth/wcwidth.c
@@ -0,0 +1,309 @@
+/*
+ * This is an implementation of wcwidth() and wcswidth() (defined in
+ * IEEE Std 1002.1-2001) for Unicode.
+ *
+ * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
+ * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
+ *
+ * In fixed-width output devices, Latin characters all occupy a single
+ * "cell" position of equal width, whereas ideographic CJK characters
+ * occupy two such cells. Interoperability between terminal-line
+ * applications and (teletype-style) character terminals using the
+ * UTF-8 encoding requires agreement on which character should advance
+ * the cursor by how many cell positions. No established formal
+ * standards exist at present on which Unicode character shall occupy
+ * how many cell positions on character terminals. These routines are
+ * a first attempt of defining such behavior based on simple rules
+ * applied to data provided by the Unicode Consortium.
+ *
+ * For some graphical characters, the Unicode standard explicitly
+ * defines a character-cell width via the definition of the East Asian
+ * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
+ * In all these cases, there is no ambiguity about which width a
+ * terminal shall use. For characters in the East Asian Ambiguous (A)
+ * class, the width choice depends purely on a preference of backward
+ * compatibility with either historic CJK or Western practice.
+ * Choosing single-width for these characters is easy to justify as
+ * the appropriate long-term solution, as the CJK practice of
+ * displaying these characters as double-width comes from historic
+ * implementation simplicity (8-bit encoded characters were displayed
+ * single-width and 16-bit ones double-width, even for Greek,
+ * Cyrillic, etc.) and not any typographic considerations.
+ *
+ * Much less clear is the choice of width for the Not East Asian
+ * (Neutral) class. Existing practice does not dictate a width for any
+ * of these characters. It would nevertheless make sense
+ * typographically to allocate two character cells to characters such
+ * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
+ * represented adequately with a single-width glyph. The following
+ * routines at present merely assign a single-cell width to all
+ * neutral characters, in the interest of simplicity. This is not
+ * entirely satisfactory and should be reconsidered before
+ * establishing a formal standard in this area. At the moment, the
+ * decision which Not East Asian (Neutral) characters should be
+ * represented by double-width glyphs cannot yet be answered by
+ * applying a simple rule from the Unicode database content. Setting
+ * up a proper standard for the behavior of UTF-8 character terminals
+ * will require a careful analysis not only of each Unicode character,
+ * but also of each presentation form, something the author of these
+ * routines has avoided to do so far.
+ *
+ * http://www.unicode.org/unicode/reports/tr11/
+ *
+ * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * for any purpose and without fee is hereby granted. The author
+ * disclaims all warranties with regard to this software.
+ *
+ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ */
+
+#include <wchar.h>
+
+struct interval {
+ int first;
+ int last;
+};
+
+/* auxiliary function for binary search in interval table */
+static int bisearch(wchar_t ucs, const struct interval *table, int max) {
+ int min = 0;
+ int mid;
+
+ if (ucs < table[0].first || ucs > table[max].last)
+ return 0;
+ while (max >= min) {
+ mid = (min + max) / 2;
+ if (ucs > table[mid].last)
+ min = mid + 1;
+ else if (ucs < table[mid].first)
+ max = mid - 1;
+ else
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* The following two functions define the column width of an ISO 10646
+ * character as follows:
+ *
+ * - The null character (U+0000) has a column width of 0.
+ *
+ * - Other C0/C1 control characters and DEL will lead to a return
+ * value of -1.
+ *
+ * - Non-spacing and enclosing combining characters (general
+ * category code Mn or Me in the Unicode database) have a
+ * column width of 0.
+ *
+ * - SOFT HYPHEN (U+00AD) has a column width of 1.
+ *
+ * - Other format characters (general category code Cf in the Unicode
+ * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
+ *
+ * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
+ * have a column width of 0.
+ *
+ * - Spacing characters in the East Asian Wide (W) or East Asian
+ * Full-width (F) category as defined in Unicode Technical
+ * Report #11 have a column width of 2.
+ *
+ * - All remaining characters (including all printable
+ * ISO 8859-1 and WGL4 characters, Unicode control characters,
+ * etc.) have a column width of 1.
+ *
+ * This implementation assumes that wchar_t characters are encoded
+ * in ISO 10646.
+ */
+
+int mk_wcwidth(wchar_t ucs)
+{
+ /* sorted list of non-overlapping intervals of non-spacing characters */
+ /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
+ static const struct interval combining[] = {
+ { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
+ { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
+ { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
+ { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
+ { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
+ { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
+ { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
+ { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
+ { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
+ { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
+ { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
+ { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
+ { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
+ { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
+ { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
+ { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
+ { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
+ { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
+ { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
+ { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
+ { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
+ { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
+ { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
+ { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
+ { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
+ { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
+ { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
+ { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
+ { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
+ { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
+ { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
+ { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
+ { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
+ { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
+ { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
+ { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
+ { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
+ { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
+ { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
+ { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
+ { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
+ { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
+ { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
+ { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
+ { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
+ { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
+ { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
+ { 0xE0100, 0xE01EF }
+ };
+
+ /* test for 8-bit control characters */
+ if (ucs == 0)
+ return 0;
+ if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
+ return -1;
+
+ /* binary search in table of non-spacing characters */
+ if (bisearch(ucs, combining,
+ sizeof(combining) / sizeof(struct interval) - 1))
+ return 0;
+
+ /* if we arrive here, ucs is not a combining or C0/C1 control character */
+
+ return 1 +
+ (ucs >= 0x1100 &&
+ (ucs <= 0x115f || /* Hangul Jamo init. consonants */
+ ucs == 0x2329 || ucs == 0x232a ||
+ (ucs >= 0x2e80 && ucs <= 0xa4cf &&
+ ucs != 0x303f) || /* CJK ... Yi */
+ (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
+ (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
+ (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
+ (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
+ (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
+ (ucs >= 0xffe0 && ucs <= 0xffe6) ||
+ (ucs >= 0x20000 && ucs <= 0x2fffd) ||
+ (ucs >= 0x30000 && ucs <= 0x3fffd)));
+}
+
+
+int mk_wcswidth(const wchar_t *pwcs, size_t n)
+{
+ int w, width = 0;
+
+ for (;*pwcs && n-- > 0; pwcs++)
+ if ((w = mk_wcwidth(*pwcs)) < 0)
+ return -1;
+ else
+ width += w;
+
+ return width;
+}
+
+
+/*
+ * The following functions are the same as mk_wcwidth() and
+ * mk_wcswidth(), except that spacing characters in the East Asian
+ * Ambiguous (A) category as defined in Unicode Technical Report #11
+ * have a column width of 2. This variant might be useful for users of
+ * CJK legacy encodings who want to migrate to UCS without changing
+ * the traditional terminal character-width behaviour. It is not
+ * otherwise recommended for general use.
+ */
+int mk_wcwidth_cjk(wchar_t ucs)
+{
+ /* sorted list of non-overlapping intervals of East Asian Ambiguous
+ * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
+ static const struct interval ambiguous[] = {
+ { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
+ { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 },
+ { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
+ { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
+ { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
+ { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
+ { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
+ { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
+ { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
+ { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
+ { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
+ { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
+ { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
+ { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
+ { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
+ { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },
+ { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },
+ { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 },
+ { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 },
+ { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 },
+ { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 },
+ { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 },
+ { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 },
+ { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 },
+ { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
+ { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
+ { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 },
+ { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 },
+ { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
+ { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 },
+ { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 },
+ { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B },
+ { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 },
+ { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 },
+ { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E },
+ { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 },
+ { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 },
+ { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F },
+ { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 },
+ { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF },
+ { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B },
+ { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 },
+ { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 },
+ { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 },
+ { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 },
+ { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 },
+ { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 },
+ { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },
+ { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },
+ { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },
+ { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF },
+ { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD }
+ };
+
+ /* binary search in table of non-spacing characters */
+ if (bisearch(ucs, ambiguous,
+ sizeof(ambiguous) / sizeof(struct interval) - 1))
+ return 2;
+
+ return mk_wcwidth(ucs);
+}
+
+
+int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n)
+{
+ int w, width = 0;
+
+ for (;*pwcs && n-- > 0; pwcs++)
+ if ((w = mk_wcwidth_cjk(*pwcs)) < 0)
+ return -1;
+ else
+ width += w;
+
+ return width;
+}
diff --git a/extern/wcwidth/wcwidth.h b/extern/wcwidth/wcwidth.h
new file mode 100644
index 00000000000..e327921b6ea
--- /dev/null
+++ b/extern/wcwidth/wcwidth.h
@@ -0,0 +1,36 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __WCWIDTH_H__
+#define __WCWIDTH_H__
+
+#include <wchar.h>
+
+int mk_wcwidth(wchar_t ucs);
+int mk_wcswidth(const wchar_t *pwcs, size_t n);
+int mk_wcwidth_cjk(wchar_t ucs);
+int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n);
+
+#endif
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 0ca97975d87..fd8bd196717 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -77,6 +77,7 @@ void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t l
/* Draw the string using the current font. */
void BLF_draw(int fontid, const char *str, size_t len);
void BLF_draw_ascii(int fontid, const char *str, size_t len);
+int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth);
/* This function return the bounding box of the string
* and are not multiplied by the aspect.
diff --git a/source/blender/blenfont/BLF_translation.h b/source/blender/blenfont/BLF_translation.h
index cbfc7c28d8d..2f40cc3f571 100644
--- a/source/blender/blenfont/BLF_translation.h
+++ b/source/blender/blenfont/BLF_translation.h
@@ -68,6 +68,8 @@ struct EnumPropertyItem *BLF_RNA_lang_enum_properties(void);
unsigned char *BLF_get_unifont(int *unifont_size);
void BLF_free_unifont(void);
+unsigned char *BLF_get_unifont_mono(int *unifont_size);
+void BLF_free_unifont_mono(void);
const char *BLF_pgettext(const char *msgctxt, const char *msgid);
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 061e8e28607..e7e277b7b34 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -576,6 +576,21 @@ void BLF_draw_ascii(int fontid, const char *str, size_t len)
}
}
+int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth)
+{
+ FontBLF *font = blf_get(fontid);
+ GLint mode, param;
+ int columns = 0;
+
+ if (font && font->glyph_cache) {
+ blf_draw__start(font, &mode, &param);
+ columns = blf_font_draw_mono(font, str, len, cwidth);
+ blf_draw__end(mode, param);
+ }
+
+ return columns;
+}
+
void BLF_boundbox(int fontid, const char *str, rctf *box)
{
FontBLF *font = blf_get(fontid);
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 1900efa2dbc..f2c36475870 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -219,6 +219,40 @@ void blf_font_draw_ascii(FontBLF *font, const char *str, size_t len)
}
}
+/* use fixed column width, but an utf8 character may occupy multiple columns */
+int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth)
+{
+ unsigned int c;
+ GlyphBLF *g;
+ int col, columns = 0;
+ int pen_x = 0, pen_y = 0;
+ size_t i = 0;
+ GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
+
+ blf_font_ensure_ascii_table(font);
+
+ while ((i < len) && str[i]) {
+ BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
+
+ if (c == BLI_UTF8_ERR)
+ break;
+ if (g == NULL)
+ continue;
+
+ /* do not return this loop if clipped, we want every character tested */
+ blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
+
+ col = BLI_wcwidth((wchar_t)c);
+ if (col < 0)
+ col = 1;
+
+ columns += col;
+ pen_x += cwidth * col;
+ }
+
+ return columns;
+}
+
/* Sanity checks are done by BLF_draw_buffer() */
void blf_font_buffer(FontBLF *font, const char *str)
{
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 65a54783978..b1301be46fd 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -53,6 +53,7 @@ void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, in
void blf_font_size(struct FontBLF *font, int size, int dpi);
void blf_font_draw(struct FontBLF *font, const char *str, size_t len);
void blf_font_draw_ascii(struct FontBLF *font, const char *str, size_t len);
+int blf_font_draw_mono(struct FontBLF *font, const char *str, size_t len, int cwidth);
void blf_font_buffer(struct FontBLF *font, const char *str);
void blf_font_boundbox(struct FontBLF *font, const char *str, struct rctf *box);
void blf_font_width_and_height(struct FontBLF *font, const char *str, float *width, float *height);
diff --git a/source/blender/blenfont/intern/blf_translation.c b/source/blender/blenfont/intern/blf_translation.c
index f7ad5c07d50..3284225c457 100644
--- a/source/blender/blenfont/intern/blf_translation.c
+++ b/source/blender/blenfont/intern/blf_translation.c
@@ -50,6 +50,9 @@
static const char unifont_filename[] = "droidsans.ttf.gz";
static unsigned char *unifont_ttf = NULL;
static int unifont_size = 0;
+static const char unifont_mono_filename[] = "bmonofont-i18n.ttf.gz";
+static unsigned char *unifont_mono_ttf = NULL;
+static int unifont_mono_size = 0;
#endif /* WITH_INTERNATIONAL */
unsigned char *BLF_get_unifont(int *unifont_size_r)
@@ -87,6 +90,41 @@ void BLF_free_unifont(void)
#endif
}
+unsigned char *BLF_get_unifont_mono(int *unifont_size_r)
+{
+#ifdef WITH_INTERNATIONAL
+ if(unifont_mono_ttf == NULL) {
+ char *fontpath = BLI_get_folder(BLENDER_DATAFILES, "fonts");
+ if (fontpath) {
+ char unifont_path[1024];
+
+ BLI_snprintf(unifont_path, sizeof(unifont_path), "%s/%s", fontpath, unifont_mono_filename);
+
+ unifont_mono_ttf = (unsigned char*)BLI_file_ungzip_to_mem(unifont_path, &unifont_mono_size);
+ }
+ else {
+ printf("%s: 'fonts' data path not found for international monospace font, continuing\n", __func__);
+ }
+ }
+
+ *unifont_size_r = unifont_mono_size;
+
+ return unifont_mono_ttf;
+#else
+ (void)unifont_size_r;
+ return NULL;
+#endif
+}
+
+void BLF_free_unifont_mono(void)
+{
+#ifdef WITH_INTERNATIONAL
+ if(unifont_mono_ttf)
+ MEM_freeN(unifont_mono_ttf);
+#else
+#endif
+}
+
const char *BLF_pgettext(const char *msgctxt, const char *msgid)
{
#ifdef WITH_INTERNATIONAL
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index 3d7b5d1c8e4..466adc9477e 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -62,6 +62,8 @@ int txt_has_sel (struct Text *text);
int txt_get_span (struct TextLine *from, struct TextLine *to);
int txt_utf8_offset_to_index(const char *str, int offset);
int txt_utf8_index_to_offset(const char *str, int index);
+int txt_utf8_offset_to_column(const char *str, int offset);
+int txt_utf8_column_to_offset(const char *str, int column);
void txt_move_up (struct Text *text, short sel);
void txt_move_down (struct Text *text, short sel);
void txt_move_left (struct Text *text, short sel);
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index a155ca47d3c..e229c288a24 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -791,6 +791,29 @@ int txt_utf8_index_to_offset(const char *str, int index)
return offset;
}
+int txt_utf8_offset_to_column(const char *str, int offset)
+{
+ int column = 0, pos = 0;
+ while (pos < offset) {
+ column += BLI_str_utf8_char_width_safe(str + pos);
+ pos += BLI_str_utf8_size_safe(str + pos);
+ }
+ return column;
+}
+
+int txt_utf8_column_to_offset(const char *str, int column)
+{
+ int offset = 0, pos = 0, col;
+ while (pos < column) {
+ col = BLI_str_utf8_char_width_safe(str + offset);
+ if (pos + col > column)
+ break;
+ offset += BLI_str_utf8_size_safe(str + offset);
+ pos += col;
+ }
+ return offset;
+}
+
/* returns the real number of characters in string */
/* not the same as BLI_strlen_utf8, which returns length for wide characters */
static int txt_utf8_len(const char *src)
@@ -804,6 +827,17 @@ static int txt_utf8_len(const char *src)
return len;
}
+static int txt_utf8_width(const char *src)
+{
+ int col = 0;
+
+ for (; *src; src += BLI_str_utf8_size(src)) {
+ col += BLI_str_utf8_char_width(src);
+ }
+
+ return col;
+}
+
void txt_move_up(Text *text, short sel)
{
TextLine **linep;
@@ -815,10 +849,10 @@ void txt_move_up(Text *text, short sel)
if (!*linep) return;
if ((*linep)->prev) {
- int index = txt_utf8_offset_to_index((*linep)->line, *charp);
+ int column = txt_utf8_offset_to_column((*linep)->line, *charp);
*linep = (*linep)->prev;
- if (index > txt_utf8_len((*linep)->line)) *charp = (*linep)->len;
- else *charp = txt_utf8_index_to_offset((*linep)->line, index);
+ if (column > txt_utf8_width((*linep)->line)) *charp = (*linep)->len;
+ else *charp = txt_utf8_column_to_offset((*linep)->line, column);
}
else {
@@ -839,10 +873,10 @@ void txt_move_down(Text *text, short sel)
if (!*linep) return;
if ((*linep)->next) {
- int index = txt_utf8_offset_to_index((*linep)->line, *charp);
+ int column = txt_utf8_offset_to_column((*linep)->line, *charp);
*linep = (*linep)->next;
- if (index > txt_utf8_len((*linep)->line)) *charp = (*linep)->len;
- else *charp = txt_utf8_index_to_offset((*linep)->line, index);
+ if (column > txt_utf8_width((*linep)->line)) *charp = (*linep)->len;
+ else *charp = txt_utf8_column_to_offset((*linep)->line, column);
}
else {
txt_move_eol(text, sel);
diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h
index 30d5c28bf98..d20cbd2a91c 100644
--- a/source/blender/blenlib/BLI_string_utf8.h
+++ b/source/blender/blenlib/BLI_string_utf8.h
@@ -56,7 +56,14 @@ size_t BLI_strnlen_utf8(const char *start, const size_t maxlen);
size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst, const wchar_t *__restrict src, const size_t maxcpy);
size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst, const char *__restrict src, const size_t maxcpy);
-#define BLI_UTF8_MAX 6
+/* count columns that character/string occupies, based on wcwidth.c */
+int BLI_wcwidth(wchar_t ucs);
+int BLI_wcswidth(const wchar_t *pwcs, size_t n);
+int BLI_str_utf8_char_width(const char *p); /* warning, can return -1 on bad chars */
+int BLI_str_utf8_char_width_safe(const char *p);
+
+#define BLI_UTF8_MAX 6 /* mem */
+#define BLI_UTF8_WIDTH_MAX 2 /* columns */
#define BLI_UTF8_ERR ((unsigned int)-1)
#ifdef __cplusplus
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index e5851109d87..bd6e84f7ef9 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -29,6 +29,7 @@ set(INC
../makesdna
../../../intern/ghost
../../../intern/guardedalloc
+ ../../../extern/wcwidth
)
set(INC_SYS
diff --git a/source/blender/blenlib/SConscript b/source/blender/blenlib/SConscript
index 2be06f7311d..41a9fe9e8b4 100644
--- a/source/blender/blenlib/SConscript
+++ b/source/blender/blenlib/SConscript
@@ -31,7 +31,7 @@ sources = env.Glob('intern/*.c')
cflags=''
# don't add ../blenkernel back!
-incs = '. ../makesdna #/intern/guardedalloc #/intern/ghost'
+incs = '. ../makesdna #/intern/guardedalloc #/intern/ghost #/extern/wcwidth'
incs += ' ' + env['BF_FREETYPE_INC']
incs += ' ' + env['BF_ZLIB_INC']
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index 26235de4dd2..fe8f3c20ab4 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <wchar.h>
#include <wctype.h>
+#include <wcwidth.h>
#include <stdio.h>
#include <stdlib.h>
@@ -317,6 +318,42 @@ size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst_w, const char *__rest
/* end wchar_t / utf8 functions */
/* --------------------------------------------------------------------------*/
+/* count columns that character/string occupies, based on wcwidth.c */
+
+int BLI_wcwidth(wchar_t ucs)
+{
+ return mk_wcwidth(ucs);
+}
+
+int BLI_wcswidth(const wchar_t *pwcs, size_t n)
+{
+ return mk_wcswidth(pwcs, n);
+}
+
+int BLI_str_utf8_char_width(const char *p)
+{
+ unsigned int unicode = BLI_str_utf8_as_unicode(p);
+ if (unicode == BLI_UTF8_ERR)
+ return -1;
+
+ return BLI_wcwidth((wchar_t)unicode);
+}
+
+int BLI_str_utf8_char_width_safe(const char *p)
+{
+ int columns;
+
+ unsigned int unicode = BLI_str_utf8_as_unicode(p);
+ if (unicode == BLI_UTF8_ERR)
+ return 1;
+
+ columns = BLI_wcwidth((wchar_t)unicode);
+
+ return (columns < 0) ? 1 : columns;
+}
+
+/* --------------------------------------------------------------------------*/
+
/* copied from glib's gutf8.c, added 'Err' arg */
/* note, glib uses unsigned int for unicode, best we do the same,
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 3cd7499c78e..03805dd0ef8 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -330,6 +330,8 @@ void uiStyleInit(void)
{
uiFont *font = U.uifonts.first;
uiStyle *style = U.uistyles.first;
+ int monofont_size = datatoc_bmonofont_ttf_size;
+ unsigned char *monofont_ttf = (unsigned char*)datatoc_bmonofont_ttf;
/* recover from uninitialized dpi */
if (U.dpi == 0)
@@ -400,15 +402,33 @@ void uiStyleInit(void)
ui_style_new(&U.uistyles, "Default Style", UIFONT_DEFAULT);
}
+#ifdef WITH_INTERNATIONAL
+ /* use unicode font for text editor and interactive console */
+ if (U.transopts & USER_DOTRANSLATE) {
+ monofont_ttf = BLF_get_unifont_mono(&monofont_size);
+
+ if (!monofont_ttf) {
+ /* fall back if not found */
+ monofont_size = datatoc_bmonofont_ttf_size;
+ monofont_ttf = (unsigned char*)datatoc_bmonofont_ttf;
+ }
+ }
+
+ /* reload */
+ BLF_unload("monospace");
+ blf_mono_font = -1;
+ blf_mono_font_render = -1;
+#endif
+
/* XXX, this should be moved into a style, but for now best only load the monospaced font once. */
if (blf_mono_font == -1)
- blf_mono_font = BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
+ blf_mono_font = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size);
BLF_size(blf_mono_font, 12 * U.pixelsize, 72);
/* second for rendering else we get threading problems */
if (blf_mono_font_render == -1)
- blf_mono_font_render = BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
+ blf_mono_font_render = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size);
BLF_size(blf_mono_font_render, 12 * U.pixelsize, 72 );
}
diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c
index 73747239255..cb191d0b15e 100644
--- a/source/blender/editors/space_console/console_draw.c
+++ b/source/blender/editors/space_console/console_draw.c
@@ -150,6 +150,26 @@ static int console_textview_line_get(struct TextViewContext *tvc, const char **l
return 1;
}
+static void console_cursor_wrap_offset(const char *str, int width, int *row, int *column, const char *end)
+{
+ int col;
+
+ for (; *str; str += BLI_str_utf8_size_safe(str)) {
+ col = BLI_str_utf8_char_width_safe(str);
+
+ if (*column + col > width) {
+ (*row)++;
+ *column = 0;
+ }
+
+ if (end && str >= end)
+ break;
+
+ *column += col;
+ }
+ return;
+}
+
static int console_textview_line_color(struct TextViewContext *tvc, unsigned char fg[3], unsigned char UNUSED(bg[3]))
{
ConsoleLine *cl_iter = (ConsoleLine *)tvc->iter;
@@ -158,24 +178,18 @@ static int console_textview_line_color(struct TextViewContext *tvc, unsigned cha
if (tvc->iter_index == 0) {
const SpaceConsole *sc = (SpaceConsole *)tvc->arg1;
const ConsoleLine *cl = (ConsoleLine *)sc->history.last;
- const int prompt_len = BLI_strlen_utf8(sc->prompt);
- const int cursor_loc = BLI_strnlen_utf8(cl->line, cl->cursor) + prompt_len;
- const int line_len = BLI_strlen_utf8(cl->line) + prompt_len;
+ int offl = 0, offc = 0;
int xy[2] = {CONSOLE_DRAW_MARGIN, CONSOLE_DRAW_MARGIN};
int pen[2];
xy[1] += tvc->lheight / 6;
- /* account for wrapping */
- if (line_len < tvc->console_width) {
- /* simple case, no wrapping */
- pen[0] = tvc->cwidth * cursor_loc;
- pen[1] = -2;
- }
- else {
- /* wrap */
- pen[0] = tvc->cwidth * (cursor_loc % tvc->console_width);
- pen[1] = -2 + (((line_len / tvc->console_width) - (cursor_loc / tvc->console_width)) * tvc->lheight);
- }
+ console_cursor_wrap_offset(sc->prompt, tvc->console_width, &offl, &offc, NULL);
+ console_cursor_wrap_offset(cl->line, tvc->console_width, &offl, &offc, cl->line + cl->cursor);
+ pen[0] = tvc->cwidth * offc;
+ pen[1] = -2 - tvc->lheight * offl;
+
+ console_cursor_wrap_offset(cl->line + cl->cursor, tvc->console_width, &offl, &offc, NULL);
+ pen[1] += tvc->lheight * offl;
/* cursor */
UI_GetThemeColor3ubv(TH_CONSOLE_CURSOR, fg);
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index 66f4904c340..58418f2befd 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -31,14 +31,19 @@
#include <limits.h>
#include <assert.h>
+#include "MEM_guardedalloc.h"
+
#include "BLF_api.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_string_utf8.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "BKE_text.h"
+
#include "ED_datafiles.h"
#include "textview.h"
@@ -68,12 +73,12 @@ BLI_INLINE void console_step_sel(ConsoleDrawContext *cdc, const int step)
cdc->sel[1] += step;
}
-static void console_draw_sel(const int sel[2], const int xy[2], const int str_len_draw, int cwidth, int lheight,
- const unsigned char bg_sel[4])
+static void console_draw_sel(const char *str, const int sel[2], const int xy[2], const int str_len_draw,
+ int cwidth, int lheight, const unsigned char bg_sel[4])
{
if (sel[0] <= str_len_draw && sel[1] >= 0) {
- const int sta = max_ii(sel[0], 0);
- const int end = min_ii(sel[1], str_len_draw);
+ const int sta = txt_utf8_offset_to_column(str, max_ii(sel[0], 0));
+ const int end = txt_utf8_offset_to_column(str, min_ii(sel[1], str_len_draw));
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -85,38 +90,72 @@ static void console_draw_sel(const int sel[2], const int xy[2], const int str_le
}
}
+/* warning: allocated memory for 'offsets' must be freed by caller */
+static int console_wrap_offsets(const char *str, int len, int width, int *lines, int **offsets)
+{
+ int i, end; /* column */
+ int j; /* mem */
+
+ *lines = 1;
+
+ *offsets = MEM_callocN(sizeof(**offsets) * (len * BLI_UTF8_WIDTH_MAX / MAX2(1, width - (BLI_UTF8_WIDTH_MAX - 1)) + 1),
+ "console_wrap_offsets");
+ (*offsets)[0] = 0;
+
+ for (i = 0, end = width, j = 0; j < len && str[j]; j += BLI_str_utf8_size_safe(str + j)) {
+ int columns = BLI_str_utf8_char_width_safe(str + j);
+
+ if (i + columns > end) {
+ (*offsets)[*lines] = j;
+ (*lines)++;
+
+ end = i + width;
+ }
+ i += columns;
+ }
+ return j; /* return actual length */
+}
+
/* return 0 if the last line is off the screen
* should be able to use this for any string type */
-static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const int str_len,
+static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str_len,
const unsigned char fg[3], const unsigned char bg[3], const unsigned char bg_sel[4])
{
int rct_ofs = cdc->lheight / 4;
- int tot_lines = (str_len / cdc->console_width) + 1; /* total number of lines for wrapping */
- int y_next = (str_len > cdc->console_width) ? cdc->xy[1] + cdc->lheight * tot_lines : cdc->xy[1] + cdc->lheight;
+ int tot_lines; /* total number of lines for wrapping */
+ int *offsets; /* offsets of line beginnings for wrapping */
+ int y_next;
const int mono = blf_mono_font;
+ str_len = console_wrap_offsets(str, str_len, cdc->console_width, &tot_lines, &offsets);
+ y_next = cdc->xy[1] + cdc->lheight * tot_lines;
+
/* just advance the height */
if (cdc->draw == 0) {
- if (cdc->pos_pick && (cdc->mval[1] != INT_MAX)) {
- if (cdc->xy[1] <= cdc->mval[1]) {
- if ((y_next >= cdc->mval[1])) {
- int ofs = (int)floor(((float)cdc->mval[0] / (float)cdc->cwidth));
-
- /* wrap */
- if (str_len > cdc->console_width)
- ofs += cdc->console_width * ((int)((((float)(y_next - cdc->mval[1]) /
- (float)(y_next - cdc->xy[1])) * tot_lines)));
-
- CLAMP(ofs, 0, str_len);
- *cdc->pos_pick += str_len - ofs;
+ if (cdc->pos_pick && cdc->mval[1] != INT_MAX && cdc->xy[1] <= cdc->mval[1]) {
+ if (y_next >= cdc->mval[1]) {
+ int ofs = 0;
+
+ /* wrap */
+ if (tot_lines > 1) {
+ int iofs = (int)((float)(y_next - cdc->mval[1]) / cdc->lheight);
+ ofs += offsets[MIN2(iofs, tot_lines - 1)];
}
- else
- *cdc->pos_pick += str_len + 1;
+
+ /* last part */
+ ofs += txt_utf8_column_to_offset(str + ofs,
+ (int)floor((float)cdc->mval[0] / cdc->cwidth));
+
+ CLAMP(ofs, 0, str_len);
+ *cdc->pos_pick += str_len - ofs;
}
+ else
+ *cdc->pos_pick += str_len + 1;
}
cdc->xy[1] = y_next;
+ MEM_freeN(offsets);
return 1;
}
else if (y_next - cdc->lheight < cdc->ymin) {
@@ -128,12 +167,15 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const i
console_step_sel(cdc, -(str_len + 1));
}
+ MEM_freeN(offsets);
return 1;
}
if (tot_lines > 1) { /* wrap? */
- const int initial_offset = ((tot_lines - 1) * cdc->console_width);
- const char *line_stride = str + initial_offset; /* advance to the last line and draw it first */
+ const int initial_offset = offsets[tot_lines - 1];
+ size_t len = str_len - initial_offset;
+ const char *s = str + initial_offset;
+ int i;
int sel_orig[2];
copy_v2_v2_int(sel_orig, cdc->sel);
@@ -151,36 +193,38 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const i
/* last part needs no clipping */
BLF_position(mono, cdc->xy[0], cdc->xy[1], 0);
- BLF_draw(mono, line_stride, str_len - initial_offset);
+ BLF_draw_mono(mono, s, len, cdc->cwidth);
if (cdc->sel[0] != cdc->sel[1]) {
console_step_sel(cdc, -initial_offset);
// glColor4ub(255, 0, 0, 96); // debug
- console_draw_sel(cdc->sel, cdc->xy, str_len % cdc->console_width, cdc->cwidth, cdc->lheight, bg_sel);
- console_step_sel(cdc, cdc->console_width);
+ console_draw_sel(s, cdc->sel, cdc->xy, len, cdc->cwidth, cdc->lheight, bg_sel);
glColor3ubv(fg);
}
cdc->xy[1] += cdc->lheight;
- line_stride -= cdc->console_width;
-
- for (; line_stride >= str; line_stride -= cdc->console_width) {
+ for (i = tot_lines - 1; i > 0; i--) {
+ len = offsets[i] - offsets[i - 1];
+ s = str + offsets[i - 1];
+
BLF_position(mono, cdc->xy[0], cdc->xy[1], 0);
- BLF_draw(mono, line_stride, cdc->console_width);
+ BLF_draw_mono(mono, s, len, cdc->cwidth);
if (cdc->sel[0] != cdc->sel[1]) {
+ console_step_sel(cdc, len);
// glColor4ub(0, 255, 0, 96); // debug
- console_draw_sel(cdc->sel, cdc->xy, cdc->console_width, cdc->cwidth, cdc->lheight, bg_sel);
- console_step_sel(cdc, cdc->console_width);
+ console_draw_sel(s, cdc->sel, cdc->xy, len, cdc->cwidth, cdc->lheight, bg_sel);
glColor3ubv(fg);
}
cdc->xy[1] += cdc->lheight;
/* check if were out of view bounds */
- if (cdc->xy[1] > cdc->ymax)
+ if (cdc->xy[1] > cdc->ymax) {
+ MEM_freeN(offsets);
return 0;
+ }
}
copy_v2_v2_int(cdc->sel, sel_orig);
@@ -196,7 +240,7 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const i
glColor3ubv(fg);
BLF_position(mono, cdc->xy[0], cdc->xy[1], 0);
- BLF_draw(mono, str, str_len);
+ BLF_draw_mono(mono, str, str_len, cdc->cwidth);
if (cdc->sel[0] != cdc->sel[1]) {
int isel[2];
@@ -205,16 +249,19 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const i
isel[1] = str_len - cdc->sel[0];
// glColor4ub(255, 255, 0, 96); // debug
- console_draw_sel(isel, cdc->xy, str_len, cdc->cwidth, cdc->lheight, bg_sel);
+ console_draw_sel(str, isel, cdc->xy, str_len, cdc->cwidth, cdc->lheight, bg_sel);
console_step_sel(cdc, -(str_len + 1));
}
cdc->xy[1] += cdc->lheight;
- if (cdc->xy[1] > cdc->ymax)
+ if (cdc->xy[1] > cdc->ymax) {
+ MEM_freeN(offsets);
return 0;
+ }
}
+ MEM_freeN(offsets);
return 1;
}
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index a146fec3dac..95fd7fce878 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -67,12 +67,14 @@ static void text_font_end(SpaceText *UNUSED(st))
{
}
-static int text_font_draw(SpaceText *UNUSED(st), int x, int y, const char *str)
+static int text_font_draw(SpaceText *st, int x, int y, const char *str)
{
+ int columns;
+
BLF_position(mono, x, y, 0);
- BLF_draw(mono, str, BLF_DRAW_STR_DUMMY_MAX);
+ columns = BLF_draw_mono(mono, str, BLF_DRAW_STR_DUMMY_MAX, st->cwidth);
- return BLF_width(mono, str);
+ return st->cwidth * columns;
}
static int text_font_draw_character(SpaceText *st, int x, int y, char c)
@@ -85,10 +87,13 @@ static int text_font_draw_character(SpaceText *st, int x, int y, char c)
static int text_font_draw_character_utf8(SpaceText *st, int x, int y, const char *c)
{
+ int columns;
+
const size_t len = BLI_str_utf8_size_safe(c);
BLF_position(mono, x, y, 0);
- BLF_draw(mono, c, len);
- return st->cwidth;
+ columns = BLF_draw_mono(mono, c, len, st->cwidth);
+
+ return st->cwidth * columns;
}
#if 0
@@ -216,7 +221,7 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *
}
max = wrap_width(st, ar);
- cursin = txt_utf8_offset_to_index(linein->line, cursin);
+ cursin = txt_utf8_offset_to_column(linein->line, cursin);
while (linep) {
start = 0;
@@ -225,6 +230,7 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *
*offc = 0;
for (i = 0, j = 0; linep->line[j]; j += BLI_str_utf8_size_safe(linep->line + j)) {
int chars;
+ int columns = BLI_str_utf8_char_width_safe(linep->line + j); /* = 1 for tab */
/* Mimic replacement of tabs */
ch = linep->line[j];
@@ -238,7 +244,9 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *
}
while (chars--) {
- if (i - start >= max) {
+ if (i + columns - start > max) {
+ end = MIN2(end, i);
+
if (chop && linep == linein && i >= cursin) {
if (i == cursin) {
(*offl)++;
@@ -261,7 +269,7 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *
if (linep == linein && i >= cursin)
return;
}
- i++;
+ i += columns;
}
}
if (linep == linein) break;
@@ -286,9 +294,10 @@ void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursi
end = max;
chop = 1;
*offc = 0;
- cursin = txt_utf8_offset_to_index(linein->line, cursin);
+ cursin = txt_utf8_offset_to_column(linein->line, cursin);
for (i = 0, j = 0; linein->line[j]; j += BLI_str_utf8_size_safe(linein->line + j)) {
+ int columns = BLI_str_utf8_char_width_safe(linein->line + j); /* = 1 for tab */
/* Mimic replacement of tabs */
ch = linein->line[j];
@@ -301,7 +310,9 @@ void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursi
chars = 1;
while (chars--) {
- if (i - start >= max) {
+ if (i + columns - start > max) {
+ end = MIN2(end, i);
+
if (chop && i >= cursin) {
if (i == cursin) {
(*offl)++;
@@ -324,7 +335,7 @@ void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursi
if (i >= cursin)
return;
}
- i++;
+ i += columns;
}
}
}
@@ -337,24 +348,35 @@ int text_get_char_pos(SpaceText *st, const char *line, int cur)
if (line[i] == '\t')
a += st->tabnumber - a % st->tabnumber;
else
- a++;
+ a += BLI_str_utf8_char_width_safe(line + i);
}
return a;
}
-static const char *txt_utf8_get_nth(const char *str, int n)
+static const char *txt_utf8_forward_columns(const char *str, int columns, int *padding)
{
- int pos = 0;
- while (str[pos] && n--) {
- pos += BLI_str_utf8_size_safe(str + pos);
+ int col;
+ const char *p = str;
+ while (*p) {
+ col = BLI_str_utf8_char_width(p);
+ if (columns - col < 0)
+ break;
+ columns -= col;
+ p += BLI_str_utf8_size_safe(p);
+ if (columns == 0)
+ break;
}
- return str + pos;
+ if (padding)
+ *padding = *p ? columns : 0;
+ return p;
}
static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w, const char *format, int skip)
{
FlattenString fs;
- int basex, i, a, start, end, max, lines; /* view */
+ int basex, lines;
+ int i, wrap, end, max, columns, padding; /* column */
+ int a, fstart, fpos; /* utf8 chars */
int mi, ma, mstart, mend; /* mem */
char fmt_prev = 0xff;
@@ -365,41 +387,46 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
basex = x;
lines = 1;
- start = 0; mstart = 0;
- end = max; mend = txt_utf8_get_nth(str, max) - str;
+ fpos = fstart = 0; mstart = 0;
+ mend = txt_utf8_forward_columns(str, max, &padding) - str;
+ end = wrap = max - padding;
- for (i = 0, mi = 0; str[mi]; i++, mi += BLI_str_utf8_size_safe(str + mi)) {
- if (i - start >= max) {
+ for (i = 0, mi = 0; str[mi]; i += columns, mi += BLI_str_utf8_size_safe(str + mi)) {
+ columns = BLI_str_utf8_char_width_safe(str + mi);
+ if (i + columns > end) {
/* skip hidden part of line */
if (skip) {
skip--;
- start = end; mstart = mend;
- end += max; mend = txt_utf8_get_nth(str + mend, max) - str;
+ fstart = fpos; mstart = mend;
+ mend = txt_utf8_forward_columns(str + mend, max, &padding) - str;
+ end = (wrap += max - padding);
continue;
}
/* Draw the visible portion of text on the overshot line */
- for (a = start, ma = mstart; a < end; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
+ for (a = fstart, ma = mstart; ma < mend; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
if (st->showsyntax && format) {
if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]);
}
x += text_font_draw_character_utf8(st, x, y, str + ma);
+ fpos++;
}
y -= st->lheight_dpi + TXT_LINE_SPACING;
x = basex;
lines++;
- start = end; mstart = mend;
- end += max; mend = txt_utf8_get_nth(str + mend, max) - str;
+ fstart = fpos; mstart = mend;
+ mend = txt_utf8_forward_columns(str + mend, max, &padding) - str;
+ end = (wrap += max - padding);
if (y <= 0) break;
}
else if (str[mi] == ' ' || str[mi] == '-') {
- end = i + 1; mend = mi + 1;
+ wrap = i + 1; mend = mi + 1;
}
}
/* Draw the remaining text */
- for (a = start, ma = mstart; str[ma] && y > 0; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
+ for (a = fstart, ma = mstart; str[ma] && y > 0; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
if (st->showsyntax && format) {
if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]);
}
@@ -412,53 +439,55 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
return lines;
}
-static int text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int draw, int x, int y, const char *format)
+static void text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int x, int y, const char *format)
{
FlattenString fs;
- int *acc, r = 0;
- const char *in;
+ int columns, size, n, w = 0, padding, amount = 0;
+ const char *in = NULL;
- int w = flatten_string(st, &fs, str);
- if (w < cshift) {
- flatten_string_free(&fs);
- return 0; /* String is shorter than shift */
- }
-
- in = txt_utf8_get_nth(fs.buf, cshift);
- acc = fs.accum + cshift;
- w = w - cshift;
+ for (n = flatten_string(st, &fs, str), str = fs.buf; n > 0; n--) {
+ columns = BLI_str_utf8_char_width_safe(str);
+ size = BLI_str_utf8_size_safe(str);
- if (draw) {
- int amount = maxwidth ? MIN2(w, maxwidth) : w;
-
- if (st->showsyntax && format) {
- int a, str_shift = 0;
- char fmt_prev = 0xff;
- format = format + cshift;
-
- for (a = 0; a < amount; a++) {
- if (format[a] != fmt_prev) format_draw_color(fmt_prev = format[a]);
- x += text_font_draw_character_utf8(st, x, y, in + str_shift);
- str_shift += BLI_str_utf8_size_safe(in + str_shift);
+ if (!in) {
+ if (w >= cshift) {
+ padding = w - cshift;
+ in = str;
}
+ else if (format)
+ format++;
}
- else {
- text_font_draw(st, x, y, in);
+ if (in) {
+ if (maxwidth && w + columns > cshift + maxwidth)
+ break;
+ amount++;
+ }
+
+ w += columns;
+ str += size;
+ }
+ if (!in) {
+ flatten_string_free(&fs);
+ return; /* String is shorter than shift or ends with a padding */
+ }
+
+ x += st->cwidth * padding;
+
+ if (st->showsyntax && format) {
+ int a, str_shift = 0;
+ char fmt_prev = 0xff;
+
+ for (a = 0; a < amount; a++) {
+ if (format[a] != fmt_prev) format_draw_color(fmt_prev = format[a]);
+ x += text_font_draw_character_utf8(st, x, y, in + str_shift);
+ str_shift += BLI_str_utf8_size_safe(in + str_shift);
}
}
else {
- while (w-- && *acc++ < maxwidth)
- r += st->cwidth;
+ text_font_draw(st, x, y, in);
}
flatten_string_free(&fs);
-
- if (cshift && r == 0)
- return 0;
- else if (st->showlinenrs)
- return r + TXT_OFFSET + TEXTXLOC;
- else
- return r + TXT_OFFSET;
}
/************************ cache utilities *****************************/
@@ -672,6 +701,8 @@ int text_get_visible_lines(SpaceText *st, ARegion *ar, const char *str)
start = 0;
end = max;
for (i = 0, j = 0; str[j]; j += BLI_str_utf8_size_safe(str + j)) {
+ int columns = BLI_str_utf8_char_width_safe(str + j); /* = 1 for tab */
+
/* Mimic replacement of tabs */
ch = str[j];
if (ch == '\t') {
@@ -683,16 +714,16 @@ int text_get_visible_lines(SpaceText *st, ARegion *ar, const char *str)
}
while (chars--) {
- if (i - start >= max) {
+ if (i + columns - start > max) {
lines++;
- start = end;
+ start = MIN2(end, i);
end += max;
}
else if (ch == ' ' || ch == '-') {
end = i + 1;
}
- i++;
+ i += columns;
}
}
@@ -931,7 +962,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar)
buf[i] = '\0';
if (lines >= 0) {
y -= st->lheight_dpi;
- text_draw(st, buf, 0, 0, 1, x + 4, y - 3, NULL);
+ text_draw(st, buf, 0, 0, x + 4, y - 3, NULL);
}
i = 0; br = DOC_WIDTH; lines++;
}
@@ -940,7 +971,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar)
buf[br] = '\0';
if (lines >= 0) {
y -= st->lheight_dpi;
- text_draw(st, buf, 0, 0, 1, x + 4, y - 3, NULL);
+ text_draw(st, buf, 0, 0, x + 4, y - 3, NULL);
}
p -= i - br - 1; /* Rewind pointer to last break */
i = 0; br = DOC_WIDTH; lines++;
@@ -959,9 +990,9 @@ static void draw_documentation(SpaceText *st, ARegion *ar)
static void draw_suggestion_list(SpaceText *st, ARegion *ar)
{
SuggItem *item, *first, *last, *sel;
- TextLine *tmp;
- char str[SUGG_LIST_WIDTH + 1];
- int w, boxw = 0, boxh, i, l, x, y, *top;
+ char str[SUGG_LIST_WIDTH * BLI_UTF8_MAX + 1];
+ int offl, offc, vcurl, vcurc;
+ int w, boxw = 0, boxh, i, x, y, *top;
const int lheight = st->lheight_dpi + TXT_LINE_SPACING;
const int margin_x = 2;
@@ -977,24 +1008,24 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar)
sel = texttool_suggest_selected();
top = texttool_suggest_top();
- /* Count the visible lines to the cursor */
- for (tmp = st->text->curl, l = -st->top; tmp; tmp = tmp->prev, l++) ;
- if (l < 0) return;
-
- if (st->showlinenrs) {
- x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET + TEXTXLOC - 4;
- }
- else {
- x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET - 4;
- }
+ wrap_offset(st, ar, st->text->curl, st->text->curc, &offl, &offc);
+ vcurl = txt_get_span(st->text->lines.first, st->text->curl) - st->top + offl;
+ vcurc = text_get_char_pos(st, st->text->curl->line, st->text->curc) - st->left + offc;
+
+ x = st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET;
+ x += vcurc * st->cwidth - 4;
+ y = ar->winy - (vcurl + 1) * lheight - 2;
+
/* offset back so the start of the text lines up with the suggestions,
* not essential but makes suggestions easier to follow */
x -= st->cwidth * (st->text->curc - text_find_identifier_start(st->text->curl->line, st->text->curc));
- y = ar->winy - lheight * l - 2;
boxw = SUGG_LIST_WIDTH * st->cwidth + 20;
boxh = SUGG_LIST_SIZE * lheight + 8;
+ if (x + boxw > ar->winx)
+ x = MAX2(0, ar->winx - boxw);
+
/* not needed but stands out nicer */
uiDrawBoxShadow(220, x, y - boxh, x + boxw, y);
@@ -1007,12 +1038,13 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar)
for (i = 0, item = first; i < *top && item->next; i++, item = item->next) ;
for (i = 0; i < SUGG_LIST_SIZE && item; i++, item = item->next) {
+ int len = txt_utf8_forward_columns(item->name, SUGG_LIST_WIDTH, NULL) - item->name;
y -= lheight;
- BLI_strncpy(str, item->name, SUGG_LIST_WIDTH);
+ BLI_strncpy(str, item->name, len + 1);
- w = BLF_width(mono, str);
+ w = st->cwidth * text_get_char_pos(st, str, len);
if (item == sel) {
UI_ThemeColor(TH_SHADE2);
@@ -1020,7 +1052,7 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar)
}
format_draw_color(item->type);
- text_draw(st, str, 0, 0, 1, x + margin_x, y - 1, NULL);
+ text_draw(st, str, 0, 0, x + margin_x, y - 1, NULL);
if (item == last) break;
}
@@ -1382,7 +1414,7 @@ void draw_text_main(SpaceText *st, ARegion *ar)
}
else {
/* draw unwrapped text */
- text_draw(st, tmp->line, st->left, ar->winx / st->cwidth, 1, x, y, tmp->format);
+ text_draw(st, tmp->line, st->left, ar->winx / st->cwidth, x, y, tmp->format);
y -= st->lheight_dpi + TXT_LINE_SPACING;
}
@@ -1439,8 +1471,6 @@ void text_scroll_to_cursor(SpaceText *st, ScrArea *sa)
winx = ar->winx;
break;
}
-
- winx -= TXT_SCROLL_WIDTH;
text_update_character_width(st);
@@ -1458,10 +1488,11 @@ void text_scroll_to_cursor(SpaceText *st, ScrArea *sa)
st->left = 0;
}
else {
- x = text_draw(st, text->sell->line, st->left, text->selc, 0, 0, 0, NULL);
+ x = st->cwidth * (text_get_char_pos(st, text->sell->line, text->selc) - st->left);
+ winx -= TXT_OFFSET + (st->showlinenrs ? TEXTXLOC : 0) + TXT_SCROLL_WIDTH;
- if (x == 0 || x > winx)
- st->left = text->curc - 0.5 * winx / st->cwidth;
+ if (x <= 0 || x > winx)
+ st->left += (x - winx / 2) / st->cwidth;
}
if (st->top < 0) st->top = 0;
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index e6f95c39baf..3a7070e1a7a 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -72,7 +72,7 @@
/************************ poll ***************************/
-BLI_INLINE int text_pixel_x_to_index(SpaceText *st, const int x)
+BLI_INLINE int text_pixel_x_to_column(SpaceText *st, const int x)
{
/* add half the char width so mouse cursor selection is inbetween letters */
return (x + (st->cwidth / 2)) / st->cwidth;
@@ -1407,6 +1407,8 @@ static int text_get_cursor_rel(SpaceText *st, ARegion *ar, TextLine *linein, int
for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe(linein->line + j)) {
int chars;
+ int columns = BLI_str_utf8_char_width_safe(linein->line + j); /* = 1 for tab */
+
/* Mimic replacement of tabs */
ch = linein->line[j];
if (ch == '\t') {
@@ -1418,16 +1420,18 @@ static int text_get_cursor_rel(SpaceText *st, ARegion *ar, TextLine *linein, int
}
while (chars--) {
- if (rell == 0 && i - start == relc) {
+ if (rell == 0 && i - start <= relc && i + columns - start > relc) {
/* current position could be wrapped to next line */
/* this should be checked when end of current line would be reached */
selc = j;
found = 1;
}
- else if (i - end == relc) {
+ else if (i - end <= relc && i + columns - end > relc) {
curs = j;
}
- if (i - start >= max) {
+ if (i + columns - start > max) {
+ end = MIN2(end, i);
+
if (found) {
/* exact cursor position was found, check if it's */
/* still on needed line (hasn't been wrapped) */
@@ -1443,7 +1447,7 @@ static int text_get_cursor_rel(SpaceText *st, ARegion *ar, TextLine *linein, int
chop = 1;
rell--;
- if (rell == 0 && i - start >= relc) {
+ if (rell == 0 && i + columns - start > relc) {
selc = curs;
loop = 0;
break;
@@ -1460,7 +1464,7 @@ static int text_get_cursor_rel(SpaceText *st, ARegion *ar, TextLine *linein, int
break;
}
- if (rell == 0 && i - start >= relc) {
+ if (rell == 0 && i + columns - start > relc) {
selc = curs;
loop = 0;
break;
@@ -1469,7 +1473,7 @@ static int text_get_cursor_rel(SpaceText *st, ARegion *ar, TextLine *linein, int
endj = j;
chop = 0;
}
- i++;
+ i += columns;
}
}
@@ -1587,6 +1591,8 @@ static void txt_wrap_move_bol(SpaceText *st, ARegion *ar, short sel)
for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe((*linep)->line + j)) {
int chars;
+ int columns = BLI_str_utf8_char_width_safe((*linep)->line + j); /* = 1 for tab */
+
/* Mimic replacement of tabs */
ch = (*linep)->line[j];
if (ch == '\t') {
@@ -1598,11 +1604,13 @@ static void txt_wrap_move_bol(SpaceText *st, ARegion *ar, short sel)
}
while (chars--) {
- if (i - start >= max) {
+ if (i + columns - start > max) {
+ end = MIN2(end, i);
+
*charp = endj;
if (j >= oldc) {
- if (ch == '\0') *charp = txt_utf8_index_to_offset((*linep)->line, start);
+ if (ch == '\0') *charp = txt_utf8_column_to_offset((*linep)->line, start);
loop = 0;
break;
}
@@ -1615,7 +1623,7 @@ static void txt_wrap_move_bol(SpaceText *st, ARegion *ar, short sel)
}
else if (ch == ' ' || ch == '-' || ch == '\0') {
if (j >= oldc) {
- *charp = txt_utf8_index_to_offset((*linep)->line, start);
+ *charp = txt_utf8_column_to_offset((*linep)->line, start);
loop = 0;
break;
}
@@ -1624,7 +1632,7 @@ static void txt_wrap_move_bol(SpaceText *st, ARegion *ar, short sel)
endj = j + 1;
chop = 0;
}
- i++;
+ i += columns;
}
}
@@ -1655,6 +1663,8 @@ static void txt_wrap_move_eol(SpaceText *st, ARegion *ar, short sel)
for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe((*linep)->line + j)) {
int chars;
+ int columns = BLI_str_utf8_char_width_safe((*linep)->line + j); /* = 1 for tab */
+
/* Mimic replacement of tabs */
ch = (*linep)->line[j];
if (ch == '\t') {
@@ -1666,7 +1676,9 @@ static void txt_wrap_move_eol(SpaceText *st, ARegion *ar, short sel)
}
while (chars--) {
- if (i - start >= max) {
+ if (i + columns - start > max) {
+ end = MIN2(end, i);
+
if (chop) endj = BLI_str_prev_char_utf8((*linep)->line + j) - (*linep)->line;
if (endj >= oldc) {
@@ -1690,7 +1702,7 @@ static void txt_wrap_move_eol(SpaceText *st, ARegion *ar, short sel)
endj = j;
chop = 0;
}
- i++;
+ i += columns;
}
}
@@ -2352,7 +2364,7 @@ typedef struct SetSelection {
short old[2];
} SetSelection;
-static int flatten_len(SpaceText *st, const char *str)
+static int flatten_width(SpaceText *st, const char *str)
{
int i, total = 0;
@@ -2361,21 +2373,29 @@ static int flatten_len(SpaceText *st, const char *str)
total += st->tabnumber - total % st->tabnumber;
}
else {
- total++;
+ total += BLI_str_utf8_char_width_safe(str + i);
}
}
return total;
}
-static int flatten_index_to_offset(SpaceText *st, const char *str, int index)
+static int flatten_column_to_offset(SpaceText *st, const char *str, int index)
{
- int i, j;
- for (i = 0, j = 0; i < index; j += BLI_str_utf8_size_safe(str + j))
+ int i = 0, j = 0, col;
+
+ while (*(str + j)) {
if (str[j] == '\t')
- i += st->tabnumber - i % st->tabnumber;
+ col = st->tabnumber - i % st->tabnumber;
else
- i++;
+ col = BLI_str_utf8_char_width_safe(str + j);
+
+ if (i + col > index)
+ break;
+
+ i += col;
+ j += BLI_str_utf8_size_safe(str + j);
+ }
return j;
}
@@ -2402,7 +2422,7 @@ static TextLine *get_first_visible_line(SpaceText *st, ARegion *ar, int *y)
static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, int y, int sel)
{
Text *text = st->text;
- int max = wrap_width(st, ar); /* view */
+ int max = wrap_width(st, ar); /* column */
int charp = -1; /* mem */
int loop = 1, found = 0; /* flags */
char ch;
@@ -2411,12 +2431,13 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
TextLine *linep = get_first_visible_line(st, ar, &y);
while (loop && linep) {
- int i = 0, start = 0, end = max; /* view */
+ int i = 0, start = 0, end = max; /* column */
int j = 0, curs = 0, endj = 0; /* mem */
int chop = 1; /* flags */
for (; loop; j += BLI_str_utf8_size_safe(linep->line + j)) {
int chars;
+ int columns = BLI_str_utf8_char_width_safe(linep->line + j); /* = 1 for tab */
/* Mimic replacement of tabs */
ch = linep->line[j];
@@ -2436,17 +2457,19 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
break;
/* Exactly at the cursor */
}
- else if (y == 0 && i - start == x) {
+ else if (y == 0 && i - start <= x && i + columns - start > x) {
/* current position could be wrapped to next line */
/* this should be checked when end of current line would be reached */
charp = curs = j;
found = 1;
/* Prepare curs for next wrap */
}
- else if (i - end == x) {
+ else if (i - end <= x && i + columns - end > x) {
curs = j;
}
- if (i - start >= max) {
+ if (i + columns - start > max) {
+ end = MIN2(end, i);
+
if (found) {
/* exact cursor position was found, check if it's */
/* still on needed line (hasn't been wrapped) */
@@ -2463,7 +2486,7 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
y--;
chop = 1;
- if (y == 0 && i - start >= x) {
+ if (y == 0 && i + columns - start > x) {
charp = curs;
loop = 0;
break;
@@ -2475,7 +2498,7 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
break;
}
- if (y == 0 && i - start >= x) {
+ if (y == 0 && i + columns - start > x) {
charp = curs;
loop = 0;
break;
@@ -2484,7 +2507,7 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
endj = j;
chop = 0;
}
- i++;
+ i += columns;
}
if (ch == '\0') break;
@@ -2523,7 +2546,7 @@ static void text_cursor_set_to_pos(SpaceText *st, ARegion *ar, int x, int y, int
else x -= TXT_OFFSET;
if (x < 0) x = 0;
- x = text_pixel_x_to_index(st, x) + st->left;
+ x = text_pixel_x_to_column(st, x) + st->left;
if (st->wordwrap) {
text_cursor_set_to_pos_wrapped(st, ar, x, y, sel);
@@ -2546,8 +2569,8 @@ static void text_cursor_set_to_pos(SpaceText *st, ARegion *ar, int x, int y, int
}
- w = flatten_len(st, (*linep)->line);
- if (x < w) *charp = flatten_index_to_offset(st, (*linep)->line, x);
+ w = flatten_width(st, (*linep)->line);
+ if (x < w) *charp = flatten_column_to_offset(st, (*linep)->line, x);
else *charp = (*linep)->len;
}
if (!sel) txt_pop_sel(text);
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index da0c6dd2a63..6e557647d12 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -449,6 +449,7 @@ void WM_exit_ext(bContext *C, const short do_python)
#ifdef WITH_INTERNATIONAL
BLF_free_unifont();
+ BLF_free_unifont_mono();
BLF_lang_free();
#endif
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index 5e65324d893..c775f7d3279 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -150,6 +150,7 @@ endif()
bf_intern_opencolorio
bf_intern_opennl
extern_rangetree
+ extern_wcwidth
)
if(WITH_MOD_CLOTH_ELTOPO)
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 24c5ccceea3..e4d37942e17 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -912,6 +912,7 @@ endif()
bf_intern_raskter
bf_intern_opencolorio
extern_rangetree
+ extern_wcwidth
)
if(WITH_COMPOSITOR)
diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
index c1f43306eba..5d843cccf85 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
@@ -1055,6 +1055,7 @@ int main(int argc, char** argv)
#ifdef WITH_INTERNATIONAL
BLF_free_unifont();
+ BLF_free_unifont_mono();
BLF_lang_free();
#endif