Skip to content

Examples

Ryan Srichai edited this page Jun 12, 2026 · 19 revisions

This page contains the full source code for examples using turtle's features. See this page to learn how to build and run a project.

List Examples

Generating prime numbers:

#define TURTLE_IMPLEMENTATION // exclude this line if compiling with -lturtle
#include "turtle.h"

int main(int argc, char *argv[]) {
    int32_t numberOfPrimes = 100;
    list_t *primes = list_init();
    list_append(primes, (unitype) 2, 'i');
    int32_t checkNumber = 3;
    while (primes -> length < numberOfPrimes) {
        int8_t isPrime = 1;
        for (int32_t j = 0; j < primes -> length; j++) {
            if (primes -> data[j].i > sqrt(checkNumber)) {
                break;
            }
            if (checkNumber % primes -> data[j].i == 0) {
                isPrime = 0;
                break;
            }
        }
        if (isPrime) {
            list_append(primes, (unitype) checkNumber, 'i');
        }
        checkNumber++;
    }
    list_print(primes);
}

Turtle Examples

Drawing with Mouse:

#define TURTLE_IMPLEMENTATION // exclude this line if compiling with -lturtle
#include "turtle.h"
#include <time.h>

int main(int argc, char *argv[]) {
    /* Initialise window */
    GLFWwindow *window = turtleCreateWindow(TURTLE_WINDOW_DEFAULT_WIDTH, TURTLE_WINDOW_DEFAULT_HEIGHT, "draw mouse demo");
    /* initialise turtle */
    turtleInit(window, -320, -180, 320, 180);

    uint32_t tps = 60; // ticks per second (locked to fps in this case)
    uint64_t tick = 0; // count number of ticks since application started
    clock_t start, end;

    turtlePenColor(0, 0, 0); // set color to black
    turtlePenSize(10); // set size to 10

    while (turtle.close == 0) {
        start = clock();
        turtleGetMouseCoordinates();
        turtleGoto(turtle.mouseX, turtle.mouseY);
        if (turtleMouseDown()) {
            turtlePenDown();
        } else {
            turtlePenUp();
        }
        turtleUpdate(); // update the screen
        end = clock();
        while ((double) (end - start) / CLOCKS_PER_SEC < (1.0 / tps)) {
            end = clock();
        }
        tick++;
    }
    turtleFree();
    glfwTerminate();
}

Moving circle with arrow keys:

#define TURTLE_IMPLEMENTATION // exclude this line if compiling with -lturtle
#include "turtle.h"
#include <time.h>

int main(int argc, char *argv[]) {
    /* Initialise window */
    GLFWwindow *window = turtleCreateWindow(TURTLE_WINDOW_DEFAULT_WIDTH, TURTLE_WINDOW_DEFAULT_HEIGHT, "controls demo");
    /* initialise turtle */
    turtleInit(window, -320, -180, 320, 180);

    uint32_t tps = 60; // ticks per second (locked to fps in this case)
    uint64_t tick = 0; // count number of ticks since application started
    clock_t start, end;

    turtlePenColor(0, 0, 0); // set color to black
    turtlePenSize(50); // set size to 10
    double ballX = 0;
    double ballY = 0;
    double ballSpeed = 5.0;

    while (turtle.close == 0) {
        start = clock();
        if (turtleKeyPressed(GLFW_KEY_UP)) {
            ballY += ballSpeed;
        }
        if (turtleKeyPressed(GLFW_KEY_DOWN)) {
            ballY -= ballSpeed;
        }
        if (turtleKeyPressed(GLFW_KEY_RIGHT)) {
            ballX += ballSpeed;
        }
        if (turtleKeyPressed(GLFW_KEY_LEFT)) {
            ballX -= ballSpeed;
        }
        turtleClear(); // clear the screen
        turtleGoto(ballX, ballY);
        turtlePenDown();
        turtlePenUp();
        turtleUpdate(); // update the screen
        end = clock();
        while ((double) (end - start) / CLOCKS_PER_SEC < (1.0 / tps)) {
            end = clock();
        }
        tick++;
    }
    turtleFree();
    glfwTerminate();
}

TurtleText Examples

