lotrointerface.com
Search Downloads

LoTROInterface SVN Calendar

[/] [Release_3.0/] [FrostyPlugins/] [CustomPluginsManager/] [CustomPluginsManager.lua] - Rev 25

Compare with Previous | Blame | View Log

import "Turbine";
import "Turbine.Gameplay";
import "Turbine.UI";
import "Turbine.UI.Extensions";
import "Turbine.UI.Lotro";
import "Turbine.Utils";
import "FrostyPlugins.CustomPluginsManager.PluginSlot"
import "FrostyPlugins.CustomPluginsManager.TooltipWindow"
import "FrostyPlugins.CustomPluginsManager.IconEntryWindow"

-- -----------------------------------------------------------------------
-- CustomPluginsManager is the main window that handles all of the plugins.
-- there are tabs for the currently loaded and available plugins.  you can
-- enable and disable plugins and check the state of the plugins.
--
-- ToDo:
-- . is there a way to programatically determine what the icons are ?
-- -----------------------------------------------------------------------

CustomPluginsManager = class( Turbine.UI.Window);

-- --------------------------------------------------------------
-- Constructor
--
-- Description: this is where the window is laid out, the fields
-- and buttons are created, and events are trapped.
-- --------------------------------------------------------------
function CustomPluginsManager:Constructor()
        Turbine.UI.Window.Constructor( self );

        -- load the last settings saved
        self:LoadSettings();

  -- static - the maximum number of plugin slot containers per page
  self.MAX_SLOTS = 16;
  --self.MAX_SLOTS = 4;
  
  -- has the mouse been moved?
  self.dragged = false;

  -- this is the list of plugin containers
  self.pluginContainers = { };

  -- the index of the set of plugins displayed on the UI
  self.displayedPluginsIndex = 1;
  
  -- the total number of valid plugins that we know about
  self.validPluginCount = 0;
  
  -- the click bias for determining if we are moving the window
  -- the units of measure is pixels
  self.clickMoveBias = 7;

  -- the move bias for determining if we are swiping the window
  -- the units of measure is pixels
  self.clickSwipeBias = 20;
  
  -- --------------------------------------------
  -- window layout
  -- --------------------------------------------
  
        -- set window properties
  self:SetBackground( "FrostyPlugins/CustomPluginsManager/Resources/ManagerBackground.tga" );
  self:SetBackColorBlendMode( Turbine.UI.BlendMode.Overlay );
        self:SetSize( 172, 255 );
        self:SetPosition( self.settings.positionX, self.settings.positionY );
        self:SetOpacity( 1 );
        self:SetAllowDrop( false );
        self:SetMouseVisible( true );
  
  -- create the "close window" button.  why don't people just use escape?
  self.closeButton = Turbine.UI.Button();
  self.closeButton:SetBackground( "FrostyPlugins/CustomPluginsManager/Resources/CloseButtonNormal.tga" );
  self.closeButton:SetBlendMode( Turbine.UI.BlendMode.Overlay );
        self.closeButton:SetParent( self );
        self.closeButton:SetPosition( 158, 0 );
        self.closeButton:SetSize( 14, 14 );
        self.closeButton:SetVisible( true );
  self.closeButton.MouseEnter = function( sender, args )
    self.closeButton:SetBackground( "FrostyPlugins/CustomPluginsManager/Resources/CloseButtonHilight.tga" );
        end
  self.closeButton.MouseLeave = function( sender, args )
    self.closeButton:SetBackground( "FrostyPlugins/CustomPluginsManager/Resources/CloseButtonNormal.tga" );
  end
  self.closeButton.Click = function( sender, args )
    self:SetVisible( false );
  end
  
        -- create the various plugin slots
  -- we are always going to create a 4x4 set of plugins icons
  local index = 1;
  local rowCount = 4;
  local columnCount = 4;
        for i = 1, rowCount do
          for j = 1, columnCount do
            local pluginContainer = FrostyPlugins.CustomPluginsManager.PluginSlotContainer();
            local x = -22 + j * 37;
            local y = -35 + i * 50;

      -- the constructor of PluginSlot sets most things up - we just need
      -- to know where on the UI this thing is placed
      pluginContainer:SetParent( self );
            pluginContainer:SetPosition( x, y );
            pluginContainer:SetVisible( false );
      pluginContainer:SetOwner( self );
      
      pluginContainer.MouseEnter = function( sender, args )
        if( pluginContainer.pluginSlot.PluginName ~= "" ) then
          local x, y = self:GetPosition();
          self.TooltipWindow:SetPosition( x + 172, y );
          self.TooltipWindow:Initialize( pluginContainer.pluginSlot );
        end
      end
      
      pluginContainer.MouseLeave = function( sender, args )
        if( pluginContainer.pluginSlot.PluginName ~= "" ) then
          self.TooltipWindow:Shutdown();
        end
      end
      
      -- save the editor
      self.pluginContainers[ index ] = pluginContainer;
      index = index + 1;
                end
        end
  
  -- near the bottom of the screen are the previous and next page buttons
  -- they will only be displayed when there are items to be paged
        self.previousPage = Turbine.UI.Button();
  self.previousPage:SetBackground( "FrostyPlugins/CustomPluginsManager/Resources/PageLeft.tga" );
  self.previousPage:SetBackColorBlendMode( Turbine.UI.BlendMode.Overlay );
        self.previousPage:SetParent( self );
        self.previousPage:SetPosition( 5, 220 );
        self.previousPage:SetSize( 20, 20 );
        self.previousPage:SetVisible( false );
  self.previousPage.MouseEnter = function( sender, args )
    self.previousPage:SetBackground( "FrostyPlugins/CustomPluginsManager/Resources/PageLeftHilight.tga" );
        end
  self.previousPage.MouseLeave = function( sender, args )
    self.previousPage:SetBackground( "FrostyPlugins/CustomPluginsManager/Resources/PageLeft.tga" );
  end
  self.previousPage.Click = function( sender, args )
    self:AdjustVisiblePlugins( -self.MAX_SLOTS );
  end

        self.nextPage = Turbine.UI.Button();
  self.nextPage:SetBackground( "FrostyPlugins/CustomPluginsManager/Resources/PageRight.tga" );
  self.nextPage:SetBackColorBlendMode( Turbine.UI.BlendMode.Overlay );
        self.nextPage:SetParent( self );
        self.nextPage:SetPosition( 147, 220 );
        self.nextPage:SetSize( 20, 20 );
        self.nextPage:SetVisible( false );
  self.nextPage.MouseEnter = function( sender, args )
    self.nextPage:SetBackground( "FrostyPlugins/CustomPluginsManager/Resources/PageRightHilight.tga" );
        end
  self.nextPage.MouseLeave = function( sender, args )
    self.nextPage:SetBackground( "FrostyPlugins/CustomPluginsManager/Resources/PageRight.tga" );
  end
  self.nextPage.Click = function( sender, args )
    self:AdjustVisiblePlugins( self.MAX_SLOTS );
  end

  -- label indicating the pages
        self.statusBar = Turbine.UI.Label();
        self.statusBar:SetMouseVisible( false );
        self.statusBar:SetMultiline( false );
        self.statusBar:SetFont( Turbine.UI.Lotro.Font.Verdana14 );
        self.statusBar:SetParent( self );
        self.statusBar:SetPosition( 31, 220 );
        self.statusBar:SetSize( 110, 20 );
        self.statusBar:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleCenter );
        self.statusBar:SetVisible( true );

  -- the tooltip window is always off to the right
  self.TooltipWindow = FrostyPlugins.CustomPluginsManager.TooltipWindow();
  self.TooltipWindow:SetPosition( self.settings.positionX + 172, self.settings.positionY );
  self.TooltipWindow:SetVisible( false );
  
  -- the icon entry window is always off to the right
  self.IconEntryWindow = FrostyPlugins.CustomPluginsManager.IconEntryWindow();
  self.IconEntryWindow:SetPosition( self.settings.positionX + 172, self.settings.positionY );
  self.IconEntryWindow:SetVisible( false );
  
  -- --------------------------------------------
  -- event handling
  -- --------------------------------------------
        -- make sure we listen for key presses
        self:SetWantsKeyEvents( true );

  --
  -- if the escape key is pressed, hide the window
  --
        self.KeyDown = function( sender, args )
                -- do this if the escape key is pressed
                if ( args.Action == Turbine.UI.Lotro.Action.Escape ) then
                        sender:SetVisible( false )
                end
        end

  --
  -- if the position changes, save the new window location
  --
        self.PositionChanged = function( sender, args )
                local x,y = self:GetPosition();
                self.settings.positionX = x;
                self.settings.positionY = y;
                self:SaveSettings();
        end
  
  --
  -- when the mouse is clicked, we may be moving the window or 
  -- "swiping" the plugins
  --
        self.MouseDown = function( sender, args )
          if ( args.Button == Turbine.UI.MouseButton.Left ) then
      -- the user clicked the mosue button
      -- if they clicked on / near the border of the window,
      -- the we promote this to a "drag" operation
      if( ( args.X <= self.clickMoveBias ) or
          ( args.Y <= self.clickMoveBias ) or
          ( args.Y >= ( self:GetHeight() - self.clickMoveBias ) ) or
          ( args.X >= ( self:GetWidth() - self.clickMoveBias ) ) ) then
        self.dragStartX = args.X;
        self.dragStartY = args.Y;
        self.dragging = true;
        self.dragged = false;
        self:SetBackColor( Turbine.UI.Color( 0.5, 0.5, 0.5, 0 ) );
        self.previousPage:SetBackColor( Turbine.UI.Color( 0.5, 0.5, 0.5, 0 ) );
        self.nextPage:SetBackColor( Turbine.UI.Color( 0.5, 0.5, 0.5, 0 ) );
      else
        -- the user clicked somewhere in the middle of the UI.
        -- we promote this to a "swiping" operation
        self.swipeStartX = args.X;
        self.swiping = true;
        self.swiped = false;
      end
          end
        
          if ( args.Button == Turbine.UI.MouseButton.Right ) then
            -- context menu?
          end
  end

  self.MouseMove = function( sender, args )
          local left, top = self:GetPosition();
        
          if ( self.dragging ) then
                  self:SetPosition( left + ( args.X - self.dragStartX ), top + ( args.Y - self.dragStartY ) );
                  self.dragged = true;            
          else
      if( self.swiping ) then
        self.swiped = true;
      end
    end
  end

  self.MouseUp = function( sender, args )
          if ( args.Button == Turbine.UI.MouseButton.Left ) then
                  self.dragging = false;
      self.swiping = false;
                  
                  -- verify the position is on the main screen
      if( self.dragged ) then
        local x, y = self:GetPosition();
        local validX = x;
        local validY = y;
        if( x < 0 ) then
          x = 0;
        end
        if( y < 0 ) then
          y = 0;
        end
        if( x + self:GetWidth() > Turbine.UI.Display.GetWidth() ) then
          x = Turbine.UI.Display.GetWidth() - self:GetWidth();
        end
        if( y + self:GetHeight() > Turbine.UI.Display.GetHeight() ) then
          y = Turbine.UI.Display.GetHeight() - self:GetHeight();
        end
        
        self:SetPosition( x, y );
      end
      if( self.swiped ) then
        local delta = args.X - self.swipeStartX;
        
        if( delta < 0 - self.clickSwipeBias ) then
          self.nextPage:Click();
        else
          if( delta > self.clickSwipeBias ) then
            self.previousPage:Click();
          end
        end
      end
          self:SetBackColor( Turbine.UI.Color( 0, 0, 0, 0 ) );
    self.previousPage:SetBackColor( Turbine.UI.Color( 0, 0, 0, 0 ) );
    self.nextPage:SetBackColor( Turbine.UI.Color( 0, 0, 0, 0 ) );
    self.dragged = false;
    self.swiped = false;
          end
  end

