Skip to content

Commit 6d076ef

Browse files
committed
initial commit
Signed-off-by: Jens Nyberg <[email protected]>
0 parents  commit 6d076ef

19 files changed

+4026
-0
lines changed

LICENCE

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Copyright (c) 2019 Jens Nyberg
2+
3+
Permission is hereby granted, free of charge, to any person
4+
obtaining a copy of this software and associated documentation
5+
files (the "Software"), to deal in the Software without
6+
restriction, including without limitation the rights to use,
7+
copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the
9+
Software is furnished to do so, subject to the following
10+
conditions:
11+
12+
The above copyright notice and this permission notice shall be
13+
included in all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22+
OTHER DEALINGS IN THE SOFTWARE.
23+

Makefile

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
BIN1:=navi
2+
OBJ1:=src/navi.o src/list.o src/parser.o src/box.o
3+
BIN2:=alfi
4+
OBJ2:=src/alfi.o src/list.o src/parser.o
5+
6+
all: $(BIN1) $(BIN2)
7+
8+
%.o: %.c
9+
$(CC) -c -o $@ -Wall -Werror -std=c89 -pedantic $^
10+
11+
$(BIN1): $(OBJ1)
12+
$(CC) -o $@ -Wall -Werror -std=c89 -pedantic $^ -lm -lGL -lglfw -lnanovg
13+
14+
$(BIN2): $(OBJ2)
15+
$(CC) -o $@ -Wall -Werror -std=c89 -pedantic $^
16+
17+
clean:
18+
$(RM) $(BIN1) $(OBJ1) $(BIN2) $(OBJ2)

README.md

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# ALFI
2+
3+
ALFI is a query language for graphical user interfaces.
4+
5+
ALFI works in a similar way to SQL but instead of talking to a database you talk
6+
to an ALFI client (or ALFI browser). The ALFI browser will convert the ALFI
7+
queries into graphical elements (i.e. widgets) and render them on the screen.
8+
9+
An ALFI query will tell the client to either insert, delete or update an
10+
element. ALFI is stateless so a typical use-case would be to have a regular web
11+
server serving ALFI queries as responses from regular HTTP requests (like GET,
12+
POST, etc).
13+
14+
The biggest strength of ALFI is that it requires very little technical skill to
15+
get started. If you know basic SQL you can easily write ALFI too. Writing an
16+
ALFI application is much simpler than writing an application using
17+
HTML/JavaScript/CSS.
18+
19+
NAVI is a proof of concept client/browser for ALFI. It takes ALFI queries and
20+
renders widgets in OpenGL. It is currently very much under development.
21+
22+
## Building / Installing
23+
24+
You need to have the glfw3 and nanovg libraries installed in order to be able to
25+
build NAVI. Installing these depends on your distribution of choice.
26+
27+
Build:
28+
29+
$ make
30+
31+
Install:
32+
33+
$ make install
34+
35+
And that's it.
36+
37+
## Running
38+
39+
To parse an alfi file:
40+
41+
$ alfi < example.alfi
42+
43+
To start navi:
44+
45+
$ navi
46+
47+
## Contact
48+
49+
50+
51+
https://github.com/jezze/alfi
52+

data/icofont.ttf

1020 KB
Binary file not shown.

data/image6.jpg

24.5 KB
Loading

data/navi.png

33.8 KB
Loading

data/roboto-bold.ttf

133 KB
Binary file not shown.

data/roboto-light.ttf

137 KB
Binary file not shown.

data/roboto-regular.ttf

142 KB
Binary file not shown.

example.alfi

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Set label of window
2+
= window label "Example window"
3+
4+
# A header and some text
5+
+ header label "What a wonderful world"
6+
+ text label "This is some text."
7+
+ subheader label "This is a subheader"
8+
+ text label "Below is a form."
9+
10+
# Basic form elements
11+
+ field id field1 type regular label "Username"
12+
+ field id field2 type password label "Password"
13+
+ select id select1 range 1 1 label "Select"
14+
+ choice in select1 id choice1 label "Option 1"
15+
+ choice in select1 id choice2 label "Option 2"
16+
+ choice in select1 id choice3 label "Option 3"
17+
+ button id submit label "Submit"
18+
19+
# Two nested lists
20+
+ list id list1
21+
+ text in list1 label "Item 1-1"
22+
+ text in list1 label "Item 1-2"
23+
+ list in list1 id list2
24+
+ text in list2 label "Item 2-1"
25+
+ text in list2 label "Item 2-2"
26+
27+
# A row of images
28+
+ hstack id gallery halign left valign top
29+
+ image in gallery link "data/image6.jpg" "image/jpeg"
30+
+ image in gallery link "data/image6.jpg" "image/jpeg"
31+
+ image in gallery link "data/image6.jpg" "image/jpeg"
32+
+ image in gallery link "data/image6.jpg" "image/jpeg"
33+
34+
# Add some items to the previous list
35+
+ text in list1 label "Item 1-3"
36+
+ text in list2 label "Item 2-3"
37+
38+
# Under construction
39+
# tab id tab1 label "Tab1"
40+
# tab id tab2 label "Tab2"
41+
# tab id tab3 label "Tab3"
42+
43+
# A divider
44+
+ divider label "There is a table below"
45+
46+
# A table
47+
+ table id table1 grid 24 0 0 0 6 0
48+
+ text in table1 label "Cell 0-0"
49+
+ text in table1 label "Cell 0-1"
50+
+ text in table1 label "Cell 0-2"
51+
+ text in table1 label "Cell 0-3"
52+
+ text in table1 label "Cell 1-0"
53+
+ text in table1 label "Cell 1-1"
54+
+ image in table1 link "data/image6.jpg" "image/jpeg"
55+
+ text in table1 label "Cell 1-3"
56+
+ text in table1 label "Cell 2-0"
57+
+ text in table1 label "Cell 2-1"
58+
+ text in table1 label "Cell 2-2"
59+
+ text in table1 label "Cell 2-3"
60+
+ text in table1 label "Cell 3-0"
61+
+ text in table1 label "Cell 3-1"
62+
63+
+ divider
64+
65+
# Add some text and then modify the text at once
66+
+ text id extra2 label "This text will be replaced."
67+
= extra2 label "This is even more text!"

