widgets: add bool widget_geometries(wibox_t *)

Signed-off-by: Gregor Best <farhaven@googlemail.com>
Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Gregor Best 2009-02-10 17:30:57 +01:00 committed by Julien Danjou
parent 18e96e360d
commit 6bbcb1f56e
8 changed files with 145 additions and 219 deletions

5
draw.c
View File

@ -224,10 +224,7 @@ draw_text(draw_context_t *ctx, draw_text_context_t *data,
pango_layout_set_font_description(ctx->layout, globalconf.font->desc);
x = area.x + margin->left;
/* + 1 is added for rounding, so that in any case of doubt we rather draw
* the text 1px lower than too high which usually results in a better type
* face */
y = area.y + (ctx->height - ext->height + 1) / 2 + margin->top;
y = area.y + margin->top;
/* only honors alignment if enough space */
if(ext->width < area.width)

174
widget.c
View File

@ -129,6 +129,93 @@ luaA_table2widgets(lua_State *L, widget_node_array_t *widgets)
}
}
/** Retrieve a list of widget geometries using a Lua layout function.
* a table which contains the geometries is then pushed onto the stack
* \param wibox The wibox.
* \return True is everything is ok, false otherwise.
* \todo What do we do if there's no layout defined?
*/
bool
widget_geometries(wibox_t *wibox)
{
/* get the layout field of the widget table */
if (wibox->widgets_table != LUA_REFNIL)
{
lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, wibox->widgets_table);
lua_getfield(globalconf.L, -1, "layout");
}
else
lua_pushnil(globalconf.L);
/* if the layout field is a function */
if(lua_isfunction(globalconf.L, -1))
{
/* Push 1st argument: wibox geometry */
area_t geometry = wibox->sw.geometry;
geometry.x = 0;
geometry.y = 0;
/* we need to exchange the width and height of the wibox window if it
* it is rotated, so the layout function doesn't need to care about that
*/
if(wibox->sw.orientation != East)
{
int i = geometry.height;
geometry.height = geometry.width;
geometry.width = i;
}
geometry.height -= 2 * wibox->sw.border.width;
geometry.width -= 2 * wibox->sw.border.width;
luaA_pusharea(globalconf.L, geometry);
/* Re-push 2nd argument: widget table */
lua_pushvalue(globalconf.L, -3);
/* Push 3rd argument: wibox screen */
lua_pushnumber(globalconf.L, screen_array_indexof(&globalconf.screens, wibox->screen));
/* Re-push the layout function */
lua_pushvalue(globalconf.L, -4);
/* call the layout function with 3 arguments (wibox geometry, widget
* table, screen) and wait for one result */
if(!luaA_dofunction(globalconf.L, 3, 1))
return false;
lua_insert(globalconf.L, -3);
lua_pop(globalconf.L, 2);
}
else
{
/* If no layout function has been specified, we just push a table with
* geometries onto the stack. These geometries are nothing fancy, they
* have x = y = 0 and their height and width set to the widgets demands
* or the wibox size, depending on which is less.
*/
widget_node_array_t *widgets = &wibox->widgets;
widget_node_array_wipe(widgets);
widget_node_array_init(widgets);
lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, wibox->widgets_table);
luaA_table2widgets(globalconf.L, widgets);
lua_pop(globalconf.L, 2);
lua_newtable(globalconf.L);
for(int i = 0; i < widgets->len; i++)
{
lua_pushnumber(globalconf.L, i + 1);
widget_t *widget = widgets->tab[i].widget;
lua_pushnumber(globalconf.L, screen_array_indexof(&globalconf.screens, wibox->screen));
area_t geometry = widget->extents(globalconf.L, widget);
lua_pop(globalconf.L, 1);
geometry.x = geometry.y = 0;
geometry.width = MIN(wibox->sw.geometry.width, geometry.width);
geometry.height = MIN(wibox->sw.geometry.height, geometry.height);
luaA_pusharea(globalconf.L, geometry);
lua_settable(globalconf.L, -3);
}
}
return true;
}
/** Render a list of widgets.
* \param wibox The wibox.
* \todo Remove GC.
@ -136,14 +223,17 @@ luaA_table2widgets(lua_State *L, widget_node_array_t *widgets)
void
widget_render(wibox_t *wibox)
{
lua_State *L = globalconf.L;
draw_context_t *ctx = &wibox->sw.ctx;
int left = 0, right = 0;
area_t rectangle = { 0, 0, 0, 0 };
color_t col;
rectangle.width = ctx->width;
rectangle.height = ctx->height;
if (!widget_geometries(wibox))
return;
if(ctx->bg.alpha != 0xffff)
{
int x = wibox->sw.geometry.x, y = wibox->sw.geometry.y;
@ -195,74 +285,23 @@ widget_render(wibox_t *wibox)
widget_node_array_wipe(widgets);
widget_node_array_init(widgets);
lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, wibox->widgets_table);
luaA_table2widgets(globalconf.L, widgets);
lua_rawgeti(L, LUA_REGISTRYINDEX, wibox->widgets_table);
luaA_table2widgets(L, widgets);
/* compute geometry */
for(int i = 0; i < widgets->len; i++)
if(widgets->tab[i].widget->align == AlignLeft
&& widgets->tab[i].widget->isvisible)
{
widgets->tab[i].geometry = widgets->tab[i].widget->geometry(widgets->tab[i].widget,
wibox->screen, ctx->height,
ctx->width - (left + right));
widgets->tab[i].geometry.x = left;
left += widgets->tab[i].geometry.width;
}
/* get computed geometries */
for(unsigned int i = 0; i < lua_objlen(L, -1); i++)
{
lua_pushnumber(L, i + 1);
lua_gettable(L, -2);
for(int i = widgets->len - 1; i >= 0; i--)
if(widgets->tab[i].widget->align == AlignRight && widgets->tab[i].widget->isvisible)
{
widgets->tab[i].geometry = widgets->tab[i].widget->geometry(widgets->tab[i].widget,
wibox->screen, ctx->height,
ctx->width - (left + right));
right += widgets->tab[i].geometry.width;
widgets->tab[i].geometry.x = ctx->width - right;
}
widgets->tab[i].geometry.x = luaA_getopt_number(L, -1, "x", wibox->sw.geometry.x);
widgets->tab[i].geometry.y = luaA_getopt_number(L, -1, "y", wibox->sw.geometry.y);
widgets->tab[i].geometry.width = luaA_getopt_number(L, -1, "width", 1);
widgets->tab[i].geometry.height = luaA_getopt_number(L, -1, "height", 1);
/* save left value */
int fake_left = left;
/* compute width of flex or fixed aligned widgets */
int flex = 0;
for(int i = 0; i < widgets->len; i++)
if(widgets->tab[i].widget->align & (AlignFlex | AlignFixed)
&& widgets->tab[i].widget->isvisible)
{
if(widgets->tab[i].widget->align_supported & AlignFlex
&& widgets->tab[i].widget->align == AlignFlex)
flex++;
else
fake_left += widgets->tab[i].widget->geometry(widgets->tab[i].widget,
wibox->screen, ctx->height,
ctx->width - (fake_left + right)).width;
}
/* now compute everybody together! */
int flex_rendered = 0;
for(int i = 0; i < widgets->len; i++)
if(widgets->tab[i].widget->align & (AlignFlex | AlignFixed)
&& widgets->tab[i].widget->isvisible)
{
if(widgets->tab[i].widget->align_supported & AlignFlex
&& widgets->tab[i].widget->align == AlignFlex)
{
int width = (ctx->width - (right + fake_left)) / flex;
/* give last pixels to last flex to be rendered */
if(flex_rendered == flex - 1)
width += (ctx->width - (right + fake_left)) % flex;
widgets->tab[i].geometry = widgets->tab[i].widget->geometry(widgets->tab[i].widget,
wibox->screen, ctx->height,
width);
flex_rendered++;
}
else
widgets->tab[i].geometry = widgets->tab[i].widget->geometry(widgets->tab[i].widget,
wibox->screen, ctx->height,
ctx->width - (left + right));
widgets->tab[i].geometry.x = left;
left += widgets->tab[i].geometry.width;
}
lua_pop(L, 1);
}
lua_pop(L, 1);
/* draw background image, only if the background color is not opaque */
if(wibox->bg_image && ctx->bg.alpha != 0xffff)
@ -275,11 +314,8 @@ widget_render(wibox_t *wibox)
/* draw everything! */
for(int i = 0; i < widgets->len; i++)
if(widgets->tab[i].widget->isvisible)
{
widgets->tab[i].geometry.y = 0;
widgets->tab[i].widget->draw(widgets->tab[i].widget,
ctx, widgets->tab[i].geometry, wibox);
}
switch(wibox->sw.orientation)
{

View File

@ -37,7 +37,7 @@ struct widget_t
/** Widget destructor */
widget_destructor_t *destructor;
/** Geometry function for drawing */
area_t (*geometry)(widget_t *, screen_t *, int, int);
area_t (*geometry)(widget_t *, int);
/** Extents function */
area_t (*extents)(lua_State *, widget_t *);
/** Draw function */
@ -72,6 +72,7 @@ struct widget_node_t
widget_t *widget_getbycoords(orientation_t, widget_node_array_t *, int, int, int16_t *, int16_t *);
void widget_render(wibox_t *);
bool widget_geometries(wibox_t *);
void widget_invalidate_bywidget(widget_t *);
void widget_invalidate_bytype(widget_constructor_t *);

View File

@ -148,13 +148,13 @@ graph_plot_get(graph_data_t *d, const char *title)
}
static area_t
graph_geometry(widget_t *widget, screen_t *screen, int height, int width)
graph_geometry(widget_t *widget, int screen)
{
area_t geometry;
graph_data_t *d = widget->data;
geometry.x = geometry.y = 0;
geometry.height = height;
geometry.height = d->width;
geometry.width = d->width;
return geometry;
@ -163,11 +163,7 @@ graph_geometry(widget_t *widget, screen_t *screen, int height, int width)
static area_t
graph_extents(lua_State *L, widget_t *widget)
{
area_t geometry;
graph_data_t *d = widget->data;
geometry.width = geometry.height = d->width;
return geometry;
return graph_geometry(widget, 0);
}
/** Draw a graph widget.

View File

@ -33,37 +33,15 @@ typedef struct
} imagebox_data_t;
static area_t
imagebox_geometry(widget_t *widget, screen_t *screen, int height, int width)
imagebox_geometry(widget_t *widget, int screen)
{
area_t geometry;
imagebox_data_t *d = widget->data;
if(d->image)
{
int iwidth = image_getwidth(d->image);
int iheight = image_getheight(d->image);
if(d->resize)
{
double ratio = (double) height / iheight;
geometry.width = ratio * iwidth;
if(geometry.width > width)
{
geometry.width = 0;
geometry.height = 0;
}
else
geometry.height = height;
}
else if(iwidth <= width)
{
geometry.width = iwidth;
geometry.height = height;
}
else
{
geometry.width = 0;
geometry.height = 0;
}
geometry.width = image_getwidth(d->image);
geometry.height = image_getheight(d->image);
}
else
{
@ -79,21 +57,7 @@ imagebox_geometry(widget_t *widget, screen_t *screen, int height, int width)
static area_t
imagebox_extents(lua_State *L, widget_t *widget)
{
area_t geometry = {
.x = 0,
.y = 0,
.width = 0,
.height = 0
};
imagebox_data_t *d = widget->data;
if(d->image)
{
geometry.width = image_getwidth(d->image);
geometry.height = image_getheight(d->image);
}
return geometry;
return imagebox_geometry(widget, 0);
}
/** Draw an image.
@ -112,22 +76,8 @@ imagebox_draw(widget_t *widget, draw_context_t *ctx, area_t geometry, wibox_t *p
if(d->bg.initialized)
draw_rectangle(ctx, geometry, 1.0, true, &d->bg);
int y = geometry.y;
int iheight = image_getheight(d->image);
double ratio = d->resize ? (double) geometry.height / iheight : 1;
switch(d->valign)
{
case AlignBottom:
y += geometry.height - iheight;
break;
case AlignCenter:
y += (geometry.height - iheight) / 2;
break;
default:
break;
}
draw_image(ctx, geometry.x, y, ratio, d->image);
double ratio = d->resize ? (double) geometry.height / image_getheight(d->image) : 1;
draw_image(ctx, geometry.x, geometry.y, ratio, d->image);
}
}

View File

@ -133,12 +133,11 @@ progressbar_bar_get(bar_array_t *bars, const char *title)
}
static area_t
progressbar_geometry(widget_t *widget, screen_t *screen, int height, int width)
progressbar_geometry(widget_t *widget, int screen)
{
area_t geometry;
progressbar_data_t *d = widget->data;
geometry.height = height;
if(d->vertical)
{
@ -157,6 +156,7 @@ progressbar_geometry(widget_t *widget, screen_t *screen, int height, int width)
}
geometry.width = pb_width + 2 * (d->border_width + d->border_padding);
}
geometry.height = geometry.width;
geometry.x = geometry.y = 0;
@ -166,29 +166,7 @@ progressbar_geometry(widget_t *widget, screen_t *screen, int height, int width)
static area_t
progressbar_extents(lua_State *L, widget_t *widget)
{
area_t geometry;
progressbar_data_t *d = widget->data;
if (d->vertical)
{
int pb_width = (int) ((d->width - 2 * (d->border_width + d->border_padding) * d->bars.len
- d->gap * (d->bars.len - 1)) / d->bars.len);
geometry.width = d->bars.len * (pb_width + 2 * (d->border_width + d->border_padding)
+ d->gap) - d->gap;
}else
{
int pb_width = d->width - 2 * (d->border_width + d->border_padding);
if(d->ticks_count && d->ticks_gap)
{
int unit = (pb_width + d->ticks_gap) / d->ticks_count;
pb_width = unit * d->ticks_count - d->ticks_gap; /* rounded to match ticks... */
}
geometry.width = pb_width + 2 * (d->border_width + d->border_padding);
}
geometry.height = geometry.width;
return geometry;
return progressbar_geometry(widget, 0);
}
/** Draw a progressbar.

View File

@ -25,6 +25,7 @@
#include "widget.h"
#include "screen.h"
#include "wibox.h"
#include "structs.h"
#include "common/xembed.h"
#include "common/atoms.h"
@ -32,36 +33,16 @@
#define _NET_SYSTEM_TRAY_ORIENTATION_VERT 1
static area_t
systray_geometry(widget_t *widget, screen_t *screen, int height, int width)
systray_geometry(widget_t *widget, int screen)
{
area_t geometry;
int phys_screen = screen_virttophys(screen_array_indexof(&globalconf.screens, screen)), n = 0;
geometry.height = height;
for(int i = 0; i < globalconf.embedded.len; i++)
if(globalconf.embedded.tab[i].phys_screen == phys_screen)
n++;
/** \todo use class hints */
geometry.width = MIN(n * height, width);
geometry.x = geometry.y = 0;
return geometry;
}
static area_t
systray_extents(lua_State *L, widget_t *widget)
{
area_t geometry;
int screen = screen_virttophys(luaL_optnumber(L, -1, 1)), n = 0;
int phys_screen = screen_virttophys(screen), n = 0;
geometry.height = 0;
int width = 0;
for(int i = 0; i < globalconf.embedded.len; i++)
if(globalconf.embedded.tab[i].phys_screen == screen)
if(globalconf.embedded.tab[i].phys_screen == phys_screen)
{
xcb_get_geometry_cookie_t geo = xcb_get_geometry(globalconf.connection, globalconf.embedded.tab[i].win);
xcb_get_geometry_reply_t *g = xcb_get_geometry_reply(globalconf.connection, geo, NULL);
@ -73,11 +54,22 @@ systray_extents(lua_State *L, widget_t *widget)
width = g->width;
}
/** \todo use class hints */
geometry.width = width * n;
geometry.x = geometry.y = 0;
return geometry;
}
static area_t
systray_extents(lua_State *L, widget_t *widget)
{
int screen = screen_virttophys(luaL_optnumber(L, -1, 1));
return systray_geometry(widget, screen);
}
static void
systray_draw(widget_t *widget, draw_context_t *ctx,
area_t geometry, wibox_t *p)