end


-- --------------------------------------------------------------
-- Initialize
--
-- Description: update the currently displayed plugins with what
-- has been loaded from disk
-- --------------------------------------------------------------
function CustomPluginsManager:Initialize()
  -- validate the status of the various plugins
  self:FindAndValidatePlugins();
 
  -- reload plugins
  self:ReloadPlugins();
  
  -- rebuild the plugin slots based on the state of the manager -
  -- on initialization, this shows the loaded plugins
  self:RebuildPluginSlots();
end

-- --------------------------------------------------------------
-- FindAndValidatePlugins
--
-- Description: determine the list of all plugins and iterate over them.
-- correlate what has been saved on disk and what exists now.
-- --------------------------------------------------------------
function CustomPluginsManager:FindAndValidatePlugins()
  -- iterate over all the existing plugins and mark them as "invalid".
  -- we assume invalid, then iterate over all the available plugins
  -- and mark existing ones as valid.
  -- also, mark the plugins and "not loaded" - we do not want to persist
  -- the "was last loaded" flag across runs of the client
  for pluginName, pluginData in pairs( self.settings.pluginSlots ) do
    self.settings.pluginSlots[ pluginName ].PluginValid = false;
    self.settings.pluginSlots[ pluginName ].PluginLoaded = false;
  end
  self.validPluginCount = 0;
  
  -- what plugins are available through the plugins manager?
  -- iterate over all the plugins and assign them to the available list
  local pluginSlots = Turbine.PluginManager.GetAvailablePlugins();
  for key, value in pairs( pluginSlots ) do
    -- we are not going to track the CustomPluginsManager, since that is US!
    -- if the name is CustomPluginsManager, skip it
    if( value.Name ~= "CPM" ) then
      -- if the plugin does not exist in the settings, we create one
      if( not self.settings.pluginSlots[ value.Name ] ) then
        self.settings.pluginSlots[ value.Name ] = FrostyPlugins.CustomPluginsManager.PluginSlot();
        self.settings.pluginSlots[ value.Name ].PluginName          = value.Name;

        -- fixme: frosty
        --        if we ever get configuration data, we could request the
        --        icon here
      end

      -- always update this stuff from the available list, since it will
      -- be the most current
      self.settings.pluginSlots[ value.Name ].PluginValid = true;
      self.settings.pluginSlots[ value.Name ].PluginVersion       = value.Version;
      self.settings.pluginSlots[ value.Name ].PluginAuthor        = value.Author;
      self.settings.pluginSlots[ value.Name ].PluginPackage       = value.Package;
      self.settings.pluginSlots[ value.Name ].PluginScriptState   = value.ScriptState;

      -- another valid plugin, hooray!
      self.validPluginCount = self.validPluginCount + 1;
    end
  end