Draw Mouse Coordinates

#define TURTLE_IMPLEMENTATION // exclude this line if compiling with -lturtle
#include "turtle.h"
#include <time.h>

int main(int argc, char *argv[]) {
    /* Initialise window */
    GLFWwindow *window = turtleCreateWindow(TURTLE_WINDOW_DEFAULT_WIDTH, TURTLE_WINDOW_DEFAULT_HEIGHT, "draw mouse demo");
    /* initialise turtle */
    turtleInit(window, -320, -180, 320, 180);
    /* initialise turtleText */
    turtleTextInit("config/roberto.tgl");

    uint32_t tps = 60; // ticks per second (locked to fps in this case)
    uint64_t tick = 0; // count number of ticks since application started
    clock_t start, end;

    turtlePenColor(0, 0, 0);
    turtlePenSize(0.5);

    while (turtle.close == 0) {
        start = clock();
        turtleClear(); // clear the screen
        turtleGetMouseCoordinates();
        turtleGoto(turtle.mouseX - 3, turtle.mouseY);
        turtlePenDown();
        turtleGoto(turtle.mouseX + 3, turtle.mouseY);
        turtlePenUp();
        turtleGoto(turtle.mouseX, turtle.mouseY - 3);
        turtlePenDown();
        turtleGoto(turtle.mouseX, turtle.mouseY + 3);
        turtlePenUp();
        turtleTextWriteStringf(turtle.mouseX + 2, turtle.mouseY + 6, 5, 0, "%.2lf, %.2lf", turtle.mouseX, turtle.mouseY);
        turtleUpdate(); // update the screen
        end = clock();
        while ((double) (end - start) / CLOCKS_PER_SEC < (1.0 / tps)) {
            end = clock();
        }
        tick++;
    }
    turtleFree();
    glfwTerminate();
}

Dialog Box

#define TURTLE_IMPLEMENTATION // exclude this line if compiling with -lturtle
#include "turtle.h"
#include <time.h>

int main(int argc, char *argv[]) {
    /* Initialise window */
    GLFWwindow *window = turtleCreateWindow(TURTLE_WINDOW_DEFAULT_WIDTH, TURTLE_WINDOW_DEFAULT_HEIGHT, "dialog demo");
    /* initialise turtle */
    turtleInit(window, -320, -180, 320, 180);
    /* initialise turtleText */
    turtleTextInit("config/roberto.tgl");

    uint32_t tps = 60; // ticks per second (locked to fps in this case)
    uint64_t tick = 0; // count number of ticks since application started
    clock_t start, end;
    char dialog[][128] = {
        "Hey it's nice to meet you",
        "This world is imperfect.",
        "What",
        "If only I could wipe away the impurities,",
        "Is anybody else listening to this",
        "and make it as beautiful as me!",
        "14 hours of gameplay later",
        "Lysanderoth! You were behind all this?",
        "Yes it was I. My machinations lay undetected for years\nfor I am a master of deception",
    };
    uint8_t color[][3] = {
        140, 140, 255,
        255, 80, 80,
        140, 140, 255,
        255, 80, 80,
        140, 140, 255,
        255, 80, 80,
        160, 160, 160,
        255, 40, 140,
        255, 80, 80,
    };
    int32_t dialogLength = sizeof(dialog) / 128;
    int32_t dialogIndex = 0;
    int32_t mouseFlag = 0;
    char text[8][128];

    while (turtle.close == 0) {
        start = clock();
        turtleClear(); // clear the screen
        turtlePenColor(60, 60, 60);
        turtleRectangle(-320, -110, 320, -180);
        turtlePenColor(color[dialogIndex][0], color[dialogIndex][1], color[dialogIndex][2]);
        int32_t lines = 0;
        int32_t next = 0;
        for (int32_t i = 0; i < strlen(dialog[dialogIndex]); i++) {
            text[lines][next] = dialog[dialogIndex][i];
            if (dialog[dialogIndex][i] == '\n') {
                text[lines][next] = '\0';
                lines++;
                next = -1;
            }
            next++;
        }
        text[lines][next] = '\0';
        lines++;
        for (int32_t i = 0; i < lines; i++) {
            turtleTextWriteUnicode(text[i], -305, -130 - i * 20, 12, 0);
        }
        if (turtleMouseDown()) {
            if (mouseFlag == 0) {
                dialogIndex++;
                mouseFlag = 1;
                if (dialogIndex >= dialogLength) {
                    dialogIndex = 0;
                }
            }
        } else {
            mouseFlag = 0;
        }
        turtleUpdate(); // update the screen
        end = clock();
        while ((double) (end - start) / CLOCKS_PER_SEC < (1.0 / tps)) {
            end = clock();
        }
        tick++;
    }
    turtleFree();
    glfwTerminate();
}

