My current scenario: I need to write an application with a GUI that works on *nix, win, and osx (or whatever apple calls it these days).
What is my best option for this, in regards to GUI? Could I achieve this by using GTK? I have never seen GTK running on win or osx, so any and all comments would be appreciated.
In case you didn’t know GNAT Studio (GPS) is GTK3. So yes, Windows and BSD (Mac stuff) are supported.
The choice is usually Qt or GTK. GTK tries to use look-and-feel of the host OS. Qt is available on a wider range of OSes. Another difference is that Qt is C++ and GTK is C. C++ is far more difficult to communicate.
I use Gnoga a lot. It’s pretty handy at work for making some quick simulators and things when I want a GUI. It’s browser based, so that helps with cross platform scenarios. I only use Windows and Linux, but so far all of my stuff has compiled for both pretty easily.
I would love to see if we can make a “native” rendering front-end for it.
Starting with something like RayGUI and maybe move to a full Ada implementation afterwards.
(I don’t know if the Sowebio people are hanging out around here)
To me GUI is all about widgets and handling events/messages. The problem with existing GUI like Qt, GTK, Win32 etc is abstraction inversion since handling events happens in wrong places. E.g. button press is handled by button widget rather that by a container of.
The event processing is unstructured and requires to be in front while the problem space logic is pushed back into callbacks.
Then of course, there is a push vs. pull problem. GUIs are built event-driven. This architecture is totally unsuitable for real-time, high-frequency and massive amounts of data applications where you would rather use polling. You can of course create an oscilloscope widget I did it in GTK and Win32, but it requires a lot of acrobatics.
This is the whole point of “Immediate Mode” GUIs like Dear, Imgui. The UI code looks like executable code, and the processing is intrinsic to how it’s written.
// All this code just normal runnable code
ImGui::Text("Hello, world %d", 123);
// Draw save button and save when "Save" is pressed (could be made into an async task)
if (ImGui::Button("Save"))
MySaveFunction();
ImGui::InputText("string", buf, IM_ARRAYSIZE(buf));
// Draw a slider, stores current value in `f`
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
Imgui is used in programs which require lots of data processing like the Tracy profiler.
No different from GTK so far. Construction of widgets you illustrated is never an issue. Event processing is also no different, you specified a call back function, what is worse in your code it has no parameters. E.g. in GTK it would be the button itself and the user data which can be turned into the event’s recipient. And, of course, it is 100% event-driven which is OK for some buttons (not for save-button, though, which might take seconds to finish) and never OK for an oscilloscope.
Maybe I misunderstand you or him, but I don’t think that’s a callback function in the same sense as what you have in, say, HTML DOM events. He could in fact have called a function with parameters; it depends on what he wants to do when someone presses the save button.
I say this also based on my own experience with immediate-mode GUIs, which I’ve used and actually dislike, though not for any good reason I can recall at the moment. But, as I say, perhaps I misunderstand you or him.
It depends on typing and marshalling. If a callback has parameters you need to marshal them to the call point. Even in an utterly untyped manner you cannot do that without specifying at least a closure at the point where you connect to an event.
I do not understand this drivel anyway. In all GUI I worked with you always can do rendering in an explicit manner. The problems begin with asynchronous events like when the widget gets covered, mouse hovers over it etc.
We’re trying a different approach. Give us a chance to show you something consistent. Time doesn’t respect what’s done without it. And there are, for the moment, only two of us.
For now, we’re taking care of the foundations by rewriting the websocket interface and using epoll. We’re now up to 1.5 M req/s on average hardware. But we can do even better. And we’ll do it if it makes sense. Like automatic reconnection, since websocket is obviously sensitive in this respect.
As this is still being settled, we also have a schedule to complete. Building - LibreFrame
Thanks for waiting a few months, but we’ll already have things ready between september and october this year.
We are, of course, always open to comments. We’re really counting on it.
Ada GUI project might be very interesting. Though it is a mammoth task I am not even sure how to approach it avoiding typical errors of GUI architectures.
Mentioning WebSockets in that context rings alarm bells to me. Anyway, good luck.
Instead of creating a bunch of widgets, and wiring them together (e.g. Qt slots/signals), an immediate-mode GUI gets written like a big procedure call that gets called every frame, where drawing and event handling code are interleaved. There are no asynchronous event mechanisms or callbacks. Handling of events happens on the next draw call through some clever caching mechanisms.
It’s a completely different UI style developed by Casey Muratori, and the reason I brought it up is because it lets you see the containing context during event handling. The two libraries I know of that work this way are Dear Imgui and Nuklear. This sort of UI seems like it would work very well in Ada.
In Ada-pseudocode, it would look like this:
Value : Float; -- value updated by slider
-- Called in update loop
procedure Draw_UI is
begin
Start_Window();
-- Within the window, two elements in the same row.
Set_Num_Cols(2);
-- Left element is a button.
if Button ("Left") then
-- Button has been clicked. This is not a callback.
-- this happens on the next draw call.
Ada.Text_IO.Put_Line ("Left button has been pressed!");
else
-- This button has not been clicked since the last time it was handled.
end if;
-- The right element is a slider. It's current value will be updated
-- immediately after this procedure call.
if Slider ("Value", Value'Access, 0.0f, 1.0f) then
-- Slider value has changed since the last draw, perhaps
-- do some logic.
Ada.Text_IO.Put_Line ("Slider changed " & Value'Image);
else
-- Slider value is the same as for the last draw.
end if;
End_Window();
end Draw_UI;
There’s a few issues with this style:
You have render at a reasonable frame rate (e.g. >= 30 FPS) since it doesn’t lazily update.
Your UI logic can’t be extensive since it will delay the next draw. For long operations you’d want to spin off work in a side task.
You need to pay a lot of attention to how you paginate data to prevent your UI from getting too slow.
I’ve thought a lot about how to react to this. Overall, my belief is this type of tone isn’t conducive to the community, and I don’t believe it was merited in this case.