Allegro.cc - Online Community

Allegro.cc Forums » Game Design & Concepts » A question for Steve Terry, Miran, Spellcaster and other GUI people!

This thread is locked; no one can reply to it. rss feed Print
A question for Steve Terry, Miran, Spellcaster and other GUI people!
Steve Terry
Member #1,989
March 2002
avatar

.. Agreed

___________________________________
[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. - planetspace.de
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

Matt Smith
Member #783
November 2000

Not agreed :D

My reasoning is as follows.

It is not possible to use a C++ library in a C program, but a C++ API can be wrapped around a C library.

C is easier to optimise and debug, IMO

My lib is in C, and works fine.

OK, that isn't all exactly objective reasoning, but the first point is hard to argue with.

X-G
Member #856
December 2000
avatar

Quote:

It is not possible to use a C++ library in a C program, but a C++ API can be wrapped around a C library.

Some of Allegro 5's internals are C++, and it will be useable with C. You can link to non-overloaded static C++ functions from C, AFAIK.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Steve Terry
Member #1,989
March 2002
avatar

aigh ok, can it be agreed upon then to have some parts of the GUI in C++ as long as there is NO overloading for C backwards compatibility if it must be done so less work is needed. I'm cool with that idea, but yes we must not limit the audience by using strict C++ code because many will be turned away. I mean that IS the main reason I'm attempting my lib in pure C and it's come a long ways... yet I still have a long way to go. Maybe if someone helps me work on my GUI subsystem aka nas.c, gets relative systems going and some way to do menus/multiple dialogs it'd be good to go. I have an excellent mouse system (at least I think so), I have the font system down with both points accomplished (the && system with TTF and partial strings... I clip mine but I think you mean the ... thing which I have yet to hack out), the skin system could use some help, but it works. But again it's probably best to start over since rewriting the subsytem will probably mean I'd have to propegate though all my other functions and apply any needed changes.. which definately takes time.
Hmm the next thing we need to decide on is... what the dialog container, are we gong with a structure like the cough allegro GUI or maybe a linked list structure, I'm not sure exactly what windows or Xwindows does... maybe a win_main() type callback? Just suggestions.

___________________________________
[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. - planetspace.de
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

Thomas Fjellstrom
Member #476
June 2000
avatar

Signals and slots is where its at :D no WndProc, no callbacks, just signals and slots. :)

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Andrei Ellman
Member #3,434
April 2003

MattSmith said:

It is not possible to use a C++ library in a C program

Another possible way of doing this is to turn the library into a COM object. This is probably overkill and X-G's method may be sufficient, but this is how DirectX works. When I was at Criterion, our game engine (not Renderware, Dive - the one they use internally) was built entirely out of COM objects. We wrote the objects in C++, but they could easily be used by a C program simply because they were COM objects. The downside is that COM only exists natively on Windows (AFAIK), but at Criterion, we managed to create a working multi-platform implementation of COM (at the time I left, we were getting it to work on the Dreamcast). Even with Windows's native COM, it would require quite a bit to get a working COM engine up and running.

Another suggestion for the GUI is to write it in C++, but use a C++ to C translator so the end-user can build a C version of the library if they're using C. I know that such programs exist. In fact, the first ever C++ 'compiler' was really just a C++ to C translator that passed the output to a C compiler.

I'm writing a GUI as part of Chickens which is being written in C. The GUI is the only part of the code where I think writing it in C++ would have been a lot better. Writing the rest of the game in C feels fine to me.

AE.

--
Don't let the illegitimates turn you into carbon.

X-G
Member #856
December 2000
avatar

You know, both C and C++ are compiled down to machine code by the time you link them anyway - the only problem lies in name mangling, and extern "C" { } will take care of that.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Thomas Fjellstrom
Member #476
June 2000
avatar

One thing I'll have to note, In the game I'll probably die before it gets done, will use the game engine for the gui.. all scripted and such. Don't know how possible it'll be to use a premade lib for the handling.. probably impossible. Or at the very least improbable.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

axilmar
Member #1,204
April 2001

Well, personally I prefer C++, but if I am a minority, I am willing to accept C as the language of choice. From what I see, C++ looks scary to some people. C is no problem for me.

If we use C, I propose that we do a clever system with classes like the following:

1struct OBJECT;
2 
3//property descriptor
4typedef struct PROPERTY {
5 int id;
6 const char *name;
7 void (*set)(struct OBJECT *object, const void *value);
8 void (*get)(struct const OBJECT *object, void *value);
9} PROPERTY;
10 
11//object vtable
12typedef struct VTABLE {
13 void *(*get_instance)(struct OBJECT *obj, const char *name);
14} VTABLE;
15 
16//an object's class
17typedef struct CLASS {
18 const char *name;
19 int size;
20 CLASS *super;
21 void (*constructor)(struct OBJECT *obj);
22 void (*destructor)(struct OBJECT *obj);
23 VTABLE *vtable;
24 PROPERTY *properties;
25} CLASS;
26 
27//the object struct
28typedef struct OBJECT {
29 CLASS *rclass; //run time class
30} OBJECT;
31 
32//function that creates an object
33OBJECT *create_object(CLASS *cl, ...);
34 
35//function that destroys an object
36void destroy_object(OBJECT *obj);
37 
38//function that sets an object's properties
39void set_object_properties(OBJECT *obj, ...);
40 
41//function that retrieves an object's properties
42void get_object_properties(OBJECT *obj, ...);

So, classes can be declared like this:

1//widget struct
2typedef struct WIDGET {
3 OBJECT object;
4 int x, y, w, h;
5} WIDGET;
6 
7 
8//widget constructor
9void widget_constructor(OBJECT *obj)
10{
11 WIDGET *wgt = (WIDGET *)obj;
12 wgt->x = 0;
13 wgt->y = 0;
14 wgt->w = 0;
15 wgt->h = 0;
16}
17 
18 
19//widget destructor
20void widget_destructor(OBJECT *obj)
21{
22 //TODO: remove from parent, destroy children
23}
24 
25 
26//widget vtable
27typedef struct WIDGET_VTABLE {
28 VTABLE object_vtable;
29 void (*set_geometry)(WIDGET *wgt, int x, int y, int w, int h);
30} WIDGET_VTABLE;
31 
32 
33//sets the widget's x property
34void widget_set_x(OBJECT *obj, const void *value)
35{
36 WIDGET *wgt = (WIDGET *)obj;
37 wgt->x = *(const int *)value;
38}
39 
40 
41//gets the widget's x property
42void widget_get_x(const OBJECT *obj, void *value)
43{
44 const WIDGET *wgt = (const WIDGET *)obj;
45 *(int *)value = wgt->x;
46}
47 
48 
49//widget properties
50PROPERTY widget_properties[] = {
51 { PROP_X, "x", widget_set_x, widget_get_x },
52 { PROP_Y, "y", widget_set_y, widget_get_y },
53 { PROP_W, "w", widget_set_w, widget_get_w },
54 { PROP_H, "h", widget_set_h, widget_get_h },
55 { 0 }
56};
57 
58 
59//widget class
60CLASS widget_class = {
61 "Widget", //this class is named "Widget"
62 sizeof(WIDGET), //size of struct
63 NULL, //base class
64 widget_constructor, //constructor
65 widget_destructor, //destructor
66 widget_vtable, //widget vtable
67 widget_properties //properties
68};
69 
70//usage
71OBJECT *wgt1 = create_object(&widget_class,
72 PROP_X, 10,
73 PROP_Y, 20,
74 PROP_W, 100,
75 PROP_H, 500,
76 NULL);

In a few words, this is a C interface for doing object-oriented programming, while at the same time allowing COM-style functionality, run-time object identification, single inheritance, and run-time property management for IDEs.

Inheritance works by embedding the super class instance as the first member of the object. Example:

typedef struct BUTTON {
    WIDGET widget;
    char *text;
} BUTTON;

In the above example, OBJECT *, WIDGET * and BUTTON * all point to the same object.

We could also generalize the signals & slots/callbacks/object events/whatever in the following way:

1//a slot
2typedef struct SLOT {
3 NODE node;
4 OBJECT *object;
5 void (*proc)(struct OBJECT *obj);
6} SLOT;
7 
8//a signal
9typedef struct SIGNAL {
10 LIST slots;
11} SIGNAL;
12 
13//emits a signal
14void emit_signal(SIGNAL *signal)
15{
16 for(SLOT *slot = (SLOT *)signal->slots.first; slot; slot = (SLOT *)slot->node.next) {
17 slot->proc(slot->object);
18 }
19}
20 
21//connects a slot to a signal
22void connect_slot(SIGNAL *signal, OBJECT *obj, void (*proc)(OBJECT *obj))
23{
24 SLOT *slot = calloc(1, sizeof(SLOT));
25 slot->object = obj;
26 slot->proc = proc;
27 append_node(&signal->slots, &slot->node);
28}
29 
30//a button with a signal
31typedef struct BUTTON {
32 WIDGET widget;
33 char *text;
34 SIGNAL click;
35} BUTTON;
36 
37//a dialog
38typedef struct DIALOG {
39 WIDGET widget;
40 BUTTON *okButton;
41} DIALOG;
42 
43//called when the dialog is accepted
44void dialog_accept(OBJECT *obj)
45{
46 DIALOG *dlg = (DIALOG *)obj;
47}
48 
49//dialog constructor
50void dialog_constructor(OBJECT *obj)
51{
52 DIALOG *dlg = (DIALOG *)obj;
53 dlg->okButton = (BUTTON *)create_object(&button_class,
54 ID_TEXT, "Ok",
55 NULL);
56 connect_slot(&dlg->okButton->click, obj, dialog_accept);
57}

By the way, we we also need a generalized linked list module, as it is obvious from the above example.

P.S.: if you like the above style of programming, let me know. I can finish the module today.

Richard Phipps
Member #1,632
November 2001
avatar

Argh, you've just depressed me Axilmar! You're far far beyond me in your programming skills. :(
I don't think I'll be much use for this project.. Which is disappointing to me.

:-/

EDIT: I think it's the way you use C to do C++ things. I just can't seem to get my head around C++ concepts. Even concepts in C like pointers get me confused.. :'(

Any chance you can explain what's happening in your code examples?

Thomas Fjellstrom
Member #476
June 2000
avatar

RP: You've got to be kidding me, you're totally capable of that :) In the least, you've got an amazing design/artistic sense.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

spellcaster
Member #1,493
September 2001
avatar

I'm not that sure if choosing the C approach will result in any postive results for us.
If we go for our own OO implementation, I'd try to add some more features, like the possibility to query for interfaces, etc.

Using aggregation to implement inheritance on that level is not a very good idea, as well.

Ok, after all this nay-saying I should try to come up with some positive suggestions as well, I guess :)

