Custom Widgets and Themes

Started by Xdesign, 17 January 2022, 22:28:45

Xdesign

I've looked up almost every page there is on themes and renderers and im really stuck!
I've made a lot of custom widgets with most of them direved from tgui::Panel.
Im currently making theming system and i cant figure how to load custom widgets from theme file.
I made this and is working:
deafult.txt (Theme file)
TaskCard{
  BackgroundColor = (0,0,0);
  ...
}
with setRenderer(theme->getRenderer("TaskCard"));
But how to load children?
I mean what i got working is for every Custom widget i have seperated name in theme.txt like:

TaskCard{
...
}
TaskCard>Group{
...
}
TaskCard>CheckedGroup{
...
}

This is what im trying is to load them the way they are supposed to be loaded:
TaskCard{
    BackgroundColor = (0,0,0);
    ...
    CheckedGroup = {
        BackgroundColor = (0,0,0);
        ...
    }
    UnavailableGroup= {
           BackgroundColor = (255,0,0);
           ...
    }
}
I guess with custom widgets i need custom renderers?

texus

If you want custom properties (i.e. define something other than properties such as BackgroundColor that already exist in the base classes) then you need to override the "void rendererChanged(const String& property)" function in your custom widget. It will be called with the name of the property (e.g. "BackgroundColor") when loading the theme. You can look at existing widgets for what the function should contain.

I don't think subsections are supported. You will have to make a CheckedGroupBackgroundColor property instead of having a section called CheckedGroup that contains a BackgroundColor property.

Xdesign

Well ill try that now.
But anyway its not just BackgroundColor propertie. Its all tgui::Panel has because Group Class is derived from tgui::Panel so that got me thinking its possible

texus

I seem to have been underestimating the amount of required work yesterday.

You will indeed need your own renderer class in combination with rendererChanged.
And you can use nested sections, see e.g. "Scrollbar" property in Label. It is used to load a renderer of a subwidget though, so not if you simply want to group some properties.

I even wrote down the required code for custom renderers in my tutorials a while ago: https://tgui.eu/tutorials/0.10/custom-widgets/#changing-renderer

Xdesign

#4
First of all sry for obvious questions and late replies, feel free to answer whenever.
Also i didnt explain myself well before, sorry for that.

I made custom Renderer and got errors.
Here is one CustomRenderer:


HabitCardRenderer.h

#pragma once
#include <TGUI/TGUI.hpp>
#include <TGUI/Backend/SFML-Graphics.hpp>
#include <SFML/Graphics.hpp>

class HabitCardRenderer : public tgui::PanelRenderer
{
public:
   using tgui::PanelRenderer::PanelRenderer;
   
   std::shared_ptr<tgui::RendererData> getNameLabel() const;
   void setNameLabel(std::shared_ptr<tgui::RendererData> namelabelRenderer);

   std::shared_ptr<tgui::RendererData> getEditButton() const;
   void setEditButton(std::shared_ptr<tgui::RendererData> editbuttonRenderer);

   std::shared_ptr<tgui::RendererData> getTask() const;
   void setTask(std::shared_ptr<tgui::RendererData> taskRenderer);

};


HabitCardRenderer.cpp

#include <TGUI/RendererDefines.hpp>
TGUI_RENDERER_PROPERTY_RENDERER(HabitCardRenderer, NameLabel, "NameLabel")
TGUI_RENDERER_PROPERTY_RENDERER(HabitCardRenderer, EditButton, "EditButton")
TGUI_RENDERER_PROPERTY_RENDERER(HabitCardRenderer, Task, "Task")


TGUI_RENDERER_PROPERTY_RENDERER is giving me errors whatever i do.
for this code its giving me "name followed by '::' must be a class or namespace name"

TGUI_RENDERER_PROPERTY_COLOR is working tho like in tutorials


Other problem i have is that i cant figure out third parametar for TGUI_RENDERER_PROPERTY_RENDERER which is RENDERER
Is this a Renderer class name?

Let's say i want my CustomRenderer to have 2 Labels Renderers.
Do i code in cpp file someting like this?
TGUI_RENDERER_PROPERTY_RENDERER(CustomWidget, Label1, "LabelRenderer");
TGUI_RENDERER_PROPERTY_RENDERER(CustomWidget, Label2, "LabelRenderer");

Or is this "LabelRenderer" what i type in theme.txt

I mean i looked up WindowChildRenderer and for example:
In ChildWindow.cpp , in function  void ChildWindow::rendererChanged(const String& property)
it says :
       else if (property == "MaximizeButton")
         {
                ...
                m_maximizeButton->setRenderer(getSharedRenderer()->getMaximizeButton());
                ...
        }
  while in
ChildWindowRenderer.cpp it says "ChildWindowButton"
in TGUI_RENDERER_PROPERTY_RENDERER(ChildWindowRenderer, CloseButton, "ChildWindowButton")

My guess ChildWindowButton is base class of CloseButton, MaximizeButton and MinimizeButton i just dont know how :D

Anyway, thanks for support!


texus

#5
Quotefor this code its giving me "name followed by '::' must be a class or namespace name"
There seems to be a bug in TGUI_RENDERER_PROPERTY_RENDERER that requires your custom class to be in the "tgui" namespace, otherwise the code doesn't compile. It's because the code uses "Theme" instead of "tgui::Theme".
Edit: adding "using Theme = tgui::Theme;" before "#include <TGUI/RendererDefines.hpp>" seems a better workaround though. Then you don't need to put your class in the tgui namespace.

QuoteOther problem i have is that i cant figure out third parametar for TGUI_RENDERER_PROPERTY_RENDERER which is RENDERER
I had to check the code to figure this out, it could have been named better (e.g. FALLBACK_RENDERER).
- if the ChildWindow section in the theme contains a MaximizeButton subsection then this will be used for the renderer (MaximizeButton = second parameter to TGUI_RENDERER_PROPERTY_RENDERER)
- Otherwise, a ChildWindowButton section is searched in the root of the theme (i.e. NOT a subsection of ChildWindow). (ChildWindowButton = third parameter to TGUI_RENDERER_PROPERTY_RENDERER)
- Otherwise, an empty renderer object is used for the maximize button

I'm actually not sure if the fallback works though. So I wouldn't rely on it.

Xdesign

Thank you a lot.
You are big help, as always!
Everything is working fine now.