[solved]Weird inconsistencies with getFont(), getPixelRect()

For help with general CEGUI usage:
- Questions about the usage of CEGUI and its features, if not explained in the documentation.
- Problems with the CMAKE configuration or problems occuring during the build process/compilation.
- Errors or unexpected behaviour.

Moderators: CEGUI MVP, CEGUI Team

Mozork
Just popping in
Just popping in
Posts: 9
Joined: Thu May 14, 2009 15:39

[solved]Weird inconsistencies with getFont(), getPixelRect()

Postby Mozork » Mon Sep 07, 2009 15:36

I've tried to write a method to adjust the height of a StaticText window according to the text it holds.

Code: Select all

/*static*/ int QuestGUINode::setHeight(CEGUI::Window* window)
    {
        COUT(1) << "PixelRect: " << window->getPixelRect().getHeight() << "x" << window->getPixelRect().getWidth() << std::endl; //Debug
        COUT(1) << "FontHeight: " << window->getFont()->getFontHeight() << ", LineSpacing:" << window->getFont()->getLineSpacing() << std::endl; //Debug
        int width = window->getPixelRect().getWidth();
        COUT(1) << "Width: " << width << std::endl; //Debug
        int lines = window->getFont()->getFormattedLineCount(window->getText(), window->getPixelRect(), CEGUI::WordWrapLeftAligned);
        COUT(1) << "Lines: " << lines << std::endl; //Debug
        int height = lines*(window->getFont()->getLineSpacing()+window->getFont()->getFontHeight());
        window->setSize(CEGUI::UVector2(CEGUI::UDim(0, width),CEGUI::UDim(0, height)));
        return height;
    }


The problems I encounter are:
1)
The width getPixelRect() gives me is incorrect.
If, for example, I insert a window with the following properties:

Code: Select all

window->setProperty("HorzFormatting", "WordWrapLeftAligned");
window->setProperty("VertFormatting", "TopAligned");
window->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 0),CEGUI::UDim(0, offset)));
window->setSize(CEGUI::UVector2(CEGUI::UDim(1.0, -13),CEGUI::UDim(1.0, 0)));

,the text already set and the window already attached to another window (with addChildWindow())
And I then do the following:

Code: Select all

int height = QuestGUINode::setHeight(window);
window->setSize(CEGUI::UVector2(CEGUI::UDim(1.0, -13),CEGUI::UDim(0, height)));

It doesn't yield the same result as just doing:

Code: Select all

int height = QuestGUINode::setHeight(window);

Which brings me to the conclusion, that the width I get with gePixelRect().getWidth() is somehow not the width of my window.

2)
getFormattedLineCount() doesn't seem to work properly. Because, the number of lines I get isn't the same I count from the displayed window, which seems odd to me.

3)
getLineSpacing() and getFontHeight() seem to be off, because in my test, I get the following numbers:
FontHeight: 18.0263, LineSpacing:18.4155
Whereas, manually (through PrintScreen) the Font Height is more like 12 pixels.

These are just too many inconsistencies to all be bugs, so where did I go wrong?
If you need more information, please don't hesitate to ask.
I'd greatly appreciate your help.
Last edited by Mozork on Sun Sep 20, 2009 21:21, edited 1 time in total.

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Re: Weird inconsistencies with getFont() and getPixelRect()

Postby CrazyEddie » Mon Sep 07, 2009 18:14

Hi, interesting issues :)

getPixelRect returns the clipped area rect of a window, for most operations you should prefer the getUnclippedPixelRect function.

When formatting the text, the area used is not necessarily the full area of the window; you didn't mention whether the StaticText has a frame or not, but it's significant and affects the formatting and therefore the number returned from getFormattedLineCount. If you're using a frame, you need to access the assigned WidgetLook and access one of the TextRenderArea named areas in order to discover the area the text is going to be drawn into. If you know for sure the size of the frame - and also are not used scrollbars - then you can make a quick and dirty solution by reducing the area rect by the sizes of the imagery (beware autoscaling also, though!).