end

-- --------------------------------------------------------------
-- ReloadPlugins
--
-- Description: For any plugin that had been marked as a "favorite",
-- load it now!
-- --------------------------------------------------------------
function CustomPluginsManager:ReloadPlugins()
  -- iterate over the list of all plugins
  for pluginName, pluginData in pairs( self.settings.pluginSlots ) do
    -- if the plugin is marked as a "favorite", then load it!
    if( pluginData.PluginFavorite == true ) then
      -- have the plugin manager load the plugin
      Turbine.PluginManager.LoadPlugin( pluginData.PluginName );
      self.settings.pluginSlots[ pluginData.PluginName ].PluginLoaded = true;
    end
  end
end

-- --------------------------------------------------------------
-- AdjustVisiblePlugins
--
-- Description: something (user button click or swipe action) has
-- caused the UI to want to display a new set of slots.  validate
-- the current index and rebuild the UI if necessary.
--
-- Params:
-- delta - the amount of slots to move
-- --------------------------------------------------------------
function CustomPluginsManager:AdjustVisiblePlugins( delta )
  local oldIndex = self.displayedPluginsIndex;
  
  -- validate the range of the new index
  self.displayedPluginsIndex = self.displayedPluginsIndex + delta;
  if( self.displayedPluginsIndex < 1 ) then
    self.displayedPluginsIndex = 1;
  else
    if( self.displayedPluginsIndex > self.validPluginCount ) then
      self.displayedPluginsIndex = oldIndex;
    end
  end
  
  -- only rebuild the slots if the index changed
  if( self.displayedPluginsIndex ~= oldIndex ) then
    self:RebuildPluginSlots();
  end
