lotrointerface.com
Search Downloads

LoTROInterface SVN SequenceBars

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

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

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

-- Class variable keeping track of all SequenceEditor instances:
SequenceEditor.instances = {};

function SequenceEditor:Constructor(bar, settings)
    Turbine.UI.Lotro.Window.Constructor(self);
    SequenceEditor.instances[self] = true;

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

    self:SetText(bar:GetName());
    self:SetZOrder(math.min(bar:GetZOrder(), 2147483642) + 5);
    self:SetResizable(true);
    self:SetVisible(true);
    
    if (not self.settings.sequenceEditor) then
        self.settings.sequenceEditor = {};
        self.settings.sequenceEditor.defaultIcon = resources.BlankIcons[3];
    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:Activated()
    -- Find the maximum Z order among all other Sequence Editors.
    local maxZ = self:GetZOrder() - 1;
    for editor in keys(SequenceEditor.instances) do
        if (editor ~= self) then
            local z = editor:GetZOrder();
            if (z > maxZ) then
                maxZ = z;
            end
        end
    end
    
    if (maxZ == 2147483647) then
        -- Move all other SequenceEditors back to make room at the front.
        for editor in keys(SequenceEditor.instances) do
            editor:SetZOrder(editor:GetZOrder() - 1);
        end
        maxZ = maxZ - 1;
    end

    -- Move the newly-activated Sequence Editor to the front of the stack.
    self:SetZOrder(maxZ + 1);
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;
    self.slotSize = self.settings.slotSize + self.settings.slotSpacing;
    self.slotsWide = math.floor((slotPanelWidth - 3) / self.slotSize);
    self.slotsHigh = math.max(math.ceil(#self.settings.sequenceItemInfo / self.slotsWide) + 1, 2);
    self:ExtendSequenceTo(self.slotsHigh * self.slotsWide);
    self.slotPanel:SetSize(self.slotsWide * self.slotSize + 3, self.slotsHigh * self.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, self.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) or (s > #self.settings.sequenceItemInfo)) then
        self.slotTabCard:SetVisible(false);
        return;
    else
        self.slotTabCard:SetVisible(true);
    end
    self:ExtendSequenceTo(s);
    local info = self.settings.sequenceItemInfo[s];

    -- 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 icon;
    local function UpdateIcon()
        if (icon) then
            icon:SetParent(nil);
        end
        icon = self:BuildSlot(s, self.slotProperties, nil, 72, 10);
        icon.numLabel:SetText(nil);     -- don't display slot number overlay
        icon.numLabel.MouseClick = nil; -- disable right-click menu
        icon.numLabel.MouseDown = nil;  -- disable dragging
        self:RebuildSlot(s, nil, nil, true);
    end
    UpdateIcon();

    -- 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:SetMultiline(false);
        textBox:SetFont(Turbine.UI.Lotro.Font.TrajanPro14);
        textBox:SetForeColor(color);
        textBox:SetText(text);
        return top, textBox;
    end

    -- Create a function for adding a centered checkbox to the properties control
    local AddCheckBox = function(top, text, color, checked)
        local checkBox = Turbine.UI.Lotro.CheckBox();
        checkBox:SetParent(self.slotProperties);
        checkBox:SetPosition(0, top);
        checkBox:SetSize(180, 20);
        top = top + 20;
        checkBox:SetTextAlignment(Turbine.UI.ContentAlignment.MiddleLeft);
        checkBox:SetFont(Turbine.UI.Lotro.Font.TrajanPro14);
        checkBox:SetForeColor(color);
        checkBox:SetText(text);
        if (checked) then
            checkBox:SetChecked(true);
        end
        return top, checkBox;
    end
    
    -- Create a function for adding a left-justified radio button to the properties control
    local AddRadioButton = function(top, text, color, checked)
        local button = Thurallor.UI.RadioButton(self.slotProperties, text, checked);
        button:SetPosition(0, top);
        button:SetSize(180, 16);
        top = top + 16;
        button:SetFont(Turbine.UI.Lotro.Font.TrajanPro14);
        button:SetForeColor(color);
        return top, button;
    end

    -- Create a function for adding a drop-down listbox to the properties control
    local AddDropDown = function(top, items, color, default)
        local dropDown = Thurallor.UI.DropDown(items, default);
        dropDown:SetParent(self.slotProperties);
        dropDown:SetPosition(0, top);
        dropDown:SetWidth(180);
        top = top + dropDown:GetHeight();
        return top, dropDown;
    end

    -- Create a function for adding a horizontal scrollbar to the properties control
    local AddSlider = function(top, minimum, maximum, value)
        local scrollBar = Turbine.UI.Lotro.ScrollBar();
        scrollBar:SetParent(self.slotProperties);
        scrollBar:SetPosition(0, top);
        scrollBar:SetSize(180, 10);
        scrollBar:SetMinimum(minimum);
        scrollBar:SetMaximum(maximum);
        scrollBar:SetSmallChange(1);
        scrollBar:SetValue(value);
        top = top + 10;
        return top, scrollBar;
    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
        
        if (info.type == Turbine.UI.Lotro.ShortcutType.Alias) then
            -- Allow the user to optionally change the icon
            top = top + 16; -- skip a line
            top = AddLabel(top, L:GetText("/SequenceEditor/ChangeIcon") .. ":", Turbine.UI.Color.Goldenrod);
            local minimum, maximum = 0, #resources.BlankIcons;
            local value = search(resources.BlankIcons, info.background);
            local slider;
            top, slider = AddSlider(top, minumum, maximum, value);
            slider.ValueChanged = function(sender)
                local value = sender:GetValue();
                if (value == 0) then
                    info.background = nil;
                else
                    info.background = resources.BlankIcons[value];
                end
                UpdateIcon();
                self.bar:ShortcutChanged();

                self.settings.sequenceEditor.defaultIcon = info.background;
                self:SaveSettings();
            end

            -- Allow the user to specify the command
            top = top + 16; -- skip a line
            top = AddLabel(top, L:GetText("/SequenceEditor/ChatCommand") .. ":", Turbine.UI.Color.Goldenrod);
            local textBox;
            top, textBox = AddTextBox(top, info.Data, 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.Data = text;
                self.bar:ShortcutChanged();
            end
        end
        
    elseif (info.class == "Turbine.UI.Control") then
        if (info.type == "GenerateEvent") then
        
            -- Allow the user to specify the event name
            top = top + 16; -- skip a line
            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
        elseif (info.type == "SetUnequipDestination") then

            -- Allow the user to specify the desired bag slot
            top = top + 16; -- skip a line
            top = AddLabel(top, L:GetText("/SequenceEditor/PreferredBagSlot") .. ":", Turbine.UI.Color.Goldenrod);
            
            local lp = Turbine.Gameplay.LocalPlayer:GetInstance();
            local bags = lp:GetBackpack();
            local inventory = {}, currentItemName;
            for i = 1, bags:GetSize() do
                table.insert(inventory, tostring(i));
                if (i == info.bagSlot) then
                    currentItemName = itemName;
                end
            end
            top, dropDown = AddDropDown(top, inventory, Turbine.UI.Color.White, tostring(info.bagSlot));
            dropDown:SetWidth(50);
            dropDown:SetLeft(65);
            dropDown.ItemChanged = function(sender, args)
                info.bagSlot = tonumber(args.Text);
                self.bar:ShortcutChanged();
            end
        elseif (string.match(info.type, "^Remove ")) then
        
            -- Allow the user to edit choose the item to be unequipped
            top = top + 16; -- skip a line
            top = AddLabel(top, L:GetText("/SequenceEditor/EquipmentType") .. ":", Turbine.UI.Color.Goldenrod);

            local currentItem = string.sub(info.type, 8);
            local prevContext = L:SetContext("/SequenceEditor/EquipmentSlots");
            local eqSlots, localEqSlots = L:GetItems(), {};
            for slot in values(eqSlots) do
                table.insert(localEqSlots, L:GetText(slot));
            end
            table.sort(localEqSlots);
            local dropDown;
            top, dropDown = AddDropDown(top, localEqSlots, Turbine.UI.Color.White, L:GetText(currentItem));
            dropDown.ItemChanged = function(sender, args)
                for slot in values(eqSlots) do
                    if (L:GetText(slot) == args.Text) then
                        self:CreateRemovalSlot(s, slot, info.bagSlot);
                        break;
                    end
                end
            end
        end            

        -- Automatic mode is not allowed for slot 1.  It also doesn't make sense for "Stop animating".
        if ((s > 1) and (info.toolTip ~= L:GetText("/SequenceEditor/RightClickMenu/SpecialSlotMenu/StopAnimating"))) then
            top = top + 16; -- skip a line
            top = AddLabel(top, L:GetText("/SequenceEditor/Activation") .. ":", Turbine.UI.Color.Goldenrod);
            local button1, button2;
            top, button1 = AddRadioButton(top, L:GetText("/SequenceEditor/WithLeftClick"), Turbine.UI.Color.DarkGoldenrod, (not info.automatic));
            top, button2 = AddRadioButton(top, L:GetText("/SequenceEditor/Automatic"), Turbine.UI.Color.DarkGoldenrod, info.automatic);
            Thurallor.UI.RadioButton.LinkPeers({button1, button2});
     
            button1.Clicked = function()
                info.automatic = nil;
                self.bar:ShortcutChanged();
            end
            button2.Clicked = function()
                info.automatic = true;
                self.bar:ShortcutChanged();
            end
        end
    end

    -- Allow the user to optionally overlay some text
    if (not info.temporary) then
        top = top + 16; -- skip a line
        top = AddLabel(top, L:GetText("/SequenceEditor/TextOverlay") .. ":", Turbine.UI.Color.Goldenrod);
        local textBox;
        top, textBox = AddTextBox(top, info.textOverlay, Turbine.UI.Color.White);
        textBox:SetFont(Turbine.UI.Lotro.Font.Verdana12);
        textBox.TextChanged = function(sender, args)
            local text = sender:GetText();
            if (text == "") then
                text = nil;
            end
            info.textOverlay = text;
            UpdateIcon();
            self.bar:ShortcutChanged();
        end
    end
    
    self.slotProperties:SetHeight(top);
end

function SequenceEditor:FindSlotAtPosition(mouseX, mouseY, drawCaret)
    local originX, originY = self.slotPanel:GetParent():PointToScreen(self.slotPanel:GetPosition());
    local relX, relY = mouseX - originX, mouseY - originY + 3;
    local posX, posY = 1 + math.floor(relX / self.slotSize), 1 + math.floor(relY / self.slotSize);
    local s = nil;
    if ((posX >= 0) and (posX <= self.slotsWide) and (posY >= 1) and (posY <= self.slotsHigh)) then
        s = ((posY - 1) * self.slotsWide) + posX;

        -- If we're hovering over the right half of the icon, insert after this icon.
        local iconRelX = self.slotSize * (relX / self.slotSize - math.floor(relX / self.slotSize));
        if (iconRelX > (self.slotSize / 2)) then
            posX = posX + 1;
            s = s + 1;
        elseif (posX == 0) then
            s = nil;
        end
    end
    
    -- Update caret position.
    if ((not drawCaret) or (not s)) then
        -- Hide carets in all Sequence Editors
        for editor in keys(SequenceEditor.instances) do
            if (editor.caret) then
                editor.caret:SetParent(nil);
                editor.caret = nil;
            end
        end
    else
        if (not self.caret) then
            self.caret = Turbine.UI.Control();
            self.caret:SetParent(self.slotPanel);
            self.caret:SetBackground(resources.Icon.Caret);
            self.caret:SetBlendMode(Turbine.UI.BlendMode.AlphaBlend);
            self.caret:SetSize(3, 36)
        end
        self.caret:SetPosition((posX - 1) * self.slotSize, (posY - 1) * self.slotSize);
    end

    return s;
end

function SequenceEditor:FindForeignSlotAtPosition(mouseX, mouseY, drawCaret)

    -- Find the frontmost SequenceEditor under the mouse cursor
    local frontEditor = self;
    local maxZ = -2147483648;
    for editor in keys(SequenceEditor.instances) do
        if (editor ~= self) then
            local left, top = editor:GetPosition();
            local width, height = editor:GetSize();
            if ((mouseX >= left) and (mouseX <= left + width) and (mouseY >= top) and (mouseY <= top + height)) then
                if (editor:GetZOrder() >= maxZ) then
                    frontEditor = editor;
                    maxZ = editor:GetZOrder();
                end
            end
        end
    end

    return frontEditor, frontEditor:FindSlotAtPosition(mouseX, mouseY, drawCaret);
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.leftOffset, object.topOffset = 0, 0;
    elseif (info.class == "Turbine.UI.Control") then
        if (not object) then
            object = Turbine.UI.Control();
        end
        object.isQuickslot = false;
        object:SetSize(32, 32);
        object.leftOffset, object.topOffset = 3, 3;
    end
    object:SetPosition(left + object.leftOffset, top + object.topOffset);
    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);
    
    -- Draw text overlay (if any)
    if (object.textOverlay) then
        object.textOverlay:SetParent(nil);
    end
    if ((info.textOverlay) or (info.background)) then
        object.textOverlay = Turbine.UI.Label();
        object.textOverlay:SetParent(object);
        object.textOverlay:SetPosition(3 - object.leftOffset, 3 - object.topOffset);
        object.textOverlay:SetSize(32, 32);
        object.textOverlay:SetMouseVisible(false);
        object.textOverlay:SetFont(Turbine.UI.Lotro.Font.Verdana10);
        object.textOverlay:SetZOrder(object:GetZOrder() + 1);
        object.textOverlay:SetTextAlignment(Turbine.UI.ContentAlignment.MiddleCenter);
        object.textOverlay:SetFontStyle(Turbine.UI.FontStyle.Outline);
        object.textOverlay:SetOutlineColor(Turbine.UI.Color(1, 0, 0, 0));
        object.textOverlay:SetMultiline(true);
        object.textOverlay:SetMarkupEnabled(true);
        object.textOverlay:SetBackground(info.background);
        object.textOverlay:SetText(info.textOverlay);
    end

    -- 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:SetSize(32, 32);
        numLabel:SetZOrder(object:GetZOrder() + 1);
        numLabel:SetMouseVisible(true);
        numLabel:SetAllowDrop(true);
    end
    numLabel:SetText(tonumber(s));
    numLabel:SetVisible(true);
    numLabel:SetPosition(left + 3, top + 3);

    -- Desired mouse behaviors:
    --   Left-click selects the slot and shows its properties in the "Slot" tab.
    --   Right-click displays the settings menu.    
    --   Left-button-drag initiates a drag-and-drop (move) operation.

    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();
        if (info.type == Turbine.UI.Lotro.ShortcutType.Alias) then
            info.textOverlay = string.gsub(info.Data, "^/", "");
            info.textOverlay = string.gsub(info.textOverlay, "%s.*$", "");
            info.background = self.settings.sequenceEditor.defaultIcon;
        end
        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
            if (not sender.mouseMoved) then
                self:SelectSlot(sender.object.s);
            end

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

    numLabel.MouseDown = function(sender, args)
        if (args.Button == Turbine.UI.MouseButton.Left) then
            -- Drag begin.  Save the current position of the icon, overlay, and mouse.
            sender.mouseDown = true;
            sender.mouseMoved = false;
            sender.object.originalLeft, sender.object.originalTop = parent:PointToScreen(sender.object:GetPosition());
            sender.originalLeft, sender.originalTop = parent:PointToScreen(sender:GetPosition());
            sender.originalMouseX, sender.originalMouseY = Turbine.UI.Display.GetMouseX(), Turbine.UI.Display.GetMouseY();
        end
    end

    numLabel.MouseMove = function(sender)
        if (sender.mouseDown) then
            -- Detach from parent if we haven't already done so.
            if (not sender.mouseMoved) then
                sender.parent = sender:GetParent();
                sender.tempContainer = Turbine.UI.Window();
                sender.tempContainer:SetVisible(true);
                sender.tempContainer:SetZOrder(2147483647);
                sender.tempContainer:SetSize(sender.object:GetSize());
                sender.tempContainer:SetOpacity(0.75);
                sender.object:SetParent(sender.tempContainer);
                sender.object:SetPosition(0, 0);
                sender:SetParent(sender.tempContainer);
                sender:SetPosition(sender.originalLeft - sender.object.originalLeft, sender.originalTop - sender.object.originalTop);
                sender:SetText(nil);
            end
        
            -- Drag continuing.  Find out how much the mouse has moved.
            sender.mouseMoved = true;
            local newMouseX, newMouseY = Turbine.UI.Display.GetMouseX(), Turbine.UI.Display.GetMouseY();
            local deltaX, deltaY = newMouseX - sender.originalMouseX, newMouseY - sender.originalMouseY;

            -- Move the icon and overlay.
            sender.tempContainer:SetPosition(sender.object.originalLeft + deltaX, sender.object.originalTop + deltaY);
            
            -- Draw a "caret" showing where the slot will be inserted.
            local editor = self;
            local newSlot = self:FindSlotAtPosition(sender.tempContainer:GetLeft(), sender.tempContainer:GetTop(), true);
            if (not newSlot) then
                editor, newSlot = self:FindForeignSlotAtPosition(sender.tempContainer:GetLeft(), sender.tempContainer:GetTop(), true);
            end
            if (newSlot) then
                sender:SetBackground(nil);
            else
                -- Show a red "X" if invalid drag location is selected.
                sender:SetBackground(resources.Icon.DragFail);
                sender:SetBlendMode(Turbine.UI.BlendMode.AlphaBlend);
            end
            if ((editor == self) and ((newSlot == sender.object.s) or (newSlot == sender.object.s + 1))) then
                self:FindSlotAtPosition(0, 0, false); -- hide caret if returning to the same position
            end
         end
    end

    numLabel.MouseUp = function(sender, args)
        if (args.Button == Turbine.UI.MouseButton.Left) then
        
            -- Drag end.  Find out how much the mouse has moved.
            sender.mouseDown = false;
            if (not sender.mouseMoved) then
                return;
            end
            local newMouseX, newMouseY = Turbine.UI.Display.GetMouseX(), Turbine.UI.Display.GetMouseY();
            local deltaX, deltaY = newMouseX - sender.originalMouseX, newMouseY - sender.originalMouseY;

            -- Select destination slot.  Hide the caret.
            local editor = self;
            local newSlot = self:FindSlotAtPosition(sender.tempContainer:GetLeft(), sender.tempContainer:GetTop(), false);
            if (not newSlot) then
                editor, newSlot = self:FindForeignSlotAtPosition(sender.tempContainer:GetLeft(), sender.tempContainer:GetTop(), false);
            end
            
            -- Reattach to parent.
            sender:SetBackground(nil);
            sender:SetParent(sender.parent);
            sender.object:SetParent(sender.parent);
            sender.tempContainer:Close();
            
            -- Do the move operation, and redraw.
            if (newSlot and (editor ~= self)) then
                editor:InsertSlot(newSlot, self.settings.sequenceItemInfo[s]);
                self:DeleteSlot(s);
            elseif (newSlot and (newSlot ~= sender.object.s) and (newSlot ~= sender.object.s + 1)) then
                self:MoveSlot(sender.object.s, newSlot);
            else
                self:Redraw();
            end
        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, alreadyDisplaying)
    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 (not alreadyDisplaying and (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
        local info = self.settings.sequenceItemInfo[s];
        if (not info.class) then
            s = nil;
        else
            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
    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()
    SequenceEditor.instances[self] = nil;
    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, "CloneSlot");
        self:AddSettingsMenuItem(parent, "InsertEmptySlot");
        self:AddSettingsMenuItem(parent, "DeleteSlot");
        self:AddSettingsMenuItem(parent, "CreateSpecialSlot");
    elseif (itemName == "CloneSlot") then
        item.Click = function(sender, args)
            self:CloneSlot(self.clickedItem);
        end
    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, "ChatCommand");
        self:AddSettingsMenuItem(item, "StopAnimating");
        self:AddSettingsMenuItem(item, "GenerateEvent");
        self:AddSettingsMenuItem(item, "SetUnequipDestination");
        L:SetContext(prevContext);
    elseif (string.find("StopAnimating|GenerateEvent|SetUnequipDestination", itemName)) then
        item.Click = function(sender, args)
            self:CreateCommandSlot(self.clickedItem, itemName, item:GetText());
        end
    elseif (itemName == "ChatCommand") then
        local commands = Turbine.Shell.GetCommands();
        local index = math.random(#commands);
        item.Click = function(sender, args)
            self:CreateAliasSlot(self.clickedItem, "/" .. commands[index]);
        end
    elseif (itemName == "RemoveEquipment") then
        item.Click = function(sender, args)
            self:CreateRemovalSlot(self.clickedItem, "Gloves");
        end
    elseif (string.sub(itemName, 1, 6) == "Remove") then
    end
end

function SequenceEditor:CreateAliasSlot(s, command)
    self:ExtendSequenceTo(s);
    local info = self.settings.sequenceItemInfo[s];
    info.class = "Turbine.UI.Lotro.Quickslot";
    info.background = nil;
    info.type = Turbine.UI.Lotro.ShortcutType.Alias;
    info.Data = command;
    info.textOverlay = string.gsub(info.Data, "^/", "");
    info.textOverlay = string.gsub(info.textOverlay, "%s.*$", "");
    info.background = self.settings.sequenceEditor.defaultIcon;
    self:RebuildSlot(s);
    self.bar:ShortcutChanged();
    self:Redraw();
    self:SelectSlot(s);
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);";
    elseif (slotName == "SetUnequipDestination") then
        info.bagSlot = 1;
        info.action = "local item, args = ...; item.bar.manager:SetUnequipDestination(item.bagSlot);";
    end
    info.type = slotName;
    info.toolTip = toolTip;
    self:RebuildSlot(s);
    self.bar:ShortcutChanged();
    self:Redraw();
    self:SelectSlot(s);
end

function SequenceEditor:CreateRemovalSlot(s, eqSlotName, bagSlot)
    self:ExtendSequenceTo(s);
    local info = self.settings.sequenceItemInfo[s];
    info.class = "Turbine.UI.Control";
    info.background = resources.Icon["Unequip" .. eqSlotName];
    info.action = "local item, args = ...; item.bar.manager:Unequip(Turbine.Gameplay.Equipment." .. eqSlotName .. ");";
    info.type = "Remove " .. eqSlotName;
    
    local prevContext = L:SetContext("/SequenceEditor");
    local toolTip = L:GetText("RemoveItem");
    L:SetContext("EquipmentSlots");
    local localEqSlotName = L:GetText(eqSlotName);
    info.toolTip = string.gsub(toolTip, "<item>", localEqSlotName);
    L:SetContext(prevContext);
    
    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:CloneSlot(s)
    self:InsertEmptySlot(s);
    DeepTableCopy(self.settings.sequenceItemInfo[s + 1], self.settings.sequenceItemInfo[s]);
    self:RebuildSlot(s);
    self.bar:ShortcutChanged();
    self:Redraw();
    self:SelectSlot(s);
end

function SequenceEditor:MoveSlot(sourceSlot, destSlot)
--Puts("sourceSlot, destSlot = " .. tostring(sourceSlot) .. ", " .. tostring(destSlot));
    self:InsertEmptySlot(destSlot);
    if (sourceSlot >= destSlot) then
        sourceSlot = sourceSlot + 1;
    end
    DeepTableCopy(self.settings.sequenceItemInfo[sourceSlot], self.settings.sequenceItemInfo[destSlot]);
    self:RebuildSlot(destSlot);
    self:DeleteSlot(sourceSlot);
    if (sourceSlot <= destSlot) then
        destSlot = destSlot - 1;
    end
    self.bar:ShortcutChanged();
    self:Redraw();
    self:SelectSlot(destSlot);
end

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

function SequenceEditor:InsertEmptySlot(s)
    self:InsertSlot(s, nil);
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 06:27 AM.


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