I'm not 100% certain what the issue is with font sizing, it should be good, though I've never actually measured things before. Perhaps I'll test this myself tomorrow :)

CE.

Mozork
Just popping in
Just popping in
Posts: 9
Joined: Thu May 14, 2009 15:39

Re: Weird inconsistencies with getFont() and getPixelRect()

Postby Mozork » Mon Sep 07, 2009 19:20

getUnclippedPixelRect() does change something, indeed. But unfortunately for the worse. ;)

To your question: The StaticText has no frame.

Now, to what has happened (and to another strange behavior I forgot to mention ;))
Before, the size I got with getPixelRect() was:
PixelRect: 551x795 (height x width)
which changed to 551x795 after setHeight() was invoked.
and a result of 30 lines.
With getUnclippedPixelRect I got:
PixelRect: 588x796
which changed to PixelRect: 768x796 after setHeight() was invoked.
and a result of 30 lines.

Where in fact I count 37 lines
What is strange as well, is, that the actual height of the resized window (through setHeight()) seems to be much less (around 300 pixel less) than the calculated (and set) height.
That is what irritates me, that I set the height but when I add another window to the same parent window with offset the height I get from setHeight(), then there is a discrepancy between both windows of about 300 pixels.

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Re: Weird inconsistencies with getFont() and getPixelRect()

Postby CrazyEddie » Tue Sep 08, 2009 09:22

I didn't spot this last night, but this line:

Code: Select all

int height = lines*(window->getFont()->getLineSpacing()+window->getFont()->getFontHeight());

is incorrect, you should just use the line spacing value.

I'm not sure what's going on with the rest of it, I'll need to run some code tests in order to get a feel for things.

You mention lots of values, except the value you're expecting to get. Also when the width changes to 768, what is the value set to the window in the setHeight function? What happens in that function if, immediately after setting the size, you get the size back? Is it the same or different? If it's different, what sizes do you have set for max/min for the static text?

I'll get back to you again once I've run some tests of my own (not for a couple of days, or so).

CE.

Mozork
Just popping in
Just popping in
Posts: 9
Joined: Thu May 14, 2009 15:39

Re: Weird inconsistencies with getFont() and getPixelRect()

Postby Mozork » Tue Sep 08, 2009 11:35

Great, thanks. :D

The error you found took care of most of the issues.

There is just the one left:
So I'll get into as much detail as I can.

I have a window (a FrameWindow):

Code: Select all

this->details_ = CEGUI::WindowManager::getSingleton().createWindow("TaharezLook/FrameWindow", stream.str());
this->details_->setSize(CEGUI::UVector2(CEGUI::UDim(0, 695),CEGUI::UDim(0.8, 0)));
this->details_->setPosition(CEGUI::UVector2(CEGUI::UDim(0.1, 0),CEGUI::UDim(0.1, 0)));

With fixed with 695 pixel. When I call getPixelrect, I get the same width
Attached to this window is:

Code: Select all

CEGUI::Window* window = CEGUI::WindowManager::getSingleton().createWindow("TaharezLook/ScrollablePane", stream.str());
window->setSize(CEGUI::UVector2(CEGUI::UDim(1.0, -10),CEGUI::UDim(1.0, -26)));
window->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 5),CEGUI::UDim(0, 26)));
this->details_->addChildWindow(window);

So the with I should get with getPixelRect() should be around 685 pixels. (695-10) But with getPixelRect() I get a width of 683, which is alright (assuming a frame of 1 pixel).
And the width of the embedded windows turn out alright as well, so everything's fine.

But when I substitute the first code block with:

Code: Select all

this->details_ = CEGUI::WindowManager::getSingleton().createWindow("TaharezLook/FrameWindow", stream.str());
this->details_->setSize(CEGUI::UVector2(CEGUI::UDim(0.8, 0),CEGUI::UDim(0.8, 0)));
this->details_->setPosition(CEGUI::UVector2(CEGUI::UDim(0.1, 0),CEGUI::UDim(0.1, 0)));

