* [Issue 949] Add initial split of listview row into widget tree.

Allowing better themeing.

* Remove unneeded code from textbox. allow dis. icons.

* Fix typo.

* Fix wrong widget offset in textbox.

* Fix mouse handling

* [ListView] Add 'fixed-columns' boolean option.

* [Listview] Fix inversion of option.

* [ListView] remove commented old code.

* [Textbox] Handle null pointer on desired width.

* [Listview] Fix crasher with fixed_columns and more max elements requested items.

* Add hack to get backwards compatibility for new listview structure.

* Fix the scrollbar test.

* Fix tests for theme update..
This commit is contained in:
Dave Davenport 2019-08-08 20:02:20 +02:00 committed by GitHub
parent d9eb9f25a1
commit 618d1396ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 305 additions and 226 deletions

View File

@ -2,63 +2,39 @@
* rofi -dump-theme output.
**/
* {
selected-normal-foreground: var(lightbg);
foreground: rgba ( 0, 43, 54, 100 % );
normal-foreground: var(foreground);
alternate-normal-background: var(lightbg);
red: rgba ( 220, 50, 47, 100 % );
selected-urgent-foreground: var(background);
blue: rgba ( 38, 139, 210, 100 % );
selected-active-foreground: var(background);
lightfg: rgba ( 88, 104, 117, 100 % );
separatorcolor: var(foreground);
urgent-foreground: var(red);
alternate-urgent-background: var(lightbg);
active-foreground: var(blue);
lightbg: rgba ( 238, 232, 213, 100 % );
selected-active-foreground: var(background);
alternate-active-background: var(lightbg);
background: rgba ( 253, 246, 227, 100 % );
alternate-normal-foreground: var(foreground);
normal-background: var(background);
lightfg: rgba ( 88, 104, 117, 100 % );
selected-normal-background: var(lightfg);
border-color: var(foreground);
spacing: 2;
separatorcolor: var(foreground);
urgent-background: var(background);
selected-urgent-background: var(red);
alternate-urgent-foreground: var(red);
background-color: rgba ( 0, 0, 0, 0 % );
alternate-active-foreground: var(blue);
active-background: var(background);
border-color: var(foreground);
normal-background: var(background);
selected-urgent-background: var(red);
alternate-active-background: var(lightbg);
spacing: 2;
blue: rgba ( 38, 139, 210, 100 % );
alternate-normal-foreground: var(foreground);
urgent-background: var(background);
selected-normal-foreground: var(lightbg);
active-foreground: var(blue);
background: rgba ( 253, 246, 227, 100 % );
selected-active-background: var(blue);
}
window {
background-color: var(background);
border: 1;
padding: 5;
}
mainbox {
border: 0;
padding: 0;
}
message {
border: 2px dash 0px 0px ;
border-color: var(separatorcolor);
padding: 1px ;
}
textbox {
text-color: var(foreground);
}
listview {
fixed-height: 0;
border: 2px dash 0px 0px ;
border-color: var(separatorcolor);
spacing: 2px ;
scrollbar: true;
padding: 2px 0px 0px ;
active-background: var(background);
selected-normal-background: var(lightfg);
alternate-normal-background: var(lightbg);
foreground: rgba ( 0, 43, 54, 100 % );
selected-urgent-foreground: var(background);
normal-foreground: var(foreground);
alternate-urgent-foreground: var(red);
alternate-active-foreground: var(blue);
}
element {
border: 0;
padding: 1px ;
spacing: 5px ;
border: 0;
}
element normal.normal {
background-color: var(normal-background);
@ -96,16 +72,24 @@ element alternate.active {
background-color: var(alternate-active-background);
text-color: var(alternate-active-foreground);
}
element-text {
background-color: rgba ( 0, 0, 0, 0 % );
text-color: inherit;
}
element-icon {
background-color: rgba ( 0, 0, 0, 0 % );
text-color: inherit;
}
scrollbar {
width: 4px ;
padding: 0;
handle-width: 8px ;
border: 0;
handle-color: var(normal-foreground);
handle-width: 8px ;
padding: 0;
}
mode-switcher {
border: 2px dash 0px 0px ;
border-color: var(separatorcolor);
border: 2px dash 0px 0px ;
}
button {
spacing: 0;
@ -116,9 +100,9 @@ button selected {
text-color: var(selected-normal-foreground);
}
inputbar {
padding: 1px ;
spacing: 0px ;
text-color: var(normal-foreground);
padding: 1px ;
children: [ prompt,textbox-prompt-colon,entry,overlay,case-indicator ];
}
case-indicator {
@ -134,12 +118,23 @@ prompt {
text-color: var(normal-foreground);
}
textbox-prompt-colon {
margin: 0px 0.3000em 0.0000em 0.0000em ;
expand: false;
str: ":";
margin: 0px 0.3000em 0.0000em 0.0000em ;
text-color: inherit;
}
error-message {
background-color: rgba ( 0, 0, 0, 0 % );
text-color: var(normal-foreground);
}
window {
padding: 5;
border: 1;
}
listview {
scrollbar: true;
spacing: 2px ;
}
message {
padding: 1px ;
}

View File

@ -2,63 +2,39 @@
* rofi -dump-theme output.
**/
* {
selected-normal-foreground: rgba ( 2, 20, 63, 100 % );
foreground: rgba ( 219, 223, 188, 100 % );
normal-foreground: var(foreground);
alternate-normal-background: rgba ( 0, 0, 0, 0 % );
red: rgba ( 220, 50, 47, 100 % );
selected-urgent-foreground: rgba ( 2, 20, 63, 100 % );
blue: rgba ( 38, 139, 210, 100 % );
selected-active-foreground: rgba ( 2, 20, 63, 100 % );
lightfg: rgba ( 88, 104, 117, 100 % );
separatorcolor: rgba ( 219, 223, 188, 100 % );
urgent-foreground: rgba ( 255, 129, 255, 100 % );
alternate-urgent-background: rgba ( 0, 0, 0, 0 % );
active-foreground: rgba ( 138, 196, 255, 100 % );
lightbg: rgba ( 238, 232, 213, 100 % );
selected-active-foreground: rgba ( 2, 20, 63, 100 % );
alternate-active-background: rgba ( 0, 0, 0, 0 % );
background: rgba ( 0, 0, 33, 87 % );
alternate-normal-foreground: var(foreground);
normal-background: rgba ( 0, 0, 0, 0 % );
lightfg: rgba ( 88, 104, 117, 100 % );
selected-normal-background: rgba ( 219, 223, 188, 100 % );
border-color: rgba ( 219, 223, 188, 100 % );
spacing: 2;
separatorcolor: rgba ( 219, 223, 188, 100 % );
urgent-background: rgba ( 0, 0, 0, 0 % );
selected-urgent-background: rgba ( 255, 129, 127, 100 % );
alternate-urgent-foreground: var(urgent-foreground);
background-color: rgba ( 0, 0, 0, 0 % );
alternate-active-foreground: var(active-foreground);
active-background: rgba ( 0, 0, 0, 0 % );
border-color: rgba ( 219, 223, 188, 100 % );
normal-background: rgba ( 0, 0, 0, 0 % );
selected-urgent-background: rgba ( 255, 129, 127, 100 % );
alternate-active-background: rgba ( 0, 0, 0, 0 % );
spacing: 2;
blue: rgba ( 38, 139, 210, 100 % );
alternate-normal-foreground: var(foreground);
urgent-background: rgba ( 0, 0, 0, 0 % );
selected-normal-foreground: rgba ( 2, 20, 63, 100 % );
active-foreground: rgba ( 138, 196, 255, 100 % );
background: rgba ( 0, 0, 33, 87 % );
selected-active-background: rgba ( 138, 196, 255, 100 % );
}
window {
background-color: var(background);
border: 1;
padding: 5;
}
mainbox {
border: 0;
padding: 0;
}
message {
border: 2px 0px 0px ;
border-color: var(separatorcolor);
padding: 1px ;
}
textbox {
text-color: var(foreground);
}
listview {
fixed-height: 0;
border: 2px 0px 0px ;
border-color: var(separatorcolor);
spacing: 2px ;
scrollbar: true;
padding: 2px 0px 0px ;
active-background: rgba ( 0, 0, 0, 0 % );
selected-normal-background: rgba ( 219, 223, 188, 100 % );
alternate-normal-background: rgba ( 0, 0, 0, 0 % );
foreground: rgba ( 219, 223, 188, 100 % );
selected-urgent-foreground: rgba ( 2, 20, 63, 100 % );
normal-foreground: var(foreground);
alternate-urgent-foreground: var(urgent-foreground);
alternate-active-foreground: var(active-foreground);
}
element {
border: 0;
padding: 1px ;
spacing: 5px ;
border: 0;
}
element normal.normal {
background-color: var(normal-background);
@ -96,16 +72,24 @@ element alternate.active {
background-color: var(alternate-active-background);
text-color: var(alternate-active-foreground);
}
element-text {
background-color: rgba ( 0, 0, 0, 0 % );
text-color: inherit;
}
element-icon {
background-color: rgba ( 0, 0, 0, 0 % );
text-color: inherit;
}
scrollbar {
width: 4px ;
padding: 0;
handle-width: 8px ;
border: 0;
handle-color: var(normal-foreground);
handle-width: 8px ;
padding: 0;
}
mode-switcher {
border: 2px 0px 0px ;
border-color: var(separatorcolor);
border: 2px 0px 0px ;
}
button {
spacing: 0;
@ -116,9 +100,9 @@ button selected {
text-color: var(selected-normal-foreground);
}
inputbar {
padding: 1px ;
spacing: 0px ;
text-color: var(normal-foreground);
padding: 1px ;
children: [ prompt,textbox-prompt-colon,entry,overlay,case-indicator ];
}
case-indicator {
@ -134,12 +118,25 @@ prompt {
text-color: var(normal-foreground);
}
textbox-prompt-colon {
margin: 0px 0.3000em 0.0000em 0.0000em ;
expand: false;
str: ":";
margin: 0px 0.3000em 0.0000em 0.0000em ;
text-color: inherit;
}
error-message {
background-color: rgba ( 0, 0, 0, 0 % );
text-color: var(normal-foreground);
}
window {
padding: 5;
border: 1;
}
listview {
scrollbar: true;
spacing: 2px ;
border: 2px 0px 0px ;
}
message {
padding: 1px ;
border: 2px 0px 0px ;
}

View File

@ -30,9 +30,9 @@
#include "widgets/container.h"
#include "widgets/widget.h"
#include "widgets/textbox.h"
#include "widgets/listview.h"
#include "widgets/box.h"
#include "widgets/icon.h"
#include "widgets/listview.h"
#include "keyb.h"
#include "xcb.h"
#include "theme.h"

View File

@ -61,7 +61,7 @@ typedef enum
*
* Update callback, this is called to set the value of each (visible) element.
*/
typedef void ( *listview_update_callback )( textbox *tb, unsigned int entry, void *udata, TextBoxFontType type, gboolean full );
typedef void ( *listview_update_callback )( textbox *tb,icon *ico, unsigned int entry, void *udata, TextBoxFontType *type, gboolean full );
/**
* Callback when a element is activated.

View File

@ -58,9 +58,6 @@ typedef struct
int markup;
int changed;
cairo_surface_t *icon; // AA TODO - pass in icons for a textbox line if needed
int icon_index;
int blink;
guint blink_timeout;
@ -69,7 +66,6 @@ typedef struct
PangoFontMetrics *metrics;
PangoEllipsizeMode emode;
int left_offset;
//
const char *theme_name;
} textbox;
@ -86,7 +82,6 @@ typedef enum
TB_WRAP = 1 << 21,
TB_PASSWORD = 1 << 22,
TB_INDICATOR = 1 << 23,
TB_ICON = 1 << 24,
} TextboxFlags;
/**
* Flags indicating current state of the textbox.
@ -147,14 +142,6 @@ void textbox_font ( textbox *tb, TextBoxFontType tbft );
*/
void textbox_text ( textbox *tb, const char *text );
/**
* @param tb Handle to the textbox
* @param icon The icon to show on the textbox
*
* Set the text to show. Cursor is moved to end (if visible)
*/
void textbox_icon ( textbox *tb, cairo_surface_t *icon );
/**
* @param tb Handle to the textbox
* @param action the #KeyBindingAction to execute on textbox
@ -297,14 +284,6 @@ void textbox_set_pango_context ( const char *font, PangoContext *p );
*/
void textbox_set_pango_attributes ( textbox *tb, PangoAttrList *list );
/**
* @param tb Handle to the textbox
* @param index character index to draw the icon at. -1 for no icon
*
* Sets the character index where the icon should be drawn
*/
void textbox_set_icon_index ( textbox *tb, int index );
/**
* @param tb Handle to the textbox
*

View File

@ -142,6 +142,15 @@ void widget_move ( widget *widget, short x, short y );
*/
WidgetType widget_type ( widget *widget );
/**
* @param widget Handle to widget
* @param type The widget type.
*
* Set the widget type.
*/
void widget_set_type ( widget *widget, WidgetType type );
/**
* @param widget Handle to widget
*

View File

@ -124,11 +124,54 @@ void rofi_theme_property_free ( Property *p )
g_slice_free ( Property, p );
}
/**
* This function is a hack to insert backward support for older theme with the updated listvie structure.
*/
static void rofi_theme_insert_listview_backwards_fix ( void )
{
GHashTable *table= g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, (GDestroyNotify) rofi_theme_property_free );
ThemeWidget *t = rofi_theme_find_or_create_name ( rofi_theme, "element" );
ThemeWidget *tt = rofi_theme_find_or_create_name ( rofi_theme, "element-text" );
ThemeWidget *ti = rofi_theme_find_or_create_name ( rofi_theme, "element-icon" );
// Inherit text color
Property *ptc = rofi_theme_property_create ( P_INHERIT );
ptc->name = g_strdup("text-color");
g_hash_table_replace ( table, ptc->name, ptc );
// Transparent background
Property *ptb = rofi_theme_property_create ( P_COLOR );
ptb->name = g_strdup("background-color");
ptb->value.color.red = 0.0;
ptb->value.color.green = 0.0;
ptb->value.color.blue = 0.0;
ptb->value.color.alpha = 0.0;
g_hash_table_replace ( table, ptb->name, ptb );
rofi_theme_widget_add_properties ( tt, table);
rofi_theme_widget_add_properties ( ti, table);
/** Add spacing between icon and text. */
g_hash_table_destroy ( table );
table= g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, (GDestroyNotify) rofi_theme_property_free );
Property *psp = rofi_theme_property_create ( P_PADDING );
psp->name = g_strdup( "spacing" );
RofiDistance d = (RofiDistance){5, ROFI_PU_PX, ROFI_HL_SOLID };
psp->value.padding = (RofiPadding){d,d,d,d};
g_hash_table_replace ( table, psp->name, psp );
rofi_theme_widget_add_properties ( t, table);
g_hash_table_destroy ( table );
}
void rofi_theme_reset ( void )
{
rofi_theme_free ( rofi_theme );
rofi_theme = g_slice_new0 ( ThemeWidget );
rofi_theme->name = g_strdup ( "Root" );
// Hack to fix backwards compatibility.
rofi_theme_insert_listview_backwards_fix ( );
}
void rofi_theme_free ( ThemeWidget *widget )

View File

@ -928,15 +928,16 @@ inline static void rofi_view_nav_last ( RofiViewState * state )
listview_set_selected ( state->list_view, -1 );
}
static void update_callback ( textbox *t, unsigned int index, void *udata, TextBoxFontType type, gboolean full )
static void update_callback ( textbox *t,icon *ico, unsigned int index, void *udata, TextBoxFontType *type, gboolean full )
{
RofiViewState *state = (RofiViewState *) udata;
if ( full ) {
GList *add_list = NULL;
int fstate = 0;
char *text = mode_get_display_value ( state->sw, state->line_map[index], &fstate, &add_list, TRUE );
type |= fstate;
textbox_font ( t, type );
(*type) |= fstate;
// TODO needed for markup.
textbox_font ( t, *type );
// Move into list view.
textbox_text ( t, text );
PangoAttrList *list = textbox_get_pango_attributes ( t );
@ -946,10 +947,11 @@ static void update_callback ( textbox *t, unsigned int index, void *udata, TextB
else{
list = pango_attr_list_new ();
}
int icon_height = textbox_get_font_height ( t );
cairo_surface_t *icon = mode_get_icon ( state->sw, state->line_map[index], icon_height );
textbox_icon ( t, icon );
if( ico ) {
int icon_height = widget_get_desired_height( WIDGET(ico) );
cairo_surface_t *icon = mode_get_icon ( state->sw, state->line_map[index], icon_height );
icon_set_surface ( ico, icon );
}
if ( state->tokens && config.show_match ) {
RofiHighlightColorStyle th = { ROFI_HL_BOLD | ROFI_HL_UNDERLINE, { 0.0, 0.0, 0.0, 0.0 } };
@ -967,8 +969,9 @@ static void update_callback ( textbox *t, unsigned int index, void *udata, TextB
else {
int fstate = 0;
mode_get_display_value ( state->sw, state->line_map[index], &fstate, NULL, FALSE );
type |= fstate;
textbox_font ( t, type );
(*type) |= fstate;
// TODO needed for markup.
textbox_font ( t, *type );
}
}

View File

@ -107,10 +107,6 @@ static int box_get_desired_height ( widget *wid )
continue;
}
active_widgets++;
if ( child->expand == TRUE ) {
height += widget_get_desired_height ( child );
continue;
}
height += widget_get_desired_height ( child );
}
if ( active_widgets > 0 ) {

View File

@ -29,8 +29,10 @@
#include <glib.h>
#include <widgets/widget.h>
#include <widgets/textbox.h>
#include <widgets/listview.h>
#include <widgets/scrollbar.h>
#include <widgets/icon.h>
#include <widgets/box.h>
#include <widgets/listview.h>
#include "settings.h"
#include "theme.h"
@ -58,6 +60,12 @@ typedef enum
RIGHT_TO_LEFT = 1
} MoveDirection;
typedef struct {
box *box;
textbox *textbox;
icon *icon;
} _listview_row;
struct _listview
{
widget widget;
@ -78,6 +86,7 @@ struct _listview
unsigned int max_elements;
//
gboolean fixed_columns;
unsigned int cur_columns;
unsigned int req_elements;
unsigned int cur_elements;
@ -95,7 +104,7 @@ struct _listview
ScrollType scroll_type;
textbox **boxes;
_listview_row * boxes;
scrollbar *scrollbar;
listview_update_callback callback;
@ -119,13 +128,79 @@ struct _listview
} barview;
};
const char *const listview_theme_prop_names[][3] = {
/** Normal row */
{ "normal.normal", "selected.normal", "alternate.normal" },
/** Urgent row */
{ "normal.urgent", "selected.urgent", "alternate.urgent" },
/** Active row */
{ "normal.active", "selected.active", "alternate.active" },
};
static void listview_set_style ( widget *w, TextBoxFontType tbft )
{
TextBoxFontType t = tbft & STATE_MASK;
if ( w == NULL ) {
return;
}
// ACTIVE has priority over URGENT if both set.
if ( t == ( URGENT | ACTIVE ) ) {
t = ACTIVE;
}
switch ( ( tbft & FMOD_MASK ) )
{
case HIGHLIGHT:
widget_set_state ( w, listview_theme_prop_names[t][1] );
break;
case ALT:
widget_set_state ( w, listview_theme_prop_names[t][2] );
break;
default:
widget_set_state ( w, listview_theme_prop_names[t][0] );
break;
}
}
static void listview_create_row ( listview *lv, _listview_row *row )
{
TextboxFlags flags = ( lv->multi_select ) ? TB_INDICATOR : 0;
row->box = box_create ( WIDGET ( lv ), "element",ROFI_ORIENTATION_HORIZONTAL );
widget_set_type ( WIDGET(row->box), WIDGET_TYPE_LISTVIEW_ELEMENT);
GList *list = rofi_theme_get_list ( WIDGET(row->box), "children", "element-icon,element-text");
row->textbox = NULL;
row->icon = NULL;
for ( GList *iter = g_list_first(list); iter != NULL;iter = g_list_next(iter)){
if ( strcasecmp((char *)iter->data, "element-icon") == 0 ) {
if ( config.show_icons ) {
row->icon = icon_create ( WIDGET ( row->box ), "element-icon" );
box_add ( row->box, WIDGET ( row->icon ), FALSE);
}
} else if ( strcasecmp ((char *)iter->data, "element-text") == 0 ){
row->textbox= textbox_create ( WIDGET ( row->box ), WIDGET_TYPE_TEXTBOX_TEXT, "element-text", TB_AUTOHEIGHT|flags, NORMAL, "DDD", 0, 0 );
box_add ( row->box, WIDGET ( row->textbox ), TRUE);
}
}
g_list_free_full ( list, g_free );
}
static void listview_set_state ( _listview_row r, TextBoxFontType type )
{
listview_set_style ( WIDGET(r.box), type);
listview_set_style ( WIDGET(r.textbox), type);
if ( r.icon ) {
listview_set_style ( WIDGET(r.icon), type);
}
widget_queue_redraw ( WIDGET( r.box ) );
}
static int listview_get_desired_height ( widget *wid );
static void listview_free ( widget *wid )
{
listview *lv = (listview *) wid;
for ( unsigned int i = 0; i < lv->cur_elements; i++ ) {
widget_free ( WIDGET ( lv->boxes [i] ) );
widget_free ( WIDGET ( lv->boxes [i].box ) );
}
g_free ( lv->boxes );
@ -200,7 +275,8 @@ static void update_element ( listview *lv, unsigned int tb, unsigned int index,
type = ( index ) == lv->selected ? HIGHLIGHT : type;
if ( lv->callback ) {
lv->callback ( lv->boxes[tb], index, lv->udata, type, full );
lv->callback ( lv->boxes[tb].textbox, lv->boxes[tb].icon, index, lv->udata, &type, full );
listview_set_state ( lv->boxes[tb], type);
}
}
@ -226,16 +302,17 @@ static void barview_draw ( widget *wid, cairo_t *draw )
if ( lv->barview.direction == LEFT_TO_RIGHT ) {
for ( unsigned int i = 0; i < max && width > 0; i++ ) {
update_element ( lv, i, i + offset, TRUE );
int twidth = textbox_get_desired_width ( WIDGET ( lv->boxes[i] ) );
int twidth = textbox_get_desired_width ( WIDGET ( lv->boxes[i].textbox ) );
if ( twidth >= width ) {
if ( !first ) {
break;
}
twidth = width;
}
textbox_moveresize ( lv->boxes[i], left_offset, top_offset, twidth, lv->element_height );
widget_move ( WIDGET(lv->boxes[i].box), left_offset, top_offset);
widget_resize ( WIDGET (lv->boxes[i].box), twidth, lv->element_height);
widget_draw ( WIDGET ( lv->boxes[i] ), draw );
widget_draw ( WIDGET ( lv->boxes[i].box ), draw );
width -= twidth + spacing_hori;
left_offset += twidth + spacing_hori;
first = FALSE;
@ -245,7 +322,7 @@ static void barview_draw ( widget *wid, cairo_t *draw )
else {
for ( unsigned int i = 0; i < lv->cur_elements && width > 0 && i <= offset; i++ ) {
update_element ( lv, i, offset - i, TRUE );
int twidth = textbox_get_desired_width ( WIDGET ( lv->boxes[i] ) );
int twidth = textbox_get_desired_width ( WIDGET ( lv->boxes[i].textbox ) );
if ( twidth >= width ) {
if ( !first ) {
break;
@ -253,9 +330,10 @@ static void barview_draw ( widget *wid, cairo_t *draw )
twidth = width;
}
right_offset -= twidth;
textbox_moveresize ( lv->boxes[i], right_offset, top_offset, twidth, lv->element_height );
widget_move ( WIDGET(lv->boxes[i].box), left_offset, top_offset);
widget_resize ( WIDGET (lv->boxes[i].box), twidth, lv->element_height);
widget_draw ( WIDGET ( lv->boxes[i] ), draw );
widget_draw ( WIDGET ( lv->boxes[i].box ), draw );
width -= twidth + spacing_hori;
right_offset -= spacing_hori;
first = FALSE;
@ -264,7 +342,7 @@ static void barview_draw ( widget *wid, cairo_t *draw )
offset -= lv->barview.cur_visible - 1;
lv->last_offset = offset;
for ( unsigned int i = 0; i < ( lv->barview.cur_visible / 2 ); i++ ) {
void * temp = lv->boxes[i];
_listview_row temp = lv->boxes[i];
int sw = lv->barview.cur_visible - i - 1;
lv->boxes[i] = lv->boxes[sw];
lv->boxes[sw] = temp;
@ -275,7 +353,7 @@ static void barview_draw ( widget *wid, cairo_t *draw )
else {
for ( unsigned int i = 0; i < lv->barview.cur_visible; i++ ) {
update_element ( lv, i, i + offset, FALSE );
widget_draw ( WIDGET ( lv->boxes[i] ), draw );
widget_draw ( WIDGET ( lv->boxes[i].box ), draw );
}
}
}
@ -326,22 +404,24 @@ static void listview_draw ( widget *wid, cairo_t *draw )
unsigned int ex = left_offset + ( ( i ) / lv->max_rows ) * ( element_width + spacing_hori );
if ( lv->reverse ) {
unsigned int ey = wid->h - ( widget_padding_get_bottom ( wid ) + ( ( i ) % lv->max_rows ) * ( lv->element_height + spacing_vert ) ) - lv->element_height;
textbox_moveresize ( lv->boxes[i], ex, ey, element_width, lv->element_height );
widget_move ( WIDGET(lv->boxes[i].box), ex, ey);
widget_resize ( WIDGET (lv->boxes[i].box), element_width, lv->element_height);
}
else {
unsigned int ey = top_offset + ( ( i ) % lv->max_rows ) * ( lv->element_height + spacing_vert );
textbox_moveresize ( lv->boxes[i], ex, ey, element_width, lv->element_height );
widget_move ( WIDGET(lv->boxes[i].box), ex, ey);
widget_resize ( WIDGET (lv->boxes[i].box), element_width, lv->element_height);
}
update_element ( lv, i, i + offset, TRUE );
widget_draw ( WIDGET ( lv->boxes[i] ), draw );
widget_draw ( WIDGET ( lv->boxes[i].box ), draw );
}
lv->rchanged = FALSE;
}
else {
for ( unsigned int i = 0; i < max; i++ ) {
update_element ( lv, i, i + offset, FALSE );
widget_draw ( WIDGET ( lv->boxes[i] ), draw );
widget_draw ( WIDGET ( lv->boxes[i].box ), draw );
}
}
}
@ -359,30 +439,32 @@ static void _listview_draw ( widget *wid, cairo_t *draw )
barview_draw ( wid, draw );
}
}
/**
* State names used for theming.
*/
static void listview_recompute_elements ( listview *lv )
{
unsigned int newne = 0;
if ( lv->max_rows == 0 ) {
return;
}
if ( lv->req_elements < lv->max_elements ) {
if ( !(lv->fixed_columns) && lv->req_elements < lv->max_elements ) {
newne = lv->req_elements;
lv->cur_columns = ( lv->req_elements + ( lv->max_rows - 1 ) ) / lv->max_rows;
}
else {
newne = lv->max_elements;
newne = MIN( lv->req_elements, lv->max_elements);
lv->cur_columns = lv->menu_columns;
}
for ( unsigned int i = newne; i < lv->cur_elements; i++ ) {
widget_free ( WIDGET ( lv->boxes[i] ) );
widget_free ( WIDGET ( lv->boxes[i].box ) );
}
lv->boxes = g_realloc ( lv->boxes, newne * sizeof ( textbox* ) );
lv->boxes = g_realloc ( lv->boxes, newne * sizeof ( _listview_row ) );
if ( newne > 0 ) {
for ( unsigned int i = lv->cur_elements; i < newne; i++ ) {
TextboxFlags flags = ( lv->multi_select ) ? TB_INDICATOR : 0;
flags |= ( ( config.show_icons ) ? TB_ICON : 0 );
lv->boxes[i] = textbox_create ( WIDGET ( lv ), WIDGET_TYPE_LISTVIEW_ELEMENT, "element", flags, NORMAL, "", 0, 0 );
widget_set_trigger_action_handler ( WIDGET ( lv->boxes[i] ), listview_element_trigger_action, lv );
listview_create_row ( lv, &(lv->boxes[i]) );
widget_set_trigger_action_handler ( WIDGET ( lv->boxes[i].box ), listview_element_trigger_action, lv );
listview_set_state ( lv->boxes[i], NORMAL);
}
}
lv->rchanged = TRUE;
@ -461,7 +543,7 @@ static widget *listview_find_mouse_target ( widget *wid, WidgetType type, gint x
unsigned int max = MIN ( lv->cur_elements, lv->req_elements - lv->last_offset );
unsigned int i;
for ( i = 0; i < max && target == NULL; i++ ) {
widget *w = WIDGET ( lv->boxes[i] );
widget *w = WIDGET ( lv->boxes[i].box );
if ( widget_intersect ( w, x, y ) ) {
rx = x - widget_get_x_pos ( w );
ry = y - widget_get_y_pos ( w );
@ -498,7 +580,7 @@ static WidgetTriggerActionResult listview_element_trigger_action ( widget *wid,
listview *lv = (listview *) user_data;
unsigned int max = MIN ( lv->cur_elements, lv->req_elements - lv->last_offset );
unsigned int i;
for ( i = 0; i < max && WIDGET ( lv->boxes[i] ) != wid; i++ ) {
for ( i = 0; i < max && WIDGET ( lv->boxes[i].box) != wid; i++ ) {
}
if ( i == max ) {
return WIDGET_TRIGGER_ACTION_RESULT_IGNORED;
@ -538,9 +620,10 @@ listview *listview_create ( widget *parent, const char *name, listview_update_ca
lv->scrollbar = scrollbar_create ( WIDGET ( lv ), "scrollbar" );
// Calculate height of an element.
//
textbox *tb = textbox_create ( WIDGET ( lv ), WIDGET_TYPE_LISTVIEW_ELEMENT, "element", 0, NORMAL, "", 0, 0 );
lv->element_height = textbox_get_estimated_height ( tb, lv->eh );
widget_free ( WIDGET ( tb ) );
_listview_row row;
listview_create_row ( lv, &row);
lv->element_height = widget_get_desired_height ( WIDGET(row.box) );
widget_free ( WIDGET ( row.box ) );
lv->callback = cb;
lv->udata = udata;
@ -552,6 +635,7 @@ listview *listview_create ( widget *parent, const char *name, listview_update_ca
lv->dynamic = rofi_theme_get_boolean ( WIDGET ( lv ), "dynamic", TRUE );
lv->reverse = rofi_theme_get_boolean ( WIDGET ( lv ), "reverse", reverse );
lv->cycle = rofi_theme_get_boolean ( WIDGET ( lv ), "cycle", config.cycle );
lv->fixed_columns = rofi_theme_get_boolean ( WIDGET ( lv ), "fixed-columns", FALSE );
lv->type = rofi_theme_get_orientation ( WIDGET ( lv ), "layout", ROFI_ORIENTATION_VERTICAL );
if ( lv->type == LISTVIEW ) {
@ -847,7 +931,7 @@ void listview_toggle_ellipsizing ( listview *lv )
}
lv->emode = mode;
for ( unsigned int i = 0; i < lv->cur_elements; i++ ) {
textbox_set_ellipsize ( lv->boxes[i], mode );
textbox_set_ellipsize ( lv->boxes[i].textbox, mode );
}
}
}

View File

@ -29,6 +29,7 @@
#include <xkbcommon/xkbcommon.h>
#include <glib.h>
#include "widgets/textbox.h"
#include "widgets/icon.h"
#include "widgets/listview.h"
#include "widgets/scrollbar.h"

View File

@ -135,7 +135,6 @@ static void textbox_initialize_font ( textbox *tb )
{
tb->metrics = p_metrics;
const char * font = rofi_theme_get_string ( WIDGET ( tb ), "font", NULL );
tb->left_offset = textbox_get_estimated_char_height ();
if ( font ) {
TBFontConfig *tbfc = g_hash_table_lookup ( tbfc_cache, font );
if ( tbfc == NULL ) {
@ -158,7 +157,6 @@ static void textbox_initialize_font ( textbox *tb )
// Update for used font.
pango_layout_set_font_description ( tb->layout, tbfc->pfd );
tb->metrics = tbfc->metrics;
tb->left_offset = ( tbfc->height ) / (double) PANGO_SCALE;
}
}
}
@ -186,10 +184,6 @@ textbox* textbox_create ( widget *parent, WidgetType type, const char *name, Tex
textbox_initialize_font ( tb );
if ( ( tb->flags & TB_ICON ) != TB_ICON ) {
tb->left_offset = 0;
}
if ( ( flags & TB_WRAP ) == TB_WRAP ) {
pango_layout_set_wrap ( tb->layout, PANGO_WRAP_WORD_CHAR );
}
@ -334,25 +328,11 @@ void textbox_text ( textbox *tb, const char *text )
widget_queue_redraw ( WIDGET ( tb ) );
}
void textbox_icon ( textbox *tb, cairo_surface_t *icon )
{
// Add our reference to the surface.
if ( icon != NULL ) {
cairo_surface_reference ( icon );
}
if ( tb->icon ) {
// If we overwrite an old one, destroy the reference we hold.
cairo_surface_destroy ( tb->icon );
}
tb->icon = icon;
widget_queue_redraw ( WIDGET ( tb ) );
}
// within the parent handled auto width/height modes
void textbox_moveresize ( textbox *tb, int x, int y, int w, int h )
{
unsigned int offset = tb->left_offset * 1.2 + ( ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0 );
unsigned int offset = ( ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0 );
if ( tb->flags & TB_AUTOWIDTH ) {
pango_layout_set_width ( tb->layout, -1 );
w = textbox_get_font_width ( tb ) + widget_padding_get_padding_width ( WIDGET ( tb ) ) + offset;
@ -402,10 +382,6 @@ static void textbox_free ( widget *wid )
}
g_free ( tb->text );
if ( tb->icon ) {
cairo_surface_destroy ( tb->icon );
tb->icon = NULL;
}
if ( tb->layout != NULL ) {
g_object_unref ( tb->layout );
}
@ -419,7 +395,7 @@ static void textbox_draw ( widget *wid, cairo_t *draw )
return;
}
textbox *tb = (textbox *) wid;
unsigned int offset = tb->left_offset * 1.2 + ( ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0 );
unsigned int offset = ( ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0 );
if ( tb->changed ) {
__textbox_update_pango_text ( tb );
@ -439,21 +415,6 @@ static void textbox_draw ( widget *wid, cairo_t *draw )
}
y += top;
// draw Icon
if ( ( tb->flags & TB_ICON ) == TB_ICON && tb->icon != NULL ) {
int iconheight = tb->left_offset;
cairo_save ( draw );
int iconh = cairo_image_surface_get_height ( tb->icon );
int iconw = cairo_image_surface_get_width ( tb->icon );
int icons = MAX ( iconh, iconw );
double scale = (double) iconheight / icons;
cairo_translate ( draw, x + ( iconheight - iconw * scale ) / 2.0, y + ( iconheight - iconh * scale ) / 2.0 );
cairo_scale ( draw, scale, scale );
cairo_set_source_surface ( draw, tb->icon, 0, 0 );
cairo_paint ( draw );
cairo_restore ( draw );
}
x += offset;
if ( tb->xalign > 0.001 ) {
@ -488,7 +449,7 @@ static void textbox_draw ( widget *wid, cairo_t *draw )
pango_cairo_show_layout ( draw, tb->layout );
if ( ( tb->flags & TB_INDICATOR ) == TB_INDICATOR && ( tb->tbft & ( SELECTED ) ) ) {
cairo_arc ( draw, tb->left_offset * 1.2 + DOT_OFFSET / 2.0, tb->widget.h / 2.0, 2.0, 0, 2.0 * M_PI );
cairo_arc ( draw, DOT_OFFSET / 2.0, tb->widget.h / 2.0, 2.0, 0, 2.0 * M_PI );
cairo_fill ( draw );
}
}
@ -934,8 +895,11 @@ int textbox_get_estimated_height ( const textbox *tb, int eh )
}
int textbox_get_desired_width ( widget *wid )
{
if ( wid == NULL ) {
return 0;
}
textbox *tb = (textbox *) wid;
unsigned int offset = tb->left_offset * 1.2 + ( ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0 );
unsigned int offset = ( ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0 );
if ( wid->expand && tb->flags & TB_AUTOWIDTH ) {
return textbox_get_font_width ( tb ) + widget_padding_get_padding_width ( wid ) + offset;
}

View File

@ -104,6 +104,13 @@ void widget_move ( widget *widget, short x, short y )
widget->y = y;
}
}
void widget_set_type ( widget *widget, WidgetType type )
{
if ( widget == NULL ) {
return ;
}
widget->type = type;
}
WidgetType widget_type ( widget *widget )
{

View File

@ -34,6 +34,7 @@
#include <string.h>
#include <widgets/scrollbar.h>
#include <widgets/textbox.h>
#include <widgets/icon.h>
#include <widgets/listview.h>
#include <widgets/widget.h>
#include <widgets/widget-internal.h>

View File

@ -125,7 +125,7 @@ START_TEST (test_core_empty_string )
{
rofi_theme_parse_string ( "");
ck_assert_ptr_nonnull ( rofi_theme );
ck_assert_ptr_null ( rofi_theme->widgets );
//ck_assert_ptr_null ( rofi_theme->widgets );
ck_assert_ptr_null ( rofi_theme->properties );
ck_assert_ptr_null ( rofi_theme->parent );
ck_assert_str_eq ( rofi_theme->name, "Root" );
@ -135,7 +135,7 @@ START_TEST (test_core_empty_global_section )
{
rofi_theme_parse_string ( " * {}");
ck_assert_ptr_nonnull ( rofi_theme );
ck_assert_ptr_null ( rofi_theme->widgets );
//ck_assert_ptr_null ( rofi_theme->widgets );
ck_assert_ptr_null ( rofi_theme->properties );
ck_assert_ptr_null ( rofi_theme->parent );
ck_assert_str_eq ( rofi_theme->name, "Root" );
@ -149,9 +149,9 @@ START_TEST (test_core_empty_section )
ck_assert_ptr_null ( rofi_theme->properties );
ck_assert_ptr_null ( rofi_theme->parent );
ck_assert_str_eq ( rofi_theme->name, "Root" );
ck_assert_str_eq ( rofi_theme->widgets[0]->name, "test" );
ck_assert_ptr_null ( rofi_theme->widgets[0]->properties );
ck_assert_ptr_eq ( rofi_theme->widgets[0]->parent, rofi_theme );
ck_assert_str_eq ( rofi_theme->widgets[3]->name, "test" );
ck_assert_ptr_null ( rofi_theme->widgets[3]->properties );
ck_assert_ptr_eq ( rofi_theme->widgets[3]->parent, rofi_theme );
}
END_TEST
START_TEST (test_core_error_root )
@ -159,7 +159,7 @@ START_TEST (test_core_error_root )
rofi_theme_parse_string ( "Blaat");
ck_assert_int_eq ( error, 1 );
ck_assert_ptr_nonnull ( rofi_theme );
ck_assert_ptr_null ( rofi_theme->widgets );
//ck_assert_ptr_null ( rofi_theme->widgets );
ck_assert_ptr_null ( rofi_theme->properties );
ck_assert_ptr_null ( rofi_theme->parent );
const char *error_str = "<big><b>Error while parsing theme:</b></big> <i>Blaat</i>\n"\
@ -181,7 +181,7 @@ START_TEST ( test_core_comments )
rofi_theme_parse_string ( "// Random comments\n// /*test */");
rofi_theme_parse_string ( "/* test \n*\n* /* aap */ */");
ck_assert_ptr_nonnull ( rofi_theme );
ck_assert_ptr_null ( rofi_theme->widgets );
//ck_assert_ptr_null ( rofi_theme->widgets );
ck_assert_ptr_null ( rofi_theme->properties );
ck_assert_ptr_null ( rofi_theme->parent );
ck_assert_str_eq ( rofi_theme->name, "Root" );
@ -195,7 +195,7 @@ START_TEST ( test_core_newline )
{
rofi_theme_parse_string ( "\r\n\n\r\n\n/*\r\n*/");
ck_assert_ptr_nonnull ( rofi_theme );
ck_assert_ptr_null ( rofi_theme->widgets );
//ck_assert_ptr_null ( rofi_theme->widgets );
ck_assert_ptr_null ( rofi_theme->properties );
ck_assert_ptr_null ( rofi_theme->parent );
ck_assert_str_eq ( rofi_theme->name, "Root" );
@ -210,7 +210,7 @@ START_TEST(test_properties_boolean)
/** Boolean property */
rofi_theme_parse_string ( "*{ test: true; test2:/* inline */false; }");
ck_assert_ptr_nonnull ( rofi_theme );
ck_assert_ptr_null ( rofi_theme->widgets );
//ck_assert_ptr_null ( rofi_theme->widgets );
ck_assert_ptr_nonnull ( rofi_theme->properties );
ck_assert_ptr_null ( rofi_theme->parent );
ck_assert_int_eq( rofi_theme_get_boolean ( &wid, "test", FALSE), TRUE );
@ -1146,7 +1146,7 @@ START_TEST ( test_parse_file_empty )
{
rofi_theme_parse_file ("/dev/null");
ck_assert_ptr_nonnull ( rofi_theme );
ck_assert_ptr_null ( rofi_theme->widgets );
//ck_assert_ptr_null ( rofi_theme->widgets );
ck_assert_ptr_null ( rofi_theme->properties );
ck_assert_ptr_null ( rofi_theme->parent );
ck_assert_str_eq ( rofi_theme->name, "Root" );
@ -1168,7 +1168,7 @@ START_TEST ( test_import_empty)
{
rofi_theme_parse_string("@import \"/dev/null\"");
ck_assert_ptr_nonnull ( rofi_theme );
ck_assert_ptr_null ( rofi_theme->widgets );
//ck_assert_ptr_null ( rofi_theme->widgets );
ck_assert_ptr_null ( rofi_theme->properties );
ck_assert_ptr_null ( rofi_theme->parent );
ck_assert_str_eq ( rofi_theme->name, "Root" );