lotrointerface.com
Search Downloads

LoTROInterface SVN SequenceBars

[/] [trunk/] [Thurallor/] [SequenceBars/] [SequenceEditor.lua] - Rev 5

Go to most recent revision | Compare with Previous | Blame | View Log

SequenceEditor = class(Turbine.UI.Lotro.Window);

function SequenceEditor:Constructor(bar, settings)
    Turbine.UI.Lotro.Window.Constructor(self);

    self.bar = bar;
    self.manager = self.bar.manager;
    self.settings = settings;

    self:SetText(bar:GetName());
    self:SetZOrder(2147483647 - 5);
    self:SetResizable(true);
    self:SetVisible(true);
    
    if (not self.settings.sequenceEditor) then
        self.settings.sequenceEditor = {};
    end
    if (self.settings.sequenceEditor.position) then
        self:SetPosition(unpack(self.settings.sequenceEditor.position));
    else
        self:SetPosition(self.bar:GetPosition());
    end
    if (self.settings.sequenceEditor.size) then
        self:SetSize(unpack(self.settings.sequenceEditor.size));
    else
        self:SetSize(470, 187);
    end
    self:Redraw();
end

function SequenceEditor:SetText(barName)
    local title = L:GetText("/SequenceEditor/Title");
    title = string.gsub(title, "<name>", barName);
    Turbine.UI.Lotro.Window.SetText(self, title);
end

function SequenceEditor:SaveSettings()
    self.bar:SaveSettings();
end