I get a Frame Window the same size (visually) but getPixelRect() now says it's 819 pixels.

Mozork
Just popping in
Just popping in
Posts: 9
Joined: Thu May 14, 2009 15:39

Re: Weird inconsistencies with getFont() and getPixelRect()

Postby Mozork » Wed Sep 09, 2009 07:13

Correction. I didn't have much time, when I wrote the previous post, so I didn't look at some things too closely.

What I found out later was, that the reason it looked ok, was that now the size of the window was too small and not all text was displayed.

To illustrate the strange behavior a little better I modified the setHeight() method to:

Code: Select all

    /*static*/ int QuestGUINode::setHeight(CEGUI::Window* window)
    {
        COUT(1) << "PixelRect before setHeight(): " << window->getPixelRect().getHeight() << "x" << window->getPixelRect().getWidth() << std::endl; //Debug
        int lines = window->getFont()->getFormattedLineCount(window->getText(), window->getPixelRect(), CEGUI::WordWrapLeftAligned);
        int height = 2*lines*window->getFont()->getLineSpacing();
        COUT(1) << "Lines: " << lines << ", LineSpacing: " << window->getFont()->getLineSpacing() << std::endl; //Debug
        window->setHeight(CEGUI::UDim(0, height));
        COUT(1) << "PixelRect after setHeight(): " << window->getPixelRect().getHeight() << "x" << window->getPixelRect().getWidth() << std::endl; //Debug
        return height;
    }

Notice the 2 times for the height, so that everything is displayed.

And the context it is used in is the following:
(The second occurrence of setHeight() is the one I'm looking at)

Code: Select all

            std::ostringstream stream;

            //! Create the main window for the details.
            stream << this->window_->getName() << "/Details";
            const QuestDescription* description = this->item_->getDescription();
            this->details_ = CEGUI::WindowManager::getSingleton().createWindow("TaharezLook/FrameWindow", stream.str());
            this->details_->setSize(CEGUI::UVector2(CEGUI::UDim(0.8, 0),CEGUI::UDim(0.8, 0)));
            this->details_->setPosition(CEGUI::UVector2(CEGUI::UDim(0.1, 0),CEGUI::UDim(0.1, 0)));
            this->details_->setText(description->getTitle());
            this->details_->setAlpha(1.0);
            this->details_->setInheritsAlpha(false);
            this->details_->setProperty("CloseButtonEnabled", "True");
            this->details_->subscribeEvent(CEGUI::FrameWindow::EventCloseClicked, CEGUI::Event::Subscriber(&QuestGUINode::closeDetails, this));

            //! Create a ScrollablePane.
            stream << "/Scrollable";
            CEGUI::Window* window = CEGUI::WindowManager::getSingleton().createWindow("TaharezLook/ScrollablePane", stream.str());
            window->setSize(CEGUI::UVector2(CEGUI::UDim(1.0, -10),CEGUI::UDim(1.0, -26)));
            window->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 5),CEGUI::UDim(0, 26)));
            this->details_->addChildWindow(window);

            int height;
            int offset = 0;

            //! Display the status of the QuestItem if it is a Quest.
            Quest* quest = dynamic_cast<Quest*>(this->item_);
            if(quest != NULL) //!< If the QuestItem is a Quest
            {
                stream.str("");
                stream << this->details_->getName() << "/Status";
                CEGUI::Window* statusWindow = CEGUI::WindowManager::getSingleton().createWindow("TaharezLook/StaticText", stream.str());
                window->addChildWindow(statusWindow);
                std::string status = "";
                if(quest->isActive(this->gui_->getPlayer()))
                {
                    status = "This quest is active.";
                }
                else if(quest->isCompleted(this->gui_->getPlayer()))
                {
                    status = "This quest was completed.";
                }
                else if(quest->isFailed(this->gui_->getPlayer()))
                {
                    status = "This quest was failed.";
                }
                statusWindow->setProperty("HorzFormatting", "WordWrapLeftAligned");
                statusWindow->setProperty("VertFormatting", "TopAligned");
                statusWindow->setText(status);
                statusWindow->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 0),CEGUI::UDim(0, offset)));
                statusWindow->setSize(CEGUI::UVector2(CEGUI::UDim(1.0, -13),CEGUI::UDim(1.0, 0)));
                height = setHeight(statusWindow);

                offset += height;
            }

            //! Display the Description of the QuestItem.
            stream.str("");
            stream << this->details_->getName() << "/Description";
            CEGUI::Window* descriptionWindow = CEGUI::WindowManager::getSingleton().createWindow("TaharezLook/StaticText", stream.str());
            window->addChildWindow(descriptionWindow);
            descriptionWindow->setProperty("HorzFormatting", "WordWrapLeftAligned");
            descriptionWindow->setProperty("VertFormatting", "TopAligned");
            descriptionWindow->setText(description->getDescription());
            descriptionWindow->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 0),CEGUI::UDim(0, offset)));
            descriptionWindow->setSize(CEGUI::UVector2(CEGUI::UDim(1.0, -13),CEGUI::UDim(1.0, 0)));
            height = setHeight(descriptionWindow);

            offset += height;

            //! Display a list of hints if the QuestItem is a Quest.
            if(quest != NULL)
            {
                for(std::list<QuestGUINode*>::iterator it = this->subNodes_.begin(); it != this->subNodes_.end(); it++)
                {
                    if(dynamic_cast<QuestHint*>((*it)->item_) != NULL) //!< If the subNode belongs to a QuestHint.
                    {
                        QuestGUINode* node = *it;
                        node->window_->setSize(CEGUI::UVector2(CEGUI::UDim(1.0, -13),CEGUI::UDim(0, 30)));
                        node->window_->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 0),CEGUI::UDim(0, offset)));
                        node->window_->setProperty("HorizontalAlignment", "Left"); // TDO: Get this working.
                        window->addChildWindow(node->window_);
                        offset += 30;
                    }
                }
            }