TurtleTools Examples

Image Editor

// #define TURTLE_IMPLEMENTATION // exclude this line if compiling with -lturtle
#include "turtle.h"
#include <time.h>

enum {
    EDITOR_KEYS_LMB = 0,
    EDITOR_KEYS_RMB = 1,
    EDITOR_KEYS_LEFT_SHIFT = 2,
};

enum {
    DRAW_INDEX_RED = 0,
    DRAW_INDEX_GREEN = 1,
    DRAW_INDEX_BLUE = 2,
    DRAW_INDEX_ALPHA = 3,
    DRAW_INDEX_SIZE = 4,
    DRAW_INDEX_X = 5,
    DRAW_INDEX_Y = 6,
    DRAW_INDEX_PEN_DOWN = 7,
    DRAW_INDEX_NUMBER_OF_FIELDS = 8,
};

typedef struct {
    list_t *draw; // see DRAW_INDEX_X
    double sidebarX;
    double canvasX;
    double canvasY;
    double canvasWidth;
    double canvasHeight;
    double editingX;
    double editingY;
    double editingZoom;
    double anchorMouseX;
    double anchorMouseY;
    double anchorEditingX;
    double anchorEditingY;
    int8_t editingMoving;
    int8_t drawing;
    turtle_texture_t transparentTexture;
    tt_button_t *cameraButton;
    int32_t cameraAnimation;
    tt_slider_t *redChannel;
    double redSave;
    tt_slider_t *greenChannel;
    double greenSave;
    tt_slider_t *blueChannel;
    double blueSave;
    tt_slider_t *sizeSlider;
    int8_t lockOffsets;
    int8_t keys[8];
} image_editor_t;

image_editor_t self;

void init() {
    self.draw = list_init();
    self.sidebarX = 200;
    self.canvasX = -100;
    self.canvasY = 0;
    self.canvasWidth = 320;
    self.canvasHeight = self.canvasWidth / 4.0 * 3;
    self.editingX = 0;
    self.editingY = 0;
    self.editingZoom = 1;
    self.editingMoving = 0;
    self.drawing = 0;
    turtleToolsSetTheme(TT_THEME_DARK);
    /* create transparent texture */
    int32_t textureWidth = 1024;
    int32_t textureHeight = 768;
    uint8_t tColor1[3] = {60, 60, 60};
    uint8_t tColor2[3] = {80, 80, 80};
    int32_t gridSize = 16;
    uint8_t *transparent = malloc(textureWidth * textureHeight * 3);
    for (int32_t i = 0; i < textureHeight; i++) {
        int32_t color = 0;
        if (i % (gridSize * 2) < gridSize) {
            color = 1;
        }
        int32_t grid = 0;
        for (int32_t j = 0; j < textureWidth; j++) {
            if (color) {
                memcpy(transparent + i * textureWidth * 3 + j * 3, tColor1, 3);
                grid++;
            } else {
                memcpy(transparent + i * textureWidth * 3 + j * 3, tColor2, 3);
                grid++;
            }
            if (grid == gridSize) {
                color = !color;
                grid = 0;
            }
        }
    }
    self.transparentTexture = turtleTextureLoadArray(transparent, textureWidth, textureHeight, GL_RGB);
    free(transparent);
    /* set up sidebar UI */
    self.cameraButton = tt_buttonInit(" 📷 ", NULL, 300, -165, 10);
    self.cameraButton -> shape = TT_BUTTON_SHAPE_ROUNDED_RECTANGLE;
    self.redChannel = tt_sliderInit("", NULL, TT_SLIDER_TYPE_HORIZONTAL, TT_SLIDER_ALIGN_CENTER, self.sidebarX, 120, 10, 80, 0, 255, 0);
    self.redChannel -> value = 255;
    self.redChannel -> defaultValue = self.redChannel -> value;
    self.greenChannel = tt_sliderInit("", NULL, TT_SLIDER_TYPE_HORIZONTAL, TT_SLIDER_ALIGN_CENTER, self.sidebarX, 100, 10, 80, 0, 255, 0);
    self.greenChannel -> value = 255;
    self.greenChannel -> defaultValue = self.greenChannel -> value;
    self.blueChannel = tt_sliderInit("", NULL, TT_SLIDER_TYPE_HORIZONTAL, TT_SLIDER_ALIGN_CENTER, self.sidebarX, 80, 10, 80, 0, 255, 0);
    self.blueChannel -> value = 255;
    self.blueChannel -> defaultValue = self.blueChannel -> value;
    self.sizeSlider = tt_sliderInit("", NULL, TT_SLIDER_TYPE_HORIZONTAL, TT_SLIDER_ALIGN_CENTER, self.sidebarX, 60, 10, 80, 1, 25, 0);
    self.sizeSlider -> value = 5;
    self.sizeSlider -> defaultValue = self.sizeSlider -> value;
}

