mirror of
https://github.com/davatorium/rofi.git
synced 2025-04-07 17:33:14 -04:00
commit
465d027c1e
5 changed files with 256 additions and 91 deletions
10
Makefile.am
10
Makefile.am
|
@ -30,6 +30,7 @@ rofi_SOURCES=\
|
|||
source/rofi.c\
|
||||
source/i3-support.c\
|
||||
source/textbox.c\
|
||||
source/scrollbar.c\
|
||||
source/xrmoptions.c\
|
||||
source/history.c\
|
||||
config/config.c\
|
||||
|
@ -47,6 +48,7 @@ rofi_SOURCES=\
|
|||
include/xrmoptions.h\
|
||||
include/history.h\
|
||||
include/textbox.h\
|
||||
include/scrollbar.h\
|
||||
include/helper.h\
|
||||
include/keyb.h\
|
||||
include/x11-helper.h\
|
||||
|
@ -154,13 +156,21 @@ test: ${bin_PROGRAMS}
|
|||
|
||||
.PHONY: test-x
|
||||
test-x: ${bin_PROGRAMS}
|
||||
echo "Test 1"
|
||||
$(top_srcdir)/test/run_test.sh 123 $(top_builddir)/textbox_test $(top_builddir) $(top_srcdir)/doc/example.xresources
|
||||
echo "Test 2"
|
||||
$(top_srcdir)/test/run_test.sh 200 $(top_srcdir)/test/run_errormsg_test.sh $(top_builddir) $(top_srcdir)/doc/example.xresources
|
||||
echo "Test 3"
|
||||
$(top_srcdir)/test/run_test.sh 201 $(top_srcdir)/test/run_switchdialog_test.sh $(top_builddir) $(top_srcdir)/doc/example.xresources
|
||||
echo "Test 4"
|
||||
$(top_srcdir)/test/run_test.sh 202 $(top_srcdir)/test/run_dmenu_test.sh $(top_builddir) $(top_srcdir)/doc/example.xresources
|
||||
echo "Test 5"
|
||||
$(top_srcdir)/test/run_test.sh 203 $(top_srcdir)/test/run_dmenu_custom_test.sh $(top_builddir) $(top_srcdir)/doc/example.xresources
|
||||
echo "Test 6"
|
||||
$(top_srcdir)/test/run_test.sh 204 $(top_srcdir)/test/run_run_test.sh $(top_builddir) $(top_srcdir)/doc/example.xresources
|
||||
echo "Test 7"
|
||||
$(top_srcdir)/test/run_test.sh 205 $(top_srcdir)/test/run_script_test.sh $(top_builddir) $(top_srcdir)/doc/example.xresources
|
||||
echo "End tests"
|
||||
|
||||
|
||||
.PHONY: indent
|
||||
|
|
93
include/scrollbar.h
Normal file
93
include/scrollbar.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
#ifndef ROFI_SCROLLBAR_H
|
||||
#define ROFI_SCROLLBAR_H
|
||||
|
||||
/**
|
||||
* Internal structure for the scrollbar.
|
||||
*/
|
||||
typedef struct _scrollbar
|
||||
{
|
||||
Window window, parent;
|
||||
short x, y, w, h;
|
||||
GC gc;
|
||||
unsigned int length;
|
||||
unsigned int pos;
|
||||
unsigned int pos_length;
|
||||
} scrollbar;
|
||||
|
||||
/**
|
||||
* @param parent the parent window
|
||||
* @param vinfo The XVisualInfo to use when creating new window
|
||||
* @param map The colormap to use for new window
|
||||
* @param x The x coordinate (relative to parent) to position the new scrollbar
|
||||
* @param y The y coordinate (relative to parent) to position the new scrollbar
|
||||
* @param w The width of the scrollbar
|
||||
* @param h The height of the scrollbar
|
||||
*
|
||||
* Create a new scrollbar
|
||||
*
|
||||
* @returns the scrollbar object.
|
||||
*/
|
||||
scrollbar *scrollbar_create ( Window parent, XVisualInfo *vinfo, Colormap map,
|
||||
short x, short y, short w, short h );
|
||||
|
||||
/**
|
||||
* @param sb scrollbar object
|
||||
*
|
||||
* Hide (unmap) the scrollbar.
|
||||
*/
|
||||
void scrollbar_hide ( scrollbar *sb );
|
||||
|
||||
/**
|
||||
* @param sb scrollbar object
|
||||
*
|
||||
* Show (map) the scrollbar.
|
||||
*/
|
||||
void scrollbar_show ( scrollbar *sb );
|
||||
|
||||
/**
|
||||
* @param sb scrollbar object
|
||||
*
|
||||
* Free the resources used by the scrollbar.
|
||||
*/
|
||||
void scrollbar_free ( scrollbar *sb );
|
||||
|
||||
/**
|
||||
* @param sb scrollbar object
|
||||
* @param pos_length new length
|
||||
*
|
||||
* set the length of the handle relative to the max value of bar.
|
||||
*/
|
||||
void scrollbar_set_handle_length ( scrollbar *sb, unsigned int pos_length );
|
||||
|
||||
/**
|
||||
* @param sb scrollbar object
|
||||
* @param pos new position
|
||||
*
|
||||
* set the position of the handle relative to the set max value of bar.
|
||||
*/
|
||||
void scrollbar_set_handle ( scrollbar *sb, unsigned int pos );
|
||||
|
||||
/**
|
||||
* @param sb scrollbar object
|
||||
* @param max the new max
|
||||
*
|
||||
* set the max value of the bar.
|
||||
*/
|
||||
void scrollbar_set_max_value ( scrollbar *sb, unsigned int max );
|
||||
|
||||
/**
|
||||
* @param sb scrollbar object
|
||||
*
|
||||
* Draw the scrollbar, used after expose event or update
|
||||
*/
|
||||
void scrollbar_draw ( scrollbar *sb );
|
||||
|
||||
/**
|
||||
* @param sb scrollbar object
|
||||
* @param y clicked position
|
||||
*
|
||||
* Calculate the position of the click relative to the max value of bar
|
||||
*/
|
||||
unsigned int scrollbar_clicked ( scrollbar *sb, int y );
|
||||
|
||||
#endif // ROFI_SCROLLBAR_H
|
|
@ -1,6 +1,5 @@
|
|||
#ifndef ROFI_TEXTBOX_H
|
||||
#define ROFI_TEXTBOX_H
|
||||
#include <X11/Xft/Xft.h>
|
||||
|
||||
#include <pango/pango.h>
|
||||
#include <pango/pangoxft.h>
|
||||
|
@ -25,13 +24,13 @@ typedef struct
|
|||
|
||||
typedef enum
|
||||
{
|
||||
TB_AUTOHEIGHT = 1 << 0,
|
||||
TB_AUTOWIDTH = 1 << 1,
|
||||
TB_LEFT = 1 << 16,
|
||||
TB_RIGHT = 1 << 17,
|
||||
TB_CENTER = 1 << 18,
|
||||
TB_EDITABLE = 1 << 19,
|
||||
TB_MARKUP = 1 << 20,
|
||||
TB_AUTOHEIGHT = 1 << 0,
|
||||
TB_AUTOWIDTH = 1 << 1,
|
||||
TB_LEFT = 1 << 16,
|
||||
TB_RIGHT = 1 << 17,
|
||||
TB_CENTER = 1 << 18,
|
||||
TB_EDITABLE = 1 << 19,
|
||||
TB_MARKUP = 1 << 20,
|
||||
} TextboxFlags;
|
||||
|
||||
|
||||
|
|
102
source/rofi.c
102
source/rofi.c
|
@ -47,6 +47,7 @@
|
|||
#include "rofi.h"
|
||||
#include "helper.h"
|
||||
#include "textbox.h"
|
||||
#include "scrollbar.h"
|
||||
#include "x11-helper.h"
|
||||
#include "xrmoptions.h"
|
||||
#include "dialogs/dialogs.h"
|
||||
|
@ -128,45 +129,6 @@ static inline MainLoopEvent wait_for_xevent_or_timeout ( Display *display, int x
|
|||
return ML_XEVENT;
|
||||
}
|
||||
|
||||
static void menu_hide_arrow_text ( int filtered_lines, int selected, int max_elements,
|
||||
textbox *arrowbox_top, textbox *arrowbox_bottom )
|
||||
{
|
||||
if ( arrowbox_top == NULL || arrowbox_bottom == NULL ) {
|
||||
return;
|
||||
}
|
||||
int page = ( filtered_lines > 0 ) ? selected / max_elements : 0;
|
||||
int npages = ( filtered_lines > 0 ) ? ( ( filtered_lines + max_elements - 1 ) / max_elements ) : 1;
|
||||
if ( !( page != 0 && npages > 1 ) ) {
|
||||
textbox_hide ( arrowbox_top );
|
||||
}
|
||||
if ( !( ( npages - 1 ) != page && npages > 1 ) ) {
|
||||
textbox_hide ( arrowbox_bottom );
|
||||
}
|
||||
}
|
||||
|
||||
static void menu_set_arrow_text ( int filtered_lines, int selected, int max_elements,
|
||||
textbox *arrowbox_top, textbox *arrowbox_bottom )
|
||||
{
|
||||
if ( arrowbox_top == NULL || arrowbox_bottom == NULL ) {
|
||||
return;
|
||||
}
|
||||
if ( filtered_lines == 0 || max_elements == 0 ) {
|
||||
return;
|
||||
}
|
||||
int page = ( filtered_lines > 0 ) ? selected / max_elements : 0;
|
||||
int npages = ( filtered_lines > 0 ) ? ( ( filtered_lines + max_elements - 1 ) / max_elements ) : 1;
|
||||
int entry = selected % max_elements;
|
||||
if ( page != 0 && npages > 1 ) {
|
||||
textbox_show ( arrowbox_top );
|
||||
textbox_font ( arrowbox_top, ( entry != 0 ) ? NORMAL : HIGHLIGHT );
|
||||
textbox_draw ( arrowbox_top );
|
||||
}
|
||||
if ( ( npages - 1 ) != page && npages > 1 ) {
|
||||
textbox_show ( arrowbox_bottom );
|
||||
textbox_font ( arrowbox_bottom, ( entry != ( max_elements - 1 ) ) ? NORMAL : HIGHLIGHT );
|
||||
textbox_draw ( arrowbox_bottom );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Levenshtein Sorting.
|
||||
|
@ -287,9 +249,8 @@ typedef struct MenuState
|
|||
textbox *prompt_tb;
|
||||
textbox *message_tb;
|
||||
textbox *case_indicator;
|
||||
textbox *arrowbox_top;
|
||||
textbox *arrowbox_bottom;
|
||||
textbox **boxes;
|
||||
scrollbar *scrollbar;
|
||||
int *distance;
|
||||
int *line_map;
|
||||
|
||||
|
@ -325,8 +286,7 @@ static void menu_free_state ( MenuState *state )
|
|||
textbox_free ( state->text );
|
||||
textbox_free ( state->prompt_tb );
|
||||
textbox_free ( state->case_indicator );
|
||||
textbox_free ( state->arrowbox_bottom );
|
||||
textbox_free ( state->arrowbox_top );
|
||||
scrollbar_free ( state->scrollbar );
|
||||
|
||||
for ( unsigned int i = 0; i < state->max_elements; i++ ) {
|
||||
textbox_free ( state->boxes[i] );
|
||||
|
@ -698,25 +658,12 @@ static void menu_mouse_navigation ( MenuState *state, XButtonEvent *xbe )
|
|||
}
|
||||
return;
|
||||
}
|
||||
if ( xbe->window == state->arrowbox_top->window ) {
|
||||
// Page up.
|
||||
if ( state->selected < state->max_rows ) {
|
||||
state->selected = 0;
|
||||
}
|
||||
else{
|
||||
state->selected -= state->max_elements;
|
||||
}
|
||||
state->update = TRUE;
|
||||
}
|
||||
else if ( xbe->window == state->arrowbox_bottom->window ) {
|
||||
// Page down.
|
||||
state->selected += state->max_elements;
|
||||
if ( state->selected >= state->filtered_lines ) {
|
||||
state->selected = state->filtered_lines - 1;
|
||||
}
|
||||
state->update = TRUE;
|
||||
}
|
||||
else {
|
||||
if ( state->scrollbar && state->scrollbar->window == xbe->window ) {
|
||||
state->selected = scrollbar_clicked ( state->scrollbar, xbe->y );
|
||||
state->update = TRUE;
|
||||
return;
|
||||
}
|
||||
for ( unsigned int i = 0; config.sidebar_mode == TRUE && i < num_switchers; i++ ) {
|
||||
if ( switchers[i]->tb->window == ( xbe->window ) ) {
|
||||
*( state->selected_line ) = 0;
|
||||
|
@ -791,6 +738,7 @@ static void menu_refilter ( MenuState *state, char **lines, menu_match_cb mmc, v
|
|||
state->quit = TRUE;
|
||||
}
|
||||
|
||||
scrollbar_set_max_value ( state->scrollbar, state->filtered_lines );
|
||||
state->refilter = FALSE;
|
||||
state->rchanged = TRUE;
|
||||
}
|
||||
|
@ -815,8 +763,9 @@ static void menu_draw ( MenuState *state )
|
|||
state->cur_page = page;
|
||||
state->rchanged = TRUE;
|
||||
}
|
||||
// Set the position.
|
||||
scrollbar_set_handle ( state->scrollbar, page * state->max_elements );
|
||||
}
|
||||
|
||||
// Re calculate the boxes and sizes, see if we can move this in the menu_calc*rowscolumns
|
||||
// Get number of remaining lines to display.
|
||||
unsigned int a_lines = MIN ( ( state->filtered_lines - offset ), state->max_elements );
|
||||
|
@ -826,6 +775,9 @@ static void menu_draw ( MenuState *state )
|
|||
state->max_rows ) / state->max_rows;
|
||||
columns = MIN ( columns, state->columns );
|
||||
|
||||
// Update the handle length.
|
||||
scrollbar_set_handle_length ( state->scrollbar, columns * state->max_rows );
|
||||
scrollbar_draw ( state->scrollbar );
|
||||
// Element width.
|
||||
unsigned int element_width = state->w - ( 2 * ( config.padding ) );
|
||||
if ( columns > 0 ) {
|
||||
|
@ -879,9 +831,6 @@ static void menu_draw ( MenuState *state )
|
|||
|
||||
static void menu_update ( MenuState *state )
|
||||
{
|
||||
menu_hide_arrow_text ( state->filtered_lines, state->selected,
|
||||
state->max_elements, state->arrowbox_top,
|
||||
state->arrowbox_bottom );
|
||||
textbox_draw ( state->case_indicator );
|
||||
textbox_draw ( state->prompt_tb );
|
||||
textbox_draw ( state->text );
|
||||
|
@ -889,9 +838,6 @@ static void menu_update ( MenuState *state )
|
|||
textbox_draw ( state->message_tb );
|
||||
}
|
||||
menu_draw ( state );
|
||||
menu_set_arrow_text ( state->filtered_lines, state->selected,
|
||||
state->max_elements, state->arrowbox_top,
|
||||
state->arrowbox_bottom );
|
||||
// Why do we need the special -1?
|
||||
XDrawLine ( display, main_window, gc, 0,
|
||||
state->line_height + ( config.padding ) * 1 + config.line_margin + 1,
|
||||
|
@ -1076,22 +1022,11 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom
|
|||
x_offset, y_offset,
|
||||
state.element_width, element_height, NORMAL, "" );
|
||||
}
|
||||
// Arrows
|
||||
state.arrowbox_top = textbox_create ( main_window, &vinfo, map, TB_AUTOWIDTH,
|
||||
( config.padding ), ( config.padding ),
|
||||
0, element_height, NORMAL,
|
||||
"↑" );
|
||||
state.arrowbox_bottom = textbox_create ( main_window, &vinfo, map, TB_AUTOWIDTH,
|
||||
( config.padding ), ( config.padding ),
|
||||
0, element_height, NORMAL,
|
||||
"↓" );
|
||||
textbox_move ( state.arrowbox_top,
|
||||
state.w - config.padding - state.arrowbox_top->w,
|
||||
state.top_offset );
|
||||
textbox_move ( state.arrowbox_bottom,
|
||||
state.w - config.padding - state.arrowbox_bottom->w,
|
||||
state.top_offset + ( state.max_rows - 1 ) * ( element_height + config.line_margin ) );
|
||||
state.scrollbar = scrollbar_create ( main_window, &vinfo, map, state.w - config.padding-config.line_margin- 8, state.top_offset,
|
||||
config.line_margin+8, ( state.max_rows - 1 ) * ( element_height + config.line_margin ) + element_height );
|
||||
|
||||
|
||||
scrollbar_set_max_value ( state.scrollbar, state.num_lines );
|
||||
// filtered list
|
||||
state.line_map = g_malloc0_n ( state.num_lines, sizeof ( int ) );
|
||||
if ( config.levenshtein_sort ) {
|
||||
|
@ -1127,6 +1062,7 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom
|
|||
}
|
||||
}
|
||||
|
||||
scrollbar_show ( state.scrollbar );
|
||||
// Display it.
|
||||
XMoveResizeWindow ( display, main_window, state.x, state.y, state.w, state.h );
|
||||
XMapRaised ( display, main_window );
|
||||
|
|
127
source/scrollbar.c
Normal file
127
source/scrollbar.c
Normal file
|
@ -0,0 +1,127 @@
|
|||
/**
|
||||
* MIT/X11 License
|
||||
* Modified (c) 2015 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 <X11/X.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xmd.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xproto.h>
|
||||
#include <X11/Xft/Xft.h>
|
||||
#include <glib.h>
|
||||
#include "scrollbar.h"
|
||||
#include "rofi.h"
|
||||
#include "x11-helper.h"
|
||||
|
||||
extern Display *display;
|
||||
|
||||
scrollbar *scrollbar_create ( Window parent, XVisualInfo *vinfo, Colormap map,
|
||||
short x, short y, short w, short h )
|
||||
{
|
||||
scrollbar *sb = g_malloc0 ( sizeof ( scrollbar ) );
|
||||
|
||||
sb->parent = parent;
|
||||
sb->x = x;
|
||||
sb->y = y;
|
||||
sb->w = MAX ( 1, w );
|
||||
sb->h = MAX ( 1, h );
|
||||
|
||||
sb->length = 10;
|
||||
sb->pos = 0;
|
||||
sb->pos_length = 4;
|
||||
|
||||
XSetWindowAttributes attr;
|
||||
attr.colormap = map;
|
||||
attr.border_pixel = color_border ( display );
|
||||
attr.background_pixel = color_background ( display );
|
||||
sb->window = XCreateWindow ( display, sb->parent, sb->x, sb->y, sb->w, sb->h, 0, vinfo->depth,
|
||||
InputOutput, vinfo->visual, CWColormap | CWBorderPixel | CWBackPixel, &attr );
|
||||
|
||||
XSelectInput ( display, sb->window, ExposureMask | ButtonPressMask );
|
||||
sb->gc = XCreateGC ( display, sb->window, 0, 0 );
|
||||
XSetForeground ( display, sb->gc, color_separator ( display ) );
|
||||
//XSetFillStyle ( display, sb->gc, FillSolid);
|
||||
|
||||
// Create GC.
|
||||
return sb;
|
||||
}
|
||||
|
||||
void scrollbar_show ( scrollbar *sb )
|
||||
{
|
||||
XMapWindow ( display, sb->window );
|
||||
}
|
||||
void scrollbar_hide ( scrollbar *sb )
|
||||
{
|
||||
XUnmapWindow ( display, sb->window );
|
||||
}
|
||||
|
||||
void scrollbar_free ( scrollbar *sb )
|
||||
{
|
||||
XFreeGC ( display, sb->gc );
|
||||
XDestroyWindow ( display, sb->window );
|
||||
g_free ( sb );
|
||||
}
|
||||
|
||||
void scrollbar_set_max_value ( scrollbar *sb, unsigned int max )
|
||||
{
|
||||
sb->length = MAX ( 1, max );
|
||||
}
|
||||
|
||||
void scrollbar_set_handle ( scrollbar *sb, unsigned int pos )
|
||||
{
|
||||
sb->pos = MIN ( sb->length, MAX ( 0, pos ) );
|
||||
}
|
||||
|
||||
void scrollbar_set_handle_length ( scrollbar *sb, unsigned int pos_length )
|
||||
{
|
||||
sb->pos_length = MIN ( sb->length, MAX ( 1, pos_length ) );
|
||||
}
|
||||
|
||||
void scrollbar_draw ( scrollbar *sb )
|
||||
{
|
||||
// Calculate position and size.
|
||||
const short bh = sb->h - 0;
|
||||
float sec = ( ( bh ) / (float) sb->length );
|
||||
short height = sb->pos_length * sec;
|
||||
short y = sb->pos * sec;
|
||||
// Set max pos.
|
||||
y = MIN ( y, bh - 2 );
|
||||
// Never go out of bar.
|
||||
height = MAX ( 2, height );
|
||||
// Cap length;
|
||||
height = MIN ( bh - y + 1, ( height ) );
|
||||
// Redraw base window
|
||||
XClearWindow ( display, sb->window );
|
||||
// Paint the handle.
|
||||
XFillRectangle ( display, sb->window, sb->gc, config.line_margin, y, sb->w-config.line_margin, height );
|
||||
}
|
||||
|
||||
unsigned int scrollbar_clicked ( scrollbar *sb, int y )
|
||||
{
|
||||
const short bh = sb->h - 2;
|
||||
float sec = ( ( bh ) / (float) sb->length );
|
||||
unsigned int sel = y / sec;
|
||||
return sel;
|
||||
}
|
Loading…
Add table
Reference in a new issue