Add window widget, play with logic for sizing (broken)

This commit is contained in:
Dave Davenport 2016-12-28 19:42:14 +01:00
parent 2db879e979
commit a2001d1b9c
10 changed files with 316 additions and 44 deletions

View file

@ -31,6 +31,7 @@ rofi_SOURCES=\
source/history.c\
source/theme.c\
source/widgets/box.c\
source/widgets/window.c\
source/widgets/widget.c\
source/widgets/textbox.c\
source/widgets/listview.c\
@ -62,6 +63,7 @@ rofi_SOURCES=\
include/history.h\
include/theme.h\
include/widgets/box.h\
include/widgets/window.h\
include/widgets/widget.h\
include/widgets/widget-internal.h\
include/widgets/textbox.h\

View file

@ -1,5 +1,6 @@
#ifndef ROFI_VIEW_INTERNAL_H
#define ROFI_VIEW_INTERNAL_H
#include "widgets/window.h"
#include "widgets/widget.h"
#include "widgets/textbox.h"
#include "widgets/separator.h"
@ -24,6 +25,7 @@ struct RofiViewState
/** Flag indicating if view needs to be refiltered. */
int refilter;
window *main_window;
/** Main #box widget holding different elements. */
box *main_box;
/** #box widget packing the input bar widgets. */

View file

@ -57,4 +57,13 @@ struct _widget
void widget_init ( widget *widget , const char *name, const char *class_name );
void widget_set_state ( widget *widget, const char *state );
int widget_padding_get_left ( const widget *wid );
int widget_padding_get_right ( const widget *wid );
int widget_padding_get_top ( const widget *wid );
int widget_padding_get_bottom ( const widget *wid );
int widget_padding_get_remaining_width ( const widget *wid );
int widget_padding_get_remaining_height ( const widget *wid );
int widget_padding_get_padding_height ( const widget *wid );
int widget_padding_get_padding_width ( const widget *wid );
#endif // WIDGET_INTERNAL_H

37
include/widgets/window.h Normal file
View file

@ -0,0 +1,37 @@
#ifndef ROFI_WINDOW_H
#define ROFI_WINDOW_H
#include "widget.h"
/**
* @defgroup window window
* @ingroup widget
*
*
* @{
*/
/**
* Abstract handle to the window widget internal state.
*/
typedef struct _window window;
/**
* @param name The name of the widget.
* @param type The packing direction of the newly created window.
*
* @returns a newly created window, free with #widget_free
*/
window * window_create ( const char *name );
/**
* @param window Handle to the window widget.
* @param child Handle to the child widget to pack.
*
* Add a widget to the window.
*/
void window_add ( window *window, widget *child );
int window_get_border_width ( const window *window );
/*@}*/
#endif // ROFI_WINDOW_H

View file

@ -23,7 +23,7 @@ WHITESPACE [[:space:]]
WORD [[:alnum:]-]+
STRING [[:print:]]+
HEX [[:xdigit:]]
NUMBER [[:digit:]]
NUMBER [[:digit:]-]
%x PROPERTIES
%x NAMESTR

View file

