Compare commits
No commits in common. "0531f58a5685db91aa5cc43d18fa75ae2242f892" and "b317951c321051a456215cf202be586ffea33c38" have entirely different histories.
0531f58a56
...
b317951c32
9
TODO
9
TODO
@ -20,14 +20,6 @@ to maintain focus until mouse release (fix scroll bars)
|
||||
[x] Fix scroll wheel when div is scrolled
|
||||
[ ] Be consistent with the initialization methods some are foo.new() and some are foo.init()
|
||||
[ ] Implement image loading (.bmp, .ff, .qoi and .png), in the future even lossy images like .jpg
|
||||
[x] .qoi
|
||||
[ ] .ff
|
||||
[ ] .bmp
|
||||
[ ] .png
|
||||
[ ] .jpg
|
||||
[ ] gif support?
|
||||
[ ] layout_set_max_rows() and layout_set_max_columns()
|
||||
[ ] Maybe SDF sprites??
|
||||
|
||||
## Layout
|
||||
|
||||
@ -73,4 +65,3 @@ _ border radius
|
||||
[ ] Text Input box
|
||||
[ ] Icon Buttons
|
||||
[ ] Switch
|
||||
[ ] Checkbox
|
||||
|
1
lib/raylib.c3l
Submodule
1
lib/raylib.c3l
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c7ebe054ce16136c1128fab54fcce4921044293e
|
@ -4,9 +4,9 @@
|
||||
// Warnings used for all targets.
|
||||
"warnings": ["no-unused"],
|
||||
// Directories where C3 library files may be found.
|
||||
"dependency-search-paths": ["lib", "../../Programs/Source/c3-vendor/libraries"],
|
||||
"dependency-search-paths": ["lib"],
|
||||
// Libraries to use for all targets.
|
||||
"dependencies": ["raylib55", "schrift", "grapheme", "mqoi"],
|
||||
"dependencies": ["raylib", "schrift", "grapheme", "mqoi"],
|
||||
"features": [
|
||||
// See rcore.c3
|
||||
//"SUPPORT_INTERNAL_MEMORY_MANAGEMENT",
|
||||
|
94
src/main.c3
94
src/main.c3
@ -2,7 +2,7 @@ import std::io;
|
||||
import vtree;
|
||||
import cache;
|
||||
import ugui;
|
||||
import raylib5::rl;
|
||||
import rl;
|
||||
import std::time;
|
||||
import std::collections::ringbuffer;
|
||||
import std::core::string;
|
||||
@ -80,19 +80,17 @@ fn int main(String[] args)
|
||||
{
|
||||
ugui::Ctx ui;
|
||||
ui.init()!!;
|
||||
defer ui.free();
|
||||
|
||||
ui.load_font("font1", "resources/hack-nerd.ttf", 16)!!;
|
||||
ui.sprite_atlas_create("icons", AtlasType.ATLAS_RGBA32, 512, 512)!!;
|
||||
ui.import_sprite_file_qoi("tux", "resources/tux.qoi")!!;
|
||||
|
||||
short width = 800;
|
||||
short height = 450;
|
||||
rl::setConfigFlags(rl::FLAG_WINDOW_RESIZABLE);
|
||||
rl::initWindow(width, height, "Ugui Test");
|
||||
rl::set_config_flags(rl::FLAG_WINDOW_RESIZABLE);
|
||||
rl::init_window(width, height, "Ugui Test");
|
||||
ui.input_window_size(width, height)!!;
|
||||
rl::setTargetFPS(60);
|
||||
rl::enableEventWaiting();
|
||||
rl::set_target_fps(60);
|
||||
rl::enable_event_waiting();
|
||||
|
||||
isz frame;
|
||||
bool toggle = true;
|
||||
@ -101,7 +99,7 @@ fn int main(String[] args)
|
||||
Times draw_times;
|
||||
|
||||
// font stuff
|
||||
rl::Shader font_shader = rl::loadShaderFromMemory(null, FONT_FS);
|
||||
rl::Shader font_shader = rl::load_shader_from_memory(null, FONT_FS);
|
||||
rl::Image font_atlas;
|
||||
rl::Image sprite_atlas;
|
||||
rl::Texture2D font_texture;
|
||||
@ -110,7 +108,7 @@ fn int main(String[] args)
|
||||
ugui::Id sprite_id = ui.get_sprite_atlas_id("icons");
|
||||
|
||||
// Main loop
|
||||
while (!rl::windowShouldClose()) {
|
||||
while (!rl::window_should_close()) {
|
||||
clock.mark();
|
||||
|
||||
/*
|
||||
@ -124,37 +122,30 @@ fn int main(String[] args)
|
||||
io::printfn("%s", k);
|
||||
} while (k != 0);
|
||||
*/
|
||||
|
||||
ugui::ModKeys mod;
|
||||
mod.rctrl = rl::isKeyDown(rl::KEY_RIGHT_CONTROL);
|
||||
mod.lctrl = rl::isKeyDown(rl::KEY_LEFT_CONTROL);
|
||||
ui.input_mod_keys(mod);
|
||||
|
||||
for (rl::KeyboardKey key; (key = (KeyboardKey)rl::getKeyPressed()) != 0;) {
|
||||
ZString kname = rl::getKeyName(key);
|
||||
if (kname == null) continue;
|
||||
ui.input_text_unicode(kname.str_view());
|
||||
for (int c; (c = rl::get_char_pressed()) != 0;) {
|
||||
int[1] ts;
|
||||
ts[0] = c;
|
||||
ui.input_text_unicode(ts[..]);
|
||||
}
|
||||
|
||||
|
||||
/* Start Input Handling */
|
||||
if (rl::isWindowResized()) {
|
||||
width = (short)rl::getScreenWidth();
|
||||
height = (short)rl::getScreenHeight();
|
||||
if (rl::is_window_resized()) {
|
||||
width = (short)rl::get_screen_width();
|
||||
height = (short)rl::get_screen_height();
|
||||
ui.input_window_size(width, height)!!;
|
||||
}
|
||||
|
||||
ui.input_changefocus(rl::isWindowFocused());
|
||||
ui.input_changefocus(rl::is_window_focused());
|
||||
|
||||
rl::Vector2 mpos = rl::getMousePosition();
|
||||
rl::Vector2 mpos = rl::get_mouse_position();
|
||||
ui.input_mouse_abs((short)mpos.x, (short)mpos.y);
|
||||
rl::Vector2 mwheel = rl::getMouseWheelMoveV();
|
||||
rl::Vector2 mwheel = rl::get_mouse_wheel_move_v();
|
||||
ui.input_mouse_wheel((short)mwheel.x, (short)mwheel.y);
|
||||
|
||||
ugui::MouseButtons buttons = {
|
||||
.btn_left = rl::isMouseButtonDown(rl::MouseButton.LEFT),
|
||||
.btn_right = rl::isMouseButtonDown(rl::MouseButton.RIGHT),
|
||||
.btn_middle = rl::isMouseButtonDown(rl::MouseButton.MIDDLE),
|
||||
.btn_left = rl::is_mouse_button_down(rl::MOUSE_BUTTON_LEFT),
|
||||
.btn_right = rl::is_mouse_button_down(rl::MOUSE_BUTTON_RIGHT),
|
||||
.btn_middle = rl::is_mouse_button_down(rl::MOUSE_BUTTON_MIDDLE),
|
||||
};
|
||||
ui.input_mouse_button(buttons);
|
||||
/* End Input Handling */
|
||||
@ -162,8 +153,6 @@ fn int main(String[] args)
|
||||
/* Start UI Handling */
|
||||
ui.frame_begin()!!;
|
||||
|
||||
if (ui.check_key_combo(ugui::KMOD_CTRL, "q")) break;
|
||||
|
||||
// main div, fill the whole window
|
||||
ui.div_begin("main", ugui::Rect{.w=-100})!!;
|
||||
{|
|
||||
@ -190,12 +179,12 @@ fn int main(String[] args)
|
||||
ui.slider_ver("slider_a", ugui::Rect{0,0,30,100}, &af)!!;
|
||||
|
||||
ui.layout_next_column()!!;
|
||||
ui.text_unbounded("text1", "Ciao Mamma\nAbilità ⚡\n'\udb80\udd2c'")!!;
|
||||
ui.text_unbounded("text1", "Ciao Mamma\nAbilità ⚡")!!;
|
||||
|
||||
ui.layout_next_column()!!;
|
||||
ui.button_label("Continua!")!!;
|
||||
|};
|
||||
ui.draw_sprite("sprite1", "tux")!!;
|
||||
ui.draw_sprite("tux")!!;
|
||||
ui.div_end()!!;
|
||||
|
||||
ui.div_begin("second", ugui::DIV_FILL, scroll_x: true, scroll_y: true)!!;
|
||||
@ -242,7 +231,7 @@ fn int main(String[] args)
|
||||
//ui_times.print_stats();
|
||||
|
||||
/* Start UI Drawing */
|
||||
rl::beginDrawing();
|
||||
rl::begin_drawing();
|
||||
// ClearBackground(BLACK);
|
||||
|
||||
for (Cmd* cmd; (cmd = ui.cmd_queue.dequeue() ?? null) != null;) {
|
||||
@ -252,7 +241,7 @@ fn int main(String[] args)
|
||||
float rad = cmd.rect.radius;
|
||||
// for some weird-ass reason the straight forward inverse formula does not work
|
||||
float roundness = r.w > r.h ? (2.1f*rad)/(float)r.h : (2.1f*rad)/(float)r.w;
|
||||
rl::drawRectangleRounded(cmd.rect.rect.conv(), roundness, 0, cmd.rect.color.conv());
|
||||
rl::draw_rectangle_rounded(cmd.rect.rect.conv(), roundness, 0, cmd.rect.color.conv());
|
||||
case ugui::CmdType.CMD_UPDATE_ATLAS:
|
||||
if (cmd.update_atlas.id == font_id) {
|
||||
//rl::unload_image(font_atlas);
|
||||
@ -260,21 +249,23 @@ fn int main(String[] args)
|
||||
font_atlas.width = cmd.update_atlas.width;
|
||||
font_atlas.height = cmd.update_atlas.height;
|
||||
font_atlas.mipmaps = 1;
|
||||
font_atlas.format = rl::PixelFormat.UNCOMPRESSED_GRAYSCALE;
|
||||
if (rl::isTextureValid(font_texture)) {
|
||||
rl::unloadTexture(font_texture);
|
||||
//font_atlas.format = rl::PixelFormat.PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
|
||||
font_atlas.format = 1;
|
||||
if (rl::is_texture_ready(font_texture)) {
|
||||
rl::unload_texture(font_texture);
|
||||
}
|
||||
font_texture = rl::loadTextureFromImage(font_atlas);
|
||||
font_texture = rl::load_texture_from_image(font_atlas);
|
||||
} else if (cmd.update_atlas.id == sprite_id) {
|
||||
sprite_atlas.data = cmd.update_atlas.raw_buffer;
|
||||
sprite_atlas.width = cmd.update_atlas.width;
|
||||
sprite_atlas.height = cmd.update_atlas.height;
|
||||
sprite_atlas.mipmaps = 1;
|
||||
sprite_atlas.format = rl::PixelFormat.UNCOMPRESSED_R8G8B8A8;
|
||||
if (rl::isTextureValid(sprite_texture)) {
|
||||
rl::unloadTexture(sprite_texture);
|
||||
//sprite_atlas.format = rl::PixelFormat.PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
|
||||
sprite_atlas.format = 7;
|
||||
if (rl::is_texture_ready(sprite_texture)) {
|
||||
rl::unload_texture(sprite_texture);
|
||||
}
|
||||
sprite_texture = rl::loadTextureFromImage(sprite_atlas);
|
||||
sprite_texture = rl::load_texture_from_image(sprite_atlas);
|
||||
}
|
||||
case ugui::CmdType.CMD_SPRITE:
|
||||
if (cmd.sprite.texture_id == font_id) {
|
||||
@ -282,23 +273,23 @@ fn int main(String[] args)
|
||||
.x = cmd.sprite.rect.x,
|
||||
.y = cmd.sprite.rect.y,
|
||||
};
|
||||
rl::beginShaderMode(font_shader);
|
||||
rl::drawTextureRec(font_texture, cmd.sprite.texture_rect.conv(), position, cmd.sprite.hue.conv());
|
||||
rl::endShaderMode();
|
||||
rl::begin_shader_mode(font_shader);
|
||||
rl::draw_texture_rec(font_texture, cmd.sprite.texture_rect.conv(), position, cmd.sprite.hue.conv());
|
||||
rl::end_shader_mode();
|
||||
} else if (cmd.sprite.texture_id == sprite_id) {
|
||||
rl::Vector2 position = {
|
||||
.x = cmd.sprite.rect.x,
|
||||
.y = cmd.sprite.rect.y,
|
||||
};
|
||||
rl::drawTextureRec(sprite_texture, cmd.sprite.texture_rect.conv(), position, cmd.sprite.hue.conv());
|
||||
rl::draw_texture_rec(sprite_texture, cmd.sprite.texture_rect.conv(), position, cmd.sprite.hue.conv());
|
||||
} else {
|
||||
io::printfn("unknown texture id: %d", cmd.sprite.texture_id);
|
||||
}
|
||||
case ugui::CmdType.CMD_SCISSOR:
|
||||
if (cmd.scissor.rect.w == 0 && cmd.scissor.rect.h == 0) {
|
||||
rl::endScissorMode();
|
||||
rl::end_scissor_mode();
|
||||
} else {
|
||||
rl::beginScissorMode(cmd.scissor.rect.x, cmd.scissor.rect.y, cmd.scissor.rect.w, cmd.scissor.rect.h);
|
||||
rl::begin_scissor_mode(cmd.scissor.rect.x, cmd.scissor.rect.y, cmd.scissor.rect.w, cmd.scissor.rect.h);
|
||||
}
|
||||
default:
|
||||
io::printfn("Unknown cmd type: %s", cmd.type);
|
||||
@ -306,12 +297,13 @@ fn int main(String[] args)
|
||||
}
|
||||
draw_times.push(clock.mark());
|
||||
//draw_times.print_stats();
|
||||
rl::endDrawing();
|
||||
rl::end_drawing();
|
||||
/* End Drawing */
|
||||
}
|
||||
|
||||
rl::closeWindow();
|
||||
rl::close_window();
|
||||
|
||||
ui.free();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,6 @@ enum ElemType {
|
||||
ETYPE_BUTTON,
|
||||
ETYPE_SLIDER,
|
||||
ETYPE_TEXT,
|
||||
ETYPE_SPRITE,
|
||||
}
|
||||
|
||||
bitstruct ElemFlags : uint {
|
||||
@ -48,7 +47,6 @@ struct Elem {
|
||||
ElemButton button;
|
||||
ElemSlider slider;
|
||||
ElemText text;
|
||||
ElemSprite sprite;
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,7 +55,7 @@ struct Elem {
|
||||
def IdTree = vtree::VTree(<Id>) @private;
|
||||
|
||||
// elements themselves are kept in a cache
|
||||
const uint MAX_ELEMENTS = 256;
|
||||
const uint MAX_ELEMENTS = 1024;
|
||||
def ElemCache = cache::Cache(<Id, Elem, MAX_ELEMENTS>) @private;
|
||||
|
||||
def CmdQueue = fifo::Fifo(<Cmd>);
|
||||
@ -326,7 +324,7 @@ fn ElemEvents Ctx.get_elem_events(&ctx, Elem *elem)
|
||||
{
|
||||
bool hover = ctx.is_hovered(elem);
|
||||
bool focus = ctx.focus_id == elem.id || (hover && ctx.is_mouse_pressed(BTN_LEFT));
|
||||
|
||||
|
||||
if (ctx.is_mouse_pressed(BTN_ANY) && !hover){
|
||||
focus = false;
|
||||
if (ctx.focus_id == elem.id) ctx.focus_id = 0;
|
||||
@ -334,7 +332,7 @@ fn ElemEvents Ctx.get_elem_events(&ctx, Elem *elem)
|
||||
|
||||
if (hover) { ctx.hover_id = elem.id; }
|
||||
if (focus) { ctx.focus_id = elem.id; }
|
||||
|
||||
|
||||
ElemEvents ev = {
|
||||
.mouse_hover = hover,
|
||||
.mouse_press = hover && focus && ctx.is_mouse_pressed(BTN_ANY),
|
||||
@ -343,3 +341,4 @@ fn ElemEvents Ctx.get_elem_events(&ctx, Elem *elem)
|
||||
};
|
||||
return ev;
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ struct Glyph {
|
||||
short adv, ox, oy;
|
||||
}
|
||||
|
||||
const uint FONT_CACHED = 128;
|
||||
const uint FONT_CACHED = 512;
|
||||
def GlyphTable = map::HashMap(<Codepoint, Glyph>) @private;
|
||||
|
||||
fault UgFontError {
|
||||
@ -89,7 +89,7 @@ fn void! Font.load(&font, String name, ZString path, uint height, float scale)
|
||||
|
||||
// TODO: allocate buffer based on FONT_CACHED and the size of a sample letter
|
||||
// like the letter 'A'
|
||||
ushort size = (ushort)font.size*(ushort)($$sqrt((float)FONT_CACHED));
|
||||
ushort size = (ushort)font.size*256;
|
||||
font.atlas.new(font.id, ATLAS_GRAYSCALE, size, size)!;
|
||||
|
||||
// preallocate the ASCII range
|
||||
|
@ -3,7 +3,7 @@ module ugui;
|
||||
import grapheme;
|
||||
import std::io;
|
||||
import std::math;
|
||||
import std::core::string;
|
||||
|
||||
|
||||
bitstruct InputEvents : uint {
|
||||
bool resize : 0; // window size was changed
|
||||
@ -58,19 +58,6 @@ const MouseButtons BTN_5 = {.btn_5 = true};
|
||||
|
||||
const ModKeys KEY_ANY = (ModKeys)(ModKeys.inner.max);
|
||||
|
||||
fn bool Ctx.check_key_combo(&ctx, ModKeys mod, String keys)
|
||||
{
|
||||
bool is_mod = (bool)(ctx.input.keyboard.down & mod);
|
||||
bool is_keys = true;
|
||||
String haystack = (String)ctx.input.keyboard.text[0..ctx.input.keyboard.text_len];
|
||||
char[2] needle;
|
||||
foreach (c: keys) {
|
||||
needle[0] = c;
|
||||
is_keys = is_keys && haystack.contains((String)needle[..]);
|
||||
}
|
||||
return is_mod && is_keys;
|
||||
}
|
||||
|
||||
// Window size was changed
|
||||
fn void! Ctx.input_window_size(&ctx, short width, short height)
|
||||
{
|
||||
@ -161,9 +148,9 @@ fn void Ctx.input_text_utf8(&ctx, char[] text)
|
||||
ctx.input.events.text_input = true;
|
||||
}
|
||||
|
||||
fn void Ctx.input_text_unicode(&ctx, char[] text)
|
||||
fn void Ctx.input_text_unicode(&ctx, int[] text)
|
||||
{
|
||||
if (text.ptr == null || text.len == 0) { return; }
|
||||
if (text.len == 0) { return; }
|
||||
|
||||
char[32] tmp;
|
||||
usz remaining = ctx.input.keyboard.text.len - ctx.input.keyboard.text_len;
|
||||
|
@ -21,9 +21,6 @@ struct SpriteAtlas {
|
||||
bool should_update;
|
||||
}
|
||||
|
||||
struct ElemSprite {
|
||||
Id id;
|
||||
}
|
||||
|
||||
// name: some examples are "icons" or "images"
|
||||
fn void! SpriteAtlas.init(&this, String name, AtlasType type, ushort width, ushort height)
|
||||
@ -121,34 +118,13 @@ fn void! Ctx.import_sprite_file_qoi(&ctx, String name, String path)
|
||||
ctx.sprite_atlas.insert(name, pixels, (ushort)w, (ushort)h, (ushort)w)!;
|
||||
}
|
||||
|
||||
fn void! Ctx.draw_sprite(&ctx, String label, String name, Point off = {0,0})
|
||||
// FIXME: test function, very different from every other function here
|
||||
fn void! Ctx.draw_sprite(&ctx, String name)
|
||||
{
|
||||
Id id = ctx.gen_id(label)!;
|
||||
|
||||
Elem *parent = ctx.get_parent()!;
|
||||
Elem *elem = ctx.get_elem(id)!;
|
||||
// add it to the tree
|
||||
ctx.tree.add(id, ctx.active_div)!;
|
||||
|
||||
if (elem.flags.is_new) {
|
||||
elem.type = ETYPE_SPRITE;
|
||||
} else if (elem.type != ETYPE_SPRITE) {
|
||||
return UgError.WRONG_ELEMENT_TYPE?;
|
||||
}
|
||||
|
||||
Sprite* sprite = ctx.sprite_atlas.get(name)!;
|
||||
|
||||
Rect bounds = { 100, 100, sprite.w, sprite.h };
|
||||
Rect uv = { sprite.u, sprite.v, sprite.w, sprite.h };
|
||||
Rect bounds = { 0, 0, sprite.w, sprite.h };
|
||||
|
||||
elem.bounds = ctx.position_element(parent, bounds.off(off), true);
|
||||
elem.sprite.id = ctx.get_sprite_atlas_id(name);
|
||||
|
||||
// if the bounds are null the element is outside the div view,
|
||||
// no interaction should occur so just return
|
||||
if (elem.bounds.is_null()) return;
|
||||
|
||||
Id tex_id = ctx.sprite_atlas.id;
|
||||
|
||||
return ctx.push_sprite(elem.bounds, uv, tex_id)!;
|
||||
return ctx.push_sprite(bounds, uv, tex_id)!;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user