Creation/Dev/Creating Tabbed Window Panes

From Graal Bible

Tutorial

The GuiTabCtrl class only handles the tabs themselves. It does not provide functionality for automatically switching between panes of GuiControls.

This tutorial should hopefully give you some basic ability to use the GuiTabCtrl for this sort of functionality.

Let's set up a basic example of GuiTabCtrl:

//#CLIENTSIDE
function onCreated()
{
  ExampleWindow = new GuiWindowCtrl("ExampleWindow");

  with (ExampleWindow)
  {
    profile     = "GuiBlueWindowProfile";
    position    = "20 20";
    extent      = "320 240";
    canMove     = true;
    canResize   = false;
    canMaximize = false;
    canClose    = true;
    tile        = true;
    text        = "Tabbed Window Pane Demo";
    
    new GuiTabCtrl(ExampleTabs)
    {
      profile   = "GuiBlueTabProfile";
      position  = "10 28";
      extent    = "300 24";
      
      clearRows();
      addRow(0, "Apple");
      addRow(1, "Banana");
      addRow(2, "Cranberry");
    };
  };
  GraalControl.addControl(ExampleWindow);
}

As you can see, we now have a window named ExampleWindow with a child GuiObject named ExampleTabs. In the initialization of ExampleTabs we add several tabs.

You should also have noted that we do not have any sort of ability to hold child objects underneath specific tabs and show/hide them when we change tab. As said earlier this functionality is not provided by GuiTabCtrl.

From the documentation we know that the name for the event when a user changes the tab is onSelect.

So lets expand our demo a little.

To easily capture an event we can add:

thiso.catchevent(name, "onSelect", "onTabSelect");

Inside of the initialization of ExampleTabs to start capturing events.

We'll of course need a function now, so let's do a simple one.

function onTabSelect(tabs)
{
  echo(tabs.selected.name @ " has been selected!");
}

In the console when a tab is selected you should see something like GuiTabCtrlEntry has been selected!. Notice that each tab is actually a GuiTabCtrlEntry object.

We can use these objects to store extra information to our advantage.

So let's make some window panes for our tabs. We will use a GuiControl as our container because it is just an object... it can have children, but it doesn't really do anything otherwise. We'll also include a GuiTextCtrl to make it more visible.

Remember, these objects should be inside of ExampleWindow object before the ExampleTabs object (code wise). We also want to make them invisible.

new GuiControl(AppleTab)
{
  visible    = false;
  profile    = "GuiBlueControlProfile";
  position   = "10 52";
  extent     = "222 184";
  
  new GuiTextCtrl(AppleTab_Label)
  {
    profile  = "GuiBlueTextProfile";
    position = "0 0";
    extent   = "222 20";
    text     = "An apple.";
  };
};

new GuiControl(BananaTab)
{
  visible    = false;
  profile    = "GuiBlueControlProfile";
  position   = "10 52";
  extent     = "222 184";
  
  new GuiTextCtrl(BananaTab_Label)
  {
    profile  = "GuiBlueTextProfile";
    position = "0 0";
    extent   = "222 20";
    text     = "A banana.";
  };
};

new GuiControl(CranberryTab)
{
  visible    = false;
  profile    = "GuiBlueControlProfile";
  position   = "10 52";
  extent     = "222 184";
  
  new GuiTextCtrl(CranberryTab_Label)
  {
    profile  = "GuiBlueTextProfile";
    position = "0 0";
    extent   = "222 20";
    text     = "A cranberry.";
  };
};

Now, since we have our window panes, we can set up our tab objects.

Remember we had the following code:

addRow(0, "Apple");
addRow(1, "Banana");
addRow(2, "Cranberry");

We'll need to add some additional information so that we know what window pane belongs to which tab, so we'll do the following:

with (addRow(0, "Apple"))
{
  this.pane = AppleTab;
}

with (addRow(1, "Banana"))
{
  this.pane = BananaTab;
}

with (addRow(2, "Cranberry"))
{
  this.pane = CranberryTab;
}

Now the tab objects know which window pane is associated with them.

Remember our onSelect event? We'll need to modify it now to make the window panes visible depending on which tab has been switched to. We will iterate through the array of tabs and check if the current one is the selected one, if it is, show the window pane, if it is not, hide it.

We also check to see if the tab has a window pane at all, so we don't get errors like GraalScript: Function hide not found in script of Weapon ExampleTabs if the tab does not have a window pane.

function onTabSelect(tabs)
{
  for (temp.tab: tabs.rows)
  {
    if (temp.tab.pane == null)
    {
      continue;
    }
    
    if (temp.tab == temp.tabs.selected)
    {
      temp.tab.pane.show();
    }
    else
    {
      temp.tab.pane.hide();
    }
  }
}

Since we want to be able to expand our tabs (and window panes) further, we make our selection event handling code easy to adapt to new (or removed) tabs.

Now, if you have not yet noticed, note that no window pane is visible on the initial window creation. An easy fix for this is to trigger a selection event to occur.

Do this (preferably) after the creation of the ExampleWindow.

ExampleTabs.setSelectedById(0);


Final Code

//#CLIENTSIDE
function onCreated()
{
  ExampleWindow = new GuiWindowCtrl("ExampleWindow");
  
  with (ExampleWindow)
  {
    profile     = "GuiBlueWindowProfile";
    position    = "20 20";
    extent      = "320 240";
    canMove     = true;
    canResize   = false;
    canMaximize = false;
    canClose    = true;
    tile        = true;
    text        = "Tabbed Window Pane Demo";
    
    new GuiControl(AppleTab)
    {
      visible    = false;
      profile    = "GuiBlueControlProfile";
      position   = "10 52";
      extent     = "222 184";
      
      new GuiTextCtrl(AppleTab_Label)
      {
        profile  = "GuiBlueTextProfile";
        position = "0 0";
        extent   = "222 20";
        text     = "An apple.";
      };
    };
    
    new GuiControl(BananaTab)
    {
      visible    = false;
      profile    = "GuiBlueControlProfile";
      position   = "10 52";
      extent     = "222 184";
      
      new GuiTextCtrl(BananaTab_Label)
      {
        profile  = "GuiBlueTextProfile";
        position = "0 0";
        extent   = "222 20";
        text     = "A banana.";
      };
    };
    
    new GuiControl(CranberryTab)
    {
      visible    = false;
      profile    = "GuiBlueControlProfile";
      position   = "10 52";
      extent     = "222 184";
      
      new GuiTextCtrl(CranberryTab_Label)
      {
        profile  = "GuiBlueTextProfile";
        position = "0 0";
        extent   = "222 20";
        text     = "A cranberry.";
      };
    };
    
    new GuiTabCtrl(ExampleTabs)
    {
      profile   = "GuiBlueTabProfile";
      position  = "10 28";
      extent    = "300 24";
      
      clearRows();
      with (addRow(0, "Apple"))
      {
        this.pane = AppleTab;
      }
      with (addRow(1, "Banana"))
      {
        this.pane = BananaTab;
      }
      with (addRow(2, "Cranberry"))
      {
        this.pane = CranberryTab;
      }
      
      thiso.catchevent(name, "onSelect", "onTabSelect");
    };
  };
  ExampleTabs.setSelectedById(0);
  GraalControl.addControl(ExampleWindow);
}

function onTabSelect(tabs)
{
  for (temp.tab: temp.tabs.rows)
  {
    if (temp.tab.pane == null)
    {
      continue;
    }
    
    if (temp.tab == temp.tabs.selected)
    {
      temp.tab.pane.show();
    }
    else
    {
      temp.tab.pane.hide();
    }
  }
}