ItemEntry: WindowRenderer for var height and word-wrapping

For help with anything that CEGUI doesn't offer straight out-of-the-box, e.g.:
- Implementation of new features, such as new Core classes, widgets, WindowRenderers, etc. ...
- Modification of any existing features for specific purposes
- Integration of CEGUI in new engines or frameworks and writing of new plugins (Renderer, Parser, ...) or modules

Moderators: CEGUI MVP, CEGUI Team

pav
Not too shy to talk
Not too shy to talk
Posts: 37
Joined: Thu Dec 01, 2011 14:17

ItemEntry: WindowRenderer for var height and word-wrapping

Postby pav » Mon Sep 17, 2012 06:57

I tried to adapt the code sample from here to the latest version on Mercurial but I'm having a hard time. I think I'm close but I'm missing something.

First, I want something like this:

Code: Select all

+-----------------------------------------------+
| [Fixed-width1] [Fixed-width2] [Flexible width |
|                               with wrapping.] |
+-----------------------------------------------+


The relevant parts of the WidgetLook:

Code: Select all

<NamedArea name="ContentSize">
   <Area>
      <Dim type="LeftEdge"><AbsoluteDim value="0" /></Dim>
      <Dim type="TopEdge"><AbsoluteDim value="0" /></Dim>
      <Dim type="RightEdge"><UnifiedDim scale="1" type="RightEdge" /></Dim>
      <Dim type="Height"> ...Some calculated value based on FontDim baseline and linespacing... </Dim>
   </Area>
</NamedArea>

<ImagerySection name="fixed1">
   <TextComponent>
      <Area>
         ...
         <Dim type="RightEdge"><PropertyDim name="Fixed1Width" type="Width" /></Dim>
         ...
      </Area>
   </TextComponent>
</ImagerySection>

<ImagerySection name="fixed2">
   <TextComponent>
      ... Similar to "fixed1" but the left edge is to the right of "fixed1" ...
   </TextComponent>
</ImagerySection>

<ImagerySection name="text">
   <TextComponent>
      <Area>
         <Dim type="LeftEdge"> ... To the right of "fixed2" ... </Dim>
         <Dim type="RightEdge"><UnifiedDim scale="1.0" type="RightEdge" /></Dim>
         <Dim type="BottomEdge"><UnifiedDim scale="1.0" type="BottomEdge" /></Dim>
      </Area>
      <HorzFormat type="WordWrapLeftAligned" />
      <VertFormat type="TopAligned" />
   </TextComponent>
</ImagerySection>


The WindowRenderer has the render() method (exact copy of the Falagard renderer for ItemEntries) and the getItemPixelSize() method:

Code: Select all

Sizef WrappingItemEntryRenderer::getItemPixelSize() const
{
   // get WidgetLookFeel for the assigned look.
   const WidgetLookFeel& wlf = getLookNFeel();

   Sizef sz(0, 0);

   Window* par = d_window->getParent();
   while (par && !dynamic_cast<ItemListbox*>(par))
      par = par->getParent();
   if (par)
      sz.d_width = static_cast<ItemListbox*>(par)->getItemRenderArea().getWidth();

   const ImagerySection& is = wlf.getImagerySection("text");

   bool renderedOnce = false;
   for (ImagerySection::TextComponentIterator it = is.getTextComponentIterator(); !it.isAtEnd() ; it++)
   {
      // If I don't do this invalidate/render then I get a crash (see below)
      if (!renderedOnce)
      {
         d_window->invalidate();
         d_window->render();
         renderedOnce = true;
      }
      const TextComponent& tc(*it);
      float th = tc.getVerticalTextExtent(*d_window);
      if (th > sz.d_height)
         sz.d_height = th;
   }

   return sz;
}


If I *do* call invalidate/render, it doesn't crash but I get some weird behavior. First, the returned size is 438 x ~1200, the width is right but the height should be close to 30. After some debugging, I saw that the text formatting/rendering components had split the string into dozens of lines, like having one character per line, which makes me think that it uses a very small width to format the string somewhere. It does appear alright though (it's rendered on two lines, as it should), if you ignore the huge white space at the bottom.

