Browse Source

Revised SDL Clicky for upload to the new repository

master
Zelaven 3 years ago
commit
8ba2e4e014
16 changed files with 937 additions and 0 deletions
  1. +20
    -0
      .gitignore
  2. +52
    -0
      Makefile
  3. +15
    -0
      README.md
  4. +143
    -0
      examples/ClickableAndDragable.c
  5. +174
    -0
      examples/Clickable_Hierarchy.c
  6. +12
    -0
      examples/Makefile
  7. +153
    -0
      examples/SimpleContainer.c
  8. +1
    -0
      examples/compile.sh
  9. +6
    -0
      src/SDL_Clicky.c
  10. +10
    -0
      src/SDL_Clicky.h
  11. +115
    -0
      src/clickable.c
  12. +33
    -0
      src/clickable.h
  13. +84
    -0
      src/clickable_hierarchy.c
  14. +45
    -0
      src/clickable_hierarchy.h
  15. +28
    -0
      src/containers/containers.c
  16. +46
    -0
      src/containers/containers.h

+ 20
- 0
.gitignore View File

@ -0,0 +1,20 @@
### C PROGRAMMING ###
# Object files
*.o
*.obj
*.elf
# Libraries
*.lib
*.a
*.la
*.lo
# Executables
*.out
### EDITOR SPECIFIC FILES ###
# Vim
*.swp

+ 52
- 0
Makefile View File

