view SayIt.lua @ 2:0b3ef26f2bb3 v1.0

Testing .pkgmeta
author contrebasse
date Sun, 08 May 2011 17:18:02 +0200
parents 24f337b9dfa0
children
line wrap: on
line source
--[[ TODO :
- Changer la couleur pour toutes les fenêtres de quête (possible ?)
- Chercher le texte pour les couleurs à partir de la somme des longueurs de texte précédents (incrémental), compliqué !
- Modifier les variables statiques directement dans la fonction Paragraphes() (Bof...)
- Traduction
- Clic droit pour phrase perso
- Shif clic droit pour emote
- griser le choix des couleurs si pas de coloration
- reset des options (virer les couleurs foireuses...)
--]]

--********************************************************
--
-- Déclarations de variables
--
--********************************************************
--
-- Variables statiques
--
local target_name = "" -- "" vide ou nom du npc
local text_table = {}  -- table du texte à dire
local text_full = ''
local i_phrase = 1     -- indice de la prochaine phrase à dire
--local char_dits = 0    -- nombre de caractères prononcés, pour améliorer la recherche lors de la coloration
local max_phrase = 0   -- indice du nombre de phrases à dire
local gossip_button, quest_button, current_button
local TextFrame

--
-- Fonctions locales pour accélérer l'exécution
--
local _G = _G
local GetUnitName = GetUnitName
local GetQuestText = GetQuestText
local GetProgressText = GetProgressText
local GetGossipText = GetGossipText
local GetRewardText = GetRewardText
local DEFAULT_CHAT_FRAME = DEFAULT_CHAT_FRAME
local UIErrorsFrame,UIErrorsFrame_OnEvent = UIErrorsFrame,UIErrorsFrame_OnEvent
local SendChatMessage = SendChatMessage
local GameTooltip = GameTooltip
local CreateFrame = CreateFrame
local IsShiftKeyDown,IsControlKeyDown = IsShiftKeyDown,IsControlKeyDown
local GossipFrame,QuestFrame = GossipFrame,QuestFrame
local GossipGreetingText = GossipGreetingText
local QuestProgressText = QuestProgressText
local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor;

local tonumber = tonumber;
local string = string;
local string_format = string.format;

local LibStub = LibStub;

--********************************************************
--
-- Fonctions de debug et warning
--
--********************************************************
--
-- fonction qui affiche des messages de debug
--
local function DEBUG(msg)
	--if true then return end
	if not msg then msg="nil" end
	DEFAULT_CHAT_FRAME:AddMessage("(DEBUG) " .. msg);
end

local function Warn(msg)
	if not msg then return end
	--DEFAULT_CHAT_FRAME:AddMessage("(SayIt) "..msg);
	local event = "UI_INFO_MESSAGE"
	UIErrorsFrame_OnEvent(UIErrorsFrame, event, msg)
end


--********************************************************
--
-- Analyse de texte
--
--********************************************************
--
-- Function qui sépare les paragraphes/phrases d'un texte en éléments de tableau
--
local function Paragraphes(txt)
	-- Si pas de texte, pas la peine de continuer
	if not txt or txt=="" then
		return {}, 0
	end

	local text = {}
	local p = 1
	for paragraph in txt:gmatch("[^\r\n]+") do
		-- On enlève au texte le double '|', le nom du Npc le " dit : " et un caractère en plus (fin de string ?)

		-- Est-ce une émote ?
		local e = (paragraph:sub(1,1)=="<" and paragraph:sub(-1)==">")
		local t,Nchar_supp
		if e then
			Nchar_supp = 2
			t = paragraph:sub(2,-2) -- on vire les < >
		else
			Nchar_supp = 9+target_name:len()
			t = paragraph
		end

		-- Coupe par phrase
		-- [.!?]+ : au moins un signe de ponctuation, permet de gérer ... !? ?! par exemple
		-- [^%s][^%s]%s* : le dernier mot de la phrase dois avoir au moins 2 caractères, pour éviter de couper "M. Dupont" (pas parfait mais mieux que rien)
		-- on transforme chaque phrase en paragraphe, et on repasse le test précédent
		for tt in t:gsub('([^%s][^%s]%s*[%.%!%?]+)(%s+)(%u)','%1\n%3'):gmatch('[^\r\n]+') do --for tt in t:gmatch('(.-[.!?]+)%s*') do
			text[p] = { -- Le texte est coupé au cas où...
			["texte"] = tt:sub(1,254-Nchar_supp), -- ça devrait être 255, mais ça ne passe pas...
			["emote"] = e }
			p = p+1
		end
	end

	return text, p-1
