Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/WolfireGames/overgrowth.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Source/GUI/IMUI/imgui.cpp')
-rw-r--r--Source/GUI/IMUI/imgui.cpp1190
1 files changed, 1190 insertions, 0 deletions
diff --git a/Source/GUI/IMUI/imgui.cpp b/Source/GUI/IMUI/imgui.cpp
new file mode 100644
index 00000000..fc3d25e8
--- /dev/null
+++ b/Source/GUI/IMUI/imgui.cpp
@@ -0,0 +1,1190 @@
+//-----------------------------------------------------------------------------
+// Name: imgui.cpp
+// Developer: Wolfire Games LLC
+// Description: Main class for creating adhoc GUIs as part of the UI tools
+// License: Read below
+//-----------------------------------------------------------------------------
+//
+//
+// Copyright 2022 Wolfire Games LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-----------------------------------------------------------------------------
+#include "imgui.h"
+
+#include <Internal/timer.h>
+
+#include <Graphics/hudimage.h>
+
+#include <map>
+#include <vector>
+#include <string>
+
+/*******************************************************************************************/
+/**
+ * @brief Constructor
+ *
+ * @param mainOrientation The orientation of the container
+ *
+ */
+int guicount = 0;
+
+IMGUI::IMGUI() :
+ elementCount(1),
+ header(),
+ footer(),
+ main(),
+ mainOffset(0.0),
+ footerOffset(0.0),
+ headerHeight(0.0),
+ footerHeight(0.0),
+ mainHeight(0.0),
+ headerPanelGap(0.0),
+ footerPanelGap(0.0),
+ mainPanelGap(0.0),
+ pendingFGLayers(1),
+ pendingBGLayers(1),
+ pendingHeaderHeight(0.0f),
+ pendingFooterHeight(0.0f),
+ refCount(1)
+{
+
+ IMrefCountTracker.addRefCountObject( "IMGUI" );
+ guicount++;
+
+ guiid = guicount;
+
+ screenSize = screenMetrics.getMetrics();
+
+ lastUpdateTime = 0;
+
+ needsRelayout = false;
+ showGuides = false;
+
+ IMGUI_IMUIContext = new IMUIContext;
+ IMGUI_IMUIContext->Init();
+
+ imevents.RegisterListener(this);
+}
+/*
+IMGUI::IMGUI( IMGUI const& other ) {
+
+ IMrefCountTracker.addRefCountObject( "IMGUI" );
+
+ lastUpdateTime = other.lastUpdateTime;
+ elementCount = other.elementCount;
+ needsRelayout = other.needsRelayout;
+ reportedErrors = other.reportedErrors;
+ showGuides = other.showGuides;
+ mousePosition = other.mousePosition;
+ leftMouseState = other.leftMouseState;
+ messageQueue = other.messageQueue;
+ backgrounds = other.backgrounds;
+ foregrounds = other.foregrounds;
+ header = other.header;
+ footer = other.footer;
+ main = other.main;
+ mainOffset = other.mainOffset;
+ footerOffset = other.footerOffset;
+ headerHeight = other.headerHeight;
+ footerHeight = other.footerHeight;
+ mainHeight = other.mainHeight;
+ headerPanelWidths = other.headerPanelWidths;
+ footerPanelWidths = other.footerPanelWidths;
+ mainPanelWidths = other.mainPanelWidths;
+ headerPanelGap = other.headerPanelGap;
+ footerPanelGap = other.footerPanelGap;
+ mainPanelGap = other.mainPanelGap;
+ pendingFGLayers = other.pendingFGLayers;
+ pendingBGLayers = other.pendingBGLayers;
+ pendingHeaderHeight = other.pendingHeaderHeight;
+ pendingFooterHeight = other.pendingFooterHeight;
+ pendingHeaderPanels = other.pendingHeaderPanels;
+ pendingMainPanels = other.pendingMainPanels;
+ pendingFooterPanels = other.pendingFooterPanels;
+ screenSize = other.screenSize;
+ refCount = other.refCount;
+
+ IMGUI_IMUIContext = new IMUIContext;
+ IMGUI_IMUIContext->Init();
+
+ imevents.RegisterListener(this);
+}
+*/
+
+void IMGUI::AddRef()
+{
+ // Increase the reference counter
+ refCount++;
+}
+
+void IMGUI::Release()
+{
+ // Decrease ref count and delete if it reaches 0
+ if( --refCount == 0 ) {
+ delete this;
+ }
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Set the number and initializes the background layers
+ *
+ * NOTE: This will destroy any existing layers
+ *
+ * Background layers are rendered highest index value first
+ *
+ * @param numLayers number of layers required
+ *
+ */
+void IMGUI::setBackgroundLayers( unsigned int numLayers ) {
+ pendingBGLayers = numLayers;
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Set the number and initializes the background layers
+ *
+ * NOTE: This will destroy any existing layers
+ *
+ * Background layers are rendered highest index value first
+ *
+ * @param numLayers number of layers required
+ *
+ */
+void IMGUI::setForegroundLayers( unsigned int numLayers ) {
+ pendingFGLayers = numLayers;
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Set the size of the header (0 for none)
+ *
+ * NOTE: This will take effect when setup is called next
+ *
+ * @param _headerSize size in GUI space
+ *
+ */
+void IMGUI::setHeaderHeight( float _headerSize ) {
+ pendingHeaderHeight = _headerSize;
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Set the size of the footer (0 for none)
+ *
+ * NOTE: This will take effect when setup is called next
+ *
+ * @param _footerSize size in GUI space
+ *
+ */
+void IMGUI::setFooterHeight( float _footerSize ) {
+ pendingFooterHeight = _footerSize;
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Sets the sizes of the various header panels
+ *
+ * If not specified (specified means non-zero) there will be one panel, full width
+ * If one is specified, it will be centered
+ * If two are specified, they will be left and right justified
+ * Three will be left, center, right justified
+ *
+ */
+void IMGUI::setHeaderPanels( float first, float second, float third ) {
+
+ if( first > 0.0 ) {
+ pendingHeaderPanels.push_back( first );
+ }
+
+ if( second > 0.0 ) {
+ pendingHeaderPanels.push_back( second );
+ }
+
+ if( third > 0.0 ) {
+ pendingHeaderPanels.push_back( third );
+ }
+
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Sets the sizes of the various main panels
+ *
+ * If not specified (specified means non-zero) there will be one panel, full width
+ * If one is specified, it will be centered
+ * If two are specified, they will be left and right justified
+ * Three will be left, center, right justified
+ *
+ */
+void IMGUI::setMainPanels( float first, float second, float third ) {
+
+ if( first > 0.0 ) {
+ pendingMainPanels.push_back( first );
+ }
+
+ if( second > 0.0 ) {
+ pendingMainPanels.push_back( second );
+ }
+
+ if( third > 0.0 ) {
+ pendingMainPanels.push_back( third );
+ }
+
+
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Sets the sizes of the various footer panels
+ *
+ * If not specified (specified means non-zero) there will be one panel, full width
+ * If one is specified, it will be centered
+ * If two are specified, they will be left and right justified
+ * Three will be left, center, right justified
+ *
+ */
+void IMGUI::setFooterPanels( float first, float second, float third ) {
+
+ if( first > 0.0 ) {
+ pendingFooterPanels.push_back( first );
+ }
+
+ if( second > 0.0 ) {
+ pendingFooterPanels.push_back( second );
+ }
+
+ if( third > 0.0 ) {
+ pendingFooterPanels.push_back( first );
+ }
+
+}
+
+
+/*******************************************************************************************/
+/**
+ * @brief Sets up main layer with header, footer and primary panel (clears any existing)
+ *
+ * @param _headerSize y size of the header (0 for none)
+ * @param _footerSize y size of the footer (0 for none)
+ *
+ */
+void IMGUI::setup() {
+
+ for( std::vector<IMContainer*>::iterator it = header.begin();
+ it != header.end();
+ ++it ) {
+
+ (*it)->Release();
+ }
+
+ for( std::vector<IMContainer*>::iterator it = footer.begin();
+ it != footer.end();
+ ++it ) {
+
+ (*it)->Release();
+ }
+
+ for( std::vector<IMContainer*>::iterator it = main.begin();
+ it != main.end();
+ ++it ) {
+
+ (*it)->Release();
+ }
+
+ header.clear();
+ footer.clear();
+ main.clear();
+
+ // Make sure we at least some values
+ if( pendingMainPanels.size() == 0 ) {
+ pendingMainPanels.push_back( screenMetrics.mainSize.x() );
+ }
+
+ if( pendingHeaderPanels.size() == 0 ) {
+ pendingHeaderPanels.push_back( screenMetrics.mainSize.x() );
+ }
+
+ if( pendingFooterPanels.size() == 0 ) {
+ pendingFooterPanels.push_back( screenMetrics.mainSize.x() );
+ }
+
+ // Sanity check
+ if( pendingHeaderHeight + pendingFooterHeight > screenMetrics.mainSize.y() ) {
+ IMDisplayError("GUI Error", "Header/footer too large");
+ }
+
+ const std::string numbering[] = { std::string("0"), std::string("1"), std::string("2") };
+
+ // Now build the panels
+ if( pendingHeaderHeight > 0 ) {
+ headerHeight = pendingHeaderHeight;
+
+ float totalWidth = 0;
+
+ // Go through the list of pending panels, create them and total their widths
+ int panelCount = 0;
+ for( std::vector<float>::iterator it = pendingHeaderPanels.begin();
+ it != pendingHeaderPanels.end();
+ ++it ) {
+
+ IMContainer* panel = new IMContainer( "header" + numbering[panelCount],
+ SizePolicy(*it),
+ SizePolicy(headerHeight) );
+ panel->setOwnerParent( this, NULL );
+ header.push_back( panel );
+
+ totalWidth += *it;
+
+ }
+
+ // Sanity check
+ if( totalWidth > screenMetrics.mainSize.x() ) {
+ IMDisplayError("GUI Error", "Header panels too wide");
+ }
+
+ // determine the gap size
+ if( header.size() == 1 || header.size() == 3 ) {
+ headerPanelGap = ( screenMetrics.mainSize.x() - totalWidth )/2;
+ }
+ else {
+ headerPanelGap = ( screenMetrics.mainSize.x() - totalWidth );
+ }
+
+ }
+
+ if( pendingFooterHeight > 0 ) {
+
+ footerHeight = pendingFooterHeight;
+
+ float totalWidth = 0;
+
+ // Go through the list of pending panels, create them and total their widths
+ int panelCount = 0;
+ for( std::vector<float>::iterator it = pendingFooterPanels.begin();
+ it != pendingFooterPanels.end();
+ ++it ) {
+
+ IMContainer* panel = new IMContainer( "footer" + numbering[panelCount],
+ SizePolicy(*it),
+ SizePolicy(footerHeight) );
+ panel->setOwnerParent( this, NULL );
+
+ footer.push_back( panel );
+
+ totalWidth += *it;
+
+ }
+
+ // Sanity check
+ if( totalWidth > screenMetrics.mainSize.x() ) {
+ IMDisplayError("GUI Error", "Footer panels too wide");
+ }
+
+ // determine the gap size
+ if( footer.size() == 1 || main.size() == 3 ) {
+ footerPanelGap = ( screenMetrics.mainSize.x() - totalWidth )/2;
+ }
+ else {
+ footerPanelGap = ( screenMetrics.mainSize.x() - totalWidth );
+ }
+
+ }
+
+ mainHeight = screenMetrics.mainSize.y() - (headerHeight + footerHeight);
+
+ {
+
+ float totalWidth = 0;
+
+ // Go through the list of pending panels, create them and total their widths
+ int panelCount = 0;
+ for( std::vector<float>::iterator it = pendingMainPanels.begin();
+ it != pendingMainPanels.end();
+ ++it ) {
+
+ IMContainer* panel = new IMContainer( "main" + numbering[panelCount],
+ SizePolicy(*it),
+ SizePolicy(mainHeight) );
+ panel->setOwnerParent( this, NULL );
+
+ main.push_back( panel );
+
+ totalWidth += *it;
+
+ }
+
+ // Sanity check
+ if( totalWidth > screenMetrics.mainSize.x() ) {
+ IMDisplayError("GUI Error", "Main panels too wide");
+ }
+
+ // determine the gap size for rendering
+ if( main.size() == 1 || main.size() == 3 ) {
+ mainPanelGap = ( screenMetrics.mainSize.x() - totalWidth )/2;
+ }
+ else {
+ mainPanelGap = ( screenMetrics.mainSize.x() - totalWidth );
+ }
+
+ }
+
+ // setup background layers
+ for( unsigned int i = 0; i < pendingFGLayers; ++i ) {
+ IMContainer* newContainer = new IMContainer( SizePolicy(screenMetrics.GUISpace.x()),
+ SizePolicy(screenMetrics.GUISpace.y()) );
+
+ newContainer->setOwnerParent( this, NULL );
+
+ foregrounds.push_back( newContainer );
+ }
+
+ for( unsigned int i = 0; i < pendingBGLayers; ++i ) {
+ IMContainer* newContainer = new IMContainer( SizePolicy(screenMetrics.GUISpace.x()),
+ SizePolicy(screenMetrics.GUISpace.y()) );
+
+ newContainer->setOwnerParent( this, NULL );
+
+ backgrounds.push_back( newContainer );
+ }
+
+ derivePanelOffsets();
+
+ doRelayout();
+
+ pendingFGLayers = 1;
+ pendingBGLayers = 1;
+ pendingHeaderHeight = 0.0f;
+ pendingFooterHeight = 0.0f;
+ pendingHeaderPanels.clear();
+ pendingFooterPanels.clear();
+ pendingMainPanels.clear();
+
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Figure out where we’re going to render the main panels - used internally
+ *
+ */
+void IMGUI::derivePanelOffsets() {
+
+ float headerEnd = -1;
+
+ if( header.size() != 0 ) {
+ headerEnd = headerHeight - 1;
+ }
+
+ footerOffset = screenMetrics.GUISpace.y();
+
+ if( footer.size() != 0 ) {
+ footerOffset = screenMetrics.GUISpace.y() - footerHeight;
+ }
+
+ if( main.size() != 0 ) {
+
+ // see if we have any space
+ if( headerHeight + footerHeight + mainHeight < screenMetrics.GUISpace.y() ) {
+ // first center the main panel
+ mainOffset = (screenMetrics.GUISpace.y()/2.0f) - (mainHeight/2.0f);
+
+ // now check if we're going over our bounds
+ if( mainOffset <= headerEnd ) {
+ mainOffset += (headerEnd - mainOffset) + 1;
+ }
+
+ float mainEnd = mainOffset + mainHeight -1;
+
+ if ( mainEnd >= footerOffset ) {
+ // we can do these two checks independently as we know there's enough room for all three
+ mainOffset -= ( mainEnd - footerOffset ) + 1;
+ }
+ }
+ else {
+ mainOffset = headerEnd + 1;
+ }
+ }
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Clear the GUI - you probably want resetMainLayer though
+ *
+ * @param mainOrientation The orientation of the container
+ *
+ */
+void IMGUI::clear() {
+
+ std::vector<IMContainer*> containerList;
+
+ containerList.insert(containerList.end(), backgrounds.begin(), backgrounds.end() );
+ containerList.insert(containerList.end(), foregrounds.begin(), foregrounds.end() );
+ containerList.insert(containerList.end(), header.begin(), header.end() );
+ containerList.insert(containerList.end(), footer.begin(), footer.end() );
+ containerList.insert(containerList.end(), main.begin(), main.end() );
+
+ backgrounds.clear();
+ foregrounds.clear();
+ header.clear();
+ footer.clear();
+ main.clear();
+
+ for( int i = int(containerList.size())-1; i >= 0; --i ) {
+ containerList[i]->Release();
+ }
+
+ for( int i = 0; i < int(messageQueue.size()); ++i ) {
+ messageQueue[i]->Release();
+ }
+ messageQueue.clear();
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Turns on (or off) the visual guides
+ *
+ * @param setting True to turn on guides, false otherwise
+ *
+ */
+void IMGUI::setGuides( bool setting ) {
+ showGuides = setting;
+}
+
+/*******************************************************************************************/
+/**
+ * @brief When this element is resized, moved, etc propagate this signal upwards
+ *
+ */
+void IMGUI::onRelayout() {
+
+ // Record this
+ needsRelayout = true;
+
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Records all the errors reported by child elements
+ *
+ * @param newError Newly reported error string
+ *
+ */
+void IMGUI::reportError( std::string const& newError ) {
+ reportedErrors += newError + "\n";
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Receives a message - used internally
+ *
+ * Remember to increase the message's ref count if used internally!
+ *
+ * @param message The message in question
+ *
+ */
+void IMGUI::receiveMessage( IMMessage* message ) {
+ IMMessage* messageCopy = new IMMessage( *message );
+ messageQueue.push_back( messageCopy );
+ message->Release();
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Gets the size of the waiting message queue
+ *
+ * @returns size of the queue (as an unsigned integer)
+ *
+ */
+unsigned int IMGUI::getMessageQueueSize() {
+ return (unsigned int)messageQueue.size();
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Gets the next available message in the queue (NULL if none)
+ *
+ * @returns A copy of the message (NULL if none)
+ *
+ */
+IMMessage* IMGUI::getNextMessage() {
+ // Again, I'm aware this isn't very efficient, but we're only dealing with at most
+ // a half dozen of these a frame
+ IMMessage* message = *messageQueue.begin();
+ messageQueue.erase( messageQueue.begin() );
+
+ return message;
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Retrieves a reference to a specified background layer
+ *
+ * @param layerNum index of the background layer (starting at 0)
+ *
+ */
+IMContainer* IMGUI::getBackgroundLayer( unsigned int layerNum ) {
+ if( layerNum >= backgrounds.size() ) {
+ IMDisplayError("GUI Error", "Unknown background layer ");
+ return NULL;
+ }
+ IMContainer* container = backgrounds[ layerNum ];
+ container->AddRef();
+ return container;
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Retrieves a reference to a specified foreground layer
+ *
+ * @param layerNum index of the foreground layer (starting at 0)
+ *
+ */
+IMContainer* IMGUI::getForegroundLayer( unsigned int layerNum ) {
+ if( layerNum >= foregrounds.size() ) {
+ IMDisplayError("GUI Error", "Unknown foreground layer ");
+ return NULL;
+ }
+
+ IMContainer* container = foregrounds[ layerNum ];
+ container->AddRef();
+ return container;
+
+}
+
+/*******************************************************************************************/
+/**
+ * @brief If a relayout is requested, perform it
+ *
+ */
+void IMGUI::doRelayout() {
+
+ int relayoutCount = 0;
+ while( needsRelayout ) {
+ relayoutCount++;
+
+ // clear the error string
+ reportedErrors = "";
+
+ needsRelayout = false;
+ for( int layer = int(backgrounds.size())-1; layer >= 0; --layer ) {
+ backgrounds[ layer ]->doRelayout();
+ }
+
+ for( std::vector<IMContainer*>::iterator it = header.begin();
+ it != header.end();
+ ++it ) {
+ (*it)->doRelayout();
+ }
+
+ for( std::vector<IMContainer*>::iterator it = footer.begin();
+ it != footer.end();
+ ++it ) {
+ (*it)->doRelayout();
+ }
+
+ for( std::vector<IMContainer*>::iterator it = main.begin();
+ it != main.end();
+ ++it ) {
+ (*it)->doRelayout();
+ }
+
+ for( unsigned int layer = 0; layer < foregrounds.size(); ++layer ) {
+ foregrounds[ layer ]->doRelayout();
+ }
+
+ // MJB Note: I'm aware that redoing the layout for the whole structure
+ // is rather inefficient, but given that this is targeted at most a few
+ // dozen elements, this should not be a problem -- can easily be optimized
+ // if so
+ }
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Updates the gui
+ *
+ */
+extern Timer ui_timer;
+void IMGUI::update() {
+
+ // Do relayout as necessary
+ doRelayout();
+
+ // If we haven't updated yet, set the time
+ if( lastUpdateTime == 0 ) {
+ lastUpdateTime = uint64_t( ui_timer.game_time * 1000 );
+ }
+
+ // Calculate the delta time
+ uint64_t delta = uint64_t( ui_timer.game_time * 1000 ) - lastUpdateTime;
+
+ // Update the time
+ lastUpdateTime = uint64_t( ui_timer.game_time * 1000 );
+
+ // Get the input from the engine
+ IMGUI_IMUIContext->UpdateControls();
+
+ vec2 engineMousePos = IMGUI_IMUIContext->getMousePosition();
+
+ // Translate to GUISpace
+ mousePosition.x() = (engineMousePos.x() - screenMetrics.renderOffset.x() ) / screenMetrics.GUItoScreenXScale;
+ mousePosition.y() = ( screenMetrics.getScreenHeight() - engineMousePos.y() + screenMetrics.renderOffset.y() ) / screenMetrics.GUItoScreenYScale;
+ leftMouseState = IMGUI_IMUIContext->getLeftMouseState();
+
+ // Fill in our GUI structure
+ guistate.mousePosition = mousePosition;
+ guistate.leftMouseState = leftMouseState;
+ guistate.inheritedMouseDown = false;
+ guistate.inheritedMouseOver = false;
+ guistate.clickHandled = false;
+
+ // Do relayout as necessary
+ doRelayout();
+
+ vec2 drawOffset(0,0);
+ // update the backgrounds
+ for( int layer = int(backgrounds.size())-1; layer >= 0; --layer ) {
+ backgrounds[ layer ]->update( delta, drawOffset, guistate );
+ }
+
+ if( header.size() == 1 ) {
+ drawOffset.x() = headerPanelGap;
+ header[0]->update( delta, drawOffset, guistate );
+ }
+ else if( header.size() == 2 ) {
+ header[0]->update( delta, drawOffset, guistate );
+ drawOffset.x() = header[0]->getSizeX() + headerPanelGap;
+ header[1]->update( delta, drawOffset, guistate );
+ }
+ else if( header.size() == 3 ) {
+ header[0]->update( delta, drawOffset, guistate );
+ drawOffset.x() = header[0]->getSizeX() + headerPanelGap;
+ header[1]->update( delta, drawOffset, guistate );
+ drawOffset.x() = header[1]->getSizeX() + headerPanelGap;
+ header[2]->update( delta, drawOffset, guistate );
+ }
+
+ drawOffset.x() = 0;
+ drawOffset.y() = mainOffset;
+ if( main.size() == 1 ) {
+ drawOffset.x() = mainPanelGap;
+ main[0]->update( delta, drawOffset, guistate );
+ }
+ else if( main.size() == 2 ) {
+ main[0]->update( delta, drawOffset, guistate );
+ drawOffset.x() = main[0]->getSizeX() + mainPanelGap;
+ main[1]->update( delta, drawOffset, guistate );
+ }
+ else if( main.size() == 3 ) {
+ main[0]->update( delta, drawOffset, guistate );
+ drawOffset.x() = main[0]->getSizeX() + mainPanelGap;
+ main[1]->update( delta, drawOffset, guistate );
+ drawOffset.x() = main[1]->getSizeX() + mainPanelGap;
+ main[2]->update( delta, drawOffset, guistate );
+ }
+
+ drawOffset.x() = 0;
+ drawOffset.y() = footerOffset;
+ if( footer.size() == 1 ) {
+ drawOffset.x() = footerPanelGap;
+ footer[0]->update( delta, drawOffset, guistate );
+ }
+ else if( footer.size() == 2 ) {
+ footer[0]->update( delta, drawOffset, guistate );
+ drawOffset.x() = footer[0]->getSizeX() + footerPanelGap;
+ footer[1]->update( delta, drawOffset, guistate );
+ }
+ else if( footer.size() == 3 ) {
+ footer[0]->update( delta, drawOffset, guistate );
+ drawOffset.x() = footer[0]->getSizeX() + footerPanelGap;
+ footer[1]->update( delta, drawOffset, guistate );
+ drawOffset.x() = footer[1]->getSizeX() + footerPanelGap;
+ footer[2]->update( delta, drawOffset, guistate );
+ }
+
+ drawOffset = vec2(0,0);
+ // update the backgrounds
+ for( int layer = int(foregrounds.size())-1; layer >= 0; --layer ) {
+ foregrounds[ layer ]->update( delta, drawOffset, guistate );
+ }
+
+ // See if this triggered any relayout events
+ doRelayout();
+
+ // If we've got here and still have an error, report it
+ if( reportedErrors != "" ) {
+ IMDisplayError("GUI Error", reportedErrors);
+ }
+
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Fired when the screen resizes
+ *
+ */
+void IMGUI::doScreenResize() {
+
+ screenMetrics.checkMetrics( screenSize );
+
+ // All the font sizes will likely have changed
+ IMGUI_IMUIContext->clearTextAtlases();
+
+ // Move our panels around (if necessary)
+ derivePanelOffsets();
+
+ // We need to inform the elements
+ for( int layer = int(backgrounds.size())-1; layer >= 0; --layer ) {
+ backgrounds[ layer ]->setSizePolicy( SizePolicy(screenMetrics.GUISpace.x()),
+ SizePolicy(screenMetrics.GUISpace.y()) );
+
+ backgrounds[ layer ]->setSize( vec2( screenMetrics.GUISpace.x(),
+ screenMetrics.GUISpace.y() ) );
+
+ backgrounds[ layer ]->doScreenResize();
+ }
+
+ for( std::vector<IMContainer*>::iterator it = header.begin();
+ it != header.end();
+ ++it ) {
+ (*it)->doScreenResize();
+ }
+
+ for( std::vector<IMContainer*>::iterator it = footer.begin();
+ it != footer.end();
+ ++it ) {
+ (*it)->doScreenResize();
+ }
+
+ for( std::vector<IMContainer*>::iterator it = main.begin();
+ it != main.end();
+ ++it ) {
+ (*it)->doScreenResize();
+ }
+
+ for( unsigned int layer = 0; layer < foregrounds.size(); ++layer ) {
+ // reset the size
+ foregrounds[ layer ]->setSizePolicy( SizePolicy(screenMetrics.GUISpace.x()),
+ SizePolicy(screenMetrics.GUISpace.y()) );
+
+
+ foregrounds[ layer ]->doScreenResize();
+ }
+
+ doRelayout();
+}
+
+
+/*******************************************************************************************/
+/**
+ * @brief Render the GUI
+ *
+ */
+void IMGUI::render() {
+
+ vec2 origin(0,0);
+ // render the backgrounds
+ for( int layer = int(backgrounds.size())-1; layer >= 0; --layer ) {
+ backgrounds[ layer ]->render( origin, origin, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ IMGUI_IMUIContext->render();
+ }
+
+ // render the main content
+ vec2 drawOffset(0,0);
+ if( header.size() == 1 ) {
+ drawOffset.x() = headerPanelGap;
+ header[0]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ }
+ else if( header.size() == 2 ) {
+ header[0]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ drawOffset.x() = header[0]->getSizeX() + headerPanelGap;
+ header[1]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ }
+ else if( header.size() == 3 ) {
+ header[0]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ drawOffset.x() = header[0]->getSizeX() + headerPanelGap;
+ header[1]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ drawOffset.x() = header[1]->getSizeX() + headerPanelGap;
+ header[2]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ }
+
+ drawOffset.x() = 0;
+ drawOffset.y() = mainOffset;
+
+ if( main.size() == 1 ) {
+ drawOffset.x() = mainPanelGap;
+ main[0]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ }
+ else if( main.size() == 2 ) {
+ main[0]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ drawOffset.x() = main[0]->getSizeX() + mainPanelGap;
+ main[1]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ }
+ else if( main.size() == 3 ) {
+ main[0]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ drawOffset.x() = main[0]->getSizeX() + mainPanelGap;
+ main[1]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ drawOffset.x() = main[1]->getSizeX() + mainPanelGap;
+ main[2]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ }
+
+ drawOffset.x() = 0;
+ drawOffset.y() = footerOffset;
+ if( footer.size() == 1 ) {
+ drawOffset.x() = footerPanelGap;
+ footer[0]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ }
+ else if( footer.size() == 2 ) {
+ footer[0]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ drawOffset.x() = footer[0]->getSizeX() + footerPanelGap;
+ footer[1]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ }
+ else if( footer.size() == 3 ) {
+ footer[0]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ drawOffset.x() = footer[0]->getSizeX() + footerPanelGap;
+ footer[1]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ drawOffset.x() = footer[1]->getSizeX() + footerPanelGap;
+ footer[2]->render( drawOffset, drawOffset, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ }
+
+ IMGUI_IMUIContext->render();
+
+ // render the foregrounds
+ for( unsigned int layer = 0; layer < foregrounds.size(); ++layer ) {
+ foregrounds[ layer ]->render( origin, origin, vec2( UNDEFINEDSIZE, UNDEFINEDSIZE ) );
+ IMGUI_IMUIContext->render();
+ }
+
+
+ // TODO
+// if( showGuides ) {
+//
+// for( int i = 2; i <= 16; i *= 2 ) {
+//
+// // draw the vertical lines
+// float increment = screenMetrics.getScreenWidth() / (float)i;
+// float xpos = increment;
+//
+// while( xpos < screenMetrics.getScreenWidth() ) {
+//
+// HUDImage* newimage = hud.AddImage();
+// newimage->SetImageFromPath("Data/Textures/ui/whiteblock.tga");
+//
+// vec2 imagepos( xpos-1, 0.0f );
+//
+// newimage->scale = 1;
+// newimage->scale.x *= 2;
+// newimage->scale.y *= screenMetrics.getScreenHeight();
+//
+// newimage->position.x = imagepos.x;
+// newimage->position.y() = screenMetrics.getScreenHeight() - imagepos.y() - (newimage.GetWidth() * newimage.scale.y() );
+// newimage->position.z() = -100.0;// 0.1f;
+//
+// newimage->color = vec4( 0.0, 0.2, 0.5 + (0.5/i), 0.25 );
+//
+// xpos += increment;
+// }
+//
+// increment = GetScreenHeight() / i;
+// int ypos = increment;
+//
+// while( ypos < GetScreenHeight() ) {
+//
+// HUDImage @newimage = hud.AddImage();
+// newimage.SetImageFromPath("Data/Textures/ui/whiteblock.tga");
+//
+// vec2 imagepos( 0, ypos -1 );
+//
+// newimage.scale = 1;
+// newimage.scale.x *= GetScreenWidth();
+// newimage.scale.y *= 2;
+//
+// newimage.position.x = imagepos.x;
+// newimage.position.y = GetScreenHeight() - imagepos.y - (newimage.GetWidth() * newimage.scale.y );
+// newimage.position.z = -100.0;// 0.1f;
+//
+// newimage.color = vec4( 0.0, 0.2, 0.5 + (0.5/i), 0.25 );
+//
+// ypos += increment;
+// }
+// }
+// }
+//
+// hud.Draw();
+ IMGUI_IMUIContext->render();
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Draw a box (in *screen* coordinates) -- used internally
+ *
+ */
+void IMGUI::drawBox( vec2 boxPos, vec2 boxSize, vec4 boxColor, int zOrder, bool shouldClip,
+ vec2 currentClipPos,
+ vec2 currentClipSize ) {
+
+ IMUIImage boxImage("Data/Textures/ui/whiteblock.tga");
+
+ boxImage.setPosition( vec3( boxPos.x(), boxPos.y(), float(zOrder) ) );
+ boxImage.setColor( boxColor );
+ boxImage.setRenderSize( vec2( boxSize.x(), boxSize.y() ) );
+
+ if( shouldClip && currentClipSize.x() != UNDEFINEDSIZE && currentClipSize.y() != UNDEFINEDSIZE ) {
+
+ vec2 screenClipPos = screenMetrics.GUIToScreen( currentClipPos );
+
+ vec2 screenClipSize( (currentClipSize.x()*screenMetrics.GUItoScreenXScale) + 0.5f,
+ (currentClipSize.y()*screenMetrics.GUItoScreenYScale) + 0.5f );
+
+ boxImage.setClipping( vec2( screenClipPos.x(), float(screenClipPos.y()) ),
+ vec2( screenClipSize.x(), screenClipSize.y() ) );
+ }
+
+ IMGUI_IMUIContext->queueImage( boxImage );
+
+}
+
+
+/*******************************************************************************************/
+/**
+ * @brief Finds an element in the gui by a given name
+ *
+ * @param elementName the name of the element
+ *
+ * @returns handle to the element (NULL if not found)
+ *
+ */
+IMElement* IMGUI::findElement( std::string const& elementName ) {
+
+
+ for( std::vector<IMContainer*>::iterator it = header.begin();
+ it != header.end();
+ ++it ) {
+ IMElement* foundElement = (*it)->findElement( elementName );
+
+ if( foundElement != NULL ) {
+ foundElement->AddRef();
+ return foundElement;
+ }
+ }
+
+ for( std::vector<IMContainer*>::iterator it = footer.begin();
+ it != footer.end();
+ ++it ) {
+ IMElement* foundElement = (*it)->findElement( elementName );
+
+ if( foundElement != NULL ) {
+ foundElement->AddRef();
+ return foundElement;
+ }
+ }
+
+ for( std::vector<IMContainer*>::iterator it = main.begin();
+ it != main.end();
+ ++it ) {
+ IMElement* foundElement = (*it)->findElement( elementName );
+
+ if( foundElement != NULL ) {
+ foundElement->AddRef();
+ return foundElement;
+ }
+ }
+
+ return NULL;
+
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Gets a unique name for assigning to unnamed elements (used internally)
+ *
+ * @returns Unique name as string
+ *
+ */
+std::string IMGUI::getUniqueName( std::string const& type ) {
+ elementCount += 1;
+
+ std::ostringstream oss;
+ oss << type << elementCount;
+
+ return oss.str();
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Remove all referenced object without releaseing references
+ *
+ */
+void IMGUI::clense() {
+
+ backgrounds.clear();
+ foregrounds.clear();
+ header.clear();
+ footer.clear();
+ main.clear();
+}
+
+/*******************************************************************************************/
+/**
+ * @brief Destructor
+ *
+ */
+IMGUI::~IMGUI() {
+
+ IMrefCountTracker.removeRefCountObject( "IMGUI" );
+ clear();
+ delete IMGUI_IMUIContext;
+
+ imevents.DeRegisterListener(this);
+ imevents.TriggerDestroyed(this);
+}
+
+void IMGUI::DestroyedIMElement( IMElement* element ) {
+ for( int i = backgrounds.size()-1; i >= 0; i-- ) {
+ if( backgrounds[i] == element ) {
+ backgrounds.erase(backgrounds.begin()+i);
+ }
+ }
+
+ for( int i = foregrounds.size()-1; i >= 0; i-- ) {
+ if( foregrounds[i] == element ) {
+ foregrounds.erase(foregrounds.begin()+i);
+ }
+ }
+
+ for( int i = header.size()-1; i >= 0; i-- ) {
+ if( header[i] == element ) {
+ header.erase(header.begin()+i);
+ }
+ }
+
+ for( int i = footer.size()-1; i >= 0; i-- ) {
+ if( footer[i] == element ) {
+ LOGI << "Removing footer " << element << std::endl;
+ footer.erase(footer.begin()+i);
+ }
+ }
+
+ for( int i = main.size()-1; i >= 0; i-- ) {
+ if( main[i] == element ) {
+ LOGI << "Removing main " << element << std::endl;
+ main.erase(main.begin()+i);
+ }
+ }
+}
+
+void IMGUI::DestroyedIMGUI( IMGUI* IMGUI ) {
+
+}