The Output it produces is:

Code: Select all

PixelRect before setHeight(): 586.584x795
Lines: 1, LineSpacing: 18.4155
PixelRect after setHeight(): 35.5845x795
PixelRect before setHeight(): 551x795
Lines: 10, LineSpacing: 18.4155
PixelRect after setHeight(): 368x795


Again, only the second part is really relevant.

And there is what is displayed:

Image

So, there are 12 lines displayed, getFormattedLineCount() however gives me only 10.
The set 368 pixels seem to be correctly displayed but the correct height would be around 228 pixels. If we omit the 2* then the calculated height would be 184, which is not enough to fit the whole text in.

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Re: Weird inconsistencies with getFont() and getPixelRect()

Postby CrazyEddie » Wed Sep 09, 2009 08:42

Hi,

Thanks for the extra info and the pictar. I'll have a closer look and run some tests if need be either later today or tomorrow (depending on 'other things') and get back to you; sorry I didn't get a quick solution for you yet!!

CE.

Mozork
Just popping in
Just popping in
Posts: 9
Joined: Thu May 14, 2009 15:39

Re: Weird inconsistencies with getFont() and getPixelRect()

Postby Mozork » Wed Sep 09, 2009 08:55

No problem. I really appreciate your effort, thanks. :D

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Re: Weird inconsistencies with getFont() and getPixelRect()

Postby CrazyEddie » Wed Sep 09, 2009 19:12

Ok. The first thing I notice is that the StaticText windows do indeed have a frame - this explains the discrepancy between the number of lines you think there should be and the number of lines there actually are; this is because the text is not rendered to the entire size of the StaticText, but to a defined area within the StaticText - which is why I asked if there was a frame!! Additionally, when subsequently setting the height of the StaticText, you need to allow for the size of the frame in the calculation. I'll now advise against using some magic number pixel value for such things, since if you change the imagery, resolution and/or skin at some later stage the code will fall apart pretty quickly.