View File

@ -20,6 +20,7 @@
*/
#include "widget.h"
#include "wibox.h"
#include "common/tokenize.h"
/** The textbox private data structure */
@ -53,38 +54,10 @@ typedef struct
} textbox_data_t;
static area_t
textbox_geometry(widget_t *widget, screen_t *screen, int height, int width)
{
area_t geometry;
textbox_data_t *d = widget->data;
geometry.height = height;
if(d->width)
geometry.width = d->width;
else if(widget->align == AlignFlex)
geometry.width = width;
else if(d->bg_image)
{
int bgi_height = image_getheight(d->bg_image);
int bgi_width = image_getwidth(d->bg_image);
double ratio = d->bg_resize ? (double) geometry.height / bgi_height : 1;
geometry.width = MIN(width, MAX(d->extents.width + d->margin.left + d->margin.right, MAX(d->width, bgi_width * ratio)));
}
else
geometry.width = MIN(d->extents.width + d->margin.left + d->margin.right, width);
geometry.x = geometry.y = 0;
return geometry;
}
static area_t
textbox_extents(lua_State *L, widget_t *widget)
textbox_geometry(widget_t *widget, int screen)
{
textbox_data_t *d = widget->data;
area_t geometry = d->extents;
geometry.width += d->margin.left + d->margin.left;
geometry.height += d->margin.bottom + d->margin.top;
@ -96,15 +69,17 @@ textbox_extents(lua_State *L, widget_t *widget)
geometry.width = MAX(d->extents.width + d->margin.left + d->margin.right, MAX(d->width, bgi_width * ratio));
}
if (d->data.len == 0)
{
geometry.width = 0;
geometry.height = 0;
}
geometry.x = geometry.y = 0;
return geometry;
}
static area_t
textbox_extents(lua_State *L, widget_t *widget)
{
return textbox_geometry(widget, 0);
}
/** Draw a textbox widget.
* \param widget The widget.
* \param ctx The draw context.
@ -152,6 +127,7 @@ textbox_draw(widget_t *widget, draw_context_t *ctx, area_t geometry, wibox_t *p)
}
}
geometry.y += (geometry.height - textbox_geometry(widget, ctx->phys_screen).height - p->sw.border.width + 1) / 2;
draw_text(ctx, &d->data, d->ellip, d->wrap, d->align, &d->margin, geometry, &d->extents);
}