Skip to content

Complex UI (part 2)

alerdenisov edited this page Jan 20, 2017 · 3 revisions

How to make complex UI with ReUI (part 2)

After part one we have nice looking item slots, but do you remember about not repeat yourself? What are you thinking about five lines of <ItemSlot />? I found it not great and think we're ready to use <Loop /> tag to itterate collection of items.

Collection of ItemSlots

To show any amount of item slots with some data let's make another custom component <ItemShelf /> where magic will live. Starts from skeleton of component:

<?xml version="1.0" encoding="utf-8" ?>
<Root Name="Shelf">
  <OnProps>
    -- state setup code here
  </OnProps>

  <Loop Component="ItemSlot">
    <Collection>
      -- return collection of data to itterate
      return {}
    </Collection>
    <Itteration>
      -- invokes for each item in collection
      return {}
    </Itteration>
  </Loop>
</Root> 

Here is few unknown tags: <Loop />, <Collection /> and <Itteration />. Let's look at them:

  • Loop says to ReUI about starts itteration section of element passed by Component attribute (ItemSlot in our case)
  • Collection says to ReUI about take from it lua code to obtain proper collection of data (we will set up it later)
  • Itteration is a function what will be invoked with two arguments: item (instance of current ItemSlot) and index (id key of collection). It will invoke N-times equal length of collection.

Imagine we're already passed as a props to ItemShelf some data and ready to set up state:

<Root Name="Shelf">
  <OnProps>
    -- set items collection to state 
    state.items = props.items or {}
  </OnProps>
  
  <Loop Component="ItemSlot">
    <Collection>
      return state.items
    </Collection>
    <Itteration>
      item:setAnchor('TopCenter')
      item:setPivot('TopRight')
      item:setPosition(0, -48 * (index - 1))
      item:setSize(42, 42)

      return state.items[index]
    </Itteration>
  </Loop>
</Root>

It's not ready, but it should work. Here is huge room of imrovements, but we will test it right now. Go to InGame.xml and call it with some collection:

<?xml version="1.0" encoding="utf-8" ?>
<Root Name="In Game UI">
  <ItemShelf Anchor="TopRight" 
             Position="-9,-53"
             Name="Armory Shelf">
    return {
      items = {
        { 
          name = "Plate helm", 
          icon = "icons/upg_helmet", 
          properties = { 
            { key = 'Exceptional', color = '#FFFF00' }
          }
        },
        { }, -- no pauldron item
        { 
          name = "Plate chest", 
          icon = "icons/armor", 
          properties = { 
            { key = 'Block Chance', value = '10%' }
          } 
        },
        { }, -- no legs item
        { }  -- no boots item
      }
    }
  </ItemShelf>
</Root> 

Yay! It's work as expected. But what about reusability? How about more that one col or row? This is improvments what I told about.

Here is not a lua tutorial

As a topic says.. I will just write simple grid code and show result. Anyway if you're not familiar with Lua and want to use ReUI, you should spend 15 minutes to understand Lua: Take a quick course made by Tyler Neylon.

<?xml version="1.0" encoding="utf-8" ?>
<Root Name="Shelf">
  <OnProps>
    -- set items collection to state 
    state.items = props.items or {}
    
    state.cols = props.cols or 5
    state.rows = props.rows or 5
    state.size = tonumber(props.size) or 42
    state.offset = tonumber(props.offset) or 6

    state.pivot = props.pivot or 'MiddleCenter'
    state.anchor = props.anchor or 'TopLeft'
  </OnProps>

  <Loop Component="ItemSlot">
    <Collection>
      -- ugly range function... :D
      
      local max = state.rows * state.cols
      log(max)
      local collection = {}
      for i = 1, max, 1 do
        collection[i] = i
      end
      
      return collection
    </Collection>
    <Itteration>
      local s = state.size
      local o = state.offset
      local c = state.cols
      local r = state.rows

      -- substract one because lua index start from 1 (have no idea why..)
      local i = index - 1

      local ir = math.floor(i / c)
      local ic = i - (ir * c)
      local is = s + o
      
      local x = is * ic
      local y = is * -ir


      item:setAnchor(state.anchor)
      item:setPivot(state.pivot)
      item:setPosition(x, y)
      item:setSize(s, s)

      return state.items[index] or {}
    </Itteration>
  </Loop>
</Root> 

Example of usage and final result

  <ItemShelf Anchor="TopLeft" 
             Position="9,-53"
             Name="Bag Shelf">
    return {
      cols = 3,
      rows = 2,
      size = 42,
      offset = 6,
      pivot = 'TopLeft';
      
      items = {
        -- items collection
      }
    }
  </ItemShelf>

There we go! Very useful shelf (as paperdoll and bags!). Next is pointer events
Clone this wiki locally