This very large height causes my ItemListbox to show the vertical scrollbar (its height is close to 300 px) but another strange thing happens: When I add a second item, it is not placed at +1200 but it overlaps the bottom part of the previous item. For some reason, it also causes both of them to re-wrap and become 3 lines each (maybe now it took the v-scrollbar into account and it hadn't before?).

Note that if I hack a fixed height into the getPixelSize() method (i.e. Sizef sz(0, 50); return sz;) then everything works right (scrollbar, wrapping, height, placement).

Halp! :mrgreen:

The backtrace if I don't call invalidate/render:

Code: Select all

#7  0xb61a0886 in CEGUI::RenderedString::getPixelSize (this=0xa2fe444, ref_wnd=0xa9170c8, line=0)
   at ~/cegui/cegui_mk2/source/cegui/src/RenderedString.cpp:254
#8  0xb61acf09 in CEGUI::LeftAlignedRenderedString::getVerticalExtent (this=0xa2b9268, ref_wnd=0xa9170c8)
    at ~/cegui/cegui_mk2/source/cegui/src/LeftAlignedRenderedString.cpp:89
#9  0xb628d09b in CEGUI::TextComponent::getVerticalTextExtent (this=0xbf8c1b78, window=...)
   at ~/cegui/cegui_mk2/source/cegui/src/falagard/TextComponent.cpp:417
#10 0xb69fde2b in WrappingItemEntryRenderer::getItemPixelSize (this=0xa919a98)
   at ~/aaa/src/gui/WrappingItemEntryRenderer.cpp:99
#11 0xb61d527d in CEGUI::ItemEntry::getItemPixelSize (this=0xa9170c8)
   at ~/cegui/cegui_mk2/source/cegui/src/widgets/ItemEntry.cpp:71
#12 0xb61e1156 in CEGUI::ItemListbox::layoutItemWidgets (this=0xa877e20)
   at ~/cegui/cegui_mk2/source/cegui/src/widgets/ItemListbox.cpp:70
#13 0xb620c6e2 in CEGUI::ItemListBase::onListContentsChanged (this=0xa877e20, e=...)
   at ~/cegui/cegui_mk2/source/cegui/src/widgets/ItemListBase.cpp:345
#14 0xb620c612 in CEGUI::ItemListBase::handleUpdatedItemData (this=0xa877e20, resort=false)
   at ~/cegui/cegui_mk2/source/cegui/src/widgets/ItemListBase.cpp:320
#15 0xb620c1f4 in CEGUI::ItemListBase::addItem (this=0xa877e20, item=0xa9170c8)
   at ~/cegui/cegui_mk2/source/cegui/src/widgets/ItemListBase.cpp:231

pav
Not too shy to talk
Not too shy to talk
Posts: 37
Joined: Thu Dec 01, 2011 14:17

Re: ItemEntry: WindowRenderer for var height and word-wrappi

Postby pav » Fri Sep 21, 2012 08:38

OK, I still haven't solved it but I've made some progress.

When the formatter tries to wrap the string (creating multiple lines, interally) in RenderedStringWordWrapper<T>::format(const Window* ref_wnd, const Sizef& area_size), area_size.d_width is -127.
As a result, it keeps splitting the string into lines, trying to fit them in the available (none) width.

The area_size is calculated at the top of:

Code: Select all

void FalagardComponentBase::render(Window& srcWindow, const CEGUI::ColourRect* modColours, const Rectf* clipper, bool clipToDisplay) const
{
    Rectf dest_rect(d_area.getPixelRect(srcWindow));

It is the size of dest_rect. However, dest_rect is not correct, the left and top dimensions are correct (x:127 and y:2) but right and bottom are zero, so the width ends up being -127.

I then realized that my WidgetLook (see below, ImagerySection "text") has the RightEdge set to be relative to the available space (scale=1, type=RightEdge) and this calculation is not working right.
Changing it to a fixed size (i.e. AbsoluteDim value="300") worked perfectly, but was wrong because it doesn't extend to fill all available space.

Any pointers?

The relevant parts of the WidgetLook:

Code: Select all

<NamedArea name="ContentSize">
   <Area>
      <Dim type="LeftEdge"><AbsoluteDim value="0" /></Dim>
      <Dim type="TopEdge"><AbsoluteDim value="0" /></Dim>
      <Dim type="RightEdge"><UnifiedDim scale="1" type="RightEdge" /></Dim>
      <Dim type="Height"> ...Some calculated value based on FontDim baseline and linespacing... </Dim>
   </Area>
</NamedArea>

<ImagerySection name="text">
   <TextComponent>
      <Area>
         <Dim type="RightEdge"><UnifiedDim scale="1.0" type="RightEdge" /></Dim>
         <Dim type="BottomEdge"><UnifiedDim scale="1.0" type="BottomEdge" /></Dim>
      </Area>
      <HorzFormat type="WordWrapLeftAligned" />
      <VertFormat type="TopAligned" />
   </TextComponent>
</ImagerySection>


Code: Select all

Sizef WrappingItemEntryRenderer::getItemPixelSize() const
{
[...]
   // If I don't do this invalidate/render then I get a crash (see below)
   d_window->invalidate();
   d_window->render();
   for (ImagerySection::TextComponentIterator it = is.getTextComponentIterator(); !it.isAtEnd() ; it++)
   {
      const TextComponent& tc(*it);
      float th = tc.getVerticalTextExtent(*d_window);
      if (th > sz.d_height)
         sz.d_height = th;
   }
   return sz;
}

pav
Not too shy to talk
Not too shy to talk
Posts: 37
Joined: Thu Dec 01, 2011 14:17

Re: ItemEntry: WindowRenderer for var height and word-wrappi

Postby pav » Fri Nov 16, 2012 12:47

Anyone familiar with the code?

pav
Not too shy to talk
Not too shy to talk
Posts: 37
Joined: Thu Dec 01, 2011 14:17

Re: ItemEntry: WindowRenderer for var height and word-wrappi

Postby pav » Thu Jan 17, 2013 08:13

I see CE is back, answering all kinds of questions again. :D

Can you please point me in the right direction? I'll (try to) do the rest.

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

Re: ItemEntry: WindowRenderer for var height and word-wrappi

Postby CrazyEddie » Thu Jan 17, 2013 10:19

From the way you describe this, it seems the issues are all caused by incorrect values when that RightEdge when it's set to scale="1" - and that pretty much seems like a bug in CEGUI.

Is the item / items added only at initialisation, or is content added after things are up and running? If you add the ItemListBox to a FrameWindow, and resize the FrameWindow, does it then calculate the right size, or is it always wrong? The answers to these questions will help narrow down the scope of this issue.

Thanks,

CE

pav
Not too shy to talk
Not too shy to talk
Posts: 37
Joined: Thu Dec 01, 2011 14:17

Re: ItemEntry: WindowRenderer for var height and word-wrappi

Postby pav » Tue Jan 22, 2013 10:55

Thanks, I will try the things you said and I'll get back to you.

pav
Not too shy to talk
Not too shy to talk
Posts: 37
Joined: Thu Dec 01, 2011 14:17

Re: ItemEntry: WindowRenderer for var height and word-wrappi

Postby pav » Fri Mar 22, 2013 13:44

I've finally made some real progress. It seems that there are a few related problems and my code was triggering them randomly making it really hard to tell what's wrong.

I still need some help but now I have a simplified testcase!
It's a small CEGUI app (CEGUI from Mercurial, OGRE 1.8, OIS) that shows 3 different problems. Get it here: https://docs.google.com/file/d/0ByfoGpl ... sp=sharing (~200KB .7z). There's no makefile, sorry for that. :oops:

The problems are:

Code: Select all

1. Crash
2. Item visibility: issue http://www.cegui.org.uk/mantis/view.php?id=933
3. Wrong height for the custom items

See the included readme.txt for details.

The interesting code is on WrappingItemEntryRenderer.cpp and at res/test.looknfeel. The rest is the initialization and a few lines of code for the functionality (at the bottom of main.cpp).


Return to “Modifications / Integrations / Customisations”

Who is online

Users browsing this forum: Baidu [Spider] and 1 guest