src/alfi.c

+191
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
#include <stdlib.h>
2+
#include <stdio.h>
3+
#include <string.h>
4+
#include "list.h"
5+
#include "box.h"
6+
#include "widgets.h"
7+
#include "parser.h"
8+
9+
#define NWIDGETS 512
10+
#define STRINGTABLESIZE 8192
11+
12+
static struct alfi_widget widgets[NWIDGETS];
13+
static char strings[STRINGTABLESIZE];
14+
static struct parser parser;
15+
static struct list freelist;
16+
static struct list usedlist;
17+
18+
static struct alfi_widget *nextwidget(struct list *list, struct alfi_widget *widget)
19+
{
20+
21+
struct list_item *current = (widget) ? widget->item.next : list->head;
22+
23+
return (current) ? current->data : 0;
24+
25+
}
26+
27+
static struct alfi_widget *findwidgetbyname(struct list *list, unsigned int group, char *name)
28+
{
29+
30+
struct alfi_widget *widget = 0;
31+
32+
while ((widget = nextwidget(list, widget)))
33+
{
34+
35+
if (widget->group != group)
36+
continue;
37+
38+
if (!widget->id.name)
39+
continue;
40+
41+
if (!strcmp(widget->id.name, name))
42+
return widget;
43+
44+
}
45+
46+
return 0;
47+
48+
}
49+
50+
static struct alfi_widget *nextchild(struct list *list, struct alfi_widget *widget, struct alfi_widget *parent)
51+
{
52+
53+
while ((widget = nextwidget(list, widget)))
54+
{
55+
56+
if (widget->group != parent->group)
57+
continue;
58+
59+
if (!widget->in.name)
60+
continue;
61+
62+
if (findwidgetbyname(list, widget->group, widget->in.name) == parent)
63+
return widget;
64+
65+
}
66+
67+
return 0;
68+
69+
}
70+
71+
static struct alfi_widget *parser_find(char *name, unsigned int group)
72+
{
73+
74+
return findwidgetbyname(&usedlist, group, name);
75+
76+
}
77+
78+
static struct alfi_widget *parser_create(unsigned int type, unsigned int group, char *in)
79+
{
80+
81+
struct list_item *item = list_pickhead(&freelist);
82+
struct alfi_widget *widget = item->data;
83+
84+
widget->type = type;
85+
widget->group = group;
86+
widget->in.name = in;
87+
88+
list_add(&usedlist, item);
89+
90+
return widget;
91+
92+
}
93+
94+
static void parser_destroy(struct alfi_widget *widget)
95+
{
96+
97+
struct alfi_widget *child = 0;
98+
99+
while ((child = nextchild(&usedlist, child, widget)))
100+
{
101+
102+
parser_destroy(child);
103+
104+
child = 0;
105+
106+
}
107+
108+
list_move(&freelist, &usedlist, &widget->item);
109+
110+
}
111+
112+
static void parser_fail(unsigned int line)
113+
{
114+
115+
printf("Parsing failed on line %u\n", line);
116+
exit(EXIT_FAILURE);
117+
118+
}
119+
120+
static void load(void)
121+
{
122+
123+
unsigned int i;
124+
125+
for (i = 0; i < NWIDGETS; i++)
126+
{
127+
128+
list_inititem(&widgets[i].item, &widgets[i]);
129+
list_add(&freelist, &widgets[i].item);
130+
131+
}
132+
133+
parser.string.data = strings;
134+
parser.string.count = STRINGTABLESIZE;
135+
parser.string.offset = 0;
136+
parser.find = parser_find;
137+
parser.create = parser_create;
138+
parser.destroy = parser_destroy;
139+
parser.fail = parser_fail;
140+
141+
}
142+
143+
static void loadbase(unsigned int group)
144+
{
145+
146+
struct alfi_widget *widget;
147+
148+
widget = parser_create(ALFI_WIDGET_WINDOW, group, "");
149+
150+
if (widget)
151+
{
152+
153+
widget->id.name = "window";
154+
widget->data.window.label.content = "undefined";
155+
156+
}
157+
158+
widget = parser_create(ALFI_WIDGET_VSTACK, group, "window");
159+
160+
if (widget)
161+
{
162+
163+
widget->id.name = "main";
164+
widget->data.vstack.halign.direction = ALFI_HALIGN_LEFT;
165+
widget->data.vstack.valign.direction = ALFI_VALIGN_TOP;
166+
167+
}
168+
169+
}
170+
171+
int main(int argc, char **argv)
172+
{
173+
174+
char data[4096];
175+
176+
load();
177+
loadbase(1);
178+
179+
parser.expr.data = data;
180+
parser.expr.count = fread(data, 1, 4096, stdin);
181+
parser.expr.offset = 0;
182+
parser.expr.line = 0;
183+
parser.expr.linebreak = 0;
184+
parser.expr.inside = 0;
185+
186+
parse(&parser, 1, "main");
187+
188+
return 0;
189+
190+
}
191+

0 commit comments

Comments
 (0)