@ -298,9 +298,7 @@ static void rofi_view_window_update_size ( RofiViewState * state )
CacheState.edit_draw = cairo_create ( CacheState.edit_surf );
// Should wrap main window in a widget.
int width = state->width - 2*state->border - state->pad.left - state->pad.right;
int height = state->height - 2*state->border - state->pad.top- state->pad.bottom;
widget_resize ( WIDGET ( state->main_box ), width, height );
widget_resize ( WIDGET ( state->main_window ), state->width, state->height );
}
static gboolean rofi_view_reload_idle ( G_GNUC_UNUSED gpointer data )
@ -388,7 +386,7 @@ void rofi_view_free ( RofiViewState *state )
}
// Do this here?
// Wait for final release?
widget_free ( WIDGET ( state->main_box ) );
widget_free ( WIDGET ( state->main_window ) );
widget_free ( WIDGET ( state->overlay ) );
g_free ( state->line_map );
@ -775,7 +773,7 @@ static void update_callback ( textbox *t, unsigned int index, void *udata, TextB
void rofi_view_update ( RofiViewState *state )
{
if ( !widget_need_redraw ( WIDGET ( state->main_box ) ) && !widget_need_redraw ( WIDGET ( state->overlay ) ) ) {
if ( !widget_need_redraw ( WIDGET ( state->main_window ) ) && !widget_need_redraw ( WIDGET ( state->overlay ) ) ) {
return;
}
TICK ();
@ -792,36 +790,17 @@ void rofi_view_update ( RofiViewState *state )
}
cairo_paint ( d );
cairo_set_operator ( d, CAIRO_OPERATOR_OVER );
color_background ( d );
rofi_theme_get_color ( "@window" , "window" , NULL, "background", d );
cairo_paint ( d );
}
else {
// Paint the background.
color_background ( d );
rofi_theme_get_color ( "@window", "window" , NULL, "background", d );
// Paint the background transparent.
cairo_set_source_rgba ( d, 0,0,0,0.0);
cairo_paint ( d );
}
TICK_N ( "Background" );
color_border ( d );
rofi_theme_get_color ( "@window", "window" , NULL, "foreground", d );
int bw = rofi_theme_get_integer ( "@window", "window", NULL, "border-width" , config.menu_bw);
if ( bw > 0 ) {
cairo_save ( d );
cairo_set_line_width ( d, bw );
cairo_rectangle ( d,
bw / 2.0,
bw / 2.0,
state->width - bw,
state->height - bw );
cairo_stroke ( d );
cairo_restore ( d );
}
// Always paint as overlay over the background.
cairo_set_operator ( d, CAIRO_OPERATOR_OVER );
widget_draw ( WIDGET ( state->main_box ), d );
widget_draw ( WIDGET ( state->main_window ), d );
if ( state->overlay ) {
widget_draw ( WIDGET ( state->overlay ), d );
@ -886,7 +865,7 @@ static void rofi_view_mouse_navigation ( RofiViewState *state, xcb_button_press_
xcb_button_press_event_t rel = *xbe;
rel.event_x -= state->pad.left;
rel.event_y -= state->pad.top;
if ( widget_clicked ( WIDGET ( state->main_box ), &rel ) ) {
if ( widget_clicked ( WIDGET ( state->main_window ), &rel ) ) {
return;
}
}
@ -1278,9 +1257,7 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *ev, xkb_st
CacheState.edit_surf = cairo_xcb_surface_create ( xcb->connection, CacheState.edit_pixmap, visual, state->width, state->height );
CacheState.edit_draw = cairo_create ( CacheState.edit_surf );
int width = state->width - 2*state->border - state->pad.left - state->pad.right;
int height = state->height - 2*state->border - state->pad.top- state->pad.bottom;
widget_resize ( WIDGET ( state->main_box ), width, height );
widget_resize ( WIDGET ( state->main_window ), state->width, state->height );
}
}
break;
@ -1303,7 +1280,7 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *ev, xkb_st
xcb_motion_notify_event_t xme = *( (xcb_motion_notify_event_t *) ev );
xme.event_x -= state->pad.left;
xme.event_y -= state->pad.top;
if ( widget_motion_notify ( WIDGET ( state->main_box ), &xme ) ) {
if ( widget_motion_notify ( WIDGET ( state->main_window ), &xme ) ) {
return;
}
break;
@ -1377,13 +1354,33 @@ static int rofi_view_calculate_height ( RofiViewState *state )
}
if ( state->filtered_lines == 0 && !config.fixed_num_lines ) {
widget_disable ( WIDGET ( state->input_bar_separator ) );
widget_disable ( WIDGET ( state->list_view) );
}
else {
widget_enable ( WIDGET ( state->input_bar_separator ) );
widget_enable ( WIDGET ( state->list_view) );
}
height = listview_get_desired_height ( state->list_view );
// Why not a factor 2 here?
height += window_get_border_width ( state->main_window );
height += box_get_fixed_pixels ( state->main_box );
height += 2 * state->border +state->pad.top+state->pad.bottom;
// How to merge this....
int perc =0;
widget *main_window = WIDGET ( state->main_window );
if ( main_window->pad.top >= 0 ){
height += main_window->pad.top;
} else {
perc -= main_window->pad.top;
}
if ( main_window->pad.bottom >= 0 ){
height += main_window->pad.bottom;
} else {
perc -= main_window->pad.bottom;
}
if ( perc > 0){
height = (100*height)/(100-perc);
}
printf("listview: %d\n", listview_get_desired_height ( state->list_view ));
return height;
}
@ -1438,8 +1435,6 @@ RofiViewState *rofi_view_create ( Mode *sw,
state->pad = (Padding){config.padding,config.padding, config.padding, config.padding, FALSE};
state->pad = rofi_theme_get_padding ( "@window", "window", NULL, "padding", state->pad);
//state->border = rofi_theme_get_integer ("@window", "window", NULL, "padding" , config.padding );
state->border += rofi_theme_get_integer ("@window", "window", NULL, "border-width" , config.menu_bw);
// Request the lines to show.
state->num_lines = mode_get_num_entries ( sw );
@ -1449,8 +1444,9 @@ RofiViewState *rofi_view_create ( Mode *sw,
// Get active monitor size.
TICK_N ( "Get active monitor" );
state->main_window = window_create ( "window" );
state->main_box = box_create ( "mainbox.box", BOX_VERTICAL );
widget_move ( WIDGET ( state->main_box ), state->border+state->pad.left, state->border+state->pad.top );
window_add ( state->main_window, WIDGET ( state->main_box ) );
// we need this at this point so we can get height.
rofi_view_calculate_window_and_element_width ( state );
@ -1541,7 +1537,7 @@ RofiViewState *rofi_view_create ( Mode *sw,
rofi_view_update ( state );
xcb_map_window ( xcb->connection, CacheState.main_window );
widget_queue_redraw ( WIDGET ( state->main_box ) );
widget_queue_redraw ( WIDGET ( state->main_window ) );
xcb_flush ( xcb->connection );
if ( xcb->sncontext != NULL ) {
sn_launchee_context_complete ( xcb->sncontext );
@ -1557,11 +1553,12 @@ int rofi_view_error_dialog ( const char *msg, int markup )
state->finalize = process_result;
state->pad = (Padding){config.padding,config.padding, config.padding, config.padding, FALSE};
state->pad = rofi_theme_get_padding ( "@window", "window", NULL, "padding", state->pad);
// state->border = rofi_theme_get_integer ( "@window", "window", NULL, "padding" , config.padding );
state->border += rofi_theme_get_integer ( "@window", "window", NULL, "border-width" , config.menu_bw);
rofi_view_calculate_window_and_element_width ( state );
state->main_window = window_create ( "window" );
state->main_box = box_create ( "mainbox.box", BOX_VERTICAL);
window_add ( state->main_window, WIDGET ( state->main_box ) );
widget_move ( WIDGET ( state->main_box ), state->border+state->pad.left, state->border+state->pad.top );
state->text = textbox_create ( "message", ( TB_AUTOHEIGHT | TB_WRAP ) + ( ( markup ) ? TB_MARKUP : 0 ),
NORMAL, ( msg != NULL ) ? msg : "" );
@ -1579,7 +1576,7 @@ int rofi_view_error_dialog ( const char *msg, int markup )
// Display it.
xcb_map_window ( xcb->connection, CacheState.main_window );
widget_queue_redraw ( WIDGET ( state->main_box ) );
widget_queue_redraw ( WIDGET ( state->main_window ) );
if ( xcb->sncontext != NULL ) {
sn_launchee_context_complete ( xcb->sncontext );

View file

@ -75,7 +75,10 @@ static void vert_calculate_size ( box *b )
}
int rem_width = b->widget.w - b->widget.pad.left-b->widget.pad.right;
int rem_height = b->widget.h - b->widget.pad.top-b->widget.pad.bottom;
b->max_size += MAX ( 0, ( ( active_widgets - 1 ) * b->spacing ) );
if ( active_widgets > 0 ){
b->max_size += ( active_widgets - 1 ) * b->spacing;
}
printf("%d %d\n", rem_height, b->max_size);
if ( b->max_size > rem_height ) {
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Widgets to large (height) for box: %d %d", b->max_size, b->widget.h );
return;
@ -107,6 +110,7 @@ static void vert_calculate_size ( box *b )
}
rem -= expanding_widgets_size;
index++;
b->max_size += widget_padding_get_padding_height ( child);
}
else if ( child->end ) {
bottom -= widget_get_height ( child );
@ -122,6 +126,7 @@ static void vert_calculate_size ( box *b )
}
}
}
b->max_size += b->widget.pad.top+b->widget.pad.bottom;
}
static void hori_calculate_size ( box *b )
{
@ -175,6 +180,7 @@ static void hori_calculate_size ( box *b )
}
rem -= expanding_widgets_size;
index++;
b->max_size += widget_padding_get_padding_width ( child);
}
else if ( child->end ) {
right -= widget_get_width ( child );
@ -190,6 +196,7 @@ static void hori_calculate_size ( box *b )
}
}
}
b->max_size += b->widget.pad.left+b->widget.pad.right;
}
static void box_draw ( widget *wid, cairo_t *draw )

