From 64b27db2ff88a420c7f914fec837091e1260b4c4 Mon Sep 17 00:00:00 2001 From: DanS Date: Fri, 17 Jul 2026 08:06:37 -0500 Subject: [PATCH] feat(chat): emoji picker as an in-pane overlay with keyword search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reworked the emoji picker from a floating popup (which overlapped the message area) into an overlay that takes over the conversation-list pane while open: a Cancel button + a keyword search box at the top, then a responsive grid below that wraps to the pane width. Each emoji now carries search keywords (grin/heart/fire/โ€ฆ) so the search box filters the ~150-emoji set. The ๐Ÿ™‚ composer button toggles the overlay; selecting an emoji appends it to the composer (byte-cap respected) and the overlay stays open for multiple picks. +1 CJK glyph (็ตต) for the ja "Search emoji" string. Co-Authored-By: Claude Opus 4.8 (1M context) --- res/fonts/NotoSansCJK-Subset.ttf | Bin 638384 -> 639240 bytes res/lang/de.json | 1 + res/lang/es.json | 1 + res/lang/fr.json | 1 + res/lang/ja.json | 1 + res/lang/ko.json | 1 + res/lang/pt.json | 1 + res/lang/ru.json | 1 + res/lang/zh.json | 1 + src/ui/windows/chat_tab.cpp | 106 +++++++++++++++++++++---------- src/util/i18n.cpp | 1 + 11 files changed, 82 insertions(+), 33 deletions(-) diff --git a/res/fonts/NotoSansCJK-Subset.ttf b/res/fonts/NotoSansCJK-Subset.ttf index 043abbbf8bc07b9e1f648f8f61a7452be62001b8..3a521b7cb52b819b064438d7c413f8c5c2a19b2a 100644 GIT binary patch delta 15278 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 delta 14604 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 diff --git a/res/lang/de.json b/res/lang/de.json index c3d4c10..9189287 100644 --- a/res/lang/de.json +++ b/res/lang/de.json @@ -139,6 +139,7 @@ "chat_cancel": "Abbrechen", "chat_contact_added": "Kontakt hinzugefรผgt โ€“ benenne ihn in Kontakte um", "chat_contact_request": "kontaktanfrage", + "chat_emoji_search": "Emoji suchen", "chat_empty_hint": "Noch keine Unterhaltungen. Nachrichten, die du erhรคltst, erscheinen hier.", "chat_empty_start": "Starte eine mit \"Neue Unterhaltung\".", "chat_empty_title": "Noch keine Unterhaltungen", diff --git a/res/lang/es.json b/res/lang/es.json index 187caea..a2020a4 100644 --- a/res/lang/es.json +++ b/res/lang/es.json @@ -139,6 +139,7 @@ "chat_cancel": "Cancelar", "chat_contact_added": "Contacto aรฑadido: renรณmbralo en Contactos", "chat_contact_request": "solicitud de contacto", + "chat_emoji_search": "Buscar emoji", "chat_empty_hint": "Aรบn no hay conversaciones. Los mensajes que recibas aparecerรกn aquรญ.", "chat_empty_start": "Inicia una con \"Nueva conversaciรณn\".", "chat_empty_title": "Aรบn no hay conversaciones", diff --git a/res/lang/fr.json b/res/lang/fr.json index 91c93c3..fba109d 100644 --- a/res/lang/fr.json +++ b/res/lang/fr.json @@ -139,6 +139,7 @@ "chat_cancel": "Annuler", "chat_contact_added": "Contact ajoutรฉ โ€” renommez-le dans Contacts", "chat_contact_request": "demande de contact", + "chat_emoji_search": "Rechercher un emoji", "chat_empty_hint": "Aucune conversation pour l'instant. Les messages que vous recevez apparaรฎtront ici.", "chat_empty_start": "Commencez-en une avec ยซ Nouvelle conversation ยป.", "chat_empty_title": "Aucune conversation pour l'instant", diff --git a/res/lang/ja.json b/res/lang/ja.json index 7852fcf..f64da30 100644 --- a/res/lang/ja.json +++ b/res/lang/ja.json @@ -139,6 +139,7 @@ "chat_cancel": "ใ‚ญใƒฃใƒณใ‚ปใƒซ", "chat_contact_added": "้€ฃ็ตกๅ…ˆใ‚’่ฟฝๅŠ ใ—ใพใ—ใŸ โ€” ้€ฃ็ตกๅ…ˆใงๅๅ‰ใ‚’ๅค‰ๆ›ดใงใใพใ™", "chat_contact_request": "้€ฃ็ตกใƒชใ‚ฏใ‚จใ‚นใƒˆ", + "chat_emoji_search": "็ตตๆ–‡ๅญ—ใ‚’ๆคœ็ดข", "chat_empty_hint": "ใพใ ไผš่ฉฑใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚ๅ—ไฟกใ—ใŸใƒกใƒƒใ‚ปใƒผใ‚ธใฏใ“ใ“ใซ่กจ็คบใ•ใ‚Œใพใ™ใ€‚", "chat_empty_start": "ใ€Œๆ–ฐใ—ใ„ไผš่ฉฑใ€ใ‹ใ‚‰ๅง‹ใ‚ใพใ—ใ‚‡ใ†ใ€‚", "chat_empty_title": "ไผš่ฉฑใฏใพใ ใ‚ใ‚Šใพใ›ใ‚“", diff --git a/res/lang/ko.json b/res/lang/ko.json index dd90b73..469c616 100644 --- a/res/lang/ko.json +++ b/res/lang/ko.json @@ -139,6 +139,7 @@ "chat_cancel": "์ทจ์†Œ", "chat_contact_added": "์—ฐ๋ฝ์ฒ˜ ์ถ”๊ฐ€๋จ โ€” ์—ฐ๋ฝ์ฒ˜์—์„œ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•˜์„ธ์š”", "chat_contact_request": "์—ฐ๋ฝ ์š”์ฒญ", + "chat_emoji_search": "์ด๋ชจ์ง€ ๊ฒ€์ƒ‰", "chat_empty_hint": "์•„์ง ๋Œ€ํ™”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋ฐ›์€ ๋ฉ”์‹œ์ง€๊ฐ€ ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.", "chat_empty_start": "\"์ƒˆ ๋Œ€ํ™”\"๋กœ ์‹œ์ž‘ํ•˜์„ธ์š”.", "chat_empty_title": "์•„์ง ๋Œ€ํ™”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค", diff --git a/res/lang/pt.json b/res/lang/pt.json index 85c2d46..665891c 100644 --- a/res/lang/pt.json +++ b/res/lang/pt.json @@ -139,6 +139,7 @@ "chat_cancel": "Cancelar", "chat_contact_added": "Contato adicionado โ€” renomeie em Contatos", "chat_contact_request": "solicitaรงรฃo de contato", + "chat_emoji_search": "Pesquisar emoji", "chat_empty_hint": "Nenhuma conversa ainda. As mensagens que vocรช receber aparecerรฃo aqui.", "chat_empty_start": "Inicie uma com \"Nova conversa\".", "chat_empty_title": "Ainda nรฃo hรก conversas", diff --git a/res/lang/ru.json b/res/lang/ru.json index 177be48..98afaed 100644 --- a/res/lang/ru.json +++ b/res/lang/ru.json @@ -139,6 +139,7 @@ "chat_cancel": "ะžั‚ะผะตะฝะฐ", "chat_contact_added": "ะšะพะฝั‚ะฐะบั‚ ะดะพะฑะฐะฒะปะตะฝ โ€” ะฟะตั€ะตะธะผะตะฝัƒะนั‚ะต ะตะณะพ ะฒ ะšะพะฝั‚ะฐะบั‚ะฐั…", "chat_contact_request": "ะทะฐะฟั€ะพั ะบะพะฝั‚ะฐะบั‚ะฐ", + "chat_emoji_search": "ะŸะพะธัะบ ัะผะพะดะทะธ", "chat_empty_hint": "ะŸะพะบะฐ ะฝะตั‚ ะฟะตั€ะตะฟะธัะพะบ. ะŸะพะปัƒั‡ะตะฝะฝั‹ะต ัะพะพะฑั‰ะตะฝะธั ะฟะพัะฒัั‚ัั ะทะดะตััŒ.", "chat_empty_start": "ะะฐั‡ะฝะธั‚ะต ะฝะพะฒั‹ะน ั ะฟะพะผะพั‰ัŒัŽ ยซะะพะฒั‹ะน ั€ะฐะทะณะพะฒะพั€ยป.", "chat_empty_title": "ะŸะพะบะฐ ะฝะตั‚ ั€ะฐะทะณะพะฒะพั€ะพะฒ", diff --git a/res/lang/zh.json b/res/lang/zh.json index bf6b509..b9acf67 100644 --- a/res/lang/zh.json +++ b/res/lang/zh.json @@ -139,6 +139,7 @@ "chat_cancel": "ๅ–ๆถˆ", "chat_contact_added": "ๅทฒๆทปๅŠ ่”็ณปไบบโ€”โ€”ๅฏๅœจ่”็ณปไบบไธญ้‡ๅ‘ฝๅ", "chat_contact_request": "่”็ณปไบบ่ฏทๆฑ‚", + "chat_emoji_search": "ๆœ็ดข่กจๆƒ…", "chat_empty_hint": "ๆš‚ๆ— ๅฏน่ฏใ€‚ๆ‚จๆ”ถๅˆฐ็š„ๆถˆๆฏๅฐ†ๆ˜พ็คบๅœจๆญคๅค„ใ€‚", "chat_empty_start": "็‚นๅ‡ป\"ๆ–ฐๅปบไผš่ฏ\"ๅผ€ๅง‹ใ€‚", "chat_empty_title": "่ฟ˜ๆฒกๆœ‰ไผš่ฏ", diff --git a/src/ui/windows/chat_tab.cpp b/src/ui/windows/chat_tab.cpp index a2ca91f..94d46de 100644 --- a/src/ui/windows/chat_tab.cpp +++ b/src/ui/windows/chat_tab.cpp @@ -49,6 +49,8 @@ char s_new_zaddr[128] = ""; char s_new_msg[256] = ""; char s_search[80] = ""; // conversation-list filter (Q8) bool s_show_hidden = false; // when on, the list also shows hidden conversations (with an Unhide action) +bool s_show_emoji_picker = false; // emoji picker overlay โ€” fills the conversation-list pane while open +char s_emoji_search[48] = ""; // emoji picker keyword filter // Effective draw-list font size for a material font (mirrors sidebar's ScaledFontSize). float scaledSize(ImFont* f) { return f->LegacySize * ImGui::GetStyle().FontScaleMain; } @@ -201,40 +203,75 @@ void centeredEmptyState(const char* icon, const char* title, const char* hint) { } } -// Emoji picker popup: a scrollable grid of common single-codepoint emoji (verified present in the -// bundled NotoEmoji subset). Clicking one appends its UTF-8 bytes to `buf` (respecting the buffer). -// The set is single-codepoint only โ€” ImGui does no shaping, so ZWJ sequences / flags wouldn't compose. -void emojiPickerPopup(const char* popupId, char* buf, std::size_t bufSize) { - static const char* const kEmoji = - u8"๐Ÿ˜€๐Ÿ˜ƒ๐Ÿ˜„๐Ÿ˜๐Ÿ˜†๐Ÿ˜…๐Ÿ˜‚๐Ÿคฃ๐Ÿ˜Š๐Ÿ˜‡๐Ÿ™‚๐Ÿ™ƒ๐Ÿ˜‰๐Ÿ˜Œ๐Ÿ˜๐Ÿฅฐ๐Ÿ˜˜๐Ÿ˜—๐Ÿ˜™๐Ÿ˜š๐Ÿ˜‹๐Ÿ˜›๐Ÿ˜๐Ÿ˜œ๐Ÿคช๐Ÿคจ๐Ÿง๐Ÿค“๐Ÿ˜Ž๐Ÿฅณ๐Ÿ˜๐Ÿ˜’๐Ÿ˜ž๐Ÿ˜”๐Ÿ˜Ÿ๐Ÿ˜•๐Ÿ™๐Ÿ˜ฃ๐Ÿ˜–๐Ÿ˜ซ๐Ÿ˜ฉ๐Ÿฅบ๐Ÿ˜ข๐Ÿ˜ญ๐Ÿ˜ค" - u8"๐Ÿ˜ ๐Ÿ˜ก๐Ÿคฌ๐Ÿคฏ๐Ÿ˜ณ๐Ÿฅต๐Ÿฅถ๐Ÿ˜ฑ๐Ÿ˜จ๐Ÿ˜ฐ๐Ÿ˜ฅ๐Ÿ˜“๐Ÿค—๐Ÿค”๐Ÿคญ๐Ÿคซ๐Ÿคฅ๐Ÿ˜ถ๐Ÿ˜๐Ÿ˜‘๐Ÿ˜ฌ๐Ÿ™„๐Ÿ˜ฏ๐Ÿ˜ฆ๐Ÿ˜ง๐Ÿ˜ฎ๐Ÿ˜ฒ๐Ÿฅฑ๐Ÿ˜ด๐Ÿคค๐Ÿ˜ช๐Ÿค๐Ÿฅด๐Ÿคข๐Ÿคฎ๐Ÿคง๐Ÿ˜ท๐Ÿค’๐Ÿค•๐Ÿ˜ˆ๐Ÿ‘ฟ๐Ÿ’€๐Ÿ‘ป๐Ÿ‘ฝ๐Ÿค–๐Ÿ˜บ๐Ÿ™€" - u8"๐Ÿ‘๐Ÿ‘Ž๐Ÿ‘ŒโœŒ๐Ÿคž๐ŸคŸ๐Ÿค˜๐Ÿ‘๐Ÿ™Œ๐Ÿ‘๐Ÿ™๐Ÿ’ช๐Ÿ‘‹๐Ÿค™๐Ÿ‘ŠโœŠ๐Ÿค›๐Ÿคœ๐Ÿ‘†๐Ÿ‘‡๐Ÿ‘ˆ๐Ÿ‘‰" - u8"โค๐Ÿงก๐Ÿ’›๐Ÿ’š๐Ÿ’™๐Ÿ’œ๐Ÿ–ค๐Ÿค๐Ÿ’”๐Ÿ’•๐Ÿ’ž๐Ÿ’—๐Ÿ’–๐Ÿ’˜๐Ÿ’๐Ÿ”ฅโญ๐ŸŽ‰๐ŸŽŠโœจ๐Ÿ’ฏโœ…โŒโ“โ—๐Ÿ‘€๐ŸŽ‚๐Ÿš€๐Ÿ’ฐ๐ŸŽ๐Ÿบ๐Ÿปโ˜•๐Ÿ•๐Ÿ‘‘๐Ÿ’Ž๐ŸŒŸ๐Ÿ’ฅ"; - const float dp = Layout::dpiScale(); - ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, 260.0f * dp)); // cap height โ†’ scrolls - if (!ImGui::BeginPopup(popupId)) return; +// Common single-codepoint emoji (all verified present in the bundled NotoEmoji subset), each with +// keyword text for the picker's search box. Single-codepoint only โ€” ImGui does no shaping, so ZWJ +// sequences / flags wouldn't compose. +struct EmojiEntry { const char* glyph; const char* keywords; }; +static const EmojiEntry kEmoji[] = { + {u8"๐Ÿ˜€","grin happy smile"},{u8"๐Ÿ˜ƒ","smile happy joy"},{u8"๐Ÿ˜„","laugh happy smile"},{u8"๐Ÿ˜","grin beam happy"}, + {u8"๐Ÿ˜†","laugh haha"},{u8"๐Ÿ˜…","sweat laugh nervous"},{u8"๐Ÿ˜‚","joy laugh tears cry funny"},{u8"๐Ÿคฃ","rofl laugh rolling funny"}, + {u8"๐Ÿ˜Š","blush smile happy"},{u8"๐Ÿ˜‡","angel innocent halo"},{u8"๐Ÿ™‚","slight smile"},{u8"๐Ÿ™ƒ","upside down silly"}, + {u8"๐Ÿ˜‰","wink"},{u8"๐Ÿ˜Œ","relieved calm"},{u8"๐Ÿ˜","heart eyes love"},{u8"๐Ÿฅฐ","love hearts adore"},{u8"๐Ÿ˜˜","kiss blow"}, + {u8"๐Ÿ˜—","kiss"},{u8"๐Ÿ˜™","kiss smile"},{u8"๐Ÿ˜š","kiss closed"},{u8"๐Ÿ˜‹","yum tasty tongue"},{u8"๐Ÿ˜›","tongue playful"}, + {u8"๐Ÿ˜","tongue squint"},{u8"๐Ÿ˜œ","wink tongue crazy"},{u8"๐Ÿคช","zany crazy silly"},{u8"๐Ÿคจ","raised eyebrow suspicious"}, + {u8"๐Ÿง","monocle thinking"},{u8"๐Ÿค“","nerd geek glasses"},{u8"๐Ÿ˜Ž","cool sunglasses"},{u8"๐Ÿฅณ","party celebrate hat"}, + {u8"๐Ÿ˜","smirk"},{u8"๐Ÿ˜’","unamused meh"},{u8"๐Ÿ˜ž","disappointed sad"},{u8"๐Ÿ˜”","pensive sad"},{u8"๐Ÿ˜Ÿ","worried"}, + {u8"๐Ÿ˜•","confused"},{u8"๐Ÿ™","frown sad"},{u8"๐Ÿ˜ฃ","persevere"},{u8"๐Ÿ˜–","confounded"},{u8"๐Ÿ˜ซ","tired"},{u8"๐Ÿ˜ฉ","weary"}, + {u8"๐Ÿฅบ","pleading puppy beg"},{u8"๐Ÿ˜ข","cry sad tear"},{u8"๐Ÿ˜ญ","sob cry bawl"},{u8"๐Ÿ˜ค","huff triumph steam"}, + {u8"๐Ÿ˜ ","angry mad"},{u8"๐Ÿ˜ก","rage mad angry"},{u8"๐Ÿคฌ","curse swear angry"},{u8"๐Ÿคฏ","mind blown shock"}, + {u8"๐Ÿ˜ณ","flushed embarrassed"},{u8"๐Ÿฅต","hot heat sweat"},{u8"๐Ÿฅถ","cold freezing"},{u8"๐Ÿ˜ฑ","scream fear shock"}, + {u8"๐Ÿ˜จ","fearful scared"},{u8"๐Ÿ˜ฐ","anxious sweat"},{u8"๐Ÿ˜ฅ","sad sweat"},{u8"๐Ÿ˜“","sweat"},{u8"๐Ÿค—","hug"}, + {u8"๐Ÿค”","think hmm"},{u8"๐Ÿคญ","giggle oops hand"},{u8"๐Ÿคซ","shush quiet"},{u8"๐Ÿคฅ","lie"},{u8"๐Ÿ˜ถ","no mouth blank"}, + {u8"๐Ÿ˜","neutral meh"},{u8"๐Ÿ˜‘","expressionless"},{u8"๐Ÿ˜ฌ","grimace awkward"},{u8"๐Ÿ™„","eye roll"},{u8"๐Ÿ˜ฏ","hushed surprise"}, + {u8"๐Ÿ˜ฆ","frown open"},{u8"๐Ÿ˜ง","anguished"},{u8"๐Ÿ˜ฎ","wow surprise oh"},{u8"๐Ÿ˜ฒ","astonished shock"},{u8"๐Ÿฅฑ","yawn tired bored"}, + {u8"๐Ÿ˜ด","sleep zzz"},{u8"๐Ÿคค","drool"},{u8"๐Ÿ˜ช","sleepy"},{u8"๐Ÿค","zipper quiet secret"},{u8"๐Ÿฅด","woozy dizzy drunk"}, + {u8"๐Ÿคข","nausea sick"},{u8"๐Ÿคฎ","vomit sick"},{u8"๐Ÿคง","sneeze sick"},{u8"๐Ÿ˜ท","mask sick"},{u8"๐Ÿค’","sick thermometer"}, + {u8"๐Ÿค•","hurt bandage injured"},{u8"๐Ÿ˜ˆ","devil imp evil"},{u8"๐Ÿ‘ฟ","devil angry"},{u8"๐Ÿ’€","skull dead"},{u8"๐Ÿ‘ป","ghost boo"}, + {u8"๐Ÿ‘ฝ","alien"},{u8"๐Ÿค–","robot bot"},{u8"๐Ÿ˜บ","cat smile"},{u8"๐Ÿ™€","cat scream"}, + {u8"๐Ÿ‘","thumbs up like yes good"},{u8"๐Ÿ‘Ž","thumbs down dislike no bad"},{u8"๐Ÿ‘Œ","ok perfect"},{u8"โœŒ","peace victory"}, + {u8"๐Ÿคž","fingers crossed luck"},{u8"๐ŸคŸ","love you"},{u8"๐Ÿค˜","rock horns"},{u8"๐Ÿ‘","clap applause"}, + {u8"๐Ÿ™Œ","raise hands celebrate"},{u8"๐Ÿ‘","open hands"},{u8"๐Ÿ™","pray thanks please"},{u8"๐Ÿ’ช","muscle strong flex"}, + {u8"๐Ÿ‘‹","wave hi hello bye"},{u8"๐Ÿค™","call shaka"},{u8"๐Ÿ‘Š","fist punch bump"},{u8"โœŠ","fist raised"},{u8"๐Ÿค›","fist left"}, + {u8"๐Ÿคœ","fist right"},{u8"๐Ÿ‘†","up point"},{u8"๐Ÿ‘‡","down point"},{u8"๐Ÿ‘ˆ","left point"},{u8"๐Ÿ‘‰","right point"}, + {u8"โค","heart red love"},{u8"๐Ÿงก","heart orange"},{u8"๐Ÿ’›","heart yellow"},{u8"๐Ÿ’š","heart green"},{u8"๐Ÿ’™","heart blue"}, + {u8"๐Ÿ’œ","heart purple"},{u8"๐Ÿ–ค","heart black"},{u8"๐Ÿค","heart white"},{u8"๐Ÿ’”","broken heart"},{u8"๐Ÿ’•","hearts love"}, + {u8"๐Ÿ’ž","revolving hearts"},{u8"๐Ÿ’—","growing heart"},{u8"๐Ÿ’–","sparkling heart"},{u8"๐Ÿ’˜","heart arrow cupid"}, + {u8"๐Ÿ’","heart gift ribbon"},{u8"๐Ÿ”ฅ","fire lit hot flame"},{u8"โญ","star"},{u8"๐ŸŽ‰","party tada celebrate confetti"}, + {u8"๐ŸŽŠ","confetti party"},{u8"โœจ","sparkles shiny"},{u8"๐Ÿ’ฏ","hundred perfect 100"},{u8"โœ…","check yes done tick"}, + {u8"โŒ","cross no wrong x"},{u8"โ“","question mark"},{u8"โ—","exclamation mark"},{u8"๐Ÿ‘€","eyes look"},{u8"๐ŸŽ‚","cake birthday"}, + {u8"๐Ÿš€","rocket launch"},{u8"๐Ÿ’ฐ","money bag cash"},{u8"๐ŸŽ","gift present"},{u8"๐Ÿบ","beer"},{u8"๐Ÿป","beers cheers"}, + {u8"โ˜•","coffee tea"},{u8"๐Ÿ•","pizza"},{u8"๐Ÿ‘‘","crown king queen"},{u8"๐Ÿ’Ž","diamond gem"},{u8"๐ŸŒŸ","glowing star"}, + {u8"๐Ÿ’ฅ","boom explosion"}, +}; + +// Emoji picker overlay: fills the conversation-list pane (cancel + keyword search at the top, then a +// grid). Clicking an emoji appends its UTF-8 bytes to `buf` (the composer), respecting the buffer. +void renderEmojiPickerOverlay(char* buf, std::size_t bufSize) { + if (ImGui::SmallButton(TR("chat_cancel"))) { s_show_emoji_picker = false; s_emoji_search[0] = '\0'; return; } + ImGui::SameLine(); + ImGui::SetNextItemWidth(-FLT_MIN); + ImGui::InputTextWithHint("##emojisearch", TR("chat_emoji_search"), s_emoji_search, sizeof(s_emoji_search)); + ImGui::Separator(); + + const std::string q = s_emoji_search; + ImGui::BeginChild("##emojigrid", ImVec2(0, 0), false); ImGui::PushFont(material::Type().subtitle1()); // larger + emoji-capable - const float cell = 30.0f * dp; - const int perRow = 9; - int idx = 0; - for (const char* s = kEmoji; *s;) { - const unsigned char lead = static_cast(*s); - const int len = (lead >= 0xF0) ? 4 : (lead >= 0xE0) ? 3 : (lead >= 0xC0) ? 2 : 1; - char glyph[5] = {0}; - for (int k = 0; k < len && s[k]; ++k) glyph[k] = s[k]; - ImGui::PushID(idx); - if (ImGui::Button(glyph, ImVec2(cell, cell))) { - const std::size_t cur = std::strlen(buf); - const std::size_t add = std::strlen(glyph); - if (cur + add < bufSize) { std::memcpy(buf + cur, glyph, add); buf[cur + add] = '\0'; } + const float cell = 32.0f * Layout::dpiScale(); + const float step = cell + ImGui::GetStyle().ItemSpacing.x; + const int perRow = std::max(1, static_cast(ImGui::GetContentRegionAvail().x / step)); + int shown = 0; + for (const auto& e : kEmoji) { + if (!q.empty() && !containsCI(e.keywords, q)) continue; + ImGui::PushID(shown); + if (ImGui::Button(e.glyph, ImVec2(cell, cell))) { + const std::size_t cur = std::strlen(buf), add = std::strlen(e.glyph); + if (cur + add < bufSize) { std::memcpy(buf + cur, e.glyph, add); buf[cur + add] = '\0'; } } ImGui::PopID(); - if ((idx + 1) % perRow != 0) ImGui::SameLine(); - s += len; - ++idx; + if (++shown % perRow != 0) ImGui::SameLine(); } ImGui::PopFont(); - ImGui::EndPopup(); + ImGui::EndChild(); } } // namespace @@ -310,7 +347,10 @@ void RenderChatTab(App* app) // Faint sidebar tint so the list reads as distinct from the thread pane (V6). ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::ColorConvertU32ToFloat4(material::WithAlpha(material::OnSurface(), 10))); ImGui::BeginChild("##ChatList", ImVec2(listW, avail.y), true); - { + if (s_show_emoji_picker) { + // Emoji picker overlay takes over the conversation-list pane while open (search + cancel + grid). + renderEmojiPickerOverlay(s_compose, sizeof(s_compose)); + } else { // Accented "New conversation" action (house tactile style). ImGui::PushStyleColor(ImGuiCol_Button, ImGui::ColorConvertU32ToFloat4(material::WithAlpha(material::Primary(), 205))); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::ColorConvertU32ToFloat4(material::Primary())); @@ -656,12 +696,12 @@ void RenderChatTab(App* app) if (material::TactileButton(TR("chat_send"), ImVec2(sendW, composerBoxH))) submit = true; ImGui::EndDisabled(); ImGui::PopStyleColor(3); - // Emoji picker button (left) + byte counter (right) on one row. + // Emoji picker button (left) + byte counter (right) on one row. The picker opens as an + // overlay over the conversation-list pane (rendered there), not a floating window. ImGui::PushFont(nameFont); // Body2 has emoji merged, so the glyph renders const bool emojiClicked = ImGui::SmallButton(u8"๐Ÿ™‚"); ImGui::PopFont(); - if (emojiClicked) ImGui::OpenPopup("##emojipick"); - emojiPickerPopup("##emojipick", s_compose, sizeof(s_compose)); + if (emojiClicked) { s_show_emoji_picker = !s_show_emoji_picker; s_emoji_search[0] = '\0'; } ImGui::SameLine(); // Byte counter (Error tint over cap) with the over-cap label. ImGui::PushFont(metaFont); diff --git a/src/util/i18n.cpp b/src/util/i18n.cpp index 235f0da..277cc64 100644 --- a/src/util/i18n.cpp +++ b/src/util/i18n.cpp @@ -255,6 +255,7 @@ void I18n::loadBuiltinEnglish() strings_["chat_hide"] = "Hide"; strings_["chat_unhide"] = "Unhide"; strings_["chat_show_hidden"] = "Show hidden"; + strings_["chat_emoji_search"] = "Search emoji"; strings_["chat_hide_hidden"] = "Hide hidden"; strings_["chat_hidden_toast"] = "Conversation hidden โ€” a new message brings it back"; strings_["chat_pick_contact"] = "Choose from contacts\xE2\x80\xA6";