@ -0,0 +1,52 @@
# Compiler to use. Make does something special with this.
CC = gcc
CFLAGS = -I"/usr/include/SDL2" -g -Wall -lSDL2
ODIR = obj
SDIR = src
_DEPS = SDL_Clicky.h clickable.h clickable_hierarchy.h containers/containers.h
DEPS = $(patsubst %,$(SDIR)/%,$(_DEPS))
_SRC = SDL_Clicky.c clickable.c clickable_hierarchy.c containers/containers.c
SRC = $(patsubst %,$(SDIR)/%,$(_SRC))
_OBJS = $(_SRC:.c=.o)
OBJS = $(patsubst %,$(ODIR)/%,$(_OBJS))
OUT = out/libSDL_Clicky.a
# Rules that are always executed regardless of file states.
.POHNY: clean force forceobjs
# Name isn't special, it's just befitting of being the first rule. The first rule is executed if no rule is specified.
make: $(OUT)
# echo $(OBJS) #Uncomment this line to see if the target gets run or just to get a list of the objs or whatever.
$(ODIR)/%.o: $(SDIR)/%.c $(DEPS)
$(CC) $(CFLAGS) -c $< -o $@
#obj/SDL_Clicky.o: src/SDL_Clicky.c $(DEPS)
# $(CC) -c $< -o $@
#obj/%.o: src/%.c $(DEPS)
# $(CC) -c $< -o $@
# Compiling the actual build.
$(OUT): $(OBJS)
#$(CC) $(OBJS) -c -o obj/libSDL_Clicky.o;
#ar rcs $(OUT) obj/libSDL_Clicky.o;
ar rcs $(OUT) $(OBJS);
# Primitive targets for forcing a compilation. Cleans up after themselves. NOT UPDATED FOR USE HERE! IT WAS COPY-PASTED FROM ELSEWHERE!
forceobjs:
$(CC) -c $(SRC)
force: forceobjs
$(CC) $(_OBJS) -o $(OUT); rm *.o
# Rule that is always executed regardless of the states of the files. Deletes junk.
clean:
rm $(OUT) $(ODIR)/*.o;
asdf:
echo $(OBJS)

+ 15
- 0
README.md View File

@ -0,0 +1,15 @@
# SDL Clicky
This is a simple library for working with GUI in SDL. By providing simple and flexible types and methods, the user can compose their own aggregate types for more complex purposes if need be.
The library relies on the fact that, on any system the author can think of that this library would ever feasibly be used to make an application for, the address of a struct is the same as the address of its first member. This is used as a form of singular inheritance, which lays the foundation of the structure of the library.
## Using SDL Clicky
The library is not ready for use. If you want to take a look, then consult the examples folder.
## Contributing
I am not open to contributions at this stage of development
## License
This project is my personal work. I do not provide it under any license because I can't be bothered with those things.
I permit using it under the common sense approach of giving credit. If you have a credits list for your project, then list me there, otherwise find a good spot.

+ 143
- 0
examples/ClickableAndDragable.c View File

@ -0,0 +1,143 @@
#include <SDL.h>
#include <stdio.h>
#include <stdbool.h>
#include "../src/SDL_Clicky.h"
void clickedClickable(void *c_, int x, int y) {
Clickable *c = c_;
printf("Size of clicked clickable at %p: %d x %d\n", c_, c->dimensions.w, c->dimensions.h);
}
bool quit = false;
void clickFunc_QuitButton(void *c_, int x, int y) {
quit = true;
}
int main() {
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
fprintf(stderr, "Could not initialize SDL: %s\n", SDL_GetError());
return 1;
}
printf("SDL Initialized\n");
SDL_Window* screen;
screen = SDL_CreateWindow("My Game Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
if(!screen) {
fprintf(stderr, "Could not set video mode: %s\n", SDL_GetError());
return 1;
}
SDL_Renderer* renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_PRESENTVSYNC);
if(!renderer) {
SDL_DestroyWindow(screen);
fprintf(stderr, "Could not create renderer: %s", SDL_GetError());
}
Clickable c;
c.dimensions.x = 0;
c.dimensions.y = 0;
c.dimensions.w = 100;
c.dimensions.h = 100;
c.isdown = false;
c.clickFunc = clickedClickable;
c.releaseFunc = NULL;
Clickable c2;
c2.dimensions.x = 590;
c2.dimensions.y = 0;
c2.dimensions.w = 50;
c2.dimensions.h = 50;
c2.isdown = false;
c2.clickFunc = clickFunc_QuitButton;
c2.releaseFunc = NULL;
SDL_Rect screenBounds;
screenBounds.x = 100;
screenBounds.y = 0;
screenBounds.w = 440 - screenBounds.x;
screenBounds.h = 280 - screenBounds.y;
Dragable d;
d.super.dimensions.x = 200;
d.super.dimensions.y = 100;
d.super.dimensions.w = 50;
d.super.dimensions.h = 50;
d.super.isdown = false;
d.super.clickFunc = Dragable_ClickFunc;
d.super.releaseFunc = Dragable_ReleaseFunc;
d.boundaries = &screenBounds;
d.coordinatesToDrag = &(d.super.dimensions); //Drag itself.
SDL_Event e;
while(!quit) {
while(SDL_PollEvent(&e)) {
switch(e.type) {
case SDL_QUIT:
quit = true;
break;
case SDL_MOUSEBUTTONDOWN:
/*if(Clickable_CheckBounds(&c ,e.button.x, e.button.y) == true) {
//printf("Clicked clickable at addr %p\n", &c);
c.clickFunc((void*)&c, e.button.x, e.button.y);
}
if(Clickable_CheckBounds(&(d.super) ,e.button.x, e.button.y) == true) {
//printf("Clicked clickable at addr %p\n", &c);
d.super.clickFunc((void*)&(d.super), e.button.x, e.button.y);
}*/
Clicky_ClickClickable((void*)&c, e.button.x, e.button.y);
Clicky_ClickClickable((void*)&c2, e.button.x, e.button.y);
Clicky_ClickClickable((void*)&d, e.button.x, e.button.y); //d has a Clickable as supertype.
break;
case SDL_MOUSEBUTTONUP:
/*if(Clickable_CheckBounds(&c ,e.button.x, e.button.y) == true) {
printf("Clicked clickable at addr %p\n", &c);
c.clickFunc((void*)&c, e.button.x, e.button.y);
}*/
/*if(Clickable_CheckBounds(&(d.super) ,e.button.x, e.button.y) == true) {
//printf("Released clickable at addr %p\n", &c);
d.super.releaseFunc((void*)&(d.super), e.button.x, e.button.y);
}*/
//These shouldn't be necessary, but they're there.
//Clicky_ReleaseClickable((void*)&c, e.button.x, e.button.y);
//Clicky_ReleaseClickable((void*)&d, e.button.x, e.button.y); //d has a Clickable as supertype.
Clicky_ReleaseHeldClickable(e.button.x, e.button.y);
break;
case SDL_MOUSEMOTION:
Clicky_DragUpdate(e.motion.x, e.motion.y);
break;
}
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 0xFF, 0, 0, 0xFF);
SDL_RenderFillRect(renderer, &(c.dimensions));
SDL_SetRenderDrawColor(renderer, 0xFF, 0, 0, 0xFF);
SDL_RenderFillRect(renderer, &(c2.dimensions));
SDL_SetRenderDrawColor(renderer, 0x7F, 0, 0, 0xFF);
SDL_RenderFillRect(renderer, &(screenBounds));
SDL_SetRenderDrawColor(renderer, 0xFF, 0, 0, 0xFF);
SDL_RenderFillRect(renderer, &(d.super.dimensions));
SDL_RenderPresent(renderer);
}
SDL_Quit();
printf("SDL Shutdown\n");
return 0;
}

