2024-01-20 12:05:26 +00:00
|
|
|
/*
|
|
|
|
* mui_menus_draw.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "mui.h"
|
|
|
|
#include "mui_priv.h"
|
|
|
|
#include "cg.h"
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Menubar/menus frames is easy as pie -- just a framed rectangle
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
mui_wdef_menubar_draw(
|
|
|
|
struct mui_window_t * win,
|
|
|
|
mui_drawable_t * dr)
|
|
|
|
{
|
|
|
|
c2_rect_t content = win->frame;
|
|
|
|
win->content = content;
|
|
|
|
struct cg_ctx_t * cg = mui_drawable_get_cg(dr);
|
|
|
|
|
|
|
|
mui_color_t frameColor = MUI_COLOR(0x000000ff);
|
|
|
|
mui_color_t contentFill = MUI_COLOR(0xf0f0f0ff);
|
|
|
|
cg_set_line_width(cg, 1);
|
|
|
|
cg_rectangle(cg, win->frame.l + 0.5f, win->frame.t + 0.5f,
|
|
|
|
c2_rect_width(&win->frame) - 1, c2_rect_height(&win->frame) - 1);
|
|
|
|
cg_set_source_color(cg, &CG_COLOR(contentFill));
|
|
|
|
cg_fill_preserve(cg);
|
|
|
|
cg_set_source_color(cg, &CG_COLOR(frameColor));
|
|
|
|
cg_stroke(cg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
extern const mui_control_color_t mui_control_color[MUI_CONTROL_STATE_COUNT];
|
|
|
|
|
2024-03-13 08:45:11 +00:00
|
|
|
enum {
|
|
|
|
MUI_MENUITEM_PART_ICON = 0,
|
|
|
|
MUI_MENUITEM_PART_TITLE,
|
|
|
|
MUI_MENUITEM_PART_KCOMBO,
|
|
|
|
MUI_MENUITEM_PART_COUNT,
|
|
|
|
};
|
2024-01-20 12:05:26 +00:00
|
|
|
|
2024-03-13 08:45:11 +00:00
|
|
|
/* this return the l,t coordinates for parts */
|
2024-01-20 12:05:26 +00:00
|
|
|
static void
|
2024-03-13 08:45:11 +00:00
|
|
|
mui_menuitem_get_part_locations(
|
2024-01-20 12:05:26 +00:00
|
|
|
mui_t * ui,
|
|
|
|
c2_rect_t * frame,
|
|
|
|
mui_menu_item_t * item,
|
2024-03-13 08:45:11 +00:00
|
|
|
c2_rect_t out[MUI_MENUITEM_PART_COUNT])
|
2024-01-20 12:05:26 +00:00
|
|
|
{
|
|
|
|
mui_font_t * main = mui_font_find(ui, "main");
|
2024-03-13 08:45:11 +00:00
|
|
|
const int margin_right = main->size / 3;
|
|
|
|
const int margin_left = main->size;
|
2024-01-20 12:05:26 +00:00
|
|
|
|
|
|
|
stb_ttc_measure m = {};
|
|
|
|
mui_font_text_measure(main, item->title, &m);
|
|
|
|
|
2024-03-13 08:45:11 +00:00
|
|
|
for (int i = 0; i < MUI_MENUITEM_PART_COUNT; i++)
|
|
|
|
out[i] = C2_RECT_WH(0, 0, 0, 0);
|
2024-01-20 12:05:26 +00:00
|
|
|
c2_rect_t title = *frame;
|
|
|
|
title.b = title.t + m.ascent - m.descent;
|
2024-03-13 08:45:11 +00:00
|
|
|
// center it vertically.
|
2024-01-20 12:05:26 +00:00
|
|
|
c2_rect_offset(&title, 0,
|
|
|
|
(c2_rect_height(frame) / 2) - (c2_rect_height(&title) / 2));
|
|
|
|
|
2024-03-13 08:45:11 +00:00
|
|
|
/* An icon shifts the title right, a 'mark' doesn't */
|
2024-01-20 12:05:26 +00:00
|
|
|
if (item->icon[0]) {
|
|
|
|
mui_font_t * icons = mui_font_find(ui, "icon_small");
|
|
|
|
mui_font_text_measure(icons, item->icon, &m);
|
2024-03-13 08:45:11 +00:00
|
|
|
title.l += 6;
|
2024-01-20 12:05:26 +00:00
|
|
|
c2_pt_t loc = title.tl;
|
2024-03-13 08:45:11 +00:00
|
|
|
loc.x += (icons->size / 2) - ((m.x1 - m.x0) / 2);
|
|
|
|
out[MUI_MENUITEM_PART_ICON].tl = loc;
|
2024-01-20 12:05:26 +00:00
|
|
|
title.l += 6;
|
|
|
|
} else if (item->mark[0]) {
|
|
|
|
mui_font_text_measure(main, item->mark, &m);
|
|
|
|
c2_pt_t loc = title.tl;
|
2024-03-13 08:45:11 +00:00
|
|
|
loc.x += (main->size / 2) - ((m.x1 - m.x0) / 2);
|
|
|
|
out[MUI_MENUITEM_PART_ICON].tl = loc;
|
2024-01-20 12:05:26 +00:00
|
|
|
}
|
2024-03-13 08:45:11 +00:00
|
|
|
// this is the 'left margin' for the menu item
|
|
|
|
title.l += margin_left;
|
2024-01-20 12:05:26 +00:00
|
|
|
if (item->kcombo[0]) {
|
|
|
|
mui_font_text_measure(main, item->kcombo, &m);
|
2024-03-13 08:45:11 +00:00
|
|
|
c2_pt_t loc = C2_PT(title.r - m.x1 - m.x0 - margin_right, title.t);
|
|
|
|
out[MUI_MENUITEM_PART_KCOMBO] = (c2_rect_t){
|
|
|
|
.l = loc.x, .t = loc.y,
|
|
|
|
.r = title.r - margin_right,
|
|
|
|
.b = title.b };
|
|
|
|
title.r = loc.x;
|
|
|
|
}
|
|
|
|
out[MUI_MENUITEM_PART_TITLE] = title;
|
|
|
|
}
|
2024-01-20 12:05:26 +00:00
|
|
|
|
2024-03-13 08:45:11 +00:00
|
|
|
void
|
|
|
|
mui_menutitle_get_part_locations(
|
|
|
|
mui_t * ui,
|
|
|
|
c2_rect_t * frame, // optional!
|
|
|
|
mui_menu_item_t * item,
|
|
|
|
c2_rect_t * out)
|
|
|
|
{
|
|
|
|
mui_font_t * main = mui_font_find(ui, "main");
|
|
|
|
const int margin = main->size / 3;
|
|
|
|
|
|
|
|
for (int i = 0; i < MUI_MENUTITLE_PART_COUNT; i++)
|
|
|
|
out[i] = C2_RECT_WH(0, 0, 0, 0);
|
|
|
|
if (item->color_icon) {
|
|
|
|
out[MUI_MENUTITLE_PART_ICON] = C2_RECT_WH(0, 0,
|
|
|
|
item->color_icon[0], item->color_icon[1]);
|
|
|
|
}
|
|
|
|
if (item->title) {
|
|
|
|
stb_ttc_measure m = {};
|
|
|
|
mui_font_text_measure(main, item->title, &m);
|
|
|
|
|
|
|
|
out[MUI_MENUTITLE_PART_TITLE] =
|
|
|
|
C2_RECT_WH(out[MUI_MENUTITLE_PART_ICON].r,
|
|
|
|
0, m.x1 - m.x0, m.ascent - m.descent);
|
|
|
|
}
|
|
|
|
out[MUI_MENUTITLE_PART_ALL] = out[MUI_MENUTITLE_PART_ICON];
|
|
|
|
c2_rect_union(
|
|
|
|
&out[MUI_MENUTITLE_PART_ALL],
|
|
|
|
&out[MUI_MENUTITLE_PART_TITLE]);
|
|
|
|
out[MUI_MENUTITLE_PART_ALL].r += margin;
|
|
|
|
if (frame) {
|
|
|
|
// center them all vertically at least
|
|
|
|
for (int i = 0; i < MUI_MENUTITLE_PART_COUNT; i++) {
|
|
|
|
c2_rect_offset(&out[i],
|
|
|
|
frame->l + margin, frame->t +
|
|
|
|
(c2_rect_height(frame) / 2) - (c2_rect_height(&out[i]) / 2));
|
|
|
|
}
|
2024-01-20 12:05:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-13 08:45:11 +00:00
|
|
|
void
|
|
|
|
mui_menutitle_draw(
|
|
|
|
mui_window_t * win,
|
|
|
|
mui_control_t * c,
|
|
|
|
mui_drawable_t *dr )
|
|
|
|
{
|
|
|
|
c2_rect_t f = c->frame;
|
|
|
|
c2_rect_offset(&f, win->content.l, win->content.t);
|
|
|
|
|
|
|
|
mui_font_t * main = mui_font_find(win->ui, "main");
|
|
|
|
|
|
|
|
c2_rect_t loc[MUI_MENUTITLE_PART_COUNT];
|
|
|
|
mui_menuitem_control_t *mic = (mui_menuitem_control_t*)c;
|
|
|
|
if (!mic->item.title)
|
|
|
|
mic->item.title = mic->control.title;
|
|
|
|
mui_menutitle_get_part_locations(win->ui, &f, &mic->item, loc);
|
2024-01-20 12:05:26 +00:00
|
|
|
|
2024-03-13 08:45:11 +00:00
|
|
|
mui_drawable_clip_push(dr, &f);
|
|
|
|
struct cg_ctx_t * cg = mui_drawable_get_cg(dr);
|
|
|
|
uint32_t state = mui_control_get_state(c);
|
|
|
|
if (state) {
|
|
|
|
cg_set_source_color(cg, &CG_COLOR(mui_control_color[state].fill));
|
|
|
|
cg_rectangle(cg, f.l, f.t, c2_rect_width(&f), c2_rect_height(&f));
|
|
|
|
cg_fill(cg);
|
|
|
|
}
|
|
|
|
if (mic->item.color_icon) {
|
|
|
|
if (!mic->color_icon) {
|
|
|
|
c2_pt_t size = C2_PT(mic->item.color_icon[0],
|
|
|
|
mic->item.color_icon[1]);
|
|
|
|
mic->color_icon = mui_drawable_new(size, 32,
|
|
|
|
(void*)(mic->item.color_icon + 2), size.x * 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
pixman_image_composite32(PIXMAN_OP_OVER,
|
|
|
|
mui_drawable_get_pixman(mic->color_icon),
|
|
|
|
NULL,
|
|
|
|
mui_drawable_get_pixman(dr),
|
|
|
|
0, 0, 0, 0,
|
|
|
|
loc[MUI_MENUTITLE_PART_ICON].l, loc[MUI_MENUTITLE_PART_ICON].t,
|
|
|
|
c2_rect_width(&loc[MUI_MENUTITLE_PART_ICON]),
|
|
|
|
c2_rect_height(&loc[MUI_MENUTITLE_PART_ICON]));
|
|
|
|
|
|
|
|
}
|
|
|
|
if (mic->item.title)
|
|
|
|
mui_font_text_draw(main, dr,
|
|
|
|
loc[MUI_MENUTITLE_PART_TITLE].tl,
|
|
|
|
mic->item.title, strlen(mic->item.title),
|
|
|
|
mui_control_color[state].text);
|
|
|
|
mui_drawable_clip_pop(dr);
|
|
|
|
}
|
2024-01-20 12:05:26 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
mui_menuitem_draw(
|
|
|
|
mui_window_t * win,
|
|
|
|
mui_control_t * c,
|
|
|
|
mui_drawable_t *dr )
|
|
|
|
{
|
|
|
|
c2_rect_t f = c->frame;
|
|
|
|
c2_rect_offset(&f, win->content.l, win->content.t);
|
|
|
|
|
|
|
|
mui_drawable_clip_push(dr, &f);
|
2024-03-13 08:45:11 +00:00
|
|
|
struct cg_ctx_t * cg = mui_drawable_get_cg(dr);
|
2024-01-20 12:05:26 +00:00
|
|
|
|
|
|
|
mui_font_t * main = TAILQ_FIRST(&win->ui->fonts);
|
|
|
|
if (c->title && c->title[0] != '-') {
|
2024-03-13 08:45:11 +00:00
|
|
|
c2_rect_t loc[MUI_MENUITEM_PART_COUNT];
|
2024-01-20 12:05:26 +00:00
|
|
|
mui_menuitem_control_t *mic = (mui_menuitem_control_t*)c;
|
2024-03-13 08:45:11 +00:00
|
|
|
mui_menuitem_get_part_locations(win->ui, &f, &mic->item, loc);
|
2024-01-20 12:05:26 +00:00
|
|
|
|
|
|
|
uint32_t state = mui_control_get_state(c);
|
|
|
|
if (state && state != MUI_CONTROL_STATE_DISABLED) {
|
|
|
|
c2_rect_t b = f;
|
|
|
|
c2_rect_inset(&b, 1, 0);
|
|
|
|
cg_set_source_color(cg, &CG_COLOR(mui_control_color[state].fill));
|
|
|
|
cg_rectangle(cg, b.l, b.t, c2_rect_width(&b), c2_rect_height(&b));
|
|
|
|
cg_fill(cg);
|
|
|
|
}
|
|
|
|
if (mic->item.icon[0]) {
|
|
|
|
mui_font_t * icons = mui_font_find(win->ui, "icon_small");
|
|
|
|
mui_font_text_draw(icons, dr,
|
2024-03-13 08:45:11 +00:00
|
|
|
loc[0].tl, mic->item.icon, 0,
|
2024-01-20 12:05:26 +00:00
|
|
|
mui_control_color[state].text);
|
|
|
|
} else if (mic->item.mark[0]) {
|
|
|
|
mui_font_text_draw(main, dr,
|
2024-03-13 08:45:11 +00:00
|
|
|
loc[0].tl, mic->item.mark, 0,
|
2024-01-20 12:05:26 +00:00
|
|
|
mui_control_color[state].text);
|
|
|
|
}
|
|
|
|
mui_font_text_draw(main, dr,
|
2024-03-13 08:45:11 +00:00
|
|
|
loc[1].tl, mic->item.title, 0,
|
2024-01-20 12:05:26 +00:00
|
|
|
mui_control_color[state].text);
|
|
|
|
|
|
|
|
if (mic->item.kcombo[0]) {
|
|
|
|
mui_font_text_draw(main, dr,
|
2024-03-13 08:45:11 +00:00
|
|
|
loc[2].tl, mic->item.kcombo, 0,
|
2024-01-20 12:05:26 +00:00
|
|
|
mui_control_color[state].text);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cg_move_to(cg, f.l, f.t + c2_rect_height(&f) / 2);
|
|
|
|
cg_line_to(cg, f.r, f.t + c2_rect_height(&f) / 2);
|
|
|
|
mui_color_t decoColor = MUI_COLOR(0x666666ff);
|
|
|
|
|
|
|
|
cg_set_source_color(cg, &CG_COLOR(decoColor));
|
|
|
|
cg_stroke(cg);
|
|
|
|
}
|
|
|
|
mui_drawable_clip_pop(dr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
mui_popuptitle_draw(
|
|
|
|
mui_window_t * win,
|
|
|
|
mui_control_t * c,
|
|
|
|
mui_drawable_t *dr )
|
|
|
|
{
|
|
|
|
mui_menu_control_t *pop = (mui_menu_control_t*)c;
|
|
|
|
c2_rect_t f = c->frame;
|
|
|
|
if (c2_rect_width(&pop->menu_frame) &&
|
|
|
|
c2_rect_width(&pop->menu_frame) < c2_rect_width(&f)) {
|
|
|
|
f = pop->menu_frame;
|
|
|
|
f.b = c->frame.b;
|
|
|
|
}
|
|
|
|
c2_rect_offset(&f, win->content.l, win->content.t);
|
|
|
|
|
|
|
|
mui_font_t * main = TAILQ_FIRST(&win->ui->fonts);
|
|
|
|
mui_font_t * icons = mui_font_find(win->ui, "icon_small");
|
|
|
|
uint32_t state = mui_control_get_state(c);
|
|
|
|
|
|
|
|
mui_drawable_clip_push(dr, &f);
|
|
|
|
struct cg_ctx_t * cg = mui_drawable_get_cg(dr);
|
|
|
|
c2_rect_t inner = f;
|
|
|
|
c2_rect_inset(&inner, 1, 1);
|
|
|
|
cg_set_line_width(cg, 2);
|
|
|
|
cg_round_rectangle(cg, inner.l, inner.t,
|
|
|
|
c2_rect_width(&inner), c2_rect_height(&inner), 3, 3);
|
|
|
|
cg_set_source_color(cg, &CG_COLOR(mui_control_color[state].fill));
|
|
|
|
cg_fill_preserve(cg);
|
|
|
|
cg_set_source_color(cg, &CG_COLOR(mui_control_color[state].frame));
|
|
|
|
cg_stroke(cg);
|
|
|
|
cg_move_to(cg, inner.r - 32, inner.t + 2);
|
|
|
|
cg_line_to(cg, inner.r - 32, inner.b - 2);
|
|
|
|
mui_color_t decoColor = MUI_COLOR(0x666666ff);
|
|
|
|
cg_set_source_color(cg, &CG_COLOR(decoColor));
|
|
|
|
cg_stroke(cg);
|
|
|
|
|
|
|
|
if (pop->menu.count) {
|
|
|
|
mui_menu_item_t item = pop->menu.e[c->value];
|
2024-03-13 08:45:11 +00:00
|
|
|
c2_rect_t loc[MUI_MENUITEM_PART_COUNT];
|
2024-01-20 12:05:26 +00:00
|
|
|
c2_rect_offset(&f, 0, -1);
|
2024-03-13 08:45:11 +00:00
|
|
|
mui_menuitem_get_part_locations(win->ui, &f, &item, loc);
|
2024-01-20 12:05:26 +00:00
|
|
|
|
|
|
|
if (item.icon[0])
|
|
|
|
mui_font_text_draw(icons, dr,
|
2024-03-13 08:45:11 +00:00
|
|
|
loc[0].tl, item.icon, 0,
|
2024-01-20 12:05:26 +00:00
|
|
|
mui_control_color[state].text);
|
|
|
|
mui_font_text_draw(main, dr,
|
2024-03-13 08:45:11 +00:00
|
|
|
loc[1].tl, item.title, 0,
|
2024-01-20 12:05:26 +00:00
|
|
|
mui_control_color[state].text);
|
|
|
|
}
|
|
|
|
mui_font_text_draw(icons, dr,
|
|
|
|
C2_PT(inner.r - 32 + 8, inner.t + 2), "", 0,
|
|
|
|
mui_control_color[state].text);
|
|
|
|
mui_drawable_clip_pop(dr);
|
|
|
|
}
|