Hello again, I'm having some trouble with a resource class that contains a debug window with a fully functional scrolling system. It also adjusts itself to new screen (RenderWindow) sizes. Here's my problem and how to reproduce it:
[TO REPRODUCE] : Compile/Build/Run in either Debug or Release mode. Resize the window, again, and again... and sometimes, the text will completely disappear from the debug window. The scroll-bar will still be there tho. LaurentGomila-SFML-2b3d9bd (SFML-2.0 rc) used. Code Blocks 10.05 used. Win7 x86 used.
Normal:
Resized, this happens:
Here's the complete code:
//camelCase all the way!
#include <SFML/Graphics.hpp> //Obvious header
#include <string> //std::string
#include <iostream> //std::cin && std::cout
//#include <vector> //std::vector<type>
#include <cstdio> //std::getchar() (Just to pause an element, it's better than using std::cin >> to pause because you don't need to declare a variable)
#include <deque> //std::deque<type> (Stores sf::Text), I guess I should replace it with pointers to sf::Text)
#include <fstream> //std::ofstream
#include <sstream> //std::stringstream << number << string .str().c_str, used for log + number + .txt
/// A CLASS FOR COMPLETE RESOURCE CONTROL PER WINDOW:
/// resources.hpp
class resources
{
///Debugger information and methods:
sf::RectangleShape debugBar; //The little scroll bar on the right side. Size_x = debugWindow.getSize().x/20?, size_y defined by amount of text. Can be modded to be click-drag-able
std::deque<sf::Text> debugInfo; //push the front, pop the back.
sf::RenderTexture debugWindow; //The actual window; size_x = window.getSize().x, size_y = window.getSize().y/3
void debugUpdate(bool scrolled); //Called after ever << input, as well as scrollDebug
void debugLog(); //Called if the size of debugInfo becomes too large, takes a chunk and puts it in a log file. File is cleaned on startup. File named after the instance-number of this class e.g.: "log2.txt"
sf::Font debugFont;
int debugCharacterSize, scroll;
int debugThisInstance; //Based off the static debugInstance
float debugTextsPerWindow, debugTextH, debugWindowY;
static int debugInstance; //Used for the naming of logs
bool debugVisible;
///Debugger information end.
int windowSizeX, windowSizeY, windowBitsPerPixel;
std::string windowTitle;
sf::View view;
public:
resources(); //Ctor initialized from the same folder the binaries are in. Currently replacement for dirty, quick initialization
resources(std::string& rootFolder); //Ctor loads settings from a specific folder, that's how I'd like to handle different windows and their respective settings
~resources();
void resize(); //Also modifies the debugging field
///To do with debugging:
void operator << (std::string debugMessage); //Merely adds a message to the deque
void operator << (const char * debugMessage);
void debugScroll(bool upOrDown); //The boolean specifies up or down
inline void debugDraw(); //Function assumes you have already cleared the window, and that you will display it afterwards. Should always be the last draw();
void debugToggle();
///End of debugging specifications
sf::Event event;
sf::RenderWindow window;
};
/// resources.cpp
int resources::debugInstance = 0;
//Private member functions:
void resources::debugUpdate(bool scrolled = false)
{
if (debugInfo.size() >= 100) //If the size is this large, it'll take a chunk of 20 items and store it, then continue
debugLog();
if (!scrolled)
scroll = 0;
debugWindow.clear(sf::Color(127,127,127,127));
for (int i = scroll; i < debugInfo.size(); i++)
{
debugInfo[i].setPosition(0.f, (debugWindow.getSize().y - (debugInfo[(i)].getGlobalBounds().height+5)) - debugInfo[i].getGlobalBounds().height*(i-scroll));
debugWindow.draw(debugInfo[(i)]);
}
debugBar.setSize(sf::Vector2f(debugBar.getSize().x, debugWindowY * (debugTextsPerWindow/debugInfo.size()))); ///sets a level of percentage, fully represents one screen
debugBar.setPosition(sf::Vector2f(windowSizeX - debugBar.getGlobalBounds().width, (debugWindow.getSize().y - debugBar.getGlobalBounds().height) - (scroll/debugTextsPerWindow)*(debugBar.getGlobalBounds().height) )); ///Okay, so I can change position based on amount of texts and current scroll position.
debugWindow.draw(debugBar);
debugWindow.display();
}
void resources::debugLog() //Operation takes 4.2~0.x ms on a bad school-computer, 5200RPM HDD, 320GB
{
std::stringstream filename;
filename << "log" << debugThisInstance << ".txt";
std::ofstream log(filename.str().c_str(), std::ios::app);
if (log.is_open())
{
for (int i = debugInfo.size()-1; i > (debugInfo.size()-80) && i > 0; i--)
{
log << (std::string)debugInfo[i].getString() << '\n';
debugInfo.pop_back();
}
}
else
std::cout << std::string("Error saving debug info to log file!\n");
//If we were to do (*this) << "...", and the file could not be made/opened, we'd end up with a massive, recursive spam!
//Eventually, the call stack would overflow, the program would terminate.
}
//Public member functions:
resources::resources()
{
debugInstance++;
debugThisInstance = debugInstance;
debugCharacterSize = 10;
scroll = 0;
windowSizeX = 400;
windowSizeY = 300;
windowBitsPerPixel = 32;
windowTitle = "Debugger Test!";
///DEBUGGER INFORMATION:
debugFont.loadFromFile("visitor1.ttf"); //Quickly load a font file.
debugWindow.create(windowSizeX, windowSizeY/3);
debugWindow.clear(sf::Color(127,127,127,127));
debugWindow.display();
debugVisible = true;
debugBar.setSize(sf::Vector2f(windowSizeX/50, 0));
debugBar.setFillColor(sf::Color(180,180,180,127));
debugWindowY = (float) debugWindow.getSize().y;
*this << " Debugger initialization";
debugTextH = (float) debugInfo[0].getGlobalBounds().height;
debugTextsPerWindow = debugWindowY / debugTextH;
debugUpdate();
///END DEBUGGER INFORMATION
window.create(sf::VideoMode(windowSizeX,windowSizeY,windowBitsPerPixel),windowTitle.c_str(), sf::Style::Default);
}
resources::resources(std::string& rootFolder)
{
}
resources::~resources()
{
}
void resources::resize()
{
windowSizeX = window.getSize().x;
windowSizeY = window.getSize().y;
view = sf::View(sf::FloatRect(0,0,windowSizeX, windowSizeY));
window.setView(view);
///We need to re-initialize some parameters of the debug-texture:
debugWindow.create(windowSizeX,windowSizeY/3);
debugBar.setSize(sf::Vector2f(windowSizeX/50, 0));
debugWindowY = (float) debugWindow.getSize().y;
debugTextH = (float) debugInfo[0].getGlobalBounds().height;
debugTextsPerWindow = debugWindowY / debugTextH;
debugUpdate();
std::stringstream windowSizes; windowSizes << " Window resized: " << windowSizeX << "x" << windowSizeY;
*this << windowSizes.str();
}
//Operator << for the debug window
void resources::operator << (std::string debugMessage)
{
debugInfo.push_front(sf::Text(debugMessage, debugFont, debugCharacterSize));
debugUpdate();
}
void resources::operator << (const char * debugMessage)
{
*this << std::string(debugMessage);
}
void resources::debugScroll(bool upOrDown = true)
{
if (upOrDown && scroll < debugInfo.size()-debugTextsPerWindow && debugInfo.size() > debugTextsPerWindow)
scroll++;
else if (scroll > 0 && !upOrDown)
scroll--;
debugUpdate(true);
}
inline void resources::debugDraw()
{
if (debugVisible)
window.draw(sf::Sprite(debugWindow.getTexture()));
}
void resources::debugToggle()
{
if (debugVisible)
*this << " Closing debug window";
else
*this << " Opening debug window";
debugVisible = !debugVisible;
}
/// RESOURCE CLASS.
int main()
{
resources rsc;
try
{
//A simple loop:
while (true)
{
if (rsc.window.waitEvent(rsc.event))
{
switch (rsc.event.type)
{
case sf::Event::Resized:
rsc.resize();
break;
case sf::Event::KeyPressed:
switch (rsc.event.key.code)
{
case sf::Keyboard::Escape:
return 0;
case sf::Keyboard::Insert:
rsc.debugToggle();
break;
case sf::Keyboard::O:
rsc.debugScroll();
break;
case sf::Keyboard::E:
rsc.debugScroll(false);
break;
case sf::Keyboard::Up:
rsc << " Up pressed";
break;
case sf::Keyboard::Down:
rsc << " Down pressed";
break;
case sf::Keyboard::Left:
rsc << " Left pressed";
break;
case sf::Keyboard::Right:
rsc << " Right pressed";
break;
default: rsc << " unknown button pressed"; break;
}
break;
case sf::Event::Closed:
return 0;
default: break;
}
}
rsc.window.clear(sf::Color::Black);
rsc.debugDraw();
rsc.window.display();
}
}
catch (const char * error)
{
std::cout << "Error: " << error << std::endl << "Press enter to exit.";
std::getchar();
}
std::getchar();
return 0;
}
http://fontgal.com/font/10468-visitoris the font used.
Press 'O' to scroll up (Only works if there's more text than the window)
Press 'E' to scroll down.
Press any arrow key to lodge a respective message.
Insert toggles the debug window.
Press any other key to lodge a standard message.
I've spent several hours tracing it, I searched the web, this forum, no hits. So I am forced to ask it here. My apologies if the question is already answered and I didn't find it.