magiblot / tvision

A modern port of Turbo Vision 2.0, the classical framework for text-based user interfaces. Now cross-platform and with Unicode support.
Other
1.99k stars 150 forks source link

TWindow & TDialog: Post message to TMyApplication #87

Closed WillianBR closed 1 year ago

WillianBR commented 1 year ago

Folks,

This is not exactly a bug ou issue. It's a work approach. Does anybody is sending message from a window/dialog to the main application?

Unfortely the TViews inherited classes don't have any reference to they parent or even application. So, to communicate with the parent or father, they have to send a message. Somebody wrote about we aren't able of access all the list of childrens of Desktop.

So, to be able of know when they are destroyed, I'm thinking about send a message to the application.

I found the function message() in "tvision/source/tvision/misc.cpp", but sometimes it doesn't work! It complain about arguments.

Does someone is using it to do the hard work?

  graph LR;
      TWindow-->|message.infoPtr |TApplication;
      TApplication-->|replay|TWindow;
      TDialog-->|message.infoPtr |TApplication;
      TApplication-->|replay|TDialog;
magiblot commented 1 year ago

TViews do have a reference to their parent: the owner field, which is of type TGroup *. You can static_cast this pointer if you know the actual class of the parent. Nevertheless, it is good practice to use messages.

There is also a way to access the application: the TProgram::application global variable, of type TProgram *. You can also access the desktop through the TProgram::deskTop global variable.

message() is the right way to send a message; if you get an error, copy it here so that we can see it.

I recommend you to read this section from the Turbo Vision 2.0 Programming Guide (page 168). It's in Pascal, so the source code is different, but the concepts are the same:

Screenshot_20230104_030503

WillianBR commented 1 year ago

@magiblot,

I was thinking about this approach.

The text states the message should be unique, to only one window repley it. But the last parameter can be used to send the class name and any extra information about the window who repley the message.

I have started my code using message() to communicate. And I found out this morning about owner. But I don't had enough time to make some tests. Tomorrow morning I will do.

Sooner I finish my tests, I'll repley here!

magiblot commented 1 year ago

Maybe you already understand the following, but I would like to clarify it just in case:

In the example from the book, only one window replies to the message. However, this does not mean that the message can only be sent to one window.

Note that the message receiver is the desktop (and not a specific window). TDesktop is an inheritor of TGroup, and so are TWindow and TApplication. When a TGroup receives an event, it propagates it to all is subviews. Therefore, by sending a single message to the desktop you can reach all windows.

However, in the example, the window that receives the cmFindWindow messages calls clearEvent(event). After this, event.what is set to evNothing and it won't be propagated to any other views.

The last parameter of message() will be the value of event.message.infoPtr when the window receives the message. Therefore, this parameter is mainly used to send information to the window.

When the window calls clearEvent(event), clearEvent sets event.message.infoPtr = this. This value of infoPtr is the one returned by message(), and it's a pointer to the window.

If the window didn't call clearEvent, then the message could be received by other windows too.

There's another important thing that is not mentioned in that section of the book. When a TGroup propagates events to its subviews, it checks their eventMask fields. For example, if the event is an evBroadcast, then it will only be propagated to views which have (eventMask & evBroadcast) != 0. The default value of eventMask is evMouseDown | evKeyDown | evCommand (see source/tvision/tview.cpp), so if you want your custom views to receive evBroadcast events you will have to add eventMask |= evBroadcast; in their constructor.

WillianBR commented 1 year ago

Man, You sure is a teacher! Thank you very much.

And sure I already had read the sources and find out about the Broadcast. Including the last param of message(). The few tests I made use this option which is void*.

I'm also toke a peek at clearevent() implementation and I saw the evNothins and this being assing to infoPtr.

But I'm sure missed the thing about eventMask |= evBroadcast;. My tests failed and now I'm aware of which cause it!

I'll make the changes tomorow. I tell you about, after.

magiblot commented 1 year ago

By the way, I will move your questions to the Discussions section, since there they will be easer to find for other users.