What about using a hashtable to store methods and attributes? We could even have different tables for private / protected / public members if needed.

But this is just an idea, not sure if it would be practical...

BTW, I still say we should stick with C++.
I see no point in doing a C API.

--
There are no stupid questions, but there are a lot of inquisitive idiots.

Richard Phipps
Member #1,632
November 2001
avatar

Unfortunately I'm not kidding... :(

What's aggregation and what's a hash table?
I don't have a take on whether it's C or C++, I'll leave that to the people who know more about all this than me! :)

X-G
Member #856
December 2000
avatar

Aggregation, in OO, is what's some times call "has a" relation - when a class contains another object. The alternative is Inheritance - "is a".

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

axilmar
Member #1,204
April 2001

Richard:

Quote:

Argh, you've just depressed me Axilmar! You're far far beyond me in your programming skills.
I don't think I'll be much use for this project.. Which is disappointing to me

Please, don't be depressed. Of course each one of us has different skills, according to our experience. If you think you are not at the same level, it's a good chance for you to learn while giving something back to the community. We are all going to learn many things through cooperation.

Quote:

Any chance you can explain what's happening in your code examples?

It's easy: a CLASS struct has all information that describes a class. This information is used to create OBJECT structs, i.e. structs that inherit from OBJECT. The CLASS struct is filled by you, the programmer with proper information. The rest is done by the framework which has 4 main functions:

1) a function for creating an object : 'create_object'
2) a function for destroying an object : 'destroy_object'
3) a function for retrieving the properties of an object: 'get_object_properties'
4) a function for setting the properties of an object: 'set_object_properties'

Since the framework knows which properties each object has, it searches the class table to find a property (search is done by the property id), then calls either 'set' or 'get' of the found PROPERTY struct.

Spellcaster:

Quote:

I'm not that sure if choosing the C approach will result in any postive results for us.
If we go for our own OO implementation, I'd try to add some more features, like the possibility to query for interfaces, etc

I don't like the C approach either, but a good GUI needs many hands. So, if it is difficult to find C++ coders in here, maybe we should do it in C. For me, a primary concern is to get it over as quickly as possible, because a good gui for Allegro is long overdue (some years!!!).

The VTABLE struct has a method 'get_instance' that is used to query the object for interfaces.

X-G
Member #856
December 2000
avatar

If anyone cares, I'm a C++ coder. Not that I'm any good. :P

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

axilmar
Member #1,204
April 2001

Ok, here is a zip file that contains the object-oriented C framework I talked earlier and an example.

If we choose C, I suggest we use this or a similar framework, in order to make our lifes easier...

spellcaster
Member #1,493
September 2001
avatar

As said, I coded quite few java widgets sets at work. It's not that difficult once you have basic framework.