+ 174
- 0
examples/Clickable_Hierarchy.c View File

@ -0,0 +1,174 @@
#include <SDL.h>
#include <stdio.h>
#include <stdbool.h>
#include "../src/SDL_Clicky.h"
void clickedClickable(void *c_, int x, int y) {
Clickable *c = c_;
printf("Size of clicked clickable at %p: %d x %d\n", c_, c->dimensions.w, c->dimensions.h);
}
void clickable_draw_red(void* c_, SDL_Renderer* r) {
Clickable *c = c_;
SDL_SetRenderDrawColor(r, 0xFF, 0, 0, 0xFF);
SDL_RenderFillRect(r, &(c->dimensions));
}
void clickable_draw_darkred(void* c_, SDL_Renderer* r) {
Clickable *c = c_;
SDL_SetRenderDrawColor(r, 0x99, 0, 0, 0xFF);
SDL_RenderFillRect(r, &(c->dimensions));
}
bool quit = false;
void clickFunc_QuitButton(void *c_, int x, int y) {
quit = true;
}
int main() {
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
fprintf(stderr, "Could not initialize SDL: %s\n", SDL_GetError());
return 1;
}
printf("SDL Initialized\n");
SDL_Window* screen;
screen = SDL_CreateWindow("My Game Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
if(!screen) {
fprintf(stderr, "Could not set video mode: %s\n", SDL_GetError());
return 1;
}
SDL_Renderer* renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_PRESENTVSYNC);
if(!renderer) {
SDL_DestroyWindow(screen);
fprintf(stderr, "Could not create renderer: %s", SDL_GetError());
}
Clickable_Hierarchy hierarchy = {
.num_children = 0,
.num_children_slots = 4,
.children = malloc(sizeof(Clickable_Hierarchy_Element)*4),
};
Clickable c;
c.dimensions.x = 0;
c.dimensions.y = 0;
c.dimensions.w = 100;
c.dimensions.h = 100;
c.isdown = false;
c.clickFunc = clickedClickable;
c.releaseFunc = NULL;
c.drawFunc = clickable_draw_red;
Clicky_Clickable_Hierarchy_Add_Clickable(&hierarchy, &c);
Clickable c2;
c2.dimensions.x = 590;
c2.dimensions.y = 0;
c2.dimensions.w = 50;
c2.dimensions.h = 50;
c2.isdown = false;
c2.clickFunc = clickFunc_QuitButton;
c2.releaseFunc = NULL;
c2.drawFunc = clickable_draw_red;
Clicky_Clickable_Hierarchy_Add_Clickable(&hierarchy, &c2);
SDL_Rect screenBounds;
screenBounds.x = 100;
screenBounds.y = 0;
screenBounds.w = 340;
screenBounds.h = 300;
Dragable d;
d.super.dimensions.x = 200;
d.super.dimensions.y = 100;
d.super.dimensions.w = 50;
d.super.dimensions.h = 50;
d.super.isdown = false;
d.super.clickFunc = Dragable_ClickFunc;
d.super.releaseFunc = Dragable_ReleaseFunc;
d.super.drawFunc = clickable_draw_red;
d.boundaries = &screenBounds;
d.coordinatesToDrag = &(d.super.dimensions); //Drag itself.
Clicky_Clickable_Hierarchy_Add_Clickable(&hierarchy, &(d.super));
//Container thing testing!
Scrollbar_Container* scrollbar = Scrollbar_Container_Constructor(25, 150, 50, 100, 20);
scrollbar->super.drawFunc = clickable_draw_darkred;
scrollbar->bar.super.drawFunc = clickable_draw_red;
//Clicky_Clickable_Hierarchy_Add_Clickable(&hierarchy, &(scrollbar->bar.super));
Clickable_Hierarchy *sh = Clicky_Clickable_Hierarchy_Add_Subtree(&hierarchy, &(scrollbar->super), 1);
Clicky_Clickable_Hierarchy_Add_Clickable(sh, &(scrollbar->bar.super));
SDL_Event e;
while(!quit) {
while(SDL_PollEvent(&e)) {
switch(e.type) {
case SDL_QUIT:
quit = true;
break;
case SDL_MOUSEBUTTONDOWN:
/*if(Clickable_CheckBounds(&c ,e.button.x, e.button.y) == true) {
//printf("Clicked clickable at addr %p\n", &c);
c.clickFunc((void*)&c, e.button.x, e.button.y);
}
if(Clickable_CheckBounds(&(d.super) ,e.button.x, e.button.y) == true) {
//printf("Clicked clickable at addr %p\n", &c);
d.super.clickFunc((void*)&(d.super), e.button.x, e.button.y);
}*/
//Clicky_ClickClickable((void*)&c, e.button.x, e.button.y);
//Clicky_ClickClickable((void*)&c2, e.button.x, e.button.y);
//Clicky_ClickClickable((void*)&d, e.button.x, e.button.y); //d has a Clickable as supertype.
Clicky_Clickable_Hierarchy_Click(&hierarchy, e.button.x, e.button.y);
break;
case SDL_MOUSEBUTTONUP:
/*if(Clickable_CheckBounds(&c ,e.button.x, e.button.y) == true) {
printf("Clicked clickable at addr %p\n", &c);
c.clickFunc((void*)&c, e.button.x, e.button.y);
}*/
/*if(Clickable_CheckBounds(&(d.super) ,e.button.x, e.button.y) == true) {
//printf("Released clickable at addr %p\n", &c);
d.super.releaseFunc((void*)&(d.super), e.button.x, e.button.y);
}*/
//These shouldn't be necessary, but they're there.
//Clicky_ReleaseClickable((void*)&c, e.button.x, e.button.y);
//Clicky_ReleaseClickable((void*)&d, e.button.x, e.button.y); //d has a Clickable as supertype.
Clicky_ReleaseHeldClickable(e.button.x, e.button.y);
break;
case SDL_MOUSEMOTION:
Clicky_DragUpdate(e.motion.x, e.motion.y);
break;
}
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
//Instead of doing this, the dragable should be put into a container, which should be drawn using the hierarchy.
// The way it is now, the rendering of the things in the hierarchy will all be laid on top, even if they should logically be drawn below.
SDL_SetRenderDrawColor(renderer, 0x7F, 0, 0, 0xFF);
SDL_RenderFillRect(renderer, &(screenBounds));
Clicky_Clickable_Hierarchy_Render(&hierarchy, renderer);
SDL_RenderPresent(renderer);
SDL_Delay(50);
}
SDL_Quit();
printf("SDL Shutdown\n");
return 0;
}