If we assume the simple case where you're not going to have scrollbars actually within the StaticText, obtaining the correct area to use for this requires going via the assigned widget look and feel. This is actually very simple, and a helper function can do this for you cleanly. The following example function gets the named area "WithFrameTextRenderArea" and returns a CEGUI::Rect describing this area in terms of the input window (which must be a StaticText):

Code: Select all

CEGUI::Rect getStaticTextArea(const CEGUI::Window* static_text)
{
    const CEGUI::WidgetLookFeel& wlf =
        CEGUI::WidgetLookManager::getSingleton().
            getWidgetLook(static_text->getLookNFeel());

    return wlf.getNamedArea("WithFrameTextRenderArea").getArea().
        getPixelRect(*static_text);
}


So, the area you get from this is the area the text is formatted and drawn into. This will allow you to correctly establish the number of formatted lines for the setHeight function. My free function recreation of that is below, with comments for each step, just to be clear about exactly what is going on:

Code: Select all

int setHeight(CEGUI::Window* static_text)
{
    // Get the area the text is formatted and drawn into.
    const CEGUI::Rect fmt_area(getStaticTextArea(static_text));

    // Calculate the pixel height of the frame by subtracting the height of the
    // area above from the total height of the window.
    const float frame_height =
        static_text->getUnclippedPixelRect().getHeight() - fmt_area.getHeight();

    // Get the formatted line count - using the formatting area obtained above.
    const float lines = static_text->getFont()->getFormattedLineCount(
            static_text->getText(), fmt_area, CEGUI::WordWrapLeftAligned);

    // Calculate pixel height of window, which is the number of formatted lines
    // multiplied by the spacing of the font, plus the pixel height of the
    // frame.
    const float height =
        lines * static_text->getFont()->getLineSpacing() + frame_height;

    // set the height to the window.
    static_text->setHeight(CEGUI::UDim(0, height));

    return static_cast<int>(height);
}


Hopefully this will get you moving along in the right direction!

[Edit]Actually, I just tried a different font and am not certain about the results here. :lol: I'll update again in a short time once I've checked over the new information I now have. D'oh!

[Edit 2] Nope, it's fine :) An optical illusion where all the text got perfectly aligned! Upon closer examination and additional testing, the output was still correct - so the functions above should do what's needed :)

CE.

Mozork
Just popping in
Just popping in
Posts: 9
Joined: Thu May 14, 2009 15:39

Re: Weird inconsistencies with getFont() and getPixelRect()

Postby Mozork » Wed Sep 09, 2009 20:12

Thanks, the method is much nicer now, the problem with the lines, however still persists.

I've just added a little debug output:

Code: Select all

    /*static*/ int QuestGUINode::setHeight(CEGUI::Window* window)
    {
        //! Get the area the text is formatted and drawn into.
        const CEGUI::Rect formattedArea = getStaticTextArea(window);
        COUT(1) << "PixelRect before setHeight(): " << formattedArea.getHeight() << "x" << formattedArea.getWidth() << std::endl; //Debug

        //! Calculate the pixel height of the frame by subtracting the height of the area above from the total height of the window.
        const float frameHeight = window->getUnclippedPixelRect().getHeight() - formattedArea.getHeight();

        //! Get the formatted line count - using the formatting area obtained above.
        const float lines = window->getFont()->getFormattedLineCount(window->getText(), formattedArea, CEGUI::WordWrapLeftAligned);
        COUT(1) << "Lines: " << lines << std::endl; //Debug

        //! Calculate pixel height of window, which is the number of formatted lines multiplied by the spacing of the font, plus the pixel height of the frame.
        const float height = lines * window->getFont()->getLineSpacing() + frameHeight;

        //! Set the height to the window.
        window->setHeight(CEGUI::UDim(0, height));
       
        //Debug
        const CEGUI::Rect newArea = getStaticTextArea(window);
        COUT(1) << "PixelRect after setHeight(): " << newArea.getHeight() << "x" << newArea.getWidth() << std::endl; //Debug

        return static_cast<int>(height);
    }


