mirror of
https://github.com/brues-code/TwitchEmotes.git
synced 2026-09-22 15:46:58 +00:00
f2daf6847e
ToggleDropDownMenu tests only the bottom and right edges, flips a list once and never re-measures, so a flipped page overflows the top instead, and its off-right test compares list coordinates against pixel widths so submenus flip leftward past the left edge. Clamp our own lists back inside the screen after it positions them.
842 lines
51 KiB
Lua
842 lines
51 KiB
Lua
local addonName = ...
|
|
local LDB = LibStub("LibDataBroker-1.1")
|
|
local LDBIcon = LibStub("LibDBIcon-1.0")
|
|
|
|
Emoticons_Settings={
|
|
["CHAT_MSG_OFFICER"]=true, --1
|
|
["CHAT_MSG_GUILD"]=true, --2
|
|
["CHAT_MSG_PARTY"]=true, --3
|
|
["CHAT_MSG_PARTY_LEADER"]=true, --dont count, tie to 3
|
|
["CHAT_MSG_PARTY_GUIDE"]=true, --dont count, tie to 3
|
|
["CHAT_MSG_RAID"]=true, --4
|
|
["CHAT_MSG_RAID_LEADER"]=true, --dont count, tie to 4
|
|
["CHAT_MSG_RAID_WARNING"]=true, --dont count, tie to 4
|
|
["CHAT_MSG_SAY"]=true, --5
|
|
["CHAT_MSG_YELL"]=true, --6
|
|
["CHAT_MSG_WHISPER"]=true, --7
|
|
["CHAT_MSG_WHISPER_INFORM"]=true, --dont count, tie to 7
|
|
["CHAT_MSG_CHANNEL"]=true, --8
|
|
-- ["CHAT_MSG_BN_WHISPER"]=true, --9
|
|
-- ["CHAT_MSG_BN_WHISPER_INFORM"]=true,--dont count, tie to 9
|
|
-- ["CHAT_MSG_BN_CONVERSATION"]=true,--10
|
|
["CHAT_MSG_BATTLEGROUND"]=true,--11
|
|
["CHAT_MSG_BATTLEGROUND_LEADER"]=true,--dont count, tie to 11
|
|
["MAIL"]=true,
|
|
["TWITCHBUTTON"]=true,
|
|
["sliderX"]=-35,
|
|
["sliderY"]=0,
|
|
["MinimapPos"] = 45,
|
|
["MINIMAPBUTTON"] = true,
|
|
["BUBBLEEMOTES"] = true,
|
|
["AUTOCOMPLETE"] = true,
|
|
["CLICKABLEEMOTES"] = true,
|
|
["FAVEMOTES"] = {true,true,true,true,true,true,true,true,true,true,
|
|
true,true,true,true,true,true,true,true,true,true,
|
|
true,true,true,true,true,true,true,true,}
|
|
|
|
};
|
|
Emoticons_Eyecandy = false;
|
|
local origsettings = {
|
|
["CHAT_MSG_OFFICER"]=true,
|
|
["CHAT_MSG_GUILD"]=true,
|
|
["CHAT_MSG_PARTY"]=true,
|
|
["CHAT_MSG_PARTY_LEADER"]=true,
|
|
["CHAT_MSG_PARTY_GUIDE"]=true,
|
|
["CHAT_MSG_RAID"]=true,
|
|
["CHAT_MSG_RAID_LEADER"]=true,
|
|
["CHAT_MSG_RAID_WARNING"]=true,
|
|
["CHAT_MSG_SAY"]=true,
|
|
["CHAT_MSG_YELL"]=true,
|
|
["CHAT_MSG_WHISPER"]=true,
|
|
["CHAT_MSG_WHISPER_INFORM"]=true,
|
|
-- ["CHAT_MSG_BN_WHISPER"]=true,
|
|
-- ["CHAT_MSG_BN_WHISPER_INFORM"]=true,
|
|
-- ["CHAT_MSG_BN_CONVERSATION"]=true,
|
|
["CHAT_MSG_CHANNEL"]=true,
|
|
["CHAT_MSG_INSTANCE_CHAT"]=true,
|
|
["MAIL"]=true,
|
|
["TWITCHBUTTON"]=true,
|
|
["sliderX"]=-35,
|
|
["sliderY"]=0,
|
|
["MinimapPos"] = 45,
|
|
["MINIMAPBUTTON"] = true,
|
|
["BUBBLEEMOTES"] = true,
|
|
["AUTOCOMPLETE"] = true,
|
|
["CLICKABLEEMOTES"] = true,
|
|
["FAVEMOTES"] = {true,true,true,true,true,true,true,true,true,true,
|
|
true,true,true,true,true,true,true,true,true,true,
|
|
true,true,true,true,true,true,true,true,}
|
|
};
|
|
local dropdown_options={
|
|
[1]= {"Asmongold","asmon1","asmon2","asmon3","asmon4","asmonBoi","asmonC","asmonCD","asmonD","asmonDad","asmonDaze","asmonDegen","asmonE","asmonE1","asmonE2","asmonE3","asmonE4","asmonFiend","asmonG","asmonGASM","asmonGet","asmonHide","asmonL","asmonLFR","asmonLong1","asmonLong2","asmonLong3","asmonLong4","asmonLove","asmonM","asmonOcean","asmonOrc","asmonP","asmonPower","asmonPray","asmonPrime","asmonR","asmonREE","asmonSad","asmonStare","asmonTar","asmonTiger","asmonUH","asmonW","asmonWHAT","asmonWHATR","asmonWOW"},
|
|
[2]= {"Preachlfw","pgeBan","pgeBen","pgeBrian","pgeCheese","pgeChick","pgeClub","pgeCrisp","pgeDrama","pgeEdge","pgeEmma","pgeFish","pgeGhost","pgeHmm","pgeNem","pgeNoob","pgeOhno","pgeOhno2","pgePog","pgePug","pgeRay","pgeScience","pgeShame","pgeSherry"},
|
|
[3]= {"BTTV+FFZ","4Head","ANELE","AngelThump","BabyRage","BBona","BibleThump","BlessRNG","BloodTrail","bUrself","cmonBrother","cmonBrug","cmonBruh","ConcernDoge","ConcernFroge","D:","DansGame","DatSheffy","DD:","DogeWitIt","EleGiggle","eShrug","FacePalm","FailFish","FrankerZ","GabeN","gachiBASS","gachiGASM","gachiHYPER","GivePLZ","haHAA","HandsUp","HeyGuys","HotPokket","HYPERBRUG","HYPERLUL","HYPERTHONK","Jebaited","Kapp","Kappa","KappaPride","Keepo","KKomrade","Kreygasm","LUL","LULE","LULW","MegaLUL","MingLee","MingLUL","MrDestructoid","NickyQ","NotLike","NotLikeThis","o_O","OhMyDog","OpieOP","PagMan","PartyTime","pokiBASS","PotFriend","PowerUpL","PowerUpR","RCool","ResidentSleeper","RFrown","RGasp","RHeart","RMeh","RPatch","RSmile","RSmiling","RTired","RTongue","RWink","RWinkTongue","SeemsGood","smileC","smileW","SMOrc","Squid1","Squid2","Squid3","Squid4","SwiftRage","TakeNRG","Thonk","tooDank","TriHard","weSmart","WideHard","WinnerWinner","WTFF","Wut","WutFace","ZULOL","ZULUL"},
|
|
[4]= {"Custom","4Play","4WeirdBusiness",":alarm:",":alert:",":Aware:",":Awoken:",":blinking:",":Classic:",":Clueless:",":Concerned:",":cringe:",":doo:",":empty:",":ew:",":groove:",":hehe:",":hehesip:",":horror:",":jons:",":kissing:",":kms:",":mc:",":meow:",":misery:",":mo:",":noted:",":om:",":penguin:",":pls:",":queen:",":quest:",":sitch:",":soy:",":torment:",":waiting:",":WM:",":xdd:",":yo:","AbdulPls","AMAZIN","ANEBruh","angrybear","arnoldHalt","AYAYA","bange","batBrah","BedgeMorgan","bidenBlast","bign","billyReady","bjornoVV","bjornoVVona","BOGGED","bruggaroniNcheese","bufeY","businesscat","Catablepon","CatDance","catJAM","CatMad","CatPop","channMies","channWeen","ChipiChipi","chompy","chupBro","chupDerp","chupHappy","ciaciuu","ciaciuWorried","Clap","Cluegi","cmon","confuseddoggo","cptfriHE","CUNGUS","deanWink","Del","Depresstiny","DestiSenpaii","Disgustiny","DocArrive","DocLeave","docmeat","DogeKek","DonoWall","ednasly","Eggroll","endANELE","endBomb","endDawg","endFrench","endHarambe","endKyori","endNotLikeThis","endRP","endTrump","evilcat","fentL","FlipThis","FLOOSHED","flushdoggo","foxsus","freddyCREEP","freddyFINGER","freddyLUL","freddyW","FrogPog","fruitBug","GAMING","GasmChamp","GigaChad","GODSTINY","goinginsane","HappyMerchant","headBang","hehecat","HiveDiver","HmmStiny","HmmTodayIWill","HowSleeper","HUH","HUHH","HyperAngryMerchant","HYPERYOGGERS","ICANT","intjCaught","intjdreaming","intjGlad","intjIdk","intjMad","intjReallyMad","intjSad","intjSalute","intjShake","intjSmile","intjSus","intjWoa","intjXD1","intjXD2","jerryWhat","jewdai","jillzoMallet","jinL","Jons","Joy2","Kekflap","KEKok","KEKWait","KermitScream","KKonaS","Klappa","KomodoHype","Krug","LaurGasm","LeoHug","LeRuse","LETHIMCOOK","LETSGOOO","lockOmegatayys","LockStone","Lole","LOLW","marcithDerp","marcithMath","mastahFloor","megaflushed","MikeSmug","modCheck","MoneySniff","monkeyS","MooCowGold","MooCowW","moWait","MrStark","NeckBeard","NoAnime","NoBitches","NOBULLY","NoTears","OKKona","oldmorDim","OMEGAKEKMAN","OMEGALOL","OverRustle","PatrickMad","PatrickPray","pedro","peepoVW","PEPE","PogCena","PogT","poki1","poki2","pokiW","politeCatWTF","Popoga","PunkChamp","RAGEY","ratJAM","REE","RIPBOZO","sameEnergy","selyihHEY","SNIFFA","StareBruh","Stonks","SuicideThinking","sunglassesflushed","SURPRISE","susfox","Sussy","SWEATSTINY","TeaTime","ThisIsFine","ThumbsUp","totekatze","TrollDespair","TrollLaugh","VoHiYo","WeirdAYAYA","worryChocolate","worryCool","worryExcite","worryFat","worryHug","worryHugged","worryLove","worryPopcorn","worryStick","worryWave","WrathChest","yacubgasm","YEE","yeshoney","YodaSip","YOGGERS","YoshiBlush","ZOINKS"},
|
|
[5]= {"Greekgodx","greekA","greekBrow","greekDiet","greekGirl","greekGordo","greekGweek","greekHard","greekHYPERP","greekJoy","greekKek","greekM","greekMlady","greekOi","greekP","greekPVC","greekSad","greekSheep","greekSleeper","greekSquad","greekT","greekThink","greekTilt","greekWC","greekWhy","greekWtf","greekYikes"},
|
|
[6]= {"nymn","nymn0","nymn1","nymn158","nymn2","nymn2x","nymn3","nymnA","nymnAww","nymnB","nymnBee","nymnBenis","nymnBiggus","nymnBridge","nymnC","nymnCaptain","nymnCC","nymnCD","nymnCozy","nymnCREB","nymnCringe","nymnCry","nymnDab","nymnDeer","nymnE","nymnElf","nymnEU","nymnEZ","nymnFEEDME","nymnFlag","nymnFlick","nymnFood","nymnG","nymnGasm","nymnGasp","nymnGnome","nymnGold","nymnGolden","nymnGun","nymnH","nymnHammer","nymnHmm","nymnHonk","nymnHydra","nymnJoy","nymnK","nymnKek","nymnKing","nymnKomrade","nymnL","nymnM","nymnNA","nymnNo","nymnNormie","nymnOkay","nymnP","nymnPains","nymnPog","nymnPuke","nymnR","nymnRaffle","nymnRupert","nymnS","nymnSad","nymnScuffed","nymnSleeper","nymnSmart","nymnSmol","nymnSmug","nymnSon","nymnSoy","nymnSpurdo","nymnStrong","nymnThink","nymnTransparent","nymnU","nymnV","nymnW","nymnWhy","nymnXD","nymnY","nymnZ"},
|
|
[7]= {"Drainerx","drxBrain","drxCozy","drxCri","drxCS","drxD","drxDict","drxED","drxED2","drxEyes","drxFE","drxFE1","drxFEED","drxGlad","drxGod","drxHappy","drxHey","drxKEK","drxLewd","drxLit","drxLUL","drxMad","drxmonkaEYES","drxPog","drxR","drxSad","drxSmart","drxSmile","drxSpace","drxSSJ","drxThink","drxW","drxWeird","drxWink"},
|
|
[8]= {"Emojis",":100:",":axe:",":b:",":bear:",":bell:",":blush:",":book:",":candle:",":checkmark:",":clock:",":coffee:",":cold_face:",":crab:",":crocodile:",":crown:",":cry:",":door:",":dragon:",":eggplant:",":eye:",":eyes:",":eyes_sus:",":f:",":face_with_raised_eyebrow:",":fire:",":flush:",":flushed:",":full_moon_with_face:",":gun:",":hand:",":handshake:",":heart:",":heart_eyes:",":hot_face:",":joy:",":kiss:",":lizard:",":mega:",":mouse_trap:",":muscle:",":nerd:",":ok_hand:",":onion:",":oof:",":peach:",":pig:",":pig_nose:",":point_left:",":point_right:",":poop:",":pray:",":question:",":rage:",":rolling_eyes:",":shrimp:",":skull:",":smiley:",":smiling_face_with_tear:",":smirk:",":smoking:",":snake:",":sob:",":sunglasses:",":sweat_drops:",":thinking:",":tiger:",":tired:",":tomato:",":tongue:",":triumph:",":turtle_cry:",":warning:",":wave:",":weary:",":wheelchair:",":wink:",":writing_hand:",":x:",":yum:",":zap:",":zipper_mouth:","eggplantW"},
|
|
[9]= {"Forsen","forsen1","forsen2","forsen3","forsen4","forsenAYAYA","forsenAYOYO","forsenBanned","forsenBee","forsenBlob","forsenBoys","forsenC","forsenCD","forsenChamp","forsenClown","forsenConnoisseur","forsenCool","forsenD","forsenDab","forsenDank","forsenDDK","forsenDED","forsenDespair","forsenDiglett","forsenE","forsenEcardo","forsenEmote","forsenEmote2","forsenFajita","forsenFeels","forsenFur","forsenG","forsenGa","forsenGASM","forsenGrill","forsenGun","forsenH","forsenHappy","forsenHead","forsenHobo","forsenHorsen","forsenIQ","forsenJoy","forsenK","forsenKek","forsenKnife","forsenKraken","forsenL","forsenLewd","forsenLicence","forsenLookingAtYou","forsenLooted","forsenLUL","forsenM","forsenMald","forsenMoney","forsenMonkey","forsenNam","forsenO","forsenODO","forsenOG","forsenOP","forsenP","forsenPepe","forsenPog","forsenPosture","forsenPosture1","forsenPosture2","forsenPuke","forsenPuke2","forsenPuke3","forsenPuke4","forsenPuke5","forsenR","forsenReally","forsenRedSonic","forsenRP","forsenS","forsenSambool","forsenScoots","forsenSheffy","forsenSith","forsenSkip","forsenSleeper","forsenSmile","forsenSS","forsenStein","forsenSwag","forsenT","forsenTILT","forsenTriggered","forsenW","forsenWC","forsenWeird","forsenWeird25","forsenWhat","forsenWhip","forsenWitch","forsenWTF","forsenWut","forsenX","forsenY","forsenYHD","PogChimp"},
|
|
[10]= {"AdmiralBahroo","rooAww","rooBlank","rooBless","rooBlind","rooBonk","rooBooli","rooBot","rooC","rooCarry","rooComfy","rooCookie","rooCop","rooCry","rooCult","rooD","rooDab","rooDerp","rooDevil","rooDisgust","rooDuck","rooEZ","rooGift","rooGun","rooHappy","rooLick","rooLick2","rooLove","rooMadSlam","rooMurica","rooNap","rooNom","rooPog","rooPs","rooRave","rooREE","rooScheme","rooScream","rooSellout","rooSleepy","rooSmush","rooThink","rooTHIVV","rooUwU","rooVV","rooW","rooWhine","rooWut"},
|
|
[11]= {"VR","02Dab","02Stare","02Yum",":HEH:","astrovrCry","astrovrHi","astrovrRee","CuteMelon","DrunkMelon","GaspMelon","HyperHappyMelon","HyperMelon","MelonGun","OwOMelon","radiantAYAYA","radiantBlush","radiantBomb","radiantBoop","radiantComfy","radiantCry","radiantCult","radiantCute","radiantEEEEE","radiantEvil","radiantGimme","radiantGun","radiantHmm","radiantISee","radiantJam","radiantKek","radiantLag","radiantLick","radiantLurk","radiantNom","radiantOmega","radiantOmegaOWO","radiantOwO","radiantPat","radiantPepega","radiantPog","radiantPout","radiantREE","radiantSalute","radiantScared","radiantShrug","radiantSip","radiantSmile","radiantSmug","radiantSnoze","radiantStare","radiantTOS","radiantWave","radiantWeird","RageMelon","ReeMelon","SadMelon","SweatMelon","tyrissBlush","tyrissBoop","tyrissComfy","tyrissDisappointed","tyrissGasp","tyrissGimme","tyrissGlare","tyrissHeadpat","tyrissHeart","tyrissHeartz","tyrissHi","tyrissHug","tyrissHyper","tyrissLul","tyrissLurk","tyrissPout","tyrissRee","tyrissRip","tyrissS","tyrissSad","tyrissSmug","tyrissSmugOwO","tyrissThink","tyrissVictory","ZevvyBlush"},
|
|
[12]= {"Pepe",":copium:",":done:",":drama:",":fml:",":fork:",":hmm:",":memes:",":need:",":shy:",":skip:",":think:",":whip:","Awakge","BadW","beanping","Bedge","Bedges","BedgeTogether","binocs","binocsSpin","BLUBBERS","Blushge","BOOBA","BOOFA","Boolin","Borpa","BorpaL","BorpaU","Catge","Chatting","Clownge","ClownHypers","COCKA","Copege","COPIUM","CringeW","CROGGERS","Cryge","CutePepe","DankHug","Deadge","DeadgeTogether","dejj","Despairge","DinkDonk","ehWTF","EVILSMILERS","EZ","FARTIUM","FatBod","FatDank","Fatge","FeelsAmazingMan","FeelsBetaMan","FeelsBlushMan","FeelsBoredMan","FeelsCoolMan","FeelsCopterMan","FeelsCringeMan","FeelsCryManW","FeelsCuteMan","FeelsDeadMan","FeelsDrunkMan","FeelsEvilMan","FeelsFatMan","FeelsGamerMan","FeelsGermanMan","FeelsGreekMan","FeelsIllidanMan","FeelsIncredibleMan","FeelsLateMan","FeelsLitMan","FeelsLoveManW","FeelsMyFingerMan","FeelsOakyMan","FeelsOldMan","FeelsPinkMan","FeelsQueueMan","FeelsRainSadge","FeelsRottenMan","FeelsSad","FeelsSorryMan","FeelsStrongMan","FeelsSuicideMan","FeelsTastyMan","FeelsTiredAF","FeelsWeakMan","FeelsWiredMan","fingi","FrogO","FUARK","FUTA","Gayge","GiggleHands","Gladge","gladgers","goodd","GoodW","HabibiPrayge","HACKERMANS","HappyJammies","Hmmge","Hmmmge","HYPEROMEGAPOGGERSCRAZY","HYPERS","imKEKWing","imOkayChamp","Jammies","JanCarlo","KEKGA","KEKWHands","KMS","LMAO","lookdown","lookup","lovehug","Lovge","LULERS","Madge","MadgeBackhand","MadgeClap","Madgee","MadgeNow","MadgeRightNow","majj","MALDD","maximumautism","meAutism","monakGun","monakHmm","monakMultiple","monakS","monakW","monkaCapture","monkaGasp","monkaGIGA","monkaHands","monkaInsane","monkaLaugh","monkaMEGA","monkaMultiple","monkaOh","monkaOMEGA","monkaPickle","monkaS","monkaShake","monkaShoot","monkaStab","monkaStare","monkaSteer","monkaSusp","monkaT","monkaThink","monkaTOS","monkaU","monkaVirus","monkaW","monkaWCB","monkaX","monkaYou","monkerS","NA","nanoMEGA","NeedCopium","Nerdge","noClown","NODDERS","NOOBA","NOP","NOPERS","Notsurege","Okayeg","Okayga","Okayge","OkaygeShrug","OkayLaugh","OkayW","oldpepe","OMEGAEZ","oniongang","PAUSERS","peep","PeepHand","peepo","peepo2","peepoAlliance","peepoBaba","peepoBlankey","peepoBritish","peepoBye","peepoCat","peepoChonk","peepoChop","peepoClap","peepoComfy","peepoDab","peepoEhm","peepoEvilSip","peepofeet","peepoFoil","peepoFR1","peepoFR2","peepoGhost","peepoGiggle","peepoGroovie","peepoHeart","peepoHehe","peepoHey","peepoHorse","peepoIsForMe","peepoJail","peepoJedi","peepoJorts","peepoJudge","peepoJuice","peepoLoser","peepoM","peepoMadder","peepoNotes","peepoPanda","peepoParty","peepoPlease","peepoPolice","peepoRiot","peepoSadLogize","peepoScam","peepoShake","peepoShy","peepoSimp","peepoSimping","peepoSith","peepoSleepo","peepoSmash","peepoSoup","peepoSPopcorn","peepoStonks","peepoStrong","peepoSure","peepoSweat","peepoTeeth","peepoTrash","peepoWhy","peepoWow","PepeAyy","PepeBald","PepeBlyat","PepeBruh","PepeCat","PepeCatGun","PepeCatHeart","PepeCoffee","PepeCoolStory","PepeCozy","PepeCry","PepeDisgust","PepeDribble","PepeFlushed","PepeFrench","PepeFU","PepeFuming","PepegaCredit","PepegaHammer","PepegaHands","PepeGang","PepegaSad","PepeHammer","PepeHands","PepeHard","PepeHeart","PepeHmm","PepeHug","PepeJAM","PepeKMS","PepeL","PepeLa","PepeLaffe","PepeLegs","PepeLoser","PepeM","PepeMods","PepeNOOO","PepeNotOK","PepeOK","PepeOuuuhh","PepePains","PepePants","PepePhone","PepePhoned","PepePlan","PepePoint","PepePoo","PepePopcorn","PepePuke","PepePyroblast","PepeReach","PepeRun","PepeScoots","PepeScout","PepeSith","PepeSlice","PepeSmile","PepeSmug","PepeStepBro","PepeStressed","PepeThumbsUp","pepeW","PepeWizard","PepeWot","PepeXD","pepoEZ","pepoGun","PepoHide","pepoS","PepoScience","PepoThink","PepperHands","Plotge","pogg","PoggersHype","POGGIES","PogO2","POOGERS","ppEZ","ppFootbol","ppHop","Prayge","RandomPepe","Ratge","Readge","Riotge","SadBlanket","Sadga","Sadge","sadgers","SadHug","SadLove","SadPepe","SAJ","sajj","SALAMI","salutt","shadowChatting","shrujj","Smadge","SMILERS","Smoge","SMUGGERS","SmugPepe","soupchamp","Starege","Stronge","SucksMan","Susge","Suske","Thinkge","TiredW","tomatogang","TroggHYPERS","UHM","Voidge","Weirdga","Weirdge","WeirdJAM","WeirdU","WeirdW","WICKED","WickedDrip","WICKEDSTEER","widepeepoHappy","widepeepoLove","widepeepoPride","widepeepoSad","widepeepoWeird","WideSadge","widestpeepoHappy","widestpeepoSad","Wipege","WOAW","Wokege","Wokegesus","YEP","Yepge","YEPPERS","yikers"},
|
|
[13]= {"peepo","peepaKiss","peepoAP","peepoBeer","peepoBlanket","peepoBlush","peepoBored","peepoCool","peepoCringe","peepoCute","peepoExit","peepoEZ","peepoFA","peepoFat","peepoFH","peepoFight","peepoFriends","peepoGlad","peepoGun","peepoHands","peepoHide","peepoHit","peepoHmm","peepoHug","peepoHugged","peepoKEKW","peepoKiss","peepoKnight","peepoLip","peepoLove","peepoMaybe","peepoNo","peepoNolegs","peepoNOO","peepoOK","peepoPants","peepoPat","peepoPee","peepoPeek","peepoPlot","peepoPoint","peepoPoo","peepoPride","peepoRain","peepoReallyHappy","peepoS","peepoSad","peepoSalute","peepoSenor","peepoShrug","peepoSick","peepoSip","peepoSmile","peepoStudy","peepoSuspect","peepoSuspicious","peepoTeddy","peepoThink","peepoTired","peepoUgh","peepoWave","peepoWoW","peepoWTF","peepoYes","pillowJammies"},
|
|
[14]= {"Suze4Mumes Life","ANELELUL","angery","beamB","beamBrah","beenocs","bricky","bubby","CaptainSuze","ClownBall","ClownPain","coffeeS","EZGiggle","FeelsCozyMan","FeelsDankMan","FeelsShadowMan","GAmer","JanCarlo2","miffs","mumes","PauseChamp","peep420","peepKing","peepoCheer","peepoChef","peepoChrist","peepoCozy","peepoCrown","peepoCry","peepoDK","peepoEZSip","peepoH","peepOK","peepoKing","peepoKnife","peepoKnifeNANI","peepoMad","peepoStab","peepoSuze","peepoWeirdCrown","PepeBed","PepeChill","PepeClown","PepeCool","PepeCop","PepeGiggle","PepeGod","PepeHacker","PepeKing","PepeKingLove","PepeRuski","PepeScience","PepeSmurf","PepeSoldier","PepeSpartan","PepeStudy","PepeSurgeon","PepeSuspect","PepeWave","PepeWheels","PogChampius","PogO","potter","SadHonk","SchubertSmile","spit1","spit2","suze4animals","suze4food","suze4know","suze4study","suzeOK","TheBoys","WeirdChampius"},
|
|
[15]= {"Ren Custom","0Head","1Head","2Head","3Head","3Lass","4HEader","4Mansion","4Shrug","4Weird","5Hard","5Head",":fluff2:",":fluff:","AMAZINGA","BaconEffect","BlackKnight","Boomer","BroKiss","cmoN","cmonEyes","CrazyChamp","DisappointChamp","DKKona","FLOPPERS","HYPERDANSGAMEW","KEKL","KEKSad","KEKW","KEKWeird","kkOna","KKonaW","LULChamp","LULWW","MaldChamp","MaN","NaM","noxSorry","OhISee","OkayChamp","OldChamp","PATHETIC","PikaWOW","pOg","Pogey","PogeyU","Poghurt","PogWarts","SadChamp","SillyChamp","StareChamp","TriEasy","TriGold","TriHardo","TriHardS","TriKool","TriPeek","VaN","WeirdBruh","WeirdChamp","WhiteKnight","WutChamp"},
|
|
[16]= {"Chromie","CavemanBob","CcKekThas","CcMile","Dedge","GusFring"},
|
|
[17]= {"HoMMedia","Anthoing","Anthoing1","BirdgeBath","Byege","CloakBan","DIDSOMEONESAYCOCK","heyge","homStuff","mantisD","sct"},
|
|
[18]= {"AnnieFuchsia","anniesAngry","anniesAw","anniesAYAYA","anniesBlind","anniesCHEER","anniesCheer","anniesCopium","anniesCozy","anniesCute","anniesDab","anniesDinkDonk","anniesFingi","anniesFull","anniesGasp","anniesGiggle","anniesHi5","anniesHmm","anniesHypers","anniesJAM","anniesKnight","anniesLUL","anniesMega","anniesNo","anniesNodders","anniesNoted","anniesPanic","anniesPet","anniesPls","anniesPog","anniesPoint","anniesPray","anniesPrime","anniesRave","anniesREE","anniesRiot","anniesRIP","anniesSad","anniesSHY","anniesSteer","anniesSwe","anniesThisIsFine","anniesToxic","anniesYikes","anniesZug"},
|
|
[19]= {"cdewx","dewRag"},
|
|
[20]= {"Pokelawl","poke1","poke2","poke3","poke4","pokeCOZY","pokeCRY","pokeEZ","pokeG","pokeHD","pokeHmm","pokeHungry","pokeL","pokeLAWL","pokeLurk","pokeM","pokeP","pokeRage","pokeSip","pokeSMOKE","pokeSUBS","pokeU","pokeWeird"},
|
|
[21]= {"loltyler1","tyler1B","tyler1B1","tyler1B2","tyler1BAD","tyler1E","tyler1H","tyler1H1","tyler1H2","tyler1H3","tyler1H4","tyler1Int","tyler1S","tyler1X"},
|
|
[22]= {"MOONMOON_OW","moon2A","moon2AY","moon2B","moon2BED","moon2BRAIN","moon2D","moon2E","moon2G","moon2PREGARIO","moon2PREGIGI","moon2SERF"},
|
|
[23]= {"GNeko","02Angery","02Cry","02Uwu","Keqing","starechamp"},
|
|
[24]= {"xQc","xqcPlot"},
|
|
[25]= {"OG_Feedback","GorillaPump"},
|
|
[26]= {"GuildEmotes","4Town","5Champ",":epic:",":epicW:",":gary:",":guna:",":italy:",":jaina:",":KEK:",":praise:",":squawk:",":stabby:",":twoofakind:","AngeryCry","Angy","BigNars","BinCat","Breadclown","CatChest","CatFat","checkdoggo","CloakofShadows","Coomer","deadgemines","DidntAsk","FatCat","FatDragon","Fradre","HmmChamp","HomieKiss","HomieL","HomieR","HYPEROMEGALUL","InspectorAngryWoof","InspectorAngryWoofM","KEKE","KEKLeo","KEKPog","KEKPoint","KEKWPog","Lyeasy","LyeCute","LyeREE","LyeShrug","LyEZ","noxWhat","OkayChomp","OMEGAKEKW","PantsGrab","Pausey","Pog","PogOff","Pogomega","PogOW","PogTasty","RowFish","RowSalt","SadCash","SadCatWave","SadOke","SmileHard","SmookSpook","SmookWink","sosig","sosigW","ThrallS","TriTasty","Wardøg","widepeepoPog","YAMERO","YUM","Zoomer"},
|
|
[27]= {"TwitchTV",":tf:","WutFaceW","YeahBoi"},
|
|
[28]= {"typeg","hyperjoy","laughhard","typegBASED","typegBricked","typegChill","typegKEKB","typegLoad","typegPaul","typegWeed","typegYIP"},
|
|
};
|
|
|
|
function stripChars(str)
|
|
local tableAccents = {}
|
|
tableAccents["À"] = "A"
|
|
tableAccents["Á"] = "A"
|
|
tableAccents["Â"] = "A"
|
|
tableAccents["Ã"] = "A"
|
|
tableAccents["Ä"] = "A"
|
|
tableAccents["Å"] = "A"
|
|
tableAccents["Æ"] = "AE"
|
|
tableAccents["Ç"] = "C"
|
|
tableAccents["È"] = "E"
|
|
tableAccents["É"] = "E"
|
|
tableAccents["Ê"] = "E"
|
|
tableAccents["Ë"] = "E"
|
|
tableAccents["Ì"] = "I"
|
|
tableAccents["Í"] = "I"
|
|
tableAccents["Î"] = "I"
|
|
tableAccents["Ï"] = "I"
|
|
tableAccents["Ð"] = "D"
|
|
tableAccents["Ñ"] = "N"
|
|
tableAccents["Ò"] = "O"
|
|
tableAccents["Ó"] = "O"
|
|
tableAccents["Ô"] = "O"
|
|
tableAccents["Õ"] = "O"
|
|
tableAccents["Ö"] = "O"
|
|
tableAccents["Ø"] = "O"
|
|
tableAccents["Ù"] = "U"
|
|
tableAccents["Ú"] = "U"
|
|
tableAccents["Û"] = "U"
|
|
tableAccents["Ü"] = "U"
|
|
tableAccents["Ý"] = "Y"
|
|
tableAccents["Þ"] = "P"
|
|
tableAccents["ß"] = "s"
|
|
tableAccents["à"] = "a"
|
|
tableAccents["á"] = "a"
|
|
tableAccents["â"] = "a"
|
|
tableAccents["ã"] = "a"
|
|
tableAccents["ä"] = "a"
|
|
tableAccents["å"] = "a"
|
|
tableAccents["æ"] = "ae"
|
|
tableAccents["ç"] = "c"
|
|
tableAccents["è"] = "e"
|
|
tableAccents["é"] = "e"
|
|
tableAccents["ê"] = "e"
|
|
tableAccents["ë"] = "e"
|
|
tableAccents["ì"] = "i"
|
|
tableAccents["í"] = "i"
|
|
tableAccents["î"] = "i"
|
|
tableAccents["ï"] = "i"
|
|
tableAccents["ð"] = "eth"
|
|
tableAccents["ñ"] = "n"
|
|
tableAccents["ò"] = "o"
|
|
tableAccents["ó"] = "o"
|
|
tableAccents["ô"] = "o"
|
|
tableAccents["õ"] = "o"
|
|
tableAccents["ö"] = "o"
|
|
tableAccents["ø"] = "o"
|
|
tableAccents["ù"] = "u"
|
|
tableAccents["ú"] = "u"
|
|
tableAccents["û"] = "u"
|
|
tableAccents["ü"] = "u"
|
|
tableAccents["ý"] = "y"
|
|
tableAccents["þ"] = "p"
|
|
tableAccents["ÿ"] = "y"
|
|
local normalisedString = ''
|
|
local normalisedString = str: gsub("[%z\1-\127\194-\244][\128-\191]*", tableAccents)
|
|
return normalisedString
|
|
end
|
|
|
|
|
|
local BuildOptionsTable, BuildFavOptionsTable -- forward declarations; assigned below
|
|
local AceConfigDialog -- set at ADDON_LOADED; used by the LDB menu and the navigate button
|
|
|
|
--Minimap Button
|
|
function Emoticons_OnEvent(self, event, ...)
|
|
if (event == "ADDON_LOADED" and select(1, ...) == addonName) then
|
|
if not LDBIcon then
|
|
print("TwitchEmotes Error: LibDBIcon-1.0 not found!")
|
|
return
|
|
end
|
|
|
|
for k, v in pairs(origsettings) do
|
|
if k ~= "MinimapPos" and Emoticons_Settings[k] == nil then
|
|
Emoticons_Settings[k] = v;
|
|
end
|
|
end
|
|
|
|
-- Default any dropdown category with no saved favourite flag to on, so
|
|
-- categories added after a save was first written (e.g. HoMMedia) still
|
|
-- appear in the menu instead of silently defaulting off.
|
|
for n = 1, #dropdown_options do
|
|
if Emoticons_Settings["FAVEMOTES"][n] == nil then
|
|
Emoticons_Settings["FAVEMOTES"][n] = true
|
|
end
|
|
end
|
|
|
|
-- Create the LDB object first
|
|
local TwitchEmotesLDB = LDB:NewDataObject("TwitchEmotesIcon", {
|
|
type = "launcher",
|
|
icon = "Interface\\AddOns\\TwitchEmotes\\Emotes\\1337.tga",
|
|
tooltip = "Twitch Emotes",
|
|
OnClick = function(frame, button)
|
|
if IsShiftKeyDown() then
|
|
TwitchStats_Toggle()
|
|
elseif button == "LeftButton" then
|
|
ToggleDropDownMenu(1, nil, EmoticonChatFrameDropDown, frame, 0, 0)
|
|
elseif button == "RightButton" then
|
|
AceConfigDialog:Open(addonName)
|
|
end
|
|
end,
|
|
-- This LibDBIcon calls obj.OnEnter()/OnLeave() with no args (the
|
|
-- button is only available via the global `this`), unlike OnClick
|
|
-- which gets (this, mouseButton).
|
|
OnEnter = function()
|
|
GameTooltip:SetOwner(this, "ANCHOR_BOTTOMLEFT")
|
|
GameTooltip:AddLine("Twitch Emotes")
|
|
GameTooltip:AddLine("|cffeda55fClick:|r Show Emotes")
|
|
GameTooltip:AddLine("|cffeda55fShift-Click:|r Emote Statistics")
|
|
GameTooltip:AddLine("|cffeda55fRight-Click:|r Options")
|
|
GameTooltip:Show()
|
|
end,
|
|
OnLeave = function()
|
|
GameTooltip:Hide()
|
|
end
|
|
})
|
|
Emoticons_Settings.hide = not Emoticons_Settings["MINIMAPBUTTON"]
|
|
LDBIcon:Register("TwitchEmotesIcon", TwitchEmotesLDB, Emoticons_Settings)
|
|
|
|
-- 1.12 has no Blizzard Interface Options panel (InterfaceOptionsFrame
|
|
-- is a 3.0 addition), so options open as standalone AceConfigDialog
|
|
-- windows instead of AddToBlizOptions categories. We register straight
|
|
-- with AceConfigRegistry (what AceConfigDialog:Open reads from) rather
|
|
-- than the AceConfig wrapper, whose Ace3v RegisterOptionsTable errors
|
|
-- when called on the library itself and only adds slash-command support
|
|
-- we don't use.
|
|
local AceConfigRegistry = LibStub("AceConfigRegistry-3.0")
|
|
AceConfigDialog = LibStub("AceConfigDialog-3.0")
|
|
AceConfigRegistry:RegisterOptionsTable("TwitchEmotes", BuildOptionsTable())
|
|
AceConfigRegistry:RegisterOptionsTable("TwitchEmotesFavs", BuildFavOptionsTable())
|
|
AceConfigDialog:SetDefaultSize("TwitchEmotes", 600, 500)
|
|
AceConfigDialog:SetDefaultSize("TwitchEmotesFavs", 400, 500)
|
|
end
|
|
end
|
|
|
|
local addonFrame = CreateFrame("Frame")
|
|
addonFrame:RegisterEvent("ADDON_LOADED")
|
|
addonFrame:SetScript("OnEvent", Emoticons_OnEvent)
|
|
|
|
local ItemTextPageTextSetText = ItemTextPageText.SetText;
|
|
function ItemTextPageText.SetText(self, msg, ...)
|
|
if(Emoticons_Settings["MAIL"] and msg ~= nil) then
|
|
msg = Emoticons_RunReplacement(msg);
|
|
end
|
|
ItemTextPageTextSetText(self, msg, ...);
|
|
end
|
|
|
|
local OpenMailBodyTextSetText = OpenMailBodyText.SetText;
|
|
function OpenMailBodyText.SetText(self,msg,...)
|
|
if(Emoticons_Settings["MAIL"] and msg ~= nil) then
|
|
msg = Emoticons_RunReplacement(msg);
|
|
end
|
|
OpenMailBodyTextSetText(self,msg,...);
|
|
end
|
|
|
|
-- A DropDownList shows at most UIDROPDOWNMENU_MAXBUTTONS (40) rows, and menus
|
|
-- go at most UIDROPDOWNMENU_MAXLEVELS (3) deep. One entry per pack:
|
|
-- level 1 = pack -> level 2 = emote-range pages (only if >40) -> level 3 = emotes
|
|
-- A pack with <=40 emotes skips the page level (level 2 lists its emotes).
|
|
local function Emoticons_CatPages(v)
|
|
return math.max(1, math.ceil((#v - 1) / UIDROPDOWNMENU_MAXBUTTONS));
|
|
end
|
|
|
|
local function Emoticons_AddEmotes(k, page, level)
|
|
local v = dropdown_options[k];
|
|
if (not v) then return end
|
|
local first = (page - 1) * UIDROPDOWNMENU_MAXBUTTONS + 2; -- [1] is the pack name
|
|
local last = math.min(first + UIDROPDOWNMENU_MAXBUTTONS - 1, #v);
|
|
for i = first, last do
|
|
local va = v[i];
|
|
local info = UIDropDownMenu_CreateInfo();
|
|
info.text = "|T"..defaultpack[va].."|t "..va;
|
|
info.value = va;
|
|
info.func = Emoticons_Dropdown_OnClick;
|
|
info.arg1 = va;
|
|
info.notCheckable = 1;
|
|
UIDropDownMenu_AddButton(info, level);
|
|
end
|
|
end
|
|
|
|
function Emoticons_LoadChatFrameDropdown(level)
|
|
level = level or UIDROPDOWNMENU_MENU_LEVEL or 1;
|
|
if (level == 1) then
|
|
for k, v in ipairs(dropdown_options) do
|
|
if (Emoticons_Settings["FAVEMOTES"][k]) then
|
|
local info = UIDropDownMenu_CreateInfo();
|
|
info.hasArrow = 1;
|
|
info.notCheckable = 1;
|
|
info.text = v[1];
|
|
info.value = { category = k };
|
|
UIDropDownMenu_AddButton(info, level);
|
|
end
|
|
end
|
|
else
|
|
local value = UIDROPDOWNMENU_MENU_VALUE;
|
|
if (type(value) ~= "table") then return end
|
|
local v = dropdown_options[value.category];
|
|
if (not v) then return end
|
|
if (value.page) then
|
|
Emoticons_AddEmotes(value.category, value.page, level); -- level 3: emotes of a page
|
|
elseif (Emoticons_CatPages(v) > 1) then
|
|
local pages = Emoticons_CatPages(v); -- level 2: name-range pages
|
|
for page = 1, pages do
|
|
local firstIdx = (page - 1) * UIDROPDOWNMENU_MAXBUTTONS + 2; -- [1] is the pack name
|
|
local lastIdx = math.min(page * UIDROPDOWNMENU_MAXBUTTONS + 1, #v);
|
|
local info = UIDropDownMenu_CreateInfo();
|
|
info.hasArrow = 1;
|
|
info.notCheckable = 1;
|
|
info.text = v[firstIdx].."-"..v[lastIdx]; -- e.g. "majj-peepofeet"
|
|
info.value = { category = value.category, page = page };
|
|
UIDropDownMenu_AddButton(info, level);
|
|
end
|
|
else
|
|
Emoticons_AddEmotes(value.category, 1, level); -- level 2: emotes (single page)
|
|
end
|
|
end
|
|
end
|
|
function Emoticons_Dropdown_OnClick(emote)
|
|
if (ChatFrameEditBox:IsVisible()) then
|
|
ChatFrameEditBox:Insert(emote);
|
|
end
|
|
end
|
|
function Emoticons_MailFrame_OnChar(self)
|
|
local msg = self:GetText();
|
|
if(Emoticons_Eyecandy and Emoticons_Settings["MAIL"] and string.sub(msg,1,1) ~= "/") then
|
|
self:SetText(Emoticons_RunReplacement(msg));
|
|
end
|
|
end
|
|
|
|
local sm = SendMail;
|
|
function SendMail(recipient,subject,msg,...)
|
|
if(Emoticons_Eyecandy and Emoticons_Settings["MAIL"]) then
|
|
msg = Emoticons_Deformat(msg);
|
|
end
|
|
sm(recipient,subject,msg,...);
|
|
end
|
|
|
|
local scm = SendChatMessage;
|
|
function SendChatMessage(msg,...)
|
|
if(Emoticons_Eyecandy) then
|
|
msg = Emoticons_Deformat(msg);
|
|
end
|
|
scm(msg,...);
|
|
end
|
|
|
|
-- Overridden by TwitchEmotesStats.lua with a version that also counts
|
|
-- emote usage. sender is the message author (arg2 of CHAT_MSG_* events).
|
|
function Emoticons_FilterMessage(msg, sender)
|
|
return Emoticons_RunReplacement(msg);
|
|
end
|
|
|
|
-- 1.12 has no ChatFrame_AddMessageEventFilter; hook ChatFrame_OnEvent and
|
|
-- rewrite the message in the global arg1 before the original handler prints
|
|
-- it. Gating on Emoticons_Settings[event] only passes for the CHAT_MSG_*
|
|
-- keys, which are toggled live by Emoticons_SetType.
|
|
local Emoticons_Orig_ChatFrame_OnEvent = ChatFrame_OnEvent;
|
|
function ChatFrame_OnEvent(event)
|
|
if (arg1 and Emoticons_Settings[event]) then
|
|
arg1 = Emoticons_FilterMessage(arg1, arg2);
|
|
end
|
|
Emoticons_Orig_ChatFrame_OnEvent(event);
|
|
end
|
|
|
|
function Emoticons_Deformat(msg)
|
|
for k,v in pairs(emoticons) do
|
|
msg = string.gsub(msg, "|T"..defaultpack[k].."|t", v);
|
|
end
|
|
return msg;
|
|
end
|
|
|
|
function Emoticons_RunReplacement(msg)
|
|
-- Turtle WoW wraps GM chat in a colour escape server-side (|c1049e6ff...|r,
|
|
-- see tortoise-wow Chat.cpp BuildChatPacket). That glues the first/last words
|
|
-- to |c<hex>/|r so they never tokenise as emotes. Peel a leading colour code
|
|
-- and its trailing |r, replace the inner text, then re-wrap. Lossless for the
|
|
-- ordinary "message is a single item link" case too.
|
|
local prefix, suffix = "", "";
|
|
local color = string.match(msg, "^(|c%x%x%x%x%x%x%x%x)");
|
|
if(color) then
|
|
prefix = color;
|
|
msg = string.sub(msg, string.len(color) + 1);
|
|
if(string.sub(msg, -2) == "|r") then
|
|
suffix = "|r";
|
|
msg = string.sub(msg, 1, -3);
|
|
end
|
|
end
|
|
|
|
local outstr = "";
|
|
local origlen = string.len(msg);
|
|
local startpos = 1;
|
|
local endpos;
|
|
|
|
while(startpos <= origlen) do
|
|
endpos = origlen;
|
|
local pos = string.find(msg,"|H",startpos,true);
|
|
if(pos ~= nil) then
|
|
endpos = pos;
|
|
end
|
|
outstr = outstr .. Emoticons_InsertEmoticons(string.sub(msg,startpos,endpos));
|
|
startpos = endpos + 1;
|
|
if(pos ~= nil) then
|
|
endpos = string.find(msg,"|h",startpos,true);
|
|
if(endpos == nil) then
|
|
endpos = origlen;
|
|
end
|
|
if(startpos < endpos) then
|
|
outstr = outstr .. string.sub(msg,startpos,endpos);
|
|
startpos = endpos + 1;
|
|
end
|
|
end
|
|
end
|
|
|
|
return prefix .. outstr .. suffix;
|
|
end
|
|
|
|
function Emoticons_SetEyecandy(state)
|
|
if(state) then
|
|
Emoticons_Eyecandy = true;
|
|
if(ChatFrameEditBox:IsVisible()) then
|
|
ChatFrameEditBox:SetText(Emoticons_RunReplacement(ChatFrameEditBox:GetText()));
|
|
end
|
|
else
|
|
Emoticons_Eyecandy = false;
|
|
if(ChatFrameEditBox:IsVisible()) then
|
|
ChatFrameEditBox:SetText(Emoticons_Deformat(ChatFrameEditBox:GetText()));
|
|
end
|
|
end
|
|
end
|
|
|
|
function Emoticons_SetMinimapButton(state)
|
|
if state then state = true else state = false end
|
|
|
|
Emoticons_Settings["MINIMAPBUTTON"] = state;
|
|
|
|
if LDBIcon then
|
|
if state then
|
|
LDBIcon:Show("TwitchEmotesIcon")
|
|
else
|
|
LDBIcon:Hide("TwitchEmotesIcon")
|
|
end
|
|
else
|
|
print("TwitchEmotes Error: LibDBIcon not available when trying to set minimap button visibility.")
|
|
end
|
|
end
|
|
local EMOTE_DELIMITERS = "%s,'<>?-%.!"
|
|
|
|
function Emoticons_InsertEmoticons(msg)
|
|
local wrapPattern = "([" .. EMOTE_DELIMITERS .. "]+)"
|
|
for word in string.gmatch(msg, "[^" .. EMOTE_DELIMITERS .. "]+") do
|
|
local emote = emoticons[word]
|
|
if (emote and defaultpack[emote]) then
|
|
local tex = defaultpack[emote]
|
|
local core
|
|
if (Emoticons_Settings["CLICKABLEEMOTES"]) then
|
|
core = "|Htel:" .. word .. "|h|T" .. tex .. "|t|h"
|
|
else
|
|
core = "|T" .. tex .. "|t"
|
|
end
|
|
msg = string.gsub(msg, wrapPattern .. word .. wrapPattern, "%1" .. core .. "%2", 1)
|
|
msg = string.gsub(msg, wrapPattern .. word .. "$", "%1" .. core, 1)
|
|
msg = string.gsub(msg, "^" .. word .. wrapPattern, core .. "%1", 1)
|
|
msg = string.gsub(msg, "^" .. word .. "$", core)
|
|
msg = string.gsub(msg, wrapPattern .. word .. "(%c)", "%1" .. core .. "%2", 1)
|
|
msg = string.gsub(msg, wrapPattern .. word .. wrapPattern, "%1" .. core .. "%2", 1)
|
|
end
|
|
end
|
|
return msg;
|
|
end
|
|
|
|
function Emoticons_SetType(chattype,state)
|
|
if(state) then
|
|
state = true;
|
|
else
|
|
state = false;
|
|
end
|
|
if(chattype == "CHAT_MSG_RAID") then
|
|
Emoticons_Settings["CHAT_MSG_RAID_LEADER"] = state;
|
|
Emoticons_Settings["CHAT_MSG_RAID_WARNING"] = state;
|
|
end
|
|
if(chattype == "CHAT_MSG_PARTY") then
|
|
Emoticons_Settings["CHAT_MSG_PARTY_LEADER"] = state;
|
|
Emoticons_Settings["CHAT_MSG_PARTY_GUIDE"] = state;
|
|
end
|
|
if(chattype == "CHAT_MSG_WHISPER") then
|
|
Emoticons_Settings["CHAT_MSG_WHISPER_INFORM"] = state;
|
|
end
|
|
if(chattype == "CHAT_MSG_BATTLEGROUND") then
|
|
Emoticons_Settings["CHAT_MSG_BATTLEGROUND_LEADER"] = state;
|
|
end
|
|
Emoticons_Settings[chattype] = state;
|
|
end
|
|
local EmoticonChatFrameDropDown = CreateFrame("Frame", "EmoticonChatFrameDropDown", UIParent, "UIDropDownMenuTemplate")
|
|
UIDropDownMenu_Initialize(EmoticonChatFrameDropDown, Emoticons_LoadChatFrameDropdown, "MENU", 1)
|
|
|
|
-- ToggleDropDownMenu only tests whether a list runs off the bottom or the
|
|
-- right of the screen, flips its anchor once and never re-measures, so a list
|
|
-- flipped upwards overflows the top instead (a 40-row emote page opened from a
|
|
-- submenu halfway down the screen), and its off-screen-X test compares the
|
|
-- list's own coordinates against pixel widths, flipping submenus left even
|
|
-- when that pushes them past the left edge. Nudge our own lists back inside
|
|
-- the screen after it has positioned them; the emote pages are at most
|
|
-- 40 * UIDROPDOWNMENU_BUTTON_HEIGHT + borders tall, so they always fit.
|
|
local function Emoticons_ClampDropDownList(level)
|
|
local list = _G["DropDownList"..level];
|
|
if (not list or not list:IsShown()) then return end
|
|
local scale = list:GetEffectiveScale();
|
|
local uiScale = UIParent:GetEffectiveScale();
|
|
local left, right = list:GetLeft(), list:GetRight();
|
|
local bottom, top = list:GetBottom(), list:GetTop();
|
|
if (not left or not bottom) then return end
|
|
-- Everything below is in screen pixels, since the list carries a scale of
|
|
-- its own (ToggleDropDownMenu sets it from the uiscale cvar).
|
|
left, right, bottom, top = left * scale, right * scale, bottom * scale, top * scale;
|
|
local screenWidth = GetScreenWidth() * uiScale;
|
|
local screenHeight = GetScreenHeight() * uiScale;
|
|
local dx, dy = 0, 0;
|
|
if (right > screenWidth) then dx = screenWidth - right end
|
|
if (left + dx < 0) then dx = -left end -- a list wider than the screen keeps its left edge
|
|
if (top > screenHeight) then dy = screenHeight - top end
|
|
if (bottom + dy < 0) then dy = -bottom end
|
|
if (dx == 0 and dy == 0) then return end
|
|
-- UIParent's BOTTOMLEFT is screen pixel (0,0); SetPoint offsets are in the
|
|
-- units of the frame being moved, so scale the corrected position back down.
|
|
list:ClearAllPoints();
|
|
list:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", (left + dx) / scale, (top + dy) / scale);
|
|
end
|
|
|
|
local Emoticons_Orig_ToggleDropDownMenu = ToggleDropDownMenu;
|
|
function ToggleDropDownMenu(level, value, dropDownFrame, anchorName, xOffset, yOffset)
|
|
Emoticons_Orig_ToggleDropDownMenu(level, value, dropDownFrame, anchorName, xOffset, yOffset);
|
|
-- Submenus are opened by the list buttons themselves with no dropDownFrame,
|
|
-- so identify ours by the menu ToggleDropDownMenu just recorded as open.
|
|
if (UIDROPDOWNMENU_OPEN_MENU == "EmoticonChatFrameDropDown") then
|
|
Emoticons_ClampDropDownList(level or 1);
|
|
end
|
|
end
|
|
|
|
do
|
|
local pending, seen = {}, {}
|
|
for _, group in ipairs(dropdown_options) do
|
|
for i = 2, #group do
|
|
local tex = defaultpack[group[i]]
|
|
if tex and not seen[tex] then
|
|
seen[tex] = true
|
|
pending[#pending + 1] = (string.gsub(tex, ":%d+:%d+$", ""))
|
|
end
|
|
end
|
|
end
|
|
|
|
local warmer = CreateFrame("Frame")
|
|
local retained = {}
|
|
local idx = 0
|
|
warmer:SetScript("OnUpdate", function(self)
|
|
if InCombatLockdown() then return end
|
|
local budget = 15
|
|
while budget > 0 and idx < #pending do
|
|
idx = idx + 1
|
|
local t = self:CreateTexture(nil, "BACKGROUND")
|
|
t:SetTexture(pending[idx])
|
|
t:Hide()
|
|
retained[idx] = t
|
|
budget = budget - 1
|
|
end
|
|
if idx >= #pending then
|
|
self:SetScript("OnUpdate", nil)
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- ── AceConfig options tables ──────────────────────────────────────────────────
|
|
|
|
BuildOptionsTable = function()
|
|
local opts = {
|
|
type = "group",
|
|
name = "TwitchEmotes",
|
|
args = {
|
|
channelsHeader = { type = "header", name = "Chat Channels", order = 1 },
|
|
say = { type = "toggle", name = "Say", order = 2,
|
|
get = function() return Emoticons_Settings["CHAT_MSG_SAY"] end,
|
|
set = function(_, v) Emoticons_SetType("CHAT_MSG_SAY", v) end },
|
|
yell = { type = "toggle", name = "Yell", order = 3,
|
|
get = function() return Emoticons_Settings["CHAT_MSG_YELL"] end,
|
|
set = function(_, v) Emoticons_SetType("CHAT_MSG_YELL", v) end },
|
|
guild = { type = "toggle", name = "Guild", order = 4,
|
|
get = function() return Emoticons_Settings["CHAT_MSG_GUILD"] end,
|
|
set = function(_, v) Emoticons_SetType("CHAT_MSG_GUILD", v) end },
|
|
officer = { type = "toggle", name = "Officer", order = 5,
|
|
get = function() return Emoticons_Settings["CHAT_MSG_OFFICER"] end,
|
|
set = function(_, v) Emoticons_SetType("CHAT_MSG_OFFICER", v) end },
|
|
whisper = { type = "toggle", name = "Whisper", order = 6,
|
|
get = function() return Emoticons_Settings["CHAT_MSG_WHISPER"] end,
|
|
set = function(_, v) Emoticons_SetType("CHAT_MSG_WHISPER", v) end },
|
|
party = { type = "toggle", name = "Party", order = 7,
|
|
get = function() return Emoticons_Settings["CHAT_MSG_PARTY"] end,
|
|
set = function(_, v) Emoticons_SetType("CHAT_MSG_PARTY", v) end },
|
|
raid = { type = "toggle", name = "Raid", order = 8,
|
|
get = function() return Emoticons_Settings["CHAT_MSG_RAID"] end,
|
|
set = function(_, v) Emoticons_SetType("CHAT_MSG_RAID", v) end },
|
|
channel = { type = "toggle", name = "Channel", order = 9,
|
|
get = function() return Emoticons_Settings["CHAT_MSG_CHANNEL"] end,
|
|
set = function(_, v) Emoticons_SetType("CHAT_MSG_CHANNEL", v) end },
|
|
battleground = { type = "toggle", name = "Battleground", order = 10,
|
|
get = function() return Emoticons_Settings["CHAT_MSG_BATTLEGROUND"] end,
|
|
set = function(_, v) Emoticons_SetType("CHAT_MSG_BATTLEGROUND", v) end },
|
|
mail = { type = "toggle", name = "Mail", order = 11,
|
|
get = function() return Emoticons_Settings["MAIL"] end,
|
|
set = function(_, v) Emoticons_Settings["MAIL"] = v end },
|
|
minimapHeader = { type = "header", name = "Minimap", order = 20 },
|
|
minimapButton = { type = "toggle", name = "Show Minimap Button", order = 21,
|
|
get = function() return Emoticons_Settings["MINIMAPBUTTON"] end,
|
|
set = function(_, v) Emoticons_SetMinimapButton(v) end },
|
|
bubblesHeader = { type = "header", name = "Chat Bubbles", order = 25 },
|
|
bubbleEmotes = { type = "toggle", name = "Show emotes in chat bubbles", order = 26,
|
|
get = function() return Emoticons_Settings["BUBBLEEMOTES"] end,
|
|
set = function(_, v) Emoticons_Settings["BUBBLEEMOTES"] = v end },
|
|
autocompleteHeader = { type = "header", name = "Autocomplete", order = 27 },
|
|
autocomplete = { type = "toggle", name = "Enable emote autocomplete", order = 28,
|
|
get = function() return Emoticons_Settings["AUTOCOMPLETE"] end,
|
|
set = function(_, v) Emoticons_Settings["AUTOCOMPLETE"] = v end },
|
|
clickableHeader = { type = "header", name = "Clickable Emotes", order = 28.5 },
|
|
clickableEmotes = { type = "toggle", name = "Clickable / hover emotes (show name on mouseover)", order = 28.6,
|
|
get = function() return Emoticons_Settings["CLICKABLEEMOTES"] end,
|
|
set = function(_, v) Emoticons_Settings["CLICKABLEEMOTES"] = v end },
|
|
favHeader = { type = "header", name = "Favourites", order = 29 },
|
|
openFavs = { type = "execute", name = "Open Favourite Groups", order = 30,
|
|
func = function()
|
|
AceConfigDialog:Open("TwitchEmotesFavs")
|
|
end },
|
|
},
|
|
}
|
|
return opts
|
|
end
|
|
|
|
BuildFavOptionsTable = function()
|
|
local opts = {
|
|
type = "group",
|
|
name = "Favourites",
|
|
args = {
|
|
enableAll = {
|
|
type = "execute", name = "Enable All", order = 1,
|
|
func = function()
|
|
for n = 1, #dropdown_options do
|
|
Emoticons_Settings["FAVEMOTES"][n] = true
|
|
end
|
|
end,
|
|
},
|
|
disableAll = {
|
|
type = "execute", name = "Disable All", order = 2,
|
|
func = function()
|
|
for n = 1, #dropdown_options do
|
|
Emoticons_Settings["FAVEMOTES"][n] = false
|
|
end
|
|
end,
|
|
},
|
|
spacer = { type = "header", name = "", order = 3 },
|
|
},
|
|
}
|
|
for n, groupData in ipairs(dropdown_options) do
|
|
opts.args["fav_" .. n] = {
|
|
type = "toggle",
|
|
name = groupData[1],
|
|
order = 10 + n,
|
|
get = function() return Emoticons_Settings["FAVEMOTES"][n] end,
|
|
set = function(_, v) Emoticons_Settings["FAVEMOTES"][n] = v end,
|
|
}
|
|
end
|
|
return opts
|
|
end
|
|
|
|
-- ── Chat Bubble Emoticon Processing ──────────────────────────────────────────
|
|
|
|
local EmoticonBubbles = {}
|
|
|
|
local function bubbleReplace(text)
|
|
if not Emoticons_Settings["BUBBLEEMOTES"] then return text end
|
|
local input = text .. " "
|
|
local cur = input
|
|
local prev
|
|
repeat
|
|
prev = cur
|
|
cur = Emoticons_RunReplacement(cur)
|
|
until cur == prev
|
|
if cur ~= input then
|
|
return cur
|
|
end
|
|
return text
|
|
end
|
|
|
|
-- The bubble text is drawn by one of two FontStrings we can't just overwrite:
|
|
-- * the engine's own (default UI) — SetText doesn't stick, the engine
|
|
-- re-asserts its text;
|
|
-- * pfUI's replacement (bubble.frame.text) when pfUI's bubbles module is on —
|
|
-- it shows the raw text in a pfUI-styled bubble and re-sets it on OnShow.
|
|
-- So we hide whichever one currently shows the text and draw our own
|
|
-- auto-sizing overlay (no width constraint, so wide emotes never clip) on top.
|
|
local function bubbleDisplayFS(bubble)
|
|
if bubble.frame and bubble.frame.text then -- pfUI's bubbles module owns it
|
|
return bubble.frame.text
|
|
end
|
|
return bubble.tweEngineFS
|
|
end
|
|
|
|
local function applyBubbleEmotes(bubble)
|
|
local fs = bubbleDisplayFS(bubble)
|
|
local overlay = bubble.tweOverlay
|
|
if not fs or not overlay then return end
|
|
local raw = fs:GetText()
|
|
if raw and raw ~= "" and Emoticons_Settings["BUBBLEEMOTES"] then
|
|
local newText = bubbleReplace(raw)
|
|
if newText ~= raw then
|
|
local r, g, b, a = fs:GetTextColor()
|
|
overlay:SetText(newText)
|
|
overlay:SetTextColor(r, g, b, a)
|
|
overlay:Show()
|
|
fs:Hide()
|
|
return
|
|
end
|
|
end
|
|
-- no emotes (or feature off): show the source text, hide our overlay
|
|
overlay:Hide()
|
|
fs:Show()
|
|
end
|
|
|
|
-- ClassicAPI exposes the modern C_ChatBubbles.GetAllChatBubbles(); the spoken
|
|
-- text is a FontString region of each bubble. Each bubble is prepared once — we
|
|
-- find its display FontString, build a matching auto-sizing overlay on the same
|
|
-- parent (so scale matches pfUI's scaled child when present), and HookScript
|
|
-- OnShow so pooled bubbles re-sync when the engine (or pfUI) recycles them. The
|
|
-- scan is deferred (see the event handler) so pfUI's per-bubble setup already
|
|
-- ran and our OnShow hook lands after pfUI's.
|
|
function EmoticonBubbles:ScanBubbles()
|
|
for _, bubble in ipairs(C_ChatBubbles.GetAllChatBubbles()) do
|
|
if bubble.tweEngineFS == nil then
|
|
bubble.tweEngineFS = false -- mark inspected even if none found
|
|
for j = 1, bubble:GetNumRegions() do
|
|
local region = select(j, bubble:GetRegions())
|
|
if region and region:GetObjectType() == "FontString" then
|
|
bubble.tweEngineFS = region
|
|
break
|
|
end
|
|
end
|
|
if bubble.tweEngineFS then
|
|
local fs = bubbleDisplayFS(bubble)
|
|
local overlay = fs:GetParent():CreateFontString(nil, "OVERLAY")
|
|
local font, size, flags = fs:GetFont()
|
|
overlay:SetFont(font, size, flags)
|
|
overlay:SetPoint("CENTER", fs, "CENTER", 0, 0)
|
|
bubble.tweOverlay = overlay
|
|
bubble:HookScript("OnShow", applyBubbleEmotes)
|
|
end
|
|
end
|
|
if bubble.tweEngineFS then
|
|
applyBubbleEmotes(bubble)
|
|
end
|
|
end
|
|
end
|
|
|
|
local bubbleFrame = CreateFrame("Frame")
|
|
bubbleFrame:RegisterEvent("CHAT_MSG_SAY")
|
|
bubbleFrame:RegisterEvent("CHAT_MSG_YELL")
|
|
bubbleFrame:RegisterEvent("CHAT_MSG_PARTY")
|
|
bubbleFrame:RegisterEvent("CHAT_MSG_PARTY_LEADER")
|
|
bubbleFrame:RegisterEvent("CHAT_MSG_MONSTER_SAY")
|
|
bubbleFrame:RegisterEvent("CHAT_MSG_MONSTER_YELL")
|
|
bubbleFrame:RegisterEvent("CHAT_MSG_MONSTER_PARTY")
|
|
bubbleFrame:SetScript("OnEvent", function()
|
|
if Emoticons_Settings["BUBBLEEMOTES"] then
|
|
-- Defer two frames: the bubble attaches one frame after the chat event,
|
|
-- and pfUI's bubbles module (if active) sets up on that same next frame.
|
|
-- Running a frame later lets us detect pfUI's managed FontString and land
|
|
-- our OnShow hook after pfUI's SetScript, regardless of addon load order.
|
|
RunNextFrame(function() RunNextFrame(function() EmoticonBubbles:ScanBubbles() end) end)
|
|
end
|
|
end)
|
|
|
|
-- ── Clickable / hoverable emote hyperlinks ───────────────────────────────────
|
|
-- When CLICKABLEEMOTES is enabled, Emoticons_InsertEmoticons wraps each emote
|
|
-- texture in a |Htel:<name>|h ... |h hyperlink. These hooks show the emote name
|
|
-- on hover, insert the emote code into chat on shift-click (the CHATLINK
|
|
-- modifier, like item links), and harmlessly swallow a plain click (the link
|
|
-- type is not a real item/spell link, so the default handler must not resolve it).
|
|
|
|
-- Put the emote code into the chat edit box (opening it if needed).
|
|
local function Emoticons_InsertEmoteToChat(name)
|
|
if ChatFrameEditBox:IsVisible() then
|
|
ChatFrameEditBox:Insert(name)
|
|
else
|
|
ChatFrame_OpenChat(name)
|
|
end
|
|
end
|
|
|
|
local Emoticons_orig_SetItemRef = SetItemRef
|
|
function SetItemRef(link, text, button, chatFrame)
|
|
if link and link:sub(1, 4) == "tel:" then
|
|
-- Always swallow tel: clicks so old links can't error, but only act on
|
|
-- shift-click while the feature is enabled.
|
|
if Emoticons_Settings["CLICKABLEEMOTES"] and IsShiftKeyDown() then
|
|
Emoticons_InsertEmoteToChat(string.sub(link, 5))
|
|
end
|
|
return
|
|
end
|
|
return Emoticons_orig_SetItemRef(link, text, button, chatFrame)
|
|
end
|
|
|
|
local function Emoticons_OnHyperlinkEnter(self, link)
|
|
if link and Emoticons_Settings["CLICKABLEEMOTES"] and link:sub(1, 4) == "tel:" then
|
|
GameTooltip:SetOwner(self, "ANCHOR_CURSOR")
|
|
GameTooltip:SetText(link:sub(5), 1, 0.82, 0)
|
|
GameTooltip:Show()
|
|
end
|
|
end
|
|
|
|
local function Emoticons_OnHyperlinkLeave(self, link)
|
|
if link and link:sub(1, 4) == "tel:" then
|
|
GameTooltip:Hide()
|
|
end
|
|
end
|
|
|
|
local hyperlinkFrame = CreateFrame("Frame")
|
|
hyperlinkFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
hyperlinkFrame:SetScript("OnEvent", function(self)
|
|
if self.hooked then return end
|
|
self.hooked = true
|
|
for i = 1, (NUM_CHAT_WINDOWS or 10) do
|
|
local cf = _G["ChatFrame" .. i]
|
|
if cf and cf.HookScript then
|
|
-- pcall: if this client build doesn't expose these script handlers,
|
|
-- degrade gracefully (clicks still swallowed, emotes still render).
|
|
pcall(cf.HookScript, cf, "OnHyperlinkEnter", Emoticons_OnHyperlinkEnter)
|
|
pcall(cf.HookScript, cf, "OnHyperlinkLeave", Emoticons_OnHyperlinkLeave)
|
|
end
|
|
end
|
|
end) |