/* Photo management app */ /* */ /* File: funtus1.c */ /* */ /* copyright (c) Sam Sandqvist, 2023 */ /* */ #define HSIZE 1200 #define VSIZE 1000 #include #include "nappgui.h" //definitions and protos typedef struct _app_t App; Label *label_new(char *); static Image *get_image(void); static Panel *filter_panel(void); static Panel *info_panel(void); struct _app_t { Window *window; uint32_t ncols; uint32_t nrows; Panel *photo_panel; uint32_t numImg; //new View *view; uint32_t col_id; uint32_t row_id; uint32_t margin; uint32_t mouse_cell_x; uint32_t mouse_cell_y; uint32_t sel_cell_x; uint32_t sel_cell_y; bool_t focus; }; //static const uint32_t i_NUM_COLS = 8; //start with this //static const uint32_t i_NUM_ROWS = 2000; static const real32_t i_CELL_SIZE = 150; /*---------------------------------------------------------------------------*/ // UTILITY /*---------------------------------------------------------------------------*/ //new label in one go Label *label_new(char *txt) { Label *lb = label_create(); label_text(lb, txt); return lb; } /*---------------------------------------------------------------------------*/ static void i_content_size(App *app) { //real32_t width = i_NUM_COLS * i_CELL_SIZE + (i_NUM_COLS + 1) * app->margin; //real32_t height = i_NUM_ROWS * i_CELL_SIZE + (i_NUM_ROWS + 1) * app->margin; real32_t width = app->ncols * i_CELL_SIZE + (app->ncols + 1) * app->margin; real32_t height = app->nrows * i_CELL_SIZE + (app->nrows + 1) * app->margin; printf("Contentsize: %f, %f\n", width, height); view_content_size(app->view, s2df((real32_t) width, (real32_t) height), s2df(10, 10)); } /*---------------------------------------------------------------------------*/ static void i_draw_clipped(App *app, DCtx *ctx, const real32_t x, const real32_t y, const real32_t width, const real32_t height) { register uint32_t sti, edi; register uint32_t stj, edj; real32_t cellsize = i_CELL_SIZE + (real32_t) app->margin; //real32_t hcell = i_CELL_SIZE / 2; register real32_t posx = 0; register real32_t posy = 0; register uint32_t i, j; uint32_t photoIndex; //counter Image *image2 = get_image(); /* Calculate the visible cols */ sti = (uint32_t) bmath_floorf(x / cellsize); edi = sti + (uint32_t) bmath_ceilf(width / cellsize) + 1; //if (edi > i_NUM_COLS) edi = i_NUM_COLS; if (edi > app->ncols) edi = app->ncols; /* Calculate the visible rows */ stj = (uint32_t) bmath_floorf(y / cellsize); edj = stj + (uint32_t) bmath_ceilf(height / cellsize) + 1; //if (edj > i_NUM_ROWS) edj = i_NUM_ROWS; if (edj > app->nrows) edj = app->nrows; posy = (real32_t)app->margin + stj * cellsize; draw_fill_color(ctx, color_gray(240)); draw_rect(ctx, ekFILL, x, y, width, height); draw_fill_color(ctx, color_gray(200)); draw_line_color(ctx, kCOLOR_BLUE); draw_line_width(ctx, 1); draw_text_align(ctx, ekCENTER, ekCENTER); draw_text_halign(ctx, ekCENTER); photoIndex = 0; for (j = stj; j < edj; ++j) { posx = (real32_t)app->margin + sti * cellsize; for (i = sti; i < edi; ++i) { //don't layout more photos than we have got... if (photoIndex++ >= app->numImg) break; char_t text[128]; bool_t special_cell = FALSE; bstd_sprintf(text, sizeof(text), "%d - %d", i+1, j+1); if (app->sel_cell_x == i && app->sel_cell_y == j) { draw_line_width(ctx, 6); if (app->focus == TRUE) draw_line_color(ctx, kCOLOR_RED); else draw_line_color(ctx, color_gray(100)); special_cell = TRUE; } else if (app->mouse_cell_x == i && app->mouse_cell_y == j) { draw_line_width(ctx, 3); draw_line_color(ctx, kCOLOR_BLUE); special_cell = TRUE; } draw_rect(ctx, ekSKFILL, posx, posy, i_CELL_SIZE, i_CELL_SIZE); draw_image(ctx, image2, posx, posy); draw_text(ctx, text, posx + 20, posy + i_CELL_SIZE - 20); // not +hcell if (special_cell == TRUE) { draw_line_width(ctx, 1); draw_line_color(ctx, kCOLOR_BLUE); } posx += cellsize; } posy += cellsize; } image_destroy(&image2); } /*---------------------------------------------------------------------------*/ static void j_OnDraw(App *app, Event *e) { const EvDraw *p = event_params(e, EvDraw); i_draw_clipped(app, p->ctx, p->x, p->y, p->width, p->height); } /*---------------------------------------------------------------------------*/ static void j_mouse_cell(App *app, const real32_t x, const real32_t y, const uint32_t action) { real32_t cellsize = i_CELL_SIZE + (real32_t)app->margin; uint32_t mx = (uint32_t)bmath_floorf(x / cellsize); uint32_t my = (uint32_t)bmath_floorf(y / cellsize); real32_t xmin = mx * cellsize + (real32_t)app->margin; real32_t xmax = xmin + i_CELL_SIZE; real32_t ymin = my * cellsize + (real32_t)app->margin; real32_t ymax = ymin + i_CELL_SIZE; if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) { if (action == 0) { app->mouse_cell_x = mx; app->mouse_cell_y = my; } else { app->sel_cell_x = mx; app->sel_cell_y = my; } } else { app->mouse_cell_x = UINT32_MAX; app->mouse_cell_y = UINT32_MAX; } view_update(app->view); } /*---------------------------------------------------------------------------*/ static void j_OnMove(App *app, Event *e) { const EvMouse *p = event_params(e, EvMouse); j_mouse_cell(app, p->x, p->y, 0); } /*---------------------------------------------------------------------------*/ static void j_OnUp(App *app, Event *e) { const EvMouse *p = event_params(e, EvMouse); j_mouse_cell(app, p->x, p->y, 0); } /*---------------------------------------------------------------------------*/ static void j_OnDown(App *app, Event *e) { const EvMouse *p = event_params(e, EvMouse); j_mouse_cell(app, p->x, p->y, 1); } /*---------------------------------------------------------------------------*/ static void j_OnFocus(App *app, Event *e) { const bool_t *p = event_params(e, bool_t); app->focus = *p; view_update(app->view); } /*---------------------------------------------------------------------------*/ static void j_OnKeyDown(App *app, Event *e) { const EvKey *p = event_params(e, EvKey); View *view = event_sender(e, View); real32_t margin = (real32_t)app->margin; real32_t cellsize = i_CELL_SIZE + margin; V2Df scroll; S2Df size; view_viewport(view, &scroll, &size); // if (p->key == ekKEY_DOWN && app->sel_cell_y < i_NUM_ROWS - 1) { if (p->key == ekKEY_DOWN && app->sel_cell_y < app->nrows - 1) { real32_t ymin = (app->sel_cell_y + 1) * cellsize + margin; ymin += i_CELL_SIZE; if (scroll.y + size.height <= ymin) { view_scroll_y(view, ymin - size.height + margin); app->mouse_cell_x = UINT32_MAX; app->mouse_cell_y = UINT32_MAX; } app->sel_cell_y += 1; view_update(app->view); } if (p->key == ekKEY_UP && app->sel_cell_y > 0) { real32_t ymin = (app->sel_cell_y - 1) * cellsize + (real32_t)app->margin; if (scroll.y >= ymin) { view_scroll_y(view, ymin - margin); app->mouse_cell_x = UINT32_MAX; app->mouse_cell_y = UINT32_MAX; } app->sel_cell_y -= 1; view_update(app->view); } // if (p->key == ekKEY_RIGHT && app->sel_cell_x < i_NUM_COLS - 1) { if (p->key == ekKEY_RIGHT && app->sel_cell_x < app->ncols - 1) { real32_t xmin = (app->sel_cell_x + 1) * cellsize + margin; xmin += i_CELL_SIZE; if (scroll.x + size.width <= xmin) { view_scroll_x(view, xmin - size.width + margin); app->mouse_cell_x = UINT32_MAX; app->mouse_cell_y = UINT32_MAX; } app->sel_cell_x += 1; view_update(app->view); } if (p->key == ekKEY_LEFT && app->sel_cell_x > 0) { real32_t xmin = (app->sel_cell_x - 1) * cellsize + (real32_t)app->margin; if (scroll.x >= xmin) { view_scroll_x(view, xmin - margin); app->mouse_cell_x = UINT32_MAX; app->mouse_cell_y = UINT32_MAX; } app->sel_cell_x -= 1; view_update(app->view); } } /*---------------------------------------------------------------------------*/ static Image *get_image(void) { //const char_t *type[] = { "png", "jpg", "CR2" }; //const char_t *file = comwin_open_file(app->window, type, 3, NULL); const char_t *file = "/Users/sam/img_0004.jpg"; Image *img, *imgScaled = NULL; //TODO: must use read bytes to buffer, image_from_data(buffer, size) or similar to handle photos... if (file != NULL) { img = image_from_file(file, NULL); imgScaled = image_scale(img, (uint32_t) i_CELL_SIZE, UINT32_MAX); } image_destroy(&img); return imgScaled; } /*---------------------------------------------------------------------------*/ static Panel *filter_panel(void) { Panel *filters = panel_create(); Layout *filtLayout = layout_create(1, 1); //size the panel panel_size(filters, s2df(1000.0, 20.0)); //TODO: proper filters and searches Label *txt = label_new("Filters and stuff"); layout_label(filtLayout, txt, 0, 0); //pass back panel_layout(filters, filtLayout); return filters; } /*---------------------------------------------------------------------------*/ static Panel *info_panel(void) { Panel *info = panel_create(); Layout *infoLayout = layout_create(1, 1); //size the panel panel_size(info, s2df(1000.0, 20.0)); //TODO: proper information Label *txt = label_new("information, statistics and stuff"); layout_label(infoLayout, txt, 0, 0); //pass back panel_layout(info, infoLayout); return info; } /*---------------------------------------------------------------------------*/ static Panel *middle_panel(App *app) { //create layouts Layout *midLayout = layout_create(3, 1); Layout *treeLayout = layout_create(1, 1); Layout *photoLayout = layout_create(1, 1); Layout *tagsLayout = layout_create(1, 1); //create controls Panel *mid = panel_create(); TableView *tree = tableview_create(); TableView *tags = tableview_create(); //view View *view = view_scroll(); view_size(view, s2df(HSIZE, VSIZE)); view_OnDraw(view, listener(app, j_OnDraw, App)); view_OnMove(view, listener(app, j_OnMove, App)); view_OnUp(view, listener(app, j_OnUp, App)); view_OnDown(view, listener(app, j_OnDown, App)); view_OnFocus(view, listener(app, j_OnFocus, App)); view_OnKeyDown(view, listener(app, j_OnKeyDown, App)); //assign layouts layout_tableview(treeLayout, tree, 0, 0); layout_tableview(tagsLayout, tags, 0, 0); layout_layout(midLayout, treeLayout, 0, 0); layout_layout(midLayout, photoLayout, 1, 0); layout_layout(midLayout, tagsLayout, 2, 0); //view layout_view(photoLayout, view, 0, 0); //make all reszing in middle layout_hexpand(midLayout, 1); //sizes & margins layout_hsize(midLayout, 0, 200); //layout_hsize(midLayout, 1, 800); layout_hsize(midLayout, 2, 200); layout_hmargin(midLayout, 0, 5); layout_hmargin(midLayout, 1, 5); //pass back app->view = view; panel_layout(mid, midLayout); return mid; } /*---------------------------------------------------------------------------*/ static Panel *i_panel(App *app) { //create layouts Layout *layout = layout_create(1, 3); Layout *filtLayout = layout_create(1, 1); Layout *infoLayout = layout_create(1, 1); Layout *midLayout = layout_create(1, 1); //panels Panel *panel = panel_create(); //main Panel *filtPanel = filter_panel(); //filters Panel *midPanel = middle_panel(app); //photo collection Panel *infoPanel = info_panel(); //information //assign layouts layout_panel(filtLayout, filtPanel, 0, 0); layout_panel(midLayout, midPanel, 0, 0); layout_panel(infoLayout, infoPanel, 0, 0); layout_layout(layout, filtLayout, 0, 0); layout_layout(layout, midLayout, 0, 1); layout_layout(layout, infoLayout, 0, 2); //make all reszing in middle layout_vexpand(layout, 1); //sizes layout_vsize(layout, 0, 20); layout_vsize(layout, 1, VSIZE); layout_vsize(layout, 2, 20); //sizes - margins (internal & external) layout_vmargin(layout, 0, 5); layout_vmargin(layout, 1, 5); layout_margin(layout,10); //pass back panel_layout(panel, layout); return panel; } /*---------------------------------------------------------------------------*/ static void i_OnResize(App *app, Event *e) { S2Df size = window_get_size(app->window); app->ncols = (uint32_t) ((size.width - 400)/165); //heuristic.... app->nrows = (uint32_t) app->numImg/app->ncols + 1; i_content_size(app); window_update(app->window); printf("Resize: %f, %f, cols: %u\n", size.width, size.height, app->ncols); unref(e); } ///*---------------------------------------------------------------------------*/ //static void myMove(App *app, Event *e) { // printf("MOVED! "); // unref(e); //} /*---------------------------------------------------------------------------*/ static void i_OnClose(App *app, Event *e) { osapp_finish(); unref(app); unref(e); } /*---------------------------------------------------------------------------*/ static App *i_create(void) { App *app = heap_new0(App); Panel *panel = i_panel(app); //basic collection app->ncols = 7; app->numImg = 80; //later from collection app->nrows = (uint32_t) app->numImg/app->ncols + 1; app->col_id = 0; app->row_id = 0; app->margin = 10; app->mouse_cell_x = UINT32_MAX; app->mouse_cell_y = UINT32_MAX; app->sel_cell_x = app->col_id; app->sel_cell_y = app->row_id; app->focus = FALSE; app->window = window_create(ekWINDOW_STDRES); i_content_size(app); window_panel(app->window, panel); window_title(app->window, "Funtus4"); window_origin(app->window, v2df(200, 200)); window_OnClose(app->window, listener(app, i_OnClose, App)); //window_OnMoved(app->window, listener(app, myMove, App)); window_OnResize(app->window, listener(app, i_OnResize, App)); window_show(app->window); return app; } /*---------------------------------------------------------------------------*/ static void i_destroy(App **app) { window_destroy(&(*app)->window); heap_delete(app, App); } /*---------------------------------------------------------------------------*/ #include "osmain.h" osmain(i_create, i_destroy, "", App)