+ 12
- 0
examples/Makefile View File

@ -0,0 +1,12 @@
.PHONY: make
make:
echo "To use: make <tesname>"
echo "Example: make test"
%: %.c
gcc -I"/usr/include/SDL2" -L../out/ -Wall $< -o $@.out -lSDL_Clicky -lSDL2

+ 153
- 0
examples/SimpleContainer.c View File

@ -0,0 +1,153 @@
#include <SDL.h>
#include <stdio.h>
#include <stdbool.h>
#include "../src/SDL_Clicky.h"
void clickedSimpleContainer(void *c_, int x, int y) {
SimpleContainer *c = c_;
printf("Clicked inside of SimpleContainer at %p with size: %d x %d\n", c_, c->super.dimensions.w, c->super.dimensions.h);
}
void drawSimpleContainer(void *c_, SDL_Renderer* renderer) {
SimpleContainer *c = c_;
SDL_SetRenderDrawColor(renderer, 0x7F, 0x7F, 0, 0xFF);
SDL_RenderFillRect(renderer, &(c->super.dimensions));
}
bool quit = false;
void clickFunc_QuitButton(void *c_, int x, int y) {
quit = true;
}
int main() {
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
fprintf(stderr, "Could not initialize SDL: %s\n", SDL_GetError());
return 1;
}
printf("SDL Initialized\n");
SDL_Window* screen;
screen = SDL_CreateWindow("My Game Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
if(!screen) {
fprintf(stderr, "Could not set video mode: %s\n", SDL_GetError());
return 1;
}
SDL_Renderer* renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_PRESENTVSYNC);
if(!renderer) {
SDL_DestroyWindow(screen);
fprintf(stderr, "Could not create renderer: %s", SDL_GetError());
}
SimpleContainer sc;
sc.super.dimensions.x = 0;
sc.super.dimensions.y = 0;
sc.super.dimensions.w = 100;
sc.super.dimensions.h = 100;
sc.super.isdown = false;
sc.super.clickFunc = clickedSimpleContainer;
sc.super.releaseFunc = NULL;
sc.drawFunc = drawSimpleContainer;
Clickable c2;
c2.dimensions.x = 590;
c2.dimensions.y = 0;
c2.dimensions.w = 50;
c2.dimensions.h = 50;
c2.isdown = false;
c2.clickFunc = clickFunc_QuitButton;
c2.releaseFunc = NULL;
SDL_Rect screenBounds;
screenBounds.x = 100;
screenBounds.y = 0;
screenBounds.w = 440 - screenBounds.x;
screenBounds.h = 280 - screenBounds.y;
Dragable d;
d.super.dimensions.x = 200;
d.super.dimensions.y = 100;
d.super.dimensions.w = 50;
d.super.dimensions.h = 50;
d.super.isdown = false;
d.super.clickFunc = Dragable_ClickFunc;
d.super.releaseFunc = Dragable_ReleaseFunc;
d.boundaries = &screenBounds;
d.coordinatesToDrag = &(d.super.dimensions); //Drag itself.
SDL_Event e;
while(!quit) {
while(SDL_PollEvent(&e)) {
switch(e.type) {
case SDL_QUIT:
quit = true;
break;
case SDL_MOUSEBUTTONDOWN:
/*if(Clickable_CheckBounds(&c ,e.button.x, e.button.y) == true) {
//printf("Clicked clickable at addr %p\n", &c);
c.clickFunc((void*)&c, e.button.x, e.button.y);
}
if(Clickable_CheckBounds(&(d.super) ,e.button.x, e.button.y) == true) {
//printf("Clicked clickable at addr %p\n", &c);
d.super.clickFunc((void*)&(d.super), e.button.x, e.button.y);
}*/
Clicky_ClickClickable((void*)&sc, e.button.x, e.button.y);
Clicky_ClickClickable((void*)&c2, e.button.x, e.button.y);
Clicky_ClickClickable((void*)&d, e.button.x, e.button.y); //d has a Clickable as supertype.
break;
case SDL_MOUSEBUTTONUP:
/*if(Clickable_CheckBounds(&c ,e.button.x, e.button.y) == true) {
printf("Clicked clickable at addr %p\n", &c);
c.clickFunc((void*)&c, e.button.x, e.button.y);
}*/
/*if(Clickable_CheckBounds(&(d.super) ,e.button.x, e.button.y) == true) {
//printf("Released clickable at addr %p\n", &c);
d.super.releaseFunc((void*)&(d.super), e.button.x, e.button.y);
}*/
//These shouldn't be necessary, but they're there.
//Clicky_ReleaseClickable((void*)&c, e.button.x, e.button.y);
//Clicky_ReleaseClickable((void*)&d, e.button.x, e.button.y); //d has a Clickable as supertype.
Clicky_ReleaseHeldClickable(e.button.x, e.button.y);
break;
case SDL_MOUSEMOTION:
Clicky_DragUpdate(e.motion.x, e.motion.y);
break;
}
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
//SDL_SetRenderDrawColor(renderer, 0xFF, 0, 0, 0xFF);
//SDL_RenderFillRect(renderer, &(c.dimensions));
sc.drawFunc(&sc, renderer);
SDL_SetRenderDrawColor(renderer, 0xFF, 0, 0, 0xFF);
SDL_RenderFillRect(renderer, &(c2.dimensions));
SDL_SetRenderDrawColor(renderer, 0x7F, 0, 0, 0xFF);
SDL_RenderFillRect(renderer, &(screenBounds));
SDL_SetRenderDrawColor(renderer, 0xFF, 0, 0, 0xFF);
SDL_RenderFillRect(renderer, &(d.super.dimensions));
SDL_RenderPresent(renderer);
}
SDL_Quit();
printf("SDL Shutdown\n");
return 0;
}