end

-- --------------------------------------------------------------
-- RebuildPluginSlots
--
-- Description: toggle between showing and hiding the plugin slots.
-- this function clears and rebuilds the plugins array and the
-- visual representation.
-- --------------------------------------------------------------
function CustomPluginsManager:RebuildPluginSlots()
  -- we are going to update all the plugin slots, so we need to know
  -- how many containers were updated.
  local nUpdateCount = 0;

  -- because the list of plugins can be paged, we need to allow for
  -- detecting the number of matches and only show those items for
  -- the current (virtual) page
  local nMatchCount = 0;

  -- iterate over the list of all plugins
  for pluginName, pluginData in pairs( self.settings.pluginSlots ) do
    -- if the plugin is valid, we will display it...
    -- provided that the plugin fits on the screen
    nMatchCount = nMatchCount + 1;
    if( ( nMatchCount >= self.displayedPluginsIndex ) and ( nMatchCount < ( self.displayedPluginsIndex + self.MAX_SLOTS ) ) ) then
      nUpdateCount = nUpdateCount + 1;
      self.pluginContainers[ nUpdateCount ]:Initialize( pluginData );
    end
  end
  
  -- iterate over all the slots that were not updated.  there are a
  -- max of sixteen plugin slot containers
  for i = nUpdateCount + 1, self.MAX_SLOTS do
    self.pluginContainers[ i ]:Reset();
  end
  
  -- turn the next page and previous page buttons on and off as necessary.
  if( self.displayedPluginsIndex == 1 ) then
    self.previousPage:SetVisible( false );
  else
    self.previousPage:SetVisible( true );
  end
  if( nMatchCount >= ( ( self.displayedPluginsIndex + self.MAX_SLOTS ) ) ) then
    self.nextPage:SetVisible( true );
  else
    self.nextPage:SetVisible( false );
  end
  
  -- update the status bar
  local minCount = math.floor( self.displayedPluginsIndex / self.MAX_SLOTS ) + 1;
  local maxCount = math.floor( self.validPluginCount / self.MAX_SLOTS );
  if( ( self.validPluginCount % self.MAX_SLOTS ) ~= 0 ) then
    maxCount = maxCount + 1;
  end
  self.statusBar:SetText( tostring( minCount ) .. " of " .. tostring( maxCount ) );
