Allow interface to be dynamically changed.

This commit is contained in:
Dave Davenport 2017-05-25 23:41:15 +02:00
parent e387105091
commit c23df70aeb
6 changed files with 219 additions and 93 deletions

View file

@ -118,6 +118,8 @@ typedef enum
P_POSITION,
/** Highlight */
P_HIGHLIGHT,
/** List */
P_LIST,
} PropertyType;
/**
@ -156,18 +158,8 @@ typedef struct
/** Color */
ThemeColor color;
} ThemeHighlight;
/**
* Property structure.
*/
typedef struct Property
{
/** Name of property */
char *name;
/** Type of property. */
PropertyType type;
/** Value */
union
{
typedef union {
/** integer */
int i;
/** Double */
@ -190,7 +182,21 @@ typedef struct Property
} link;
/** Highlight Style */
ThemeHighlight highlight;
} value;
/** List */
GList *list;
} PropertyValue;
/**
* Property structure.
*/
typedef struct Property
{
/** Name of property */
char *name;
/** Type of property. */
PropertyType type;
/** Value */
PropertyValue value;
} Property;
/**
* ThemeWidget.
@ -445,6 +451,7 @@ ThemeWidget *rofi_theme_find_widget ( const char *name, const char *state, gbool
*/
Property *rofi_theme_find_property ( ThemeWidget *widget, PropertyType type, const char *property, gboolean exact );
GList *rofi_theme_get_list ( const widget *widget, const char * property, const char *defaults);
/**
* Checks if a theme is set, or is empty.
* @returns TRUE when empty.

View file

@ -211,6 +211,9 @@ S_T_PARENT_RIGHT \)
COMMA ,
FORWARD_SLASH \/
LIST_OPEN \[
LIST_CLOSE \]
LS_DASH "dash"
LS_SOLID "solid"
@ -220,6 +223,7 @@ CONFIGURATION "configuration"
%x INCLUDE
%x PROPERTIES
%x PROPERTIES_LIST
%x NAMESTR
%x SECTION
%x DEFAULTS
@ -382,7 +386,7 @@ if ( queue == NULL ){
/* After Namestr/Classstr we want to go to state str, then to { */
<INITIAL,SECTION>{WHITESPACE}+ ; // ignore all whitespace
<PROPERTIES>{WHITESPACE}+ ; // ignore all whitespace
<PROPERTIES,PROPERTIES_LIST>{WHITESPACE}+ ; // ignore all whitespace
<SECTION>":" { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(PROPERTIES); return T_PSEP; }
<PROPERTIES>";" { BEGIN(GPOINTER_TO_INT ( g_queue_pop_head ( queue ))); return T_PCLOSE;}
@ -448,7 +452,16 @@ if ( queue == NULL ){
/* Fluff */
<PROPERTIES>{S_T_PARENT_LEFT} { return T_PARENT_LEFT; }
<PROPERTIES>{S_T_PARENT_RIGHT} { return T_PARENT_RIGHT; }
<PROPERTIES>{COMMA} { return T_COMMA; }
<PROPERTIES,PROPERTIES_LIST>{COMMA} { return T_COMMA; }
<PROPERTIES>{LIST_OPEN} {
g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );
BEGIN(PROPERTIES_LIST);
return T_LIST_OPEN;
}
<PROPERTIES_LIST>{LIST_CLOSE} {
BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue )));
return T_LIST_CLOSE;
}
<PROPERTIES>{FORWARD_SLASH} { return T_FORWARD_SLASH; }
/* Position */
<PROPERTIES>{CENTER} { return T_POS_CENTER; }
@ -521,7 +534,12 @@ if ( queue == NULL ){
<SECTION>. {
return T_ERROR_SECTION;
}
<PROPERTIES>. {
<PROPERTIES_LIST>{WORD} {
yylval->sval = g_strdup(yytext);
return T_ELEMENT;
}
<PROPERTIES,PROPERTIES_LIST>. {
return T_ERROR_PROPERTY;
}
<NAMESTR>. {

View file

@ -141,7 +141,7 @@ static ThemeColor hwb_to_rgb ( double h, double w, double b)
WindowLocation wloc;
ThemeColor colorval;
ThemeWidget *theme;
GList *name_path;
GList *list;
Property *property;
GHashTable *property_list;
Distance distance;
@ -163,6 +163,7 @@ static ThemeColor hwb_to_rgb ( double h, double w, double b)
%token <bval> T_BOOLEAN "Boolean value (true or false)"
%token <colorval> T_COLOR "Hexidecimal color value"
%token <sval> T_LINK "Reference"
%token <sval> T_ELEMENT "Name of element"
%token T_POS_CENTER "Center"
%token T_POS_EAST "East"
%token T_POS_WEST "West"
@ -198,6 +199,8 @@ static ThemeColor hwb_to_rgb ( double h, double w, double b)
%token T_OPTIONAL_COMMA "Optional comma separator (',')"
%token T_FORWARD_SLASH "forward slash ('/')"
%token T_PERCENT "Percent sign ('%')"
%token T_LIST_OPEN "List open ('[')"
%token T_LIST_CLOSE "List close (']')"
%token T_BOPEN "bracket open ('{')"
%token T_BCLOSE "bracket close ('}')"
@ -213,7 +216,7 @@ static ThemeColor hwb_to_rgb ( double h, double w, double b)
%type <sval> t_entry
%type <theme> t_entry_list
%type <name_path> t_entry_name_path
%type <list> t_entry_name_path
%type <property> t_property
%type <property_list> t_property_list
%type <property_list> t_property_list_optional
@ -232,6 +235,7 @@ static ThemeColor hwb_to_rgb ( double h, double w, double b)
%type <ival> t_property_highlight_styles
%type <ival> t_property_highlight_style
%type <ival> t_property_line_style
%type <list> t_property_element_list
%start t_entry_list
%%
@ -363,6 +367,19 @@ t_property
$$->name = $1;
$$->value.color = $3;
}
| t_property_name T_PSEP T_LIST_OPEN t_property_element_list T_LIST_CLOSE T_PCLOSE {
$$ = rofi_theme_property_create ( P_LIST );
$$->name = $1;
$$->value.list = $4;
}
;
/** List of elements */
t_property_element_list
: T_ELEMENT { $$ = g_list_append ( NULL, $1); }
| t_property_element_list T_COMMA T_ELEMENT {
$$ = g_list_append ( $1, $3 );
}
;
/**

View file

@ -591,6 +591,28 @@ Padding rofi_theme_get_padding ( const widget *widget, const char *property, Pad
g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property );
return pad;
}
GList *rofi_theme_get_list ( const widget *widget, const char * property, const char *defaults )
{
ThemeWidget *wid2 = rofi_theme_find_widget ( widget->name, widget->state, FALSE );
Property *p = rofi_theme_find_property ( wid2, P_LIST, property, TRUE);
if ( p ) {
if ( p->type == P_LIST ){
return g_list_copy_deep ( p->value.list, g_strdup, NULL );
}
}
char **r = defaults?g_strsplit (defaults, ",",0):NULL;
if ( r ){
GList *l = NULL;
for ( int i =0; r[i] != NULL; i++){
l = g_list_append(l, r[i]);
}
g_free(r);
return l;
}
return NULL;
}
ThemeHighlight rofi_theme_get_highlight ( widget *widget, const char *property, ThemeHighlight th )
{
ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, FALSE );

View file

@ -1578,6 +1578,121 @@ static void rofi_view_listview_mouse_activated_cb ( listview *lv, xcb_button_pre
state->skip_absorb = TRUE;
}
static void rofi_view_add_widget ( RofiViewState *state, widget *parent_widget, const char *parent, const char *name )
{
char *defaults = NULL;
widget *wid = NULL;
char *str= g_strjoin ( "." , parent, name, NULL );
char *strbox= g_strjoin ( "." , str, "box",NULL );
/**
* MAINBOX
*/
if ( strcmp ( name, "mainbox") == 0 ){
state->main_box = box_create ( strbox, BOX_VERTICAL );
container_add ( (container *)parent_widget, WIDGET ( state->main_box ) );
wid = WIDGET ( state->main_box );
defaults = "inputbar,message,listview";
}
/**
* INPUTBAR
*/
else if ( strcmp ( name, "inputbar" ) == 0 ){
state->input_bar = box_create ( strbox, BOX_HORIZONTAL );
wid = WIDGET( state->input_bar );
defaults = "prompt,entry,case-indicator";
box_add ( (box *)parent_widget, WIDGET ( state->input_bar ), FALSE, 0 );
}
/**
* PROMPT
*/
else if ( strcmp ( name, "prompt" ) == 0 ){
// Prompt box.
state->prompt = textbox_create ( str, TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "" );
rofi_view_update_prompt ( state );
box_add ( (box *)parent_widget, WIDGET ( state->prompt ), FALSE, 1 );
defaults = NULL;
}
/**
* CASE INDICATOR
*/
else if ( strcmp ( name, "case-indicator") == 0 ){
state->case_indicator = textbox_create ( str, TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "*" );
// Add small separator between case indicator and text box.
box_add ( (box *)parent_widget, WIDGET ( state->case_indicator ), FALSE, 3 );
textbox_text ( state->case_indicator, get_matching_state () );
}
/**
* ENTRY BOX
*/
else if ( strcmp ( name, "entry" ) == 0 ){
// Entry box
TextboxFlags tfl = TB_EDITABLE;
tfl |= ( ( state->menu_flags & MENU_PASSWORD ) == MENU_PASSWORD ) ? TB_PASSWORD : 0;
state->text = textbox_create ( str, tfl | TB_AUTOHEIGHT, NORMAL, NULL);
box_add ( (box*)parent_widget, WIDGET ( state->text ), TRUE, 2 );
}
/**
* MESSAGE
*/
else if ( strcmp ( name, "message") == 0 ){
char *strmsg= g_strjoin ( "." , str, "textbox",NULL );
state->mesg_box = container_create ( strbox );
state->mesg_tb = textbox_create ( strmsg, TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP, NORMAL, NULL );
container_add ( state->mesg_box, WIDGET ( state->mesg_tb ) );
rofi_view_reload_message_bar ( state );
box_add ( (box*)parent_widget, WIDGET ( state->mesg_box ), FALSE, 2 );
g_free(strmsg);
}
/**
* LISTVIEW
*/
else if ( strcmp ( name, "listview" ) == 0 ) {
state->list_view = listview_create ( str, update_callback, state, config.element_height, 0);
box_add ( (box*)parent_widget, WIDGET ( state->list_view ), TRUE, 3 );
// Set configuration
listview_set_multi_select ( state->list_view, ( state->menu_flags & MENU_INDICATOR ) == MENU_INDICATOR );
listview_set_scroll_type ( state->list_view, config.scroll_method );
listview_set_mouse_activated_cb ( state->list_view, rofi_view_listview_mouse_activated_cb, state );
int lines = rofi_theme_get_integer ( WIDGET ( state->list_view ), "lines", config.menu_lines );
listview_set_num_lines ( state->list_view, lines );
listview_set_max_lines ( state->list_view, state->num_lines );
}
/**
* SIDEBAR
*/
else if ( strcmp( name, "sidebar" ) == 0 ) {
state->sidebar_bar = box_create ( strbox, BOX_HORIZONTAL );
box_add ( (box*)parent_widget, WIDGET ( state->sidebar_bar ), FALSE, 10 );
state->num_modi = rofi_get_num_enabled_modi ();
state->modi = g_malloc0 ( state->num_modi * sizeof ( textbox * ) );
char *strbutton= g_strjoin ( "." , str, "button",NULL );
for ( unsigned int j = 0; j < state->num_modi; j++ ) {
const Mode * mode = rofi_get_mode ( j );
state->modi[j] = textbox_create ( strbutton, TB_CENTER | TB_AUTOHEIGHT, ( mode == state->sw ) ? HIGHLIGHT : NORMAL,
mode_get_display_name ( mode ) );
box_add ( state->sidebar_bar, WIDGET ( state->modi[j] ), TRUE, j );
widget_set_clicked_handler ( WIDGET ( state->modi[j] ), rofi_view_modi_clicked_cb, state );
}
g_free(strbutton);
}
else {
g_error("The widget %s does not exists. Invalid layout.", name);
}
if ( wid ) {
GList *list = rofi_theme_get_list ( wid, "children",defaults);
for ( const GList *iter = list; iter != NULL; iter = g_list_next ( iter )){
rofi_view_add_widget ( state, wid, str, (const char *)iter->data );
}
g_list_free_full ( list, g_free );
}
g_free(strbox);
g_free(str);
}
RofiViewState *rofi_view_create ( Mode *sw,
const char *input,
MenuFlags menu_flags,
@ -1605,77 +1720,24 @@ RofiViewState *rofi_view_create ( Mode *sw,
// Get active monitor size.
TICK_N ( "Get active monitor" );
state->main_window = container_create ( "window.box" );
state->main_box = box_create ( "window.mainbox.box", BOX_VERTICAL );
container_add ( state->main_window, WIDGET ( state->main_box ) );
// Get children.
GList *list = rofi_theme_get_list ( WIDGET(state->main_window), "children", "mainbox");
for ( const GList *iter = list; iter != NULL; iter = g_list_next ( iter )){
rofi_view_add_widget ( state, WIDGET(state->main_window), "window", (const char *)iter->data );
state->input_bar = box_create ( "window.mainbox.inputbar.box", BOX_HORIZONTAL );
// Only enable widget when sidebar is enabled.
if ( config.sidebar_mode ) {
state->sidebar_bar = box_create ( "window.mainbox.sidebar.box", BOX_HORIZONTAL );
box_add ( state->main_box, WIDGET ( state->sidebar_bar ), FALSE, 10 );
state->num_modi = rofi_get_num_enabled_modi ();
state->modi = g_malloc0 ( state->num_modi * sizeof ( textbox * ) );
for ( unsigned int j = 0; j < state->num_modi; j++ ) {
const Mode * mode = rofi_get_mode ( j );
state->modi[j] = textbox_create ( "window.mainbox.sidebar.button", TB_CENTER | TB_AUTOHEIGHT, ( mode == state->sw ) ? HIGHLIGHT : NORMAL,
mode_get_display_name ( mode ) );
box_add ( state->sidebar_bar, WIDGET ( state->modi[j] ), TRUE, j );
widget_set_clicked_handler ( WIDGET ( state->modi[j] ), rofi_view_modi_clicked_cb, state );
}
g_list_free_full ( list, g_free );
if ( state->text && input) {
textbox_text ( state->text, input );
}
int location = rofi_theme_get_position ( WIDGET ( state->main_window ), "location", config.location );
int end = ( location == WL_SOUTH_EAST || location == WL_SOUTH || location == WL_SOUTH_WEST );
box_add ( state->main_box, WIDGET ( state->input_bar ), FALSE, end ? 9 : 0 );
state->case_indicator = textbox_create ( "window.mainbox.inputbar.case-indicator", TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "*" );
// Add small separator between case indicator and text box.
box_add ( state->input_bar, WIDGET ( state->case_indicator ), FALSE, 3 );
// Prompt box.
state->prompt = textbox_create ( "window.mainbox.inputbar.prompt", TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "" );
rofi_view_update_prompt ( state );
box_add ( state->input_bar, WIDGET ( state->prompt ), FALSE, 1 );
// Entry box
TextboxFlags tfl = TB_EDITABLE;
tfl |= ( ( menu_flags & MENU_PASSWORD ) == MENU_PASSWORD ) ? TB_PASSWORD : 0;
state->text = textbox_create ( "window.mainbox.inputbar.entry", tfl | TB_AUTOHEIGHT, NORMAL, input );
box_add ( state->input_bar, WIDGET ( state->text ), TRUE, 2 );
textbox_text ( state->case_indicator, get_matching_state () );
state->mesg_box = container_create ( "window.mainbox.message.box" );
state->mesg_tb = textbox_create ( "window.mainbox.message.textbox", TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP, NORMAL, NULL );
container_add ( state->mesg_box, WIDGET ( state->mesg_tb ) );
rofi_view_reload_message_bar ( state );
box_add ( state->main_box, WIDGET ( state->mesg_box ), FALSE, end ? 8 : 2 );
state->overlay = textbox_create ( "window.overlay", TB_AUTOWIDTH | TB_AUTOHEIGHT, URGENT, "blaat" );
state->overlay->widget.parent = WIDGET ( state->main_window );
widget_disable ( WIDGET ( state->overlay ) );
state->list_view = listview_create ( "window.mainbox.listview", update_callback, state, config.element_height, end );
// Set configuration
listview_set_multi_select ( state->list_view, ( state->menu_flags & MENU_INDICATOR ) == MENU_INDICATOR );
listview_set_scroll_type ( state->list_view, config.scroll_method );
listview_set_mouse_activated_cb ( state->list_view, rofi_view_listview_mouse_activated_cb, state );
int lines = rofi_theme_get_integer ( WIDGET ( state->list_view ), "lines", config.menu_lines );
listview_set_num_lines ( state->list_view, lines );
listview_set_max_lines ( state->list_view, state->num_lines );
if ( rofi_theme_get_boolean ( WIDGET ( state->main_window ), "listview-in-inputbar", FALSE)){
box_add ( state->input_bar, WIDGET ( state->list_view ), TRUE, 3 );
Distance d = rofi_theme_get_distance_exact ( WIDGET ( state->text ) , "width", 150);
state->text->widget.expand = FALSE;
widget_resize ( WIDGET( state->text ), distance_get_pixel ( d, ORIENTATION_HORIZONTAL ), -1);
} else {
box_add ( state->main_box, WIDGET ( state->list_view ), TRUE, 3 );
}
// filtered list
state->line_map = g_malloc0_n ( state->num_lines, sizeof ( unsigned int ) );

View file

@ -263,7 +263,7 @@ void box_add ( box *box, widget *child, gboolean expand, int index )
child->index = rofi_theme_get_integer_exact ( child, "index", index );
child->parent = WIDGET ( box );
box->children = g_list_append ( box->children, (void *) child );
box->children = g_list_sort ( box->children, box_sort_children );
//box->children = g_list_sort ( box->children, box_sort_children );
widget_update ( WIDGET ( box ) );
}