+ 1
- 0
examples/compile.sh View File

@ -0,0 +1 @@
make $1

+ 6
- 0
src/SDL_Clicky.c View File

@ -0,0 +1,6 @@
#include <SDL.h>
#include "SDL_Clicky.h"

+ 10
- 0
src/SDL_Clicky.h View File

@ -0,0 +1,10 @@
#ifndef SDL_CLICKY_H_
#define SDL_CLICKY_H_
#include "clickable.h"
#include "clickable_hierarchy.h"
#include "containers/containers.h"
#endif //SDL_CLICKY_H_

+ 115
- 0
src/clickable.c View File

@ -0,0 +1,115 @@
#include <stdbool.h>
#include "clickable.h"
bool Clickable_CheckBounds(Clickable *c, int x, int y) {
if(c->dimensions.x < x
&&c->dimensions.x+c->dimensions.w > x
&&c->dimensions.y < y
&&c->dimensions.y+c->dimensions.h > y
) {
return true;
}
else {
return false;
}
}
Clickable *heldClickable;
//Calls the clickables clickFunc iff the mouse is inside the clickable.
//Returns true if it is clicked regardless of whether the clickFunc is NULL or not, and false otherwise.
bool Clicky_ClickClickable(void *c_, int x, int y) {
//printf("CALL: Clicky_ClickClickable\n Params: %p, %d, %d\n", c_, x, y);
Clickable *c = c_;
if(Clickable_CheckBounds(c, x, y)) {
heldClickable = c;
if(c->clickFunc != NULL) { //Not necessarily true.
c->clickFunc((void*)c, x, y);
}
return true; //It doesn't matter if the clickable does anything, if it is clicked it reports it.
}
return false;
}
//Calls the clickables releaseFunc iff the mouse is inside the clickable.
void Clicky_ReleaseClickable(void *c_, int x, int y) {
Clickable *c = c_;
if(Clickable_CheckBounds(c, x, y)) {
heldClickable = c;
if(c->releaseFunc != NULL) { //Not necessarily true.
c->releaseFunc((void*)c, x, y);
}
}
}
//Calls the releasefunc of the held clickable, if it isn't NULL.
void Clicky_ReleaseHeldClickable(int x, int y) {
//printf("Releasing held clickable.\n");
//printf(" heldClickable: %p\n", heldClickable);
//printf(" heldClickable->x: %d\n", heldClickable->dimensions.x);
//printf(" heldClickable->releaseFunc: %p\n", heldClickable->releaseFunc);
if(heldClickable == NULL) {
return; //Nothing to do.
}
//Only call the function if it exists.
if(heldClickable->releaseFunc != NULL) {
heldClickable->releaseFunc(heldClickable, x, y);
}
//Always clear this.
heldClickable = NULL;
}
Dragable *currentDragged = NULL; //This gets dragged on.
SDL_Rect dragOffset; //When a dragable gets dragged, this is the local offset into the container to move.
void Clicky_DragUpdate(int x, int y) {
if(currentDragged == NULL) {
return; //Nothing to do here.
}
Dragable *d = currentDragged;
d->coordinatesToDrag->x = x-dragOffset.x;
d->coordinatesToDrag->y = y-dragOffset.y;
//Check boundaries.
if(d->boundaries != NULL) {
//Left boundary.
if(d->coordinatesToDrag->x < d->boundaries->x) {
d->coordinatesToDrag->x = d->boundaries->x;
}
//Upper boundary.
if(d->coordinatesToDrag->y < d->boundaries->y) {
d->coordinatesToDrag->y = d->boundaries->y;
}
//Right boundary.
if(d->coordinatesToDrag->x > d->boundaries->x + d->boundaries->w - d->coordinatesToDrag->w) {
d->coordinatesToDrag->x = d->boundaries->x + d->boundaries->w - d->coordinatesToDrag->w;
}
//Lower boundary.
if(d->coordinatesToDrag->y > d->boundaries->y + d->boundaries->h - d->coordinatesToDrag->h) {
d->coordinatesToDrag->y = d->boundaries->y + d->boundaries->h - d->coordinatesToDrag->h;
}
//printf("New coords: %d, %d, %d, %d\n", d->coordinatesToDrag->x, d->coordinatesToDrag->y, d->coordinatesToDrag->x+d->coordinatesToDrag->w, d->coordinatesToDrag->y+d->coordinatesToDrag->h);
}
}
//Sets the global variables for the dragging mechanism. They are used in the function Dragable_DragUpdate.
void Dragable_ClickFunc(void *dragable, int x, int y) {
//printf("Dragable clicked.\n");
currentDragged = dragable;
dragOffset.x = x - currentDragged->coordinatesToDrag->x;
dragOffset.y = y - currentDragged->coordinatesToDrag->y;
}
//This function clears the global variables so nothing will be dragged.
//The args are ignored.
void Dragable_ReleaseFunc(void *dragable, int x, int y) {
//printf("Dragable released.\n");
currentDragged = NULL;
dragOffset.x = 0;
dragOffset.y = 0;
}