void render() {
    /* canvas */
    // turtleTexture(self.transparentTexture, self.canvasX - self.canvasWidth / 2, self.canvasY + self.canvasHeight / 2, self.canvasX + self.canvasWidth / 2, self.canvasY - self.canvasHeight / 2, 0, 255, 255, 255);
    turtleTexture(self.transparentTexture, (self.canvasX + self.editingX - self.canvasWidth / 2) * self.editingZoom, (self.canvasY + self.editingY + self.canvasHeight / 2) * self.editingZoom, (self.canvasX + self.editingX + self.canvasWidth / 2) * self.editingZoom, (self.canvasY + self.editingY - self.canvasHeight / 2) * self.editingZoom, 0, 255, 255, 255);
    for (int32_t drawIndex = 0; drawIndex < self.draw -> length; drawIndex += DRAW_INDEX_NUMBER_OF_FIELDS) {
        if (self.draw -> data[drawIndex + DRAW_INDEX_PEN_DOWN].i == 0) {
            turtlePenUp();
        }
        turtleGoto((self.draw -> data[drawIndex + DRAW_INDEX_X].d + self.editingX + self.canvasX) * self.editingZoom, (self.draw -> data[drawIndex + DRAW_INDEX_Y].d + self.editingY + self.canvasY) * self.editingZoom);
        turtlePenSize(self.draw -> data[drawIndex + DRAW_INDEX_SIZE].d * self.editingZoom);
        turtlePenColorAlpha(self.draw -> data[drawIndex + DRAW_INDEX_RED].d, self.draw -> data[drawIndex + DRAW_INDEX_GREEN].d, self.draw -> data[drawIndex + DRAW_INDEX_BLUE].d, self.draw -> data[drawIndex + DRAW_INDEX_ALPHA].d);
        if (self.draw -> data[drawIndex + DRAW_INDEX_PEN_DOWN].i) {
            turtlePenDown();
        }
    }
    turtlePenUp();
    turtleGoto(turtle.mouseX, turtle.mouseY);
    turtlePenSize(self.sizeSlider -> value * self.editingZoom);
    turtlePenColorAlpha(self.redChannel -> value, self.greenChannel -> value, self.blueChannel -> value, 0.0);
    turtlePenDown();
    turtlePenUp();
    /* occlude */
    tt_setColor(TT_COLOR_BACKGROUND);
    turtleRectangle(-320, -180, 320, self.canvasY - self.canvasHeight / 2);
    turtleRectangle(-320, 180, 320, self.canvasY + self.canvasHeight / 2);
    turtleRectangle(-320, 180, self.canvasX - self.canvasWidth / 2, -180);
    turtleRectangle(320, 180, self.canvasX + self.canvasWidth / 2, -180);
    /* handle camera button */
    if (self.cameraButton -> value) {
        self.cameraButton -> value = 0;
        self.cameraAnimation = 1;
    }
    /* handle RGB slider sync */
    if (self.lockOffsets) {
        if (self.redChannel -> value != self.redSave) {
            double offset = self.redChannel -> value - self.redSave;
            if (self.greenSave + offset > 255) {
                offset = 255 - self.greenSave;
            }
            if (self.blueSave + offset > 255) {
                offset = 255 - self.blueSave;
            }
            if (self.greenSave + offset < 0) {
                offset = 0 - self.greenSave;
            }
            if (self.blueSave + offset < 0) {
                offset = 0 - self.blueSave;
            }
            self.redChannel -> value = self.redSave + offset;
            self.greenChannel -> value = self.greenSave + offset;
            self.blueChannel -> value = self.blueSave + offset;
            self.greenSave = self.greenChannel -> value;
            self.blueSave = self.blueChannel -> value;
            self.redSave = self.redChannel -> value;
        }
        if (self.greenChannel -> value != self.greenSave) {
            double offset = self.greenChannel -> value - self.greenSave;
            if (self.redSave + offset > 255) {
                offset = 255 - self.redSave;
            }
            if (self.blueSave + offset > 255) {
                offset = 255 - self.blueSave;
            }
            if (self.redSave + offset < 0) {
                offset = 0 - self.redSave;
            }
            if (self.blueSave + offset < 0) {
                offset = 0 - self.blueSave;
            }
            self.greenChannel -> value = self.greenSave + offset;
            self.redChannel -> value = self.redSave + offset;
            self.blueChannel -> value = self.blueSave + offset;
            self.redSave = self.redChannel -> value;
            self.blueSave = self.blueChannel -> value;
            self.greenSave = self.greenChannel -> value;
        }
        if (self.blueChannel -> value != self.blueSave) {
            double offset = self.blueChannel -> value - self.blueSave;
            if (self.greenSave + offset > 255) {
                offset = 255 - self.greenSave;
            }
            if (self.redSave + offset > 255) {
                offset = 255 - self.redSave;
            }
            if (self.greenSave + offset < 0) {
                offset = 0 - self.greenSave;
            }
            if (self.redSave + offset < 0) {
                offset = 0 - self.redSave;
            }
            self.blueChannel -> value = self.blueSave + offset;
            self.greenChannel -> value = self.greenSave + offset;
            self.redChannel -> value = self.redSave + offset;
            self.greenSave = self.greenChannel -> value;
            self.redSave = self.redChannel -> value;
            self.blueSave = self.blueChannel -> value;
        }
    }
    /* render annotations to sliders */
    tt_setColor(TT_COLOR_TEXT);
    turtleTextWriteString("Red", self.redChannel -> x - self.redChannel -> length / 2 - self.redChannel -> size, self.redChannel -> y, self.redChannel -> size - 1, 100);
    turtleTextWriteStringf(self.redChannel -> x + self.redChannel -> length / 2 + self.redChannel -> size, self.redChannel -> y, self.redChannel -> size - 1, 0, "%.0lf", round(self.redChannel -> value));
    turtleTextWriteString("Green", self.greenChannel -> x -self. greenChannel -> length / 2 - self.greenChannel -> size, self.greenChannel -> y, self.greenChannel -> size - 1, 100);
    turtleTextWriteStringf(self.greenChannel -> x + self.greenChannel -> length / 2 + self.greenChannel -> size, self.greenChannel -> y, self.greenChannel -> size - 1, 0, "%.0lf", round(self.greenChannel -> value));
    turtleTextWriteString("Blue", self.blueChannel -> x - self.blueChannel -> length / 2 - self.blueChannel -> size, self.blueChannel -> y, self.blueChannel -> size - 1, 100);
    turtleTextWriteStringf(self.blueChannel -> x + self.blueChannel -> length / 2 + self.blueChannel -> size, self.blueChannel -> y, self.blueChannel -> size - 1, 0, "%.0lf", round(self.blueChannel -> value));
    turtleTextWriteString("Size", self.sizeSlider -> x - self.sizeSlider -> length / 2 - self.sizeSlider -> size, self.sizeSlider -> y, self.sizeSlider -> size - 1, 100);
    turtleTextWriteStringf(self.sizeSlider -> x + self.sizeSlider -> length / 2 + self.sizeSlider -> size, self.sizeSlider -> y, self.sizeSlider -> size - 1, 0, "%.0lf", round(self.sizeSlider -> value));
    turtlePenColor(self.redChannel -> value, self.greenChannel -> value, self.blueChannel -> value);
    turtlePenSize(16);
    turtleGoto(self.sidebarX, 40);
    turtlePenDown();
    turtlePenUp();
}

