panel: New volume slider menu widget
This commit is contained in:
parent
f0091f8f87
commit
729b0c231f
121
apps/panel.c
121
apps/panel.c
@ -287,10 +287,7 @@ static void update_volume_level(void) {
|
||||
ioctl(mixer, SND_MIXER_READ_KNOB, &value);
|
||||
volume_level = value.val;
|
||||
}
|
||||
static void volume_raise(void) {
|
||||
volume_level += 0x10000000;
|
||||
if (volume_level > 0xF0000000) volume_level = 0xFC000000;
|
||||
|
||||
static void set_volume(void) {
|
||||
snd_knob_value_t value = {0};
|
||||
value.device = VOLUME_DEVICE_ID; /* TODO configure this somewhere */
|
||||
value.id = VOLUME_KNOB_ID; /* TODO this too */
|
||||
@ -299,19 +296,96 @@ static void volume_raise(void) {
|
||||
ioctl(mixer, SND_MIXER_WRITE_KNOB, &value);
|
||||
redraw();
|
||||
}
|
||||
static void volume_raise(void) {
|
||||
volume_level += 0x10000000;
|
||||
if (volume_level > 0xF0000000) volume_level = 0xFC000000;
|
||||
set_volume();
|
||||
}
|
||||
static void volume_lower(void) {
|
||||
volume_level -= 0x10000000;
|
||||
if (volume_level < 0x0) volume_level = 0x0;
|
||||
|
||||
snd_knob_value_t value = {0};
|
||||
value.device = VOLUME_DEVICE_ID; /* TODO configure this somewhere */
|
||||
value.id = VOLUME_KNOB_ID; /* TODO this too */
|
||||
value.val = volume_level;
|
||||
|
||||
ioctl(mixer, SND_MIXER_WRITE_KNOB, &value);
|
||||
redraw();
|
||||
set_volume();
|
||||
}
|
||||
|
||||
#define VOLUME_SLIDER_LEFT_PAD 36
|
||||
#define VOLUME_SLIDER_RIGHT_PAD 12
|
||||
#define VOLUME_SLIDER_PAD (VOLUME_SLIDER_LEFT_PAD + VOLUME_SLIDER_RIGHT_PAD)
|
||||
#define VOLUME_SLIDER_VERT_PAD 8
|
||||
#define VOLUME_SLIDER_BALL_RADIUS 8
|
||||
|
||||
struct SliderStuff {
|
||||
int level;
|
||||
uint32_t on;
|
||||
uint32_t off;
|
||||
};
|
||||
|
||||
uint32_t volume_pattern(int32_t x, int32_t y, double alpha, void * extra) {
|
||||
struct SliderStuff * stuff = extra;
|
||||
if (alpha > 1.0) alpha = 1.0;
|
||||
if (alpha < 0.0) alpha = 0.0;
|
||||
uint32_t color = stuff->off;
|
||||
if (x < stuff->level + VOLUME_SLIDER_LEFT_PAD) {
|
||||
color = stuff->on;
|
||||
}
|
||||
color |= rgba(0,0,0,alpha*255);
|
||||
return premultiply(color);
|
||||
}
|
||||
|
||||
void _menu_draw_MenuEntry_Slider(gfx_context_t * ctx, struct MenuEntry * self, int offset) {
|
||||
self->offset = offset;
|
||||
|
||||
draw_sprite_alpha_paint(ctx, sprite_volume_high, 4, offset, 1.0, rgb(0,0,0));
|
||||
|
||||
struct SliderStuff stuff;
|
||||
stuff.level = (ctx->width - VOLUME_SLIDER_PAD) * (float)volume_level / (float)0xFC000000;
|
||||
stuff.on = rgba(0,120,220,0);
|
||||
stuff.off = rgba(140,140,140,0);
|
||||
draw_rounded_rectangle_pattern(ctx,
|
||||
VOLUME_SLIDER_LEFT_PAD - 1, offset + VOLUME_SLIDER_VERT_PAD - 1,
|
||||
ctx->width - VOLUME_SLIDER_PAD + 2, self->height - 2 * VOLUME_SLIDER_VERT_PAD + 2, 6, volume_pattern, &stuff);
|
||||
stuff.on = rgba(40,160,255,0);
|
||||
stuff.off = rgba(200,200,200,0);
|
||||
draw_rounded_rectangle_pattern(ctx,
|
||||
VOLUME_SLIDER_LEFT_PAD, offset + VOLUME_SLIDER_VERT_PAD,
|
||||
ctx->width - VOLUME_SLIDER_PAD, self->height - 2 * VOLUME_SLIDER_VERT_PAD, 5, volume_pattern, &stuff);
|
||||
|
||||
draw_rounded_rectangle(ctx, stuff.level - VOLUME_SLIDER_BALL_RADIUS + VOLUME_SLIDER_LEFT_PAD, offset + 12 - VOLUME_SLIDER_BALL_RADIUS,
|
||||
VOLUME_SLIDER_BALL_RADIUS * 2, VOLUME_SLIDER_BALL_RADIUS * 2, VOLUME_SLIDER_BALL_RADIUS, rgb(140,140,140));
|
||||
draw_rounded_rectangle(ctx, stuff.level - VOLUME_SLIDER_BALL_RADIUS + 1 + VOLUME_SLIDER_LEFT_PAD, offset + 12 - VOLUME_SLIDER_BALL_RADIUS + 1,
|
||||
VOLUME_SLIDER_BALL_RADIUS * 2 - 2, VOLUME_SLIDER_BALL_RADIUS * 2 - 2, VOLUME_SLIDER_BALL_RADIUS - 1, rgb(220,220,220));
|
||||
}
|
||||
|
||||
int _menu_mouse_MenuEntry_Slider(struct MenuEntry * self, struct yutani_msg_window_mouse_event * event) {
|
||||
if (event->buttons & YUTANI_MOUSE_BUTTON_LEFT) {
|
||||
/* Figure out where it is */
|
||||
float level = (float)(event->new_x - VOLUME_SLIDER_LEFT_PAD) / (float)(self->width - VOLUME_SLIDER_PAD);
|
||||
if (level >= 1.0) level = 1.0;
|
||||
if (level <= 0.0) level = 0.0;
|
||||
if (volume_level != level * 0xFC000000) {
|
||||
volume_level = level * 0xFC000000;
|
||||
set_volume();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct MenuEntryVTable slider_vtable = {
|
||||
.methods = 4,
|
||||
.renderer = _menu_draw_MenuEntry_Slider,
|
||||
.mouse_event = _menu_mouse_MenuEntry_Slider,
|
||||
};
|
||||
|
||||
struct MenuEntry * menu_create_slider(void) {
|
||||
struct MenuEntry * out = menu_create_separator(); /* Steal some defaults */
|
||||
out->_type = -1; /* Special */
|
||||
out->height = 24;
|
||||
out->rwidth = 200;
|
||||
out->vtable = &slider_vtable;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
static int volume_left = 0;
|
||||
static void show_volume_status(void) {
|
||||
if (!volume_menu) {
|
||||
@ -326,14 +400,7 @@ static void show_volume_status(void) {
|
||||
free(node);
|
||||
}
|
||||
|
||||
/* Add the current volume status */
|
||||
char volume_level_label[100];
|
||||
if (volume_level < 10) {
|
||||
snprintf(volume_level_label, 99, "<b>Volume:</b> <i>Muted</i>");
|
||||
} else {
|
||||
snprintf(volume_level_label, 99, "<b>Volume:</b> %d%%", (int)(100 * ((float)volume_level / (float)0xFc000000)));
|
||||
}
|
||||
menu_insert(volume_menu, menu_create_normal(NULL, NULL, volume_level_label, NULL));
|
||||
menu_insert(volume_menu, menu_create_slider());
|
||||
|
||||
/* TODO Our mixer supports multiple knobs and we could show all of them. */
|
||||
/* TODO We could also show a nice slider... if we had one... */
|
||||
@ -1392,6 +1459,11 @@ void _menu_draw_MenuEntry_Clock(gfx_context_t * ctx, struct MenuEntry * self, in
|
||||
|
||||
}
|
||||
|
||||
static struct MenuEntryVTable clock_vtable = {
|
||||
.methods = 3,
|
||||
.renderer = _menu_draw_MenuEntry_Clock,
|
||||
};
|
||||
|
||||
struct MenuEntry * menu_create_clock(void) {
|
||||
struct MenuEntry * out = menu_create_separator(); /* Steal some defaults */
|
||||
|
||||
@ -1403,7 +1475,7 @@ struct MenuEntry * menu_create_clock(void) {
|
||||
out->_type = -1; /* Special */
|
||||
out->height = 140;
|
||||
out->rwidth = 148;
|
||||
out->renderer = _menu_draw_MenuEntry_Clock;
|
||||
out->vtable = &clock_vtable;
|
||||
return out;
|
||||
}
|
||||
|
||||
@ -1503,6 +1575,11 @@ void _menu_draw_MenuEntry_Calendar(gfx_context_t * ctx, struct MenuEntry * self,
|
||||
}
|
||||
}
|
||||
|
||||
static struct MenuEntryVTable calendar_vtable = {
|
||||
.methods = 3,
|
||||
.renderer = _menu_draw_MenuEntry_Calendar,
|
||||
};
|
||||
|
||||
/*
|
||||
* Special menu entry to display a calendar
|
||||
*/
|
||||
@ -1517,7 +1594,7 @@ struct MenuEntry * menu_create_calendar(void) {
|
||||
|
||||
tt_set_size(font_mono, 13);
|
||||
out->rwidth = 200; //tt_string_width(font_mono, "XX XX XX XX XX XX XX") + 20;
|
||||
out->renderer = _menu_draw_MenuEntry_Calendar;
|
||||
out->vtable = &calendar_vtable;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/hashmap.h>
|
||||
#include <toaru/list.h>
|
||||
#include <toaru/yutani.h>
|
||||
|
||||
_Begin_C_Header
|
||||
|
||||
@ -15,6 +16,15 @@ enum MenuEntry_Type {
|
||||
};
|
||||
|
||||
struct MenuList;
|
||||
struct MenuEntry;
|
||||
|
||||
struct MenuEntryVTable {
|
||||
size_t methods;
|
||||
void (*renderer)(gfx_context_t *, struct MenuEntry *, int);
|
||||
void (*focus_change)(struct MenuEntry *, int);
|
||||
void (*activate)(struct MenuEntry *, int);
|
||||
int (*mouse_event)(struct MenuEntry *, struct yutani_msg_window_mouse_event *);
|
||||
};
|
||||
|
||||
struct MenuEntry {
|
||||
enum MenuEntry_Type _type;
|
||||
@ -27,10 +37,7 @@ struct MenuEntry {
|
||||
int hilight; /* Is currently hilighted */
|
||||
int offset; /* Our offset when we were rendered */
|
||||
|
||||
void (*renderer)(gfx_context_t *, struct MenuEntry *, int);
|
||||
void (*focus_change)(struct MenuEntry *, int);
|
||||
void (*activate)(struct MenuEntry *, int);
|
||||
|
||||
struct MenuEntryVTable * vtable;
|
||||
void (*callback)(struct MenuEntry *);
|
||||
};
|
||||
|
||||
|
65
lib/menu.c
65
lib/menu.c
@ -127,15 +127,20 @@ void _menu_activate_MenuEntry_Normal(struct MenuEntry * self, int flags) {
|
||||
}
|
||||
}
|
||||
|
||||
static struct MenuEntryVTable _menu_vtable_MenuEntry_Normal = {
|
||||
.methods = 3,
|
||||
.renderer = _menu_draw_MenuEntry_Normal,
|
||||
.focus_change = _menu_focus_MenuEntry_Normal,
|
||||
.activate = _menu_activate_MenuEntry_Normal,
|
||||
};
|
||||
|
||||
struct MenuEntry * menu_create_normal(const char * icon, const char * action, const char * title, void (*callback)(struct MenuEntry *)) {
|
||||
struct MenuEntry_Normal * out = malloc(sizeof(struct MenuEntry_Normal));
|
||||
|
||||
out->_type = MenuEntry_Normal;
|
||||
out->height = MENU_ENTRY_HEIGHT;
|
||||
out->hilight = 0;
|
||||
out->renderer = _menu_draw_MenuEntry_Normal;
|
||||
out->focus_change = _menu_focus_MenuEntry_Normal;
|
||||
out->activate = _menu_activate_MenuEntry_Normal;
|
||||
out->vtable = &_menu_vtable_MenuEntry_Normal;
|
||||
out->icon = icon ? strdup(icon) : NULL;
|
||||
out->title = strdup(title);
|
||||
out->action = action ? strdup(action) : NULL;
|
||||
@ -164,7 +169,7 @@ void _menu_draw_MenuEntry_Submenu(gfx_context_t * ctx, struct MenuEntry * self,
|
||||
|
||||
void _menu_focus_MenuEntry_Submenu(struct MenuEntry * self, int focused) {
|
||||
if (focused) {
|
||||
self->activate(self, focused);
|
||||
self->vtable->activate(self, focused);
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,15 +200,20 @@ void _menu_activate_MenuEntry_Submenu(struct MenuEntry * self, int focused) {
|
||||
|
||||
}
|
||||
|
||||
static struct MenuEntryVTable _menu_vtable_MenuEntry_Submenu = {
|
||||
.methods = 3,
|
||||
.renderer = _menu_draw_MenuEntry_Submenu,
|
||||
.focus_change = _menu_focus_MenuEntry_Submenu,
|
||||
.activate = _menu_activate_MenuEntry_Submenu,
|
||||
};
|
||||
|
||||
struct MenuEntry * menu_create_submenu(const char * icon, const char * action, const char * title) {
|
||||
struct MenuEntry_Submenu * out = malloc(sizeof(struct MenuEntry_Submenu));
|
||||
|
||||
out->_type = MenuEntry_Submenu;
|
||||
out->height = MENU_ENTRY_HEIGHT;
|
||||
out->hilight = 0;
|
||||
out->renderer = _menu_draw_MenuEntry_Submenu;
|
||||
out->focus_change = _menu_focus_MenuEntry_Submenu;
|
||||
out->activate = _menu_activate_MenuEntry_Submenu;
|
||||
out->vtable = &_menu_vtable_MenuEntry_Submenu;
|
||||
out->icon = icon ? strdup(icon) : NULL;
|
||||
out->title = strdup(title);
|
||||
out->action = action ? strdup(action) : NULL;
|
||||
@ -232,16 +242,21 @@ void _menu_activate_MenuEntry_Separator(struct MenuEntry * self, int focused) {
|
||||
|
||||
}
|
||||
|
||||
static struct MenuEntryVTable _menu_vtable_MenuEntry_Separator = {
|
||||
.methods = 3,
|
||||
.renderer = _menu_draw_MenuEntry_Separator,
|
||||
.focus_change = _menu_focus_MenuEntry_Separator,
|
||||
.activate = _menu_activate_MenuEntry_Separator,
|
||||
};
|
||||
|
||||
struct MenuEntry * menu_create_separator(void) {
|
||||
struct MenuEntry_Separator * out = malloc(sizeof(struct MenuEntry_Separator));
|
||||
|
||||
out->_type = MenuEntry_Separator;
|
||||
out->height = 6;
|
||||
out->hilight = 0;
|
||||
out->renderer = _menu_draw_MenuEntry_Separator;
|
||||
out->focus_change = _menu_focus_MenuEntry_Separator;
|
||||
out->rwidth = 10; /* at least a bit please */
|
||||
out->activate = _menu_activate_MenuEntry_Separator;
|
||||
out->vtable = &_menu_vtable_MenuEntry_Separator;
|
||||
|
||||
return (struct MenuEntry *)out;
|
||||
}
|
||||
@ -545,8 +560,8 @@ static void _menu_redraw(yutani_window_t * menu_window, yutani_t * yctx, struct
|
||||
int offset = (menu->flags & MENU_FLAG_BUBBLE) ? 12 : 4;
|
||||
foreach(node, entries) {
|
||||
struct MenuEntry * entry = node->value;
|
||||
if (entry->renderer) {
|
||||
entry->renderer(ctx, entry, offset);
|
||||
if (entry->vtable->methods >= 1 && entry->vtable->renderer) {
|
||||
entry->vtable->renderer(ctx, entry, offset);
|
||||
}
|
||||
|
||||
offset += entry->height;
|
||||
@ -734,7 +749,9 @@ void menu_key_action(struct MenuList * menu, struct yutani_msg_key_event * me) {
|
||||
if (hilighted) {
|
||||
hilighted->hilight = 1;
|
||||
if (hilighted->_type == MenuEntry_Submenu) {
|
||||
hilighted->activate(hilighted, 0);
|
||||
if (hilighted->vtable->methods >= 3 && hilighted->vtable->activate) {
|
||||
hilighted->vtable->activate(hilighted, 0);
|
||||
}
|
||||
_menu_redraw(window,yctx,menu,1);
|
||||
} else {
|
||||
struct menu_bar * bar = NULL;
|
||||
@ -764,7 +781,9 @@ void menu_key_action(struct MenuList * menu, struct yutani_msg_key_event * me) {
|
||||
}
|
||||
if (hilighted) {
|
||||
hilighted->hilight = 1;
|
||||
hilighted->activate(hilighted, 0);
|
||||
if (hilighted->vtable->methods >= 3 && hilighted->vtable->activate) {
|
||||
hilighted->vtable->activate(hilighted, 0);
|
||||
}
|
||||
}
|
||||
} else if (me->event.keycode == KEY_ARROW_LEFT) {
|
||||
if (menu->parent) {
|
||||
@ -800,18 +819,26 @@ void menu_mouse_action(struct MenuList * menu, struct yutani_msg_window_mouse_ev
|
||||
if (!entry->hilight) {
|
||||
changed = 1;
|
||||
entry->hilight = 1;
|
||||
entry->focus_change(entry, 1);
|
||||
if (entry->vtable->methods >= 2 && entry->vtable->focus_change) {
|
||||
entry->vtable->focus_change(entry, 1);
|
||||
}
|
||||
}
|
||||
if (me->command == YUTANI_MOUSE_EVENT_CLICK || _close_enough(me)) {
|
||||
if (entry->activate) {
|
||||
entry->activate(entry, 0);
|
||||
if (entry->vtable->methods >= 4 && entry->vtable->mouse_event) {
|
||||
if (entry->vtable->mouse_event(entry, me)) {
|
||||
_menu_redraw(window,yctx,menu,1);
|
||||
}
|
||||
} else if (me->command == YUTANI_MOUSE_EVENT_CLICK || _close_enough(me)) {
|
||||
if (entry->vtable->methods >= 3 && entry->vtable->activate) {
|
||||
entry->vtable->activate(entry, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (entry->hilight) {
|
||||
changed = 1;
|
||||
entry->hilight = 0;
|
||||
entry->focus_change(entry, 0);
|
||||
if (entry->vtable->methods >= 2 && entry->vtable->focus_change) {
|
||||
entry->vtable->focus_change(entry, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
offset += entry->height;
|
||||
|
Loading…
Reference in New Issue
Block a user