+ 33
- 0
src/clickable.h View File

@ -0,0 +1,33 @@
#ifndef SDL_CLICKY_CLICKABLE_H_
#define SDL_CLICKY_CLICKABLE_H_
#include <SDL.h>
#include <stdbool.h>
typedef struct {
SDL_Rect dimensions;
bool isdown; //When clicked and held.
void (*clickFunc)(void*, int, int); //The function to call when the clickable is registered as clicked. The arg should be set to be a pointer to the clicked clickable. Makes sense when the clickable is the first member (not as pointer) of an "inheriting" type.
void (*releaseFunc)(void*, int, int); //Same as above for when the button is released.
void (*drawFunc)(void*, SDL_Renderer*);
} Clickable;
typedef struct {
Clickable super;
SDL_Rect *boundaries; //Don't go outside these bounds. May be NULL.
SDL_Rect *coordinatesToDrag; //The dragable may be inside a container to be moved around.
} Dragable;
bool Clickable_CheckBounds(Clickable *c, int x, int y);
bool Clicky_ClickClickable(void *c_, int x, int y);
void Clicky_ReleaseClickable(void *c_, int x, int y);
void Clicky_ReleaseHeldClickable(int x, int y);
void Clicky_DragUpdate(int x, int y); //Updates the dragging.
void Dragable_ClickFunc(void *dragable, int x, int y);
void Dragable_ReleaseFunc(void *dragable, int x, int y);
#endif // SDL_CLICKY_CLICKABLE_H_

