0

I've been working on creating my own GUI library for MS-DOS on my free time and I got stuck on how I can implement an array that would contain structures of GUI elements.

So far I was able to make it draw the window itself, but I needed a way to draw the elements inside the window such as text boxes, text labels, buttons, ect.

Here's my current code:

#include <stdio.h>
#include <conio.h>
#include <malloc.h>
#include <string.h>

#include "graph.h" //Watcom graphics library

#define false 0
#define true  1

#define border_none 0
#define border_out  1
#define border_in   2

struct text_button {
    char text[128];
    int pos_x;
    int pos_y;
    int size_x;
    int size_y;
    int text_color;
    int button_color;
};

struct window_structure {
    char title[128];
    int pos_x;
    int pos_y;
    int pre_pos_x;
    int pre_pos_y;
    int size_x;
    int size_y;
    int min_size_x;
    int min_size_y;
    int max_size_x;
    int max_size_y;
    int show_tab;
    int border_type;
    int focused;
    //Right here is where I would add the array containing the elements.
};

void draw_border(int type,int pos_x,int pos_y,int size_x,int size_y) {
    int c_1,c_2;

    if (type==1) {
        c_1=15;
        c_2=0;
    } else if (type==2) {
        c_1=0;
        c_2=15;
    }

    if (type!=0) {
        _setcolor(c_1);
        _moveto(pos_x,pos_y);
        _lineto(pos_x+size_x,pos_y);
        _moveto(pos_x,pos_y);
        _lineto(pos_x,pos_y+size_y);
        _setcolor(c_2);
        _moveto(pos_x+size_x,pos_y+size_y);
        _lineto(pos_x+size_x,pos_y);
        _moveto(pos_x+size_x,pos_y+size_y);
        _lineto(pos_x,pos_y+size_y);
    }
}

void draw_box(int type,int color,int pos_x,int pos_y,int size_x,int size_y) {
    _setcolor(color);
    _rectangle(_GFILLINTERIOR,pos_x,pos_y,pos_x+size_x,pos_y+size_y);
    draw_border(type,pos_x-1,pos_y-1,size_x+2,size_y+2);
}

struct window_structure create_window(
    char title[],
    int pos_x,
    int pos_y,
    int size_x,
    int size_y,
    int min_size_x,
    int min_size_y,
    int max_size_x,
    int max_size_y,
    int show_tab,
    int border_type
) {
    struct window_structure window;

    strcpy(window.title,title);
    window.pos_x=pos_x;
    window.pos_y=pos_y;
    window.pre_pos_x=pos_x;
    window.pre_pos_y=pos_y;
    window.size_x=size_x;
    window.size_y=size_y;
    window.min_size_x=min_size_x;
    window.min_size_y=min_size_y;
    window.max_size_x=max_size_x;
    window.max_size_y=max_size_y;
    window.show_tab=show_tab;
    window.border_type=border_type;
    window.focused=true;

    return window;
}

void draw_window(struct window_structure window) {
    int offset_x,offset_y;

    if (window.size_x<window.min_size_x) {
        window.size_x=window.min_size_x;
    } else if (window.size_x>window.max_size_x) {
        window.size_x=window.max_size_x;
    }
    if (window.size_y<window.min_size_y) {
        window.size_y=window.min_size_y;
    } else if (window.size_y>window.max_size_y) {
        window.size_y=window.max_size_y;
    }

    if (window.show_tab==true) {
        int tab_color;

        if (window.focused==true) {
            tab_color=9;
        } else {
            tab_color=8;
        }

        draw_box(
            window.border_type,
            tab_color,
            window.pos_x,
            window.pos_y-1,
            window.size_x-1,
            18
        );
        offset_x=0;
        offset_y=20;
    }

    draw_box(
        window.border_type,
        7,
        window.pos_x+offset_x,
        window.pos_y+offset_y,
        window.size_x-1,
        window.size_y-1
    );

    //Once the window has been drawn, the next part it would do here is draw the elements

    window.pre_pos_x=window.pos_x;
    window.pre_pos_y=window.pos_y;
}

I know MS-DOS is quite outdated, this is just for my hobby. I'm currently using Open Watcom as my compiler.

Jason Lee
  • 83
  • 1
  • 1
  • 5
  • I did find a rough alternative, but I'm still trying to find a much cleaner solution. My current option was to change the script from c to c++ in order to properly use an array, but I still have to declare all the types of GUI elements under window_structure. – Jason Lee Jul 26 '16 at 12:32
  • FWIW, you can take some inspiration from TurboVision, an UI library for DOS. http://tvision.sourceforge.net. – Rudy Velthuis Jul 26 '16 at 17:23
  • The point was to see if I could make my own from scratch. The only other issue I have is that my program is already reaching the 640k limit causing a "stack overflow" error. – Jason Lee Jul 26 '16 at 22:22
  • Is that limit (almost) reached because of your UI code, or just because of the rest of the program logic? I know that Turbo C++ (for DOS) had something called overlays to swap in and swap out pieces of unused code. Does Watcom have something similar? – Rudy Velthuis Jul 26 '16 at 22:28
  • I believe most of it is caused from just my code. I tried to reduce it some parts and deleting minor variables. I also tried to port this to turbo c, and it's apparently even worse. However, I think it can be fixed by using himem. – Jason Lee Jul 26 '16 at 22:51
  • If you can use himem, do so. Can't you write a number of smaller programs which call each other where necessary? – Rudy Velthuis Jul 26 '16 at 22:54
  • You mean using a DLL file? I thought of doing that but I realized even when I use a DLL file, I still have to declare the functions and values in the program that would be using it, which only makes me spend more time typing. I also fixed my memory issue. I found a memory extender which allowed me to pass the 640k barrier and go up to 4 GB, and now my program no longer gets an overflow error. – Jason Lee Jul 27 '16 at 02:25

1 Answers1

0
//Right here is where I would add the array containing the elements.

You know, since you'll have a variable number of elements, you can't declare a fixed-size array here, so you can just declare a pointer and allocate the array as needed. You'll also need to store the number of elements allocated.

struct window_structure
{
    …
    int nelem;                  // how many elements are there
    struct element *elements;   // pointer to allocated elements
};

Both shall be initialized to 0.

struct window_structure create_window(…)
{
    …
    window.nelem = 0;
    window.elements = NULL;
    return window;
}

The struct element type could be defined as

struct element
{   enum elemtype { text_button, /* add other types here */ } elemtype;
    union
    {   struct text_button tb;
        /* add other types here */
    } u;
};

An element, e. g. a text_button, could then be added to the window with

    struct element *new;
    new = realloc(window.elements, (window.nelem+1) * sizeof *new);
    if (!new) exit(1);  // or some better error handling
    window.elements = new;
    window.elements[window.nelem].elemtype = text_button;
    window.elements[window.nelem].u.tb = your_text_button_to_add;
    ++window.nelem;
//Once the window has been drawn, the next part it would do here is draw the elements

This would then be done like

    int i;
    for (i = 0; i < window.nelem; ++i)
        switch (window.elements[i].elemtype)
        {
        case text_button:
            /* draw the text_button window.elements[i].u.tb here */
            break;
        /* add cases for other element types here */
        }
Armali
  • 18,255
  • 14
  • 57
  • 171