end

--
-- Coloration du texte de la fenêtre
--
local cDit = "|cff".."606060" -- gris clair
local cJusteDit = "|cff".."7f0000" -- gris foncé
local cADire = "|cff".."00007f" -- jaunasse
local cNonDit = "|cff".."202020" -- noir

local function SpecialChar(txt)
	return txt and txt:gsub('([%(%)%.%+%-%*%?%[%^%$%]])','%%%1') or ''
end
local function ColorieTexte(txt)
	--print('______')
	local tJusteDit,tADire
	if i_phrase > 1 then
		tJusteDit = text_table[i_phrase-1].texte
	end
	if i_phrase <= max_phrase then
		tADire = text_table[i_phrase].texte
	end
	
	--print(txt)
	--print('^(.*)('..SpecialChar(tJusteDit)..')(.-)('..SpecialChar(tADire)..')(.*)$')
	local _,_,tDit,tJusteDit2,space,tADire2,tNonDit = txt:find('^(.-)('..SpecialChar(tJusteDit)..')(.-)('..SpecialChar(tADire)..')(.*)$') --,char_dits)

	--print('tDit:'..(tDit or ''))
	--print('tJusteDit2:'..(tJusteDit2 or ''))
	--print('tADire2:'..(tADire2 or ''))
	--print('tNonDit:'..(tNonDit or ''))

	return (tDit and SayItOptions.cDit..tDit..'|r' or '' )..
			(tJusteDit and SayItOptions.cJusteDit..tJusteDit..'|r' or '' )..
			(space or '')..(tADire and SayItOptions.cADire..tADire..'|r' or '' )..
			(tNonDit and SayItOptions.cNonDit..tNonDit..'|r' or '' )
end

--
-- Faire parler un Npc
--
local function NpcDit(txt)
	if not txt then return end
	if not txt.emote then
		SendChatMessage("\124\124 "..GetUnitName("Npc").." dit : "..
				txt.texte,"EMOTE")
	else
		SendChatMessage("\124\124 "..txt.texte,"EMOTE")
		return
	end
end


--********************************************************
--
-- Boutons et tooltips
--
--********************************************************
--
-- Remplissage du tooltip
--
local function TooltipUpdate(b)
	if max_phrase>0 then
		-- Coloration du texte dans la fenêtre
		if TextFrame and SayItOptions.colorisation == 2 then
			TextFrame:SetText(ColorieTexte(text_full))
		end

		-- tooltip
		if not SayItOptions.tooltip then return end

		if SayItOptions.ancre_tooltip then
			GameTooltip:SetOwner(b,"ANCHOR_BOTTOMRIGHT")-- Position du tooltip
		else
			GameTooltip_SetDefaultAnchor(GameTooltip, b)
		end

		-- texte du tolltip
		GameTooltip:SetText(target_name,1,1,1) -- Nom du Pnj
		if SayItOptions.texte_tooltip then
			local txt = ""
			if i_phrase <= max_phrase then
				if not text_table[i_phrase].emote then
					GameTooltip:AppendText(" va dire :")
				else
					GameTooltip:AppendText(" :")
				end
				txt = text_table[i_phrase].texte
				GameTooltip:AddLine('"'..txt..'"',1,0.82,0,true)
			else
				GameTooltip:AppendText(" a terminé.")
			end
		end

		-- Raccourcis
		if SayItOptions.raccourcis_tooltip then
			GameTooltip:AddLine(" ")
			if i_phrase <= max_phrase then
				GameTooltip:AddDoubleLine("Dire la phrase","Clic gauche",1,1,1,1,1,1)
			end
			if i_phrase>1 then
				GameTooltip:AddDoubleLine("Phrase précédente","Ctrl+Clic/Roulette haut",1,1,1,1,1,1)
			end
			if i_phrase <= max_phrase then
				GameTooltip:AddDoubleLine("Sauter la phrase","Shift+Clic/Roulette bas",1,1,1,1,1,1)
			end
		end
		GameTooltip:Show()
	else
		GameTooltip:SetText("")
		GameTooltip:Hide()
	end