View file

@ -248,7 +248,7 @@ static void listview_resize ( widget *wid, short w, short h )
listview *lv = (listview *) wid;
lv->widget.w = MAX ( 0, w );
lv->widget.h = MAX ( 0, h );
int height = lv->widget.h - lv->widget.pad.top-lv->widget.pad.bottom;
int height = lv->widget.h - lv->widget.pad.top-lv->widget.pad.bottom;
lv->max_rows = ( lv->spacing + height ) / ( lv->element_height + lv->spacing );
lv->max_elements = lv->max_rows * lv->menu_columns;
@ -451,7 +451,7 @@ void listview_nav_page_next ( listview *lv )
unsigned int listview_get_desired_height ( listview *lv )
{
if ( lv == NULL ) {
if ( lv == NULL || lv->widget.enabled == FALSE ) {
return 0;
}
int h = lv->menu_lines;
@ -459,7 +459,7 @@ unsigned int listview_get_desired_height ( listview *lv )
h = MIN ( lv->menu_lines, lv->req_elements );
}
if ( h == 0 ) {
return 0;
return lv->widget.pad.top+lv->widget.pad.bottom;
}
return h * lv->element_height + ( h - 1 ) * lv->spacing+lv->widget.pad.top+lv->widget.pad.bottom;
}