void frameBoundsCheck() {
    if ((self.canvasX + self.canvasWidth / 2 + self.editingX) * self.editingZoom < self.canvasX + self.canvasWidth / 2) {
        self.editingX = (self.canvasX + self.canvasWidth / 2) / self.editingZoom - self.canvasX - self.canvasWidth / 2;
    }
    if ((self.canvasX - self.canvasWidth / 2 + self.editingX) * self.editingZoom > self.canvasX - self.canvasWidth / 2) {
        self.editingX = (self.canvasX - self.canvasWidth / 2) / self.editingZoom - self.canvasX + self.canvasWidth / 2;
    }
    if ((self.canvasY + self.canvasHeight / 2 + self.editingY) * self.editingZoom < self.canvasY + self.canvasHeight / 2) {
        self.editingY = (self.canvasY + self.canvasHeight / 2) / self.editingZoom - self.canvasY - self.canvasHeight / 2;
    }
    if ((self.canvasY - self.canvasHeight / 2 + self.editingY) * self.editingZoom > self.canvasY - self.canvasHeight / 2) {
        self.editingY = (self.canvasY - self.canvasHeight / 2) / self.editingZoom - self.canvasY + self.canvasHeight / 2;
    }
}

void mouse() {
    if (turtleKeyPressed(GLFW_KEY_LEFT_SHIFT)) {
        self.keys[EDITOR_KEYS_LEFT_SHIFT] = 1;
        if (self.lockOffsets == 0) {
            self.lockOffsets = 1;
            self.redSave = self.redChannel -> value;
            self.greenSave = self.greenChannel -> value;
            self.blueSave = self.blueChannel -> value;
        }
    } else {
        self.lockOffsets = 0;
        self.keys[EDITOR_KEYS_LEFT_SHIFT] = 0;
    }
    if (turtleMouseLeft()) {
        if (self.keys[EDITOR_KEYS_LMB] == 0) {
            self.keys[EDITOR_KEYS_LMB] = 1;
            if (turtle.mouseX >= self.canvasX - self.canvasWidth / 2 && turtle.mouseX <= self.canvasX + self.canvasWidth / 2 && turtle.mouseY >= self.canvasY - self.canvasHeight / 2 && turtle.mouseY <= self.canvasY + self.canvasHeight / 2) {
                list_append(self.draw, (unitype) self.redChannel -> value, 'i'); // DRAW_INDEX_RED
                list_append(self.draw, (unitype) self.greenChannel -> value, 'i'); // DRAW_INDEX_GREEN
                list_append(self.draw, (unitype) self.blueChannel -> value, 'i'); // DRAW_INDEX_BLUE
                list_append(self.draw, (unitype) 0, 'i'); // DRAW_INDEX_ALPHA
                list_append(self.draw, (unitype) self.sizeSlider -> value, 'd'); // DRAW_INDEX_SIZE
                list_append(self.draw, (unitype) (turtle.mouseX / self.editingZoom - self.editingX - self.canvasX), 'd'); // DRAW_INDEX_X
                list_append(self.draw, (unitype) (turtle.mouseY / self.editingZoom - self.editingY - self.canvasY), 'd'); // DRAW_INDEX_Y
                list_append(self.draw, (unitype) 0, 'i'); // DRAW_INDEX_PEN_DOWN
                self.drawing = 1;
            }
        }
        if (self.drawing) {
            list_append(self.draw, (unitype) self.redChannel -> value, 'd'); // DRAW_INDEX_RED
            list_append(self.draw, (unitype) self.greenChannel -> value, 'd'); // DRAW_INDEX_GREEN
            list_append(self.draw, (unitype) self.blueChannel -> value, 'd'); // DRAW_INDEX_BLUE
            list_append(self.draw, (unitype) 0.0, 'd'); // DRAW_INDEX_ALPHA
            list_append(self.draw, (unitype) self.sizeSlider -> value, 'd'); // DRAW_INDEX_SIZE
            list_append(self.draw, (unitype) (turtle.mouseX / self.editingZoom - self.editingX - self.canvasX), 'd'); // DRAW_INDEX_X
            list_append(self.draw, (unitype) (turtle.mouseY / self.editingZoom - self.editingY - self.canvasY), 'd'); // DRAW_INDEX_Y
            list_append(self.draw, (unitype) 1, 'i'); // DRAW_INDEX_PEN_DOWN
        }
    } else {
        self.keys[EDITOR_KEYS_LMB] = 0;
        self.drawing = 0;
    }
    if (turtleMouseRight()) {
        if (self.keys[EDITOR_KEYS_RMB] == 0) {
            self.keys[EDITOR_KEYS_RMB] = 1;
            if (turtle.mouseX >= self.canvasX - self.canvasWidth / 2 && turtle.mouseX <= self.canvasX + self.canvasWidth / 2 && turtle.mouseY >= self.canvasY - self.canvasHeight / 2 && turtle.mouseY <= self.canvasY + self.canvasHeight / 2) {
                self.anchorEditingX = self.editingX;
                self.anchorEditingY = self.editingY;
                self.anchorMouseX = turtle.mouseX;
                self.anchorMouseY = turtle.mouseY;
                self.editingMoving = 1;
            }
        } else {
            if (self.editingMoving) {
                self.editingX = self.anchorEditingX + (turtle.mouseX - self.anchorMouseX) / self.editingZoom;
                self.editingY = self.anchorEditingY + (turtle.mouseY - self.anchorMouseY) / self.editingZoom;
                frameBoundsCheck();
            }
        }
    } else {
        self.keys[EDITOR_KEYS_RMB] = 0;
    }
    /* scrollwheel */
    double scroll = turtleMouseWheel();
    if (scroll > 0) {
        if (turtle.mouseX >= self.canvasX - self.canvasWidth / 2 && turtle.mouseX <= self.canvasX + self.canvasWidth / 2 && turtle.mouseY >= self.canvasY - self.canvasHeight / 2 && turtle.mouseY <= self.canvasY + self.canvasHeight / 2) {
            /* zoom in (frame) */
            const double scrollSpeed = 1.1;
            self.editingX -= (turtle.mouseX * (-1 / scrollSpeed + 1)) / self.editingZoom;
            self.editingY -= (turtle.mouseY * (-1 / scrollSpeed + 1)) / self.editingZoom;
            self.editingZoom *= scrollSpeed;
            frameBoundsCheck();
        }
    } else if (scroll < 0) {
        if (turtle.mouseX >= self.canvasX - self.canvasWidth / 2 && turtle.mouseX <= self.canvasX + self.canvasWidth / 2 && turtle.mouseY >= self.canvasY - self.canvasHeight / 2 && turtle.mouseY <= self.canvasY + self.canvasHeight / 2) {
            /* zoom out (frame) */
            const double scrollSpeed = 1.1;
            self.editingZoom /= scrollSpeed;
            if (self.editingZoom < 1) {
                self.editingZoom = 1;
            }
            self.editingX += (turtle.mouseX * (-1 / scrollSpeed + 1)) / self.editingZoom;
            self.editingY += (turtle.mouseY * (-1 / scrollSpeed + 1)) / self.editingZoom;
            frameBoundsCheck();
        }
    }
}