end

--
-- Créations des boutons, avec les fonctions des clics/mouseover
--
local function CreerBouton(parent)
	local button = CreateFrame("Button", parent:GetName().."SayButton", parent, "UIPanelButtonTemplate")
	button:SetText("Dire")
	button:SetHeight(22)
	button:SetWidth(button:GetTextWidth() + 40)
	button:SetPoint("BOTTOM",parent,"BOTTOM",-9,72)

	-- Set the frame level of the gossip_button to be 1 deeper than its parent
	local buttonparent = button:GetParent()
	local framelevel = buttonparent:GetFrameLevel()
	local framestrata = buttonparent:GetFrameStrata()
	button:SetFrameLevel(framelevel + 1)
	button:SetFrameStrata(framestrata)
	button:Enable()

	-- Action du bouton
	button:RegisterForClicks("LeftButtonUp")
	button:EnableMouseWheel(true)
	button:SetScript("OnClick",function(self, button, down)
				-- état des modificateurs
				local shiftDown = IsShiftKeyDown();
				local ctrlDown  = IsControlKeyDown();

				-- On évite le cas foireux
				if shiftDown and ctrlDown then return end

				-- lecture phrase actuelle
				if not shiftDown and not ctrlDown and i_phrase<=max_phrase then
					NpcDit(text_table[i_phrase])
				end

				-- Passage phrase suivante
				if ctrlDown then
					if i_phrase==1 then
						Warn("Le début du texte est atteint.")
					else
						i_phrase = i_phrase-1
						--char_dits = char_dits - text_table[i_phrase].texte:len()
						if TextFrame and SayItOptions.colorisation == 3 then
							TextFrame:SetText(ColorieTexte(text_full))
						end
					end
				else
					if i_phrase>max_phrase then
						Warn("La fin du texte est atteinte.")
					else
						--char_dits = char_dits + text_table[i_phrase].texte:len()
						i_phrase = i_phrase+1
						if TextFrame and SayItOptions.colorisation == 3 then
							TextFrame:SetText(ColorieTexte(text_full))
						end
					end
				end

				-- Mise à jour du texte du tooltip
				TooltipUpdate(self)
			end)
	button:SetScript("OnMouseWheel", function(self, delta)
				-- Passage phrase suivante
				if delta==1 then
					if i_phrase==1 then
						Warn("Le début du texte est atteint.")
					else
						i_phrase = i_phrase-1
						--char_dits = char_dits - text_table[i_phrase].texte:len()
						if TextFrame and SayItOptions.colorisation == 3 then
							TextFrame:SetText(ColorieTexte(text_full))
						end
					end
				else
					if i_phrase>max_phrase then
						Warn("La fin du texte est atteinte.")
					else
						--char_dits = char_dits + text_table[i_phrase].texte:len()
						i_phrase = i_phrase+1
						if TextFrame and SayItOptions.colorisation == 3 then
							TextFrame:SetText(ColorieTexte(text_full))
						end
					end
				end

				-- Mise à jour du texte du tooltip
				TooltipUpdate(self)
			end)


	-- Tooltip
	button:SetScript("OnEnter", TooltipUpdate)
	button:SetScript("OnLeave", function()
			GameTooltip:Hide()
			if TextFrame and SayItOptions.colorisation == 2 then
				TextFrame:SetText(text_full)
			end
		end)

	return button
end


--********************************************************
--
-- Gestion des events
--
--********************************************************
--
-- fonction lancée au chargement de l'add-on
--
function _G.SayIt_OnLoad(self,...)
	-- Création des deux boutons
	gossip_button = CreerBouton(GossipFrame)
	quest_button = CreerBouton(QuestFrame)

	-- Pour ne pas avoir de warning avec findglobals
	-- GLOBALS: this
	-- Events à suivre
	SayItFrame:RegisterEvent("GOSSIP_SHOW");    -- Affiche fenêtre Gossip
	SayItFrame:RegisterEvent("GOSSIP_CLOSED");  -- Ferme fenêtre gossip (peut-être appelé juste avant l'ouverture d'une quête)
	SayItFrame:RegisterEvent("QUEST_DETAIL");   -- Nouvelle quête
	SayItFrame:RegisterEvent("QUEST_PROGRESS"); -- Quête en cours, non terminée
	SayItFrame:RegisterEvent("QUEST_COMPLETE"); -- Quête en cours et terminée
	SayItFrame:RegisterEvent("QUEST_FINISHED"); -- Fermeture fenêtre quête
	--"QUEST_GREETING" ?