Now when I run the GUI again I get the following output:

Code: Select all

PixelRect before setHeight(): 572x780
Lines: 1
PixelRect after setHeight(): 18x780
PixelRect before setHeight(): 572x780
Lines: 10
PixelRect after setHeight(): 184x780


So, the height of the text gets set to 184 pixels. But as you can see from the previous picture the text takes up a height of approximately 228 pixels. Also the line count is (with 10) incorrect. (It's 12 in the previously posted picture)

Here a picture of the result, as you can see, the text gets clipped at line 10, the 2 lines after that are not displayed.

Image

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Re: Weird inconsistencies with getFont() and getPixelRect()

Postby CrazyEddie » Thu Sep 10, 2009 08:38

I'm actually running out of ideas here, the code posted is effectively the same code used internally by the StaticText - I really can't explain the differing results here.

Just to confirm a few things, so we can eliminate this - or not - as some odd 'edge case' CEGUI bug:
1) Which version of CEGUI is this, exactly?
2) Can you post the font definition XML or code.
3) What is the size of the viewport you're running in.

Thanks,

CE.

Mozork
Just popping in
Just popping in
Posts: 9
Joined: Thu May 14, 2009 15:39

Re: Weird inconsistencies with getFont() and getPixelRect()

Postby Mozork » Thu Sep 10, 2009 10:46

1) Version is 0.6.1
2)
My GUI is loaded by a lua script which defines:

Code: Select all

local schemeMgr = CEGUI.SchemeManager:getSingleton()
winMgr = CEGUI.WindowManager:getSingleton()
local logger = CEGUI.Logger:getSingleton()
local system = CEGUI.System:getSingleton()
local cursor = CEGUI.MouseCursor:getSingleton()

schemeMgr:loadScheme("TaharezLookSkin.scheme")
-- load scheme with our own images
schemeMgr:loadScheme("OrxonoxGUIScheme.scheme")

system:setDefaultMouseCursor("TaharezLook", "MouseArrow")
system:setDefaultFont("BlueHighway-12")
system:setDefaultTooltip("TaharezLook/Tooltip")

3) The size of the viewport is 1024x768

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Re: Weird inconsistencies with getFont() and getPixelRect()

Postby CrazyEddie » Thu Sep 10, 2009 11:57

Thanks for the info. I'll try again to recreate the issue tomorrow; it's really annoying for me, because I know it should work, but clearly it doesn't!

CE.

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Re: Weird inconsistencies with getFont() and getPixelRect()

Postby CrazyEddie » Sun Sep 13, 2009 20:48

Just to update: I did not do any further testing on this yet, but I have not forgotten and will get back to you soon :)

CE.

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Re: Weird inconsistencies with getFont() and getPixelRect()

Postby CrazyEddie » Tue Sep 15, 2009 11:39

Ok. I have run some more tests on this, and using all the information provided: The amount of text seen in the very first image, with the font set up as stated, all windows created as stated.

My output from the setHeight function look like this:

Code: Select all

PixelRect before setHeight(): 572x780
PixelRect after setHeight(): 18x780
PixelRect before setHeight(): 572x780
PixelRect after setHeight(): 184x780


My font states it's size as:

Code: Select all

Font Height: 18.0263
Font Spacing: 18.4155


In the final output, however, there are only ten lines of text!

Looking again at the images, however, I see a difference in the size of the innermost FrameWindow and mine. This suggests to me that it's being added to a non-screen sized parent window after it's initial creation, and most importantly, after the content has been generated and the sizes set. This is what is throwing off the calculations, because 80% of 1024 - used when then window is initially created and the content added, is not the same as 80% of the size of the smaller window eventually used as the parent of this FrameWindow. The solutions open to you are to either use a fixed pixel size for the FrameWindow(s), or to have an event handler that resizes the attached content whenever the container FrameWindow size changes.

HTH

CE.


Return to “Help”

Who is online

Users browsing this forum: No registered users and 12 guests