View file

@ -207,3 +207,61 @@ void widget_set_name ( widget *wid, const char *name )
}
wid->name = g_strdup ( name );
}
int widget_padding_get_left ( const widget *wid )
{
if ( wid->pad.left < 0 ){
return (wid->w*-wid->pad.left)/100;
}
return wid->pad.left;
}
int widget_padding_get_right ( const widget *wid )
{
if ( wid->pad.right < 0 ){
return (wid->w*-wid->pad.right)/100;
}
return wid->pad.right;
}
int widget_padding_get_top ( const widget *wid )
{
if ( wid->pad.top < 0 ){
return (wid->h*-wid->pad.top)/100;
}
return wid->pad.top;
}
int widget_padding_get_bottom ( const widget *wid )
{
if ( wid->pad.bottom < 0 ){
return (wid->h*-wid->pad.bottom)/100;
}
return wid->pad.bottom;
}
int widget_padding_get_remaining_width ( const widget *wid )
{
int width = wid->w;
width -= widget_padding_get_left ( wid );
width -= widget_padding_get_right ( wid );
return width;
}
int widget_padding_get_remaining_height ( const widget *wid )
{
int height = wid->h;
height -= widget_padding_get_top ( wid );
height -= widget_padding_get_bottom ( wid );
return height;
}
int widget_padding_get_padding_height ( const widget *wid )
{
int height = 0;
height += widget_padding_get_top ( wid );
height += widget_padding_get_bottom ( wid );
return height;
}
int widget_padding_get_padding_width ( const widget *wid )
{
int width = 0;
width += widget_padding_get_left ( wid );
width += widget_padding_get_right ( wid );
return width;
}