Starting from java.awt.Container it's normally a 8 week job to create a basic widget set with all widgets needed for your normal digital tv needs.
This includes pushbuttons, checkboxes, radiobuttons, thumbwheels, inputwidgets for num and alphanum, formatted text input, textoutput, icons, scrollbar, scrollpanes, splitter windows, tabbed windows, lists, trees and focus management.

We normally did this in a 4week, 2 persons routine (using your normal 8h workdays).

I don't think writing a widget set / gui lib is that much of a problem if one decides first what he wants.

The problem with GUIs for game development is normally that the "what people want" part is the most problematic point.

IMO, throwing code around right now, is a pretty bad idea.
If we want to start creating a GUI, what we should do first is collecting a list of wanted features / requirements.

Then we should start grouping them, both inheritance and priority wise. Once this is done, we'll be able to get an image of what we need as a framework.

I think most of us (reading this thread) have already a pretty good view of what they want. I also think our views are prety different. :)
Since I'm used to java widget sets (and prefer this way of coding to win32 style), I tend to go into the direction and recrating this environment.

Others might prefer the win style.

So, i't important that we get a better idea of what we want, before we start thinking about "how we implement it".

--
There are no stupid questions, but there are a lot of inquisitive idiots.

X-G
Member #856
December 2000
avatar

Again, I know this is skipping ahead ... but today I wrote (entirely unrelated to this) another entity system I realized in the end was very similar to how GUI systems group their widgets. A .tar.gz is attached - have a look if you want.

No, I'm not trying to hijack the thread. :P

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Richard Phipps
Member #1,632
November 2001
avatar

X-G!! I could swear at you!!

You say you can't do work on your version of Chaos and then you show me some code that I can't even understand!

Grrr...

;D

On-topic I think that people need to decide C/C++ before they do any coding.

X-G
Member #856
December 2000
avatar

That work wasn't for my Chaos clone. If you didn't know, it's listed as Inactive/Abandoned on my page (see sig).

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

axilmar
Member #1,204
April 2001

Ok, here is a list of widgets that I would like to have:

1) button
2) check box
3) radio button
4) button frame
5) scroll bar
6) slider
7) separator
8) label
9) image
10) raised panel
11) sunken panel
12) menu bar
13) menu item
14) popup menu
15) window
16) toolbar
17) tool button
18) tree
19) list
20) text box
21) text editor
22) html viewer
23) splitter
24) spin box
25) combo box
26) table
27) common dialogs
28) bitmap button
29) message box