+ 84
- 0
src/clickable_hierarchy.c View File

@ -0,0 +1,84 @@
#include <stdbool.h>
#include "clickable_hierarchy.h"
void Clicky_Clickable_Hierarchy_Render(Clickable_Hierarchy* ch, SDL_Renderer* r) {
for(int i = 0; i < ch->num_children; i++) {
Clickable_Hierarchy_Element* elem = (ch->children)+i;
//Render the clickable.
if(elem->clickable->drawFunc != NULL) {
elem->clickable->drawFunc(elem->clickable, r);
}
if(elem->subtree != NULL) {
Clicky_Clickable_Hierarchy_Render(elem->subtree, r);
}
}
}
//True if a clickable was activated, false otherwise.
bool Clicky_Clickable_Hierarchy_Click(Clickable_Hierarchy* ch, int x, int y) {
//printf("Call_ Click_Clickable_Hierarchy_Click\n Params: %p, %d, %d\n", ch, x, y);
//printf(" #children: %d, #children slots: %d, children: %p\n", ch->num_children, ch->num_children_slots, ch->children);
bool retval = false;
for(int i = 0; i < ch->num_children; i++) {
Clickable_Hierarchy_Element* elem = (ch->children)+i;
if(elem->subtree != NULL) { //If it is a container, first attempt its children.
bool innerclick = Clicky_Clickable_Hierarchy_Click(elem->subtree, x, y);
if(!innerclick) { //Didn't hit anything inside the clickable, propagate to the clickable itself.
retval = Clicky_ClickClickable((void*)(elem->clickable), x, y);
if(retval) {break;}
}
} else {
retval = Clicky_ClickClickable((void*)(elem->clickable), x, y);
if(retval) {break;}
}
}
return retval;
}
int Clicky_Clickable_Hierarchy_Add_Clickable(Clickable_Hierarchy* ch, Clickable* cl) {
//printf("Hierarchy: %p, Clickable: %p\n", ch, cl);
//printf(" #children: %d, #children slots: %d, children: %p\n", ch->num_children, ch->num_children_slots, ch->children);
if(ch->num_children >= ch->num_children_slots) {
return 1;
}
//printf("%p, %p\n", ch->children, ch->children+1);
Clickable_Hierarchy_Element *elem = (ch->children+ch->num_children);
//printf("Element pointer: %p\n", elem);
elem->clickable = cl;
elem->subtree = NULL;
ch->num_children++;
return 0;
}
Clickable_Hierarchy* Clicky_Clickable_Hierarchy_Add_Subtree(Clickable_Hierarchy* ch, Clickable* cl, int num_children) {
if(ch->num_children >= ch->num_children_slots) {
return NULL;
}
Clickable_Hierarchy_Element *elem = (ch->children+ch->num_children);
//printf("Element pointer: %p\n", elem);
elem->clickable = cl;
Clickable_Hierarchy* sh = (Clickable_Hierarchy*) malloc(sizeof(Clickable_Hierarchy));
sh->num_children = 0;
sh->num_children_slots = num_children;
sh->children = (Clickable_Hierarchy_Element*) malloc(sizeof(Clickable_Hierarchy_Element)*num_children);
elem->subtree = sh;
ch->num_children++;
return sh;
}

+ 45
- 0
src/clickable_hierarchy.h View File

