IUP for Zig (original) (raw)

Cover image for IUP for Zig

First of all, what is an IUP?

IUP (pronounced like "yup") in Portuguese stands for "interface do usuário portátil" or "portable user interface" in English.
It's a cross-platform GUI toolkit developed by PUC-RIO, the same university behind the excellent Lua language.

For more detailed information about IUP, please visit https://www.tecgraf.puc-rio.br/iup/.

My story using IUP

My first contact with IUP was between 2002 and 2003 when I was a junior developer hired to work on a desktop application written in C, using IUP as GUI Toolkit.

I quickly got used to it and could manage to do a decent job writing user interfaces. But, to my surprise, just a few months later, the project manager decided to switch from IUP to Swing and rewrite the GUI in Java while keeping performance-sensitive parts in C.

Then, I started to write a ton of JNI interfaces to be consumed by the Java side and port code from C to Java (oh, it was so 2000 🙄).

After a while, I left the company, and my life moved on, I worked on many other projects, but I never played with IUP again ...

Why bring it up now?

I first discovered Zig in 2020, and I was strongly motivated by the "better C" slogan, so I needed to try Zig on something I could measure how much better Zig is.

I started playing with Zig, and I realized that we hadn't any cross-platform desktop GUI toolkit for Zig yet. I checked on IUP after all this time and started putting things together.

As someone who has written the same user interfaces in IUP and Swing, I think IUP can be much more productive, but the C language doesn't have the desired productivity tools. Time to give IUP another chance in Zig! 🦎

The IUPforZig project

IUP is a solid and well-proven toolkit that exposes a simple raw C FFI, allowing me to focus on the library-binding design rather than on implementation details.

You can visit https://github.com/batiati/IUPforZig for more demos and details about the project.

IUP has dozens of GUI elements such as texts, buttons, calendars, panels, layouts, and so on, each accepting various attributes (value, size, color, alignment, etc.), resulting in thousands of bindings to glue between C and Zig. Such an extensive API would be very hard to write and maintain by hand, so inspired by Marler's zigwin32, I came up with IUPMetadata, an attempt to collect rich information about each element and attribute in order to autogenerate the bindings code in idiomatic and type-checked Zig.

One challenge of generating code is that IUP primarily uses name/value pairs as uppercase strings, but there is limited information about the expected data types for these values (e.g., string, int, float, enum, struct). Therefore, a significant portion of the work involved in the IUPMetadata consisted of collecting the data-type information and correctly converting cases, such as "SCROLLTOPOS" to "ScrollToPos" instead of "ScrollTopOS".

Sections of the original HTML documentation for IUP are included as doc comments in the generated Zig code, providing easy access to API documentation and improving productivity. This makes working with IUPforZig more enjoyable. Using Zls in your preferred code editor can make the experience even easier 😍

Integrated doc comments on VSCode

Here is a simple demo especially made for this post 🤓

Hello ZigNew on Windows Classic

Hello ZigNew on Ubuntu

And here is the source code:

// Compiles with Zig 0.11.0-dev
const std = @import("std");
const iup = @import("iup.zig");

pub fn main() !void {
    try iup.MainLoop.open();
    defer iup.MainLoop.close();

    var dlg = try iup.Dialog.init()
        .setTitle("Hi there!")
        .setSize(.Third, .Quarter)
        .setChildren(
        .{
            iup.VBox.init()
                .setMargin(10, 10)
                .setGap(10)
                .setAlignment(.ACenter)
                .setChildren(
                .{
                    iup.Label.init()
                        .setTitle("IUP FOR ZIG")
                        .setFontSize(32)
                        .setFontFace("Zig")
                        .setFgColor(.{ .r = 247, .g = 164, .b = 29 }),

                    iup.Link.init()
                        .setTitle("We're on zig.news")
                        .setUrl("https://zig.news"),
                },
            ),
        },
    ).unwrap();
    defer dlg.deinit();

    try dlg.showXY(.Center, .Center);

    try iup.MainLoop.beginLoop();
}

Enter fullscreen mode Exit fullscreen mode

EDITED:
Although IUPforZig was my first Zig project back in the 0.8.0 days, it was fundamental to get my hands dirty in Zig and learn some of this fantastic programming language!

Updating it to Zig 0.11.0-dev was such a pleasure, and a great opportunity to learn how the language evolved.