Game Development Community

Torque: Gui Updates - Beta 1

by Phillip O'Shea · 10/25/2008 (10:56 pm) · 12 comments

Check out my last blog if you haven't already: Torque: Gui Updates.

I finally found some time to clean this work up and apply it to TGEA 1.7.1. I am going to release what I have done now as "beta 1" and I intend to add some of the other features in future beta releases based on feedback. The context menu is a nice idea but in practice it is a bit tricky (right click rotates the camera).

The build that you will find below is basically the TGEA 1.7.1 editor, reskinned with very little added to it. I would like to get this build stable and working properly before I release any of the other features.

Here is the download link to the latest build: Download!.

All you need to do is replace the current missionEditor folder (located in tools/missionEditor) with the one found in the zip.

There are a few mods that need to be made to the source to get things working properly:

//-----------------------------------------------------------------------
// guiTabBookCtrl.h
//-----------------------------------------------------------------------
 
// Add at the bottom of the class
void removePage(GuiTabPageCtrl* child);
 
//-----------------------------------------------------------------------
// guiTabBookCtrl.cpp
//-----------------------------------------------------------------------
 
// Add at the bottom
void GuiTabBookCtrl::removePage(GuiTabPageCtrl* child)
{
   for (S32 i = 0; i < mPages.size(); i++ )
   {
      GuiTabPageCtrl* tab = mPages[i].Page;
      if( tab == child )
      {
         if( tab == mActivePage )
            mActivePage = NULL;
         mPages.erase( i );
         break;
      }
   }

   // Recalculate Page Information
   calculatePageTabs();

   if( mPages.empty() )
      mActivePage = NULL;
   else if (mActivePage == NULL )
   {
      mActivePage = static_cast<GuiTabPageCtrl*>(mPages[0].Page);
      mActivePage->setVisible( true );
   }
}

ConsoleMethod( GuiTabBookCtrl, removePage, void, 3, 3, "(obj pageId)")
{
    GuiTabPageCtrl* page = dynamic_cast<GuiTabPageCtrl*>(Sim::findObject(argv[2]));
    if (page)
    {
        // Clear the page
        object->removePage(page);
    }
}
 
//-----------------------------------------------------------------------
// guiIconButtonCtrl.cpp
//-----------------------------------------------------------------------
 
// Add at the top
#include "util/stringUnit.h"
 