end

-- --------------------------------------------------------------
-- LoadSettings
--
-- Description: loads our internal settings from disk.  For this class,
-- this includes the position of the window and the list of plugins.
-- if the position does not exist, we set it to 0, 0.  if we do not
-- know about any plugins, we create a list
-- --------------------------------------------------------------
function CustomPluginsManager:LoadSettings()
        -- load the settings.  If a value is not available, set a default value
        self.settings = Turbine.PluginData.Load( Turbine.DataScope.Character, "CustomPluginsManagerSettings" );

        if ( type( self.settings ) ~= "table" ) then
                self.settings = { };
        end

        if ( not self.settings.positionX ) then
                self.settings.positionX = 0; 
        end

        if ( not self.settings.positionY ) then
                self.settings.positionY = 0;
        end

        if ( not self.settings.pluginSlots ) then
                self.settings.pluginSlots = { };
        end
  
  -- sort the list of plugins
  table.sort( self.settings.pluginSlots, function(a,b) return (a.PluginName < b.PluginName) end );
end

-- --------------------------------------------------------------
-- SaveSettings
--
-- Description: save our internal settings to disk.  For this class,
-- this includes the position of the wrapper window and the list of
-- events that have been created.
-- --------------------------------------------------------------
function CustomPluginsManager:SaveSettings()
  
  -- sort the list of plugins
  table.sort( self.settings.pluginSlots, function(a,b) return (a.PluginName < b.PluginName) end );

        -- save the settings
        Turbine.PluginData.Save( Turbine.DataScope.Character, "CustomPluginsManagerSettings", self.settings );
end

-- --------------------------------------------------------------
-- --------------------------------------------------------------
-- Callbacks
--
-- callbacks are received from the PluginSlotContainers.  whenever
-- a PluginSlot changes state such that the CustomPluginsManager
-- should do something (load, unload, mark as favorite, etc.) a
-- callback is generated.
-- --------------------------------------------------------------
-- --------------------------------------------------------------