@ -0,0 +1,45 @@
//This is the central structure that is supposed to make this library be useful.
//It is essentially a rose-tree structure that is traversed in a depth-first-esque manner.
//When rendering, the tree is traversed in "left to right" fashion, rendering everything things as it goes.
//When clicking, the tree is traversed in "right to left" fashion and stops at the first eligible object.
//Possible todo: add usage of nifty means to figure out at runtime when updates are made to structure,
// which objects don't need to be rendered at all and keep track of that by managing the tree structure more closely.
//That might require some trickery, depending on how the management of this structure pans out.
#ifndef SDL_CLICKY_CLICKABLE_HIERARCHY_H_
#define SDL_CLICKY_CLICKABLE_HIERARCHY_H_
#include "clickable.h"
struct Clickable_Hierarchy_Element;
//Simply a list of subtress that may be leaves.
typedef struct {
int num_children;
int num_children_slots;
struct Clickable_Hierarchy_Element* children;
} Clickable_Hierarchy;
//This one requires explanation.
//The clickable should be self-explanatory, this is the clickable that this element represents.
//The subtree, though, determines if this is a leaf (NULL) or not (!NULL). If !NULL, then the clickable is a container object.
//How to use this, from a clickable and container perspective?
// Clickable: Just add it and the subtree will be NULL.
// Container: If your container only renders itself then it should add all of its subelements to the tree.
// If it recursively renders all of its own subelements, then it should not add those to the tree because the tree would render them too.
// That means, if you handle the rendering of subelements, just pretend to only be a clickable.
// If you have a mix for some reason, register as a container but only add the subelements you don't handle yourself.
typedef struct Clickable_Hierarchy_Element {
Clickable* clickable;
Clickable_Hierarchy* subtree;
} Clickable_Hierarchy_Element;
void Clicky_Clickable_Hierarchy_Render(Clickable_Hierarchy* ch, SDL_Renderer* r);
bool Clicky_Clickable_Hierarchy_Click(Clickable_Hierarchy* ch, int x, int y);
int Clicky_Clickable_Hierarchy_Add_Clickable(Clickable_Hierarchy* ch, Clickable* cl);
Clickable_Hierarchy* Clicky_Clickable_Hierarchy_Add_Subtree(Clickable_Hierarchy* ch, Clickable* cl, int numchildren);
#endif // SDL_CLICKY_CLICKABLE_HIERARCHY_H_

+ 28
- 0
src/containers/containers.c View File

@ -0,0 +1,28 @@
#include "containers.h"
Scrollbar_Container* Scrollbar_Container_Constructor(int x, int y, int width, int height, int blockheight) {
Scrollbar_Container* sb = malloc(sizeof(Scrollbar_Container));
sb->super.dimensions.x = x;
sb->super.dimensions.y = y;
sb->super.dimensions.w = width;
sb->super.dimensions.h = height;
sb->super.isdown = false;
sb->super.clickFunc = NULL;
sb->super.releaseFunc = NULL;
sb->super.drawFunc = NULL;
sb->bar.super.dimensions.x = x;
sb->bar.super.dimensions.y = y;
sb->bar.super.dimensions.w = width;
sb->bar.super.dimensions.h = blockheight;
sb->bar.super.isdown = false;
sb->bar.super.clickFunc = Dragable_ClickFunc;
sb->bar.super.releaseFunc = Dragable_ReleaseFunc;
sb->bar.super.drawFunc = NULL;
sb->bar.boundaries = &(sb->super.dimensions);
sb->bar.coordinatesToDrag = &(sb->bar.super.dimensions);
return sb;
}

+ 46
- 0
src/containers/containers.h View File

@ -0,0 +1,46 @@
#ifndef SDL_CLICKY_CONTAINERS_H_
#define SDL_CLICKY_CONTAINERS_H_
#include <SDL.h>
#include "../clickable.h"
//This idea has been scrapped. Function argument polymorphism isn't the answer to this problem.
/*
typedef struct ClickyContainerFunctionTable;
typedef struct {
void *container;
struct functions;
} ClickyContainer;
*/
//Inheritance is king. Inherit from Clickable and go nuts.
//Dragable containers are a bit of a problem, but not too badly. Having a container be a dragable isn't something I can think of a use for right now, and even then it should be possible to deal with by simply having a dragable inside the container.
//Simple container. It's a clickable that can be drawn.
// The drawing can be one in any way the user wants to, which means that it is sufficient for things like simple button and such. In fact, it's sufficient for a lot of things. Other container types simply provide functionality for the sake of not having to implement it yourself.
// Another thing with this container is that each variant of drawing requires another drawing function, as the drawing function doesn't take any additional arguments.
// In theory, adding a single void* to this container could act as an extension by composition, where the pointer could point to any data that could ever be desired. Perhaps this fact should be given more consideration, though it would have to be handled very well to not be a hassle to use for the user.
typedef struct {
Clickable super;
} SimpleContainer;
// ^ Might not even have any use. It will stick around for now.
//A container for a scroll bar. It should have related functions but at the time of writing, it is simply used for testing the clickable hierarchy structure.
typedef struct {
Clickable super;
Dragable bar;
} Scrollbar_Container;
Scrollbar_Container* Scrollbar_Container_Constructor(int x, int y, int width, int height, int blockheight);
//Add more container types here.
#endif // SDL_CLICKY_CONTAINERS_H_

Loading…
Cancel
Save