diff --git a/lang/Czech.ini b/lang/Czech.ini index 81a2e89a3..e270079c7 100644 --- a/lang/Czech.ini +++ b/lang/Czech.ini @@ -58,6 +58,8 @@ MOD_DESC = "/moderator [JMÉNO|ID] - Hráč bude moci používat příkazy jako NAMETAGS_DESC = "/nametags [show-tag|show-health] - Změňte, zda vidíte svůj vlastní štítek a zda vidíte zdraví" UNRECOGNIZED = "Neznámý příkaz." MOD_GRANTED = "\\#fff982\\Jste nyní moderátor." +ALL_COMMANDS = "Všechny příkazy" +TAB_COMPLETE_INFO = "Stiskni TAB pro automatické dokončení příkazů, Shift+TAB naviguje zpět" [MENU] BACK = "Zpět" @@ -106,6 +108,7 @@ DEADZONE = "Deadzone" RUMBLE_STRENGTH = "Síla vibrace" CHAT = "Chat" +CHAT_COMMAND = "Chat (Příkaz)" PLAYERS = "Hráči" D_UP = "D-Pad nahoru" D_DOWN = "D-Pad dolů" @@ -320,7 +323,6 @@ DEBUG_ERRORS = "Debug Errors" MISC_TITLE = "JINE" PAUSE_IN_SINGLEPLAYER = "Pauza v hře s jedním hráčem" DISABLE_POPUPS = "Vypnout vyskakovací okna" -USE_STANDARD_KEY_BINDINGS_CHAT = "Klasické ovládání chatu" MENU_OPTIONS = "Nastavení hlavního menu" INFORMATION = "Informace" DEBUG = "Debug" @@ -329,6 +331,34 @@ COOP_COMPATIBILITY = "Povolit kompatibilitu sm64ex-coop" R_BUTTON = "Tlačítko R - Možnosti" L_BUTTON = "Tlačítko L - Znovu načíst aktivní mody" +[CHAT_OPTIONS] +CHAT = "CHAT" +USE_STANDARD_KEY_BINDINGS_CHAT = "Použít ovládání chatu Terminal/CMD" +CHAT_WIDTH = "Šířka chatu" +CHAT_HEIGHT = "Výška chatu" +CHAT_SIZE_MINIMUM = "Minimum" +CHAT_SIZE_VERY_TINY = "Prťavá" +CHAT_SIZE_TINY = "Drobná" +CHAT_SIZE_VERY_SMALL = "Velmi malá" +CHAT_SIZE_SMALL = "Malá" +CHAT_SIZE_NORMAL = "Normální" +CHAT_SIZE_BIG = "Velká" +CHAT_SIZE_VERY_BIG = "Velmi velká" +CHAT_SIZE_HUGE = "Obrovská" +CHAT_SIZE_VERY_HUGE = "Obří" +CHAT_SIZE_MAXIMUM = "Maximum" +CHAT_TEXT_SCALE = "Velikost textu chatu" +CHAT_BACKGROUND_OPACITY = "Průhlednost pozadí chatu" +CHAT_TEXT_OPACITY = "Průhlednost textu chatu" +CHAT_LIFETIME = "Doba zobrazení zpráv" +CHAT_CHAR_COUNTER = "Zobrazit počitadlo znaků chatu" +CHAT_CLOSED_MODE = "Zobrazit historii chatu" +CHAT_CLOSED_DISABLED = "Skrytý" +CHAT_CLOSED_LIFETIME = "Skrýt po: %us" +CHAT_CLOSED_ALWAYS = "Vždy viditelný" +CHAT_SHIFT_HINT = "Podržte Shift pro jemné nastavení" +CHAT_SHIFT_HINT_ACTIVE = "Jemné nastavení aktivní" + [INFORMATION] INFORMATION_TITLE = "INFORMACE" CHANGELOG = "Záznam změn" @@ -344,6 +374,7 @@ OPTIONS = "NASTAVENI" PLAYER = "Hráč" CAMERA = "Kamera" CONTROLS = "Ovládání" +CHAT = "Chat" DISPLAY = "Video" SOUND = "Zvuk" MISC = "Jiné" diff --git a/lang/Dutch.ini b/lang/Dutch.ini index c4e32f77c..6ae5f34d0 100644 --- a/lang/Dutch.ini +++ b/lang/Dutch.ini @@ -58,6 +58,8 @@ MOD_DESC = "/moderator [NAAM|ID] - Geeft deze spelere de toestemming om commando NAMETAGS_DESC = "/nametags [show-tag|show-health] - Verander of je je eigen naamtag ziet en of je gezondheid ziet" UNRECOGNIZED = "onbekent Chat commando." MOD_GRANTED = "\\#fff982\\Je bent nu een Moderator." +ALL_COMMANDS = "Alle commando's" +TAB_COMPLETE_INFO = "Druk op TAB om opdrachten automatisch aan te vullen, gebruik Shift+TAB om terug te gaan" [MENU] BACK = "Terug" @@ -106,6 +108,7 @@ DEADZONE = "Doode-zone" RUMBLE_STRENGTH = "Rommel Kracht" CHAT = "Chat" +CHAT_COMMAND = "Chat (Commando)" PLAYERS = "Spelers" D_UP = "D Omhoog" D_DOWN = "D Naar Beneden" @@ -320,7 +323,6 @@ DEBUG_ERRORS = "Debug Errors" MISC_TITLE = "MISC" PAUSE_IN_SINGLEPLAYER = "Pauzeer in een speler" DISABLE_POPUPS = "Popups uitzetten" -USE_STANDARD_KEY_BINDINGS_CHAT = "Klassieke chatbediening" MENU_OPTIONS = "Menu Instellingen" INFORMATION = "Informatie" DEBUG = "Debug" @@ -329,6 +331,34 @@ COOP_COMPATIBILITY = "Schakel sm64ex-coop compatibiliteit in" R_BUTTON = "R-knop - Opties" L_BUTTON = "L-knop - Actieve mods opnieuw laden" +[CHAT_OPTIONS] +CHAT = "CHAT" +USE_STANDARD_KEY_BINDINGS_CHAT = "Terminal/CMD Chatbox besturingen gebruiken" +CHAT_WIDTH = "Chatbreedte" +CHAT_HEIGHT = "Chathoogte" +CHAT_SIZE_MINIMUM = "Minimum" +CHAT_SIZE_VERY_TINY = "Heel erg klein" +CHAT_SIZE_TINY = "Zeer klein" +CHAT_SIZE_VERY_SMALL = "Erg klein" +CHAT_SIZE_SMALL = "Klein" +CHAT_SIZE_NORMAL = "Normaal" +CHAT_SIZE_BIG = "Groot" +CHAT_SIZE_VERY_BIG = "Zeer groot" +CHAT_SIZE_HUGE = "Enorm" +CHAT_SIZE_VERY_HUGE = "Gigantisch" +CHAT_SIZE_MAXIMUM = "Maximum" +CHAT_TEXT_SCALE = "Chat-tekstgrootte" +CHAT_BACKGROUND_OPACITY = "Transparantie van de chatachtergrond" +CHAT_TEXT_OPACITY = "Transparantie van de chattekst" +CHAT_LIFETIME = "Weergaveduur berichten" +CHAT_CHAR_COUNTER = "Chat-tekensteller weergeven" +CHAT_CLOSED_MODE = "Chatgeschiedenis tonen" +CHAT_CLOSED_DISABLED = "Verborgen" +CHAT_CLOSED_LIFETIME = "Verbergen na: %us" +CHAT_CLOSED_ALWAYS = "Altijd zichtbaar" +CHAT_SHIFT_HINT = "Houd Shift ingedrukt voor fijne aanpassing" +CHAT_SHIFT_HINT_ACTIVE = "Fijne aanpassing actief" + [INFORMATION] INFORMATION_TITLE = "INFORMATIE" CHANGELOG = "Wijzigingenlogboek" @@ -347,6 +377,7 @@ CONTROLS = "Controles" DISPLAY = "Weergave" SOUND = "Geluid" MISC = "Misc" +CHAT = "Chat" USER_FOLDER = "Gebruikersmap openen" APPDATA = "Open AppData" diff --git a/lang/English.ini b/lang/English.ini index 0560d9ac2..04cd6ffd0 100644 --- a/lang/English.ini +++ b/lang/English.ini @@ -58,7 +58,8 @@ MOD_DESC = "/moderator [NAME|ID] - Make this player able to use commands like /k NAMETAGS_DESC = "/nametags [show-tag|show-health] - Change whether or not you see your own nametag and whether or not you see health" UNRECOGNIZED = "Unrecognized chat command." MOD_GRANTED = "\\#fff982\\You are now a Moderator." - +ALL_COMMANDS = "All commands" +TAB_COMPLETE_INFO = "Press TAB to autocomplete commands, use Shift+TAB to navigate backwards" [MENU] BACK = "Back" CANCEL = "Cancel" @@ -106,6 +107,7 @@ DEADZONE = "Deadzone" RUMBLE_STRENGTH = "Rumble Strength" CHAT = "Chat" +CHAT_COMMAND = "Chat (Command)" PLAYERS = "Players" D_UP = "D-Up" D_DOWN = "D-Down" @@ -320,7 +322,6 @@ DEBUG_ERRORS = "Debug Errors" MISC_TITLE = "MISC" PAUSE_IN_SINGLEPLAYER = "Pause In Singleplayer" DISABLE_POPUPS = "Disable Popups" -USE_STANDARD_KEY_BINDINGS_CHAT = "Classic Chatbox Controls" MENU_OPTIONS = "Menu Options" INFORMATION = "Info" DEBUG = "Debug" @@ -329,6 +330,34 @@ COOP_COMPATIBILITY = "Enable sm64ex-coop Compatibility" R_BUTTON = "R Button - Options" L_BUTTON = "L Button - Reload Active Mods" +[CHAT_OPTIONS] +CHAT = "CHAT" +USE_STANDARD_KEY_BINDINGS_CHAT = "Use Terminal/CMD Chatbox Controls" +CHAT_WIDTH = "Chat Width" +CHAT_HEIGHT = "Chat Height" +CHAT_SIZE_MINIMUM = "Minimum" +CHAT_SIZE_VERY_TINY = "Very Tiny" +CHAT_SIZE_TINY = "Tiny" +CHAT_SIZE_VERY_SMALL = "Very Small" +CHAT_SIZE_SMALL = "Small" +CHAT_SIZE_NORMAL = "Normal" +CHAT_SIZE_BIG = "Big" +CHAT_SIZE_VERY_BIG = "Very Big" +CHAT_SIZE_HUGE = "Huge" +CHAT_SIZE_VERY_HUGE = "Very Huge" +CHAT_SIZE_MAXIMUM = "Maximum" +CHAT_TEXT_SCALE = "Chat Text Size" +CHAT_BACKGROUND_OPACITY = "Chat Background Opacity" +CHAT_TEXT_OPACITY = "Chat Text Opacity" +CHAT_LIFETIME = "Chat Message Lifetime" +CHAT_CHAR_COUNTER = "Show Chat Character Counter" +CHAT_CLOSED_MODE = "Show Chat History" +CHAT_CLOSED_DISABLED = "Hide immediately" +CHAT_CLOSED_LIFETIME = "Fade after: %us" +CHAT_CLOSED_ALWAYS = "Always visible" +CHAT_SHIFT_HINT = "Hold Shift for fine adjustment" +CHAT_SHIFT_HINT_ACTIVE = "Fine adjustment active" + [INFORMATION] INFORMATION_TITLE = "INFO" CHANGELOG = "Changelog" @@ -344,6 +373,7 @@ OPTIONS = "OPTIONS" PLAYER = "Player" CAMERA = "Camera" CONTROLS = "Controls" +CHAT = "Chat" DISPLAY = "Display" SOUND = "Sound" MISC = "Misc" diff --git a/lang/French.ini b/lang/French.ini index 645ed0c2a..6ea212b5f 100644 --- a/lang/French.ini +++ b/lang/French.ini @@ -58,6 +58,8 @@ MOD_DESC = "/moderator [NAME|ID] - Rend ce joueur capable d'utiliser des command NAMETAGS_DESC = "/nametags [show-tag|show-health] - Modifiez si vous voyez votre propre étiquette de nom et si vous voyez la santé" UNRECOGNIZED = "Cette commande n'est pas reconnue." MOD_GRANTED = "\\#fff982\\Vous êtes désormais un modérateur." +ALL_COMMANDS = "Toutes les commandes" +TAB_COMPLETE_INFO = "Appuie sur TAB pour compléter automatiquement les commandes, utilise Shift+TAB pour revenir en arrière" [MENU] BACK = "Retour" @@ -106,6 +108,7 @@ DEADZONE = "Zone Morte" RUMBLE_STRENGTH = "Vibrations" CHAT = "Chat" +CHAT_COMMAND = "Chat (Commande)" PLAYERS = "Joueurs" D_UP = "D Haut" D_DOWN = "D Bas" @@ -320,7 +323,6 @@ DEBUG_ERRORS = "Erreurs de Débogage" MISC_TITLE = "AUTRES" PAUSE_IN_SINGLEPLAYER = "Pause en Solo" DISABLE_POPUPS = "Désactiver les Pop-ups" -USE_STANDARD_KEY_BINDINGS_CHAT = "Commandes de chat classiques" MENU_OPTIONS = "Options du menu" INFORMATION = "Information" DEBUG = "Débogage" @@ -329,6 +331,34 @@ COOP_COMPATIBILITY = "Activer la compatibilité sm64ex-coop" R_BUTTON = "Bouton R - Options" L_BUTTON = "Bouton L - Recharger les mods actifs" +[CHAT_OPTIONS] +CHAT = "CHAT" +USE_STANDARD_KEY_BINDINGS_CHAT = "Utiliser les contrôles de chat Terminal/CMD" +CHAT_WIDTH = "Largeur du chat" +CHAT_HEIGHT = "Hauteur du chat" +CHAT_SIZE_MINIMUM = "Minimum" +CHAT_SIZE_VERY_TINY = "Infime" +CHAT_SIZE_TINY = "Minuscule" +CHAT_SIZE_VERY_SMALL = "Très petite" +CHAT_SIZE_SMALL = "Petite" +CHAT_SIZE_NORMAL = "Normale" +CHAT_SIZE_BIG = "Grande" +CHAT_SIZE_VERY_BIG = "Très grande" +CHAT_SIZE_HUGE = "Énorme" +CHAT_SIZE_VERY_HUGE = "Gigantesque" +CHAT_SIZE_MAXIMUM = "Maximum" +CHAT_TEXT_SCALE = "Taille du texte du chat" +CHAT_BACKGROUND_OPACITY = "Opacité du fond du chat" +CHAT_TEXT_OPACITY = "Opacité du texte du chat" +CHAT_LIFETIME = "Durée d'affichage des messages" +CHAT_CHAR_COUNTER = "Afficher le compteur de caractères du chat" +CHAT_CLOSED_MODE = "Afficher l'historique du chat" +CHAT_CLOSED_DISABLED = "Masqué" +CHAT_CLOSED_LIFETIME = "Masquer après : %us" +CHAT_CLOSED_ALWAYS = "Toujours visible" +CHAT_SHIFT_HINT = "Maintenir Shift pour réglage fin" +CHAT_SHIFT_HINT_ACTIVE = "Réglage fin actif" + [INFORMATION] INFORMATION_TITLE = "INFORMATION" CHANGELOG = "Notes de mise à jour" @@ -344,6 +374,7 @@ OPTIONS = "OPTIONS" PLAYER = "Joueur" CAMERA = "Caméra" CONTROLS = "Contrôles" +CHAT = "Chat" DISPLAY = "Affichage" SOUND = "Audio" MISC = "Autres Paramètres" diff --git a/lang/German.ini b/lang/German.ini index 1fb8031d7..ff5916f0d 100644 --- a/lang/German.ini +++ b/lang/German.ini @@ -58,6 +58,8 @@ MOD_DESC = "/moderator [NAME|ID] - Gebe einem Spieler Moderator rechte wie /kick NAMETAGS_DESC = "/nametags [show-tag|show-health] - Sichtbarkeit von Spielernamen sowie der KP/Kraft aktivieren oder deaktivieren " UNRECOGNIZED = "Unbekannter Befehl!" MOD_GRANTED = "\\#fff982\\Du bist jetzt ein Moderator." +ALL_COMMANDS = "Alle Befehle" +TAB_COMPLETE_INFO = "Drücke TAB zum Autovervollständigen der Befehle, mit Shift+TAB navigierst du rückwärts" [MENU] BACK = "Zurück" @@ -106,6 +108,7 @@ DEADZONE = "Tote Zone" RUMBLE_STRENGTH = "Vibration-Stärke" CHAT = "Chat" +CHAT_COMMAND = "Chat (Befehl)" PLAYERS = "Spieler" D_UP = "D-Hoch" D_DOWN = "D-Unten" @@ -320,7 +323,6 @@ DEBUG_ERRORS = "Debug Fehler" MISC_TITLE = "SONSTIGES" PAUSE_IN_SINGLEPLAYER = "Pause im Einzelspieler" DISABLE_POPUPS = "Pop-ups deaktivieren" -USE_STANDARD_KEY_BINDINGS_CHAT = "Standard-Tastennavigation im Chat" MENU_OPTIONS = "Menüoptionen" INFORMATION = "Info" DEBUG = "Debug" @@ -329,6 +331,34 @@ COOP_COMPATIBILITY = "Aktiviere sm64ex-coop Kompatibilität" R_BUTTON = "R-Taste - Optionen" L_BUTTON = "L-Taste - Aktive Mods neu laden" +[CHAT_OPTIONS] +CHAT = "CHAT" +USE_STANDARD_KEY_BINDINGS_CHAT = "Terminal/CMD Chatbox-Steuerung verwenden" +CHAT_WIDTH = "Chatbreite" +CHAT_HEIGHT = "Chathöhe" +CHAT_SIZE_MINIMUM = "Minimal" +CHAT_SIZE_VERY_TINY = "Sehr winzig" +CHAT_SIZE_TINY = "Winzig" +CHAT_SIZE_VERY_SMALL = "Sehr klein" +CHAT_SIZE_SMALL = "Klein" +CHAT_SIZE_NORMAL = "Normal" +CHAT_SIZE_BIG = "Groß" +CHAT_SIZE_VERY_BIG = "Sehr groß" +CHAT_SIZE_HUGE = "Riesig" +CHAT_SIZE_VERY_HUGE = "Gigantisch" +CHAT_SIZE_MAXIMUM = "Maximal" +CHAT_TEXT_SCALE = "Chat-Textgröße" +CHAT_BACKGROUND_OPACITY = "Chat-Hintergrundtransparenz" +CHAT_TEXT_OPACITY = "Chat-Texttransparenz" +CHAT_LIFETIME = "Chat-Anzeigedauer" +CHAT_CHAR_COUNTER = "Chat-Zeichenzähler anzeigen" +CHAT_CLOSED_MODE = "Chatverlauf anzeigen" +CHAT_CLOSED_DISABLED = "Sofort ausblenden" +CHAT_CLOSED_LIFETIME = "Ausblenden nach: %us" +CHAT_CLOSED_ALWAYS = "Dauerhaft anzeigen" +CHAT_SHIFT_HINT = "Shift für Feinjustierung gedrückt halten" +CHAT_SHIFT_HINT_ACTIVE = "Feinjustierung aktiv" + [INFORMATION] INFORMATION_TITLE = "INFORMATION" CHANGELOG = "Änderungsprotokoll" @@ -344,6 +374,7 @@ OPTIONS = "OPTIONEN" PLAYER = "Spieler" CAMERA = "Kamera" CONTROLS = "Steuerung" +CHAT = "Chat" DISPLAY = "Anzeige" SOUND = "Sound" MISC = "Sonstiges" diff --git a/lang/Italian.ini b/lang/Italian.ini index dfe13d3bb..4860e0099 100644 --- a/lang/Italian.ini +++ b/lang/Italian.ini @@ -58,6 +58,8 @@ MOD_DESC = "/moderator [NAME|ID] - Dai al giocatore il permesso di eseguire coma NAMETAGS_DESC = "/nametags [show-tag|show-health] - Cambia la visibilità del tuo nome e della salute" UNRECOGNIZED = "Comando non riconosciuto." MOD_GRANTED = "\\#fff982\\Ora sei un moderatore." +ALL_COMMANDS = "Tutti i comandi" +TAB_COMPLETE_INFO = "Premi TAB per completare automaticamente i comandi, usa Shift+TAB per navigare all'indietro" [MENU] BACK = "Indietro" @@ -104,6 +106,7 @@ GAMEPAD = "Controller" DEADZONE = "Zona Morta" RUMBLE_STRENGTH = "Intesità Vibrazione" CHAT = "Chat" +CHAT_COMMAND = "Chat (Comando)" PLAYERS = "Giocatori" D_UP = "D Su" D_DOWN = "D Giù" @@ -318,7 +321,6 @@ DEBUG_ERRORS = "Errori di debug" MISC_TITLE = "VARIE" PAUSE_IN_SINGLEPLAYER = "Pausa in Giocatore Singolo" DISABLE_POPUPS = "Disabilita Popup" -USE_STANDARD_KEY_BINDINGS_CHAT = "Controlli della chat classici" MENU_OPTIONS = "Opzioni Menù" INFORMATION = "Informazione" DEBUG = "Debug" @@ -327,6 +329,34 @@ COOP_COMPATIBILITY = "Abilita la compatibilità con sm64ex-coop" R_BUTTON = "Pulsante R - Opzioni" L_BUTTON = "Pulsante L - Ricarica Mod Attive" +[CHAT_OPTIONS] +CHAT = "CHAT" +USE_STANDARD_KEY_BINDINGS_CHAT = "Usa controlli chat Terminale/CMD" +CHAT_WIDTH = "Larghezza chat" +CHAT_HEIGHT = "Altezza chat" +CHAT_SIZE_MINIMUM = "Minimo" +CHAT_SIZE_VERY_TINY = "Piccolissima" +CHAT_SIZE_TINY = "Minuscola" +CHAT_SIZE_VERY_SMALL = "Molto piccola" +CHAT_SIZE_SMALL = "Piccola" +CHAT_SIZE_NORMAL = "Normale" +CHAT_SIZE_BIG = "Grande" +CHAT_SIZE_VERY_BIG = "Molto grande" +CHAT_SIZE_HUGE = "Enorme" +CHAT_SIZE_VERY_HUGE = "Enormissima" +CHAT_SIZE_MAXIMUM = "Massimo" +CHAT_TEXT_SCALE = "Dimensione testo chat" +CHAT_BACKGROUND_OPACITY = "Opacità sfondo chat" +CHAT_TEXT_OPACITY = "Opacità testo chat" +CHAT_LIFETIME = "Durata messaggi chat" +CHAT_CHAR_COUNTER = "Mostra contatore caratteri della chat" +CHAT_CLOSED_MODE = "Mostrare la cronologia della chat" +CHAT_CLOSED_DISABLED = "Disattivata" +CHAT_CLOSED_LIFETIME = "Nascondi dopo: %us" +CHAT_CLOSED_ALWAYS = "Sempre visibile" +CHAT_SHIFT_HINT = "Tieni premuto Shift per regolazione fine" +CHAT_SHIFT_HINT_ACTIVE = "Regolazione fine attiva" + [INFORMATION] INFORMATION_TITLE = "INFO" CHANGELOG = "Registro delle modifiche" @@ -342,6 +372,7 @@ OPTIONS = "OPZIONI" PLAYER = "Giocatore" CAMERA = "Telecamera" CONTROLS = "Comandi" +CHAT = "Chat" DISPLAY = "Grafica" SOUND = "Audio" MISC = "Varie" diff --git a/lang/Japanese.ini b/lang/Japanese.ini index 05b20a216..ee8c6a5d0 100644 --- a/lang/Japanese.ini +++ b/lang/Japanese.ini @@ -58,6 +58,8 @@ MOD_DESC = "/moderator [プレイヤー名|ID] - 指定したプレイヤーに/ NAMETAGS_DESC = "/nametags [show-tag|show-health] - あなたのネームタグ/体力の表示を変更します。" UNRECOGNIZED = "未知のコマンドです。" MOD_GRANTED = "\\#fff982\\あなたはモデレーターになりました。" +ALL_COMMANDS = "すべてのコマンド" +TAB_COMPLETE_INFO = "TABキーでコマンドを自動補完、Shift+TABで逆方向に移動" [MENU] BACK = "戻る" @@ -329,6 +331,34 @@ COOP_COMPATIBILITY = "sm64ex-coopとの互換性を有効にする" R_BUTTON = "Rボタン - 設定" L_BUTTON = "Lボタン - 有効化されたMODを再読み込み" +[CHAT_OPTIONS] +CHAT = "CHAT" +USE_STANDARD_KEY_BINDINGS_CHAT = "ターミナル/CMDチャットボックスコントロールを使用" +CHAT_WIDTH = "チャット幅" +CHAT_HEIGHT = "チャットの高さ" +CHAT_SIZE_MINIMUM = "最小" +CHAT_SIZE_VERY_TINY = "極小" +CHAT_SIZE_TINY = "とても小さい" +CHAT_SIZE_VERY_SMALL = "かなり小さい" +CHAT_SIZE_SMALL = "小さい" +CHAT_SIZE_NORMAL = "標準" +CHAT_SIZE_BIG = "大きい" +CHAT_SIZE_VERY_BIG = "とても大きい" +CHAT_SIZE_HUGE = "巨大" +CHAT_SIZE_VERY_HUGE = "超巨大" +CHAT_SIZE_MAXIMUM = "最大" +CHAT_TEXT_SCALE = "チャット文字サイズ" +CHAT_BACKGROUND_OPACITY = "チャット背景の不透明度" +CHAT_TEXT_OPACITY = "チャット文字の不透明度" +CHAT_LIFETIME = "メッセージ表示時間" +CHAT_CHAR_COUNTER = "チャットの文字数カウンターを表示" +CHAT_CLOSED_MODE = "チャット履歴の表示" +CHAT_CLOSED_DISABLED = "非表示" +CHAT_CLOSED_LIFETIME = "非表示まで: %us" +CHAT_CLOSED_ALWAYS = "常に表示" +CHAT_SHIFT_HINT = "微調整にはShiftキーを押し続けてください" +CHAT_SHIFT_HINT_ACTIVE = "微調整が有効です" + [INFORMATION] INFORMATION_TITLE = "INFO" CHANGELOG = "変更履歴" @@ -344,6 +374,7 @@ OPTIONS = "OPTIONS" PLAYER = "プレイヤー" CAMERA = "カメラ" CONTROLS = "操作" +CHAT = "チャット" DISPLAY = "ディスプレイ" SOUND = "サウンド" MISC = "その他" diff --git a/lang/Polish.ini b/lang/Polish.ini index cb983027d..8208f62ca 100644 --- a/lang/Polish.ini +++ b/lang/Polish.ini @@ -58,6 +58,8 @@ MOD_DESC = "/moderator [NAME|ID] - Umożliwia temu graczowi korzystanie z polece NAMETAGS_DESC = "/nametags [show-tag|show-health] - Zmień, czy widzisz swój identyfikator i czy widzisz zdrowie" UNRECOGNIZED = "Nieznane polecenie czatu." MOD_GRANTED = "\\#fff982\\Jesteś teraz Moderatorem." +ALL_COMMANDS = "Wszystkie komendy" +TAB_COMPLETE_INFO = "Naciśnij TAB, aby autouzupełnić polecenia, użyj Shift+TAB, aby cofnąć się" [MENU] BACK = "Wróć" @@ -106,6 +108,7 @@ DEADZONE = "Martwa Strefa" RUMBLE_STRENGTH = "Siła Wibracji" CHAT = "Czat" +CHAT_COMMAND = "Czat (Komenda)" PLAYERS = "Gracze" D_UP = "Kierunek w Górę" D_DOWN = "Kierunek w Dół" @@ -320,7 +323,6 @@ DEBUG_ERRORS = "Błędy z Debugowania" MISC_TITLE = "POZOSTAŁE OPCJE" PAUSE_IN_SINGLEPLAYER = "Pauza w Trybie Pojedynczego Gracza" DISABLE_POPUPS = "Wyłącz Dymki Powiadomień" -USE_STANDARD_KEY_BINDINGS_CHAT = "Klasyczna Historia Czatu" MENU_OPTIONS = "Opcje Menu" INFORMATION = "Informacja" DEBUG = "Debugowanie" @@ -329,6 +331,34 @@ COOP_COMPATIBILITY = "Włącz kompatybilność z sm64ex-coop" R_BUTTON = "Przycisk R - Opcje" L_BUTTON = "Przycisk L - Przeładuj aktywne mody" +[CHAT_OPTIONS] +CHAT = "CHAT" +USE_STANDARD_KEY_BINDINGS_CHAT = "Użyj sterowania czatu Terminal/CMD" +CHAT_WIDTH = "Szerokość czatu" +CHAT_HEIGHT = "Wysokość czatu" +CHAT_SIZE_MINIMUM = "Minimum" +CHAT_SIZE_VERY_TINY = "Malusieńka" +CHAT_SIZE_TINY = "Maleńka" +CHAT_SIZE_VERY_SMALL = "Bardzo mała" +CHAT_SIZE_SMALL = "Mała" +CHAT_SIZE_NORMAL = "Normalna" +CHAT_SIZE_BIG = "Duża" +CHAT_SIZE_VERY_BIG = "Bardzo duża" +CHAT_SIZE_HUGE = "Ogromna" +CHAT_SIZE_VERY_HUGE = "Olbrzymia" +CHAT_SIZE_MAXIMUM = "Maksimum" +CHAT_TEXT_SCALE = "Rozmiar tekstu czatu" +CHAT_BACKGROUND_OPACITY = "Przezroczystość tła czatu" +CHAT_TEXT_OPACITY = "Przezroczystość tekstu czatu" +CHAT_LIFETIME = "Czas wyświetlania wiadomości" +CHAT_CHAR_COUNTER = "Pokaż licznik znaków czatu" +CHAT_CLOSED_MODE = "Wyświetlanie historii czatu" +CHAT_CLOSED_DISABLED = "Wyłączony" +CHAT_CLOSED_LIFETIME = "Ukryj po: %us" +CHAT_CLOSED_ALWAYS = "Zawsze widoczny" +CHAT_SHIFT_HINT = "Przytrzymaj Shift dla precyzyjnej regulacji" +CHAT_SHIFT_HINT_ACTIVE = "Precyzyjna regulacja aktywna" + [INFORMATION] INFORMATION_TITLE = "INFORMACJA" CHANGELOG = "Rejestr Zmian" @@ -344,6 +374,7 @@ OPTIONS = "OPCJE" PLAYER = "Gracz" CAMERA = "Kamera" CONTROLS = "Sterowanie" +CHAT = "Czat" DISPLAY = "Wyświetlanie" SOUND = "Dźwięk" MISC = "Pozostałe Opcje" diff --git a/lang/Portuguese.ini b/lang/Portuguese.ini index d3b9e0c6b..21884263b 100644 --- a/lang/Portuguese.ini +++ b/lang/Portuguese.ini @@ -58,6 +58,8 @@ MOD_DESC = "/moderator [NOME|ID] - Permite que um jogador use comandos como /kic NAMETAGS_DESC = "/nametags [show-tag|show-health] - Altera se você vê sua própria etiqueta ou a barra de vida de outros jogadores" UNRECOGNIZED = "Comando de chat desconhecido." MOD_GRANTED = "\\#fff982\\Você é um(a) moderador(a) agora." +ALL_COMMANDS = "Todos os comandos" +TAB_COMPLETE_INFO = "Pressiona TAB para autocompletar comandos, usa Shift+TAB para navegar para trás" [MENU] BACK = "Voltar" @@ -106,6 +108,7 @@ DEADZONE = "Zona morta" RUMBLE_STRENGTH = "Força de vibração" CHAT = "Chat" +CHAT_COMMAND = "Chat (Comando)" PLAYERS = "Jogadores" D_UP = "D-Cima" D_DOWN = "D-Baixo" @@ -320,7 +323,6 @@ DEBUG_ERRORS = "Erros de debug" MISC_TITLE = "OUTROS" PAUSE_IN_SINGLEPLAYER = "Pausar com apenas um jogador" DISABLE_POPUPS = "Desativar pop-ups" -USE_STANDARD_KEY_BINDINGS_CHAT = "Controles clássicos do chat" MENU_OPTIONS = "Opções de menu" INFORMATION = "Informações" DEBUG = "Debug" @@ -329,6 +331,34 @@ COOP_COMPATIBILITY = "Ativar a compatibilidade com sm64ex-coop" R_BUTTON = "Botão R - Opções" L_BUTTON = "Botão L - Recarregar mods ativos" +[CHAT_OPTIONS] +CHAT = "CHAT" +USE_STANDARD_KEY_BINDINGS_CHAT = "Usar controles de chat Terminal/CMD" +CHAT_WIDTH = "Largura do chat" +CHAT_HEIGHT = "Altura do chat" +CHAT_SIZE_MINIMUM = "Mínimo" +CHAT_SIZE_VERY_TINY = "Muito minúsculo" +CHAT_SIZE_TINY = "Minúsculo" +CHAT_SIZE_VERY_SMALL = "Muito pequena" +CHAT_SIZE_SMALL = "Pequena" +CHAT_SIZE_NORMAL = "Normal" +CHAT_SIZE_BIG = "Grande" +CHAT_SIZE_VERY_BIG = "Muito grande" +CHAT_SIZE_HUGE = "Enorme" +CHAT_SIZE_VERY_HUGE = "Enorme demais" +CHAT_SIZE_MAXIMUM = "Máximo" +CHAT_TEXT_SCALE = "Tamanho do texto do chat" +CHAT_BACKGROUND_OPACITY = "Opacidade do fundo do chat" +CHAT_TEXT_OPACITY = "Opacidade do texto do chat" +CHAT_LIFETIME = "Duração da mensagem do chat" +CHAT_CHAR_COUNTER = "Mostrar contador de caracteres do chat" +CHAT_CLOSED_MODE = "Exibir histórico do chat" +CHAT_CLOSED_DISABLED = "Oculto" +CHAT_CLOSED_LIFETIME = "Ocultar após: %us" +CHAT_CLOSED_ALWAYS = "Sempre visível" +CHAT_SHIFT_HINT = "Mantenha Shift pressionado para ajuste fino" +CHAT_SHIFT_HINT_ACTIVE = "Ajuste fino ativo" + [INFORMATION] INFORMATION_TITLE = "INFORMAÇÃO" CHANGELOG = "Registro de alterações" @@ -344,6 +374,7 @@ OPTIONS = "OPÇÕES" PLAYER = "Jogador" CAMERA = "Câmera" CONTROLS = "Controles" +CHAT = "Chat" DISPLAY = "Vídeo" SOUND = "Som" MISC = "Outros" diff --git a/lang/Russian.ini b/lang/Russian.ini index 85d39ae37..6aec1b3df 100644 --- a/lang/Russian.ini +++ b/lang/Russian.ini @@ -58,6 +58,8 @@ MOD_DESC = "/moderator [NAME|ID] - Разрешить игроку исполь NAMETAGS_DESC = "/nametags [show-tag|show-health] - Измените, видите ли вы свой собственный тег и видите ли здоровье" UNRECOGNIZED = "Неизвестная команда чата." MOD_GRANTED = "\\#fff982\\Теперь вы модератор." +ALL_COMMANDS = "Все команды" +TAB_COMPLETE_INFO = "Нажми TAB для автодополнения команд, Shift+TAB — переход назад" [MENU] BACK = "Назад" @@ -105,6 +107,7 @@ DEADZONE = "Mёртвая зона" RUMBLE_STRENGTH = "Вибрация" CHAT = "Чат" +CHAT_COMMAND = "Чат (Команда)" PLAYERS = "Игроки" D_UP = "Крестовина вверх" D_DOWN = "Крестовина вниз" @@ -319,7 +322,6 @@ DEBUG_ERRORS = "Ошибки отладки" MISC_TITLE = "MISC" PAUSE_IN_SINGLEPLAYER = "Пауза в одиночной игре" DISABLE_POPUPS = "Отключить всплывающие окна" -USE_STANDARD_KEY_BINDINGS_CHAT = "Классическое управление чатом" MENU_OPTIONS = "Параметры меню" INFORMATION = "Информация" DEBUG = "Отладка" @@ -328,6 +330,33 @@ COOP_COMPATIBILITY = "Включить совместимость sm64ex-coop" R_BUTTON = "Кнопка R - Опции" L_BUTTON = "Кнопка L - Перезагрузить активные моды" +[CHAT_OPTIONS] +USE_STANDARD_KEY_BINDINGS_CHAT = "Использовать управление чатом Terminal/CMD" +CHAT_WIDTH = "Ширина чата" +CHAT_HEIGHT = "Высота чата" +CHAT_SIZE_MINIMUM = "Минимум" +CHAT_SIZE_VERY_TINY = "Крошечнейшая" +CHAT_SIZE_TINY = "Крошечная" +CHAT_SIZE_VERY_SMALL = "Очень маленькая" +CHAT_SIZE_SMALL = "Маленькая" +CHAT_SIZE_NORMAL = "Обычная" +CHAT_SIZE_BIG = "Большая" +CHAT_SIZE_VERY_BIG = "Очень большая" +CHAT_SIZE_HUGE = "Огромная" +CHAT_SIZE_VERY_HUGE = "Гигантская" +CHAT_SIZE_MAXIMUM = "Максимум" +CHAT_TEXT_SCALE = "Размер текста чата" +CHAT_BACKGROUND_OPACITY = "Прозрачность фона чата" +CHAT_TEXT_OPACITY = "Прозрачность текста чата" +CHAT_LIFETIME = "Время показа сообщений" +CHAT_CHAR_COUNTER = "Показывать счётчик символов чата" +CHAT_CLOSED_MODE = "Показывать историю чата" +CHAT_CLOSED_DISABLED = "Скрыт" +CHAT_CLOSED_LIFETIME = "Скрывать через: %us" +CHAT_CLOSED_ALWAYS = "Всегда виден" +CHAT_SHIFT_HINT = "Удерживайте Shift для точной настройки" +CHAT_SHIFT_HINT_ACTIVE = "Точная настройка активна" + [INFORMATION] INFORMATION_TITLE = "INFORMATION" CHANGELOG = "Журнал изменений" @@ -343,6 +372,7 @@ OPTIONS = "OPTIONS" PLAYER = "Игрок" CAMERA = "Камера" CONTROLS = "Управление" +CHAT = "Чат" DISPLAY = "Дисплей" SOUND = "Звук" MISC = "Разное" diff --git a/lang/Spanish.ini b/lang/Spanish.ini index 50660a637..d86080379 100644 --- a/lang/Spanish.ini +++ b/lang/Spanish.ini @@ -58,6 +58,8 @@ MOD_DESC = "/moderator [NOMBRE|ID] - Permite a un jugador usar comandos como /ki NAMETAGS_DESC = "/nametags [show-tag|show-health] - Cambia si ves tu propia etiqueta y si ves la salud de los demás." UNRECOGNIZED = "Comando desconocido." MOD_GRANTED = "\\#fff982\\Ahora eres moderador." +ALL_COMMANDS = "Todos los comandos" +TAB_COMPLETE_INFO = "Pulsa TAB para autocompletar comandos, usa Shift+TAB para retroceder" [MENU] BACK = "Volver" @@ -106,6 +108,7 @@ DEADZONE = "Zona muerta" RUMBLE_STRENGTH = "Intensidad de vibración" CHAT = "Chat" +CHAT_COMMAND = "Chat (Comando)" PLAYERS = "Jugadores" D_UP = "Dpad Arriba" D_DOWN = "Dpad Abajo" @@ -320,7 +323,6 @@ DEBUG_ERRORS = "Errores de Depuración" MISC_TITLE = "OTROS" PAUSE_IN_SINGLEPLAYER = "Pausa en modo de un jugador" DISABLE_POPUPS = "Deshabilitar mensajes emergentes" -USE_STANDARD_KEY_BINDINGS_CHAT = "Controles de chat clásicos" MENU_OPTIONS = "Opciones del menú" INFORMATION = "Información" DEBUG = "Depuración" @@ -329,6 +331,34 @@ COOP_COMPATIBILITY = "Habilitar la compatibilidad con sm64ex-coop" R_BUTTON = "Botón R - Opciones" L_BUTTON = "Botón L - Recargar mods activos" +[CHAT_OPTIONS] +CHAT = "CHAT" +USE_STANDARD_KEY_BINDINGS_CHAT = "Usar controles de chat Terminal/CMD" +CHAT_WIDTH = "Ancho del chat" +CHAT_HEIGHT = "Altura del chat" +CHAT_SIZE_MINIMUM = "Mínimo" +CHAT_SIZE_VERY_TINY = "Muy minúsculo" +CHAT_SIZE_TINY = "Minúsculo" +CHAT_SIZE_VERY_SMALL = "Muy pequeño" +CHAT_SIZE_SMALL = "Pequeño" +CHAT_SIZE_NORMAL = "Normal" +CHAT_SIZE_BIG = "Grande" +CHAT_SIZE_VERY_BIG = "Muy grande" +CHAT_SIZE_HUGE = "Enorme" +CHAT_SIZE_VERY_HUGE = "Enorme+" +CHAT_SIZE_MAXIMUM = "Máximo" +CHAT_TEXT_SCALE = "Tamaño de texto del chat" +CHAT_BACKGROUND_OPACITY = "Opacidad del fondo del chat" +CHAT_TEXT_OPACITY = "Opacidad del texto del chat" +CHAT_LIFETIME = "Duración del mensaje de chat" +CHAT_CHAR_COUNTER = "Mostrar contador de caracteres del chat" +CHAT_CLOSED_MODE = "Mostrar historial de chat" +CHAT_CLOSED_DISABLED = "Oculto" +CHAT_CLOSED_LIFETIME = "Ocultar tras: %us" +CHAT_CLOSED_ALWAYS = "Siempre visible" +CHAT_SHIFT_HINT = "Mantén presionado Shift para ajuste fino" +CHAT_SHIFT_HINT_ACTIVE = "Ajuste fino activo" + [INFORMATION] INFORMATION_TITLE = "INFORMACIÓN" CHANGELOG = "Registro de\ncambios" @@ -344,6 +374,7 @@ OPTIONS = "OPCIONES" PLAYER = "Jugador" CAMERA = "Cámara" CONTROLS = "Controles" +CHAT = "Chat" DISPLAY = "Pantalla" SOUND = "Sonido" MISC = "Otros" diff --git a/mods/personal-starcount-ex.lua b/mods/personal-starcount-ex.lua index 6709a4216..37d8ff4bb 100644 --- a/mods/personal-starcount-ex.lua +++ b/mods/personal-starcount-ex.lua @@ -300,7 +300,7 @@ hook_event(HOOK_ON_INTERACT, star_counter_on_interact) hook_event(HOOK_ON_HUD_RENDER, hud_render_psc) hook_event(HOOK_ON_HUD_RENDER_BEHIND, behind_hud_render_psc) hook_event(HOOK_UPDATE, psc_update) -hook_chat_command('psc', "On|Off - Displays stars you've collected. Default is On.", toggle_psc) +hook_chat_command('psc', "[On|Off] - Displays stars you've collected. Default is On.", toggle_psc) -- Globalize functions for other mods to use -- Created by PeachyPeach diff --git a/src/pc/configfile.c b/src/pc/configfile.c index 4e52b50b6..3cf2c3e6f 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -4,6 +4,9 @@ #include #include #include +#ifdef _WIN32 +#include +#endif #include #include "platform.h" @@ -114,6 +117,7 @@ unsigned int configKeyStickDown[MAX_BINDS] = { 0x001F, VK_INVALID, VK unsigned int configKeyStickLeft[MAX_BINDS] = { 0x001E, VK_INVALID, VK_INVALID }; unsigned int configKeyStickRight[MAX_BINDS] = { 0x0020, VK_INVALID, VK_INVALID }; unsigned int configKeyChat[MAX_BINDS] = { 0x001C, VK_INVALID, VK_INVALID }; +unsigned int configKeyChatCommand[MAX_BINDS] = { VK_INVALID, VK_INVALID, VK_INVALID }; unsigned int configKeyPlayerList[MAX_BINDS] = { 0x000F, 0x1004, VK_INVALID }; unsigned int configKeyDUp[MAX_BINDS] = { 0x0147, 0x100b, VK_INVALID }; unsigned int configKeyDDown[MAX_BINDS] = { 0x014f, 0x100c, VK_INVALID }; @@ -129,7 +133,15 @@ unsigned int configGamepadNumber = 0; bool configBackgroundGamepad = true; bool configExtendedReports = false; bool configDisableGamepads = false; -bool configUseStandardKeyBindingsChat = false; +bool configUseStandardKeyBindingsChat = true; +bool configChatCharCounter = true; +unsigned int configChatClosedMode = 1; +unsigned int configChatWidth = 800; +unsigned int configChatHeight = 400; +unsigned int configChatTextScale = 100; +unsigned int configChatBackgroundOpacity = 70; +unsigned int configChatTextOpacity = 100; +unsigned int configChatMessageLifetime = 10; bool configSmoothScrolling = false; // free camera settings bool configEnableFreeCamera = false; @@ -258,6 +270,7 @@ static const struct ConfigOption options[] = { {.name = "key_stickleft", .type = CONFIG_TYPE_BIND, .uintValue = configKeyStickLeft}, {.name = "key_stickright", .type = CONFIG_TYPE_BIND, .uintValue = configKeyStickRight}, {.name = "key_chat", .type = CONFIG_TYPE_BIND, .uintValue = configKeyChat}, + {.name = "key_chat_command", .type = CONFIG_TYPE_BIND, .uintValue = configKeyChatCommand}, {.name = "key_playerlist", .type = CONFIG_TYPE_BIND, .uintValue = configKeyPlayerList}, {.name = "key_dup", .type = CONFIG_TYPE_BIND, .uintValue = configKeyDUp}, {.name = "key_ddown", .type = CONFIG_TYPE_BIND, .uintValue = configKeyDDown}, @@ -276,6 +289,14 @@ static const struct ConfigOption options[] = { {.name = "disable_gamepads", .type = CONFIG_TYPE_BOOL, .boolValue = &configDisableGamepads}, #endif {.name = "use_standard_key_bindings_chat", .type = CONFIG_TYPE_BOOL, .boolValue = &configUseStandardKeyBindingsChat}, + {.name = "chat_width", .type = CONFIG_TYPE_UINT, .uintValue = &configChatWidth}, + {.name = "chat_height", .type = CONFIG_TYPE_UINT, .uintValue = &configChatHeight}, + {.name = "chat_text_scale", .type = CONFIG_TYPE_UINT, .uintValue = &configChatTextScale}, + {.name = "chat_background_opacity", .type = CONFIG_TYPE_UINT, .uintValue = &configChatBackgroundOpacity}, + {.name = "chat_text_opacity", .type = CONFIG_TYPE_UINT, .uintValue = &configChatTextOpacity}, + {.name = "chat_message_lifetime", .type = CONFIG_TYPE_UINT, .uintValue = &configChatMessageLifetime}, + {.name = "chat_closed_mode", .type = CONFIG_TYPE_UINT, .uintValue = &configChatClosedMode}, + {.name = "chat_char_counter", .type = CONFIG_TYPE_BOOL, .boolValue = &configChatCharCounter}, {.name = "smooth_scrolling", .type = CONFIG_TYPE_BOOL, .boolValue = &configSmoothScrolling}, {.name = "stick_rotate_left", .type = CONFIG_TYPE_BOOL, .boolValue = &configStick.rotateLeft}, {.name = "stick_invert_left_x", .type = CONFIG_TYPE_BOOL, .boolValue = &configStick.invertLeftX}, @@ -668,6 +689,23 @@ static void configfile_load_internal(const char *filename, bool* error) { if (file == NULL) { // Create a new config file and save defaults printf("Config file '%s' not found. Creating it.\n", filename); + // set sensible default for chat command key depending on keyboard layout + if (configKeyChatCommand[0] == VK_INVALID && configKeyChatCommand[1] == VK_INVALID && configKeyChatCommand[2] == VK_INVALID) { +#ifdef _WIN32 + HKL hkl = GetKeyboardLayout(0); + LANGID lang = LOWORD(hkl); + switch (PRIMARYLANGID(lang)) { + case LANG_GERMAN: + configKeyChatCommand[0] = 0x002B; // '#' on QWERTZ (OEM_5 position) + break; + default: + configKeyChatCommand[0] = 0x0035; // '/' on US QWERTY + break; + } +#else + configKeyChatCommand[0] = 0x0035; // '/' default on non-Windows +#endif + } configfile_save(filename); return; } @@ -779,6 +817,23 @@ NEXT_OPTION: } fs_close(file); + // If user has no chat command bind yet, set a default based on layout + if (configKeyChatCommand[0] == VK_INVALID && configKeyChatCommand[1] == VK_INVALID && configKeyChatCommand[2] == VK_INVALID) { +#ifdef _WIN32 + HKL hkl = GetKeyboardLayout(0); + LANGID lang = LOWORD(hkl); + switch (PRIMARYLANGID(lang)) { + case LANG_GERMAN: + configKeyChatCommand[0] = 0x002B; // '#' + break; + default: + configKeyChatCommand[0] = 0x0035; // '/' + break; + } +#else + configKeyChatCommand[0] = 0x0035; +#endif + } if (configFramerateMode < 0 || configFramerateMode > RRM_MAX) { configFramerateMode = 0; } if (configFrameLimit < 30) { configFrameLimit = 30; } diff --git a/src/pc/configfile.h b/src/pc/configfile.h index 11cdbd5bc..115119218 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -80,6 +80,7 @@ extern unsigned int configKeyStickDown[MAX_BINDS]; extern unsigned int configKeyStickLeft[MAX_BINDS]; extern unsigned int configKeyStickRight[MAX_BINDS]; extern unsigned int configKeyChat[MAX_BINDS]; +extern unsigned int configKeyChatCommand[MAX_BINDS]; extern unsigned int configKeyPlayerList[MAX_BINDS]; extern unsigned int configKeyDUp[MAX_BINDS]; extern unsigned int configKeyDDown[MAX_BINDS]; @@ -96,6 +97,14 @@ extern bool configBackgroundGamepad; extern bool configExtendedReports; extern bool configDisableGamepads; extern bool configUseStandardKeyBindingsChat; +extern bool configChatCharCounter; +extern unsigned int configChatClosedMode; +extern unsigned int configChatWidth; +extern unsigned int configChatHeight; +extern unsigned int configChatTextScale; +extern unsigned int configChatBackgroundOpacity; +extern unsigned int configChatTextOpacity; +extern unsigned int configChatMessageLifetime; extern bool configSmoothScrolling; // free camera settings extern bool configEnableFreeCamera; diff --git a/src/pc/djui/djui_chat_box.c b/src/pc/djui/djui_chat_box.c index bddb52f6d..f0e16387d 100644 --- a/src/pc/djui/djui_chat_box.c +++ b/src/pc/djui/djui_chat_box.c @@ -54,6 +54,11 @@ void sent_history_init(ArrayList *arrayList) { void sent_history_add_message(ArrayList *arrayList, const char *newMessage) { if (!configUseStandardKeyBindingsChat && (!newMessage || newMessage[0] != '/')) { return; } + // Don't add duplicate messages - check if the new message is the same as the last one + if (arrayList->size > 0 && strcmp(arrayList->messages[arrayList->size - 1], newMessage) == 0) { + return; + } + if (arrayList->size == MAX_HISTORY_SIZE) { for (s32 i = 1; i < MAX_HISTORY_SIZE; i++) { snprintf(arrayList->messages[i-1], MAX_CHAT_MSG_LENGTH, "%s", arrayList->messages[i]); @@ -100,7 +105,7 @@ void sent_history_reset_navigation(ArrayList *arrayList) { bool djui_chat_box_render(struct DjuiBase* base) { struct DjuiChatBox* chatBox = (struct DjuiChatBox*)base; struct DjuiBase* ccBase = &chatBox->chatContainer->base; - djui_base_set_size(ccBase, 1.0f, chatBox->base.comp.height - 32 - 8); + djui_base_set_size(ccBase, 1.0f, chatBox->base.comp.height - 32 - 18); if (chatBox->scrolling) { f32 yMax = chatBox->chatContainer->base.elem.height - chatBox->chatFlow->base.height.value; f32 target = chatBox->chatFlow->base.y.value + (chatBox->scrollY - chatBox->chatFlow->base.y.value) * (configSmoothScrolling ? 0.5f : 1.f); @@ -130,7 +135,15 @@ static void djui_chat_box_set_focus_style(void) { djui_interactable_set_input_focus(&gDjuiChatBox->chatInput->base); } - djui_base_set_color(&gDjuiChatBox->chatFlow->base, 0, 0, 0, gDjuiChatBoxFocus ? 128 : 0); + bool hasMessages = (gDjuiChatBox->chatFlow->base.height.value > 2.0f); + u8 alpha = 0; + if (hasMessages) { + int baseAlpha = (int)(configChatBackgroundOpacity * 2.55f); + if (baseAlpha > 255) { baseAlpha = 255; } + if (baseAlpha < 0) { baseAlpha = 0; } + alpha = gDjuiChatBoxFocus ? (u8)baseAlpha : 0; + } + djui_base_set_color(&gDjuiChatBox->chatFlow->base, 0, 0, 0, alpha); } static void djui_chat_box_input_enter(struct DjuiInputbox* chatInput) { @@ -140,6 +153,10 @@ static void djui_chat_box_input_enter(struct DjuiInputbox* chatInput) { sent_history_add_message(&sentHistory, chatInput->buffer); if (chatInput->buffer[0] == '/') { if (strcmp(chatInput->buffer, "/help") == 0 || strcmp(chatInput->buffer, "/?") == 0 || strcmp(chatInput->buffer, "/") == 0) { + char tabcompletionHint[MAX_CHAT_MSG_LENGTH]; + snprintf(tabcompletionHint, sizeof(tabcompletionHint), "\\#ff2020\\%s \\#ffa020\\(%s)\\#ff2020\\:\\#000000\\", + DLANG(CHAT, ALL_COMMANDS), DLANG(CHAT, TAB_COMPLETE_INFO)); + djui_chat_message_create(tabcompletionHint); display_chat_commands(); } else if (!exec_chat_command(chatInput->buffer)) { char extendedUnknownCommandMessage[MAX_CHAT_MSG_LENGTH]; @@ -176,7 +193,7 @@ static char* get_main_command_from_input(const char* input) { return command; } -static bool complete_subcommand(const char* mainCommand, const char* subCommandPrefix) { +static bool complete_subcommand(const char* mainCommand, const char* subCommandPrefix, bool reverse) { char** subcommands = smlua_get_chat_subcommands_list(mainCommand); if (!subcommands || !subcommands[0]) { @@ -192,7 +209,13 @@ static bool complete_subcommand(const char* mainCommand, const char* subCommandP bool completionSuccess = false; if (foundSubCommandsCount > 0) { - sCommandsTabCompletionIndex = (sCommandsTabCompletionIndex + 1) % foundSubCommandsCount; + if (reverse) { + sCommandsTabCompletionIndex = (sCommandsTabCompletionIndex <= 0) + ? foundSubCommandsCount - 1 + : (sCommandsTabCompletionIndex - 1) % foundSubCommandsCount; + } else { + sCommandsTabCompletionIndex = (sCommandsTabCompletionIndex + 1) % foundSubCommandsCount; + } s32 currentIndex = 0; for (s32 i = 0; subcommands[i] != NULL; i++) { @@ -273,7 +296,7 @@ void djui_inputbox_replace_current_word(struct DjuiInputbox* inputbox, char* tex djui_inputbox_move_cursor_to_position(inputbox, currentWordStart + strlen(text)); } -static bool complete_player_name(const char* namePrefix) { +static bool complete_player_name(const char* namePrefix, bool reverse) { char** playerNames = smlua_get_chat_player_list(); if (!playerNames || !playerNames[0]) { if (playerNames) { @@ -291,7 +314,13 @@ static bool complete_player_name(const char* namePrefix) { bool completionSuccess = false; if (foundNamesCount > 0) { - sPlayersTabCompletionIndex = (sPlayersTabCompletionIndex + 1) % foundNamesCount; + if (reverse) { + sPlayersTabCompletionIndex = (sPlayersTabCompletionIndex <= 0) + ? foundNamesCount - 1 + : (sPlayersTabCompletionIndex - 1) % foundNamesCount; + } else { + sPlayersTabCompletionIndex = (sPlayersTabCompletionIndex + 1) % foundNamesCount; + } s32 currentIndex = 0; for (s32 i = 0; playerNames[i] != NULL; i++) { @@ -314,14 +343,83 @@ static bool complete_player_name(const char* namePrefix) { return completionSuccess; } -static void handle_tab_completion(void) { +char* get_next_tab_completion_preview(const char* input) { + if (input[0] != '/') { + return NULL; + } + + char* spacePosition = strrchr(input, ' '); + if (spacePosition != NULL) { + // Subcommand completion + char* mainCommand = get_main_command_from_input(input); + if (mainCommand) { + char** subcommands = smlua_get_chat_subcommands_list(mainCommand + 1); + if (subcommands && subcommands[0]) { + s32 foundSubCommandsCount = 0; + + // Count matching subcommands + for (s32 i = 0; subcommands[i] != NULL; i++) { + if (strncmp(subcommands[i], spacePosition + 1, strlen(spacePosition + 1)) == 0) { + foundSubCommandsCount++; + } + } + + if (foundSubCommandsCount > 0) { + // Find the first matching subcommand + for (s32 i = 0; subcommands[i] != NULL; i++) { + if (strncmp(subcommands[i], spacePosition + 1, strlen(spacePosition + 1)) == 0) { + char* preview = malloc(MAX_CHAT_MSG_LENGTH); + // Only show the missing part of the subcommand + char* inputSubcommand = spacePosition + 1; + char* missingPart = subcommands[i] + strlen(inputSubcommand); + snprintf(preview, MAX_CHAT_MSG_LENGTH, "%s", missingPart); + free(mainCommand); + return preview; + } + } + } + } + free(mainCommand); + } + } else { + // Main command completion + char* bufferWithoutSlash = (char*)input + 1; + char** commands = smlua_get_chat_maincommands_list(); + if (commands && commands[0]) { + s32 foundCommandsCount = 0; + + // Count matching commands + for (s32 i = 0; commands[i] != NULL; i++) { + if (strncmp(commands[i], bufferWithoutSlash, strlen(bufferWithoutSlash)) == 0) { + foundCommandsCount++; + } + } + + if (foundCommandsCount > 0) { + // Find the first matching command + for (s32 i = 0; commands[i] != NULL; i++) { + if (strncmp(commands[i], bufferWithoutSlash, strlen(bufferWithoutSlash)) == 0) { + char* preview = malloc(MAX_CHAT_MSG_LENGTH); + // Only show the missing part of the command + snprintf(preview, MAX_CHAT_MSG_LENGTH, "%s", commands[i] + strlen(bufferWithoutSlash)); + return preview; + } + } + } + } + } + + return NULL; +} + +static void handle_tab_completion(bool reverse) { bool alreadyTabCompleted = false; if (gDjuiChatBox->chatInput->buffer[0] == '/') { char* spacePosition = strrchr(sCommandsTabCompletionOriginalText, ' '); if (spacePosition != NULL) { char* mainCommand = get_main_command_from_input(sCommandsTabCompletionOriginalText); if (mainCommand) { - if (!complete_subcommand(mainCommand + 1, spacePosition + 1)) { + if (!complete_subcommand(mainCommand + 1, spacePosition + 1, reverse)) { reset_tab_completion_all(); } else { alreadyTabCompleted = true; @@ -344,7 +442,13 @@ static void handle_tab_completion(void) { } if (foundCommandsCount > 0) { - sCommandsTabCompletionIndex = (sCommandsTabCompletionIndex + 1) % foundCommandsCount; + if (reverse) { + sCommandsTabCompletionIndex = (sCommandsTabCompletionIndex <= 0) + ? foundCommandsCount - 1 + : (sCommandsTabCompletionIndex - 1) % foundCommandsCount; + } else { + sCommandsTabCompletionIndex = (sCommandsTabCompletionIndex + 1) % foundCommandsCount; + } s32 currentIndex = 0; for (s32 i = 0; commands[i] != NULL; i++) { @@ -364,7 +468,7 @@ static void handle_tab_completion(void) { if (spacePositionB != NULL) { char* mainCommandB = get_main_command_from_input(sCommandsTabCompletionOriginalText); if (mainCommandB) { - if (!complete_subcommand(mainCommandB + 1, spacePositionB + 1)) { + if (!complete_subcommand(mainCommandB + 1, spacePositionB + 1, reverse)) { reset_tab_completion_all(); } else { alreadyTabCompleted = true; @@ -404,7 +508,7 @@ static void handle_tab_completion(void) { if (sPlayersTabCompletionIndex == -1) { snprintf(sPlayersTabCompletionOriginalText, MAX_CHAT_MSG_LENGTH, "%s", wordInfo.word); } - if (!complete_player_name(sPlayersTabCompletionOriginalText)) { + if (!complete_player_name(sPlayersTabCompletionOriginalText, reverse)) { reset_tab_completion_players(); } else { alreadyTabCompleted = true; @@ -457,7 +561,7 @@ static bool djui_chat_box_input_on_key_down(UNUSED struct DjuiBase* base, int sc gDjuiChatBox->scrollY -= pageAmount; break; case SCANCODE_TAB: - handle_tab_completion(); + handle_tab_completion(gDjuiInputHeldShift); return true; case SCANCODE_ENTER: reset_tab_completion_all(); @@ -517,7 +621,21 @@ void djui_chat_box_toggle(void) { gDjuiChatBoxFocus = !gDjuiChatBoxFocus; djui_chat_box_set_focus_style(); gDjuiChatBox->scrolling = false; - gDjuiChatBox->chatFlow->base.y.value = gDjuiChatBox->chatContainer->base.elem.height - gDjuiChatBox->chatFlow->base.height.value; + f32 containerHeight = gDjuiChatBox->base.height.value - 32.0f - 18.0f; + gDjuiChatBox->chatFlow->base.y.value = containerHeight - gDjuiChatBox->chatFlow->base.height.value; +} + +void djui_chat_box_open_with_text(const char* text) { + if (gDjuiChatBox == NULL) { return; } + if (!gDjuiChatBoxFocus) { + sDjuiChatBoxClearText = false; + gDjuiChatBoxFocus = true; + djui_chat_box_set_focus_style(); + } + if (gDjuiChatBox->chatInput != NULL && text != NULL) { + djui_inputbox_set_text(gDjuiChatBox->chatInput, (char*)text); + djui_inputbox_move_cursor_to_end(gDjuiChatBox->chatInput); + } } struct DjuiChatBox* djui_chat_box_create(void) { @@ -531,7 +649,7 @@ struct DjuiChatBox* djui_chat_box_create(void) { djui_base_init(&gDjuiRoot->base, base, djui_chat_box_render, djui_chat_box_destroy); djui_base_set_size_type(base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); - djui_base_set_size(base, 600, 400); + djui_base_set_size(base, configChatWidth, configChatHeight); djui_base_set_alignment(base, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM); djui_base_set_color(base, 0, 0, 0, 0); djui_base_set_padding(base, 0, 8, 8, 8); @@ -545,12 +663,12 @@ struct DjuiChatBox* djui_chat_box_create(void) { struct DjuiFlowLayout* chatFlow = djui_flow_layout_create(ccBase); struct DjuiBase* cfBase = &chatFlow->base; - djui_base_set_location(cfBase, 0, 0); + djui_base_set_location(cfBase, 0, 8); djui_base_set_size_type(cfBase, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size(cfBase, 1.0f, 2); - djui_base_set_color(cfBase, 0, 0, 0, 128); - djui_base_set_padding(cfBase, 2, 2, 2, 2); - djui_flow_layout_set_margin(chatFlow, 2); + djui_base_set_color(cfBase, 0, 0, 0, 64); + djui_base_set_padding(cfBase, 0, 2, 0, 2); + djui_flow_layout_set_margin(chatFlow, 0); djui_flow_layout_set_flow_direction(chatFlow, DJUI_FLOW_DIR_UP); cfBase->addChildrenToHead = true; cfBase->abandonAfterChildRenderFail = true; @@ -561,6 +679,9 @@ struct DjuiChatBox* djui_chat_box_create(void) { djui_base_set_size_type(ciBase, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size(ciBase, 1.0f, 32); djui_base_set_alignment(ciBase, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM); + djui_base_set_location(ciBase, 0, 0); + djui_base_set_border_width(ciBase, 0); + djui_interactable_hook_key(&chatInput->base, djui_chat_box_input_on_key_down, djui_inputbox_on_key_up); djui_interactable_hook_text_input(&chatInput->base, djui_chat_box_input_on_text_input); djui_interactable_hook_text_editing(&chatInput->base, djui_chat_box_input_on_text_editing); diff --git a/src/pc/djui/djui_chat_box.h b/src/pc/djui/djui_chat_box.h index 1c5a7d150..5bed791c8 100644 --- a/src/pc/djui/djui_chat_box.h +++ b/src/pc/djui/djui_chat_box.h @@ -14,4 +14,6 @@ extern struct DjuiChatBox* gDjuiChatBox; extern bool gDjuiChatBoxFocus; void djui_chat_box_toggle(void); +void djui_chat_box_open_with_text(const char* text); +char* get_next_tab_completion_preview(const char* input); struct DjuiChatBox* djui_chat_box_create(void); diff --git a/src/pc/djui/djui_chat_message.c b/src/pc/djui/djui_chat_message.c index dd299af34..0c0d0b958 100644 --- a/src/pc/djui/djui_chat_message.c +++ b/src/pc/djui/djui_chat_message.c @@ -8,34 +8,58 @@ #include "djui_hud_utils.h" #include "pc/debuglog.h" #include "pc/lua/smlua_hooks.h" +#include "pc/configfile.h" -#define DJUI_CHAT_LIFE_TIME 10.0f +#define DJUI_CHAT_LIFE_TIME_DEFAULT 10.0f static bool djui_chat_message_render(struct DjuiBase* base) { struct DjuiChatMessage* chatMessage = (struct DjuiChatMessage*)base; struct DjuiBase* ctBase = &chatMessage->message->base; - f32 seconds = clock_elapsed() - chatMessage->createTime; f32 f = 1.0f; - if (seconds >= (DJUI_CHAT_LIFE_TIME - 1)) { - f = fmax(1.0f - (seconds - (DJUI_CHAT_LIFE_TIME - 1)), 0.0f); - f *= f; - f *= f; + + if (!gDjuiChatBoxFocus) { + u32 mode = configChatClosedMode; + if (mode > 2) { mode = 1; } + + if (mode == 0) { + return false; + } + + if (mode == 1) { + f32 lifeTime = (f32)configChatMessageLifetime; + if (lifeTime < 1.0f) lifeTime = 1.0f; + if (lifeTime > 120.0f) lifeTime = 120.0f; + + f32 seconds = clock_elapsed() - chatMessage->createTime; + if (seconds >= (lifeTime - 1.0f)) { + f = fmax(1.0f - (seconds - (lifeTime - 1.0f)), 0.0f); + f *= f; + f *= f; + } + if (f <= 0.1f) { + return false; + } + } else { + f = 1.0f; + } + + int bgAlphaI = (int)(configChatBackgroundOpacity * f * 2.55f); + if (bgAlphaI > 255) { bgAlphaI = 255; } + if (bgAlphaI < 0) { bgAlphaI = 0; } + u8 bgAlpha = (u8)bgAlphaI; + + u8 textAlpha = (u8)(255.0f * f * ((f32)configChatTextOpacity / 100.0f)); + + djui_base_set_color(base, 0, 0, 0, bgAlpha); + djui_base_set_color(ctBase, 255, 255, 255, textAlpha); + } else { + djui_base_set_color(base, 0, 0, 0, 0); + djui_base_set_color(ctBase, 255, 255, 255, 255); } - if (gDjuiChatBoxFocus) { - djui_base_set_color(base, 0, 0, 0, 120); - djui_base_set_color(ctBase, 255, 255, 255, 255); - djui_base_set_size_type(base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); - djui_base_set_size(base, 1.0f, chatMessage->base.height.value); - } else if (f <= 0.1f) { - return false; - } else { - djui_base_set_color(base, 0, 0, 0, 180 * f); - djui_base_set_color(ctBase, 255, 255, 255, 255 * f); - djui_base_set_size_type(base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); - djui_base_set_size(base, chatMessage->messageWidth, chatMessage->base.height.value); - } + djui_base_set_size_type(base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(base, 1.0f, chatMessage->base.height.value); djui_text_set_font(chatMessage->message, gDjuiFonts[configDjuiThemeFont == 0 ? FONT_NORMAL : FONT_ALIASED]); @@ -69,6 +93,57 @@ void djui_chat_message_create_from(u8 globalIndex, const char* message) { djui_chat_message_create(chatMsg); } +static void djui_chat_message_apply_style_one(struct DjuiChatMessage* chatMessage) { + struct DjuiBase* base = &chatMessage->base; + + f32 maxTextWidth = gDjuiChatBox->base.width.value + - gDjuiChatBox->base.padding.left.value - gDjuiChatBox->base.padding.right.value + - base->padding.left.value - base->padding.right.value; + + struct DjuiText* chatText = chatMessage->message; + struct DjuiBase* ctBase = &chatText->base; + djui_base_set_size_type(ctBase, DJUI_SVT_ABSOLUTE, DJUI_SVT_RELATIVE); + djui_base_set_size(ctBase, maxTextWidth, 1.0f); + djui_base_set_color(ctBase, 255, 255, 255, 255); + djui_base_set_location(ctBase, 0, 0); + djui_text_set_alignment(chatText, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP); + + // apply text scale based on config + f32 scale = ((f32)configChatTextScale) / 100.0f; + if (scale < 0.5f) { scale = 0.5f; } + if (scale > 2.0f) { scale = 2.0f; } + djui_text_set_font_scale(chatText, chatText->font->defaultFontScale * scale); + + // figure out chat message height + chatText->base.comp.width = maxTextWidth; + f32 messageHeight = djui_text_count_lines(chatText, 10) + * (chatText->font->lineHeight * chatText->font->defaultFontScale * scale) + 8; + djui_base_set_size(base, 1.0f, messageHeight); + + // figure out chat message width + f32 messageWidth = djui_text_find_width(chatText, 10); + chatMessage->messageWidth = messageWidth + 8; +} + +void djui_chat_messages_apply_style(void) { + if (gDjuiChatBox == NULL || gDjuiChatBox->chatFlow == NULL) { return; } + + gDjuiChatBox->chatFlow->base.height.value = 0; + + struct DjuiBaseChild* child = gDjuiChatBox->chatFlow->base.child; + while (child != NULL) { + struct DjuiChatMessage* msg = (struct DjuiChatMessage*)child->base; + djui_chat_message_apply_style_one(msg); + gDjuiChatBox->chatFlow->base.height.value += msg->base.height.value + gDjuiChatBox->chatFlow->margin.value; + child = child->next; + } + + if (!gDjuiChatBox->scrolling) { + f32 containerHeight = gDjuiChatBox->base.height.value - 32.0f - 18.0f; + gDjuiChatBox->chatFlow->base.y.value = containerHeight - gDjuiChatBox->chatFlow->base.height.value; + } +} + void djui_chat_message_create(const char* message) { if (gDjuiChatBox == NULL || gDjuiChatBox->chatFlow == NULL) { return; } struct DjuiChatMessage* chatMessage = calloc(1, sizeof(struct DjuiChatMessage)); @@ -76,32 +151,18 @@ void djui_chat_message_create(const char* message) { djui_base_init(&gDjuiChatBox->chatFlow->base, base, djui_chat_message_render, djui_chat_message_destroy); djui_base_set_size_type(base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size(base, 1.0f, 0); - djui_base_set_color(base, 0, 0, 0, 64); - djui_base_set_padding(base, 2, 4, 2, 4); + djui_base_set_color(base, 0, 0, 0, 0); + djui_base_set_padding(base, 0, 4, 0, 4); djui_base_set_alignment(base, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM); - f32 maxTextWidth = gDjuiChatBox->base.width.value - gDjuiChatBox->base.padding.left.value - gDjuiChatBox->base.padding.right.value - base->padding.left.value - base->padding.right.value; - struct DjuiText* chatText = djui_text_create(base, message); - struct DjuiBase* ctBase = &chatText->base; - djui_base_set_size_type(ctBase, DJUI_SVT_ABSOLUTE, DJUI_SVT_RELATIVE); - djui_base_set_size(ctBase, maxTextWidth, 1.0f); - djui_base_set_color(ctBase, 255, 255, 255, 255); - djui_base_set_location(ctBase, 0, 0); - djui_text_set_alignment(chatText, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP); chatMessage->message = chatText; chatMessage->createTime = clock_elapsed(); - // figure out chat message height - chatText->base.comp.width = maxTextWidth; - f32 messageHeight = djui_text_count_lines(chatText, 10) * (chatText->font->lineHeight * chatText->font->defaultFontScale) + 8; - djui_base_set_size(base, 1.0f, messageHeight); - gDjuiChatBox->chatFlow->base.height.value += messageHeight + gDjuiChatBox->chatFlow->margin.value; + djui_chat_message_apply_style_one(chatMessage); + + gDjuiChatBox->chatFlow->base.height.value += chatMessage->base.height.value + gDjuiChatBox->chatFlow->margin.value; if (!gDjuiChatBox->scrolling) { gDjuiChatBox->chatFlow->base.y.value = gDjuiChatBox->chatContainer->base.elem.height - gDjuiChatBox->chatFlow->base.height.value; } - - // figure out chat message width - f32 messageWidth = djui_text_find_width(chatText, 10); - chatMessage->messageWidth = messageWidth + 8; } diff --git a/src/pc/djui/djui_chat_message.h b/src/pc/djui/djui_chat_message.h index cc79c5b00..7bfa59c4b 100644 --- a/src/pc/djui/djui_chat_message.h +++ b/src/pc/djui/djui_chat_message.h @@ -14,3 +14,4 @@ struct DjuiChatMessage { void djui_chat_message_create_from(u8 globalIndex, const char* message); /* |description|Creates a `message` in the game's chat box|descriptionEnd| */ void djui_chat_message_create(const char* message); +void djui_chat_messages_apply_style(void); diff --git a/src/pc/djui/djui_inputbox.c b/src/pc/djui/djui_inputbox.c index c0a911130..4730f5e48 100644 --- a/src/pc/djui/djui_inputbox.c +++ b/src/pc/djui/djui_inputbox.c @@ -3,12 +3,14 @@ #include "djui.h" #include "djui_unicode.h" #include "djui_hud_utils.h" +#include "djui_chat_box.h" #include "pc/gfx/gfx_window_manager_api.h" #include "pc/pc_main.h" #include "game/segment2.h" #include "pc/controller/controller_keyboard.h" +#include "pc/configfile.h" -#define DJUI_INPUTBOX_YOFF (-3) +#define DJUI_INPUTBOX_YOFF (-2) #define DJUI_INPUTBOX_MAX_BLINK 50 #define DJUI_INPUTBOX_MID_BLINK (DJUI_INPUTBOX_MAX_BLINK / 2) #define DJUI_INPUTBOX_CURSOR_WIDTH (2.0f / 32.0f) @@ -20,6 +22,14 @@ static u8 sCursorBlink = 0; static void djui_inputbox_update_style(struct DjuiBase* base) { struct DjuiInputbox* inputbox = (struct DjuiInputbox*)base; + if (gDjuiChatBox != NULL && &gDjuiChatBox->chatInput->base == base) { + djui_base_set_border_width(base, 0); + djui_base_set_border_color(base, 0, 0, 0, 0); + u8 alpha = gDjuiChatBoxFocus ? 200 : 150; + djui_base_set_color(&inputbox->base, 0, 0, 0, alpha); + return; + } + if (!inputbox->base.enabled) { djui_base_set_border_color(base, 90, 90, 90, 255); djui_base_set_color(&inputbox->base, 140, 140, 140, 255); @@ -447,8 +457,63 @@ static void djui_inputbox_render_char(struct DjuiInputbox* inputbox, char* c, f3 *additionalShift += charWidth; } +static void djui_inputbox_render_preview_text(struct DjuiInputbox* inputbox) { + // Always show debug preview when focused (remove all conditions for testing) + if (!djui_interactable_is_input_focus(&inputbox->base)) { + return; + } + + const struct DjuiFont* font = gDjuiFonts[configDjuiThemeFont == 0 ? FONT_NORMAL : FONT_ALIASED]; + struct DjuiBaseRect* comp = &inputbox->base.comp; + + // Calculate current text width + f32 currentTextWidth = 0; + char* c = inputbox->buffer; + while (*c != '\0') { + char* dc = inputbox->passwordChar[0] ? inputbox->passwordChar : c; + currentTextWidth += font->char_width(dc) * font->defaultFontScale; + c = djui_unicode_next_char(c); + } + + // Calculate preview position - use absolute positioning + f32 previewX = comp->x + inputbox->viewX + currentTextWidth + 50; // Add 50px offset + f32 previewY = comp->y + DJUI_INPUTBOX_YOFF + 30; // Move down 30px + + // Apply position translation + djui_gfx_position_translate(&previewX, &previewY); + + // Create translation matrix for the preview text + create_dl_translation_matrix(DJUI_MTX_PUSH, previewX, previewY, 0); + f32 translatedFontSize = font->defaultFontScale; + djui_gfx_size_translate(&translatedFontSize); + create_dl_scale_matrix(DJUI_MTX_NOPUSH, translatedFontSize, translatedFontSize, 1.0f); + + // Set bright red color for debug visibility + gDPSetEnvColor(gDisplayListHead++, 255, 0, 0, 255); + + // Begin font rendering + if (font->textBeginDisplayList != NULL) { + gSPDisplayList(gDisplayListHead++, font->textBeginDisplayList); + } + + // Render debug text + char testText[] = "DEBUG"; + char* testChar = testText; + while (*testChar != '\0') { + font->render_char(testChar); + f32 charWidth = font->char_width(testChar); + previewX += charWidth * font->defaultFontScale; + testChar = djui_unicode_next_char(testChar); + } + + // Clean up matrices + gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); + gSPDisplayList(gDisplayListHead++, dl_ia_text_end); +} + static void djui_inputbox_render_selection(struct DjuiInputbox* inputbox) { const struct DjuiFont* font = gDjuiFonts[configDjuiThemeFont == 0 ? FONT_NORMAL : FONT_ALIASED]; + bool isChatInput = (gDjuiChatBox != NULL && &gDjuiChatBox->chatInput->base == &inputbox->base); // make selection well formed u16 selection[2] = { 0 }; @@ -486,7 +551,11 @@ static void djui_inputbox_render_selection(struct DjuiInputbox* inputbox) { if (sCursorBlink < DJUI_INPUTBOX_MID_BLINK && djui_interactable_is_input_focus(&inputbox->base)) { create_dl_translation_matrix(DJUI_MTX_PUSH, renderX - DJUI_INPUTBOX_CURSOR_WIDTH / 2.0f, -0.1f, 0); create_dl_scale_matrix(DJUI_MTX_NOPUSH, DJUI_INPUTBOX_CURSOR_WIDTH, 0.8f, 1.0f); - gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255); + if (isChatInput) { + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); + } else { + gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255); + } gSPDisplayList(gDisplayListHead++, dl_djui_simple_rect); gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); } @@ -550,9 +619,15 @@ static bool djui_inputbox_render(struct DjuiBase* base) { const struct DjuiFont* font = gDjuiFonts[configDjuiThemeFont == 0 ? FONT_NORMAL : FONT_ALIASED]; djui_rect_render(base); - // Shift the text away from the left side a tad - comp->x += 2; - comp->width -= 2; + bool isChatInput = (gDjuiChatBox != NULL && &gDjuiChatBox->chatInput->base == base); + if (isChatInput) { + comp->x += 6; + comp->y -= 1; + comp->width -= 6; + } else { + comp->x += 2; + comp->width -= 2; + } // shift the viewing window to keep the selection in view djui_inputbox_keep_selection_in_view(inputbox); @@ -560,6 +635,12 @@ static bool djui_inputbox_render(struct DjuiBase* base) { // translate position f32 translatedX = comp->x + inputbox->viewX; f32 translatedY = comp->y + DJUI_INPUTBOX_YOFF; + if (isChatInput) { + f32 lineHeight = font->lineHeight * font->defaultFontScale; + f32 innerHeight = comp->height - base->borderWidth.value * 2; + f32 centerOffset = (innerHeight - lineHeight) * 0.5f; + translatedY += fmaxf(centerOffset, 0.0f); + } djui_gfx_position_translate(&translatedX, &translatedY); create_dl_translation_matrix(DJUI_MTX_PUSH, translatedX, translatedY, 0); @@ -576,8 +657,14 @@ static bool djui_inputbox_render(struct DjuiBase* base) { gSPDisplayList(gDisplayListHead++, font->textBeginDisplayList); } - // set color - gDPSetEnvColor(gDisplayListHead++, inputbox->textColor.r, inputbox->textColor.g, inputbox->textColor.b, inputbox->textColor.a); + // render preview text (for tab completion) - after font setup + // djui_inputbox_render_preview_text(inputbox); + + if (isChatInput) { + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); + } else { + gDPSetEnvColor(gDisplayListHead++, inputbox->textColor.r, inputbox->textColor.g, inputbox->textColor.b, inputbox->textColor.a); + } // make selection well formed u16 selection[2] = { 0 }; @@ -610,7 +697,11 @@ static bool djui_inputbox_render(struct DjuiBase* base) { if (insideSelection && !wasInsideSelection) { gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); } else if (!insideSelection && wasInsideSelection) { - gDPSetEnvColor(gDisplayListHead++, inputbox->textColor.r, inputbox->textColor.g, inputbox->textColor.b, inputbox->textColor.a); + if (isChatInput) { + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); + } else { + gDPSetEnvColor(gDisplayListHead++, inputbox->textColor.r, inputbox->textColor.g, inputbox->textColor.b, inputbox->textColor.a); + } } wasInsideSelection = insideSelection; } @@ -619,10 +710,102 @@ static bool djui_inputbox_render(struct DjuiBase* base) { djui_inputbox_render_char(inputbox, c, &drawX, &additionalShift); c = djui_unicode_next_char(c); } + + // Tab completion preview - show what would happen if TAB was pressed + if (djui_interactable_is_input_focus(&inputbox->base) && inputbox->buffer[0] == '/') { + // Get preview text from tab completion function + extern char* get_next_tab_completion_preview(const char* input); + char* previewText = get_next_tab_completion_preview(inputbox->buffer); + + if (previewText != NULL && strlen(previewText) > 0) { + // Set gray color for preview text + gDPSetEnvColor(gDisplayListHead++, 128, 128, 128, 128); + + // Render preview text at the current position + char* previewChar = previewText; + while (*previewChar != '\0') { + djui_inputbox_render_char(inputbox, previewChar, &drawX, &additionalShift); + previewChar = djui_unicode_next_char(previewChar); + } + + // Free the preview text + free(previewText); + + // Reset color back to normal + gDPSetEnvColor(gDisplayListHead++, inputbox->textColor.r, inputbox->textColor.g, inputbox->textColor.b, inputbox->textColor.a); + } + } font->render_end(); gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); gSPDisplayList(gDisplayListHead++, dl_ia_text_end); + + if (isChatInput && djui_interactable_is_input_focus(&inputbox->base) && configChatCharCounter) { + char charCountText[32]; + int currentLength = djui_unicode_len(inputbox->buffer); + snprintf(charCountText, sizeof(charCountText), "%d", currentLength); + + f32 originalX = comp->x; + f32 originalY = comp->y; + f32 originalWidth = comp->width; + + if (isChatInput) { + originalX -= 6; + originalY += 1; + originalWidth += 6; + } else { + originalX -= 2; + originalWidth += 2; + } + + f32 counterX = originalX + originalWidth + 10 - 3; + f32 counterY = originalY + (comp->height - font->lineHeight * font->defaultFontScale) * 0.5f - 3; + + djui_gfx_position_translate(&counterX, &counterY); + create_dl_translation_matrix(DJUI_MTX_PUSH, counterX, counterY, 0); + + f32 translatedFontSize = font->defaultFontScale; + djui_gfx_size_translate(&translatedFontSize); + create_dl_scale_matrix(DJUI_MTX_NOPUSH, translatedFontSize, translatedFontSize, 1.0f); + + u8 colR = 255, colG = 255, colB = 255; + if (currentLength >= 499) { + colG = 0; colB = 0; + } else if (currentLength >= 256) { + colG = 128; colB = 64; + } else if (currentLength >= 192) { + colG = 192; colB = 64; + } else if (currentLength >= 128) { + colG = 255; colB = 64; + } + gDPSetEnvColor(gDisplayListHead++, colR, colG, colB, 255); + + if (font->textBeginDisplayList != NULL) { + gSPDisplayList(gDisplayListHead++, font->textBeginDisplayList); + } + + char* c = charCountText; + while (*c != '\0') { + font->render_char(c); + f32 cw = font->char_width(c); + create_dl_translation_matrix(DJUI_MTX_NOPUSH, cw, 0, 0); + c = djui_unicode_next_char(c); + } + + gSPDisplayList(gDisplayListHead++, dl_ia_text_end); + + gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); + } + + if (isChatInput) { + comp->x -= 6; + comp->y += 1; + comp->width += 6; + } else { + comp->x -= 2; + comp->width += 2; + } + return true; } diff --git a/src/pc/djui/djui_interactable.c b/src/pc/djui/djui_interactable.c index 96f3acc06..311499755 100644 --- a/src/pc/djui/djui_interactable.c +++ b/src/pc/djui/djui_interactable.c @@ -4,6 +4,7 @@ #include "djui_panel_pause.h" #include "djui_panel_modlist.h" #include "djui_panel_playerlist.h" +#include "djui_panel_chat.h" #include "pc/controller/controller_sdl.h" #include "pc/controller/controller_mouse.h" @@ -198,6 +199,19 @@ bool djui_interactable_on_key_down(int scancode) { return true; } + switch (scancode) { + case SCANCODE_SHIFT_LEFT: gDjuiInputHeldShift |= (1 << 0); break; + case SCANCODE_SHIFT_RIGHT: gDjuiInputHeldShift |= (1 << 1); break; + case SCANCODE_CONTROL_LEFT: gDjuiInputHeldControl |= (1 << 0); break; + case SCANCODE_CONTROL_RIGHT: gDjuiInputHeldControl |= (1 << 1); break; + case SCANCODE_ALT_LEFT: gDjuiInputHeldAlt |= (1 << 0); break; + case SCANCODE_ALT_RIGHT: gDjuiInputHeldAlt |= (1 << 1); break; + } + + if ((scancode == SCANCODE_SHIFT_LEFT || scancode == SCANCODE_SHIFT_RIGHT) && djui_panel_chat_is_shift_hint_visible()) { + djui_panel_chat_update_shift_hint(); + } + bool keyFocused = (gInteractableFocus != NULL) && (gInteractableFocus->interactable != NULL) && (gInteractableFocus->interactable->on_key_down != NULL); @@ -219,14 +233,21 @@ bool djui_interactable_on_key_down(int scancode) { if (gDjuiChatBox != NULL && !gDjuiChatBoxFocus) { bool pressChat = false; + bool pressChatCommand = false; for (int i = 0; i < MAX_BINDS; i++) { if (scancode == (int)configKeyChat[i]) { pressChat = true; } + if (scancode == (int)configKeyChatCommand[i]) { pressChatCommand = true; } } - if (pressChat && !gDjuiConsoleFocus) { + if (pressChat && !gDjuiConsoleFocus && !gDjuiChatBoxFocus) { djui_chat_box_toggle(); return true; } + + if (pressChatCommand && !gDjuiConsoleFocus) { + djui_chat_box_open_with_text("/"); + return true; + } } if ((gDjuiPlayerList != NULL || gDjuiModList != NULL)) { @@ -278,6 +299,18 @@ bool djui_interactable_on_key_down(int scancode) { } void djui_interactable_on_key_up(int scancode) { + switch (scancode) { + case SCANCODE_SHIFT_LEFT: gDjuiInputHeldShift &= ~(1 << 0); break; + case SCANCODE_SHIFT_RIGHT: gDjuiInputHeldShift &= ~(1 << 1); break; + case SCANCODE_CONTROL_LEFT: gDjuiInputHeldControl &= ~(1 << 0); break; + case SCANCODE_CONTROL_RIGHT: gDjuiInputHeldControl &= ~(1 << 1); break; + case SCANCODE_ALT_LEFT: gDjuiInputHeldAlt &= ~(1 << 0); break; + case SCANCODE_ALT_RIGHT: gDjuiInputHeldAlt &= ~(1 << 1); break; + } + + if ((scancode == SCANCODE_SHIFT_LEFT || scancode == SCANCODE_SHIFT_RIGHT) && djui_panel_chat_is_shift_hint_visible()) { + djui_panel_chat_update_shift_hint(); + } if (!gDjuiChatBoxFocus) { for (int i = 0; i < MAX_BINDS; i++) { diff --git a/src/pc/djui/djui_panel_chat.c b/src/pc/djui/djui_panel_chat.c new file mode 100644 index 000000000..b6e9048ad --- /dev/null +++ b/src/pc/djui/djui_panel_chat.c @@ -0,0 +1,531 @@ +#include "djui.h" +#include "djui_panel.h" +#include "djui_panel_menu.h" +#include "djui_selectionbox.h" +#include "pc/utils/misc.h" +#include "pc/configfile.h" + +#define CHAT_WIDTH_DEFAULT 800 +#define CHAT_HEIGHT_DEFAULT 400 +#define CHAT_TEXT_SCALE_DEFAULT 100 +#define CHAT_BG_OPACITY_DEFAULT 70 +#define CHAT_TEXT_OPACITY_DEFAULT 100 +#define CHAT_LIFETIME_DEFAULT 10 +#define CHAT_USE_STD_KEY_BINDINGS_DEFAULT true +#define CHAT_CHAR_COUNTER_DEFAULT true +#define CHAT_CLOSED_MODE_DEFAULT 1 + +static const u8 CHAT_LABEL_LOW_RGB[3] = { 32, 64, 255 }; +static const u8 CHAT_LABEL_DEFAULT_RGB[3] = { 32, 224, 32 }; +static const u8 CHAT_LABEL_HIGH_RGB[3] = { 255, 64, 32 }; + +static struct DjuiSlider* sSliderWidth = NULL; +static struct DjuiSlider* sSliderHeight = NULL; +static struct DjuiSlider* sSliderTextScale = NULL; +static struct DjuiSlider* sSliderBgOpacity = NULL; +static struct DjuiSlider* sSliderTextOpacity = NULL; +static struct DjuiSlider* sSliderLifetime = NULL; + +static struct DjuiCheckbox* sCheckboxUseStdChat = NULL; +static struct DjuiCheckbox* sCheckboxCharCounter = NULL; + +static struct DjuiButton* sResetWidthButton = NULL; +static struct DjuiButton* sResetHeightButton = NULL; +static struct DjuiButton* sResetTextScaleButton = NULL; +static struct DjuiButton* sResetBgOpacityButton = NULL; +static struct DjuiButton* sResetTextOpacityButton = NULL; +static struct DjuiButton* sResetLifetimeButton = NULL; +static struct DjuiButton* sResetUseStdChatButton = NULL; +static struct DjuiButton* sResetCharCounterButton = NULL; +static struct DjuiButton* sResetClosedModeButton = NULL; + +static struct DjuiText* sChatShiftHintText = NULL; + +static void djui_panel_chat_destroy(UNUSED struct DjuiBase* base) { + sChatShiftHintText = NULL; + sSliderWidth = NULL; + sSliderHeight = NULL; + sSliderTextScale = NULL; + sSliderBgOpacity = NULL; + sSliderTextOpacity = NULL; + sSliderLifetime = NULL; + sCheckboxUseStdChat = NULL; + sCheckboxCharCounter = NULL; + sResetWidthButton = NULL; + sResetHeightButton = NULL; + sResetTextScaleButton = NULL; + sResetBgOpacityButton = NULL; + sResetTextOpacityButton = NULL; + sResetLifetimeButton = NULL; + sResetUseStdChatButton = NULL; + sResetCharCounterButton = NULL; + sResetClosedModeButton = NULL; +} + +bool djui_panel_chat_is_shift_hint_visible(void) { + return (sChatShiftHintText != NULL && sChatShiftHintText->base.visible); +} + +void djui_panel_chat_update_shift_hint(void) { + if (sChatShiftHintText == NULL) { return; } + if (!sChatShiftHintText->base.visible) { return; } + if (gDjuiInputHeldShift) { + djui_text_set_text(sChatShiftHintText, DLANG(CHAT_OPTIONS, CHAT_SHIFT_HINT_ACTIVE)); + djui_base_set_color(&sChatShiftHintText->base, 255, 165, 0, 255); + } else { + djui_text_set_text(sChatShiftHintText, DLANG(CHAT_OPTIONS, CHAT_SHIFT_HINT)); + djui_base_set_color(&sChatShiftHintText->base, 128, 128, 128, 255); + } +} + +static void djui_panel_chat_update_lifetime_slider_enabled(void); +static void djui_panel_chat_update_closed_mode_lifetime_label(void); + +static struct DjuiSelectionbox* sChatClosedModeSelection = NULL; + +static void djui_panel_chat_apply_chatbox_style(void) { + if (gDjuiChatBox == NULL) { return; } + + djui_chat_messages_apply_style(); + + if (gDjuiChatBox != NULL && gDjuiChatBoxFocus) { + bool hasMessages = (gDjuiChatBox->chatFlow->base.height.value > 2.0f); + u8 alpha = 0; + if (hasMessages) { + int baseAlpha = (int)(configChatBackgroundOpacity * 2.55f); + if (baseAlpha > 255) { baseAlpha = 255; } + if (baseAlpha < 0) { baseAlpha = 0; } + alpha = (u8)baseAlpha; + } + djui_base_set_color(&gDjuiChatBox->chatFlow->base, 0, 0, 0, alpha); + } +} + +static void djui_panel_chat_update_value_labels(void) { + if (sSliderWidth != NULL) { + struct DjuiText* sChatWidthLabel = djui_slider_get_value_text(sSliderWidth); + if (sChatWidthLabel != NULL) { + char buf[16]; + snprintf(buf, sizeof(buf), "%u", configChatWidth); + djui_text_set_text(sChatWidthLabel, buf); + struct DjuiBase* base = &sChatWidthLabel->base; + if (configChatWidth < CHAT_WIDTH_DEFAULT) { + djui_base_set_color(base, CHAT_LABEL_LOW_RGB[0], CHAT_LABEL_LOW_RGB[1], CHAT_LABEL_LOW_RGB[2], 255); + } else if (configChatWidth == CHAT_WIDTH_DEFAULT) { + djui_base_set_color(base, CHAT_LABEL_DEFAULT_RGB[0], CHAT_LABEL_DEFAULT_RGB[1], CHAT_LABEL_DEFAULT_RGB[2], 255); + } else { + djui_base_set_color(base, CHAT_LABEL_HIGH_RGB[0], CHAT_LABEL_HIGH_RGB[1], CHAT_LABEL_HIGH_RGB[2], 255); + } + } + } + + if (sSliderHeight != NULL) { + struct DjuiText* sChatHeightLabel = djui_slider_get_value_text(sSliderHeight); + if (sChatHeightLabel != NULL) { + char buf[16]; + snprintf(buf, sizeof(buf), "%u", configChatHeight); + djui_text_set_text(sChatHeightLabel, buf); + struct DjuiBase* base = &sChatHeightLabel->base; + if (configChatHeight < CHAT_HEIGHT_DEFAULT) { + djui_base_set_color(base, CHAT_LABEL_LOW_RGB[0], CHAT_LABEL_LOW_RGB[1], CHAT_LABEL_LOW_RGB[2], 255); + } else if (configChatHeight == CHAT_HEIGHT_DEFAULT) { + djui_base_set_color(base, CHAT_LABEL_DEFAULT_RGB[0], CHAT_LABEL_DEFAULT_RGB[1], CHAT_LABEL_DEFAULT_RGB[2], 255); + } else { + djui_base_set_color(base, CHAT_LABEL_HIGH_RGB[0], CHAT_LABEL_HIGH_RGB[1], CHAT_LABEL_HIGH_RGB[2], 255); + } + } + } + + if (sSliderTextScale != NULL) { + struct DjuiText* sChatTextScaleLabel = djui_slider_get_value_text(sSliderTextScale); + if (sChatTextScaleLabel != NULL) { + char buf[16]; + snprintf(buf, sizeof(buf), "%u%%", configChatTextScale); + djui_text_set_text(sChatTextScaleLabel, buf); + struct DjuiBase* base = &sChatTextScaleLabel->base; + if (configChatTextScale < 100) { + djui_base_set_color(base, CHAT_LABEL_LOW_RGB[0], CHAT_LABEL_LOW_RGB[1], CHAT_LABEL_LOW_RGB[2], 255); + } else if (configChatTextScale == 100) { + djui_base_set_color(base, CHAT_LABEL_DEFAULT_RGB[0], CHAT_LABEL_DEFAULT_RGB[1], CHAT_LABEL_DEFAULT_RGB[2], 255); + } else { + djui_base_set_color(base, CHAT_LABEL_HIGH_RGB[0], CHAT_LABEL_HIGH_RGB[1], CHAT_LABEL_HIGH_RGB[2], 255); + } + } + } + + if (sSliderBgOpacity != NULL) { + struct DjuiText* sChatBgOpacityLabel = djui_slider_get_value_text(sSliderBgOpacity); + if (sChatBgOpacityLabel != NULL) { + char buf[16]; + snprintf(buf, sizeof(buf), "%u%%", configChatBackgroundOpacity); + djui_text_set_text(sChatBgOpacityLabel, buf); + struct DjuiBase* base = &sChatBgOpacityLabel->base; + if (configChatBackgroundOpacity < 70) { + djui_base_set_color(base, CHAT_LABEL_LOW_RGB[0], CHAT_LABEL_LOW_RGB[1], CHAT_LABEL_LOW_RGB[2], 255); + } else if (configChatBackgroundOpacity == 70) { + djui_base_set_color(base, CHAT_LABEL_DEFAULT_RGB[0], CHAT_LABEL_DEFAULT_RGB[1], CHAT_LABEL_DEFAULT_RGB[2], 255); + } else { + djui_base_set_color(base, CHAT_LABEL_HIGH_RGB[0], CHAT_LABEL_HIGH_RGB[1], CHAT_LABEL_HIGH_RGB[2], 255); + } + } + } + + if (sSliderTextOpacity != NULL) { + struct DjuiText* sChatTextOpacityLabel = djui_slider_get_value_text(sSliderTextOpacity); + if (sChatTextOpacityLabel != NULL) { + char buf[16]; + snprintf(buf, sizeof(buf), "%u%%", configChatTextOpacity); + djui_text_set_text(sChatTextOpacityLabel, buf); + struct DjuiBase* base = &sChatTextOpacityLabel->base; + if (configChatTextOpacity < 100) { + djui_base_set_color(base, CHAT_LABEL_LOW_RGB[0], CHAT_LABEL_LOW_RGB[1], CHAT_LABEL_LOW_RGB[2], 255); + } else if (configChatTextOpacity == 100) { + djui_base_set_color(base, CHAT_LABEL_DEFAULT_RGB[0], CHAT_LABEL_DEFAULT_RGB[1], CHAT_LABEL_DEFAULT_RGB[2], 255); + } else { + djui_base_set_color(base, CHAT_LABEL_HIGH_RGB[0], CHAT_LABEL_HIGH_RGB[1], CHAT_LABEL_HIGH_RGB[2], 255); + } + } + } + + if (sSliderLifetime != NULL) { + struct DjuiText* sChatLifetimeLabel = djui_slider_get_value_text(sSliderLifetime); + if (sChatLifetimeLabel != NULL) { + char buf[16]; + snprintf(buf, sizeof(buf), "%us", configChatMessageLifetime); + djui_text_set_text(sChatLifetimeLabel, buf); + struct DjuiBase* base = &sChatLifetimeLabel->base; + + if (configChatClosedMode != 1) { + djui_base_set_color(base, 160, 160, 160, 255); + } else { + if (configChatMessageLifetime < CHAT_LIFETIME_DEFAULT) { + djui_base_set_color(base, CHAT_LABEL_LOW_RGB[0], CHAT_LABEL_LOW_RGB[1], CHAT_LABEL_LOW_RGB[2], 255); + } else if (configChatMessageLifetime == CHAT_LIFETIME_DEFAULT) { + djui_base_set_color(base, CHAT_LABEL_DEFAULT_RGB[0], CHAT_LABEL_DEFAULT_RGB[1], CHAT_LABEL_DEFAULT_RGB[2], 255); + } else { + djui_base_set_color(base, CHAT_LABEL_HIGH_RGB[0], CHAT_LABEL_HIGH_RGB[1], CHAT_LABEL_HIGH_RGB[2], 255); + } + } + } + } +} + +static void djui_panel_chat_update_reset_buttons(void) { + const struct { struct DjuiButton** btn; bool active; } entries[] = { + { &sResetUseStdChatButton, configUseStandardKeyBindingsChat != CHAT_USE_STD_KEY_BINDINGS_DEFAULT }, + { &sResetCharCounterButton, configChatCharCounter != CHAT_CHAR_COUNTER_DEFAULT }, + { &sResetClosedModeButton, configChatClosedMode != CHAT_CLOSED_MODE_DEFAULT }, + { &sResetWidthButton, configChatWidth != CHAT_WIDTH_DEFAULT }, + { &sResetHeightButton, configChatHeight != CHAT_HEIGHT_DEFAULT }, + { &sResetTextScaleButton, configChatTextScale != CHAT_TEXT_SCALE_DEFAULT }, + { &sResetBgOpacityButton, configChatBackgroundOpacity != CHAT_BG_OPACITY_DEFAULT }, + { &sResetTextOpacityButton, configChatTextOpacity != CHAT_TEXT_OPACITY_DEFAULT }, + { &sResetLifetimeButton, (configChatClosedMode == 1) && (configChatMessageLifetime != CHAT_LIFETIME_DEFAULT) }, + }; + + for (int i = 0; i < 9; i++) { + struct DjuiButton* btn = *entries[i].btn; + if (btn == NULL) { continue; } + + bool active = entries[i].active; + djui_base_set_enabled(&btn->base, active); + + if (btn->text != NULL) { + if (active) { + djui_base_set_color(&btn->text->base, 255, 64, 64, 255); // rot + } else { + djui_base_set_color(&btn->text->base, 160, 160, 160, 255); // grau + } + } + } +} + +static void djui_panel_chat_update_lifetime_slider_enabled(void) { + if (sSliderLifetime == NULL) { return; } + bool lifetimeActive = (configChatClosedMode == 1); + djui_base_set_enabled(&sSliderLifetime->base, lifetimeActive); +} + + +static void djui_panel_chat_on_width_slider_change(UNUSED struct DjuiBase* b) { + if (configChatWidth < 200) { configChatWidth = 200; } + if (configChatWidth > 2000) { configChatWidth = 2000; } + if (gDjuiChatBox != NULL) { + djui_base_set_size(&gDjuiChatBox->base, configChatWidth, gDjuiChatBox->base.height.value); + djui_panel_chat_apply_chatbox_style(); + } + djui_panel_chat_update_value_labels(); + djui_panel_chat_update_reset_buttons(); +} + +static void djui_panel_chat_on_height_slider_change(UNUSED struct DjuiBase* b) { + if (configChatHeight < 100) { configChatHeight = 100; } + if (configChatHeight > 1000) { configChatHeight = 1000; } + if (gDjuiChatBox != NULL) { + djui_base_set_size(&gDjuiChatBox->base, gDjuiChatBox->base.width.value, configChatHeight); + djui_panel_chat_apply_chatbox_style(); + } + djui_panel_chat_update_value_labels(); + djui_panel_chat_update_reset_buttons(); +} + +static void djui_panel_chat_on_style_change(UNUSED struct DjuiBase* b) { + djui_panel_chat_apply_chatbox_style(); + djui_panel_chat_update_value_labels(); + djui_panel_chat_update_reset_buttons(); +} + +static void djui_panel_chat_on_lifetime_change(UNUSED struct DjuiBase* b) { + djui_panel_chat_update_value_labels(); + djui_panel_chat_update_reset_buttons(); + djui_panel_chat_update_closed_mode_lifetime_label(); +} + +static void djui_panel_chat_on_closed_mode_change(UNUSED struct DjuiBase* b) { + if (configChatClosedMode > 2) { + configChatClosedMode = 1; + } + djui_panel_chat_update_lifetime_slider_enabled(); + djui_panel_chat_update_reset_buttons(); + djui_panel_chat_update_value_labels(); + djui_panel_chat_update_closed_mode_lifetime_label(); +} + +static void djui_panel_chat_update_closed_mode_lifetime_label(void) { + if (sChatClosedModeSelection == NULL) { return; } + char buf[64]; + snprintf(buf, sizeof(buf), DLANG(CHAT_OPTIONS, CHAT_CLOSED_LIFETIME), configChatMessageLifetime); + djui_selectionbox_set_choice_text(sChatClosedModeSelection, 1, buf); +} + +static void djui_panel_chat_on_reset_width(UNUSED struct DjuiBase* b) { + configChatWidth = CHAT_WIDTH_DEFAULT; + if (sSliderWidth != NULL) { + djui_slider_update_value(&sSliderWidth->base); + } + if (gDjuiChatBox != NULL) { + djui_base_set_size(&gDjuiChatBox->base, configChatWidth, gDjuiChatBox->base.height.value); + djui_panel_chat_apply_chatbox_style(); + } + djui_panel_chat_update_value_labels(); + djui_panel_chat_update_reset_buttons(); +} + +static void djui_panel_chat_on_reset_height(UNUSED struct DjuiBase* b) { + configChatHeight = CHAT_HEIGHT_DEFAULT; + if (sSliderHeight != NULL) { + djui_slider_update_value(&sSliderHeight->base); + } + if (gDjuiChatBox != NULL) { + djui_base_set_size(&gDjuiChatBox->base, gDjuiChatBox->base.width.value, configChatHeight); + djui_panel_chat_apply_chatbox_style(); + } + djui_panel_chat_update_value_labels(); + djui_panel_chat_update_reset_buttons(); +} + +static void djui_panel_chat_on_reset_text_scale(UNUSED struct DjuiBase* b) { + configChatTextScale = CHAT_TEXT_SCALE_DEFAULT; + if (sSliderTextScale != NULL) { + djui_slider_update_value(&sSliderTextScale->base); + } + djui_panel_chat_apply_chatbox_style(); + djui_panel_chat_update_value_labels(); + djui_panel_chat_update_reset_buttons(); +} + +static void djui_panel_chat_on_reset_bg_opacity(UNUSED struct DjuiBase* b) { + configChatBackgroundOpacity = CHAT_BG_OPACITY_DEFAULT; + if (sSliderBgOpacity != NULL) { + djui_slider_update_value(&sSliderBgOpacity->base); + } + djui_panel_chat_apply_chatbox_style(); + djui_panel_chat_update_value_labels(); + djui_panel_chat_update_reset_buttons(); +} + +static void djui_panel_chat_on_reset_text_opacity(UNUSED struct DjuiBase* b) { + configChatTextOpacity = CHAT_TEXT_OPACITY_DEFAULT; + if (sSliderTextOpacity != NULL) { + djui_slider_update_value(&sSliderTextOpacity->base); + } + djui_panel_chat_apply_chatbox_style(); + djui_panel_chat_update_value_labels(); + djui_panel_chat_update_reset_buttons(); +} + +static void djui_panel_chat_on_reset_lifetime(UNUSED struct DjuiBase* b) { + configChatMessageLifetime = CHAT_LIFETIME_DEFAULT; + if (sSliderLifetime != NULL) { + djui_slider_update_value(&sSliderLifetime->base); + } + djui_panel_chat_update_value_labels(); + djui_panel_chat_update_reset_buttons(); + djui_panel_chat_update_closed_mode_lifetime_label(); +} + +static void djui_panel_chat_on_reset_use_std_chat(UNUSED struct DjuiBase* b) { + configUseStandardKeyBindingsChat = CHAT_USE_STD_KEY_BINDINGS_DEFAULT; + if (sCheckboxUseStdChat != NULL && sCheckboxUseStdChat->rectValue != NULL) { + djui_base_set_visible(&sCheckboxUseStdChat->rectValue->base, configUseStandardKeyBindingsChat); + } + djui_panel_chat_update_reset_buttons(); +} + +static void djui_panel_chat_on_reset_char_counter(UNUSED struct DjuiBase* b) { + configChatCharCounter = CHAT_CHAR_COUNTER_DEFAULT; + if (sCheckboxCharCounter != NULL && sCheckboxCharCounter->rectValue != NULL) { + djui_base_set_visible(&sCheckboxCharCounter->rectValue->base, configChatCharCounter); + } + djui_panel_chat_update_reset_buttons(); +} + +static void djui_panel_chat_on_reset_closed_mode(UNUSED struct DjuiBase* b) { + configChatClosedMode = CHAT_CLOSED_MODE_DEFAULT; + if (sChatClosedModeSelection != NULL) { + djui_selectionbox_update_value(&sChatClosedModeSelection->base); + djui_panel_chat_on_closed_mode_change(&sChatClosedModeSelection->base); + } else { + djui_panel_chat_on_closed_mode_change(NULL); + } +} + +static void djui_panel_chat_on_checkbox_change(UNUSED struct DjuiBase* b) { + djui_panel_chat_update_reset_buttons(); +} + +void djui_panel_chat_create(struct DjuiBase* caller) { + struct DjuiThreePanel* panel = djui_panel_menu_create(DLANG(CHAT_OPTIONS, CHAT), false); + struct DjuiBase* body = djui_three_panel_get_body(panel); + { + struct DjuiRect* rowUseStdChat = djui_rect_container_create(body, 32); + struct DjuiRect* rowCharCounter = djui_rect_container_create(body, 32); + struct DjuiRect* rowClosedMode = djui_rect_container_create(body, 32); + + sCheckboxUseStdChat = djui_checkbox_create(&rowUseStdChat->base, DLANG(CHAT_OPTIONS, USE_STANDARD_KEY_BINDINGS_CHAT), &configUseStandardKeyBindingsChat, djui_panel_chat_on_checkbox_change); + sCheckboxCharCounter = djui_checkbox_create(&rowCharCounter->base, DLANG(CHAT_OPTIONS, CHAT_CHAR_COUNTER), &configChatCharCounter, djui_panel_chat_on_checkbox_change); + + char lifetimeChoice[64]; + snprintf(lifetimeChoice, sizeof(lifetimeChoice), DLANG(CHAT_OPTIONS, CHAT_CLOSED_LIFETIME), configChatMessageLifetime); + char* chatClosedModeChoices[] = { + DLANG(CHAT_OPTIONS, CHAT_CLOSED_DISABLED), + lifetimeChoice, + DLANG(CHAT_OPTIONS, CHAT_CLOSED_ALWAYS), + }; + sChatClosedModeSelection = djui_selectionbox_create(&rowClosedMode->base, DLANG(CHAT_OPTIONS, CHAT_CLOSED_MODE), chatClosedModeChoices, 3, &configChatClosedMode, djui_panel_chat_on_closed_mode_change); + + char* chatSizeChoices[] = { + DLANG(CHAT_OPTIONS, CHAT_SIZE_MINIMUM), + DLANG(CHAT_OPTIONS, CHAT_SIZE_VERY_TINY), + DLANG(CHAT_OPTIONS, CHAT_SIZE_TINY), + DLANG(CHAT_OPTIONS, CHAT_SIZE_VERY_SMALL), + DLANG(CHAT_OPTIONS, CHAT_SIZE_SMALL), + DLANG(CHAT_OPTIONS, CHAT_SIZE_NORMAL), + DLANG(CHAT_OPTIONS, CHAT_SIZE_BIG), + DLANG(CHAT_OPTIONS, CHAT_SIZE_VERY_BIG), + DLANG(CHAT_OPTIONS, CHAT_SIZE_HUGE), + DLANG(CHAT_OPTIONS, CHAT_SIZE_VERY_HUGE), + DLANG(CHAT_OPTIONS, CHAT_SIZE_MAXIMUM) + }; + (void)chatSizeChoices; + + if (sCheckboxUseStdChat != NULL) { + djui_base_set_size(&sCheckboxUseStdChat->base, 0.94f, 32.0f); + } + if (sCheckboxCharCounter != NULL) { + djui_base_set_size(&sCheckboxCharCounter->base, 0.94f, 32.0f); + } + if (sChatClosedModeSelection != NULL) { + djui_base_set_size(&sChatClosedModeSelection->base, 0.94f, 32.0f); + if (sChatClosedModeSelection->rect != NULL) { + djui_base_set_size(&sChatClosedModeSelection->rect->base, 0.46f, 1.0f); + } + } + + struct DjuiRect* rowLifetime = djui_rect_container_create(body, 32); + struct DjuiRect* rowWidth = djui_rect_container_create(body, 32); + struct DjuiRect* rowHeight = djui_rect_container_create(body, 32); + struct DjuiRect* rowTextScale = djui_rect_container_create(body, 32); + struct DjuiRect* rowBgOpacity = djui_rect_container_create(body, 32); + struct DjuiRect* rowTextOpacity= djui_rect_container_create(body, 32); + + sSliderLifetime = djui_slider_create(&rowLifetime->base, DLANG(CHAT_OPTIONS, CHAT_LIFETIME), &configChatMessageLifetime, 1, 120, djui_panel_chat_on_lifetime_change); + sSliderWidth = djui_slider_create(&rowWidth->base, DLANG(CHAT_OPTIONS, CHAT_WIDTH), &configChatWidth, 200, 2000, djui_panel_chat_on_width_slider_change); + sSliderHeight = djui_slider_create(&rowHeight->base, DLANG(CHAT_OPTIONS, CHAT_HEIGHT), &configChatHeight, 100, 1000, djui_panel_chat_on_height_slider_change); + sSliderTextScale = djui_slider_create(&rowTextScale->base, DLANG(CHAT_OPTIONS, CHAT_TEXT_SCALE), &configChatTextScale, 50, 200, djui_panel_chat_on_style_change); + sSliderBgOpacity = djui_slider_create(&rowBgOpacity->base, DLANG(CHAT_OPTIONS, CHAT_BACKGROUND_OPACITY), &configChatBackgroundOpacity, 0, 100, djui_panel_chat_on_style_change); + sSliderTextOpacity = djui_slider_create(&rowTextOpacity->base, DLANG(CHAT_OPTIONS, CHAT_TEXT_OPACITY), &configChatTextOpacity, 0, 100, djui_panel_chat_on_style_change); + + + struct DjuiSlider* sliders[] = { + sSliderWidth, + sSliderHeight, + sSliderTextScale, + sSliderBgOpacity, + sSliderTextOpacity, + sSliderLifetime, + }; + for (int i = 0; i < 6; i++) { + struct DjuiSlider* s = sliders[i]; + if (s == NULL) { continue; } + djui_base_set_alignment(&s->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_CENTER); + djui_base_set_size_type(&s->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + // Slider-Bereich weiter nach rechts ziehen, sodass nur noch ein schmaler Abstand vor dem X bleibt + djui_base_set_size(&s->base, 0.94f, 32.0f); + djui_base_set_size(&s->rect->base, 0.46f, 1.0f); + } + + sResetUseStdChatButton = djui_button_create(&rowUseStdChat->base, "X", DJUI_BUTTON_STYLE_NORMAL, djui_panel_chat_on_reset_use_std_chat); + sResetCharCounterButton = djui_button_create(&rowCharCounter->base, "X", DJUI_BUTTON_STYLE_NORMAL, djui_panel_chat_on_reset_char_counter); + sResetClosedModeButton = djui_button_create(&rowClosedMode->base, "X", DJUI_BUTTON_STYLE_NORMAL, djui_panel_chat_on_reset_closed_mode); + sResetWidthButton = djui_button_create(&rowWidth->base, "X", DJUI_BUTTON_STYLE_NORMAL, djui_panel_chat_on_reset_width); + sResetHeightButton = djui_button_create(&rowHeight->base, "X", DJUI_BUTTON_STYLE_NORMAL, djui_panel_chat_on_reset_height); + sResetTextScaleButton = djui_button_create(&rowTextScale->base, "X", DJUI_BUTTON_STYLE_NORMAL, djui_panel_chat_on_reset_text_scale); + sResetBgOpacityButton = djui_button_create(&rowBgOpacity->base, "X", DJUI_BUTTON_STYLE_NORMAL, djui_panel_chat_on_reset_bg_opacity); + sResetTextOpacityButton = djui_button_create(&rowTextOpacity->base, "X", DJUI_BUTTON_STYLE_NORMAL, djui_panel_chat_on_reset_text_opacity); + sResetLifetimeButton = djui_button_create(&rowLifetime->base, "X", DJUI_BUTTON_STYLE_NORMAL, djui_panel_chat_on_reset_lifetime); + + struct DjuiButton* buttons[] = { + sResetUseStdChatButton, + sResetCharCounterButton, + sResetClosedModeButton, + sResetWidthButton, + sResetHeightButton, + sResetTextScaleButton, + sResetBgOpacityButton, + sResetTextOpacityButton, + sResetLifetimeButton, + }; + for (int i = 0; i < 9; i++) { + struct DjuiButton* btn = buttons[i]; + if (btn == NULL) { continue; } + djui_base_set_alignment(&btn->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_CENTER); + djui_base_set_size_type(&btn->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&btn->base, 32.0f, 32.0f); + } + + djui_panel_chat_update_value_labels(); + djui_panel_chat_update_lifetime_slider_enabled(); + djui_panel_chat_update_reset_buttons(); + + struct DjuiRect* rowShiftHint = djui_rect_container_create(body, 32); + djui_base_set_color(&rowShiftHint->base, 0, 0, 0, 0); + + sChatShiftHintText = djui_text_create(&rowShiftHint->base, ""); + djui_base_set_alignment(&sChatShiftHintText->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); + djui_base_set_size_type(&sChatShiftHintText->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE); + djui_base_set_size(&sChatShiftHintText->base, 1.0f, 1.0f); + djui_text_set_alignment(sChatShiftHintText, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); + djui_text_set_drop_shadow(sChatShiftHintText, 64, 64, 64, 100); + djui_base_set_visible(&sChatShiftHintText->base, true); + djui_panel_chat_update_shift_hint(); + + djui_button_create(body, DLANG(MENU, BACK), DJUI_BUTTON_STYLE_BACK, djui_panel_menu_back); + } + + struct DjuiPanel* p = djui_panel_add(caller, panel, NULL); + if (!p) { return; } + p->on_panel_destroy = djui_panel_chat_destroy; +} + + diff --git a/src/pc/djui/djui_panel_chat.h b/src/pc/djui/djui_panel_chat.h new file mode 100644 index 000000000..ad065f7ad --- /dev/null +++ b/src/pc/djui/djui_panel_chat.h @@ -0,0 +1,8 @@ +#pragma once +#include "djui.h" + +void djui_panel_chat_create(struct DjuiBase* caller); +void djui_panel_chat_update_shift_hint(void); +bool djui_panel_chat_is_shift_hint_visible(void); + + diff --git a/src/pc/djui/djui_panel_controls.c b/src/pc/djui/djui_panel_controls.c index e8b39396d..689dfe945 100644 --- a/src/pc/djui/djui_panel_controls.c +++ b/src/pc/djui/djui_panel_controls.c @@ -40,7 +40,6 @@ void djui_panel_controls_create(struct DjuiBase* caller) { #ifndef HANDHELD djui_checkbox_create(body, DLANG(CONTROLS, DISABLE_GAMEPADS), &configDisableGamepads, NULL); #endif - djui_checkbox_create(body, DLANG(MISC, USE_STANDARD_KEY_BINDINGS_CHAT), &configUseStandardKeyBindingsChat, NULL); #ifdef HAVE_SDL2 djui_checkbox_create(body, DLANG(CONTROLS, EXTENDED_REPORTS), &configExtendedReports, NULL); diff --git a/src/pc/djui/djui_panel_controls_extra.c b/src/pc/djui/djui_panel_controls_extra.c index e4727b45f..9669dea17 100644 --- a/src/pc/djui/djui_panel_controls_extra.c +++ b/src/pc/djui/djui_panel_controls_extra.c @@ -15,18 +15,19 @@ void djui_panel_controls_extra_create(struct DjuiBase* caller) { djui_base_set_color(&bindBody->base, 0, 0, 0, 0); djui_flow_layout_set_margin(bindBody, 1); { - djui_bind_create(&bindBody->base, DLANG(CONTROLS, CHAT), configKeyChat); - djui_bind_create(&bindBody->base, DLANG(CONTROLS, PLAYERS), configKeyPlayerList); - djui_bind_create(&bindBody->base, DLANG(CONTROLS, D_UP), configKeyDUp); - djui_bind_create(&bindBody->base, DLANG(CONTROLS, D_DOWN), configKeyDDown); - djui_bind_create(&bindBody->base, DLANG(CONTROLS, D_LEFT), configKeyDLeft); - djui_bind_create(&bindBody->base, DLANG(CONTROLS, D_RIGHT), configKeyDRight); - djui_bind_create(&bindBody->base, DLANG(CONTROLS, X), configKeyX); - djui_bind_create(&bindBody->base, DLANG(CONTROLS, Y), configKeyY); - djui_bind_create(&bindBody->base, DLANG(CONTROLS, CONSOLE), configKeyConsole); - djui_bind_create(&bindBody->base, DLANG(CONTROLS, PREV), configKeyPrevPage); - djui_bind_create(&bindBody->base, DLANG(CONTROLS, NEXT), configKeyNextPage); - djui_bind_create(&bindBody->base, DLANG(CONTROLS, DISCONNECT), configKeyDisconnect); + djui_bind_create(&bindBody->base, DLANG(CONTROLS, CHAT), configKeyChat); + djui_bind_create(&bindBody->base, DLANG(CONTROLS, CHAT_COMMAND), configKeyChatCommand); + djui_bind_create(&bindBody->base, DLANG(CONTROLS, PLAYERS), configKeyPlayerList); + djui_bind_create(&bindBody->base, DLANG(CONTROLS, D_UP), configKeyDUp); + djui_bind_create(&bindBody->base, DLANG(CONTROLS, D_DOWN), configKeyDDown); + djui_bind_create(&bindBody->base, DLANG(CONTROLS, D_LEFT), configKeyDLeft); + djui_bind_create(&bindBody->base, DLANG(CONTROLS, D_RIGHT), configKeyDRight); + djui_bind_create(&bindBody->base, DLANG(CONTROLS, X), configKeyX); + djui_bind_create(&bindBody->base, DLANG(CONTROLS, Y), configKeyY); + djui_bind_create(&bindBody->base, DLANG(CONTROLS, CONSOLE), configKeyConsole); + djui_bind_create(&bindBody->base, DLANG(CONTROLS, PREV), configKeyPrevPage); + djui_bind_create(&bindBody->base, DLANG(CONTROLS, NEXT), configKeyNextPage); + djui_bind_create(&bindBody->base, DLANG(CONTROLS, DISCONNECT), configKeyDisconnect); } djui_button_create(body, DLANG(MENU, BACK), DJUI_BUTTON_STYLE_BACK, djui_panel_menu_back); diff --git a/src/pc/djui/djui_panel_options.c b/src/pc/djui/djui_panel_options.c index 37e8ea1bd..7f833bf31 100644 --- a/src/pc/djui/djui_panel_options.c +++ b/src/pc/djui/djui_panel_options.c @@ -3,6 +3,7 @@ #include "djui_panel_player.h" #include "djui_panel_camera.h" #include "djui_panel_controls.h" +#include "djui_panel_chat.h" #include "djui_panel_display.h" #include "djui_panel_sound.h" #include "djui_panel_misc.h" @@ -30,6 +31,7 @@ void djui_panel_options_create(struct DjuiBase* caller) { } djui_button_create(body, DLANG(OPTIONS, CAMERA), DJUI_BUTTON_STYLE_NORMAL, djui_panel_camera_create); djui_button_create(body, DLANG(OPTIONS, CONTROLS), DJUI_BUTTON_STYLE_NORMAL, djui_panel_controls_create); + djui_button_create(body, DLANG(OPTIONS, CHAT), DJUI_BUTTON_STYLE_NORMAL, djui_panel_chat_create); djui_button_create(body, DLANG(OPTIONS, DISPLAY), DJUI_BUTTON_STYLE_NORMAL, djui_panel_display_create); djui_button_create(body, DLANG(OPTIONS, SOUND), DJUI_BUTTON_STYLE_NORMAL, djui_panel_sound_create); djui_button_create(body, DLANG(OPTIONS, MISC), DJUI_BUTTON_STYLE_NORMAL, djui_panel_misc_create); diff --git a/src/pc/djui/djui_selectionbox.c b/src/pc/djui/djui_selectionbox.c index addb888ef..f47c73c9b 100644 --- a/src/pc/djui/djui_selectionbox.c +++ b/src/pc/djui/djui_selectionbox.c @@ -167,3 +167,20 @@ struct DjuiSelectionbox* djui_selectionbox_create(struct DjuiBase* parent, const return selectionbox; } + +void djui_selectionbox_set_choice_text(struct DjuiSelectionbox* selectionbox, u8 index, const char* text) { + if (selectionbox == NULL) { return; } + if (index >= selectionbox->choiceCount) { return; } + + if (selectionbox->choices[index] != NULL) { + free(selectionbox->choices[index]); + } + + u32 length = strlen(text); + selectionbox->choices[index] = calloc(length + 1, sizeof(char)); + sprintf(selectionbox->choices[index], "%s", text); + + if (*selectionbox->value == index && selectionbox->rectText != NULL) { + djui_text_set_text(selectionbox->rectText, selectionbox->choices[index]); + } +} \ No newline at end of file diff --git a/src/pc/djui/djui_selectionbox.h b/src/pc/djui/djui_selectionbox.h index c79e224e6..9cca82cd0 100644 --- a/src/pc/djui/djui_selectionbox.h +++ b/src/pc/djui/djui_selectionbox.h @@ -14,4 +14,5 @@ struct DjuiSelectionbox { }; struct DjuiSelectionbox* djui_selectionbox_create(struct DjuiBase* parent, const char* message, char* choices[], u8 choiceCount, unsigned int* value, void (*on_value_change)(struct DjuiBase*)); -void djui_selectionbox_update_value(struct DjuiBase* base); \ No newline at end of file +void djui_selectionbox_update_value(struct DjuiBase* base); +void djui_selectionbox_set_choice_text(struct DjuiSelectionbox* selectionbox, u8 index, const char* text); \ No newline at end of file diff --git a/src/pc/djui/djui_slider.c b/src/pc/djui/djui_slider.c index c92799ce7..05b363d1e 100644 --- a/src/pc/djui/djui_slider.c +++ b/src/pc/djui/djui_slider.c @@ -1,4 +1,15 @@ #include "djui.h" +#include "djui_cursor.h" +#include "djui_inputbox.h" + +static f32 sSliderLastCursorX = 0.0f; + +static void djui_slider_default_format_value(struct DjuiSlider* slider, char* buf, int bufSize) { + if (slider == NULL || slider->value == NULL || bufSize <= 0) { + return; + } + snprintf(buf, bufSize, "%u", *slider->value); +} static void djui_slider_update_style(struct DjuiBase* base) { struct DjuiSlider* slider = (struct DjuiSlider*)base; @@ -38,6 +49,16 @@ void djui_slider_update_value(struct DjuiBase* base) { u32 max = slider->max; u32* value = slider->value; djui_base_set_size(&slider->rectValue->base, ((f32)*value - min) / ((f32)max - min), 1.0f); + + if (slider->valueText != NULL) { + char buf[32]; + if (slider->formatCallback != NULL) { + slider->formatCallback(slider, buf, sizeof(buf)); + } else { + djui_slider_default_format_value(slider, buf, sizeof(buf)); + } + djui_text_set_text(slider->valueText, buf); + } } static void djui_slider_get_cursor_hover_location(struct DjuiBase* base, f32* x, f32* y) { @@ -52,12 +73,43 @@ static void djui_slider_on_cursor_down(struct DjuiBase* base) { u32 min = slider->min; u32 max = slider->max; u32* value = slider->value; - f32 x = slider->rect->base.elem.x; - f32 w = slider->rect->base.elem.width; - f32 cursorX = gCursorX; - cursorX = fmax(cursorX, x); - cursorX = fmin(cursorX, x + w); - *value = ((cursorX - x) / w) * (max - min) + min; + + bool fineAdjust = (gDjuiInputHeldShift != 0); + int newValue = (int)*value; + + if (fineAdjust) { + f32 w = slider->rect->base.elem.width; + if (w <= 0.0f) { w = 1.0f; } + + f32 baseStepPerPixel = (f32)(max - min) / w; + f32 fineStepPerPixel = baseStepPerPixel * 0.1f; + + f32 cursorX = gCursorX; + f32 deltaX = cursorX - sSliderLastCursorX; + sSliderLastCursorX = cursorX; + + newValue = (int)((f32)newValue + deltaX * fineStepPerPixel + 0.5f); + } else { + f32 x = slider->rect->base.elem.x; + f32 w = slider->rect->base.elem.width; + f32 cursorX = gCursorX; + cursorX = fmax(cursorX, x); + cursorX = fmin(cursorX, x + w); + + f32 t = 0.0f; + if (w > 0.0f) { + t = (cursorX - x) / w; + } + if (t < 0.0f) t = 0.0f; + if (t > 1.0f) t = 1.0f; + + newValue = (int)(t * (f32)(max - min) + 0.5f) + (int)min; + } + + if (newValue < (int)min) newValue = (int)min; + if (newValue > (int)max) newValue = (int)max; + *value = (u32)newValue; + if (base != NULL && base->interactable != NULL && base->interactable->on_value_change != NULL) { base->interactable->on_value_change(base); } @@ -71,6 +123,7 @@ static void djui_slider_on_cursor_down_begin(struct DjuiBase* base, bool inputCu if (inputCursor) { djui_interactable_set_input_focus(base); } else { + sSliderLastCursorX = gCursorX; slider->base.interactable->on_cursor_down = djui_slider_on_cursor_down; } } else { @@ -81,6 +134,7 @@ static void djui_slider_on_cursor_down_begin(struct DjuiBase* base, bool inputCu static void djui_slider_on_cursor_down_end(struct DjuiBase* base) { struct DjuiSlider* slider = (struct DjuiSlider*)base; slider->base.interactable->on_cursor_down = NULL; + sSliderLastCursorX = 0.0f; } static void djui_slider_on_focus(struct DjuiBase* base, OSContPad* pad) { @@ -111,6 +165,7 @@ struct DjuiSlider* djui_slider_create(struct DjuiBase* parent, const char* messa slider->max = max; slider->updateRectValueColor = true; + slider->formatCallback = djui_slider_default_format_value; djui_base_init(parent, base, NULL, djui_slider_destroy); djui_interactable_create(base, djui_slider_update_style); @@ -137,6 +192,14 @@ struct DjuiSlider* djui_slider_create(struct DjuiBase* parent, const char* messa djui_base_set_size_type(&rectValue->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE); slider->rectValue = rectValue; + struct DjuiText* valueText = djui_text_create(&rect->base, ""); + djui_base_set_alignment(&valueText->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); + djui_base_set_size_type(&valueText->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE); + djui_base_set_size(&valueText->base, 1.0f, 1.0f); + djui_text_set_alignment(valueText, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); + djui_text_set_drop_shadow(valueText, 64, 64, 64, 100); + slider->valueText = valueText; + djui_slider_update_value(base); djui_slider_update_style(base); @@ -148,3 +211,14 @@ struct DjuiSlider* djui_slider_create(struct DjuiBase* parent, const char* messa return slider; } + +void djui_slider_set_format_callback(struct DjuiSlider* slider, DjuiSliderFormatCallback cb) { + if (slider == NULL) { return; } + slider->formatCallback = cb; + djui_slider_update_value(&slider->base); +} + +struct DjuiText* djui_slider_get_value_text(struct DjuiSlider* slider) { + if (slider == NULL) { return NULL; } + return slider->valueText; +} diff --git a/src/pc/djui/djui_slider.h b/src/pc/djui/djui_slider.h index b41d18e91..9b387ff4b 100644 --- a/src/pc/djui/djui_slider.h +++ b/src/pc/djui/djui_slider.h @@ -1,16 +1,24 @@ #pragma once #include "djui.h" +struct DjuiSlider; + +typedef void (*DjuiSliderFormatCallback)(struct DjuiSlider* slider, char* buf, int bufSize); + struct DjuiSlider { struct DjuiBase base; struct DjuiRect* rect; struct DjuiRect* rectValue; struct DjuiText* text; + struct DjuiText* valueText; unsigned int* value; unsigned int min; unsigned int max; bool updateRectValueColor; + DjuiSliderFormatCallback formatCallback; }; struct DjuiSlider* djui_slider_create(struct DjuiBase* parent, const char* message, unsigned int* value, unsigned int min, unsigned int max, void (*on_value_change)(struct DjuiBase*)); void djui_slider_update_value(struct DjuiBase* base); +void djui_slider_set_format_callback(struct DjuiSlider* slider, DjuiSliderFormatCallback cb); +struct DjuiText* djui_slider_get_value_text(struct DjuiSlider* slider);