void parseRibbonOutput() {
    if (tt_ribbon.output[0] == 0) {
        return;
    }
    tt_ribbon.output[0] = 0;
    if (tt_ribbon.output[1] == 0) { // File
        if (tt_ribbon.output[2] == 1) { // New
            list_clear(osToolsFileDialog.selectedFilenames);
            list_clear(self.draw);
            printf("New\n");
        }
        if (tt_ribbon.output[2] == 2) { // Save
            if (osToolsFileDialog.selectedFilenames -> length == 0) {
                if (osToolsFileDialogSave(OSTOOLS_FILE_DIALOG_FILE, "Save.txt", NULL) != -1) {
                    printf("Saved to: %s\n", osToolsFileDialog.selectedFilenames -> data[0].s);
                }
            } else {
                printf("Saved to: %s\n", osToolsFileDialog.selectedFilenames -> data[0].s);
            }
        }
        if (tt_ribbon.output[2] == 3) { // Save As...
            list_clear(osToolsFileDialog.selectedFilenames);
            if (osToolsFileDialogSave(OSTOOLS_FILE_DIALOG_FILE, "Save.txt", NULL) != -1) {
                printf("Saved to: %s\n", osToolsFileDialog.selectedFilenames -> data[0].s);
            }
        }
        if (tt_ribbon.output[2] == 4) { // Open
            list_clear(osToolsFileDialog.selectedFilenames);
            if (osToolsFileDialogOpen(OSTOOLS_FILE_DIALOG_MULTIPLE_SELECT, OSTOOLS_FILE_DIALOG_FILE, "", NULL) != -1) {
                printf("Loaded data from: ");
                list_print(osToolsFileDialog.selectedFilenames);
            }
        }
    }
    if (tt_ribbon.output[1] == 1) { // View
        if (tt_ribbon.output[2] == 1) { // Change theme
            if (tt_theme == TT_THEME_DARK) {
                turtleBackgroundColor(36, 30, 32);
                turtleToolsSetTheme(TT_THEME_COLT);
                printf("Theme: Colt\n");
            } else if (tt_theme == TT_THEME_COLT) {
                turtleBackgroundColor(212, 201, 190);
                turtleToolsSetTheme(TT_THEME_NAVY);
                printf("Theme: Navy\n");
            } else if (tt_theme == TT_THEME_NAVY) {
                turtleBackgroundColor(255, 255, 255);
                turtleToolsSetTheme(TT_THEME_LIGHT);
                printf("Theme: Light\n");
            } else if (tt_theme == TT_THEME_LIGHT) {
                turtleBackgroundColor(30, 30, 30);
                turtleToolsSetTheme(TT_THEME_DARK);
                printf("Theme: Dark\n");
            }
        } 
    }
}

