Custom tooltip
Moderators: CEGUI MVP, CEGUI Team
Custom tooltip
Hi,
i'm starting using CEGUI and i'm reproducing some features i've implemented in a different GUI system. I'm trying to create a tooltip made of two text lines, a title and a description. The title has a type bigger font, the other a small one.
I'd like to ask how i can subclass the existing tooltip. I'm thinking of passing the 2 strings with setTooltipText with a new line between the two texts. After the custom tooltip class parse the text and assign the content to the two text elements of the tooltip and display it.
Is it a viable way? To subclass do i need just to create a class in my project derived from CEGUITooltip, use createWindow to create an instance of it and use setTooltip to pass its pointer to each of my controls?
In the new class the setText done in the original Tooltip type will be overriden with a call to setText of 2 elements inside my custom Window. I'd like to understand if it's possible to create a .layout of this window and load it. I'm a little confused about the TextComponent tag inside the looknfeel files, it seems like i can have just one textcomponent inside each widget.. so a layout is preferred, isn't it?
i'm starting using CEGUI and i'm reproducing some features i've implemented in a different GUI system. I'm trying to create a tooltip made of two text lines, a title and a description. The title has a type bigger font, the other a small one.
I'd like to ask how i can subclass the existing tooltip. I'm thinking of passing the 2 strings with setTooltipText with a new line between the two texts. After the custom tooltip class parse the text and assign the content to the two text elements of the tooltip and display it.
Is it a viable way? To subclass do i need just to create a class in my project derived from CEGUITooltip, use createWindow to create an instance of it and use setTooltip to pass its pointer to each of my controls?
In the new class the setText done in the original Tooltip type will be overriden with a call to setText of 2 elements inside my custom Window. I'd like to understand if it's possible to create a .layout of this window and load it. I'm a little confused about the TextComponent tag inside the looknfeel files, it seems like i can have just one textcomponent inside each widget.. so a layout is preferred, isn't it?
- CrazyEddie
- CEGUI Project Lead
- Posts: 6760
- Joined: Wed Jan 12, 2005 12:06
- Location: England
- Contact:
Hi, and welcome
There are a couple of approaches you can take with this - one is indeed to subclass the Tooltip window class, another alternative is to provide a custom window renderer class, a third alternative would be to do it all in the skin, although here you lose the ability to parse the existing window text.
A brief little discussion of how things are architected...
Windows are created by associated WindowFactory objects that are registered with the WindowFactoryManager, and enable the WindowManager to create the various classes of Window based objects.
A Window generally does its rendering by storing rendering operations to be performed in a RenderCache that each window has. The RenderCache can be filled by the Window itself, via the Window::populateRenderCache member, or alternatively, a Window can have an assigned WindowRenderer based object that will perform this step instead.
A WindowRenderer generally makes use of the Falagard skinning information assigned to it's associated Window - extracting the various parts it may require and stuffing the details into the RenderCache. A WindowRenderer has an associated WindowRendererFactory that is registered with the WindowRendererManager.
All these parts are tied together via a "Falagard mapping" - this created a mapping for a new window type from some base Window type, a WindowRenderer, and the name of a WidgetLook / LookNFeel (skin definition). Usually this mapping is specified in a scheme XML file, although it is also possible to do that in code.
How far along this road you need to go is up to you; you can definitely get what you need without the extra work of the WindowRenderer approach.
Anyway, to create a subclass of a Window and it's associated factory, you might refer to this post in which I describe how to do that in detail: http://www.cegui.org.uk/phpBB2/viewtopi ... 4730#14730
Other things to be aware of are, that you can't override the setText member - it's not virtual. You should override the onTextChanged member and do stuff in there instead.
With regards to looknfeel and layouts - the way to think about this is that layouts are more like 'objects', they represent a concrete definition of a set of windows. Whereas a looknfeel is more like a 'class', in that it defines general aspects that can be used many times over.
Generally speaking the looknfeel system is vastly more powerful that the layout system. You can actually have as many TextComponent definitions as you want. You could also, for instance, define separate properties for the tooltip title and main text, then get the rest of the skin to render it (the caveat here is that the rest of the system would not know about those new properties if defined solely in XML).
Personally, I think a subclass of Tooltip, an overridden onTextChanged, and an implementation of populateRenderCache is the way to go (one you have that you can branch out into WindowRenderers if the need arises).
CE.
There are a couple of approaches you can take with this - one is indeed to subclass the Tooltip window class, another alternative is to provide a custom window renderer class, a third alternative would be to do it all in the skin, although here you lose the ability to parse the existing window text.
A brief little discussion of how things are architected...
Windows are created by associated WindowFactory objects that are registered with the WindowFactoryManager, and enable the WindowManager to create the various classes of Window based objects.
A Window generally does its rendering by storing rendering operations to be performed in a RenderCache that each window has. The RenderCache can be filled by the Window itself, via the Window::populateRenderCache member, or alternatively, a Window can have an assigned WindowRenderer based object that will perform this step instead.
A WindowRenderer generally makes use of the Falagard skinning information assigned to it's associated Window - extracting the various parts it may require and stuffing the details into the RenderCache. A WindowRenderer has an associated WindowRendererFactory that is registered with the WindowRendererManager.
All these parts are tied together via a "Falagard mapping" - this created a mapping for a new window type from some base Window type, a WindowRenderer, and the name of a WidgetLook / LookNFeel (skin definition). Usually this mapping is specified in a scheme XML file, although it is also possible to do that in code.
How far along this road you need to go is up to you; you can definitely get what you need without the extra work of the WindowRenderer approach.
Anyway, to create a subclass of a Window and it's associated factory, you might refer to this post in which I describe how to do that in detail: http://www.cegui.org.uk/phpBB2/viewtopi ... 4730#14730
Other things to be aware of are, that you can't override the setText member - it's not virtual. You should override the onTextChanged member and do stuff in there instead.
With regards to looknfeel and layouts - the way to think about this is that layouts are more like 'objects', they represent a concrete definition of a set of windows. Whereas a looknfeel is more like a 'class', in that it defines general aspects that can be used many times over.
Generally speaking the looknfeel system is vastly more powerful that the layout system. You can actually have as many TextComponent definitions as you want. You could also, for instance, define separate properties for the tooltip title and main text, then get the rest of the skin to render it (the caveat here is that the rest of the system would not know about those new properties if defined solely in XML).
Personally, I think a subclass of Tooltip, an overridden onTextChanged, and an implementation of populateRenderCache is the way to go (one you have that you can branch out into WindowRenderers if the need arises).
CE.
Thank you for your explanation Is it possible to support the looknfeel technology using a WindowFactory? I think it'd be good to define the look of the tooltip inside the skin files.
In the WindowManager class i've found this piece of code in the createWindow function about the use of the falagard system:
Looking at the entire function, would it good to add my factory to the system, then create the tooltip with createWindow, as the other standard elements? There the line
that make me think the factory would be recognized.
Is needed a change inside the .scheme file? The original definition
Points to CEGUI/Tooltip that is the WidgetTypeName specified inside the Tooltip class. Do i need to change it to have the FactoryManager use the right factory?
There's also the Falagard/Tooltip correspondent class FalagardTooltip. Here i'll need to change the getTextSize function to manage the 2 strings and return the size of the larger one. Is there a factory to register also for these classes?
The last thing i've again some problems to understand is where exactly the text is associated/rendered with a textcomponet inside the looknfeel definition. I've seen there's a named area called TextArea that define the area where the text is defined but i cannot find where the later TextComponent uses that area to rendered the text. Is the Falagard system searching for the first TextComponent inside the looknfeel elements? If i've two areas and two textcomponents is there a way to associate each components to the right text?
Sorry for the questions
In the WindowManager class i've found this piece of code in the createWindow function about the use of the falagard system:
Code: Select all
// see if we need to assign a look to this window
if (wfMgr.isFalagardMappedType(type))
{
const WindowFactoryManager::FalagardWindowMapping& fwm = wfMgr.getFalagardMappingForType(type);
// this was a mapped type, so assign a look to the window so it can finalise
// its initialisation
newWindow->d_falagardType = type;
newWindow->setWindowRenderer(fwm.d_rendererType);
newWindow->setLookNFeel(fwm.d_lookName);
}
Looking at the entire function, would it good to add my factory to the system, then create the tooltip with createWindow, as the other standard elements? There the line
Code: Select all
WindowFactory* factory = wfMgr.getFactory(type);
that make me think the factory would be recognized.
Is needed a change inside the .scheme file? The original definition
Code: Select all
<FalagardMapping WindowType="TaharezLook/Tooltip" TargetType="CEGUI/Tooltip" Renderer="Falagard/Tooltip" LookNFeel="TaharezLook/Tooltip" />
Points to CEGUI/Tooltip that is the WidgetTypeName specified inside the Tooltip class. Do i need to change it to have the FactoryManager use the right factory?
There's also the Falagard/Tooltip correspondent class FalagardTooltip. Here i'll need to change the getTextSize function to manage the 2 strings and return the size of the larger one. Is there a factory to register also for these classes?
The last thing i've again some problems to understand is where exactly the text is associated/rendered with a textcomponet inside the looknfeel definition. I've seen there's a named area called TextArea that define the area where the text is defined but i cannot find where the later TextComponent uses that area to rendered the text. Is the Falagard system searching for the first TextComponent inside the looknfeel elements? If i've two areas and two textcomponents is there a way to associate each components to the right text?
Sorry for the questions
- CrazyEddie
- CEGUI Project Lead
- Posts: 6760
- Joined: Wed Jan 12, 2005 12:06
- Location: England
- Contact:
Hi,
To use the looknfeel parts of the system you need to also have a WindowRenderer (in addition to the Window class and WindowFactory). I'm actually not 100% why we made this a requirement, but still, for now at least, there it is!
To get the system to use a custom tooltip type / class you have a few options. You could tell the system object the type name of the Tooltip to use as the default, you can create a single instance of the new Tooltip class (via the WindowManager::createWindow member) and pass that to the System object to use as the default tooltip, or you can assign custom Tooltip objects to each individual window you create (this is usually overkill, and not necessary).
Yes, here you need to specify the name of the new class in place of "CEGUI/Tooltip", the name of a replacement (Window)Renderer, and the name of a skin LookNFeel definition that the new WindowRenderer can make sense of.
This is a WindowRenderer type, to use the mappings/skin system you'll need a new WindowRenderer and a WindowRendererFactory that creates the new type registered with the WindowRendererManager.
If a TextComponent has no Text or TextProperty element defined within it, the text it uses comes from the main text string associated with Window that the skin is applied to.
The TextArea named area is something that the WindowRenderer class stipulates must be present, it uses the defines area to decide how large the rendered text is (this is how the automatic position adjustment, at the screen edges, is implemented.
CE.
To use the looknfeel parts of the system you need to also have a WindowRenderer (in addition to the Window class and WindowFactory). I'm actually not 100% why we made this a requirement, but still, for now at least, there it is!
To get the system to use a custom tooltip type / class you have a few options. You could tell the system object the type name of the Tooltip to use as the default, you can create a single instance of the new Tooltip class (via the WindowManager::createWindow member) and pass that to the System object to use as the default tooltip, or you can assign custom Tooltip objects to each individual window you create (this is usually overkill, and not necessary).
Is needed a change inside the .scheme file? The original definitionCode: Select all
<FalagardMapping WindowType="TaharezLook/Tooltip" TargetType="CEGUI/Tooltip" Renderer="Falagard/Tooltip" LookNFeel="TaharezLook/Tooltip" />
Points to CEGUI/Tooltip that is the WidgetTypeName specified inside the Tooltip class. Do i need to change it to have the FactoryManager use the right factory?
Yes, here you need to specify the name of the new class in place of "CEGUI/Tooltip", the name of a replacement (Window)Renderer, and the name of a skin LookNFeel definition that the new WindowRenderer can make sense of.
There's also the Falagard/Tooltip correspondent class FalagardTooltip. Here i'll need to change the getTextSize function to manage the 2 strings and return the size of the larger one. Is there a factory to register also for these classes?
This is a WindowRenderer type, to use the mappings/skin system you'll need a new WindowRenderer and a WindowRendererFactory that creates the new type registered with the WindowRendererManager.
The last thing i've again some problems to understand is where exactly the text is associated/rendered with a textcomponet inside the looknfeel definition. I've seen there's a named area called TextArea that define the area where the text is defined but i cannot find where the later TextComponent uses that area to rendered the text. Is the Falagard system searching for the first TextComponent inside the looknfeel elements? If i've two areas and two textcomponents is there a way to associate each components to the right text?
If a TextComponent has no Text or TextProperty element defined within it, the text it uses comes from the main text string associated with Window that the skin is applied to.
The TextArea named area is something that the WindowRenderer class stipulates must be present, it uses the defines area to decide how large the rendered text is (this is how the automatic position adjustment, at the screen edges, is implemented.
CE.
Re: Custom tooltip
Hi,
I am here again. After solving the problem for the chat ui with clickable text, I think I have know more for the CEGUI than before.
I am working for the tooltip now. I think this article is almost the same as my requirement. I tried it but failed. I guess this article is too old and I am using 0.7.5. I can't find the function "WIndow::populateRenderCache" as you guided.
At the moment, I clone "Tooltip1" from "Tooltip" in the looknfeel file and I add one more named text component. I can set different text to both text component without the problem.(one is default and the text can be input from Window:setText and another one named "text" can be input by the text property)
The point is how to resize the tooltip window correctly when there are more text components in the tooltip-like window.
I subclass a renderer "class FalTooltip1". I thinked maybe it is the same as you taught me from the itementry. (grin evilly)
I rewrote the function "FalagardTooltip1::getTextSize()" as follows.
It is bad luck and it is not as what I thought as.
floattext_tc->getText() is always zero. Originally I didn't add this checking, it is always crashing. "text_tc->d_formattedRenderedString->d_renderedString" seem not be initiallized (I check it from the "Watch") . I feel it is similar to the problem I meet when I was fighting with ItemEntry viewtopic.php?f=10&t=4322&start=30. During fighting with ItemEntry, the crash is gone when I use your code and I thinkit related to "invalidate() and render() of window. At this time, I add the same method but it is useless.
I can display the text as what I want with the original tooltip renderer except the window size is incorrect. From this code, the height of return value is always zero so I can only see a very small tooltip.
I read this discussion in detail and I think maybe it is out of date. That is why I am asking help now.
Please give me some suggestions.
I am here again. After solving the problem for the chat ui with clickable text, I think I have know more for the CEGUI than before.
I am working for the tooltip now. I think this article is almost the same as my requirement. I tried it but failed. I guess this article is too old and I am using 0.7.5. I can't find the function "WIndow::populateRenderCache" as you guided.
At the moment, I clone "Tooltip1" from "Tooltip" in the looknfeel file and I add one more named text component. I can set different text to both text component without the problem.(one is default and the text can be input from Window:setText and another one named "text" can be input by the text property)
The point is how to resize the tooltip window correctly when there are more text components in the tooltip-like window.
I subclass a renderer "class FalTooltip1". I thinked maybe it is the same as you taught me from the itementry. (grin evilly)
I rewrote the function "FalagardTooltip1::getTextSize()" as follows.
Code: Select all
Size FalagardTooltip1::getTextSize() const
{
Tooltip* w = (Tooltip*)d_window;
// get WidgetLookFeel for the assigned look.
const WidgetLookFeel& wlf = getLookNFeel();
#if 0
Size sz(w->getTextSize_impl());
#else
float height=0;
const ImagerySection& text_IS = wlf.getImagerySection("text");
const TextComponent* text_tc=text_IS.getTextComponent(0);
bool bInvalidate=false;
if(text_tc) {
if(text_tc->getText().size()>0) {
bInvalidate=true;
d_window->invalidate();
d_window->render();
height=text_tc->getVerticalExtent();
}
}
const ImagerySection& floattext_IS=wlf.getImagerySection("floattext");
const TextComponent* floattext_tc=floattext_IS.getTextComponent(0);
if(floattext_tc) {
if(floattext_tc->getText().size()>0) {
if(!bInvalidate) {
d_window->invalidate();
d_window->render();
}
height+=floattext_tc->getVerticalExtent();
}
}
Size sz(400, height);
#endif
Rect textArea(wlf.getNamedArea("TextArea").getArea().getPixelRect(*w));
Rect wndArea(w->getArea().asAbsolute(w->getParentPixelSize()));
sz.d_width = PixelAligned(sz.d_width + wndArea.getWidth() - textArea.getWidth());
sz.d_height = PixelAligned(sz.d_height + wndArea.getHeight() - textArea.getHeight());
return sz;
}
It is bad luck and it is not as what I thought as.
floattext_tc->getText() is always zero. Originally I didn't add this checking, it is always crashing. "text_tc->d_formattedRenderedString->d_renderedString" seem not be initiallized (I check it from the "Watch") . I feel it is similar to the problem I meet when I was fighting with ItemEntry viewtopic.php?f=10&t=4322&start=30. During fighting with ItemEntry, the crash is gone when I use your code and I thinkit related to "invalidate() and render() of window. At this time, I add the same method but it is useless.
I can display the text as what I want with the original tooltip renderer except the window size is incorrect. From this code, the height of return value is always zero so I can only see a very small tooltip.
I read this discussion in detail and I think maybe it is out of date. That is why I am asking help now.
Please give me some suggestions.
- CrazyEddie
- CEGUI Project Lead
- Posts: 6760
- Joined: Wed Jan 12, 2005 12:06
- Location: England
- Contact:
Re: Custom tooltip
This user is doing something similar: viewtopic.php?f=10&t=5892 I pointed them to the ItemEntry solution
I'm unsure what the issue is right now. Can you post the WidgetLook that contains 'floattext' ImagerySection and I'll have a think on it.
CE.
I'm unsure what the issue is right now. Can you post the WidgetLook that contains 'floattext' ImagerySection and I'll have a think on it.
CE.
Useful Links: Forum Guidelines | Documentation | Tutorials | HOWTO | Videos | Donate to CEGUI | CEGUI Twitter
Re: Custom tooltip
Please take a look the looknfeel of tooltip1 with FloatText. Thank you.
Code: Select all
<!--
***************************************************
game1/Tooltip1
***************************************************
-->
<WidgetLook name="game1/Tooltip1">
<PropertyDefinition name="FloatText" initialValue="" redrawOnWrite="true" />
<NamedArea name="TextArea">
<Area>
<Dim type="LeftEdge" ><ImageDim imageset="game1" image="TooltipLeftEdge" dimension="Width" /></Dim>
<Dim type="TopEdge" ><ImageDim imageset="game1" image="TooltipTopEdge" dimension="Height" /></Dim>
<Dim type="RightEdge" >
<UnifiedDim scale="1" type="RightEdge">
<DimOperator op="Subtract">
<ImageDim imageset="game1" image="TooltipRightEdge" dimension="Width" />
</DimOperator>
</UnifiedDim>
</Dim>
<Dim type="BottomEdge" >
<UnifiedDim scale="1" type="BottomEdge">
<DimOperator op="Subtract">
<ImageDim imageset="game1" image="TooltipBottomEdge" dimension="Height" />
</DimOperator>
</UnifiedDim>
</Dim>
</Area>
</NamedArea>
<ImagerySection name="main">
<FrameComponent>
<Area>
<Dim type="LeftEdge" ><AbsoluteDim value="0" /></Dim>
<Dim type="TopEdge" ><AbsoluteDim value="0" /></Dim>
<Dim type="Width" ><UnifiedDim scale="1" type="Width" /></Dim>
<Dim type="Height" ><UnifiedDim scale="1" type="Height" /></Dim>
</Area>
<Image type="TopLeftCorner" imageset="game1" image="TooltipTopLeft" />
<Image type="TopRightCorner" imageset="game1" image="TooltipTopRight" />
<Image type="BottomLeftCorner" imageset="game1" image="TooltipBottomLeft" />
<Image type="BottomRightCorner" imageset="game1" image="TooltipBottomRight" />
<Image type="LeftEdge" imageset="game1" image="TooltipLeftEdge" />
<Image type="RightEdge" imageset="game1" image="TooltipRightEdge" />
<Image type="TopEdge" imageset="game1" image="TooltipTopEdge" />
<Image type="BottomEdge" imageset="game1" image="TooltipBottomEdge" />
<Image type="Background" imageset="game1" image="TooltipMiddle" />
</FrameComponent>
</ImagerySection>
<ImagerySection name="text">
<TextComponent>
<Area>
<Dim type="LeftEdge" ><ImageDim imageset="game1" image="TooltipLeftEdge" dimension="Width" /></Dim>
<Dim type="TopEdge" ><ImageDim imageset="game1" image="TooltipTopEdge" dimension="Height" /></Dim>
<Dim type="RightEdge" >
<UnifiedDim scale="1" type="RightEdge">
<DimOperator op="Subtract">
<ImageDim imageset="game1" image="TooltipRightEdge" dimension="Width" />
</DimOperator>
</UnifiedDim>
</Dim>
<Dim type="BottomEdge" >
<UnifiedDim scale="1" type="BottomEdge">
<DimOperator op="Subtract">
<ImageDim imageset="game1" image="TooltipBottomEdge" dimension="Height" />
</DimOperator>
</UnifiedDim>
</Dim>
</Area>
<Colours topLeft="FF000000" topRight="FF000000" bottomLeft="FF000000" bottomRight="FF000000" />
<VertFormat type="CentreAligned" />
<HorzFormat type="CentreAligned" />
</TextComponent>
</ImagerySection>
<ImagerySection name="floattext">
<TextComponent>
<Area>
<Dim type="LeftEdge" ><ImageDim imageset="game1" image="TooltipLeftEdge" dimension="Width" /></Dim>
<Dim type="TopEdge" ><ImageDim imageset="game1" image="TooltipTopEdge" dimension="Height" /></Dim>
<Dim type="RightEdge" >
<UnifiedDim scale="1" type="RightEdge">
<DimOperator op="Subtract">
<ImageDim imageset="game1" image="TooltipRightEdge" dimension="Width" />
</DimOperator>
</UnifiedDim>
</Dim>
<Dim type="BottomEdge" >
<UnifiedDim scale="1" type="BottomEdge">
<DimOperator op="Subtract">
<ImageDim imageset="game1" image="TooltipBottomEdge" dimension="Height" />
</DimOperator>
</UnifiedDim>
</Dim>
</Area>
<TextProperty name="FloatText" />
<Colours topLeft="FFFFFFFF" topRight="FFFFFFFF" bottomLeft="FFFFFFFF" bottomRight="FFFFFFFF" />
<VertFormat type="CentreAligned" />
<HorzFormat type="CentreAligned" />
</TextComponent>
</ImagerySection>
<StateImagery name="Enabled">
<Layer>
<Section section="main" />
<Section section="text" />
<Section section="floattext" />
</Layer>
</StateImagery>
<StateImagery name="Disabled">
<Layer>
<Section section="main" />
<Section section="title" />
<Section section="floattext" />
</Layer>
</StateImagery>
</WidgetLook>
- CrazyEddie
- CEGUI Project Lead
- Posts: 6760
- Joined: Wed Jan 12, 2005 12:06
- Location: England
- Contact:
Re: Custom tooltip
I've looked at this, and played around a bit with things myself to properly understand the issues and such.
I can recreate various issues related to this, and the worst of those is unexplainable by me right at the moment.
The issue with TextComponent::getText always returning an empty string is at best an inconsistency between the docs and the implementation, and at worst, a bug. Basically the docs say it will return the string to be rendered, though in reality it only returns the string directly set on the TextComponent; it currently returns the empty string if the string to be rendered is sourced from either a property or the target window. I'm undecided whether to 'fix' the existing function or add a new one at the moment. But I will certainly add a ticket to make the 'correct' information available somehow.
Ok, since that not working was a blocker, I removed the string check, and had something rendering, but very unstable (basically the kind of issue you mention), an example backtrace:
The crazy thing about this is, that I've looked over the code and this should be working. The d_lines collection in RenderedString where it crashes contains a totally incorrect return value from size(), which indicates something going horribly wrong either in the parsing / formatting or with general memory corruption. I don't think it's a case that the string was not processed yet, as the std::vector should report a size() of 0. I need to investigate this further.
Ok, all this aside. The times when I did see rendering, things were also not as I would have liked, but perfectly expected and explainable. Basically, the various TextComponents were all overlapping each other - this is expected since the areas defined in the looknfeel are all the same. To arrange things differently would require either the areas to be set differently, though that requires prior knowledge of the size (height) of the formatted content, and is likely a non starter, or to use some other means to lay out the individual strings - such as using the Tooltip as a container for some other lightweight label rendering window. I think using the container / label approach would allow you to have each label size itself, and have the host Tooltip set its height to the sum of the child label heights. If that works correctly, it works around the bugs and sidesteps the shortcomings that using TextComponent currently presents. Additionally you would/could use PropertyLinkDefinition elements on the Tooltip to link to the Text property of the component label windows (created using Child tags).
Adding those things is a slightly bigger job, of course, and while I think it would work I can't say for sure without having tested it So, the usual thing applies here, you could have a go yourself, or let me know if not, and I'll have a stab at it in a couple of weeks or so.
CE.
I can recreate various issues related to this, and the worst of those is unexplainable by me right at the moment.
The issue with TextComponent::getText always returning an empty string is at best an inconsistency between the docs and the implementation, and at worst, a bug. Basically the docs say it will return the string to be rendered, though in reality it only returns the string directly set on the TextComponent; it currently returns the empty string if the string to be rendered is sourced from either a property or the target window. I'm undecided whether to 'fix' the existing function or add a new one at the moment. But I will certainly add a ticket to make the 'correct' information available somehow.
Ok, since that not working was a blocker, I removed the string check, and had something rendering, but very unstable (basically the kind of issue you mention), an example backtrace:
Code: Select all
#0 0x00007ffff79c788f in CEGUI::RenderedString::getPixelSize (this=0xa7b300, line=0) at ../../../cegui/src/CEGUIRenderedString.cpp:252
#1 0x00007ffff79bf48f in CEGUI::LeftAlignedRenderedString::getVerticalExtent (this=0xa2f710) at ../../../cegui/src/CEGUILeftAlignedRenderedString.cpp:87
#2 0x00007ffff7aa1b71 in CEGUI::TextComponent::getVerticalTextExtent (this=0xa82e40) at ../../../cegui/src/falagard/CEGUIFalTextComponent.cpp:427
#3 0x00007fffee8cfe59 in CEGUI::FalagardTooltip::getTextSize (this=0x95c270) at ../../../../../cegui/src/WindowRendererSets/Falagard/FalTooltip.cpp:91
#4 0x00007ffff7a8195b in CEGUI::Tooltip::getTextSize (this=0xb91ea0) at ../../../cegui/src/elements/CEGUITooltip.cpp:174
#5 0x00007ffff7a8178a in CEGUI::Tooltip::sizeSelf (this=0xb91ea0) at ../../../cegui/src/elements/CEGUITooltip.cpp:132
#6 0x00007ffff7a824c9 in CEGUI::Tooltip::onTextChanged (this=0xb91ea0, e=...) at ../../../cegui/src/elements/CEGUITooltip.cpp:415
#7 0x00007ffff79face8 in CEGUI::Window::setText (this=0xb91ea0, text=...) at ../../../cegui/src/CEGUIWindow.cpp:881
#8 0x00007ffff7a818cd in CEGUI::Tooltip::setTargetWindow (this=0xb91ea0, wnd=0x954830) at ../../../cegui/src/elements/CEGUITooltip.cpp:154
#9 0x00007ffff7a01161 in CEGUI::Window::onMouseEnters (this=0x954830, e=...) at ../../../cegui/src/CEGUIWindow.cpp:2871
#10 0x00007ffff79ec5cf in CEGUI::System::updateWindowContainingMouse (this=0x6d46a0) at ../../../cegui/src/CEGUISystem.cpp:1733
#11 0x00007ffff79ec228 in CEGUI::System::mouseMoveInjection_impl (this=0x6d46a0, ma=...) at ../../../cegui/src/CEGUISystem.cpp:1639
#12 0x00007ffff79ea158 in CEGUI::System::injectMousePosition (this=0x6d46a0, x_pos=345, y_pos=478) at ../../../cegui/src/CEGUISystem.cpp:985
The crazy thing about this is, that I've looked over the code and this should be working. The d_lines collection in RenderedString where it crashes contains a totally incorrect return value from size(), which indicates something going horribly wrong either in the parsing / formatting or with general memory corruption. I don't think it's a case that the string was not processed yet, as the std::vector should report a size() of 0. I need to investigate this further.
Ok, all this aside. The times when I did see rendering, things were also not as I would have liked, but perfectly expected and explainable. Basically, the various TextComponents were all overlapping each other - this is expected since the areas defined in the looknfeel are all the same. To arrange things differently would require either the areas to be set differently, though that requires prior knowledge of the size (height) of the formatted content, and is likely a non starter, or to use some other means to lay out the individual strings - such as using the Tooltip as a container for some other lightweight label rendering window. I think using the container / label approach would allow you to have each label size itself, and have the host Tooltip set its height to the sum of the child label heights. If that works correctly, it works around the bugs and sidesteps the shortcomings that using TextComponent currently presents. Additionally you would/could use PropertyLinkDefinition elements on the Tooltip to link to the Text property of the component label windows (created using Child tags).
Adding those things is a slightly bigger job, of course, and while I think it would work I can't say for sure without having tested it So, the usual thing applies here, you could have a go yourself, or let me know if not, and I'll have a stab at it in a couple of weeks or so.
CE.
Useful Links: Forum Guidelines | Documentation | Tutorials | HOWTO | Videos | Donate to CEGUI | CEGUI Twitter
Re: Custom tooltip
Regarding the container / label approach, do you mean to add multiple static text in the tooltip window? Is it similar to add sub-window "__auto_titlebar__" on the widget FrameWindow? I don't know if it's easy to add sub-window. At least I have no experience on it.
For this approach, are the works all in the looknfeel? Or which extra code do I need to rewrite it?
For this approach, are the works all in the looknfeel? Or which extra code do I need to rewrite it?
- CrazyEddie
- CEGUI Project Lead
- Posts: 6760
- Joined: Wed Jan 12, 2005 12:06
- Location: England
- Contact:
Re: Custom tooltip
I would definitely not use StaticText, it's way to heavyweight for most purposes and that totally sucks.
The correct choice for the multiple label approach, I think, is to create a lightweight label type, which basically just draws a formatted string - the base case for this can actually be done entirely in XML (mainly looknfeel - in the simplest case, containing just an ImagerySection with TextComponent, - though you would need a scheme entry to specify the new type, mapping a default window using the default window renderer to some type name string). Because you need the content to size itself, you likely will need some kind of supporting code to handle that - another alternative might be to make use of the LayoutContainer classes, which may be enough to get you what you want, though that does add another layer of complexity due to the fact you'll likely want property links to expose the label content.
I can't give absolute answers regarding this, as this is basically 'one possible solution' I came up with, and I'm sure there are potential issues that may not have occurred to me immediately. It's definitely something that is do-able, though as you likely guessed - as with all things - it's selecting the lesser of the evils, rather than finding some perfect solution.
There does, of course, always remain the option of a custom Tooltip subclass. I - as the library creator - tend to think first for more generic options - especially ones that minimise c/c++ coding and CEGUI library customisation or modification. Though there are definitely times when a custom class ends up being easier in the long run - especially if you're doing that custom code for a specific project (which most users obviously are, and this is something I tend to overlook, sometimes ).
CE.
The correct choice for the multiple label approach, I think, is to create a lightweight label type, which basically just draws a formatted string - the base case for this can actually be done entirely in XML (mainly looknfeel - in the simplest case, containing just an ImagerySection with TextComponent, - though you would need a scheme entry to specify the new type, mapping a default window using the default window renderer to some type name string). Because you need the content to size itself, you likely will need some kind of supporting code to handle that - another alternative might be to make use of the LayoutContainer classes, which may be enough to get you what you want, though that does add another layer of complexity due to the fact you'll likely want property links to expose the label content.
I can't give absolute answers regarding this, as this is basically 'one possible solution' I came up with, and I'm sure there are potential issues that may not have occurred to me immediately. It's definitely something that is do-able, though as you likely guessed - as with all things - it's selecting the lesser of the evils, rather than finding some perfect solution.
There does, of course, always remain the option of a custom Tooltip subclass. I - as the library creator - tend to think first for more generic options - especially ones that minimise c/c++ coding and CEGUI library customisation or modification. Though there are definitely times when a custom class ends up being easier in the long run - especially if you're doing that custom code for a specific project (which most users obviously are, and this is something I tend to overlook, sometimes ).
CE.
Useful Links: Forum Guidelines | Documentation | Tutorials | HOWTO | Videos | Donate to CEGUI | CEGUI Twitter
Re: Custom tooltip
I am trying to following your suggestion and added two simple Label in the tooltip2 in the looknfeel file as follows.
And the scheme file is as follows.
I only rewrote the function "FalagardTooltip1::getTextSize()" in the renderer tooltip1 as follows.
My first step is to see all the text but it failed. I think the two child labels are inside the tooltip window and I can find two children in the window.
When I set the text as follows, I only can see the first text "1234567890". I am sure "MainText" and "FloatText" are in the text of two children because I watched the memory.
tooltipWindow:setText("1234567890")
tooltipWindow:setProperty("MainText", "aaaaaaaaaaaaaaaaaaaaa")
tooltipWindow:setProperty("FloatText", "tttttttttttttt")
I don't know why I can't see "MainText" and "FloatText". Please give me some suggestions.
Code: Select all
<!--
***************************************************
game1/Label
***************************************************
-->
<WidgetLook name="game1/Label">
<ImagerySection name="main">
<TextComponent>
<Area>
<Dim type="LeftEdge" ><AbsoluteDim value="0" /></Dim>
<Dim type="TopEdge" ><AbsoluteDim value="0" /></Dim>
<Dim type="Width" ><UnifiedDim scale="1" type="Width" /></Dim>
<Dim type="Height" ><UnifiedDim scale="1" type="Height" /></Dim>
</Area>
<Colours topLeft="FFFFFFFF" topRight="FFFFFFFF" bottomLeft="FFFFFFFF" bottomRight="FFFFFFFF" />
<VertFormat type="CentreAligned" />
<HorzFormat type="LeftAligned" />
</TextComponent>
</ImagerySection>
<StateImagery name="Enabled">
<Layer>
<Section section="main" />
</Layer>
</StateImagery>
<StateImagery name="Disabled">
<Layer>
<Section section="main" />
</Layer>
</StateImagery>
</WidgetLook>
<!--
***************************************************
game1/Tooltip2
***************************************************
-->
<WidgetLook name="game1/Tooltip2">
<PropertyLinkDefinition name="MainText" widget="__auto_text__" targetProperty="Text" initialValue="" />
<PropertyLinkDefinition name="FloatText" widget="__auto_floattext__" targetProperty="Text" initialValue="" />
<NamedArea name="TextArea">
<Area>
<Dim type="LeftEdge" ><ImageDim imageset="game1" image="TooltipLeftEdge" dimension="Width" /></Dim>
<Dim type="TopEdge" ><ImageDim imageset="game1" image="TooltipTopEdge" dimension="Height" /></Dim>
<Dim type="RightEdge" >
<UnifiedDim scale="1" type="RightEdge">
<DimOperator op="Subtract">
<ImageDim imageset="game1" image="TooltipRightEdge" dimension="Width" />
</DimOperator>
</UnifiedDim>
</Dim>
<Dim type="BottomEdge" >
<UnifiedDim scale="1" type="BottomEdge">
<DimOperator op="Subtract">
<ImageDim imageset="game1" image="TooltipBottomEdge" dimension="Height" />
</DimOperator>
</UnifiedDim>
</Dim>
</Area>
</NamedArea>
<ImagerySection name="main">
<FrameComponent>
<Area>
<Dim type="LeftEdge" ><AbsoluteDim value="0" /></Dim>
<Dim type="TopEdge" ><AbsoluteDim value="0" /></Dim>
<Dim type="Width" ><UnifiedDim scale="1" type="Width" /></Dim>
<Dim type="Height" ><UnifiedDim scale="1" type="Height" /></Dim>
</Area>
<Image type="TopLeftCorner" imageset="game1" image="TooltipTopLeft" />
<Image type="TopRightCorner" imageset="game1" image="TooltipTopRight" />
<Image type="BottomLeftCorner" imageset="game1" image="TooltipBottomLeft" />
<Image type="BottomRightCorner" imageset="game1" image="TooltipBottomRight" />
<Image type="LeftEdge" imageset="game1" image="TooltipLeftEdge" />
<Image type="RightEdge" imageset="game1" image="TooltipRightEdge" />
<Image type="TopEdge" imageset="game1" image="TooltipTopEdge" />
<Image type="BottomEdge" imageset="game1" image="TooltipBottomEdge" />
<Image type="Background" imageset="game1" image="TooltipMiddle" />
</FrameComponent>
</ImagerySection>
<ImagerySection name="text">
<TextComponent>
<Area>
<Dim type="LeftEdge" ><ImageDim imageset="game1" image="TooltipLeftEdge" dimension="Width" /></Dim>
<Dim type="TopEdge" ><ImageDim imageset="game1" image="TooltipTopEdge" dimension="Height" /></Dim>
<Dim type="RightEdge" >
<UnifiedDim scale="1" type="RightEdge">
<DimOperator op="Subtract">
<ImageDim imageset="game1" image="TooltipRightEdge" dimension="Width" />
</DimOperator>
</UnifiedDim>
</Dim>
<Dim type="BottomEdge" >
<UnifiedDim scale="1" type="BottomEdge">
<DimOperator op="Subtract">
<ImageDim imageset="game1" image="TooltipBottomEdge" dimension="Height" />
</DimOperator>
</UnifiedDim>
</Dim>
</Area>
<Colours topLeft="FF000000" topRight="FF000000" bottomLeft="FF000000" bottomRight="FF000000" />
<VertFormat type="CentreAligned" />
<HorzFormat type="CentreAligned" />
</TextComponent>
</ImagerySection>
<Child type="game1/Label" nameSuffix="__auto_text__">
<Area>
<Dim type="LeftEdge" ><AbsoluteDim value="0" /></Dim>
<Dim type="TopEdge" ><AbsoluteDim value="0" /></Dim>
<Dim type="Width" ><UnifiedDim scale="1" type="Width" /></Dim>
<Dim type="Height" ><AbsoluteDim value="24" /></Dim>
</Area>
<Property name="MousePassThroughEnabled" value="True" />
</Child>
<Child type="game1/Label" nameSuffix="__auto_floattext__">
<Area>
<Dim type="LeftEdge" ><AbsoluteDim value="0" /></Dim>
<Dim type="TopEdge" ><WidgetDim widget="__auto_text__" dimension="Height" /></Dim>
<Dim type="Width" ><UnifiedDim scale="1" type="Width" /></Dim>
<Dim type="Height" ><AbsoluteDim value="24" /></Dim>
</Area>
<Property name="MousePassThroughEnabled" value="True" />
</Child>
<StateImagery name="Enabled">
<Layer>
<Section section="main" />
<Section section="text" />
</Layer>
</StateImagery>
<StateImagery name="Disabled">
<Layer>
<Section section="main" />
<Section section="text" />
</Layer>
</StateImagery>
</WidgetLook>
And the scheme file is as follows.
Code: Select all
<FalagardMapping WindowType="game1/Label" TargetType="DefaultWindow" Renderer="Falagard/Default" LookNFeel="game1/Label" />
<FalagardMapping WindowType="game1/Tooltip2" TargetType="CEGUI/Tooltip" Renderer="Falagard/Tooltip1" LookNFeel="game1/Tooltip2" />
I only rewrote the function "FalagardTooltip1::getTextSize()" in the renderer tooltip1 as follows.
Code: Select all
Size FalagardTooltip1::getTextSize() const
{
Tooltip* w = (Tooltip*)d_window;
// get WidgetLookFeel for the assigned look.
const WidgetLookFeel& wlf = getLookNFeel();
Size sz(200, 200);
Rect textArea(wlf.getNamedArea("TextArea").getArea().getPixelRect(*w));
Rect wndArea(w->getArea().asAbsolute(w->getParentPixelSize()));
sz.d_width = PixelAligned(sz.d_width + wndArea.getWidth() - textArea.getWidth());
sz.d_height = PixelAligned(sz.d_height + wndArea.getHeight() - textArea.getHeight());
return sz;
}
My first step is to see all the text but it failed. I think the two child labels are inside the tooltip window and I can find two children in the window.
When I set the text as follows, I only can see the first text "1234567890". I am sure "MainText" and "FloatText" are in the text of two children because I watched the memory.
tooltipWindow:setText("1234567890")
tooltipWindow:setProperty("MainText", "aaaaaaaaaaaaaaaaaaaaa")
tooltipWindow:setProperty("FloatText", "tttttttttttttt")
I don't know why I can't see "MainText" and "FloatText". Please give me some suggestions.
Return to “Modifications / Integrations / Customisations”
Who is online
Users browsing this forum: Bing [Bot] and 7 guests