mirror of
https://github.com/Lacustat/Freewood-OctoWoW-Core.git
synced 2026-11-03 20:57:00 +00:00
0.1.237: Fluesterfenster (klein, verschiebbar, nie im Kampf, nach dem Kampf wieder offen), Einstellungen dazu [ungeprueft]
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016onJCSHLwhs9udhC9ZLzk9
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
7b53e1b963
commit
e7ae558f37
+17
-4
@@ -85,7 +85,7 @@ end
|
||||
-- Spielerdaten (Klasse, Level) merken
|
||||
------------------------------------------------------------------------
|
||||
|
||||
function CL.Note(name, class, level)
|
||||
function CL.Note(name, class, level, extra)
|
||||
if type(name) ~= "string" or name == "" then return end
|
||||
local tok = CL.ClassToken(class) or (type(class) == "string" and FALLBACK_COLORS[class] and class) or nil
|
||||
local lv = tonumber(level)
|
||||
@@ -97,10 +97,21 @@ function CL.Note(name, class, level)
|
||||
local changed = false
|
||||
if tok and r.c ~= tok then r.c = tok; changed = true end
|
||||
if lv and lv > 0 and r.l ~= lv then r.l = lv; changed = true end
|
||||
if type(extra) == "table" then
|
||||
if extra.race and extra.race ~= "" and r.r ~= extra.race then r.r = extra.race; changed = true end
|
||||
if extra.guild and r.g ~= extra.guild then r.g = extra.guild; changed = true end
|
||||
if extra.cn and extra.cn ~= "" and r.cn ~= extra.cn then r.cn = extra.cn; changed = true end
|
||||
end
|
||||
r.t = Now()
|
||||
if changed then CL.version = CL.version + 1 end
|
||||
end
|
||||
|
||||
-- ganzer Merker-Eintrag (c, l, r, g, cn) oder nil
|
||||
function CL.Detail(name)
|
||||
local db = PDB()
|
||||
return db and db[name] or nil
|
||||
end
|
||||
|
||||
function CL.Info(name)
|
||||
local db = PDB()
|
||||
local r = db and db[name]
|
||||
@@ -111,8 +122,10 @@ end
|
||||
local function NoteUnit(unit)
|
||||
if not (G.UnitExists and G.UnitExists(unit) and G.UnitIsPlayer and G.UnitIsPlayer(unit)) then return end
|
||||
local name = G.UnitName(unit)
|
||||
local _, tok = G.UnitClass(unit)
|
||||
CL.Note(name, tok, G.UnitLevel(unit))
|
||||
local cn, tok = G.UnitClass(unit)
|
||||
local guild = G.GetGuildInfo and G.GetGuildInfo(unit) or nil
|
||||
local race = G.UnitRace and G.UnitRace(unit) or nil
|
||||
CL.Note(name, tok, G.UnitLevel(unit), { race = race, guild = guild, cn = cn })
|
||||
end
|
||||
|
||||
function CL.ScanGroup()
|
||||
@@ -248,7 +261,7 @@ local function OnWho()
|
||||
while i <= n do
|
||||
local name, guild, level, race, class = G.GetWhoInfo(i)
|
||||
if name then
|
||||
CL.Note(name, class, level)
|
||||
CL.Note(name, class, level, { race = race, guild = guild or "", cn = class })
|
||||
if forced[name] then
|
||||
forced[name] = nil
|
||||
FW:Print(name .. ": " .. tostring(level) .. " " .. tostring(class) .. (guild and guild ~= "" and (" <" .. guild .. ">") or ""))
|
||||
|
||||
@@ -277,6 +277,8 @@ FW.defaults = {
|
||||
scale = 1,
|
||||
locale = "auto",
|
||||
debug = false,
|
||||
whisperPopup = true,
|
||||
whisperPopupAlways = false,
|
||||
windowPos = false,
|
||||
windowSize = false,
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Notes: Base addon of the Freewood family: data storage, UI kit, export/import and the main window.
|
||||
## Notes-deDE: Basis-Addon der Freewood-Familie: Datenspeicher, UI-Bausteine, Export/Import und Hauptfenster.
|
||||
## Author: Lacustat
|
||||
## Version: 0.1.236
|
||||
## Version: 0.1.237
|
||||
## SavedVariables: FreewoodDB
|
||||
## SavedVariablesPerCharacter: FreewoodCharDB
|
||||
|
||||
@@ -19,6 +19,7 @@ UI\Tabs.lua
|
||||
Core\Channels.lua
|
||||
Core\ChatLog.lua
|
||||
UI\ChannelsTab.lua
|
||||
UI\WhisperPopups.lua
|
||||
Core\Tooltips.lua
|
||||
Core\TooltipInfo.lua
|
||||
Core\TooltipCompare.lua
|
||||
|
||||
@@ -82,6 +82,10 @@ FW:AddLocale("enUS", {
|
||||
CHAT_NOWHISPER = "No open whispers. A whisper appears in the list when someone writes to you.",
|
||||
CHAT_CLOSE_WHISPER = "Close whisper",
|
||||
CHAT_KEPT = "Chats are kept up to 7 days.",
|
||||
SETTINGS_WHISPER_POPUP = "Show whisper windows (never in combat)",
|
||||
SETTINGS_WHISPER_ALWAYS = "Whisper windows also while the Freewood window is open",
|
||||
POP_TAB = "Chat",
|
||||
POP_INFO_NONE = "...",
|
||||
CHAT_MENU_JOIN = "Join or create channel...",
|
||||
CHAT_MENU_NEWCAT = "New category...",
|
||||
CHAT_DLG_JOIN = "Join or create channel",
|
||||
@@ -251,6 +255,10 @@ FW:AddLocale("deDE", {
|
||||
CHAT_NOWHISPER = "Keine offenen Flüsterchats. Sobald dich jemand anflüstert, erscheint er hier in der Liste.",
|
||||
CHAT_CLOSE_WHISPER = "Flüsterchat schließen",
|
||||
CHAT_KEPT = "Chats werden bis zu 7 Tage gespeichert.",
|
||||
SETTINGS_WHISPER_POPUP = "Flüsterfenster anzeigen (nie im Kampf)",
|
||||
SETTINGS_WHISPER_ALWAYS = "Flüsterfenster auch bei offenem Freewood-Fenster",
|
||||
POP_TAB = "Chat",
|
||||
POP_INFO_NONE = "...",
|
||||
CHAT_MENU_JOIN = "Kanal beitreten oder erstellen...",
|
||||
CHAT_MENU_NEWCAT = "Neue Kategorie...",
|
||||
CHAT_DLG_JOIN = "Kanal beitreten oder erstellen",
|
||||
|
||||
@@ -1300,6 +1300,10 @@ local function Build(content)
|
||||
end
|
||||
CL.RequestGuild()
|
||||
stick = true
|
||||
if CL.requestKey then
|
||||
selKey = CL.requestKey
|
||||
CL.requestKey = nil
|
||||
end
|
||||
Redraw()
|
||||
end
|
||||
|
||||
|
||||
+10
@@ -514,6 +514,16 @@ local function BuildSettings(content)
|
||||
end)
|
||||
stack:Add(debugBox, { fit = true })
|
||||
|
||||
local wpBox = UI.CreateCheckbox(lf, L.SETTINGS_WHISPER_POPUP,
|
||||
function() return FW.settings.whisperPopup ~= false end,
|
||||
function(value) FW.settings.whisperPopup = value and true or false end)
|
||||
stack:Add(wpBox, { fit = true })
|
||||
|
||||
local wpAlways = UI.CreateCheckbox(lf, L.SETTINGS_WHISPER_ALWAYS,
|
||||
function() return FW.settings.whisperPopupAlways == true end,
|
||||
function(value) FW.settings.whisperPopupAlways = value and true or false end)
|
||||
stack:Add(wpAlways, { fit = true })
|
||||
|
||||
-- Fenstergroesse: Zeile mit - / Prozent / +
|
||||
local scaleLabel = UI.CreateLabel(lf, L.SETTINGS_SCALE, { size = 12 })
|
||||
stack:Add(scaleLabel, { height = 16, gap = 18 })
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
-- Freewood-OctoWoW-Core: kleine verschiebbare Fluesterfenster (nur ausserhalb des Kampfes). UNGEPRUEFT im Spiel.
|
||||
-- Auslöser: CHAT_MSG_WHISPER / CHAT_MSG_WHISPER_INFORM. Der Verlauf liegt in Core/ChatLog.lua (Schluessel "w:<Name>").
|
||||
|
||||
local ADDON, FW = ...
|
||||
|
||||
local UI = FW.UI
|
||||
local CL = FW.ChatLog
|
||||
local G = _G
|
||||
|
||||
local Pop = {}
|
||||
FW.WhisperPopups = Pop
|
||||
|
||||
local W, H = 330, 230
|
||||
local MAX_OPEN = 4
|
||||
local wins = {} -- wins[name] = Fenster
|
||||
local openOrder = {} -- Namen in Oeffnungsreihenfolge
|
||||
local pending = {} -- nach dem Kampf (wieder) zu oeffnen
|
||||
local inCombat = false
|
||||
|
||||
local function RemoveAt(t, idx)
|
||||
local n = table.getn(t)
|
||||
local k = idx
|
||||
while k < n do t[k] = t[k + 1]; k = k + 1 end
|
||||
t[n] = nil
|
||||
end
|
||||
|
||||
local function PosDB()
|
||||
local d = G.FreewoodDB
|
||||
if type(d) ~= "table" then return {} end
|
||||
if type(d.chatPopupPos) ~= "table" then d.chatPopupPos = {} end
|
||||
return d.chatPopupPos
|
||||
end
|
||||
|
||||
local function Time(t)
|
||||
if not (t and G.date) then return "" end
|
||||
local ok, s = pcall(G.date, "%H:%M", t)
|
||||
return ok and s or ""
|
||||
end
|
||||
|
||||
local function InfoText(name)
|
||||
local r = CL.Detail(name)
|
||||
if not r then return FW.L.POP_INFO_NONE end
|
||||
local parts = {}
|
||||
if r.l then parts[table.getn(parts) + 1] = tostring(r.l) end
|
||||
if r.r then parts[table.getn(parts) + 1] = r.r end
|
||||
local cn = r.cn or r.c
|
||||
if cn then parts[table.getn(parts) + 1] = cn end
|
||||
local txt = table.concat(parts, " ")
|
||||
if r.g and r.g ~= "" then txt = "<" .. r.g .. "> " .. txt end
|
||||
if txt == "" then return FW.L.POP_INFO_NONE end
|
||||
return txt
|
||||
end
|
||||
|
||||
local function AddLine(win, ln)
|
||||
local mine = ln.o ~= nil
|
||||
local nameCol = mine and "|cff6fa8dc" or "|cffff9ff3"
|
||||
local text = "|cff9a978c" .. Time(ln.t) .. "|r " .. nameCol .. (ln.s or "?") .. "|r: " .. (ln.m or "")
|
||||
win.log:AddMessage(text, 0.9, 0.89, 0.84)
|
||||
end
|
||||
|
||||
local function FillNew(win)
|
||||
local lines = CL.Lines("w:" .. win.name) or {}
|
||||
local n = table.getn(lines)
|
||||
local from = win.shown
|
||||
if from == 0 then from = math.max(0, n - 25) end
|
||||
local i = from + 1
|
||||
while i <= n do
|
||||
AddLine(win, lines[i])
|
||||
i = i + 1
|
||||
end
|
||||
win.shown = n
|
||||
end
|
||||
|
||||
local function Place(win)
|
||||
local pos = PosDB()[win.name]
|
||||
win:ClearAllPoints()
|
||||
if pos and pos.l and pos.b then
|
||||
win:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", pos.l, pos.b)
|
||||
else
|
||||
local idx = table.getn(openOrder)
|
||||
win:SetPoint("CENTER", UIParent, "CENTER", 220 - idx * 28, 160 - idx * 28)
|
||||
end
|
||||
end
|
||||
|
||||
local function Hide(win, keepPending)
|
||||
if not win then return end
|
||||
win:Hide()
|
||||
win.edit:ClearFocus()
|
||||
local k = 1
|
||||
while k <= table.getn(openOrder) do
|
||||
if openOrder[k] == win.name then RemoveAt(openOrder, k); break end
|
||||
k = k + 1
|
||||
end
|
||||
if not keepPending then pending[win.name] = nil end
|
||||
end
|
||||
|
||||
local function Create(name)
|
||||
local L = FW.L
|
||||
local win = UI.CreatePanel(UIParent, "bgDeep", "gold")
|
||||
win.name = name
|
||||
win.shown = 0
|
||||
win.flash = 0
|
||||
win:SetSize(W, H)
|
||||
win:SetFrameStrata("DIALOG")
|
||||
win:SetMovable(true)
|
||||
win:SetClampedToScreen(true)
|
||||
win:Hide()
|
||||
|
||||
local head = CreateFrame("Button", nil, win)
|
||||
head:SetPoint("TOPLEFT", win, "TOPLEFT", 0, 0)
|
||||
head:SetPoint("TOPRIGHT", win, "TOPRIGHT", 0, 0)
|
||||
head:SetHeight(44)
|
||||
head:RegisterForDrag("LeftButton")
|
||||
head:SetScript("OnDragStart", function() win:StartMoving() end)
|
||||
head:SetScript("OnDragStop", function()
|
||||
win:StopMovingOrSizing()
|
||||
local l, b = win:GetLeft(), win:GetBottom()
|
||||
if l and b then PosDB()[name] = { l = l, b = b } end
|
||||
end)
|
||||
|
||||
win.title = UI.CreateLabel(win, name, { font = "heading", size = 14, color = "gold", justify = "LEFT" })
|
||||
win.title:SetPoint("TOPLEFT", win, "TOPLEFT", 12, -8)
|
||||
win.title:SetPoint("TOPRIGHT", win, "TOPRIGHT", -90, -8)
|
||||
win.info = UI.CreateLabel(win, "", { size = 11, color = "textDim", justify = "LEFT" })
|
||||
win.info:SetPoint("TOPLEFT", win, "TOPLEFT", 12, -26)
|
||||
win.info:SetPoint("TOPRIGHT", win, "TOPRIGHT", -12, -26)
|
||||
|
||||
local close = UI.CreateButton(win, "x", 24, 22, function() Hide(win, false) end)
|
||||
close:SetPoint("TOPRIGHT", win, "TOPRIGHT", -6, -6)
|
||||
local tab = UI.CreateButton(win, L.POP_TAB, 52, 22, function()
|
||||
CL.requestKey = "w:" .. name
|
||||
Hide(win, false)
|
||||
if UI.Show then UI:Show("channels") end
|
||||
end)
|
||||
tab:SetPoint("RIGHT", close, "LEFT", -4, 0)
|
||||
|
||||
local logBox = UI.CreatePanel(win, "bg", "bronze")
|
||||
logBox:SetPoint("TOPLEFT", win, "TOPLEFT", 8, -48)
|
||||
logBox:SetPoint("BOTTOMRIGHT", win, "BOTTOMRIGHT", -8, 40)
|
||||
local log = CreateFrame("ScrollingMessageFrame", nil, logBox)
|
||||
log:SetPoint("TOPLEFT", logBox, "TOPLEFT", 6, -6)
|
||||
log:SetPoint("BOTTOMRIGHT", logBox, "BOTTOMRIGHT", -6, 6)
|
||||
if not pcall(log.SetFont, log, UI.GetFontPath("body"), 12, "") then
|
||||
pcall(log.SetFont, log, "Fonts\\FRIZQT__.TTF", 12, "")
|
||||
end
|
||||
log:SetJustifyH("LEFT")
|
||||
log:SetMaxLines(120)
|
||||
log:SetFading(false)
|
||||
log:EnableMouseWheel(true)
|
||||
log:SetScript("OnMouseWheel", function(self, delta)
|
||||
delta = delta or arg1 or 0
|
||||
if delta > 0 then self:ScrollUp() else self:ScrollDown() end
|
||||
end)
|
||||
win.log = log
|
||||
|
||||
local ibox = UI.CreatePanel(win, "bg", "bronze")
|
||||
ibox:SetPoint("BOTTOMLEFT", win, "BOTTOMLEFT", 8, 8)
|
||||
ibox:SetPoint("BOTTOMRIGHT", win, "BOTTOMRIGHT", -8, 8)
|
||||
ibox:SetHeight(26)
|
||||
local edit = CreateFrame("EditBox", nil, ibox)
|
||||
edit:SetAutoFocus(false)
|
||||
edit:SetPoint("TOPLEFT", ibox, "TOPLEFT", 6, -3)
|
||||
edit:SetPoint("BOTTOMRIGHT", ibox, "BOTTOMRIGHT", -6, 3)
|
||||
edit:SetMaxLetters(255)
|
||||
if not edit:SetFont(UI.GetFontPath("body"), 12, "") then edit:SetFont("Fonts\\FRIZQT__.TTF", 12, "") end
|
||||
edit:SetTextColor(UI.Color("text"))
|
||||
edit:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
|
||||
edit:SetScript("OnEnterPressed", function(self)
|
||||
local txt = self:GetText() or ""
|
||||
if txt ~= "" then CL.Send("whisper", name, txt) end
|
||||
self:SetText("")
|
||||
self:SetFocus()
|
||||
end)
|
||||
win.edit = edit
|
||||
|
||||
-- Kopf blinkt golden bei neuer Nachricht, Infozeile aktualisiert sich
|
||||
local acc, infoAcc = 0, 0
|
||||
win:SetScript("OnUpdate", function(_, el)
|
||||
el = el or arg1 or 0
|
||||
if win.flash > 0 then
|
||||
win.flash = win.flash - el
|
||||
if win.flash > 0 then
|
||||
local on = math.mod(math.floor(win.flash * 4), 2) == 1
|
||||
if on then win.title:SetTextColor(UI.Color("goldLight")) else win.title:SetTextColor(UI.Color("text")) end
|
||||
else
|
||||
win.title:SetTextColor(UI.Color("gold"))
|
||||
end
|
||||
end
|
||||
infoAcc = infoAcc + el
|
||||
if infoAcc >= 1 then
|
||||
infoAcc = 0
|
||||
win.info:SetText(InfoText(name))
|
||||
end
|
||||
end)
|
||||
return win
|
||||
end
|
||||
|
||||
function Pop.Open(name)
|
||||
local win = wins[name]
|
||||
if not win then
|
||||
win = Create(name)
|
||||
wins[name] = win
|
||||
end
|
||||
if not win:IsShown() then
|
||||
openOrder[table.getn(openOrder) + 1] = name
|
||||
Place(win)
|
||||
win:Show()
|
||||
-- zu viele offen: das aelteste schliessen
|
||||
while table.getn(openOrder) > MAX_OPEN do
|
||||
local old = wins[openOrder[1]]
|
||||
Hide(old, false)
|
||||
end
|
||||
end
|
||||
win.info:SetText(InfoText(name))
|
||||
FillNew(win)
|
||||
win.flash = 1.5
|
||||
return win
|
||||
end
|
||||
|
||||
local function CanShow()
|
||||
if inCombat then return false end
|
||||
if G.UnitAffectingCombat and G.UnitAffectingCombat("player") then return false end
|
||||
local s = FW.settings
|
||||
if s and s.whisperPopup == false then return false end
|
||||
if UI.window and UI.window:IsShown() and not (s and s.whisperPopupAlways == true) then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
local function Notify(name)
|
||||
if type(name) ~= "string" or name == "" then return end
|
||||
CL.Ask(name)
|
||||
local win = wins[name]
|
||||
if win and win:IsShown() then
|
||||
FillNew(win)
|
||||
win.flash = 1.5
|
||||
return
|
||||
end
|
||||
if CanShow() then
|
||||
Pop.Open(name)
|
||||
elseif inCombat or (G.UnitAffectingCombat and G.UnitAffectingCombat("player")) then
|
||||
pending[name] = true
|
||||
end
|
||||
end
|
||||
|
||||
FW:RegisterEvent("CHAT_MSG_WHISPER", function(text, sender) Notify(sender) end)
|
||||
FW:RegisterEvent("CHAT_MSG_WHISPER_INFORM", function(text, target) Notify(target) end)
|
||||
|
||||
-- Kampf beginnt: alle Fenster schliessen (Namen merken); Kampf vorbei: wieder oeffnen
|
||||
FW:RegisterEvent("PLAYER_REGEN_DISABLED", function()
|
||||
inCombat = true
|
||||
local names, k = {}, 1
|
||||
while k <= table.getn(openOrder) do names[k] = openOrder[k]; k = k + 1 end
|
||||
k = 1
|
||||
while k <= table.getn(names) do
|
||||
pending[names[k]] = true
|
||||
Hide(wins[names[k]], true)
|
||||
k = k + 1
|
||||
end
|
||||
end)
|
||||
|
||||
FW:RegisterEvent("PLAYER_REGEN_ENABLED", function()
|
||||
inCombat = false
|
||||
local names = {}
|
||||
for name in pairs(pending) do names[table.getn(names) + 1] = name end
|
||||
pending = {}
|
||||
local k = 1
|
||||
while k <= table.getn(names) do
|
||||
if CanShow() then Pop.Open(names[k]) end
|
||||
k = k + 1
|
||||
end
|
||||
end)
|
||||
|
||||
if G.UnitAffectingCombat and G.UnitAffectingCombat("player") then inCombat = true end
|
||||
Reference in New Issue
Block a user