panel: knock off more of the gnome-shell panel design

No, really, I'm not going to beat around the bush here.
This is a straight up clone of the gnome-shell panel design.
It always was anyway - this is just doing a better job of it.
This commit is contained in:
K. Lange 2023-04-25 19:32:34 +09:00
parent a2d68c8fa6
commit 40e3a43b1f
10 changed files with 135 additions and 87 deletions

View File

@ -50,6 +50,17 @@
#define ALTF2_WIDTH 400
#define ALTF2_HEIGHT 200
/* How many windows we can support in the advertisement lift before truncating it */
#define MAX_WINDOW_COUNT 100
/* Height of the panel window */
#define PANEL_HEIGHT 27
/* How far down dropdown menus should be shown */
#define DROPDOWN_OFFSET PANEL_HEIGHT
/* How much padding should be assured on the left and right of the screen for menus */
#define MENU_PAD 4
static struct PanelContext panel_context;
static gfx_context_t * ctx = NULL;
static yutani_window_t * panel = NULL;
@ -68,17 +79,11 @@ yutani_t * yctx;
int width;
int height;
struct TT_Font * font = NULL;
struct TT_Font * font_bold = NULL;
struct TT_Font * font_mono = NULL;
struct TT_Font * font_mono_bold = NULL;
list_t * widgets_enabled = NULL;
/* Windows, indexed by z-order */
struct window_ad * ads_by_z[MAX_WINDOW_COUNT+1] = {NULL};
int focused_app = -1;
int active_window = -1;
static int was_tabbing = 0;
@ -226,9 +231,9 @@ static void redraw_altf2(void) {
draw_rounded_rectangle(a2ctx,0,0, ALTF2_WIDTH, ALTF2_HEIGHT, 11, premultiply(rgba(120,120,120,150)));
draw_rounded_rectangle(a2ctx,1,1, ALTF2_WIDTH-2, ALTF2_HEIGHT-2, 10, ALTTAB_BACKGROUND);
tt_set_size(font, 20);
int t = tt_string_width(font, altf2_buffer);
tt_draw_string(a2ctx, font, center_x_a2(t), 80, altf2_buffer, rgb(255,255,255));
tt_set_size(panel_context.font, 20);
int t = tt_string_width(panel_context.font, altf2_buffer);
tt_draw_string(a2ctx, panel_context.font, center_x_a2(t), 80, altf2_buffer, rgb(255,255,255));
flip(a2ctx);
yutani_flip(yctx, alt_f2);
@ -337,9 +342,9 @@ static void redraw_alttab(void) {
{
struct window_ad * ad = ads_by_z[new_focused];
int t;
char * title = ellipsify(ad->name, 16, font, alttab->width - 20, &t);
tt_set_size(font, 16);
tt_draw_string(actx, font, center_x_a(t), rows * (ALTTAB_WIN_SIZE + 20) + 44, title, rgb(255,255,255));
char * title = ellipsify(ad->name, 16, panel_context.font, alttab->width - 20, &t);
tt_set_size(panel_context.font, 16);
tt_draw_string(actx, panel_context.font, center_x_a(t), rows * (ALTTAB_WIN_SIZE + 20) + 44, title, rgb(255,255,255));
free(title);
}
@ -532,7 +537,7 @@ void redraw(void) {
foreach(widget_node, widgets_enabled) {
struct PanelWidget * widget = widget_node->value;
gfx_context_t * inner = init_graphics_subregion(ctx, widget->left, Y_PAD, widget->width, PANEL_HEIGHT - Y_PAD * 2);
gfx_context_t * inner = init_graphics_subregion(ctx, widget->left, 0, widget->width, PANEL_HEIGHT);
widget->draw(widget, inner);
free(inner);
}
@ -679,6 +684,12 @@ static int widget_leave_generic(struct PanelWidget * this, struct yutani_msg_win
return 1;
}
void panel_highlight_widget(struct PanelWidget * this, gfx_context_t * ctx, int active) {
if (this->highlighted || active) {
draw_rounded_rectangle(ctx, 3, 3, ctx->width - 6, ctx->height - 6, 11, premultiply(rgba(120,120,120,active ? 180 : 150)));
}
}
static int widget_draw_generic(struct PanelWidget * this, gfx_context_t * ctx) {
draw_rounded_rectangle(
ctx, 0, 0, ctx->width, ctx->height, 7, premultiply(rgba(120,120,120,150)));
@ -702,6 +713,7 @@ static int widget_onkey_generic(struct PanelWidget * this, struct yutani_msg_key
struct PanelWidget * widget_new(void) {
struct PanelWidget * out = calloc(1, sizeof(struct PanelWidget));
out->pctx = &panel_context;
out->draw = widget_draw_generic;
out->click = mouse_event_ignore; /* click_generic */
out->right_click = mouse_event_ignore; /* right_click_generic */
@ -804,17 +816,26 @@ int main (int argc, char ** argv) {
yctx = yutani_init();
/* Shared fonts */
font = tt_font_from_shm("sans-serif");
font_bold = tt_font_from_shm("sans-serif.bold");
font_mono = tt_font_from_shm("monospace");
font_mono_bold = tt_font_from_shm("monospace.bold");
panel_context.font = tt_font_from_shm("sans-serif");
panel_context.font_bold = tt_font_from_shm("sans-serif.bold");
panel_context.font_mono = tt_font_from_shm("monospace");
panel_context.font_mono_bold = tt_font_from_shm("monospace.bold");
/* For convenience, store the display size */
width = yctx->display_width;
height = yctx->display_height;
panel_context.color_text_normal = rgb(230,230,230);
panel_context.color_text_hilighted = rgb(142,216,255);
panel_context.color_text_focused = rgb(255,255,255);
panel_context.color_icon_normal = rgb(230,230,230);
panel_context.color_special = rgb(93,163,236);
panel_context.font_size_default = 14;
panel_context.extra_widget_spacing = 12;
/* Create the panel window */
panel = yutani_window_create_flags(yctx, width, PANEL_HEIGHT, YUTANI_WINDOW_FLAG_NO_STEAL_FOCUS | YUTANI_WINDOW_FLAG_ALT_ANIMATION);
panel_context.basewindow = panel;
/* And move it to the top layer */
yutani_set_stack(yctx, panel, YUTANI_ZORDER_TOP);

View File

@ -18,7 +18,27 @@
_Begin_C_Header
struct PanelContext {
uint32_t color_text_normal;
uint32_t color_text_hilighted;
uint32_t color_text_focused;
uint32_t color_icon_normal;
uint32_t color_special;
int font_size_default;
yutani_window_t * basewindow;
struct TT_Font * font;
struct TT_Font * font_bold;
struct TT_Font * font_mono;
struct TT_Font * font_mono_bold;
int extra_widget_spacing;
};
struct PanelWidget {
struct PanelContext * pctx;
int highlighted;
int left;
int width;
@ -36,31 +56,8 @@ struct PanelWidget {
extern yutani_t * yctx;
extern list_t * widgets_enabled;
extern int width, height;
extern struct PanelWidget * widget_new(void);
#define MAX_WINDOW_COUNT 100
#define PANEL_HEIGHT 36
#define DROPDOWN_OFFSET 34
#define FONT_SIZE 14
#define X_PAD 4
#define Y_PAD 4
#define ICON_Y_PAD 5
#define TEXT_Y_OFFSET 6
#define ICON_PADDING 2
#define HILIGHT_COLOR rgb(142,216,255)
#define FOCUS_COLOR rgb(255,255,255)
#define TEXT_COLOR rgb(230,230,230)
#define ICON_COLOR rgb(230,230,230)
#define SPECIAL_COLOR rgb(93,163,236)
extern struct TT_Font * font;
extern struct TT_Font * font_bold;
extern struct TT_Font * font_mono;
extern struct TT_Font * font_mono_bold;
extern void launch_application_menu(struct MenuEntry * self);
struct window_ad {
@ -77,11 +74,10 @@ struct window_ad {
extern struct window_ad * ads_by_z[];
extern list_t * window_list;
extern int focused_app;
extern int active_window;
extern void redraw(void);
extern char * ellipsify(char * input, int font_size, struct TT_Font * font, int max_width, int * out_width);
extern int panel_menu_show(struct PanelWidget * this, struct MenuList * menu);
extern int panel_menu_show_at(struct MenuList * menu, int x);
extern void panel_highlight_widget(struct PanelWidget * this, gfx_context_t * ctx, int active);
_End_C_Header

View File

@ -12,8 +12,10 @@
static struct MenuList * appmenu;
static int widget_draw_appmenu(struct PanelWidget * this, gfx_context_t * ctx) {
tt_set_size(font, 16);
tt_draw_string(ctx, font, 0, 20, "Applications", appmenu->window ? HILIGHT_COLOR : TEXT_COLOR);
panel_highlight_widget(this,ctx, !!appmenu->window);
tt_set_size(this->pctx->font, 16);
int w = tt_string_width(this->pctx->font, "Applications");
tt_draw_string(ctx, this->pctx->font, (ctx->width - w) / 2, 20, "Applications", appmenu->window ? this->pctx->color_text_hilighted : this->pctx->color_text_normal);
return 0;
}
@ -42,6 +44,7 @@ struct PanelWidget * widget_init_appmenu(void) {
yutani_key_bind(yctx, KEY_F1, KEY_MOD_LEFT_ALT, YUTANI_BIND_STEAL);
struct PanelWidget * widget = widget_new();
widget->width = 130;
widget->draw = widget_draw_appmenu;
widget->click = widget_click_appmenu;

View File

@ -39,6 +39,7 @@ void _menu_draw_MenuEntry_Clock(gfx_context_t * ctx, struct MenuEntry * self, in
static const char * digits[] = {"12","1","2","3","4","5","6","7","8","9","10","11"};
struct TT_Font * font = ((struct PanelWidget*)self->_private)->pctx->font;
tt_set_size(font, 12);
for (int i = 0; i < 12; ++i) {
int w = tt_string_width(font, digits[i]);
@ -73,13 +74,14 @@ static struct MenuEntryVTable clock_vtable = {
.renderer = _menu_draw_MenuEntry_Clock,
};
struct MenuEntry * menu_create_clock(void) {
struct MenuEntry * menu_create_clock(struct PanelWidget * this) {
struct MenuEntry * out = menu_create_separator(); /* Steal some defaults */
out->_type = -1; /* Special */
out->height = 140;
out->rwidth = 148;
out->vtable = &clock_vtable;
out->_private = this;
return out;
}
@ -87,6 +89,10 @@ static int widget_draw_clock(struct PanelWidget * this, gfx_context_t * ctx) {
struct timeval now;
struct tm * timeinfo;
panel_highlight_widget(this,ctx,!!clockmenu->window);
struct TT_Font * font = this->pctx->font;
/* Get the current time for the clock */
gettimeofday(&now, NULL);
timeinfo = localtime((time_t *)&now.tv_sec);
@ -95,7 +101,8 @@ static int widget_draw_clock(struct PanelWidget * this, gfx_context_t * ctx) {
char time[80];
strftime(time, 80, "%H:%M:%S", timeinfo);
tt_set_size(font, 16);
tt_draw_string(ctx, font, 0, 20, time, clockmenu->window ? HILIGHT_COLOR : TEXT_COLOR);
int w = tt_string_width(font, time);
tt_draw_string(ctx, font, (ctx->width - w) / 2, 20, time, clockmenu->window ? this->pctx->color_text_hilighted : this->pctx->color_text_normal);
return 0;
}
@ -117,12 +124,13 @@ static int widget_update_clock(struct PanelWidget * this, int * force_updates) {
}
struct PanelWidget * widget_init_clock(void) {
struct PanelWidget * widget = widget_new();
clockmenu = menu_create();
clockmenu->flags |= MENU_FLAG_BUBBLE_RIGHT;
menu_insert(clockmenu, menu_create_clock());
menu_insert(clockmenu, menu_create_clock(widget));
struct PanelWidget * widget = widget_new();
widget->width = 80; /* TODO what */
widget->width = 90; /* TODO what */
widget->draw = widget_draw_clock;
widget->click = widget_click_clock;
widget->update = widget_update_clock;

View File

@ -53,6 +53,9 @@ void _menu_draw_MenuEntry_Calendar(gfx_context_t * ctx, struct MenuEntry * self,
memcpy(&actual, timeinfo, sizeof(struct tm));
timeinfo = &actual;
struct TT_Font * font = ((struct PanelWidget*)self->_private)->pctx->font;
struct TT_Font * font_bold = ((struct PanelWidget*)self->_private)->pctx->font_bold;
/* Render heading with Month Year */
{
char month[20];
@ -90,7 +93,7 @@ void _menu_draw_MenuEntry_Calendar(gfx_context_t * ctx, struct MenuEntry * self,
snprintf(date, 11, "%d", day);
/* Is this the cell for today? */
if (day == timeinfo->tm_mday) {
draw_rounded_rectangle(ctx, left - 1, self->offset + CALENDAR_BASE_HEIGHT + line * CALENDAR_LINE_HEIGHT - 2, cell_size + 2, CALENDAR_LINE_HEIGHT, 12, SPECIAL_COLOR);
draw_rounded_rectangle(ctx, left - 1, self->offset + CALENDAR_BASE_HEIGHT + line * CALENDAR_LINE_HEIGHT - 2, cell_size + 2, CALENDAR_LINE_HEIGHT, 12, ((struct PanelWidget*)self->_private)->pctx->color_special);
tt_draw_string(ctx, font, left + (cell_size - tt_string_width(font, date)) / 2,
self->offset + CALENDAR_BASE_HEIGHT + 13 + line * CALENDAR_LINE_HEIGHT, date, rgb(255,255,255));
} else {
@ -114,7 +117,7 @@ static struct MenuEntryVTable calendar_vtable = {
/*
* Special menu entry to display a calendar
*/
struct MenuEntry * menu_create_calendar(void) {
struct MenuEntry * menu_create_calendar(struct PanelWidget * this) {
struct MenuEntry * out = menu_create_separator(); /* Steal some defaults */
out->_type = -1; /* Special */
@ -123,9 +126,9 @@ struct MenuEntry * menu_create_calendar(void) {
gettimeofday(&now, NULL);
out->height = CALENDAR_LINE_HEIGHT * weeks_in_month(localtime((time_t *)&now.tv_sec)) + CALENDAR_BASE_HEIGHT + CALENDAR_PAD_HEIGHT;
tt_set_size(font_mono, 13);
out->rwidth = 200; //tt_string_width(font_mono, "XX XX XX XX XX XX XX") + 20;
out->rwidth = 200;
out->vtable = &calendar_vtable;
out->_private = this;
return out;
}
@ -133,10 +136,13 @@ struct MenuEntry * menu_create_calendar(void) {
static int weekday_width, date_width;
static char weekday[80], date[80];
static void update_date_widget(void) {
static void update_date_widget(struct PanelWidget * this) {
struct timeval now;
struct tm * timeinfo;
struct TT_Font * font = this->pctx->font;
struct TT_Font * font_bold = this->pctx->font_bold;
/* Get the current time for the clock */
gettimeofday(&now, NULL);
timeinfo = localtime((time_t *)&now.tv_sec);
@ -156,15 +162,20 @@ static void update_date_widget(void) {
}
static int widget_draw_date(struct PanelWidget * this, gfx_context_t * ctx) {
update_date_widget();
update_date_widget(this);
panel_highlight_widget(this,ctx,!!calmenu->window);
struct TT_Font * font = this->pctx->font;
struct TT_Font * font_bold = this->pctx->font_bold;
/* Day-of-week */
int t = (this->width - weekday_width) / 2;
tt_draw_string(ctx, font, t, 13, weekday, calmenu->window ? HILIGHT_COLOR : TEXT_COLOR);
tt_draw_string(ctx, font, t, 13, weekday, calmenu->window ? this->pctx->color_text_hilighted : this->pctx->color_text_normal);
/* Month Day */
t = (this->width - date_width) / 2;
tt_draw_string(ctx, font_bold, t, 23, date, calmenu->window ? HILIGHT_COLOR : TEXT_COLOR);
tt_draw_string(ctx, font_bold, t, 23, date, calmenu->window ? this->pctx->color_text_hilighted : this->pctx->color_text_normal);
return 0;
}
@ -179,17 +190,18 @@ static int widget_click_date(struct PanelWidget * this, struct yutani_msg_window
static int widget_update_date(struct PanelWidget * this, int * force_updates) {
int width_before = date_widget_width;
update_date_widget();
update_date_widget(this);
this->width = date_widget_width;
return width_before != date_widget_width;
}
struct PanelWidget * widget_init_date(void) {
struct PanelWidget * widget = widget_new();
calmenu = menu_create();
calmenu->flags |= MENU_FLAG_BUBBLE_CENTER;
menu_insert(calmenu, menu_create_calendar());
menu_insert(calmenu, menu_create_calendar(widget));
struct PanelWidget * widget = widget_new();
widget->width = 92; /* TODO calculate correct width */
widget->draw = widget_draw_date;
widget->click = widget_click_date;

View File

@ -12,7 +12,8 @@ static struct MenuList * logout_menu;
static sprite_t * sprite_logout;
static int widget_draw_logout(struct PanelWidget * this, gfx_context_t * ctx) {
draw_sprite_alpha_paint(ctx, sprite_logout, 1, 2, 1.0, (logout_menu->window ? HILIGHT_COLOR : ICON_COLOR)); /* Logout button */
panel_highlight_widget(this,ctx,!!logout_menu->window);
draw_sprite_alpha_paint(ctx, sprite_logout, (ctx->width - sprite_logout->width) / 2, 2, 1.0, (logout_menu->window ? this->pctx->color_text_hilighted : this->pctx->color_icon_normal)); /* Logout button */
return 0;
}
@ -32,7 +33,8 @@ struct PanelWidget * widget_init_logout(void) {
menu_insert(logout_menu, menu_create_normal("exit", "log-out", "Log Out", launch_application_menu));
struct PanelWidget * widget = widget_new();
widget->width = 24;
widget->width = sprite_logout->width + widget->pctx->extra_widget_spacing;
widget->draw = widget_draw_logout;
widget->click = widget_click_logout;
list_insert(widgets_enabled, widget);

View File

@ -139,11 +139,12 @@ static int widget_click_network(struct PanelWidget * this, struct yutani_msg_win
}
static int widget_draw_network(struct PanelWidget * this, gfx_context_t * ctx) {
uint32_t color = (netstat && netstat->window) ? HILIGHT_COLOR : ICON_COLOR;
uint32_t color = (netstat && netstat->window) ? this->pctx->color_text_hilighted : this->pctx->color_icon_normal;
panel_highlight_widget(this,ctx,(netstat && netstat->window));
if (network_status & 2) {
draw_sprite_alpha_paint(ctx, sprite_net_active, 0, 1, 1.0, color);
draw_sprite_alpha_paint(ctx, sprite_net_active, (ctx->width - sprite_net_active->width) / 2, 1, 1.0, color);
} else {
draw_sprite_alpha_paint(ctx, sprite_net_disabled, 0, 1, 1.0, color);
draw_sprite_alpha_paint(ctx, sprite_net_disabled, (ctx->width - sprite_net_disabled->width) / 2, 1, 1.0, color);
}
return 0;
@ -156,7 +157,7 @@ struct PanelWidget * widget_init_network(void) {
load_sprite(sprite_net_disabled, "/usr/share/icons/24/net-disconnected.png");
struct PanelWidget * widget = widget_new();
widget->width = 24;
widget->width = sprite_net_active->width + widget->pctx->extra_widget_spacing;
widget->draw = widget_draw_network;
widget->click = widget_click_network;
widget->update = widget_update_network;

View File

@ -179,15 +179,18 @@ static int widget_click_volume(struct PanelWidget * this, struct yutani_msg_wind
static int widget_draw_volume(struct PanelWidget * this, gfx_context_t * ctx) {
uint32_t color = (volume_menu && volume_menu->window) ? HILIGHT_COLOR : ICON_COLOR;
uint32_t color = (volume_menu && volume_menu->window) ? this->pctx->color_text_hilighted : this->pctx->color_icon_normal;
panel_highlight_widget(this,ctx,(volume_menu && volume_menu->window));
if (volume_level < 10) {
draw_sprite_alpha_paint(ctx, sprite_volume_mute, 0, 1, 1.0, color);
draw_sprite_alpha_paint(ctx, sprite_volume_mute, (ctx->width - sprite_volume_mute->width) / 2, 1, 1.0, color);
} else if (volume_level < 0x547ae147) {
draw_sprite_alpha_paint(ctx, sprite_volume_low, 0, 1, 1.0, color);
draw_sprite_alpha_paint(ctx, sprite_volume_low, (ctx->width - sprite_volume_low->width) / 2, 1, 1.0, color);
} else if (volume_level < 0xa8f5c28e) {
draw_sprite_alpha_paint(ctx, sprite_volume_med, 0, 1, 1.0, color);
draw_sprite_alpha_paint(ctx, sprite_volume_med, (ctx->width - sprite_volume_med->width) / 2, 1, 1.0, color);
} else {
draw_sprite_alpha_paint(ctx, sprite_volume_high, 0, 1, 1.0, color);
draw_sprite_alpha_paint(ctx, sprite_volume_high, (ctx->width - sprite_volume_high->width) / 2, 1, 1.0, color);
}
return 0;
@ -221,7 +224,7 @@ struct PanelWidget * widget_init_volume(void) {
load_sprite(sprite_volume_high, "/usr/share/icons/24/volume-full.png");
struct PanelWidget * widget = widget_new();
widget->width = 24;
widget->width = sprite_volume_high->width + widget->pctx->extra_widget_spacing;
widget->draw = widget_draw_volume;
widget->click = widget_click_volume;
widget->move = widget_move_volume;

View File

@ -116,7 +116,7 @@ static int widget_update_weather(struct PanelWidget * this, int * force_updates)
if (!widgets_weather_enabled) {
widgets_weather_enabled = 1;
this->width = 48;
this->width = 60;
return 1;
}
@ -173,11 +173,12 @@ static int widget_click_weather(struct PanelWidget * this, struct yutani_msg_win
static int widget_draw_weather(struct PanelWidget * this, gfx_context_t * ctx) {
if (widgets_weather_enabled) {
uint32_t color = (weather && weather->window) ? HILIGHT_COLOR : ICON_COLOR;
tt_set_size(font, 12);
int t = tt_string_width(font, weather_temp_str);
tt_draw_string(ctx, font, 24 + (24 - t) / 2, 6 + 12, weather_temp_str, color);
draw_sprite_alpha_paint(ctx, weather_icon, 0, 1, 1.0, color);
uint32_t color = (weather && weather->window) ? this->pctx->color_text_hilighted : this->pctx->color_icon_normal;
panel_highlight_widget(this,ctx, (weather && weather->window));
tt_set_size(this->pctx->font, 12);
int t = tt_string_width(this->pctx->font, weather_temp_str);
tt_draw_string(ctx, this->pctx->font, 4 + 24 + (24 - t) / 2, 6 + 12, weather_temp_str, color);
draw_sprite_alpha_paint(ctx, weather_icon, 4, 1, 1.0, color);
}
return 0;
}

View File

@ -16,6 +16,7 @@
static struct MenuList * window_menu;
static int title_width = 0;
static yutani_wid_t _window_menu_wid = 0;
static int focused_app = -1;
static void _window_menu_start_move(struct MenuEntry * self) {
if (!_window_menu_wid)
@ -84,30 +85,30 @@ static int widget_draw_windowlist(struct PanelWidget * this, gfx_context_t * ctx
}
}
uint32_t text_color = TEXT_COLOR;
if (j == focused_app) text_color = HILIGHT_COLOR;
else if (ad->flags & 1) text_color = FOCUS_COLOR;
else if (ad->flags & 2) text_color = premultiply(rgba(_RED(TEXT_COLOR),_GRE(TEXT_COLOR),_BLU(TEXT_COLOR),127));
uint32_t text_color = this->pctx->color_text_normal;
if (j == focused_app) text_color = this->pctx->color_text_hilighted;
else if (ad->flags & 1) text_color = this->pctx->color_text_focused;
else if (ad->flags & 2) text_color = premultiply(rgba(_RED(this->pctx->color_text_normal),_GRE(this->pctx->color_text_normal),_BLU(this->pctx->color_text_normal),127));
if (title_width >= MIN_TEXT_WIDTH) {
/* Ellipsifiy the title */
char * s = ellipsify(ad->name, 14, font, title_width - 4, NULL);
char * s = ellipsify(ad->name, 14, this->pctx->font, title_width - 4, NULL);
sprite_t * icon = icon_get_48(ad->icon);
gfx_context_t * subctx = init_graphics_subregion(ctx, i, 0, w, ctx->height);
gfx_context_t * subctx = init_graphics_subregion(ctx, i, 0, w, ctx->height-1);
draw_sprite_scaled_alpha(subctx, icon, w - 48 - 2, 0, 48, 48, (ad->flags & 1) ? 1.0 : 0.7);
tt_draw_string_shadow(subctx, font, s, 14, 2, TEXT_Y_OFFSET, text_color, rgb(0,0,0), 4);
tt_draw_string_shadow(subctx, this->pctx->font, s, 14, 2, 6, text_color, rgb(0,0,0), 4);
free(subctx);
free(s);
} else {
sprite_t * icon = icon_get_16(ad->icon);
gfx_context_t * subctx = init_graphics_subregion(ctx, i, 0, w, ctx->height);
gfx_context_t * subctx = init_graphics_subregion(ctx, i, 0, w, ctx->height-1);
draw_sprite_scaled(subctx, icon, 6, 6, 16, 16);
free(subctx);
}
ad->left = this->left + i;
yutani_window_panel_size(yctx, ad->wid, ad->left + X_PAD, Y_PAD, w, ctx->height);
yutani_window_panel_size(yctx, ad->wid, ad->left + this->pctx->basewindow->x, this->pctx->basewindow->y, w, ctx->height);
j++;
i += w;