-- --------------------------------------------------------------
-- LoadPlugin
--
-- Description: load the input plugin.
--
-- Params:
-- pluginSlotContainer - PluginSlotContainer - the plugin slot to be loaded
-- bLoad - boolean - the flag indicating the plugin should be unloaded or loaded
-- --------------------------------------------------------------
function CustomPluginsManager:LoadPlugin( pluginSlotContainer, bLoad )
  local pluginSlot = self.settings.pluginSlots[ pluginSlotContainer.pluginSlot.PluginName ];
  if( pluginSlot ) then
    -- have the plugin manager load the plugin
    Turbine.PluginManager.LoadPlugin( pluginSlotContainer.pluginSlot.PluginName );
    
    -- update the "loaded" value
    self.settings.pluginSlots[ pluginSlotContainer.pluginSlot.PluginName ].PluginLoaded = bLoad;
    pluginSlotContainer.pluginSlot.PluginLoaded = bLoad;
    
    -- refresh the overlays (loaded / favorites)
    pluginSlotContainer:RefreshOverlays();
    self:SaveSettings();
  end
end

-- --------------------------------------------------------------
-- SetFavorite
--
-- Description: set the plugin as a favorite: a favorite plugin will
-- be loaded on startup.
--
-- Params:
-- pluginSlotContainer - PluginSlotContainer - the plugin slot to be marked
-- bLoad - boolean - the flag indicating how the plugin should be maked
-- --------------------------------------------------------------
function CustomPluginsManager:SetFavorite( pluginSlotContainer, bFavorite )
  local pluginSlot = self.settings.pluginSlots[ pluginSlotContainer.pluginSlot.PluginName ];
  if( pluginSlot ) then
    -- update the "loaded" value
    self.settings.pluginSlots[ pluginSlotContainer.pluginSlot.PluginName ].PluginFavorite = bFavorite;
    pluginSlotContainer.pluginSlot.PluginFavorite = bFavorite;
    
    -- refresh the overlays (loaded / favorites)
    pluginSlotContainer:RefreshOverlays();
    self:SaveSettings();
  end
end

-- --------------------------------------------------------------
-- RefreshAllPlugins
--
-- Description: refresh all plugins and update the display if necessary.
-- --------------------------------------------------------------
function CustomPluginsManager:RefreshAllPlugins()
  -- the first thing we do is look for all the valid plugins.  we've
  -- already got a function to do that!
  self:FindAndValidatePlugins();
  
  -- iterate the known, loaded plugins and mark anything as loaded
  local pluginSlots = Turbine.PluginManager.GetLoadedPlugins();
  for key, value in pairs( pluginSlots ) do
    -- we are not going to track the CustomPluginsManager, since that is US!
    if( value.Name ~= "CPM" ) then
      -- we are assuming that a loaded plugin is also an available plugin.
      -- otherwise, this is going to error
      self.settings.pluginSlots[ value.Name ].PluginLoaded = true;
    end
  end
  
  -- rebuild the plugin slots based on the state of the manager -
  -- on initialization, this shows the loaded plugins
  self:RebuildPluginSlots();
end

-- --------------------------------------------------------------
-- SetIcon
--
-- Description: display the icon editing window, then update the
-- icon field in the plugin
-- --------------------------------------------------------------
function CustomPluginsManager:SetIcon( pluginSlotContainer )
  local pluginSlot = self.settings.pluginSlots[ pluginSlotContainer.pluginSlot.PluginName ];
  if( pluginSlot ) then
    -- create a temporary window to allow the user to enter the plugin icon name
    self.IconEntryWindow:Initialize( pluginSlot, self );
  end
end

-- --------------------------------------------------------------
-- UpdateIcon
--
-- Description: a callback from the icon editing window.  update
-- the named plugin with a new icon.
-- --------------------------------------------------------------
function CustomPluginsManager:UpdateIcon( pluginName, pluginIcon )

  local pluginSlot = self.settings.pluginSlots[ pluginName ];
  if( pluginSlot ) then
    self.settings.pluginSlots[ pluginName ].PluginIcon = pluginIcon;
  
    -- save the settings and rebuild the plugin slots
    self:SaveSettings();
    self:RebuildPluginSlots();
  end
  
  self.IconEntryWindow:Shutdown();
end

Compare with Previous | Blame


All times are GMT -5. The time now is 04:25 PM.


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