end

--
-- fonction appelée quand il y a un event
--
function _G.SayIt_OnEvent(self, event, ...)
	--DEBUG("Event:"..event)
	--Warn(event)

	if ( event=="GOSSIP_CLOSED" or event=="QUEST_FINISHED") then
		-- Reset
		target_name = ""
		text_full = nil
		current_button = nil
		TextFrame = nil

	elseif event=="GOSSIP_SHOW" then
		target_name = GetUnitName("Npc")
		text_full = GetGossipText()
		current_button = gossip_button
		TextFrame = GossipGreetingText

	elseif event=="QUEST_DETAIL" then
		target_name = GetUnitName("Npc")
		text_full = GetQuestText();
		current_button = quest_button
		TextFrame = nil

	elseif event=="QUEST_PROGRESS" then
		target_name = GetUnitName("Npc")
		text_full = GetProgressText();
		current_button = quest_button
		TextFrame = QuestProgressText
		
	elseif event=="QUEST_COMPLETE" then
		target_name = GetUnitName("Npc")
		text_full = GetRewardText();
		current_button = quest_button
		TextFrame = nil

	--elseif event=="QUEST_GREETING" then
	-- GetGreetingText()
	--GreetingText
	else return
	end

	-- On ne sait jamais (ça arrive quand la fenêtre ne s'ouvre pas parce que celle des options est ouverte, par exemple)
	if not target_name or not text_full or not current_button then
		return
	end

	-- Reset de l'indice
	i_phrase = 1
	--char_dits = 0

	-- Découpage du texte en paragraphes/phrase
	text_table, max_phrase = Paragraphes(text_full)

	-- Affichage en couleur
	if TextFrame and SayItOptions.colorisation == 3 then
		TextFrame:SetText(ColorieTexte(text_full))
	end
end


--********************************************************
--
-- Ace 3.0
--
--********************************************************
-- http://www.wowace.com/addons/ace3/pages/getting-started/

-- Enregistrement comme add-on
local SayIt = LibStub("AceAddon-3.0"):NewAddon("SayIt")
--
-- Ace Config
--
local function Hex2Val(h)
	if not h then return 0,0,0 end
	return tonumber(h:sub(5,6),16)/255, tonumber(h:sub(7,8),16)/255, tonumber(h:sub(9,10),16)/255
end
local function Val2Hex(r,g,b)
	return string_format("|cff%02x%02x%02x",(r or 0)*255,(g or 0)*255,(b or 0)*255)
end
local options = {
	type = "group",
	args = {
		tooltip_header = {
			name = "Tooltip",
			type = "header",
			order = 80
		},
		activer_tooltip = {
			name = "Afficher le tooltip",
			desc = "Affiche un tooltip pour le bouton \"Dire\"",
			type = "toggle",
			get = function() return SayItOptions.tooltip end,
			set = function(info,state) SayItOptions.tooltip = state end,
			width = "full",
			order = 81
		},
		montrer_texte = {
			name = "Afficher le texte dans le tooltip",
			desc = "Affiche le texte qui va être dit pas le pnj dans le tooltip du bouton \"Dire\"",
			type = "toggle",
			get = function() return SayItOptions.texte_tooltip end,
			set = function(info,state) SayItOptions.texte_tooltip = state end,
			width = "full",
			order = 82
		},
		montrer_raccourcis = {
			name = "Afficher les raccourcis dans le tooltip",
			desc = "Affiche les raccourcis dans le tooltip du bouton \"Dire\"",
			type = "toggle",
			get = function() return SayItOptions.raccourcis_tooltip end,
			set = function(info,state) SayItOptions.raccourcis_tooltip = state end,
			width = "full",
			order = 83
		},
		ancre_tooltip = {
			name = "Ancrer le tooltip au bouton",
			desc = "Ancre le tooltip au bouton \"Dire\". Sinon, il sera dans sa position par défaut.",
			type = "toggle",
			get = function() return SayItOptions.ancre_tooltip end,
			set = function(info,state) SayItOptions.ancre_tooltip = state end,
			width = "full",
			order = 84
		},
		couleur_header = {
			name = "Couleurs des textes",
			type = "header",
			order = 99
		},
		o100 = {
			name = "|cffffd100Remarque :|r La colorisation ne marche pas pour les fenêtres d'acceptation et de rendu de quête.\n",
			type = "description",
			order = 100
		},
		colorier = {
			name = "Colorisation",
			desc = "Colore le texte dans la fenêtre du pnj.",
			--descStyle = 'inline',
			type = "select",
			values = {
				"Aucune",
				"Sous la souris",
				"Toujours"
			},
			style = 'radio',
			get = function() return SayItOptions.colorisation end,
			set = function(info,val) SayItOptions.colorisation = val end,
			order = 101
		},
		o102 = {
			name = "\n|cffffd100Couleurs utilisées lors de la colorisation des textes|r",
			type = "description",
			order = 102
		},
		couleur_cDit = {
			name = "Texte déjà dit",
			desc = "Couleur dans laquelle apparaitra le texte que le pnj a déjà dit.",
			type = "color",
			get = function() return Hex2Val(SayItOptions.cDit) end,
			set = function(info,r,g,b) SayItOptions.cDit = Val2Hex(r,g,b) end,
			width = "full",
			order = 103
		},
		couleur_cJusteDit = {
			name = "Texte tout juste dit",
			desc = "Couleur dans laquelle apparaitra le texte que le pnj vient de dire.",
			type = "color",
			get = function() return Hex2Val(SayItOptions.cJusteDit) end,
			set = function(info,r,g,b) SayItOptions.cJusteDit = Val2Hex(r,g,b) end,
			width = "full",
			order = 104
		},
		couleur_cADire = {
			name = "Texte qui va être dit",
			desc = "Couleur dans laquelle apparaitra le texte que le pnj dira la prochaine fois.",
			type = "color",
			get = function() return Hex2Val(SayItOptions.cADire) end,
			set = function(info,r,g,b) SayItOptions.cADire = Val2Hex(r,g,b) end,
			width = "full",
			order = 105
		},
		couleur_cNonDit = {
			name = "Texte pas encore dit",
			desc = "Couleur dans laquelle apparaitra le texte que le pnj n'a pas encore dit.",
			type = "color",
			get = function() return Hex2Val(SayItOptions.cNonDit) end,
			set = function(info,r,g,b) SayItOptions.cNonDit = Val2Hex(r,g,b) end,
			width = "full",
			order = 106
		}
	}
}

function SayIt:OnInitialize()
	-- Code that you want to run when the addon is first loaded goes here.

	-- Application de la config par Ace
	LibStub("AceConfig-3.0"):RegisterOptionsTable("SayIt".."BlizzOptions", options, {"sayit"})
	LibStub("AceConfigDialog-3.0"):AddToBlizOptions("SayIt".."BlizzOptions","Say It")
	LibStub("AceConfig-3.0"):RegisterOptionsTable("SayIt", function() return self:GetOptions() end) -- tiré de adibags

	-- Récupération de la config...
	if not SayItOptions then
		SayItOptions = {}
	end
	if SayItOptions.tooltip==nil then
		SayItOptions.tooltip = true
	end
	if SayItOptions.texte_tooltip==nil then
		SayItOptions.texte_tooltip = true
	end
	if SayItOptions.raccourcis_tooltip==nil then
		SayItOptions.raccourcis_tooltip = true
	end
	if SayItOptions.ancre_tooltip==nil then
		SayItOptions.ancre_tooltip = true
	end
	if not SayItOptions.colorisation then
		SayItOptions.colorisation = 2
	end
	if not SayItOptions.cDit then
		SayItOptions.cDit = "|cff".."606060"
	end
	if not SayItOptions.cJusteDit then
		SayItOptions.cJusteDit = "|cff".."7f0000"
	end
	if not SayItOptions.cADire then
		SayItOptions.cADire = "|cff".."00007f"
	end
	if not SayItOptions.cNonDit then
		SayItOptions.cNonDit = "|cff".."202020"
	end
end

--function SayIt:OnEnable()
	-- Called when the addon is enabled
--end

--function SayIt:OnDisable()
	-- Called when the addon is disabled
--end