On Thursday, 14 May 2026 at 20:56:22 UTC, c-smile wrote:
I've almost done with D version of [Sciter](https://sciter.com) SDK.

HTML5, CSS3, DOM, JS for a GUI application is absolutely not necessary. However I do understand why people want to use them - these are anywhere. People are familiar with them, etc...

![Simiar application with giD, running on Linux](https://gcdnb.pbrd.co/images/UNoIFtgUT4QC.png)

To run, save to clock.d and then `dub run --single clock.d`, and soon you will get the application window similar to the screenshot above, assuming you have GTK4 installed.

PS. I could as easily embed entire WebKit into my giD-based application and have all the above, and more, so what do D developers get with sciter that separates it from the rest of the crowd?

Code:
```d
/+dub.sdl:
    name "gidex-clock"
    dependency "gid:gtk4" version="*"
    targetType "executable"
+/

/// Analog clock application using gid:gtk4 and Cairo.
/// Run with: dub run --single src/gidex/clock.d

module gidex.clock;

import std.datetime.systime;
import core.stdc.stdio : sprintf;

import gtk.application;
import gtk.application_window;
import gtk.box;
import gtk.label;
import gtk.types : Orientation;
import gio.types : ApplicationFlags;
import gio.application : GioApp = Application;
import gtk.drawing_area;

import cairo.context;

import glib.global : timeoutAdd;

enum PI = 3.1415926f;

class ClockWindow : ApplicationWindow {
    DrawingArea drawingArea;

    this(gtk.application.Application app) {
        super(app);
        setTitle("giD Clock");
        setDefaultSize(400, 450);

        auto box = new Box(Orientation.Vertical, 8);

        auto titleLbl = new Label("The D Clock");
        titleLbl.setMarginTop(8);
        box.append(titleLbl);

        drawingArea = new DrawingArea();
        drawingArea.setContentWidth(300);
        drawingArea.setContentHeight(300);
        drawingArea.setMarginStart(16);
        drawingArea.setMarginEnd(16);
        drawingArea.setVexpand(true);
        drawingArea.setHexpand(true);

        drawingArea.setDrawFunc(&drawClock);

        box.append(drawingArea);

        setChild(box);

        // Tick every second to keep the clock hands moving
        timeoutAdd(0, 1000, {
            drawingArea.queueDraw();
            return true;
        });
    }

void drawClock(DrawingArea area, Context cr, int width, int height) {
        import std.math : cos, sin;
        import cairo.types;

        float cx = width / 2.0f;
        float cy = height / 2.0f;
        float radius = (cx < cy ? cx : cy) * 0.9f;

        // White clock face
        cr.setSourceRgba(1.0, 1.0, 1.0, 1.0);
        cr.arc(cx, cy, radius, 0, 2 * PI);
        cr.fill();

        // Clock border
        cr.setSourceRgba(0.2, 0.2, 0.2, 1.0);
        cr.setLineWidth(radius * 0.02);
        cr.arc(cx, cy, radius, 0, 2 * PI);
        cr.stroke();

        cr.setLineCap(LineCap.Round);

        // Hour marks
        cr.setSourceRgba(0.196, 0.373, 0.635, 1.0); // #325FA2
        cr.setLineWidth(radius * 0.04);
        foreach (i; 0 .. 12) {
            float angle = i * PI / 6.0f - PI / 2.0f;
            float inner = radius * 0.85f;
            float outer = radius * 0.92f;
cr.moveTo(cx + inner * cos(angle), cy + inner * sin(angle)); cr.lineTo(cx + outer * cos(angle), cy + outer * sin(angle));
            cr.stroke();
        }

        // Minute marks
        cr.setSourceRgba(0.647, 0.165, 0.165, 1.0); // #A52A2A
        cr.setLineWidth(radius * 0.015);
        foreach (i; 0 .. 60) {
            if (i % 5 != 0) {
                float angle = i * PI / 30.0f - PI / 2.0f;
                float inner = radius * 0.9f;
                float outer = radius * 0.92f;
cr.moveTo(cx + inner * cos(angle), cy + inner * sin(angle)); cr.lineTo(cx + outer * cos(angle), cy + outer * sin(angle));
                cr.stroke();
            }
        }

        // Current time
        SysTime now = Clock.currTime();
        uint sec = now.second;
        uint min = now.minute;
        uint hr = now.hour;
        hr = hr >= 12 ? hr - 12 : hr;

        // Date text
        {
            char[20] buf;
            int written = sprintf(buf.ptr, "%04d-%02d-%02d",
                now.year, now.month, now.day);
            string dateStr = buf[0 .. written].idup;
            cr.setSourceRgba(0.647, 0.165, 0.165, 1.0); // brown
cr.selectFontFace("Sans", FontSlant.Normal, FontWeight.Normal);
            cr.setFontSize(radius * 0.12);
            TextExtents te;
            cr.textExtents(dateStr, te);
            cr.moveTo(cx - te.width / 2.0, cy + radius * 0.35);
            cr.showText(dateStr);
        }

        // Hour hand
        {
float angle = (hr * (PI / 6.0f) + (PI / 360.0f) * min + (PI / 21600.0f) * sec) - PI / 2.0f;
            cr.setSourceRgba(0.196, 0.373, 0.635, 1.0);
            cr.setLineWidth(radius * 0.06);
            cr.setLineCap(LineCap.Round);
cr.moveTo(cx - radius * 0.12 * cos(angle), cy - radius * 0.12 * sin(angle)); cr.lineTo(cx + radius * 0.5 * cos(angle), cy + radius * 0.5 * sin(angle));
            cr.stroke();
        }

        // Minute hand
        {
float angle = ((PI / 30.0f) * min + (PI / 1800.0f) * sec) - PI / 2.0f;
            cr.setSourceRgba(0.196, 0.373, 0.635, 1.0);
            cr.setLineWidth(radius * 0.04);
            cr.setLineCap(LineCap.Round);
cr.moveTo(cx - radius * 0.15 * cos(angle), cy - radius * 0.15 * sin(angle)); cr.lineTo(cx + radius * 0.7 * cos(angle), cy + radius * 0.7 * sin(angle));
            cr.stroke();
        }

        // Second hand
        {
            float angle = sec * PI / 30.0f - PI / 2.0f;
            cr.setSourceRgba(0.831, 0.0, 0.0, 1.0); // #D40000
            cr.setLineWidth(radius * 0.02);
            cr.setLineCap(LineCap.Round);
cr.moveTo(cx - radius * 0.18 * cos(angle), cy - radius * 0.18 * sin(angle)); cr.lineTo(cx + radius * 0.6 * cos(angle), cy + radius * 0.6 * sin(angle));
            cr.stroke();

            // Small circle at tip
cr.arc(cx + radius * 0.6 * cos(angle), cy + radius * 0.6 * sin(angle), radius * 0.03, 0, 2 * PI);
            cr.fill();

            // Center dot
            cr.arc(cx, cy, radius * 0.04, 0, 2 * PI);
            cr.fill();
        }
    }
}

class ClockApplication : gtk.application.Application {
    ClockWindow window;

    this() {
super("org.example.gidex-clock", ApplicationFlags.DefaultFlags);
        connectActivate(&onActivate);
    }

    void onActivate(GioApp app) {
        if (!window)
            window = new ClockWindow(this);
        window.present();
    }
}

void main(string[] args) {
    auto app = new ClockApplication;
    app.run(args);
}
```

Reply via email to