From dd5f84bee046fdb62f7ae5f31e3a4bd698de5c4b Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Wed, 11 Jun 2025 10:13:08 -0400 Subject: Default color(4) to white, TUI improvements - Add some default uniforms. - Fix depth usage. - Add new shader hack for HLSL compat. - Update deps. Signed-off-by: Andrew Opalach --- flake.lock | 6 +- src/context.h | 4 +- src/engine.cc | 1 + src/engine.h | 1 + src/gl.cc | 11 +- src/gl.h | 1 + src/mauri.cc | 2 +- src/objects/effect.cc | 2 + src/objects/object.cc | 2 +- src/objects/pass.cc | 18 +++ src/objects/pass.h | 4 + src/shader.cc | 27 ++++- subprojects/libalabaster.wrap | 2 +- subprojects/libnaunet.wrap | 2 +- subprojects/stela.wrap | 2 +- taro/daemon.c | 2 +- taro/tests/notcurses_ffmpeg.c | 2 +- taro/ui.c | 276 +++++++++++++++++++++--------------------- 18 files changed, 213 insertions(+), 152 deletions(-) diff --git a/flake.lock b/flake.lock index f2a579f..68074f7 100644 --- a/flake.lock +++ b/flake.lock @@ -19,11 +19,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1748693115, - "narHash": "sha256-StSrWhklmDuXT93yc3GrTlb0cKSS0agTAxMGjLKAsY8=", + "lastModified": 1749285348, + "narHash": "sha256-frdhQvPbmDYaScPFiCnfdh3B/Vh81Uuoo0w5TkWmmjU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "910796cabe436259a29a72e8d3f5e180fc6dfacc", + "rev": "3e3afe5174c561dee0df6f2c2b2236990146329f", "type": "github" }, "original": { diff --git a/src/context.h b/src/context.h index ab27cb2..dce9d5e 100644 --- a/src/context.h +++ b/src/context.h @@ -35,7 +35,8 @@ class Context this->window->pointer_pos_callback = pointer_pos_callback; this->window->should_close_callback = should_close_callback; this->window->userdata = this; - s32 flags = STELA_WINDOW_VSYNC | (monitor.empty() ? 0 : STELA_WINDOW_WALLPAPER); + s32 flags = STELA_WINDOW_VSYNC; + if (!monitor.empty()) flags |= STELA_WINDOW_WALLPAPER; if (!this->window->create_window(this->window, width, height, monitor.c_str(), name.c_str(), flags)) { return false; } @@ -44,7 +45,6 @@ class Context return false; } glEnable(GL_BLEND); - glEnable(GL_MULTISAMPLE); return true; } diff --git a/src/engine.cc b/src/engine.cc index 1943357..d4424a7 100644 --- a/src/engine.cc +++ b/src/engine.cc @@ -66,6 +66,7 @@ Engine::Engine(Scene *scene, f32 rate, bool audio) this->default_mat = glm::ortho(-1.f, 1.f, -1.f, 1.f, -3.f, 1.f); this->default_mat = glm::scale(this->default_mat, vec3{1.f, 1.f, 0.001f}); + this->default_mat_inverse = glm::inverse(this->default_mat); this->default_object = new RenderObject(DEFAULT); this->flipped_object = new RenderObject(DEFAULT_FLIPPED); diff --git a/src/engine.h b/src/engine.h index 991c226..4b90dbf 100644 --- a/src/engine.h +++ b/src/engine.h @@ -53,6 +53,7 @@ class Engine View view; mat4x4 default_mat; + mat4x4 default_mat_inverse; RenderObject *default_object; RenderObject *flipped_object; diff --git a/src/gl.cc b/src/gl.cc index 9cf1b2d..2570c61 100644 --- a/src/gl.cc +++ b/src/gl.cc @@ -496,7 +496,9 @@ auto RenderFramebuffer::clear(vec4 color) -> void { if (!context()->is_draw_enabled()) return; glBindFramebuffer(GL_DRAW_FRAMEBUFFER, this->id); - glClearBufferfv(GL_COLOR | GL_DEPTH, 0, glm::value_ptr(color)); + glClearBufferfv(GL_COLOR, 0, glm::value_ptr(color)); + GLfloat depth = 0.f; + glClearBufferfv(GL_DEPTH, 0, &depth); } RenderFramebuffer::~RenderFramebuffer() @@ -518,6 +520,13 @@ auto Render::color_mask(f32 r, f32 g, f32 b, f32 a) -> void glColorMask(r, g, b, a); } +auto Render::depth_test(bool enabled) -> void +{ + if (!context()->is_draw_enabled()) return; + if (enabled) glEnable(GL_DEPTH_TEST); + else glDisable(GL_DEPTH_TEST); +} + auto Render::bind_framebuffer(s32 id) -> void { if (!context()->is_draw_enabled()) return; diff --git a/src/gl.h b/src/gl.h index 47c5f8a..0c6450b 100644 --- a/src/gl.h +++ b/src/gl.h @@ -126,6 +126,7 @@ class Render public: static auto blend_func(s32 sfactor, s32 dfactor) -> void; static auto color_mask(f32 r, f32 g, f32 b, f32 a) -> void; + static auto depth_test(bool enabled) -> void; static auto bind_framebuffer(s32 id) -> void; static auto set_viewport(s32 x, s32 y, s32 width, s32 height) -> void; }; diff --git a/src/mauri.cc b/src/mauri.cc index 6e0bcbf..7cb1476 100644 --- a/src/mauri.cc +++ b/src/mauri.cc @@ -138,7 +138,7 @@ auto main(s32 argc, char *argv[]) -> s32 auto wmain(s32 argc, wchar_t **argv) -> s32 #endif { - if (!nn_common_init()) return EXIT_FAILURE; + if (!nn_common_init(NULL)) return EXIT_FAILURE; janus::ArgParser args(HELP_TEXT, "0.13"); args.newString("package p", ""); diff --git a/src/objects/effect.cc b/src/objects/effect.cc index 2a6960f..75b7187 100644 --- a/src/objects/effect.cc +++ b/src/objects/effect.cc @@ -1,3 +1,5 @@ +#include "../log.h" + #include "effect.h" #include "pass.h" diff --git a/src/objects/object.cc b/src/objects/object.cc index 6240c30..4e710ee 100644 --- a/src/objects/object.cc +++ b/src/objects/object.cc @@ -51,7 +51,7 @@ auto Object::parse(Parser &pr, const json &root) -> Object * warn("non 0 origin[2]"); object->origin[2] = 0.f; } - pr.map_value(root, "color", &object->color, vec3(0.f)); + pr.map_value(root, "color", &object->color, vec3(1.f)); pr.map_value(root, "alpha", &object->alpha, 1.f); pr.map_value(root, "colorBlendMode", &object->color_blend_mode, 0); diff --git a/src/objects/pass.cc b/src/objects/pass.cc index e2dc02d..b07e98f 100644 --- a/src/objects/pass.cc +++ b/src/objects/pass.cc @@ -1,6 +1,7 @@ #include "../gl.h" //#define AL_LOG_ENABLE_TRACE #include "../log.h" +#include "../context.h" #include "pass.h" @@ -45,6 +46,8 @@ auto Pass::parse(Parser &pr, const json &root, PassStage stage) -> Pass * if (pass->shader == "genericimage4") { pass->shader = "genericimage2"; } + pass->depthtest = root["depthtest"] != "disabled"; + pass->depthwrite = root["depthwrite"] != "disabled"; break; } @@ -130,6 +133,8 @@ auto Pass::load(Engine *engine, PassStage stage, Pass *pass) -> void case MATERIAL_ONLY_PASS: case MATERIAL_PASS: pass->shader = this->shader; + pass->depthtest = this->depthtest; + pass->depthwrite = this->depthwrite; break; } } @@ -163,6 +168,11 @@ RenderPass::RenderPass(Engine *engine, Pass *pass) this->model = pass->model; this->combine = pass->combine; + this->depth = pass->depthtest; + if (pass->depthtest || pass->depthwrite) + { + warn("depth test support incomplete"); + } this->shader = get_shader(pass->shader); @@ -213,6 +223,10 @@ RenderPass::RenderPass(Engine *engine, Pass *pass) for (Uniform *uniform : this->shader->uniforms) { + if (uniform->uname == "g_Color4") + { + uniform->value = &this->object->color4; + } for (UniformOverride *uniform_override : pass->uniforms) { if (uniform->name.empty()) continue; @@ -334,6 +348,8 @@ auto RenderPass::draw(Engine *engine) -> void if (!this->target) this->object->swap_buffers(); + if (this->depth) Render::depth_test(true); + if (this->combine) Render::blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); else Render::blend_func(GL_ONE, GL_ZERO); @@ -344,6 +360,8 @@ auto RenderPass::draw(Engine *engine) -> void this->render_object->draw(); + if (this->depth) Render::depth_test(false); + #ifdef FRAME_STEP adjusted_target->buffer->blit(0, context()->width(), context()->height()); context()->swap_buffers(); diff --git a/src/objects/pass.h b/src/objects/pass.h index fdec680..6d91a03 100644 --- a/src/objects/pass.h +++ b/src/objects/pass.h @@ -50,6 +50,9 @@ class Pass Object *object; Effect *effect; + bool depthtest; + bool depthwrite; + std::string shader; std::array binds = {}; @@ -77,6 +80,7 @@ class RenderPass bool model; bool combine; + bool depth; Shader *shader = nullptr; diff --git a/src/shader.cc b/src/shader.cc index 71597da..878f5b2 100644 --- a/src/shader.cc +++ b/src/shader.cc @@ -126,10 +126,30 @@ static auto bokeh_blur_hack(std::string_view &line) -> const std::string_view return line; } +static auto hlsl_hack(std::string_view &line) -> const std::string_view +{ + // https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-per-component-math#the-vector-type + // HLSL would take the first components in these situations (I think). + if (line == " float pointer = g_PointerPosition.xy * u_pointerSpeed;\r\n") + { + return " float pointer = g_PointerPosition.x * u_pointerSpeed;\r\n"; + } + if (line == "vec3 albedo = texSample2D(g_Texture0, v_TexCoord.xy);\r\n") + { + return "vec3 albedo = texSample2D(g_Texture0, v_TexCoord.xy).xyz;\r\n"; + } + if (line == "float scale = pow(length(abs(v_TexCoord - CAST2(u_offset)) * 1.0), 3.0) * u_scale;\r\n") + { + return "float scale = pow(length(abs(v_TexCoord.xy - CAST2(u_offset)) * 1.0), 3.0) * u_scale;\r\n"; + } + return line; +} + static auto apply_hacks(std::string_view line) -> const std::string_view { line = simple_audio_bars_hack(line); line = bokeh_blur_hack(line); + line = hlsl_hack(line); return line; } @@ -421,6 +441,10 @@ auto Shader::bind(RenderShader *shader, Engine *engine, Object *object, mat4x4 * shader->set_uniform("g_ModelViewProjectionMatrix", TYPE_MAT4, glm::value_ptr(*model)); shader->set_uniform("g_ModelViewProjectionMatrixInverse", TYPE_MAT4, glm::value_ptr(inverse)); shader->set_uniform("g_EffectModelViewProjectionMatrix", TYPE_MAT4, glm::value_ptr(engine->default_mat)); + shader->set_uniform("g_EffectModelViewProjectionMatrixInverse", TYPE_MAT4, glm::value_ptr(engine->default_mat_inverse)); + shader->set_uniform("g_EffectTextureProjectionMatrix", TYPE_MAT4, glm::value_ptr(engine->default_mat)); + shader->set_uniform("g_EffectTextureProjectionMatrixInverse", TYPE_MAT4, glm::value_ptr(engine->default_mat_inverse)); + shader->set_uniform("g_ModelMatrix", TYPE_MAT4, glm::value_ptr(engine->default_mat)); } @@ -434,10 +458,11 @@ auto Shader::bind(RenderShader *shader, Engine *engine, Object *object, mat4x4 * } cursor_pos[0] /= engine->view.width; cursor_pos[1] /= engine->view.height; + //cursor_pos[1] = -cursor_pos[1]; shader->set_uniform("g_PointerPosition", TYPE_VEC2, glm::value_ptr(cursor_pos)); shader->set_uniform("g_Alpha", TYPE_FLOAT, &object->alpha); shader->set_uniform("g_Color", TYPE_VEC3, glm::value_ptr(object->color)); - shader->set_uniform("g_Color4", TYPE_VEC4, glm::value_ptr(object->color4)); + //shader->set_uniform("g_Color4", TYPE_VEC4, glm::value_ptr(object->color4)); } static const std::array empty_bars = {}; diff --git a/subprojects/libalabaster.wrap b/subprojects/libalabaster.wrap index 243dff8..e3aedee 100644 --- a/subprojects/libalabaster.wrap +++ b/subprojects/libalabaster.wrap @@ -1,4 +1,4 @@ [wrap-git] url = https://git.akon.city/libalabaster -revision = ec99011aca3a9b92964c653d74d693e693ac052f +revision = 93f664a69a3c688d196bdc228d572b45a65e7991 depth = 1 diff --git a/subprojects/libnaunet.wrap b/subprojects/libnaunet.wrap index 3f43502..8388a93 100644 --- a/subprojects/libnaunet.wrap +++ b/subprojects/libnaunet.wrap @@ -1,4 +1,4 @@ [wrap-git] url = https://git.akon.city/libnaunet -revision = 6993b9814769668fb03b4d282734f20f63b16f9c +revision = 393e266f6bfceb25a97cd1cf28dfc72cac9e9f81 depth = 1 diff --git a/subprojects/stela.wrap b/subprojects/stela.wrap index 4d0add3..444d851 100644 --- a/subprojects/stela.wrap +++ b/subprojects/stela.wrap @@ -1,4 +1,4 @@ [wrap-git] url = https://git.akon.city/stela -revision = a2e04b98512e9db93d5457ecc52ac385b9a9e0aa +revision = 658e476c3d43718a2c9eb2884f16ac37cc3f1da2 depth = 1 diff --git a/taro/daemon.c b/taro/daemon.c index a26de8b..6ceba90 100644 --- a/taro/daemon.c +++ b/taro/daemon.c @@ -482,7 +482,7 @@ static void sigint_handler(s32 signum) s32 main(void) { - if (!nn_common_init() || !open_config(&dmon.conf, true)) { + if (!nn_common_init(NULL) || !open_config(&dmon.conf, true)) { return EXIT_FAILURE; } diff --git a/taro/tests/notcurses_ffmpeg.c b/taro/tests/notcurses_ffmpeg.c index adf9689..342d115 100644 --- a/taro/tests/notcurses_ffmpeg.c +++ b/taro/tests/notcurses_ffmpeg.c @@ -5,7 +5,7 @@ s32 main(void) { - if (!nn_common_init()) return EXIT_FAILURE; + if (!nn_common_init(NULL)) return EXIT_FAILURE; struct notcurses *nc = notcurses_init(NULL, stdin); diff --git a/taro/ui.c b/taro/ui.c index d8a2054..1162196 100644 --- a/taro/ui.c +++ b/taro/ui.c @@ -15,6 +15,7 @@ #define PIXEL_BLIT 1 #define TIMER_UPDATE_BASE 1.f +#define TIMER_TICK(delay) MAX(TIMER_UPDATE_BASE * (delay / 1000000.f), 0.001f) #define TEXT_UPDATE_RATE 0.4f #define FLASH_DURATION 0.4f @@ -75,7 +76,6 @@ struct monitors { array(char *) monitors; s32 selected_monitor; s32 set_monitor; - f32 flash; str selection_path; }; @@ -83,12 +83,13 @@ struct grid { struct ncplane *p; s32 tiles_x; s32 tiles_y; + u32 tiles_per_page; + s32 previous_index; s32 min_index; s32 max_index; s32 selected_index; s32 set_index; f32 flash; - u32 tiles_per_page; array(struct tile) tiles; }; @@ -100,12 +101,11 @@ struct info_prop { struct info { struct ncplane *ip; struct entry *e; - f32 flash; bool blitted; struct scrolling_text text; u32 max_props; - s32 selected_prop; array(struct info_prop) props; + s32 selected_prop; }; enum { @@ -125,6 +125,7 @@ struct ui { u32 term_rows; u32 term_cols; u8 selected_menu; + u8 previous_menu; struct ncplane *p, *mp, *gp, *ip; struct monitors m; struct grid g; @@ -134,9 +135,9 @@ struct ui { struct config conf; }; -// --------- +// ------- // Client -// --------- +// ------- static s32 get_entry_from_config(struct ui *u) { @@ -183,11 +184,7 @@ static void write_selected_entry_to_config(struct ui *u) al_str_from(&config, "||"); } else { al_str_clone(&config, &u->n.e->id); - if (u->n.e->has_package) { - al_str_cat(&config, &al_str_c("_p")); - } else { - al_str_cat(&config, &al_str_c("_d")); - } + al_str_cat(&config, u->n.e->has_package ? &al_str_c("_p") : &al_str_c("_d")); al_str_cat(&config, &al_str_c("|false,100|")); struct prop *p; al_array_foreach_ptr(u->n.e->props, i, p) { @@ -200,16 +197,14 @@ static void write_selected_entry_to_config(struct ui *u) } al_str_cat(&config, &al_str_c(",")); } - if (al_str_at(&config, config.length - 1) == ',') { - config.length--; - } + if (al_str_atr(&config, 1) == ',') config.length--; } nn_file_open_and_replace(&u->m.selection_path, &config, true); } -// --------- -// Interface -// --------- +// --------------- +// User Interface +// --------------- static bool init_info(struct info *n) { @@ -305,14 +300,14 @@ static bool init_ui(struct ui *u) struct image *get_image_from_pool(struct image_pool *pool, str *path) { u32 hash = al_str_hash(path); - struct image *rimg; - al_array_foreach_ptr(pool->images, i, rimg) { - if (rimg->hash == hash) { - return rimg; - } + + struct image *cached; + al_array_foreach_ptr(pool->images, i, cached) { + if (cached->hash == hash) return cached; } if (pool->images.count >= pool->max) { + // This should at least be based on LRU. for (u32 i = 0; i < pool->chunk_size; i++) { ncvisual_destroy(al_array_at(pool->images, i).v); } @@ -320,19 +315,13 @@ struct image *get_image_from_pool(struct image_pool *pool, str *path) } u32 index = al_str_rfind(path, '.'); - bool gif = index != AL_STR_NPOS && al_str_cmp(path, &al_str_c(".gif"), index, 4) == 0; - + bool is_gif = index != AL_STR_NPOS && al_str_cmp(path, &al_str_c(".gif"), index, 4) == 0; char *c_str = al_str_to_c_str(path); - struct image img = { - .hash = hash, - .gif = gif, - .errored = false, - .v = ncvisual_from_file(c_str) - }; + struct ncvisual *v = ncvisual_from_file(c_str); al_free(c_str); - if (!img.v) return NULL; - al_array_push(pool->images, img); + if (!v) return NULL; + al_array_push(pool->images, ((struct image){ hash, is_gif, false, v })); return &al_array_last(pool->images); } @@ -358,8 +347,7 @@ static s32 resize_cb(struct ncplane *p) } u->n.blitted = false; ncplane_erase(u->n.ip); - // To not break images we need to erase them - // then render them in 2 steps. + // To not break images we need to erase then render them in 2 steps. notcurses_refresh(u->nc, NULL, NULL); notcurses_render(u->nc); draw_monitors(u, &u->m); @@ -421,14 +409,15 @@ static void maybe_destroy_info(struct info *n) static void set_info_entry(struct ui *u, struct info *n) { - n->e = &al_array_at(u->db.entries, u->g.selected_index); + struct entry *e = &al_array_at(u->db.entries, u->g.selected_index); + if (e == n->e) return; + n->e = e; n->blitted = false; s32 width = al_wstr_width(&u->n.e->title); s32 tx = 2 + ((width < INFO_TEXT_WIDTH) ? (INFO_TEXT_WIDTH - width) / 2 : 0); set_scrolling_text(&n->text, &u->n.e->title, INFO_IMG_HEIGHT + 1, tx, INFO_TEXT_WIDTH); - n->selected_prop = 0; n->props.count = 0; struct prop *p; struct info_prop *ip; @@ -439,6 +428,7 @@ static void set_info_entry(struct ui *u, struct info *n) s32 ty = INFO_IMG_HEIGHT + 3 + ((i % n->max_props) * 2); set_scrolling_text(&ip->text, &p->title, ty, 0, PROP_TEXT_WIDTH); } + n->selected_prop = 0; } static bool layout_info(struct ui *u, struct info *n, struct ncplane *parent, s32 height) @@ -449,14 +439,11 @@ static bool layout_info(struct ui *u, struct info *n, struct ncplane *parent, s3 if (!n->max_props) return false; struct ncplane_options nopts = { 0 }; - nopts.cols = INFO_IMG_WIDTH; nopts.rows = INFO_IMG_HEIGHT; nopts.x = 0; nopts.y = 1; - - n->ip = ncplane_create(parent, &nopts); - if (!n->ip) { + if (!(n->ip = ncplane_create(parent, &nopts))) { maybe_destroy_info(n); return false; } @@ -486,7 +473,11 @@ static void maybe_destroy_grid(struct grid *g) static void set_grid_tiles(struct ui *u, struct grid *g) { u32 selected = (g->selected_index >= 0) ? g->selected_index : g->set_index; - u32 index = (selected - (selected % g->tiles_per_page)); + u32 index = selected - (selected % g->tiles_per_page); + if (g->previous_index >= 0 && index == (u32)g->previous_index) { + return; + } + g->previous_index = index; g->min_index = index; g->max_index = index; @@ -552,19 +543,16 @@ static bool layout_grid(struct ui *u, struct grid *g, struct ncplane *parent, s3 { maybe_destroy_grid(g); - s32 inner_width = width; - s32 inner_height = height; - g->tiles_x = width / GRID_TILE_WIDTH; g->tiles_y = height / GRID_TILE_HEIGHT; - if (!g->tiles_x || !g->tiles_y) { // Window is too small. return false; } - g->tiles_per_page = g->tiles_x * g->tiles_y; + g->previous_index = -1; + // Reserve space for 4 pages, but never shrink. if (u->pool.chunk_size < g->tiles_per_page) { u->pool.chunk_size = g->tiles_per_page; @@ -572,35 +560,28 @@ static bool layout_grid(struct ui *u, struct grid *g, struct ncplane *parent, s3 al_array_reserve(u->pool.images, u->pool.max); } - while (inner_width && inner_width % g->tiles_x != 0) { - inner_width--; - } - - while (inner_height && inner_height % g->tiles_y != 0) { - inner_height--; - } + s32 inner_width = width; + s32 inner_height = height; + while (inner_width && inner_width % g->tiles_x != 0) inner_width--; + while (inner_height && inner_height % g->tiles_y != 0) inner_height--; struct ncplane_options nopts = { 0 }; - nopts.cols = inner_width; nopts.rows = inner_height; nopts.x = (width - (g->tiles_x * GRID_TILE_WIDTH)) / 2; nopts.y = (height - (g->tiles_y * GRID_TILE_HEIGHT)) / 2; + if (!(g->p = ncplane_create(parent, &nopts))) { + return false; + } - g->p = ncplane_create(parent, &nopts); - if (!g->p) return false; - + struct tile t = { 0 }; for (s32 y = 0; y < g->tiles_y; y++) { for (s32 x = 0; x < g->tiles_x; x++) { - struct tile t = { 0 }; - nopts.cols = GRID_TILE_WIDTH; nopts.rows = GRID_TILE_HEIGHT; nopts.x = x * GRID_TILE_WIDTH; nopts.y = y * GRID_TILE_HEIGHT; - - t.p = ncplane_create(g->p, &nopts); - if (!t.p) { + if (!(t.p = ncplane_create(g->p, &nopts))) { maybe_destroy_grid(g); return false; } @@ -609,9 +590,7 @@ static bool layout_grid(struct ui *u, struct grid *g, struct ncplane *parent, s3 nopts.rows = GRID_TILE_HEIGHT - 2; nopts.x = 1; nopts.y = 1; - - t.ip = ncplane_create(t.p, &nopts); - if (!t.ip) { + if (!(t.ip = ncplane_create(t.p, &nopts))) { maybe_destroy_grid(g); return false; } @@ -655,7 +634,6 @@ bool layout_ui(struct ui *u) u32 rwidth = even ? UI_RESERVE_WIDTH + 1 : UI_RESERVE_WIDTH; u32 rheight = even ? UI_RESERVE_HEIGHT + 1 : UI_RESERVE_HEIGHT; - if (u->term_cols < GRID_TILE_WIDTH + rwidth || u->term_rows < GRID_TILE_HEIGHT + rheight) { return false; } @@ -663,18 +641,14 @@ bool layout_ui(struct ui *u) maybe_destroy_ui(u); struct ncplane_options nopts = { 0 }; - nopts.rows = u->term_rows; nopts.cols = u->term_cols; - - u->p = ncplane_create(notcurses_stdplane(u->nc), &nopts); - if (!u->p) { + if (!(u->p = ncplane_create(notcurses_stdplane(u->nc), &nopts))) { return false; } s32 cols = (s32)u->term_cols - rwidth; s32 rows = (s32)u->term_rows - rheight; - if (cols < 0 || rows < 0) { maybe_destroy_ui(u); return false; @@ -684,9 +658,7 @@ bool layout_ui(struct ui *u) nopts.y = 1; nopts.cols = cols - 1; nopts.rows = 1; - - u->mp = ncplane_create(u->p, &nopts); - if (!u->mp) { + if (!(u->mp = ncplane_create(u->p, &nopts))) { maybe_destroy_ui(u); return false; } @@ -695,9 +667,7 @@ bool layout_ui(struct ui *u) nopts.y = 2; nopts.cols = cols - 1; nopts.rows = rows - 2; - - u->gp = ncplane_create(u->p, &nopts); - if (!u->gp) { + if (!(u->gp = ncplane_create(u->p, &nopts))) { maybe_destroy_ui(u); return false; } @@ -711,9 +681,7 @@ bool layout_ui(struct ui *u) nopts.y = INFO_Y_OFFSET; nopts.cols = INFO_WIDTH; nopts.rows = u->term_rows - rheight; - - u->ip = ncplane_create(u->p, &nopts); - if (!u->ip) { + if (!(u->ip = ncplane_create(u->p, &nopts))) { maybe_destroy_ui(u); return false; } @@ -743,8 +711,7 @@ void draw_monitors(struct ui *u, struct monitors *m) } ncplane_set_styles(u->mp, NCSTYLE_BOLD); - s32 w = ncplane_dim_x(u->mp); - s32 x = ((w - 1) - width) / 2; + s32 x = ((ncplane_dim_x(u->mp) - 1) - width) / 2; ncplane_cursor_move_yx(u->mp, 0, x); if (u->m.selected_monitor == -1) { @@ -758,13 +725,12 @@ void draw_monitors(struct ui *u, struct monitors *m) ncplane_putstr(u->mp, no_monitors); } else { al_array_foreach(m->monitors, i, monitor) { - if (m->flash <= 0.f && u->selected_menu == MENU_MONITORS && i == (u32)m->selected_monitor) { + if (u->selected_menu == MENU_MONITORS && i == (u32)m->selected_monitor) { ncplane_set_bg_palindex(u->mp, 8); ncplane_set_fg_palindex(u->mp, 0); } else if (i == (u32)m->set_monitor) { ncplane_set_bg_palindex(u->mp, 7); ncplane_set_fg_palindex(u->mp, 0); - m->flash -= MAX(TIMER_UPDATE_BASE * (u->delay / 1000000.f), 0.001f); } else { ncplane_set_fg_default(u->mp); ncplane_set_bg_default(u->mp); @@ -781,7 +747,6 @@ void draw_info(struct ui *u, struct info *n, bool update_text) ncplane_erase(u->ip); - struct ncvisual_options vopts = { 0 }; vopts.scaling = PIXEL_BLIT ? NCSCALE_SCALE_HIRES : NCSCALE_STRETCH; vopts.blitter = PIXEL_BLIT ? NCBLIT_PIXEL : NCBLIT_2x1; @@ -806,9 +771,8 @@ void draw_info(struct ui *u, struct info *n, bool update_text) ncplane_set_fg_default(u->ip); draw_scrolling_text(u->ip, &n->text, update_text); - u32 selected_index = n->selected_prop - (n->selected_prop % n->max_props); + u32 i, index, selected_index = n->selected_prop - (n->selected_prop % n->max_props); struct info_prop *ip = NULL; - u32 i, index; for (i = 0; i < n->max_props; i++) { index = i + selected_index; if (index >= n->props.count) { @@ -816,24 +780,17 @@ void draw_info(struct ui *u, struct info *n, bool update_text) } ip = &al_array_at(n->props, index); if (u->selected_menu == MENU_INFO && index == (u32)n->selected_prop) { - if (n->flash > 0.f) { - ncplane_set_fg_palindex(u->ip, 0); - ncplane_set_bg_palindex(u->ip, 7); - n->flash -= MAX(TIMER_UPDATE_BASE * (u->delay / 1000000.f), 0.001f); - } else { - ncplane_set_fg_palindex(u->ip, 8); - ncplane_set_bg_default(u->ip); - } + ncplane_set_fg_palindex(u->ip, 8); } else { ncplane_set_fg_default(u->ip); - ncplane_set_bg_default(u->ip); } draw_scrolling_text(u->ip, &ip->text, update_text); switch (ip->p->type) { - case PROP_TYPE_BOOL: - ncplane_putstr_yx(u->ip, ip->text.y, ip->text.width + 2, - *((bool *)ip->p->value) ? "[x]" : "[ ]"); + case PROP_TYPE_BOOL: { + char *c = *((bool *)ip->p->value) ? "[x]" : "[ ]"; + ncplane_putstr_yx(u->ip, ip->text.y, ip->text.width + 2, c); break; + } case PROP_TYPE_SLIDER: { char c[16]; al_snprintf(c, sizeof(c), "%.2f", ((struct slider_value *)ip->p->value)->value); @@ -847,21 +804,27 @@ void draw_info(struct ui *u, struct info *n, bool update_text) } } -static void set_tile_highlight(struct tile *t, s32 bindex, s32 findex) +static void set_tile_highlight(struct tile *t, s32 findex, s32 bindex) { - ncplane_set_bg_alpha(t->p, NCALPHA_TRANSPARENT); struct nccell ncl; nccell_init(&ncl); nccell_load(t->p, &ncl, " "); nccell_set_bg_palindex(&ncl, bindex); + nccell_set_fg_default(&ncl); ncplane_polyfill_yx(t->p, 1, 0, &ncl); + nccell_release(t->p, &ncl); + ncplane_set_bg_default(t->p); ncplane_set_fg_palindex(t->p, bindex); for (s32 i = 0; i < GRID_TILE_WIDTH; i++) { ncplane_putwc_yx(t->p, 0, i, L'▃'); } - ncplane_set_fg_palindex(t->p, findex); + (void)findex; + //ncplane_set_fg_palindex(t->p, findex); + // If we set both fg and bg palindex here, the fg color + // will carry over to the info prop list for a split second. + // This might be a notcurses bug, I need to look more carefully. + ncplane_set_fg_rgb8(t->p, 0, 0, 0); ncplane_set_bg_palindex(t->p, bindex); - ncplane_set_bg_alpha(t->p, NCALPHA_OPAQUE); ncplane_set_styles(t->p, NCSTYLE_BOLD); } @@ -873,12 +836,9 @@ void draw_grid_tiles(struct ui *u, struct grid *g, bool update_text) vopts.scaling = PIXEL_BLIT ? NCSCALE_SCALE_HIRES : NCSCALE_STRETCH; vopts.blitter = PIXEL_BLIT ? NCBLIT_PIXEL : NCBLIT_2x1; - s32 index = (g->selected_index - (g->selected_index % g->tiles_per_page)); struct tile *t; al_array_foreach_ptr(g->tiles, i, t) { - ncplane_erase(t->p); - if (!t->e) continue; - if (t->e->has_preview) { + if (t->e && t->e->has_preview) { struct image *img = get_image_from_pool(&u->pool, &t->e->preview_path); if (img && !t->blitted && !img->errored) { vopts.n = t->ip; @@ -886,15 +846,19 @@ void draw_grid_tiles(struct ui *u, struct grid *g, bool update_text) t->blitted = true; } } + } + s32 index = g->selected_index - (g->selected_index % g->tiles_per_page); + al_array_foreach_ptr(g->tiles, i, t) { + ncplane_erase(t->p); + if (!t->e) continue; if (index == g->selected_index && g->flash <= 0.f && u->selected_menu == MENU_GRID) { - set_tile_highlight(t, 8, 0); + set_tile_highlight(t, 0, 8); } else if (index == g->set_index && g->set_index >= 0) { - set_tile_highlight(t, 7, 0); - g->flash -= MAX(TIMER_UPDATE_BASE * (u->delay / 1000000.f), 0.001f); + set_tile_highlight(t, 0, 7); + g->flash -= TIMER_TICK(u->delay); } else { ncplane_set_fg_default(t->p); ncplane_set_bg_default(t->p); - ncplane_set_bg_alpha(t->p, NCALPHA_TRANSPARENT); ncplane_set_styles(t->p, NCSTYLE_NONE); } if (t->text.s && !al_wstr_is_empty(t->text.s)) { @@ -928,10 +892,17 @@ static bool handle_input_monitors(struct ui *u, struct monitors *m, struct ncinp should_redraw_monitors = true; break; } + case NCKEY_DOWN: + case 'j': { + u->selected_menu = MENU_GRID; + should_redraw_monitors = true; + should_redraw_grid = true; + break; + } case NCKEY_RETURN: case NCKEY_SPACE: { select_monitor(u); - m->flash = FLASH_DURATION; + u->selected_menu = MENU_GRID; should_redraw_monitors = true; should_redraw_grid = true; should_redraw_info = true; @@ -1055,6 +1026,7 @@ static bool handle_input_grid(struct ui *u, struct grid *g, struct ncinput *inpu bool should_update_grid = false; bool should_redraw_grid = false; bool should_redraw_info = false; + bool should_redraw_monitors = false; switch (input->id) { case NCKEY_LEFT: case 'h': { @@ -1087,10 +1059,12 @@ static bool handle_input_grid(struct ui *u, struct grid *g, struct ncinput *inpu case NCKEY_UP: case 'k': { if (g->selected_index - g->tiles_x < g->min_index) { - return false; + u->selected_menu = MENU_MONITORS; + should_redraw_monitors = true; + } else { + g->selected_index -= g->tiles_x; + should_redraw_info = true; } - g->selected_index -= g->tiles_x; - should_redraw_info = true; should_redraw_grid = true; break; } @@ -1104,6 +1078,18 @@ static bool handle_input_grid(struct ui *u, struct grid *g, struct ncinput *inpu should_redraw_grid = true; break; } + case '0': { + g->selected_index -= g->selected_index % g->tiles_x; + should_redraw_info = true; + should_redraw_grid = true; + break; + } + case '4': { // '$' in vim. + g->selected_index += g->tiles_x - (g->selected_index % g->tiles_x) - 1; + should_redraw_info = true; + should_redraw_grid = true; + break; + } case 'f': { if (grid_next_page(u, &u->g, 0)) { should_update_grid = true; @@ -1160,6 +1146,9 @@ static bool handle_input_grid(struct ui *u, struct grid *g, struct ncinput *inpu set_info_entry(u, &u->n); draw_info(u, &u->n, false); } + if (should_redraw_monitors) { + draw_monitors(u, &u->m); + } return should_redraw_grid || should_redraw_info; } @@ -1172,44 +1161,55 @@ static void input_poll_callback(void *userdata, s32 revents) u32 ret; while (1) { ret = notcurses_get_nblock(u->nc, &input); - if (ret == (u32)-1 || ret == 0) { - break; - } + if (ret == (u32)-1 || ret == 0) break; if (input.evtype == NCTYPE_PRESS || input.evtype == NCTYPE_UNKNOWN) { if (input.id == NCKEY_TAB) { switch (u->selected_menu) { + case MENU_MONITORS: + break; case MENU_GRID: if (u->n.props.count > 0) { u->selected_menu = MENU_INFO; - u->n.flash = FLASH_DURATION; - } else { - u->selected_menu = MENU_MONITORS; } break; case MENU_INFO: - u->selected_menu = MENU_MONITORS; - break; - case MENU_MONITORS: u->selected_menu = MENU_GRID; break; } draw_info(u, &u->n, false); - draw_monitors(u, &u->m); draw_grid_tiles(u, &u->g, false); should_render = true; + } else if (input.id == 'm') { + if (u->selected_menu != MENU_MONITORS) { + u->previous_menu = u->selected_menu; + u->selected_menu = MENU_MONITORS; + } else { + u->selected_menu = u->previous_menu; + } + draw_monitors(u, &u->m); + switch (u->previous_menu) { + case MENU_GRID: + draw_grid_tiles(u, &u->g, false); + break; + case MENU_INFO: + draw_info(u, &u->n, false); + break; + } + should_render = true; } else if (input.id == 'q') { nn_event_loop_break(&u->loop); - } - switch (u->selected_menu) { - case MENU_GRID: - should_render |= handle_input_grid(u, &u->g, &input); - break; - case MENU_INFO: - should_render |= handle_input_info(u, &u->n, &input); - break; - case MENU_MONITORS: - should_render |= handle_input_monitors(u, &u->m, &input); - break; + } else { + switch (u->selected_menu) { + case MENU_GRID: + should_render |= handle_input_grid(u, &u->g, &input); + break; + case MENU_INFO: + should_render |= handle_input_info(u, &u->n, &input); + break; + case MENU_MONITORS: + should_render |= handle_input_monitors(u, &u->m, &input); + break; + } } } } @@ -1231,7 +1231,7 @@ static void timer_callback(void *userdata, struct nn_timer *timer) draw_grid_tiles(u, &u->g, true); draw_info(u, &u->n, true); } else { - u->text_update -= MAX(TIMER_UPDATE_BASE * (u->delay / 1000000.f), 0.001f); + u->text_update -= TIMER_TICK(u->delay); draw_grid_tiles(u, &u->g, false); draw_info(u, &u->n, false); } @@ -1248,7 +1248,7 @@ static struct ui u = { 0 }; s32 main(void) { - if (!nn_common_init()) return EXIT_FAILURE; + if (!nn_common_init(NULL)) return EXIT_FAILURE; if (!open_config(&u.conf, false)) { log_error("failed to open config, run `tarod` at least once to generate needed config"); -- cgit v1.2.3-101-g0448