// Replace function
void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect )
{
   bool highlight = mMouseOver;
   // PO: Unused
   // bool depressed = mDepressed;

   ColorI fontColor   = mActive ? (highlight ? mProfile->mFontColor : mProfile->mFontColor) : mProfile->mFontColorNA;
   ColorI backColor   = mActive ? mProfile->mFillColor : mProfile->mFillColorNA; 
   ColorI borderColor = mActive ? mProfile->mBorderColor : mProfile->mBorderColorNA;

   RectI boundsRect(offset, getExtent());

   if (mDepressed || mStateOn)
   {
      // If there is a bitmap array then render using it.  Otherwise use a standard
      // fill.
      if(mProfile->mUseBitmapArray && mProfile->mBitmapArrayRects.size())
         renderBitmapArray(boundsRect, statePressed);
      else
         renderSlightlyLoweredBox(boundsRect, mProfile);
   }
   else if(mMouseOver && mActive)
   {
      // If there is a bitmap array then render using it.  Otherwise use a standard
      // fill.
      if(mProfile->mUseBitmapArray && mProfile->mBitmapArrayRects.size())
         renderBitmapArray(boundsRect, stateMouseOver);
      else
         renderSlightlyRaisedBox(boundsRect, mProfile);
   }
   else
   {
      // If there is a bitmap array then render using it.  Otherwise use a standard
      // fill.
      if(mProfile->mUseBitmapArray && mProfile->mBitmapArrayRects.size())
      {
         if(mActive)
            renderBitmapArray(boundsRect, stateNormal);
         else
            renderBitmapArray(boundsRect, stateDisabled);
      }
      else
      {
         GFX->getDrawUtil()->drawRectFill(boundsRect, mProfile->mFillColorNA);
         GFX->getDrawUtil()->drawRect(boundsRect, mProfile->mBorderColorNA);
      }
   }

   // PO
   if(mDepressed || mStateOn)
      offset += Point2I(1,1);

   // Render the icon
   if ( mTextureNormal && mIconLocation != GuiIconButtonCtrl::IconLocNone )
   {
      // Render the normal bitmap
      GFX->getDrawUtil()->clearBitmapModulation();

      // Maintain the bitmap size or fill the button?
      if(!mFitBitmapToButton)
      {
         RectI iconRect(offset + mButtonMargin, Point2I(mTextureNormal->getWidth(), mTextureNormal->getHeight()));
         Point2I textureSize( mTextureNormal->getWidth(), mTextureNormal->getHeight() );

         if( mIconLocation == IconLocRight )         
            iconRect.set( offset + getExtent() - ( mButtonMargin + textureSize ), textureSize  );
         else if( mIconLocation == IconLocLeft )
            iconRect.set(offset + mButtonMargin, textureSize );

         GFX->getDrawUtil()->drawBitmapStretch(mTextureNormal, iconRect);

      } 
      else
      {
         RectI rect(offset + mButtonMargin, getExtent() - (mButtonMargin * 2) );
         GFX->getDrawUtil()->drawBitmapStretch(mTextureNormal, rect);
      }

   }

   // Render text
   if(mTextLocation != TextLocNone)
   {
      GFX->getDrawUtil()->setBitmapModulation( fontColor );
      S32 textWidth = mProfile->mFont->getStrWidth(mButtonText);

      // PO: Get the number of columns in the text
      S32 colcount = StringUnit::getUnitCount(mButtonText, "\t");

      if(mTextLocation == TextLocRight)
      {

         Point2I start( mTextMargin, (getHeight()-mProfile->mFont->getHeight())/2 );
         if( mTextureNormal && mIconLocation != GuiIconButtonCtrl::IconLocNone )
         {
            start.x = mTextureNormal->getWidth() + mButtonMargin.x + mTextMargin;
         }

         // PO: Right hand justify the 2nd colum
         if (colcount >= 2)
         {
            // Draw the first column
            GFX->getDrawUtil()->drawText(mProfile->mFont, start + offset, StringUnit::getUnit(mButtonText, 0, "\t"));

            // Draw the second column
            const char *buff = StringUnit::getUnit(mButtonText, 1, "\t");
            Point2I textpos(getExtent().x - mProfile->mFont->getStrWidth(buff) - mTextMargin, start.y);
            GFX->getDrawUtil()->drawText(mProfile->mFont, textpos + offset, buff);
         }
         else
         {
            GFX->getDrawUtil()->drawText(mProfile->mFont, start + offset, mButtonText);
         }
      }

      if(mTextLocation == TextLocCenter)
      {
         Point2I start;
         if( mTextureNormal && mIconLocation != GuiIconButtonCtrl::IconLocNone )
         {
            start.set( ( (getWidth() - textWidth - mTextureNormal->getWidth() )/2) + mTextureNormal->getWidth(), (getHeight()-mProfile->mFont->getHeight())/2 );
         }
         else
            start.set( (getWidth() - textWidth)/2, (getHeight()-mProfile->mFont->getHeight())/2 );
         GFX->getDrawUtil()->setBitmapModulation( fontColor );
         GFX->getDrawUtil()->drawText( mProfile->mFont, start + offset, mButtonText, mProfile->mFontColors );
      }
   }

   renderChildControls( offset, updateRect);
}
 
//-----------------------------------------------------------------------
// guiTypes.cpp
//-----------------------------------------------------------------------
 
// Add at the bottom
ConsoleMethod(GuiControlProfile, getStringWidth, S32, 3, 3, "(int stringWidth) Returns the width of a string with this profile's settings.\n"
                                                                    "@param string")
{
    // Get Position.
    S32 strWidth = -1;
    Resource<GFont> pFont = GFont::create(object->mFontType, object->mFontSize, object->sFontCacheDirectory, object->mFontCharset);
    if (pFont)
        strWidth = pFont->getStrWidth(argv[2]);

    return strWidth;
}