function SequenceEditor:Redraw()
    local width, height = self:GetSize();

    -- Enforce minimum size of 468 x 152.
    self:SetMinimumWidth(470);
    self:SetMinimumHeight(152);

    local xMargin = 16;
    local topMargin = 35;
    local bottomMargin = 42;

    if (not self.slotTabCard) then
        self.slotTabCard = Thurallor.UI.TabCard();
        self.slotTabCard:SetParent(self);
        self.slotTabCard:SetTop(topMargin);
        self.slotTabCard:SetWidth(200);
        self.slotTabCard:SetTabWidth(120);
        self.slotTabCard:SetTabText(L:GetText("/SequenceEditor/SlotTab"));
    end
    self.slotTabCard:SetLeft(width - 200 - xMargin);
    self.slotTabCard:SetHeight(height - topMargin - bottomMargin);
    
    if (not self.sequenceTabCard) then
        self.sequenceTabCard = Thurallor.UI.TabCard();
        self.sequenceTabCard:SetParent(self);
        self.sequenceTabCard:SetPosition(xMargin, topMargin);
        self.sequenceTabCard:SetTabWidth(120);
        self.sequenceTabCard:SetTabText(L:GetText("/SequenceEditor/SequenceTab"));
        self.slotPanel = Turbine.UI.Label();
    end
    self.sequenceTabCard:SetSize(self.slotTabCard:GetLeft() - xMargin - 8, self.slotTabCard:GetHeight());

    self:DeleteEmptyTrailingSlots();
    local slotPanelWidth = self.sequenceTabCard:GetWidth() - 17;
    local slotSize = self.settings.slotSize + self.settings.slotSpacing;
    self.slotsWide = math.floor((slotPanelWidth - 3) / slotSize);
    local slotsHigh = math.max(math.ceil(#self.settings.sequenceItemInfo / self.slotsWide) + 1, 2);
    self:ExtendSequenceTo(slotsHigh * self.slotsWide);
    self.slotPanel:SetSize(self.slotsWide * slotSize + 3, slotsHigh * slotSize + 3);
    self.sequenceTabCard:SetInteriorControl(self.slotPanel);
    self.slotPanel:SetBackColor(self.bar.color);
    
    -- Draw some quickslots
    if (not self.sequenceItems) then
        self.sequenceItems = {};
    end
    local s = 1;
    for y = 1, slotsHigh, 1 do
        for x = 1, self.slotsWide, 1 do
            self:RebuildSlot(s, x, y);
            s = s + 1;
        end
    end
    
    if (not self.instructions) then
        self.instructions = Turbine.UI.Label();
        self.instructions:SetParent(self);
        self.instructions:SetMouseVisible(false);
        self.instructions:SetTextAlignment(Turbine.UI.ContentAlignment.MiddleCenter);
        self.instructions:SetFont(Turbine.UI.Lotro.Font.TrajanPro15);
        self.instructions:SetMultiline(true);
        self.instructions:SetForeColor(Turbine.UI.Color.PaleGoldenrod);
        self.instructions:SetText(L:GetText("/SequenceEditor/Instructions"));
    end
    self.instructions:SetSize(self:GetWidth() - 2 * xMargin, 30);
    self.instructions:SetPosition(xMargin, self:GetHeight() - 40);
    
    if (self.Marquee) then
        self:SelectSlot(self.Marquee.s);
    end
end

function SequenceEditor:SizeChanged()
    self:Redraw();
    self.settings.sequenceEditor.size = {self:GetSize()};
    self:SaveSettings();
end

function SequenceEditor:PositionChanged()
    self.settings.sequenceEditor.position = {self:GetPosition()};
    self:SaveSettings();
end

function SequenceEditor:DisplaySlot(s)
    self.slotTabCard:SetInteriorControl(nil);
    self.slotTabCard:SetTabText(L:GetText("/SequenceEditor/SlotTab"));
    if (s == nil) then
        return;
    end

    self:ExtendSequenceTo(s);
    local info = self.settings.sequenceItemInfo[s];
    if (not info.class) then
        -- Empty slot should be rendered as a standard quickslot
        info.class = "Turbine.UI.Lotro.Quickslot";
        info.temporary = true;
    end

    -- Update slot tab caption and create properties container
    self.slotTabCard:SetTabText(L:GetText("/SequenceEditor/SlotTab") .. " " .. tostring(s));
    self.slotProperties = Turbine.UI.Control();
    self.slotTabCard:SetInteriorControl(self.slotProperties);
    local width = self.slotTabCard:GetWidth() - 17;
    self.slotProperties:SetWidth(width);
--self.slotProperties:SetBackColor(Turbine.UI.Color(1, 0.25, 0.25, 0.25));

    -- Create the icon
    local object = self:BuildSlot(s, self.slotProperties, nil, 72, 10);
    object.numLabel:SetText(nil);     -- don't display slot number overlay
    object.numLabel.MouseClick = nil; -- disable right-click menu

    -- Create a function for adding a centered line of text to the properties control
    local AddLabel = function(top, text, color)
        local label = Turbine.UI.Label();
        label:SetParent(self.slotProperties);
        label:SetPosition(0, top);
        label:SetSize(180, 16);
        top = top + 16;
        label:SetTextAlignment(Turbine.UI.ContentAlignment.MiddleCenter);
        label:SetFont(Turbine.UI.Lotro.Font.TrajanPro14);
        label:SetForeColor(color);
        label:SetMarkupEnabled(true);
        label:SetText(text);
        return top, label;
    end

    -- Create a function for adding a centered text box to the properties control
    local AddTextBox = function(top, text, color)
        local textBox = Turbine.UI.Lotro.TextBox();
        textBox:SetParent(self.slotProperties);
        textBox:SetPosition(0, top);
        textBox:SetSize(180, 20);
        top = top + 20;
        textBox:SetTextAlignment(Turbine.UI.ContentAlignment.MiddleLeft);
        textBox:SetFont(Turbine.UI.Lotro.Font.TrajanPro14);
        textBox:SetForeColor(color);
        textBox:SetText(text);
        
     --   textBox:SetReadOnly(true);
     --   textBox.FocusGained = function(sender, args)
     --       sender:SetReadOnly(false);
     --   end
     --   -- Trap enter key
     --   textBox:SetWantsKeyEvents(true);
     --   textBox.KeyDown = function(sender, args)
     --       if (args.Action == Turbine.UI.Lotro.Action.EnterKey) then
     --           sender:SetReadOnly(true);
     --       end
     --   end
        return top, textBox;
    end
    
    -- Draw the caption
    local top = 54;
    if (info.class == "Turbine.UI.Lotro.Quickslot") then
        top = AddLabel(top, L:GetText("/SequenceEditor/StandardQuickslot"), Turbine.UI.Color.PaleGoldenrod);
    elseif (info.class == "Turbine.UI.Control") then
        top = AddLabel(top, L:GetText("/SequenceEditor/SpecialSlot") .. ":", Turbine.UI.Color.PaleGoldenrod);
        top = AddLabel(top, info.toolTip, Turbine.UI.Color.PaleGoldenrod);
    end

    -- Draw the arguments
    if (info.class == "Turbine.UI.Lotro.Quickslot") then
        top = top + 16; -- skip a line
        for key, value in pairs(Turbine.UI.Lotro.ShortcutType) do
            if (info.type == value) then
                top = AddLabel(top, L:GetText("/SequenceEditor/ShortcutType") .. ": " .. L:GetText("/SequenceEditor/ShortcutTypes/" .. key), Turbine.UI.Color.Goldenrod);
                break;
            end
        end
    elseif (info.class == "Turbine.UI.Control") then
        top = top + 16; -- skip a line
        if (info.type == "GenerateEvent") then
            top = AddLabel(top, L:GetText("/SequenceEditor/EventName"), Turbine.UI.Color.Goldenrod);
            local textBox;
            top, textBox = AddTextBox(top, info.eventName, Turbine.UI.Color.White);
            textBox.TextChanged = function(sender, args)
                local text = sender:GetText();
                -- Remove carriage returns
                local stripped = string.gsub(text, "\n", "");
                if (stripped ~= text) then
                    sender:SetText(stripped);
                    text = stripped;
                end
                info.eventName = text;
                self.bar:ShortcutChanged();
            end
        end
    end

    if (info.temporary) then
        -- Delete temporary empty slot
        info.class = nil;
        info.temporary = nil;
    end
    
    self.slotProperties:SetHeight(top);
end

function SequenceEditor:BuildSlot(s, parent, object, left, top)

    -- Get slot info, or initialize to default
    local info = self.settings.sequenceItemInfo[s];
    if (type(info) ~= "table") then
        info = {};
    end
    if (not info.class) then
        -- Empty slot should be rendered as a standard quickslot
        info.class = "Turbine.UI.Lotro.Quickslot";
        info.temporary = true;
    end

    -- Discard old object, if it's a different type
    if (object and (object.class ~= info.class)) then
        if (object.numLabel) then
            object.numLabel:SetParent(nil);
        end
        object:SetParent(nil);
        object = nil;
    end
    
    -- Create the quickslot object or command icon
    if (info.class == "Turbine.UI.Lotro.Quickslot") then
        if (not object) then
            object = Turbine.UI.Lotro.Quickslot();
        end
        object.ShortcutChanged = nil;
        object:SetShortcut(Turbine.UI.Lotro.Shortcut(info.type, info.Data));
        object.isQuickslot = true;
        object:SetPosition(left, top);
    elseif (info.class == "Turbine.UI.Control") then
        if (not object) then
            object = Turbine.UI.Control();
        end
        object:SetBackground(info.background);
        object.isQuickslot = false;
        object:SetSize(32, 32);
        object:SetPosition(left + 3, top + 3);
    end
    object.class = info.class;
    object.s = s;
    object:SetParent(parent);
    object:SetZOrder(parent:GetZOrder() + 2);
    object:SetBlendMode(Turbine.UI.BlendMode.Overlay)    
    object:SetEnabled(false);
    object:SetMouseVisible(false);

    -- Create slot number overlay, which accepts mouse events
    local numLabel = object.numLabel;
    if (not numLabel) then
        object.numLabel = Turbine.UI.Label();
        numLabel = object.numLabel;
        numLabel.object = object;
        numLabel:SetParent(parent);
        numLabel:SetFont(Turbine.UI.Lotro.Font.TrajanPro15);
        numLabel:SetFontStyle(Turbine.UI.FontStyle.Outline);
        numLabel:SetOutlineColor(Turbine.UI.Color(1, 0, 0, 0));
        numLabel:SetTextAlignment(Turbine.UI.ContentAlignment.MiddleCenter);
        numLabel:SetText(tonumber(s));
        numLabel:SetSize(32, 32);
        numLabel:SetZOrder(object:GetZOrder() + 1);
        numLabel:SetMouseVisible(true);
        numLabel:SetAllowDrop(true);
    end
    numLabel:SetVisible(true);
    numLabel:SetPosition(left + 3, top + 3);

    -- Desired mouse behavior:
    -- Left-click should do nothing.  (Maybe flash a red 'X' to indicate that nothing happened.)
    --   The 'numLabel' object should handle right-click events.
    --   The 'quickslot' object should accept 'drop' operations.
    --   Ideally the quickslot should be draggable, but this may not be possible.

    numLabel.DragDrop = function(sender, args)
        local s = sender.object.s;
        self:ExtendSequenceTo(s);
        self.settings.sequenceItemInfo[s] = {};
        local info = self.settings.sequenceItemInfo[s];
        info.class = "Turbine.UI.Lotro.Quickslot";
        info.type = args.DragDropInfo:GetShortcut():GetType();
        info.Data = args.DragDropInfo:GetShortcut():GetData();
        self:RebuildSlot(s);
        self.bar:ShortcutChanged();
        self:Redraw();
        self:SelectSlot(s);
        
        -- Don't remove the item/skill from the location where it was dragged from.
        args.DragDropInfo:SetSuccessful(false);
    end

    numLabel.MouseClick = function(sender, args)
        -- Left-click selects the slot and shows its properties in the "Slot" tab.
        if (args.Button == Turbine.UI.MouseButton.Left) then
            self:SelectSlot(sender.object.s);

        -- Right-click displays the settings menu.
        elseif (args.Button == Turbine.UI.MouseButton.Right) then
            self.clickedItem = sender.object.s;
            self:ShowContextMenu();
        end
    end

    if (info.temporary) then
        -- Delete temporary empty slot
        info.class = nil;
        info.temporary = nil;
    end
    
    return object;
end

function SequenceEditor:RebuildSlot(s, x, y)
    local oldObject = self.sequenceItems[s];
    
    -- If x and y aren't specified, then presumably the object has already been positioned previously
    if (x == nil) then
        x = oldObject.x;
        y = oldObject.y;
    end
    local left, top = self:GetSlotPosition(x, y);

    local newObject = self:BuildSlot(s, self.slotPanel, oldObject, left, top);
    newObject.x = x;
    newObject.y = y;
    self.sequenceItems[s] = newObject;

    if (self.selectedSlot == s) then
        self:DisplaySlot(s);
    end
end

function SequenceEditor:SelectSlot(s)
    if (self.Marquee) then
        self.Marquee:SetParent(nil);
        self.Marquee = nil;
    end
    if (self.selectedSlot) then
        local prevObject = self.settings.sequenceItemInfo[self.selectedSlot];
        if (prevObject and (prevObject.class == "Turbine.UI.Lotro.Quickslot") and (not prevObject.type)) then
            -- Delete empty shortcut
            prevObject.class = nil;
        end
    end
    if (s ~= nil) then
        self:ExtendSequenceTo(s);
        object = self.sequenceItems[s];
        self.Marquee = Thurallor.UI.Marquee();
        self.Marquee.s = s;
        self.Marquee:SetParent(self.slotPanel);
        local left, top = self.slotPanel:PointToClient(object.numLabel:PointToScreen(0, 0));
        local width, height = object.numLabel:GetSize();
        self.Marquee:SetPosition(left - 1, top - 1);
        self.Marquee:SetSize(width + 2, height + 2);
        self.Marquee:SetMouseVisible(false);
    end
    self.selectedSlot = s;
    self:DisplaySlot(s);
end

function SequenceEditor:GetSlotPosition(x, y)
    local left = (x - 1) * (self.settings.slotSize + self.settings.slotSpacing) - self.settings.slotSpacing;
    local top = (y - 1) * (self.settings.slotSize + self.settings.slotSpacing) - self.settings.slotSpacing;
    return left, top;
end

function SequenceEditor:Closing()
    self:DeleteEmptyTrailingSlots();
    self.bar:ShortcutChanged();
end

function SequenceEditor:Close()
    Turbine.UI.Lotro.Window.Close(self);
end

function SequenceEditor:ShowContextMenu()
    -- Build the settings menu.
    if (not self.settingsMenu) then
        self.settingsMenu = Turbine.UI.ContextMenu();
    end
    local prevContext = L:SetContext("/SequenceEditor/RightClickMenu");
    self:AddSettingsMenuItem(self.settingsMenu, "Root", false);
    L:SetContext(prevContext);
    self.settingsMenu:ShowMenu();
end

function SequenceEditor:AddSettingsMenuItem(parent, itemName)
    local item = Turbine.UI.MenuItem(L:GetText(itemName), true, false);
    parent:GetItems():Add(item);

    if (itemName == "Root") then
        parent:GetItems():Clear();
        self:AddSettingsMenuItem(parent, "InsertEmptySlot");
        self:AddSettingsMenuItem(parent, "DeleteSlot");
        self:AddSettingsMenuItem(parent, "CreateSpecialSlot");
    elseif (itemName == "InsertEmptySlot") then
        item.Click = function(sender, args)
            self:InsertEmptySlot(self.clickedItem);
        end
    elseif (itemName == ("DeleteSlot")) then
        item.Click = function(sender, args)
            self:DeleteSlot(self.clickedItem);
        end
    elseif (itemName == "CreateSpecialSlot") then
        local prevContext = L:SetContext("SpecialSlotMenu");
        self:AddSettingsMenuItem(item, "RemoveEquipment");
        self:AddSettingsMenuItem(item, "StopAnimating");
        self:AddSettingsMenuItem(item, "GenerateEvent");
        L:SetContext(prevContext);
    elseif (string.find("StopAnimating|GenerateEvent", itemName)) then
        item.Click = function(sender, args)
            self:CreateCommandSlot(self.clickedItem, itemName, item:GetText());
        end
    elseif (itemName == "RemoveEquipment") then
        local prevContext = L:SetContext("RemoveEquipmentMenu");
        for itemSlot in keys(Turbine.Gameplay.Equipment) do
            local value = Turbine.Gameplay.Equipment[itemSlot];
            if ((type(value) == "number") and (value > 0)) then
                self:AddSettingsMenuItem(item, "Remove" .. itemSlot);
            end
        end
        L:SetContext(prevContext);
    elseif (string.sub(itemName, 1, 6) == "Remove") then
        item.Click = function(sender, args)
            self:CreateRemovalSlot(self.clickedItem, string.sub(itemName, 7), item:GetText());
        end
    end
end

function SequenceEditor:CreateCommandSlot(s, slotName, toolTip)
    self:ExtendSequenceTo(s);
    local info = self.settings.sequenceItemInfo[s];
    info.class = "Turbine.UI.Control";
    info.background = resources.Icon[slotName];
    if (slotName == "StopAnimating") then
        info.action = "local item, args = ...; item.bar.animationStopped = true;";
    elseif (slotName == "GenerateEvent") then
        info.eventName = "New Event";
        info.action = "local item, args = ...; item.bar.manager:PropagateEvent(item.eventName);";
    end
    info.type = slotName;
    info.toolTip = toolTip;
    self:RebuildSlot(s);
    self.bar:ShortcutChanged();
    self:Redraw();
    self:SelectSlot(s);
end

function SequenceEditor:CreateRemovalSlot(s, slotName, toolTip)
    self:ExtendSequenceTo(s);
    local info = self.settings.sequenceItemInfo[s];
    info.class = "Turbine.UI.Control";
    info.background = resources.Icon["Unequip" .. slotName];
    info.action = "Unequip(Turbine.Gameplay.Equipment." .. slotName .. ", \"" .. slotName .. "\");";
    info.type = slotName;
    info.toolTip = toolTip;
    self:RebuildSlot(s);
    self.bar:ShortcutChanged();
    self:Redraw();
    self:SelectSlot(s);
end

function SequenceEditor:ExtendSequenceTo(s)
    if (s <= #self.settings.sequenceItemInfo) then
        return false;
    end
    while (s > #self.settings.sequenceItemInfo) do
        table.insert(self.settings.sequenceItemInfo, {});
    end
    return true;
end

function SequenceEditor:DeleteEmptyTrailingSlots()
    local sequenceItemInfo = self.settings.sequenceItemInfo;
    for s = #sequenceItemInfo, 1, -1 do
        local info = sequenceItemInfo[s];
        if (not info.class) then
            table.remove(sequenceItemInfo, s);
            -- Remove empty slot displays
            if (self.sequenceItems) then
                local object = self.sequenceItems[s];
                if (object) then
                    if (object.numLabel) then
                        object.numLabel:SetParent(nil);
                    end
                    object:SetParent(nil);
                    self.sequenceItems[s] = nil;
                end
            end
        else
            break;
        end
    end
end

function SequenceEditor:InsertEmptySlot(s)
    if (s > #self.settings.sequenceItemInfo) then
        self:ExtendSequenceTo(s);
    else
        table.insert(self.settings.sequenceItemInfo, s, {});
    end
    self:Redraw();
    self.bar:ShortcutChanged();
    self:SelectSlot(s);
end

function SequenceEditor:DeleteSlot(s)
    table.remove(self.settings.sequenceItemInfo, s);
    self:Redraw();
    self.bar:ShortcutChanged();
    self:ExtendSequenceTo(s);
    self:SelectSlot(nil);
end

Go to most recent revision | Compare with Previous | Blame


All times are GMT -5. The time now is 02:25 AM.


Our Network
EQInterface | EQ2Interface | Minion | WoWInterface | ESOUI | LoTROInterface | MMOUI | Swtorui