Hmmm...it certainly does not seem as a 2 month job to me, especially if the underlying window and drawing system is not there. On top of it, I would like a programming style as simple as possible: just creating one widget within the other, set a few properties, a few callbacks, and that's it basically.

I am thinking towards applications for Allegro, and not necessarily games.

Bah, now that I think it, it is too much work, especially for the summer...

X-G
Member #856
December 2000
avatar

Okay, I'm going to be critical a bit - see this as positive feedback, because I'm interested in seeing a good GUI lib too, and communication is what makes things better. :)

Quote:

10) raised panel
11) sunken panel

Same widget, different options to change drawing style.

Quote:

20) text box
21) text editor

Same widget - one can do multi-line, the other can't. Might as well be a flag. One can subclass if one wants, say, richtext features.

Quote:

25) combo box

Aggregation of button/label, but still a widget in its own ...

Quote:

27) common dialogs

Aggregation of window and buttons - doesn't deserve its own widget, should just be a static function that creates a preset common window.

Quote:

28) bitmap button

Add bitmap support to the regular button instead.

Quote:

29) message box

See #27.

Also, I would like to add something like an icon pane (like your desktop, for instance) and a scrollable canvas space.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

spellcaster
Member #1,493
September 2001
avatar

What's a "button border"?

Labels and buttons share most of the layout code (position of text and image in relation to another and the area they occupy).

Toolbars are just a container with a lot of buttons, but I agree we should have some utilities to allow a quick creation of them.

I see no difference between a menu and a pop-up menu. Your normal menu is just a pop-up menu which is shown at agiven position below your menu bar.

Ok, so let's group this list a little.

1Static:
2* labels. Can display both text and/ or images
3 
4Buttons:
5* Pushbutton
6* togglebutton
7* checkbox
8* Radiobutton (and group)
9 
10Menus
11* Menu Bar
12* Menu
13 
14Bounded Range Widgets
15* sliders
16* scrollbars
17* Spinner
18 
19Input Widgets
20* textfield
21* formatted input field
22 
23Single Selection Widgets
24* Combobox
25* Thumbwheel
26* Color Selector
27 
28Multi Selection Widgets
29* List
30* Tree
31* Table
32 
33Container
34* Panels
35* Splitter Panes
36* Frames
37* Scrollpanes
38* tabbed panes
39 
40Dialogs
41* File IO
42* Messageboxes
43* Inputboxes
44* Color chooser

I removed the window and html viewer. Reason to remove the window was that a window makes no sense ATM, since it would be equivalent to a Panel at the moment (Since allegro doesn't allow us to spawn new windows).
So, what we really need is a frame (a window with a border and title).

The html viewer is too much to chew, IMO.

If you have the label, the push button is almost done as well. Once the push button is done, the others will follow, since labels and all buttons have just a few minor differences.

Most containers are pretty simple as well, since they are mainly aggregations of existing widgets.

The most complex widget in that list is the table (or grid) followed by the tree.

The other widgets are more or less pretty simply, since they only extend existing widgets, add new functionality by grouping widgets or simply because they have a simple structure....

So, besides the table and tree, the foundation, the event, drawing and layout/resize code is the largest problem.

--
There are no stupid questions, but there are a lot of inquisitive idiots.

X-G
Member #856
December 2000
avatar

I feel no distinction should be made between togglebuttons and regular buttons - "togglable" should be a flag. They both share the same behaviour, and I don't feel such a small change warrants a widget of its own.

I'm not sure what you mean with "formatted input field" - if you mean richtext, then yes, it should be its own. If you just mean "format masked", then it should probably be a part of the textbox.

What would the different between a Panel and a Frame be?

And, as mentioned, the dialogs might as well not be widgets of their own ... a file list might very well be though (a list or iconview that automatically populates by reading from filesystem).

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!



Go to: