Customization of GUI Appearance

Discussion regarding the development of CEGUI itself - as opposed to questions about CEGUI usage that should be in the help forums.

Moderators: CEGUI MVP, CEGUI Team

User avatar
Falagard
Just popping in
Just popping in
Posts: 12
Joined: Wed Jan 12, 2005 12:06

Customization of GUI Appearance

Postby Falagard » Thu May 13, 2004 03:06

I've noticed in your previous version of the GUI that it uses a single .tga file to define the look of the various borders, corners, buttons, etc. for the GUI. Although I haven't delved deep into your GUI code, was it possible to specify different configuration files for each control?

Does Mk2 plan to support appearance customization on a per control basis?

Is it possible to use a different background texture for a particular window, for example?

I'd like to use your GUI system for an RPG game, and to make things look decent, there are usually requirements for different customized windows appearances. Here are some screenshots of a game I've been playing for the last few days called Guild Wars. I am sure that your GUI system could handle the same GUI that Guild Wars has from a feature perspective, (with the exception perhaps of drag and drop?) but from a artistic perspective, does your GUI system have the ability to be customized enough to produce something like this?

http://www.larabie.net/jet/GuildWars1.jpg
http://www.larabie.net/jet/GuildWars2.jpg
http://www.larabie.net/jet/GuildWars3.jpg

Needless to say, I'm very excited about your GUI. I've used a very good game GUI system in the past using a commercial game engine, but even it lacked some of your features such highlighting and selecting text, allowing copy/paste, and create list box controls. It did have pretty good customization of controls, and a WYSIWYG editor though. Each control could specify a configuration file that contained its look and feel. The configuration file was somewhat similar to yours. Each dialog was also a seperate configuration file that was used for layout of the controls, and therefore it was easy to modify the appearance without having to do it in code.

Just curious if you have any plans to support these sort of features.

Thanks, and keep up the great work!

Clay

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

Customization of GUI Appearance

Postby CrazyEddie » Thu May 13, 2004 08:38

It was always, and will remain, possible to use as many files as you wished when defining imagery for the various controls. Personally I think that one image per control is wasteful, hence the approach that I took (plus those graphics were supplied to me like that ;))

To answer you questions about customisation: it depends :) It's always *possible*, because if it comes to the worst case scenario then you can create a new control class that does what you need. Whether all the controls will support every customisation "out-of-the-box" as it were, then the answer is more correctly a probably not, since to try and cater for every possible option would make the job very difficult and at some stage you get locked into thinking about things a certain way. What I have tried to do here (in all versions) is have the control logic in a base class and rendering code in a derived class - this enables the system to be customised in any conceivable way, but requires the programmer using the system to do a little more work than just call a few methods (though not much more work).

The kind of things in those screen shots is definately possible, with a little work.. I don't know if you saw the screen shot that alipolatolu posted yesterday, but this shows the beginnings of a window style that is totally different from my demos and show's the tip of the iceberg of what is possible.

The config files and what have you are in XML for mk2. I intned to provide a dialog editor and a Imageset editor at a later stage. You mention customisation without using code, it is my hope that the system will achive a 'middle-ground' via what is available in the provided example widget sets and the possibilities provided via scripting support. Though I would consider it possible to provide a 'similar' look to those screenshots by modifying imagery alone.

I hope that this answers at least some of your questions, in any event I'm always willing to help wherever I can to enable people to achieve the results they are looking for.

User avatar
Falagard
Just popping in
Just popping in
Posts: 12
Joined: Wed Jan 12, 2005 12:06

Customization of GUI Appearance

Postby Falagard » Fri May 14, 2004 03:05

I think we misunderstood one another to an extent. I've looked at the source code for the Taharez and Windows Look demos and it surprised me that each required custom classes for the different appearances.

Instead of having to create custom classes, I was asking if it's possible to use a data driven approach, which it currently is not.

I think it's great to have the flexibility of being able to do your own custom appearances by actually overriding the rendering of the buttons, but I assumed (before looking at the source) that the WinLook.sdf.txt and CEGUI.sdf.txt files contained the information about how to customize the controls without having to override the render functions of the controls.

I think that most of the customization that is required for a GUI could be data driven instead having to create custom classes. Or at least that there should be a data driven default implementation that can be overridden if you need to do something that isn't supported by the default implementation. If people want to do something very custom that is not support by using config files, they can, but for most cases it should not be necessary given a flexible configuration system.

Here's an example of an appearance config file format I just made up that can handle lots of different requirements. This config file could be used for defining the background, border, and corners of a control, through the use of align = top, bottom, left, right, topleft, topright, bottomleft, bottomright but also with additional center and middle alignments you could do even more. What you'd do is have one of these config files for each of the states that a control can have, so that normal, hover, pressed, etc. each have their own config file, or they are share entries in a single config file.

The config file itself doesn't contain the values for an individual control, it describes the visual appearance of the control. For example,
myButton.SetNormalAppearance( "WindowsButtonNormal.config.txt" );
myButton.SetPressedAppearance("WindowsButtonPressed.config.txt");
myButton.SetText( "Okay" );
myButton.SetTextAlignment( JUST_CENTER );

Okay, here's an example.

Layers are just like they sound, rendered on top of each other in layers. Everything in a layer is rendered first, then the next layer is rendered, etc. Multiple parts make up a layer. For example, each corner of a window control would be a part, which specifies its alignment, tiling information, which image to use, etc.

A part has:
description - just for demonstrative purposes to let you know what this part does
align - top, left, bottom, right, topleft, topright, bottomleft, bottomright, center, middle - where this part should be rendered
tile - none, vertical, horizontal, both. How this part should tile. If align = top and tile = horizontal, the part will tile across the top of the control.
image - this describes what image to use for this part, including a src file, and the area of the source file to retrieve the image from. This allows you to use a single .tga with all your sprites, or seperate images for each.
indent - this is how much space should be left around the image. For example, although the top edge is aligned top and tile is horizontal, the indent says to leave 4 pixels of space on the right and left sides of the part. The indent is important because it basically allows you to position an image a certain distance from the aligned side, and clips the image if it extends past the indents on the other side.

That's pretty much it. I haven't actually put in real values for the image area top and left properties, but based on height and width being 4 pixels, the indents are pretty much correct. Couldn't use > and < so I put in curly braces.

Code: Select all

{layer}
  {part}
    {description}background{/description}
    {align}none{/align}
    {tile}both{/tile}
    {image}
      {src}GUI.tga{/src}
      {area}
        {left}0{/left}
        {top}0{/top}
        {height}32{/height}
        {width}32{/width}
      {/area}
    {/image}
    {indent}
      {left}4{/left}
      {top}4{/top}
      {right}4{/right}
      {bottom}4{/bottom}
    {/indent}
  {/part}
{/layer}
{layer}
  {part}
    {description}top edge{/description}
    {align}top{/align}
    {tile}horizontal{/tile}
    {image}
      {src}GUI.tga{/src}
      {area}
        {left}0{/left}
        {top}0{/top}
        {height}4{/height}
        {width}4{/width}
      {/area}
    {/image}
    {indent}
      {left}4{/left}
      {top}0{/top}
      {right}4{/right}
      {bottom}0{/bottom}
    {/indent}
  {/part}
  {part}
    {description}bottom edge{/description}
    {align}bottom{/align}
    {tile}horizontal{/tile}
    {image}
      {src}GUI.tga{/src}
      {area}
     {left}0{/left}
        {top}0{/top}
        {height}4{/height}
        {width}4{/width}
      {/area}
    {/image}
    {indent}
      {left}4{/left}
      {top}0{/left}
      {right}4{/left}
      {bottom}0{/bottom}
    {/indent}
  {/part}
  {part}
    {description}left edge{/description}
    {align}left{/align}
    {tile}vertical{/tile}
    {image}
      {src}GUI.tga{/src}
      {area}
     {left}0{/left}
        {top}0{/top}
        {height}4{/height}
        {width}4{/width}
      {/area}
    {/image}
    {indent}
      {left}0{/left}
      {top}4{/left}
      {right}0{/left}
      {bottom}4{/bottom}
    {/indent}
  {/part}
  {part}
    {description}right edge{/description}
    {align}right{/align}
    {tile}vertical{/tile}
    {image}
      {src}GUI.tga{/src}
      {area}
     {left}0{/left}
        {top}0{/top}
        {height}4{/height}
        {width}4{/width}
      {/area}
    {/image}
    {indent}
      {left}0{/left}
      {top}4{/left}
      {right}0{/left}
      {bottom}4{/bottom}
    {/indent}
  {/part}
  {part}
    {description}top left corner{/description}
    {align}topleft{/align}
    {tile}none{/tile}
    {image}
      {src}GUI.tga{/src}
      {area}
     {left}0{/left}
        {top}0{/top}
        {height}4{/height}
        {width}4{/width}
      {/area}
    {/image}
    {indent}
      {left}0{/left}
      {top}0{/left}
      {right}0{/left}
      {bottom}0{/bottom}
    {/indent}
  {/part}
  {part}
    {description}top right corner{/description}
    {align}topright{/align}
    {tile}none{/tile}
    {image}
      {src}GUI.tga{/src}
      {area}
     {left}0{/left}
        {top}0{/top}
        {height}4{/height}
        {width}4{/width}
      {/area}
    {/image}
    {indent}
      {left}0{/left}
      {top}0{/left}
      {right}0{/left}
      {bottom}0{/bottom}
    {/indent}
  {/part}
  {part}
    {description}bottom left corner{/description}
    {align}bottomleft{/align}
    {tile}none{/tile}
    {image}
      {src}GUI.tga{/src}
      {area}
     {left}0{/left}
        {top}0{/top}
        {height}4{/height}
        {width}4{/width}
      {/area}
    {/image}
    {indent}
      {left}0{/left}
      {top}0{/left}
      {right}0{/left}
      {bottom}0{/bottom}
    {/indent}
  {/part}
  {part}
    {description}bottom right corner{/description}
    {align}bottomright{/align}
    {tile}none{/tile}
    {image}
      {src}GUI.tga{/src}
      {area}
     {left}0{/left}
        {top}0{/top}
        {height}4{/height}
        {width}4{/width}
      {/area}
    {/image}
    {indent}
      {left}0{/left}
      {top}0{/left}
      {right}0{/left}
      {bottom}0{/bottom}
    {/indent}
  {/part}   
{/layer}


Of course, I'm not trying to pressure you, I'm just trying to make suggestions. This solution will not work for everyone, but I think it handles a large majority as I have worked with something similar in the past which had no customizability beyond similar config files, and it worked like a charm.

If you don't implement something like this, then it's possible I'll give it a shot. :-) I'm not one of those people that begs for features without trying to implement them myself :-)

Clay

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

Customization of GUI Appearance

Postby CrazyEddie » Fri May 14, 2004 08:31

Thanks for the post clarifying your original point.

I basically agree with your idea - I should really have come up with something like this myself, oh well :roll:

Anything I do like this will be for the Mk-2 system only at this stage. There are too many other issues with Mk-1 and I don't see it's worth the investment (though it could be basically back-ported to Mk-1 later).

I'd also say that in order to keep from throwing the project off the rails completely, the approach I'd have to take will be to continue in the same way I am at the moment, in order to get the core functionality in, and then once that is done, create a set of specialised classes that implement the data-driven system that you describe (or similar). This way I do not break the overall design of the system, and the final result would offer the best of both worlds. Additionally, anyone not interested in a 100% data-driven system (or more correctly, anyone who doesn't want to wait any longer) can happily use the system via the other classes provided.

User avatar
Falagard
Just popping in
Just popping in
Posts: 12
Joined: Wed Jan 12, 2005 12:06

Customization of GUI Appearance

Postby Falagard » Sun May 16, 2004 23:53

Sounds great. Glad to see you like the suggestion.

One of the nice benefits of such a system is that artists can create designs for controls without having to ask a programmer to do any additional coding.

Another suggestion is to come up with a different layout config file which is used for actually laying out a GUI. You would usually have one of these per dialog/window, and it contains the window and all controls on the window, their positions and values, etc.

Here's an example of one of these files:


Code: Select all

{control}
  {controlproperties}
    {type}window{/type}
    {name}mywindow{/name}
    {position}
      {top}50{/top}
      {left}50{/left}
      {height}200{/height}
      {width}200{/width}
    {/position}
    {normalconfig}windownormalconfig.txt{/normalconfig}
    {hoverconfig}windownormalconfig.txt{/hoverconfig}
    {pressedconfig}windownormalconfig.txt{/pressedconfig}
  {/controlproperties}
  {windowproperties}
    {title}My Window Title{/title}
    {resizable}false{/resizable}
    {fixed}true{/fixed}
  {/window}
  {childcontrols}
    {control}
      {controlproperties}
        {type}button{/type}
        {name}testbutton{/name}
        {position}
          {top}{/top}
          {left}{/left}
          {height}{/height}
          {width}{/width}
        {/position}
        {normalconfig}buttonnormalconfig.txt{/normalconfig}
        {hoverconfig}buttonhoverconfig.txt{/hoverconfig}
        {pressedconfig}buttonpressedconfig.txt{/pressedconfig}
      {/controlproperties}
      {staticproperties}
        {font}Arial{/font}
        {multiline}false{/multiline}
      {/staticproperties}
      {buttonproperties}
        {somecustombuttonproperty}true{/somecustombuttonproperty}
      {/buttonproperties}
    {/control}
  {/childcontrols}
{/control}


As you can see this is a window with a button. This example shows a control section, with controlproperties that every control has, and then windowproperties that are custom to the window control. In this case, assuming button inherits from a class called "static", then you get controlproperties, staticproperties, and buttonproperties. This is nice because each class can load its own properties and the base class can load its properties, etc.

Then from code, I'd open this GUI by loading it, and then ask for controls by name:

Code: Select all

Dialog *dialog = new Dialog();
dialog->Load( "MyGUI.txt" );
Window *myWindow = dialog->GetControl("mywindow");
Button *testButton = dialog->GetControl("testbutton");
testButton->SetClickedCommand( myCommand );


And therefore don't have to worry about laying out the controls manually. It lets the artists lay out controls, and visual appearance through the other config files (normalconfig, pressedconfig, etc.) without any code changes required.

Clay

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

Customization of GUI Appearance

Postby CrazyEddie » Mon May 17, 2004 08:28

Hi Clay,

Yeah, the ability to create a dialog / window from a data file is something that I have always intended to do.

For the Mk1 system this became something that got put off time and time again, and ultimately other things I did not like with the system prevented me from finally implementing the feature.

For the Mk2 system (once a few more bits are in there) this will be very, very, simple to do, since all stuff will be accessible by name anyway. So you can literally grab the details out of the config / layout file and pump these into the GUI system (this is one of the two main reasons why the design has these features, the other reason is scripting support).

User avatar
gcarlton
Just can't stay away
Just can't stay away
Posts: 149
Joined: Wed Jan 12, 2005 12:06

Customization of GUI Appearance

Postby gcarlton » Fri Oct 29, 2004 05:53

I've also been thinking along similar lines (the last place I worked also had a custom gui library with a data driven approach as well). And again, I've been thinking I'll give it a shot eventually if nobody else does.. not for a while yet though.

To throw some new ideas into the mix, here is the way we did it:
Widgets could have a "style", which is just a set of data, like above. However, this is broken up into a set of "appearance" layers. Each had a set of conditions, and then the data for the apperance. To render, it iterated the list looking for the first appearance that matched the condition flags.

The conditions were essentially a set of flags and whether each matched to true or false. They matched things like enabled, rollover (cursor over the widget), pressed, active (which was really a widget specific state). The widget then just set all the states, and it could work out which appearance to use. As an example, a button style may have 5 apperances, with these conditions:
1.) !enabled
2.) pressed & rollover
3.) pressed
4.) rollover
5.) default
Since its in order, if the button is disabled, it always has the first apperance (greyed out). Otherwise, it would choose one of the others - if nothing matches, it falls through to the default apperance.

That worked very nicely, and allowed very powerful control without much coupling to the widget itself.

The actual appearance data used an underlying type I think - we always used the 3x3 appearance type, which had 9 "cells" in a 3x3 grid. Each cell had an image (and texture tiling: single, repeat, or stretched), the cell size, or leave the cell size stretch. e.g. a button may have a set of fixed 8 pixel border textures, with a large stretchy part in the middle. This worked well, although just listing the parts (as described in the previous post) looks pretty powerful too, and easier to implement.

There were also higlights, to overlay a colour over the entire cell or set of cells, so it was easy to add "rollover" highlights, which allowed the gui to look very responsive. Lastly, even progress/slider bar styles were simple to make up - I can't exactly remember how it handled them, but it involved adding another appearance and the widget must have rendered that appearance partway across (Thus it must have rendered two apperances somehow.. Hmm). In fact, there wasn't a difference between progress or sliders, they were all just styles that looked a bit different.

A single widget, like a button, had maybe a dozen different styles.. it was pretty cool. You could everything from a button that looked "pressed" in, a picture that had a yellow higlight when pressed, or an image that changed completely when pressed.

This system was obviously very complex; new features were generally implemented as extensions to the style system rather than hard coding them. I think a fully featured gui should be able to support both. (sometimes you just want to jump in an code up some very specific behaviour, like the amazing worms3d gui).

No big need to get such a system up and running, but I want to jot this stuff down before I forgot how it all worked. :)

PS: Probably not good timing to post this before your break CE - don't really want you to spend it thinking about gui stuff! ;)

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

Customization of GUI Appearance

Postby CrazyEddie » Fri Oct 29, 2004 08:32

Cool :) Thanks for the additional input. I'll think about all this some more when I return :lol:

When I do come back I'll be pushing forward with most of the new features, so should actually get to start implementing this data driven approach hopefully in January or February of next year (which implies that everything else will be donw by then, as this is the 'big one' that I'm leaving until last).

CE.

User avatar
Falagard
Just popping in
Just popping in
Posts: 12
Joined: Wed Jan 12, 2005 12:06

Customization of GUI Appearance

Postby Falagard » Fri Oct 29, 2004 13:51

Awesome. Enjoy your well deserved break, and great job on the GUI system.

Clay


Return to “CEGUI Library Development Discussion”

Who is online

Users browsing this forum: No registered users and 8 guests