The icons are pretty crappy at the moment so if you have some nice ones, or find some on the net that would be suited to some of the un-iconed buttons, please let me know at: pdos00 at gmail dot com.

About the author

Head of Violent Tulip, a small independent software development company working in Wollongong, Australia. Go to http://www.violent-tulip.com/ to see our latest offerings.


#1
10/26/2008 (1:40 am)
Sweeettttt.......
#2
10/26/2008 (3:16 am)
Nice! ... iv been waiting for an update on your project since your last post 5 months ago
#3
10/26/2008 (7:43 am)
This works a treat. I love the layout.
I have found one problem.
See the image below.

3dcentral.net/myPic/torque/newGui1.png
The popup boxes are too narrow and text gets cut off. This is happening in a couple of the popups.

edited for correct image and spelling
Edit 2: found some other problems.

I can add static shapes, but not interiors. Even torques own.
Here are the messages in console.log:
tools/missionEditor/scripts/ToolBar.ed.cs (561): Unknown command getStringWidth.
  Object levelEditorToolbarDropDownMenuItem(1613) levelEditorToolbarDropDownMenuItem -> GuiControlProfile -> SimObject
  
Mapping string: ToggleCamera to index: 3
Warning! You have a duplicate datablock name of TerrainPainterContainer. This can cause problems. You should rename one of them.
Warning! You have a duplicate datablock name of TerrainEditorContainer. This can cause problems. You should rename one of them.
General\tTab_general\tgeneral_min_height\t50\tgeneral_scale\t300\tgeneral_water\t0.000\tgeneral_centerx\t0\tgeneral_centery\t0
Tab data: General^Tab_general^general_min_height^50^general_scale^300^general_water^0.000^general_centerx^0^general_centery^0 tab: Tab_general
Heightfield::eval:0  General
Heightfield::eval:0  General
Heightfield::eval:0  General
Tried to get the object for item 13, which is not InspectorData!
Adding the torque cottage yeilds this error and crashes torque.
#4
10/26/2008 (2:50 pm)
Mike, it looks as if you didn't implement the final source change: implementing the method "getStringWidth". The other issue, the inability to add interiors, I will have to look into.

Thanks!
#5
10/26/2008 (4:03 pm)
In guiTypes.cc? Yup. I did include it. I went back and double checked all the code changes needed, and they are all there.
I'm using a copy of tgea 1.7.1 to make these modifications.
#6
10/26/2008 (6:32 pm)
It may sound a little bit silly, but are you sure that you're using the exe that you compiled? It doesn't make sense that the console function added cannot be called from script.

If not, is there any other information you can give me? How many times is it spammed in the console, etc?
#7
10/26/2008 (7:15 pm)
There isn't a guiTypes.cc in TGEA 1.7.1, only a guiTypes.cpp :p So, if you put in a .cc file, then time to fix it!
#8
10/26/2008 (7:25 pm)
Now I'm embarrased.
Ok, this is what I did.

Added code fixes.
overwrote the editor folder with the new files. (used /projects/lost/ as a test world)
compiled using the "compileAll" bat file in the lost folder.

It didn't work. If I go and take the exe from t2d demo, it works. What you see in the screenshot is working like it should as well. Interiors still give me an error about missing tverts (or something like that) and crashes torque.
Here is my console.log file

@ Jeramia, the .cc was a goof. It is actually .cpp
#9
10/27/2008 (6:24 am)
Well I implemented the tool and first glance .... it works great ... one problem though.
When I press F11 again to go back in to "the game", and then re-enters the editor, the tabs are gone ... and the sections are all scrambles on top of each other.

www.snowpeak.se/files/bug2.png

No errors in the console.
reloading the mission temporarly fixes the bug.
and the bug is repeatable.
#10
10/27/2008 (6:32 pm)
Does this work with torque game engine 1.5.2?
#11
10/28/2008 (6:52 am)
Phillip, incredible work! Sadly I dont have all the time I would wish, I'll do my best in helping with the Betatesting.

I would suggest to open a forum thread for the beta testing, and link the thread from here...
#12
02/07/2009 (8:19 pm)
Since Torque 3D is coming out are you still pushing this update for TGEA? Are they using your concept for the T3D instead of TGEA?