int main(int argc, char *argv[]) {
    /* Initialise window */
    GLFWwindow *window = turtleCreateWindow(TURTLE_WINDOW_DEFAULT_WIDTH, TURTLE_WINDOW_DEFAULT_HEIGHT, "draw mouse demo");
    /* initialise turtle */
    turtleInit(window, -320, -180, 320, 180);
    /* initialise turtleText */
    turtleTextInit("config/roberto.tgl");
    /* initialise ribbon */
    list_t *ribbonConfig = list_init();
    list_append(ribbonConfig, (unitype) "File, 📄 New, 📄 Save, 📄 Save As..., 📄 Open", 's');
    list_append(ribbonConfig, (unitype) "View, Change Theme", 's');
    tt_ribbonInitList(ribbonConfig);
    /* initialise osTools */
    osToolsInit(argv[0], window);

    init();

    uint32_t tps = 60; // ticks per second (locked to fps in this case)
    uint64_t tick = 0; // count number of ticks since application started
    clock_t start, end;

    while (turtle.close == 0) {
        start = clock();
        turtleClear(); // clear the screen
        turtleGetMouseCoordinates();
        mouse();
        render();
        parseRibbonOutput(); // user defined function to use ribbon
        turtleToolsUpdate(); // update turtleTools
        /* render camera flash (in front of all UI) */
        if (self.cameraAnimation > 0) {
            turtleRectangleColor(-320, -180, 320, 180, 255, 255, 255, self.cameraAnimation * 10);
            self.cameraAnimation++;
            if (self.cameraAnimation > 25) {
                self.cameraAnimation = 0;
            }
        }
        turtleUpdate(); // update the screen
        end = clock();
        while ((double) (end - start) / CLOCKS_PER_SEC < (1.0 / tps)) {
            end = clock();
        }
        tick++;
    }
    turtleFree();
    glfwTerminate();
}

OsTools Examples

Clone this wiki locally