From bbb8fce43f25f0d42e2c4b61a98df1df21120868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sun, 1 Feb 2026 21:46:42 -0300 Subject: [PATCH] Instead of using `*::cell::text` and `tableview::cell::icon` in breeze and styles we will just use `*::tableview::cell`. And leave the inner elements of PushButton unaltered (since the father already can alter them). Did some fixes in `Text::findCharacterPos` and `Text::findCharacterFromPos`, also tentatively added support for soft-wrap in those function (I haven't tested much yet). --- bin/assets/ui/breeze.css | 38 +-- include/eepp/graphics/shapedglyph.hpp | 377 ++++++++++------------ include/eepp/graphics/text.hpp | 19 +- src/eepp/graphics/text.cpp | 204 ++++++++++-- src/tests/unit_tests/fontrendering.cpp | 49 +++ src/tools/ecode/applayout.xml.hpp | 38 ++- src/tools/ecode/ecode.cpp | 4 +- src/tools/ecode/plugins/git/gitplugin.cpp | 6 +- src/tools/ecode/settingsactions.cpp | 2 +- 9 files changed, 458 insertions(+), 279 deletions(-) diff --git a/bin/assets/ui/breeze.css b/bin/assets/ui/breeze.css index 0d99d09a4..014e7bcd7 100644 --- a/bin/assets/ui/breeze.css +++ b/bin/assets/ui/breeze.css @@ -52,12 +52,12 @@ droppable-hovering-color: #FFFFFF20; } -pushbutton::icon, -selectbutton::icon, -tableview::cell::icon, -treeview::cell::icon, +pushbutton, +selectbutton, +tableview::cell, +treeview::cell, treeview::cell::expander, -listview::cell::icon, +listview::cell, tableview::header::column:hover, treeview::header::column:hover, listview::header::column:hover { @@ -65,16 +65,16 @@ listview::header::column:hover { tint: var(--font); } -PushButton:pressed > PushButton::icon, -SelectButton:pressed > SelectButton::icon, -SelectButton:selected > SelectButton::icon, -SelectButton:selected:pressed > SelectButton::icon, -tableview::row:selected tableview::cell::text, -treeview::row:selected treeview::cell::text, -listview::row:selected listview::cell::text, -tableview::row:selected tableview::cell::icon, -treeview::row:selected treeview::cell::icon, -listview::row:selected listview::cell::icon, +PushButton:pressed > PushButton, +SelectButton:pressed > SelectButton, +SelectButton:selected > SelectButton, +SelectButton:selected:pressed > SelectButton, +tableview::row:selected tableview::cell, +treeview::row:selected treeview::cell, +listview::row:selected listview::cell, +tableview::row:selected tableview::cell, +treeview::row:selected treeview::cell, +listview::row:selected listview::cell, tableview::row:selected tableview::cell::expander, treeview::row:selected treeview::cell::expander, listview::row:selected listview::cell::expander { @@ -104,10 +104,10 @@ Tooltip, MenuBar::button, Window::title, ListView::cell, -table::cell::text, -tableview::cell::text, -treeview::cell::text, -listview::cell::text { +table::cell, +tableview::cell, +treeview::cell, +listview::cell { color: var(--font); } diff --git a/include/eepp/graphics/shapedglyph.hpp b/include/eepp/graphics/shapedglyph.hpp index 9629015fb..b010c6431 100644 --- a/include/eepp/graphics/shapedglyph.hpp +++ b/include/eepp/graphics/shapedglyph.hpp @@ -20,220 +20,171 @@ enum class TextDirection : Uint8 { /** LangScript values are the same as in hb_script_t from HarfBuzz */ enum class LangScript : Uint32 { - COMMON = EE_TAG( 'Z', 'y', 'y', 'y' ), /*1.1*/ - INHERITED = EE_TAG( 'Z', 'i', 'n', 'h' ), /*1.1*/ - UNKNOWN = EE_TAG( 'Z', 'z', 'z', 'z' ), /*5.0*/ - - ARABIC = EE_TAG( 'A', 'r', 'a', 'b' ), /*1.1*/ - ARMENIAN = EE_TAG( 'A', 'r', 'm', 'n' ), /*1.1*/ - BENGALI = EE_TAG( 'B', 'e', 'n', 'g' ), /*1.1*/ - CYRILLIC = EE_TAG( 'C', 'y', 'r', 'l' ), /*1.1*/ - DEVANAGARI = EE_TAG( 'D', 'e', 'v', 'a' ), /*1.1*/ - GEORGIAN = EE_TAG( 'G', 'e', 'o', 'r' ), /*1.1*/ - GREEK = EE_TAG( 'G', 'r', 'e', 'k' ), /*1.1*/ - GUJARATI = EE_TAG( 'G', 'u', 'j', 'r' ), /*1.1*/ - GURMUKHI = EE_TAG( 'G', 'u', 'r', 'u' ), /*1.1*/ - HANGUL = EE_TAG( 'H', 'a', 'n', 'g' ), /*1.1*/ - HAN = EE_TAG( 'H', 'a', 'n', 'i' ), /*1.1*/ - HEBREW = EE_TAG( 'H', 'e', 'b', 'r' ), /*1.1*/ - HIRAGANA = EE_TAG( 'H', 'i', 'r', 'a' ), /*1.1*/ - KANNADA = EE_TAG( 'K', 'n', 'd', 'a' ), /*1.1*/ - KATAKANA = EE_TAG( 'K', 'a', 'n', 'a' ), /*1.1*/ - LAO = EE_TAG( 'L', 'a', 'o', 'o' ), /*1.1*/ - LATIN = EE_TAG( 'L', 'a', 't', 'n' ), /*1.1*/ - MALAYALAM = EE_TAG( 'M', 'l', 'y', 'm' ), /*1.1*/ - ORIYA = EE_TAG( 'O', 'r', 'y', 'a' ), /*1.1*/ - TAMIL = EE_TAG( 'T', 'a', 'm', 'l' ), /*1.1*/ - TELUGU = EE_TAG( 'T', 'e', 'l', 'u' ), /*1.1*/ - THAI = EE_TAG( 'T', 'h', 'a', 'i' ), /*1.1*/ - - TIBETAN = EE_TAG( 'T', 'i', 'b', 't' ), /*2.0*/ - - BOPOMOFO = EE_TAG( 'B', 'o', 'p', 'o' ), /*3.0*/ - BRAILLE = EE_TAG( 'B', 'r', 'a', 'i' ), /*3.0*/ - CANADIAN_SYLLABICS = EE_TAG( 'C', 'a', 'n', 's' ), /*3.0*/ - CHEROKEE = EE_TAG( 'C', 'h', 'e', 'r' ), /*3.0*/ - ETHIOPIC = EE_TAG( 'E', 't', 'h', 'i' ), /*3.0*/ - KHMER = EE_TAG( 'K', 'h', 'm', 'r' ), /*3.0*/ - MONGOLIAN = EE_TAG( 'M', 'o', 'n', 'g' ), /*3.0*/ - MYANMAR = EE_TAG( 'M', 'y', 'm', 'r' ), /*3.0*/ - OGHAM = EE_TAG( 'O', 'g', 'a', 'm' ), /*3.0*/ - RUNIC = EE_TAG( 'R', 'u', 'n', 'r' ), /*3.0*/ - SINHALA = EE_TAG( 'S', 'i', 'n', 'h' ), /*3.0*/ - SYRIAC = EE_TAG( 'S', 'y', 'r', 'c' ), /*3.0*/ - THAANA = EE_TAG( 'T', 'h', 'a', 'a' ), /*3.0*/ - YI = EE_TAG( 'Y', 'i', 'i', 'i' ), /*3.0*/ - - DESERET = EE_TAG( 'D', 's', 'r', 't' ), /*3.1*/ - GOTHIC = EE_TAG( 'G', 'o', 't', 'h' ), /*3.1*/ - OLD_ITALIC = EE_TAG( 'I', 't', 'a', 'l' ), /*3.1*/ - - BUHID = EE_TAG( 'B', 'u', 'h', 'd' ), /*3.2*/ - HANUNOO = EE_TAG( 'H', 'a', 'n', 'o' ), /*3.2*/ - TAGALOG = EE_TAG( 'T', 'g', 'l', 'g' ), /*3.2*/ - TAGBANWA = EE_TAG( 'T', 'a', 'g', 'b' ), /*3.2*/ - - CYPRIOT = EE_TAG( 'C', 'p', 'r', 't' ), /*4.0*/ - LIMBU = EE_TAG( 'L', 'i', 'm', 'b' ), /*4.0*/ - LINEAR_B = EE_TAG( 'L', 'i', 'n', 'b' ), /*4.0*/ - OSMANYA = EE_TAG( 'O', 's', 'm', 'a' ), /*4.0*/ - SHAVIAN = EE_TAG( 'S', 'h', 'a', 'w' ), /*4.0*/ - TAI_LE = EE_TAG( 'T', 'a', 'l', 'e' ), /*4.0*/ - UGARITIC = EE_TAG( 'U', 'g', 'a', 'r' ), /*4.0*/ - - BUGINESE = EE_TAG( 'B', 'u', 'g', 'i' ), /*4.1*/ - COPTIC = EE_TAG( 'C', 'o', 'p', 't' ), /*4.1*/ - GLAGOLITIC = EE_TAG( 'G', 'l', 'a', 'g' ), /*4.1*/ - KHAROSHTHI = EE_TAG( 'K', 'h', 'a', 'r' ), /*4.1*/ - NEW_TAI_LUE = EE_TAG( 'T', 'a', 'l', 'u' ), /*4.1*/ - OLD_PERSIAN = EE_TAG( 'X', 'p', 'e', 'o' ), /*4.1*/ - SYLOTI_NAGRI = EE_TAG( 'S', 'y', 'l', 'o' ), /*4.1*/ - TIFINAGH = EE_TAG( 'T', 'f', 'n', 'g' ), /*4.1*/ - - BALINESE = EE_TAG( 'B', 'a', 'l', 'i' ), /*5.0*/ - CUNEIFORM = EE_TAG( 'X', 's', 'u', 'x' ), /*5.0*/ - NKO = EE_TAG( 'N', 'k', 'o', 'o' ), /*5.0*/ - PHAGS_PA = EE_TAG( 'P', 'h', 'a', 'g' ), /*5.0*/ - PHOENICIAN = EE_TAG( 'P', 'h', 'n', 'x' ), /*5.0*/ - - CARIAN = EE_TAG( 'C', 'a', 'r', 'i' ), /*5.1*/ - CHAM = EE_TAG( 'C', 'h', 'a', 'm' ), /*5.1*/ - KAYAH_LI = EE_TAG( 'K', 'a', 'l', 'i' ), /*5.1*/ - LEPCHA = EE_TAG( 'L', 'e', 'p', 'c' ), /*5.1*/ - LYCIAN = EE_TAG( 'L', 'y', 'c', 'i' ), /*5.1*/ - LYDIAN = EE_TAG( 'L', 'y', 'd', 'i' ), /*5.1*/ - OL_CHIKI = EE_TAG( 'O', 'l', 'c', 'k' ), /*5.1*/ - REJANG = EE_TAG( 'R', 'j', 'n', 'g' ), /*5.1*/ - SAURASHTRA = EE_TAG( 'S', 'a', 'u', 'r' ), /*5.1*/ - SUNDANESE = EE_TAG( 'S', 'u', 'n', 'd' ), /*5.1*/ - VAI = EE_TAG( 'V', 'a', 'i', 'i' ), /*5.1*/ - - AVESTAN = EE_TAG( 'A', 'v', 's', 't' ), /*5.2*/ - BAMUM = EE_TAG( 'B', 'a', 'm', 'u' ), /*5.2*/ - EGYPTIAN_HIEROGLYPHS = EE_TAG( 'E', 'g', 'y', 'p' ), /*5.2*/ - IMPERIAL_ARAMAIC = EE_TAG( 'A', 'r', 'm', 'i' ), /*5.2*/ - INSCRIPTIONAL_PAHLAVI = EE_TAG( 'P', 'h', 'l', 'i' ), /*5.2*/ - INSCRIPTIONAL_PARTHIAN = EE_TAG( 'P', 'r', 't', 'i' ), /*5.2*/ - JAVANESE = EE_TAG( 'J', 'a', 'v', 'a' ), /*5.2*/ - KAITHI = EE_TAG( 'K', 't', 'h', 'i' ), /*5.2*/ - LISU = EE_TAG( 'L', 'i', 's', 'u' ), /*5.2*/ - MEETEI_MAYEK = EE_TAG( 'M', 't', 'e', 'i' ), /*5.2*/ - OLD_SOUTH_ARABIAN = EE_TAG( 'S', 'a', 'r', 'b' ), /*5.2*/ - OLD_TURKIC = EE_TAG( 'O', 'r', 'k', 'h' ), /*5.2*/ - SAMARITAN = EE_TAG( 'S', 'a', 'm', 'r' ), /*5.2*/ - TAI_THAM = EE_TAG( 'L', 'a', 'n', 'a' ), /*5.2*/ - TAI_VIET = EE_TAG( 'T', 'a', 'v', 't' ), /*5.2*/ - - BATAK = EE_TAG( 'B', 'a', 't', 'k' ), /*6.0*/ - BRAHMI = EE_TAG( 'B', 'r', 'a', 'h' ), /*6.0*/ - MANDAIC = EE_TAG( 'M', 'a', 'n', 'd' ), /*6.0*/ - - CHAKMA = EE_TAG( 'C', 'a', 'k', 'm' ), /*6.1*/ - MEROITIC_CURSIVE = EE_TAG( 'M', 'e', 'r', 'c' ), /*6.1*/ - MEROITIC_HIEROGLYPHS = EE_TAG( 'M', 'e', 'r', 'o' ), /*6.1*/ - MIAO = EE_TAG( 'P', 'l', 'r', 'd' ), /*6.1*/ - SHARADA = EE_TAG( 'S', 'h', 'r', 'd' ), /*6.1*/ - SORA_SOMPENG = EE_TAG( 'S', 'o', 'r', 'a' ), /*6.1*/ - TAKRI = EE_TAG( 'T', 'a', 'k', 'r' ), /*6.1*/ - - /* - * Since: 0.9.30 - */ - BASSA_VAH = EE_TAG( 'B', 'a', 's', 's' ), /*7.0*/ - CAUCASIAN_ALBANIAN = EE_TAG( 'A', 'g', 'h', 'b' ), /*7.0*/ - DUPLOYAN = EE_TAG( 'D', 'u', 'p', 'l' ), /*7.0*/ - ELBASAN = EE_TAG( 'E', 'l', 'b', 'a' ), /*7.0*/ - GRANTHA = EE_TAG( 'G', 'r', 'a', 'n' ), /*7.0*/ - KHOJKI = EE_TAG( 'K', 'h', 'o', 'j' ), /*7.0*/ - KHUDAWADI = EE_TAG( 'S', 'i', 'n', 'd' ), /*7.0*/ - LINEAR_A = EE_TAG( 'L', 'i', 'n', 'a' ), /*7.0*/ - MAHAJANI = EE_TAG( 'M', 'a', 'h', 'j' ), /*7.0*/ - MANICHAEAN = EE_TAG( 'M', 'a', 'n', 'i' ), /*7.0*/ - MENDE_KIKAKUI = EE_TAG( 'M', 'e', 'n', 'd' ), /*7.0*/ - MODI = EE_TAG( 'M', 'o', 'd', 'i' ), /*7.0*/ - MRO = EE_TAG( 'M', 'r', 'o', 'o' ), /*7.0*/ - NABATAEAN = EE_TAG( 'N', 'b', 'a', 't' ), /*7.0*/ - OLD_NORTH_ARABIAN = EE_TAG( 'N', 'a', 'r', 'b' ), /*7.0*/ - OLD_PERMIC = EE_TAG( 'P', 'e', 'r', 'm' ), /*7.0*/ - PAHAWH_HMONG = EE_TAG( 'H', 'm', 'n', 'g' ), /*7.0*/ - PALMYRENE = EE_TAG( 'P', 'a', 'l', 'm' ), /*7.0*/ - PAU_CIN_HAU = EE_TAG( 'P', 'a', 'u', 'c' ), /*7.0*/ - PSALTER_PAHLAVI = EE_TAG( 'P', 'h', 'l', 'p' ), /*7.0*/ - SIDDHAM = EE_TAG( 'S', 'i', 'd', 'd' ), /*7.0*/ - TIRHUTA = EE_TAG( 'T', 'i', 'r', 'h' ), /*7.0*/ - WARANG_CITI = EE_TAG( 'W', 'a', 'r', 'a' ), /*7.0*/ - - AHOM = EE_TAG( 'A', 'h', 'o', 'm' ), /*8.0*/ - ANATOLIAN_HIEROGLYPHS = EE_TAG( 'H', 'l', 'u', 'w' ), /*8.0*/ - HATRAN = EE_TAG( 'H', 'a', 't', 'r' ), /*8.0*/ - MULTANI = EE_TAG( 'M', 'u', 'l', 't' ), /*8.0*/ - OLD_HUNGARIAN = EE_TAG( 'H', 'u', 'n', 'g' ), /*8.0*/ - SIGNWRITING = EE_TAG( 'S', 'g', 'n', 'w' ), /*8.0*/ - - /* - * Since 1.3.0 - */ - ADLAM = EE_TAG( 'A', 'd', 'l', 'm' ), /*9.0*/ - BHAIKSUKI = EE_TAG( 'B', 'h', 'k', 's' ), /*9.0*/ - MARCHEN = EE_TAG( 'M', 'a', 'r', 'c' ), /*9.0*/ - OSAGE = EE_TAG( 'O', 's', 'g', 'e' ), /*9.0*/ - TANGUT = EE_TAG( 'T', 'a', 'n', 'g' ), /*9.0*/ - NEWA = EE_TAG( 'N', 'e', 'w', 'a' ), /*9.0*/ - - /* - * Since 1.6.0 - */ - MASARAM_GONDI = EE_TAG( 'G', 'o', 'n', 'm' ), /*10.0*/ - NUSHU = EE_TAG( 'N', 's', 'h', 'u' ), /*10.0*/ - SOYOMBO = EE_TAG( 'S', 'o', 'y', 'o' ), /*10.0*/ - ZANABAZAR_SQUARE = EE_TAG( 'Z', 'a', 'n', 'b' ), /*10.0*/ - - /* - * Since 1.8.0 - */ - DOGRA = EE_TAG( 'D', 'o', 'g', 'r' ), /*11.0*/ - GUNJALA_GONDI = EE_TAG( 'G', 'o', 'n', 'g' ), /*11.0*/ - HANIFI_ROHINGYA = EE_TAG( 'R', 'o', 'h', 'g' ), /*11.0*/ - MAKASAR = EE_TAG( 'M', 'a', 'k', 'a' ), /*11.0*/ - MEDEFAIDRIN = EE_TAG( 'M', 'e', 'd', 'f' ), /*11.0*/ - OLD_SOGDIAN = EE_TAG( 'S', 'o', 'g', 'o' ), /*11.0*/ - SOGDIAN = EE_TAG( 'S', 'o', 'g', 'd' ), /*11.0*/ - - /* - * Since 2.4.0 - */ - ELYMAIC = EE_TAG( 'E', 'l', 'y', 'm' ), /*12.0*/ - NANDINAGARI = EE_TAG( 'N', 'a', 'n', 'd' ), /*12.0*/ - NYIAKENG_PUACHUE_HMONG = EE_TAG( 'H', 'm', 'n', 'p' ), /*12.0*/ - WANCHO = EE_TAG( 'W', 'c', 'h', 'o' ), /*12.0*/ - - /* - * Since 2.6.7 - */ - CHORASMIAN = EE_TAG( 'C', 'h', 'r', 's' ), /*13.0*/ - DIVES_AKURU = EE_TAG( 'D', 'i', 'a', 'k' ), /*13.0*/ - KHITAN_SMALL_SCRIPT = EE_TAG( 'K', 'i', 't', 's' ), /*13.0*/ - YEZIDI = EE_TAG( 'Y', 'e', 'z', 'i' ), /*13.0*/ - - /* - * Since 3.0.0 - */ - CYPRO_MINOAN = EE_TAG( 'C', 'p', 'm', 'n' ), /*14.0*/ - OLD_UYGHUR = EE_TAG( 'O', 'u', 'g', 'r' ), /*14.0*/ - TANGSA = EE_TAG( 'T', 'n', 's', 'a' ), /*14.0*/ - TOTO = EE_TAG( 'T', 'o', 't', 'o' ), /*14.0*/ - VITHKUQI = EE_TAG( 'V', 'i', 't', 'h' ), /*14.0*/ - - /* - * Since 3.4.0 - */ + COMMON = EE_TAG( 'Z', 'y', 'y', 'y' ), + INHERITED = EE_TAG( 'Z', 'i', 'n', 'h' ), + UNKNOWN = EE_TAG( 'Z', 'z', 'z', 'z' ), + ARABIC = EE_TAG( 'A', 'r', 'a', 'b' ), + ARMENIAN = EE_TAG( 'A', 'r', 'm', 'n' ), + BENGALI = EE_TAG( 'B', 'e', 'n', 'g' ), + CYRILLIC = EE_TAG( 'C', 'y', 'r', 'l' ), + DEVANAGARI = EE_TAG( 'D', 'e', 'v', 'a' ), + GEORGIAN = EE_TAG( 'G', 'e', 'o', 'r' ), + GREEK = EE_TAG( 'G', 'r', 'e', 'k' ), + GUJARATI = EE_TAG( 'G', 'u', 'j', 'r' ), + GURMUKHI = EE_TAG( 'G', 'u', 'r', 'u' ), + HANGUL = EE_TAG( 'H', 'a', 'n', 'g' ), + HAN = EE_TAG( 'H', 'a', 'n', 'i' ), + HEBREW = EE_TAG( 'H', 'e', 'b', 'r' ), + HIRAGANA = EE_TAG( 'H', 'i', 'r', 'a' ), + KANNADA = EE_TAG( 'K', 'n', 'd', 'a' ), + KATAKANA = EE_TAG( 'K', 'a', 'n', 'a' ), + LAO = EE_TAG( 'L', 'a', 'o', 'o' ), + LATIN = EE_TAG( 'L', 'a', 't', 'n' ), + MALAYALAM = EE_TAG( 'M', 'l', 'y', 'm' ), + ORIYA = EE_TAG( 'O', 'r', 'y', 'a' ), + TAMIL = EE_TAG( 'T', 'a', 'm', 'l' ), + TELUGU = EE_TAG( 'T', 'e', 'l', 'u' ), + THAI = EE_TAG( 'T', 'h', 'a', 'i' ), + TIBETAN = EE_TAG( 'T', 'i', 'b', 't' ), + BOPOMOFO = EE_TAG( 'B', 'o', 'p', 'o' ), + BRAILLE = EE_TAG( 'B', 'r', 'a', 'i' ), + CANADIAN_SYLLABICS = EE_TAG( 'C', 'a', 'n', 's' ), + CHEROKEE = EE_TAG( 'C', 'h', 'e', 'r' ), + ETHIOPIC = EE_TAG( 'E', 't', 'h', 'i' ), + KHMER = EE_TAG( 'K', 'h', 'm', 'r' ), + MONGOLIAN = EE_TAG( 'M', 'o', 'n', 'g' ), + MYANMAR = EE_TAG( 'M', 'y', 'm', 'r' ), + OGHAM = EE_TAG( 'O', 'g', 'a', 'm' ), + RUNIC = EE_TAG( 'R', 'u', 'n', 'r' ), + SINHALA = EE_TAG( 'S', 'i', 'n', 'h' ), + SYRIAC = EE_TAG( 'S', 'y', 'r', 'c' ), + THAANA = EE_TAG( 'T', 'h', 'a', 'a' ), + YI = EE_TAG( 'Y', 'i', 'i', 'i' ), + DESERET = EE_TAG( 'D', 's', 'r', 't' ), + GOTHIC = EE_TAG( 'G', 'o', 't', 'h' ), + OLD_ITALIC = EE_TAG( 'I', 't', 'a', 'l' ), + BUHID = EE_TAG( 'B', 'u', 'h', 'd' ), + HANUNOO = EE_TAG( 'H', 'a', 'n', 'o' ), + TAGALOG = EE_TAG( 'T', 'g', 'l', 'g' ), + TAGBANWA = EE_TAG( 'T', 'a', 'g', 'b' ), + CYPRIOT = EE_TAG( 'C', 'p', 'r', 't' ), + LIMBU = EE_TAG( 'L', 'i', 'm', 'b' ), + LINEAR_B = EE_TAG( 'L', 'i', 'n', 'b' ), + OSMANYA = EE_TAG( 'O', 's', 'm', 'a' ), + SHAVIAN = EE_TAG( 'S', 'h', 'a', 'w' ), + TAI_LE = EE_TAG( 'T', 'a', 'l', 'e' ), + UGARITIC = EE_TAG( 'U', 'g', 'a', 'r' ), + BUGINESE = EE_TAG( 'B', 'u', 'g', 'i' ), + COPTIC = EE_TAG( 'C', 'o', 'p', 't' ), + GLAGOLITIC = EE_TAG( 'G', 'l', 'a', 'g' ), + KHAROSHTHI = EE_TAG( 'K', 'h', 'a', 'r' ), + NEW_TAI_LUE = EE_TAG( 'T', 'a', 'l', 'u' ), + OLD_PERSIAN = EE_TAG( 'X', 'p', 'e', 'o' ), + SYLOTI_NAGRI = EE_TAG( 'S', 'y', 'l', 'o' ), + TIFINAGH = EE_TAG( 'T', 'f', 'n', 'g' ), + BALINESE = EE_TAG( 'B', 'a', 'l', 'i' ), + CUNEIFORM = EE_TAG( 'X', 's', 'u', 'x' ), + NKO = EE_TAG( 'N', 'k', 'o', 'o' ), + PHAGS_PA = EE_TAG( 'P', 'h', 'a', 'g' ), + PHOENICIAN = EE_TAG( 'P', 'h', 'n', 'x' ), + CARIAN = EE_TAG( 'C', 'a', 'r', 'i' ), + CHAM = EE_TAG( 'C', 'h', 'a', 'm' ), + KAYAH_LI = EE_TAG( 'K', 'a', 'l', 'i' ), + LEPCHA = EE_TAG( 'L', 'e', 'p', 'c' ), + LYCIAN = EE_TAG( 'L', 'y', 'c', 'i' ), + LYDIAN = EE_TAG( 'L', 'y', 'd', 'i' ), + OL_CHIKI = EE_TAG( 'O', 'l', 'c', 'k' ), + REJANG = EE_TAG( 'R', 'j', 'n', 'g' ), + SAURASHTRA = EE_TAG( 'S', 'a', 'u', 'r' ), + SUNDANESE = EE_TAG( 'S', 'u', 'n', 'd' ), + VAI = EE_TAG( 'V', 'a', 'i', 'i' ), + AVESTAN = EE_TAG( 'A', 'v', 's', 't' ), + BAMUM = EE_TAG( 'B', 'a', 'm', 'u' ), + EGYPTIAN_HIEROGLYPHS = EE_TAG( 'E', 'g', 'y', 'p' ), + IMPERIAL_ARAMAIC = EE_TAG( 'A', 'r', 'm', 'i' ), + INSCRIPTIONAL_PAHLAVI = EE_TAG( 'P', 'h', 'l', 'i' ), + INSCRIPTIONAL_PARTHIAN = EE_TAG( 'P', 'r', 't', 'i' ), + JAVANESE = EE_TAG( 'J', 'a', 'v', 'a' ), + KAITHI = EE_TAG( 'K', 't', 'h', 'i' ), + LISU = EE_TAG( 'L', 'i', 's', 'u' ), + MEETEI_MAYEK = EE_TAG( 'M', 't', 'e', 'i' ), + OLD_SOUTH_ARABIAN = EE_TAG( 'S', 'a', 'r', 'b' ), + OLD_TURKIC = EE_TAG( 'O', 'r', 'k', 'h' ), + SAMARITAN = EE_TAG( 'S', 'a', 'm', 'r' ), + TAI_THAM = EE_TAG( 'L', 'a', 'n', 'a' ), + TAI_VIET = EE_TAG( 'T', 'a', 'v', 't' ), + BATAK = EE_TAG( 'B', 'a', 't', 'k' ), + BRAHMI = EE_TAG( 'B', 'r', 'a', 'h' ), + MANDAIC = EE_TAG( 'M', 'a', 'n', 'd' ), + CHAKMA = EE_TAG( 'C', 'a', 'k', 'm' ), + MEROITIC_CURSIVE = EE_TAG( 'M', 'e', 'r', 'c' ), + MEROITIC_HIEROGLYPHS = EE_TAG( 'M', 'e', 'r', 'o' ), + MIAO = EE_TAG( 'P', 'l', 'r', 'd' ), + SHARADA = EE_TAG( 'S', 'h', 'r', 'd' ), + SORA_SOMPENG = EE_TAG( 'S', 'o', 'r', 'a' ), + TAKRI = EE_TAG( 'T', 'a', 'k', 'r' ), + BASSA_VAH = EE_TAG( 'B', 'a', 's', 's' ), + CAUCASIAN_ALBANIAN = EE_TAG( 'A', 'g', 'h', 'b' ), + DUPLOYAN = EE_TAG( 'D', 'u', 'p', 'l' ), + ELBASAN = EE_TAG( 'E', 'l', 'b', 'a' ), + GRANTHA = EE_TAG( 'G', 'r', 'a', 'n' ), + KHOJKI = EE_TAG( 'K', 'h', 'o', 'j' ), + KHUDAWADI = EE_TAG( 'S', 'i', 'n', 'd' ), + LINEAR_A = EE_TAG( 'L', 'i', 'n', 'a' ), + MAHAJANI = EE_TAG( 'M', 'a', 'h', 'j' ), + MANICHAEAN = EE_TAG( 'M', 'a', 'n', 'i' ), + MENDE_KIKAKUI = EE_TAG( 'M', 'e', 'n', 'd' ), + MODI = EE_TAG( 'M', 'o', 'd', 'i' ), + MRO = EE_TAG( 'M', 'r', 'o', 'o' ), + NABATAEAN = EE_TAG( 'N', 'b', 'a', 't' ), + OLD_NORTH_ARABIAN = EE_TAG( 'N', 'a', 'r', 'b' ), + OLD_PERMIC = EE_TAG( 'P', 'e', 'r', 'm' ), + PAHAWH_HMONG = EE_TAG( 'H', 'm', 'n', 'g' ), + PALMYRENE = EE_TAG( 'P', 'a', 'l', 'm' ), + PAU_CIN_HAU = EE_TAG( 'P', 'a', 'u', 'c' ), + PSALTER_PAHLAVI = EE_TAG( 'P', 'h', 'l', 'p' ), + SIDDHAM = EE_TAG( 'S', 'i', 'd', 'd' ), + TIRHUTA = EE_TAG( 'T', 'i', 'r', 'h' ), + WARANG_CITI = EE_TAG( 'W', 'a', 'r', 'a' ), + AHOM = EE_TAG( 'A', 'h', 'o', 'm' ), + ANATOLIAN_HIEROGLYPHS = EE_TAG( 'H', 'l', 'u', 'w' ), + HATRAN = EE_TAG( 'H', 'a', 't', 'r' ), + MULTANI = EE_TAG( 'M', 'u', 'l', 't' ), + OLD_HUNGARIAN = EE_TAG( 'H', 'u', 'n', 'g' ), + SIGNWRITING = EE_TAG( 'S', 'g', 'n', 'w' ), + ADLAM = EE_TAG( 'A', 'd', 'l', 'm' ), + BHAIKSUKI = EE_TAG( 'B', 'h', 'k', 's' ), + MARCHEN = EE_TAG( 'M', 'a', 'r', 'c' ), + OSAGE = EE_TAG( 'O', 's', 'g', 'e' ), + TANGUT = EE_TAG( 'T', 'a', 'n', 'g' ), + NEWA = EE_TAG( 'N', 'e', 'w', 'a' ), + MASARAM_GONDI = EE_TAG( 'G', 'o', 'n', 'm' ), + NUSHU = EE_TAG( 'N', 's', 'h', 'u' ), + SOYOMBO = EE_TAG( 'S', 'o', 'y', 'o' ), + ZANABAZAR_SQUARE = EE_TAG( 'Z', 'a', 'n', 'b' ), + DOGRA = EE_TAG( 'D', 'o', 'g', 'r' ), + GUNJALA_GONDI = EE_TAG( 'G', 'o', 'n', 'g' ), + HANIFI_ROHINGYA = EE_TAG( 'R', 'o', 'h', 'g' ), + MAKASAR = EE_TAG( 'M', 'a', 'k', 'a' ), + MEDEFAIDRIN = EE_TAG( 'M', 'e', 'd', 'f' ), + OLD_SOGDIAN = EE_TAG( 'S', 'o', 'g', 'o' ), + SOGDIAN = EE_TAG( 'S', 'o', 'g', 'd' ), + ELYMAIC = EE_TAG( 'E', 'l', 'y', 'm' ), + NANDINAGARI = EE_TAG( 'N', 'a', 'n', 'd' ), + NYIAKENG_PUACHUE_HMONG = EE_TAG( 'H', 'm', 'n', 'p' ), + WANCHO = EE_TAG( 'W', 'c', 'h', 'o' ), + CHORASMIAN = EE_TAG( 'C', 'h', 'r', 's' ), + DIVES_AKURU = EE_TAG( 'D', 'i', 'a', 'k' ), + KHITAN_SMALL_SCRIPT = EE_TAG( 'K', 'i', 't', 's' ), + YEZIDI = EE_TAG( 'Y', 'e', 'z', 'i' ), + CYPRO_MINOAN = EE_TAG( 'C', 'p', 'm', 'n' ), + OLD_UYGHUR = EE_TAG( 'O', 'u', 'g', 'r' ), + TANGSA = EE_TAG( 'T', 'n', 's', 'a' ), + TOTO = EE_TAG( 'T', 'o', 't', 'o' ), + VITHKUQI = EE_TAG( 'V', 'i', 't', 'h' ), MATH = EE_TAG( 'Z', 'm', 't', 'h' ), - - /* - * Since 5.2.0 - */ - KAWI = EE_TAG( 'K', 'a', 'w', 'i' ), /*15.0*/ - NAG_MUNDARI = EE_TAG( 'N', 'a', 'g', 'm' ), /*15.0*/ + KAWI = EE_TAG( 'K', 'a', 'w', 'i' ), + NAG_MUNDARI = EE_TAG( 'N', 'a', 'g', 'm' ), /* No script set. */ INVALID = EE_TAG_NONE, diff --git a/include/eepp/graphics/text.hpp b/include/eepp/graphics/text.hpp index 389d22cc0..1c35c8aaf 100644 --- a/include/eepp/graphics/text.hpp +++ b/include/eepp/graphics/text.hpp @@ -356,9 +356,9 @@ class EE_API Text { Uint32 getVisualLineCount(); /** Callback type for iterating over visual lines. - * Parameters: visual line index, start char index, line width + * Parameters: visual line index, start char index, end char index (exclusive), line width */ - using VisualLineCallback = std::function; + using VisualLineCallback = std::function; /** Iterates over each visual line, calling the callback with line info. * This is useful for selection drawing and other operations that need visual line info. @@ -467,6 +467,21 @@ class EE_API Text { /** Ensures visual line info is up to date. */ void ensureVisualLinesUpdate(); + + static Vector2f findCharacterPos( std::size_t index, Font* font, const Uint32& fontSize, + const String& string, const Uint32& style, + const Uint32& tabWidth, const Float& outlineThickness, + std::optional tabOffset, bool allowNewLine, + Uint32 textHints, TextDirection direction, + LineWrapMode lineWrapMode, Float maxWrapWidth ); + + static Int32 findCharacterFromPos( const Vector2i& pos, bool returnNearest, Font* font, + const Uint32& fontSize, const String& string, + const Uint32& style, const Uint32& tabWidth, + const Float& outlineThickness, + std::optional tabOffset, Uint32 textHints, + TextDirection direction, LineWrapMode lineWrapMode, + Float maxWrapWidth ); }; }} // namespace EE::Graphics diff --git a/src/eepp/graphics/text.cpp b/src/eepp/graphics/text.cpp index adb993a97..888b00263 100644 --- a/src/eepp/graphics/text.cpp +++ b/src/eepp/graphics/text.cpp @@ -761,18 +761,144 @@ Vector2f Text::findCharacterPos( std::size_t index ) const { if ( index > mString.size() ) index = mString.size(); - return Text::findCharacterPos( index, mFontStyleConfig.Font, mFontStyleConfig.CharacterSize, - mString, mFontStyleConfig.Style, mTabWidth, - mFontStyleConfig.OutlineThickness, {}, true, mTextHints ); + if ( mLineWrapMode == LineWrapMode::NoWrap || mMaxWrapWidth <= 0 ) { + return Text::findCharacterPos( index, mFontStyleConfig.Font, mFontStyleConfig.CharacterSize, + mString, mFontStyleConfig.Style, mTabWidth, + mFontStyleConfig.OutlineThickness, {}, true, mTextHints ); + } + +#ifdef EE_TEXT_SHAPER_ENABLED + if ( TextShaperEnabled && mFontStyleConfig.Font->getType() == FontType::TTF && + !canSkipShaping( mTextHints ) ) { + return Text::findCharacterPos( index, mFontStyleConfig.Font, mFontStyleConfig.CharacterSize, + mString, mFontStyleConfig.Style, mTabWidth, + mFontStyleConfig.OutlineThickness, {}, true, mTextHints, + TextDirection::Unspecified, mLineWrapMode, mMaxWrapWidth ); + } +#endif + + const_cast( this )->ensureVisualLinesUpdate(); + + std::size_t visualLinesSize = mVisualLines.size(); + std::size_t lineIndex = const_cast( this )->findVisualLineFromCharIndex( index ); + Float vspace = static_cast( + mFontStyleConfig.Font->getLineSpacing( mFontStyleConfig.CharacterSize ) ); + Float y = lineIndex * vspace; + Float centerDiffX = 0; + + if ( lineIndex < mLinesWidth.size() ) { + switch ( Font::getHorizontalAlign( mAlign ) ) { + case TEXT_ALIGN_CENTER: + centerDiffX = std::trunc( ( mCachedWidth - mLinesWidth[lineIndex] ) * 0.5f ); + break; + case TEXT_ALIGN_RIGHT: + centerDiffX = mCachedWidth - mLinesWidth[lineIndex]; + break; + } + } + + if ( mLineWrapKeepIndentation && lineIndex > 0 ) { + Int64 prevLineStart = mVisualLines[lineIndex]; + if ( prevLineStart > 0 && mString[prevLineStart - 1] != '\n' ) { + centerDiffX += LineWrap::computeOffsets( mString.view(), mFontStyleConfig, mTabWidth, + mMaxWrapWidth, mTabStops ); + } + } + + Int64 startIdx = mVisualLines[lineIndex]; + Int64 endIdx = + ( lineIndex + 1 < visualLinesSize ) ? mVisualLines[lineIndex + 1] : (Int64)mString.size(); + if ( endIdx > (Int64)mString.size() ) + endIdx = mString.size(); + + if ( index < (size_t)startIdx ) + index = startIdx; + + String strWrapper( + String::View( mString.view().data() + startIdx, (std::size_t)( endIdx - startIdx ) ) ); + + Vector2f pos = Text::findCharacterPos( + index - startIdx, mFontStyleConfig.Font, mFontStyleConfig.CharacterSize, strWrapper, + mFontStyleConfig.Style, mTabWidth, mFontStyleConfig.OutlineThickness, {}, true, + mTextHints ); + + return Vector2f( pos.x + centerDiffX, y ); } -Int32 Text::findCharacterFromPos( const Vector2i& pos, bool nearest ) const { +Int32 Text::findCharacterFromPos( const Vector2i& pos, bool returnNearest ) const { if ( NULL == mFontStyleConfig.Font || mString.empty() ) return 0; - return Text::findCharacterFromPos( - pos, nearest, mFontStyleConfig.Font, mFontStyleConfig.CharacterSize, mString, - mFontStyleConfig.Style, mTabWidth, mFontStyleConfig.OutlineThickness ); + if ( mLineWrapMode == LineWrapMode::NoWrap || mMaxWrapWidth <= 0 ) { + return Text::findCharacterFromPos( + pos, returnNearest, mFontStyleConfig.Font, mFontStyleConfig.CharacterSize, mString, + mFontStyleConfig.Style, mTabWidth, mFontStyleConfig.OutlineThickness ); + } + +#ifdef EE_TEXT_SHAPER_ENABLED + if ( TextShaperEnabled && mFontStyleConfig.Font->getType() == FontType::TTF && + !canSkipShaping( mTextHints ) ) { + return Text::findCharacterFromPos( + pos, returnNearest, mFontStyleConfig.Font, mFontStyleConfig.CharacterSize, mString, + mFontStyleConfig.Style, mTabWidth, mFontStyleConfig.OutlineThickness, {}, mTextHints, + TextDirection::Unspecified, mLineWrapMode, mMaxWrapWidth ); + } +#endif + + const_cast( this )->ensureVisualLinesUpdate(); + + Float vspace = mFontStyleConfig.Font->getLineSpacing( mFontStyleConfig.CharacterSize ); + int lineIndex = std::floor( pos.y / vspace ); + std::size_t visualLinesSize = mVisualLines.size(); + + if ( lineIndex < 0 ) + lineIndex = 0; + if ( lineIndex >= (int)visualLinesSize ) { + if ( returnNearest ) + lineIndex = visualLinesSize - 1; + else + return -1; + } + + Float centerDiffX = 0; + + if ( lineIndex < (int)mLinesWidth.size() ) { + switch ( Font::getHorizontalAlign( mAlign ) ) { + case TEXT_ALIGN_CENTER: + centerDiffX = std::trunc( ( mCachedWidth - mLinesWidth[lineIndex] ) * 0.5f ); + break; + case TEXT_ALIGN_RIGHT: + centerDiffX = mCachedWidth - mLinesWidth[lineIndex]; + break; + } + } + + if ( mLineWrapKeepIndentation && lineIndex > 0 ) { + Int64 prevLineStart = mVisualLines[lineIndex]; + if ( prevLineStart > 0 && mString[prevLineStart - 1] != '\n' ) { + centerDiffX += LineWrap::computeOffsets( mString.view(), mFontStyleConfig, mTabWidth, + mMaxWrapWidth, mTabStops ); + } + } + + Int64 startIdx = mVisualLines[lineIndex]; + Int64 endIdx = ( lineIndex + 1 < (int)visualLinesSize ) ? mVisualLines[lineIndex + 1] + : (Int64)mString.size(); + if ( endIdx > (Int64)mString.size() ) + endIdx = mString.size(); + + String strWrapper( + String::View( mString.view().data() + startIdx, (std::size_t)( endIdx - startIdx ) ) ); + Vector2i localPos( pos.x - centerDiffX, 0 ); // Y is treated as 0 in single line + + Int32 foundIndex = Text::findCharacterFromPos( + localPos, returnNearest, mFontStyleConfig.Font, mFontStyleConfig.CharacterSize, strWrapper, + mFontStyleConfig.Style, mTabWidth, mFontStyleConfig.OutlineThickness, {}, mTextHints ); + + if ( foundIndex != -1 ) + return startIdx + foundIndex; + + return -1; } static bool isStopSelChar( Uint32 c ) { @@ -942,6 +1068,16 @@ Vector2f Text::findCharacterPos( std::size_t index, Font* font, const Uint32& fo const Float& outlineThickness, std::optional tabOffset, bool allowNewLine, Uint32 textDrawHints, TextDirection direction ) { + return findCharacterPos( index, font, fontSize, string, style, tabWidth, outlineThickness, + tabOffset, allowNewLine, textDrawHints, direction, + LineWrapMode::NoWrap, 0.f ); +} + +Vector2f Text::findCharacterPos( std::size_t index, Font* font, const Uint32& fontSize, + const String& string, const Uint32& style, const Uint32& tabWidth, + const Float& outlineThickness, std::optional tabOffset, + bool allowNewLine, Uint32 textDrawHints, TextDirection direction, + LineWrapMode lineWrapMode, Float maxWrapWidth ) { // Make sure that we have a valid font if ( !font ) return Vector2f(); @@ -963,8 +1099,22 @@ Vector2f Text::findCharacterPos( std::size_t index, Font* font, const Uint32& fo #ifdef EE_TEXT_SHAPER_ENABLED if ( TextShaperEnabled && font->getType() == FontType::TTF && !canSkipShaping( textDrawHints ) ) { - auto layout = TextLayout::layout( string, font, fontSize, style, tabWidth, outlineThickness, - tabOffset, 0, direction ); + auto layout = + TextLayout::layout( string, font, fontSize, style, tabWidth, outlineThickness, + tabOffset, textDrawHints, direction, lineWrapMode, maxWrapWidth ); + bool hasGlyphs = + allowNewLine + ? !layout->paragraphs.empty() && !layout->paragraphs.back().shapedGlyphs.empty() + : !layout->paragraphs.empty() && !layout->paragraphs.front().shapedGlyphs.empty(); + + if ( index == string.size() && hasGlyphs ) { + return allowNewLine + ? Vector2f{ layout->paragraphs.back().shapedGlyphs.back().position + + layout->paragraphs.back().shapedGlyphs.back().advance } + : Vector2f{ layout->paragraphs.front().shapedGlyphs.back().position + + layout->paragraphs.front().shapedGlyphs.back().advance }; + } + Uint32 maxStringIndex = 0; Uint32 closestDist = std::numeric_limits::max(); @@ -991,8 +1141,7 @@ Vector2f Text::findCharacterPos( std::size_t index, Font* font, const Uint32& fo } } - if ( layout->paragraphs.empty() && !layout->paragraphs.back().shapedGlyphs.empty() && - !layout->isRTL() && index >= maxStringIndex + 1 && msg ) { + if ( hasGlyphs && !layout->isRTL() && index >= maxStringIndex + 1 && msg ) { Glyph metrics = msg->font->getGlyphByIndex( msg->glyphIndex, fontSize, bold, italic, outlineThickness ); if ( string[msg->stringIndex] == '\t' ) { @@ -1059,6 +1208,17 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos, bool returnNearest, Font* const Uint32& tabWidth, const Float& outlineThickness, std::optional tabOffset, Uint32 textDrawHints, TextDirection direction ) { + return findCharacterFromPos( pos, returnNearest, font, fontSize, string, style, tabWidth, + outlineThickness, tabOffset, textDrawHints, direction, + LineWrapMode::NoWrap, 0.f ); +} + +Int32 Text::findCharacterFromPos( const Vector2i& pos, bool returnNearest, Font* font, + const Uint32& fontSize, const String& string, const Uint32& style, + const Uint32& tabWidth, const Float& outlineThickness, + std::optional tabOffset, Uint32 textDrawHints, + TextDirection direction, LineWrapMode lineWrapMode, + Float maxWrapWidth ) { if ( NULL == font ) return 0; @@ -1080,15 +1240,16 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos, bool returnNearest, Font* #ifdef EE_TEXT_SHAPER_ENABLED if ( TextShaperEnabled && font->getType() == FontType::TTF && !canSkipShaping( textDrawHints ) ) { - auto layout = TextLayout::layout( string, font, fontSize, style, tabWidth, outlineThickness, - tabOffset, 0, direction ); + auto layout = + TextLayout::layout( string, font, fontSize, style, tabWidth, outlineThickness, + tabOffset, textDrawHints, direction, lineWrapMode, maxWrapWidth ); - int sgs; + int sgs = 0; if ( pos.x < 0 ) return layout->isRTL() ? tSize : 0; - Float charLeft, charTop, charBottom, charRight; + Float charLeft = 0, charTop = 0, charBottom = 0, charRight = 0; for ( const ShapedTextParagraph& sp : layout->paragraphs ) { sgs = sp.shapedGlyphs.size(); if ( sgs == 0 ) @@ -1100,7 +1261,7 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos, bool returnNearest, Font* charLeft = sg->position.x; charTop = sg->position.y; charBottom = charTop + vspace; - charRight = charLeft + sg->advance.x; + charRight = sg->position.x + sg->advance.x; // Expand bounds over the whole cluster (multiple glyphs for one string index) while ( i + 1 < sgs && sp.shapedGlyphs[i + 1].stringIndex == sg->stringIndex ) { @@ -1139,6 +1300,10 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos, bool returnNearest, Font* } } + if ( i == sgs - 1 && fpos.x > charRight ) { + return tSize; + } + if ( returnNearest ) { Vector2f cellCenter( charLeft + ( charRight - charLeft ) * 0.5f, charTop + vspace * 0.5f ); @@ -2595,9 +2760,10 @@ Uint32 Text::getVisualLineCount() { void Text::forEachVisualLine( const VisualLineCallback& callback ) { ensureVisualLinesUpdate(); for ( size_t i = 0; i < mVisualLines.size(); ++i ) { - const auto& vl = mVisualLines[i]; - const auto& lw = mLinesWidth[i]; - callback( i, vl, lw ); + auto vl = mVisualLines[i]; + auto vle = i + 1 < mVisualLines.size() ? mVisualLines[i + 1] : mString.size(); + auto lw = mLinesWidth[i]; + callback( i, vl, vle, lw ); } } diff --git a/src/tests/unit_tests/fontrendering.cpp b/src/tests/unit_tests/fontrendering.cpp index 6bc9040ae..5d3e7994e 100644 --- a/src/tests/unit_tests/fontrendering.cpp +++ b/src/tests/unit_tests/fontrendering.cpp @@ -1088,3 +1088,52 @@ UTEST( FontRendering, TextHardWrap ) { runTest(); } } + +UTEST( FontRendering, TextSoftWrapPos ) { + const auto runTest = [&]() { + UIApplication app( + WindowSettings( 1024, 768, "eepp - Text Soft Wrap Pos", WindowStyle::Default, + WindowBackend::Default, 32, {}, 1, false, true ), + UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) ); + FileSystem::changeWorkingDirectory( Sys::getProcessPath() ); + + FontTrueType* font = FontTrueType::New( "DejaVuSansMono" ); + font->loadFromFile( "../assets/fonts/DejaVuSansMono.ttf" ); + + Text text; + text.setFont( font ); + text.setFontSize( 20 ); + text.setString( "This is a long string that should wrap when the width is restricted." ); + text.setColor( Color::White ); + text.setLineWrapMode( LineWrapMode::Word ); + text.setMaxWrapWidth( 200.f ); + + Vector2f pos = text.findCharacterPos( 30 ); + EXPECT_GT( pos.y, 0 ); + + Float vspace = text.getFont()->getLineSpacing( text.getCharacterSize() ); + Vector2i queryPos( 10, (int)vspace + 5 ); + Int32 foundIndex = text.findCharacterFromPos( queryPos ); + + EXPECT_GT( foundIndex, 14 ); + + Vector2f foundPos = text.findCharacterPos( foundIndex ); + EXPECT_GT( foundPos.y, 0 ); + }; + + UTEST_PRINT_STEP( "Text Shaper disabled" ); + { + BoolScopedOp op( Text::TextShaperEnabled, false ); + runTest(); + } + + UTEST_PRINT_STEP( "Text Shaper enabled" ); + { + BoolScopedOp op( Text::TextShaperEnabled, true ); + runTest(); + + UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" ); + BoolScopedOp op2( Text::TextShaperOptimizations, false ); + runTest(); + } +} diff --git a/src/tools/ecode/applayout.xml.hpp b/src/tools/ecode/applayout.xml.hpp index edcc64402..676dd775c 100644 --- a/src/tools/ecode/applayout.xml.hpp +++ b/src/tools/ecode/applayout.xml.hpp @@ -84,18 +84,18 @@ StatusBar > #doc_info { #search_replace.error { border-color: #ff4040; } -TableView#locate_bar_table > tableview::row > tableview::cell:nth-child(2) > tableview::cell::text, -TableView#locate_bar_table > tableview::row > tableview::cell:nth-child(3) > tableview::cell::text { +TableView#locate_bar_table > tableview::row > tableview::cell:nth-child(2), +TableView#locate_bar_table > tableview::row > tableview::cell:nth-child(3) { color: var(--font-hint); } -TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child(2) > tableview::cell::text, -TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child(3) > tableview::cell::text { +TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child(2), +TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child(3) { color: var(--list-row-active) } .search_tree treeview::cell { font-family: monospace; } -.search_tree treeview::row:selected treeview::cell::text { +.search_tree treeview::row:selected treeview::cell { color: var(--font); } .search_tree treeview::row:selected treeview::cell::expander { @@ -397,30 +397,30 @@ TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child .custom_output_parser_cont > .capture_positions_cont > * { padding: 2dp; } -.theme-error > tableview::cell::text, -.theme-error > treeview::cell::text, -.theme-error > listview::cell::text, +.theme-error > tableview::cell, +.theme-error > treeview::cell, +.theme-error > listview::cell, .error { color: var(--theme-error); } -.theme-warning > tableview::cell::text, -.theme-warning > treeview::cell::text, -.theme-warning > listview::cell::text, +.theme-warning > tableview::cell, +.theme-warning > treeview::cell, +.theme-warning > listview::cell, .warning { color: var(--theme-warning); } -.theme-success > tableview::cell::text, -.theme-success > treeview::cell::text, -.theme-success > listview::cell::text, +.theme-success > tableview::cell, +.theme-success > treeview::cell, +.theme-success > listview::cell, .success { color: var(--theme-success); } -.theme-none > tableview::cell::text, -.theme-none > treeview::cell::text, -.theme-none > listview::cell::text, +.theme-none > tableview::cell, +.theme-none > treeview::cell, +.theme-none > listview::cell, .none { color: #d48838; } @@ -447,10 +447,8 @@ Anchor.error:hover { #build_output_issues TableView::cell.theme-error > TableView::cell::icon { tint: var(--theme-error); } -#build_output_issues TableView::row:selected TableView::cell.theme-error > TableView::cell::text { +#build_output_issues TableView::row:selected TableView::cell.theme-error > TableView::cell { color: var(--list-row-active); -} -#build_output_issues TableView::row:selected TableView::cell.theme-error > TableView::cell::icon { tint: var(--list-row-active); } .texture-preview { diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index dffd0b0d7..05c54aa36 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -4486,8 +4486,8 @@ void App::init( InitParameters& params ) { } std::string panelUI( String::format( R"css( - #panel treeview > treeview::row > treeview::cell > treeview::cell::text, - #panel treeview > treeview::row > table::cell > table::cell::text { + #panel treeview > treeview::row > treeview::cell, + #panel treeview > treeview::row > table::cell { font-size: %s; } )css", diff --git a/src/tools/ecode/plugins/git/gitplugin.cpp b/src/tools/ecode/plugins/git/gitplugin.cpp index ca7e47419..3d49740fc 100644 --- a/src/tools/ecode/plugins/git/gitplugin.cpp +++ b/src/tools/ecode/plugins/git/gitplugin.cpp @@ -1444,11 +1444,11 @@ void GitPlugin::buildSidePanelTab() { #git_status_tree ScrollBar:focus-within { opacity: 1; } - .git_highlight_style > treeview::cell::text { + .git_highlight_style > treeview::cell { color: %s; } - treeview::row:selected .git_highlight_style > treeview::cell::text, - treeview::row:selected .git_highlight_style > treeview::cell::text { + treeview::row:selected .git_highlight_style > treeview::cell, + treeview::row:selected .git_highlight_style > treeview::cell { color: var(--list-row-active); tint: var(--list-row-active); } diff --git a/src/tools/ecode/settingsactions.cpp b/src/tools/ecode/settingsactions.cpp index 71ba55d9c..378717d8f 100644 --- a/src/tools/ecode/settingsactions.cpp +++ b/src/tools/ecode/settingsactions.cpp @@ -380,7 +380,7 @@ void SettingsActions::setUIPanelFontSize() { // Update the CSS auto selsFound = mApp->getUISceneNode()->getStyleSheet().findStyleFromSelectorName( - "#project_view > treeview::row > treeview::cell > treeview::cell::text" ); + "#project_view > treeview::row > treeview::cell" ); if ( !selsFound.empty() ) { for ( auto sel : selsFound ) sel->updatePropertyValue( "font-size",