160
source/widgets/window.c Normal file
View file

@ -0,0 +1,160 @@
/**
* rofi
*
* MIT/X11 License
* Modified 2016 Qball Cow <qball@gmpclient.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <config.h>
#include <stdio.h>
#include "widgets/widget.h"
#include "widgets/widget-internal.h"
#include "widgets/window.h"
#include "theme.h"
#include "settings.h"
#define LOG_DOMAIN "Widgets.Window"
const char *WINDOW_CLASS_NAME = "@window";
/**
* @param window Handle to the window widget.
* @param spacing The spacing to apply.
*
* Set the spacing to apply between the children in pixels.
*/
void window_set_spacing ( window * window, unsigned int spacing );
struct _window
{
widget widget;
widget *child;
int border_width;
};
static void window_update ( widget *wid );
static void window_draw ( widget *wid, cairo_t *draw )
{
window *b = (window *) wid;
cairo_save ( draw );
rofi_theme_get_color ( "@window", "window" , NULL, "foreground", draw );
cairo_set_line_width ( draw, b->border_width );
cairo_rectangle ( draw,
b->border_width / 2.0,
b->border_width / 2.0,
wid->w - b->border_width,
wid->h - b->border_width );
cairo_stroke ( draw );
cairo_restore ( draw );
widget_draw ( b->child, draw );
}
static void window_free ( widget *wid )
{
window *b = (window *) wid;
widget_free ( b->child );
g_free ( b );
}
void window_add ( window *window, widget *child )
{
if ( window == NULL ) {
return;
}
window->child = child;
child->parent = WIDGET ( window );
widget_update ( WIDGET ( window ) );
}
static void window_resize ( widget *widget, short w, short h )
{
window *b = (window *) widget;
if ( b->widget.w != w || b->widget.h != h ) {
b->widget.w = w;
b->widget.h = h;
widget_update ( widget );
}
}
static gboolean window_clicked ( widget *wid, xcb_button_press_event_t *xbe, G_GNUC_UNUSED void *udata )
{
window *b = (window *) wid;
if ( widget_intersect ( b->child, xbe->event_x, xbe->event_y ) ) {
xcb_button_press_event_t rel = *xbe;
rel.event_x -= b->child->x;
rel.event_y -= b->child->y;
return widget_clicked ( b->child, &rel );
}
return FALSE;
}
static gboolean window_motion_notify ( widget *wid, xcb_motion_notify_event_t *xme )
{
window *b = (window *) wid;
if ( widget_intersect ( b->child, xme->event_x, xme->event_y ) ) {
xcb_motion_notify_event_t rel = *xme;
rel.event_x -= b->child->x;
rel.event_y -= b->child->y;
return widget_motion_notify ( b->child, &rel );
}
return FALSE;
}
window * window_create ( const char *name )
{
window *b = g_malloc0 ( sizeof ( window ) );
// Initialize widget.
widget_init ( WIDGET(b), name, WINDOW_CLASS_NAME);
b->widget.draw = window_draw;
b->widget.free = window_free;
b->widget.resize = window_resize;
b->widget.update = window_update;
b->widget.clicked = window_clicked;
b->widget.motion_notify = window_motion_notify;
b->widget.enabled = TRUE;
b->border_width = rofi_theme_get_integer (
b->widget.class_name, b->widget.name, NULL, "border-width" , config.menu_bw);
return b;
}
static void window_update ( widget *wid )
{
window *b = (window *) wid;
if ( b->child && b->child->enabled ){
widget_resize ( WIDGET ( b->child ),
widget_padding_get_remaining_width (WIDGET(b))-2*b->border_width,
widget_padding_get_remaining_height (WIDGET(b))-2*b->border_width
);
widget_move ( WIDGET ( b->child ),
b->border_width+widget_padding_get_left (WIDGET(b)),
b->border_width+widget_padding_get_top (WIDGET(b))
);
}
}
int window_get_border_width ( const window *window )
{
return window->border_width*2;
}