mirror of
https://github.com/davatorium/rofi.git
synced 2024-11-25 13:55:34 -05:00
Qtk widgets (#478)
* Initial support for using boxes for packing widgets. * Make CapiTalIzation more consistent * Move widgets to subdirectory * Removed nolonger needed resize function. * Small cleanup * When switching mode, reuse view, don't rebuild it. Reduces artifacts. * Needs cleaning up. * Remove separate prompt argument, use display_name * Simplify run-switcher code. * Add notion of parents, and trigger parent update on resize. * Use widget_get_height wrapper, avoid crash * Size separator width based on height. (indent) * TODO add margin to box. * First draft version of listview. * Add scrollbar to listview widget * Add padding option to box * Move access to global config out of widget. (1/2 done) * Remove printf * Make listview not access global config * Add click support, implement on mode buttons. * Re-introduce mouse handling on list-view. * TODO draggin on scrollbar. * Fix multi-select * Fix warnings * Fix include
This commit is contained in:
parent
0da0587087
commit
3c64507f02
28 changed files with 1675 additions and 928 deletions
29
Makefile.am
29
Makefile.am
|
@ -23,11 +23,14 @@ rofi_SOURCES=\
|
||||||
source/keyb.c\
|
source/keyb.c\
|
||||||
config/config.c\
|
config/config.c\
|
||||||
source/helper.c\
|
source/helper.c\
|
||||||
source/widget.c\
|
|
||||||
source/textbox.c\
|
|
||||||
source/timings.c\
|
source/timings.c\
|
||||||
source/history.c\
|
source/history.c\
|
||||||
source/scrollbar.c\
|
source/widgets/box.c\
|
||||||
|
source/widgets/widget.c\
|
||||||
|
source/widgets/textbox.c\
|
||||||
|
source/widgets/listview.c\
|
||||||
|
source/widgets/scrollbar.c\
|
||||||
|
source/widgets/separator.c\
|
||||||
source/xrmoptions.c\
|
source/xrmoptions.c\
|
||||||
source/x11-helper.c\
|
source/x11-helper.c\
|
||||||
source/dialogs/run.c\
|
source/dialogs/run.c\
|
||||||
|
@ -50,9 +53,12 @@ rofi_SOURCES=\
|
||||||
include/helper.h\
|
include/helper.h\
|
||||||
include/timings.h\
|
include/timings.h\
|
||||||
include/history.h\
|
include/history.h\
|
||||||
include/widget.h\
|
include/widgets/box.h\
|
||||||
include/textbox.h\
|
include/widgets/widget.h\
|
||||||
include/scrollbar.h\
|
include/widgets/textbox.h\
|
||||||
|
include/widgets/listview.h\
|
||||||
|
include/widgets/scrollbar.h\
|
||||||
|
include/widgets/separator.h\
|
||||||
include/xrmoptions.h\
|
include/xrmoptions.h\
|
||||||
include/x11-helper.h\
|
include/x11-helper.h\
|
||||||
include/dialogs/ssh.h\
|
include/dialogs/ssh.h\
|
||||||
|
@ -181,20 +187,19 @@ textbox_test_LDADD=\
|
||||||
widget_test_LDADD=$(textbox_test_LDADD)
|
widget_test_LDADD=$(textbox_test_LDADD)
|
||||||
widget_test_CFLAGS=$(textbox_test_CFLAGS)
|
widget_test_CFLAGS=$(textbox_test_CFLAGS)
|
||||||
widget_test_SOURCES=\
|
widget_test_SOURCES=\
|
||||||
source/widget.c\
|
source/widgets/widget.c\
|
||||||
test/widget-test.c
|
test/widget-test.c
|
||||||
textbox_test_SOURCES=\
|
textbox_test_SOURCES=\
|
||||||
source/widget.c\
|
source/widgets/widget.c\
|
||||||
source/textbox.c\
|
source/widgets/textbox.c\
|
||||||
config/config.c\
|
config/config.c\
|
||||||
include/keyb.h\
|
include/keyb.h\
|
||||||
include/rofi.h\
|
include/rofi.h\
|
||||||
include/mode.h\
|
include/mode.h\
|
||||||
include/mode-private.h\
|
include/mode-private.h\
|
||||||
include/settings.h\
|
include/settings.h\
|
||||||
include/widget.h\
|
include/widgets/widget.h\
|
||||||
include/textbox.h\
|
include/widgets/textbox.h\
|
||||||
include/widget.h\
|
|
||||||
include/xrmoptions.h\
|
include/xrmoptions.h\
|
||||||
include/helper.h\
|
include/helper.h\
|
||||||
test/textbox-test.c
|
test/textbox-test.c
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#ifndef ROFI_VIEW_INTERNAL_H
|
#ifndef ROFI_VIEW_INTERNAL_H
|
||||||
#define ROFI_VIEW_INTERNAL_H
|
#define ROFI_VIEW_INTERNAL_H
|
||||||
#include "widget.h"
|
#include "widgets/widget.h"
|
||||||
#include "textbox.h"
|
#include "widgets/textbox.h"
|
||||||
#include "scrollbar.h"
|
#include "widgets/separator.h"
|
||||||
|
#include "widgets/listview.h"
|
||||||
|
#include "widgets/box.h"
|
||||||
#include "keyb.h"
|
#include "keyb.h"
|
||||||
#include "x11-helper.h"
|
#include "x11-helper.h"
|
||||||
|
|
||||||
|
@ -16,27 +18,21 @@
|
||||||
struct RofiViewState
|
struct RofiViewState
|
||||||
{
|
{
|
||||||
Mode *sw;
|
Mode *sw;
|
||||||
unsigned int menu_lines;
|
|
||||||
unsigned int max_elements;
|
|
||||||
unsigned int max_rows;
|
|
||||||
unsigned int columns;
|
|
||||||
|
|
||||||
unsigned int element_width;
|
|
||||||
int top_offset;
|
|
||||||
|
|
||||||
// Update/Refilter list.
|
// Update/Refilter list.
|
||||||
int update;
|
|
||||||
int refilter;
|
int refilter;
|
||||||
int rchanged;
|
int rchanged;
|
||||||
unsigned int cur_page;
|
|
||||||
|
|
||||||
|
box *main_box;
|
||||||
// Entries
|
// Entries
|
||||||
|
box *input_bar;
|
||||||
|
separator *input_bar_separator;
|
||||||
|
|
||||||
|
textbox *prompt;
|
||||||
textbox *text;
|
textbox *text;
|
||||||
textbox *prompt_tb;
|
|
||||||
textbox *message_tb;
|
|
||||||
textbox *case_indicator;
|
textbox *case_indicator;
|
||||||
textbox **boxes;
|
|
||||||
scrollbar *scrollbar;
|
listview *list_view;
|
||||||
// Small overlay.
|
// Small overlay.
|
||||||
textbox *overlay;
|
textbox *overlay;
|
||||||
int *distance;
|
int *distance;
|
||||||
|
@ -45,7 +41,6 @@ struct RofiViewState
|
||||||
unsigned int num_lines;
|
unsigned int num_lines;
|
||||||
|
|
||||||
// Selected element.
|
// Selected element.
|
||||||
unsigned int selected;
|
|
||||||
unsigned int filtered_lines;
|
unsigned int filtered_lines;
|
||||||
// Last offset in paginating.
|
// Last offset in paginating.
|
||||||
unsigned int last_offset;
|
unsigned int last_offset;
|
||||||
|
@ -58,11 +53,11 @@ struct RofiViewState
|
||||||
// Return state
|
// Return state
|
||||||
unsigned int selected_line;
|
unsigned int selected_line;
|
||||||
MenuReturn retv;
|
MenuReturn retv;
|
||||||
int line_height;
|
|
||||||
unsigned int border;
|
unsigned int border;
|
||||||
workarea mon;
|
workarea mon;
|
||||||
|
|
||||||
// Sidebar view
|
// Sidebar view
|
||||||
|
box *sidebar_bar;
|
||||||
unsigned int num_modi;
|
unsigned int num_modi;
|
||||||
textbox **modi;
|
textbox **modi;
|
||||||
|
|
||||||
|
|
|
@ -40,9 +40,9 @@ typedef enum
|
||||||
*
|
*
|
||||||
* @returns The command issued (see MenuReturn)
|
* @returns The command issued (see MenuReturn)
|
||||||
*/
|
*/
|
||||||
RofiViewState *rofi_view_create ( Mode *sw, const char *input, char *prompt, const char *message, MenuFlags flags, void ( *finalize )(
|
RofiViewState *rofi_view_create ( Mode *sw, const char *input, const char *message, MenuFlags flags, void ( *finalize )(
|
||||||
RofiViewState * ) )
|
RofiViewState * ) )
|
||||||
__attribute__ ( ( nonnull ( 1, 2, 3, 6 ) ) );
|
__attribute__ ( ( nonnull ( 1, 2, 5 ) ) );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param state The Menu Handle
|
* @param state The Menu Handle
|
||||||
|
@ -162,5 +162,6 @@ void rofi_view_set_overlay ( RofiViewState *state, const char *text );
|
||||||
*/
|
*/
|
||||||
void rofi_view_hide ( void );
|
void rofi_view_hide ( void );
|
||||||
void rofi_view_reload ( void );
|
void rofi_view_reload ( void );
|
||||||
|
void rofi_view_switch_mode ( RofiViewState *state, Mode *mode );
|
||||||
/**@}*/
|
/**@}*/
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
#ifndef ROFI_WIDGET_H
|
|
||||||
#define ROFI_WIDGET_H
|
|
||||||
|
|
||||||
#include <cairo.h>
|
|
||||||
/**
|
|
||||||
* @defgroup Widgets Widgets
|
|
||||||
*
|
|
||||||
* Generic Widget class
|
|
||||||
*
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
typedef struct _Widget
|
|
||||||
{
|
|
||||||
/** X position relative to parent */
|
|
||||||
short x;
|
|
||||||
/** Y position relative to parent */
|
|
||||||
short y;
|
|
||||||
/** Width of the widget */
|
|
||||||
short w;
|
|
||||||
/** Height of the widget */
|
|
||||||
short h;
|
|
||||||
/** enabled or not */
|
|
||||||
gboolean enabled;
|
|
||||||
/** Function prototypes */
|
|
||||||
|
|
||||||
void ( *draw )( struct _Widget *widget, cairo_t *draw );
|
|
||||||
void ( *free )( struct _Widget *widget );
|
|
||||||
} Widget;
|
|
||||||
|
|
||||||
/** Macro to get widget from an implementation (e.g. textbox/scrollbar) */
|
|
||||||
#define WIDGET( a ) ( a != NULL ? (Widget *) ( a ) : NULL )
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param widget The widget to check
|
|
||||||
* @param x The X position relative to parent window
|
|
||||||
* @param y the Y position relative to parent window
|
|
||||||
*
|
|
||||||
* Check if x,y falls within the widget.
|
|
||||||
*
|
|
||||||
* @return TRUE if x,y falls within the widget
|
|
||||||
*/
|
|
||||||
int widget_intersect ( const Widget *widget, int x, int y );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param widget The widget to move
|
|
||||||
* @param x The new X position relative to parent window
|
|
||||||
* @param y The new Y position relative to parent window
|
|
||||||
*
|
|
||||||
* Moves the widget.
|
|
||||||
*/
|
|
||||||
void widget_move ( Widget *widget, short x, short y );
|
|
||||||
|
|
||||||
gboolean widget_enabled ( Widget *widget );
|
|
||||||
void widget_disable ( Widget *widget );
|
|
||||||
void widget_enable ( Widget *widget );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param tb Handle to the widget
|
|
||||||
* @param draw The cairo object used to draw itself.
|
|
||||||
*
|
|
||||||
* Render the textbox.
|
|
||||||
*/
|
|
||||||
void widget_draw ( Widget *widget, cairo_t *d );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param tb Handle to the widget
|
|
||||||
*
|
|
||||||
* Free the widget and all allocated memory.
|
|
||||||
*/
|
|
||||||
void widget_free ( Widget *widget );
|
|
||||||
|
|
||||||
/*@}*/
|
|
||||||
#endif // ROFI_WIDGET_H
|
|
26
include/widgets/box.h
Normal file
26
include/widgets/box.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef ROFI_HBOX_H
|
||||||
|
#define ROFI_HBOX_H
|
||||||
|
|
||||||
|
#include "widget.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup box box
|
||||||
|
* @ingroup widgets
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
typedef struct _box box;
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
BOX_HORIZONTAL,
|
||||||
|
BOX_VERTICAL
|
||||||
|
} boxType;
|
||||||
|
|
||||||
|
box * box_create ( boxType type, short x, short y, short w, short h );
|
||||||
|
|
||||||
|
void box_add ( box *box, widget *child, gboolean expand, gboolean end );
|
||||||
|
|
||||||
|
int box_get_fixed_pixels ( box *box );
|
||||||
|
void box_set_padding ( box * box, unsigned int padding );
|
||||||
|
/*@}*/
|
||||||
|
#endif // ROFI_HBOX_H
|
90
include/widgets/listview.h
Normal file
90
include/widgets/listview.h
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#ifndef ROFI_LISTVIEW_H
|
||||||
|
#define ROFI_LISTVIEW_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup listview listview
|
||||||
|
* @ingroup widgets
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _listview listview;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
LISTVIEW_SCROLL_PER_PAGE,
|
||||||
|
LISTVIEW_SCROLL_CONTINIOUS
|
||||||
|
} ScrollType;
|
||||||
|
|
||||||
|
typedef void ( *listview_update_callback )( textbox *tb, unsigned int entry, void *udata, TextBoxFontType type, gboolean full );
|
||||||
|
typedef void ( *listview_mouse_activated_cb )( listview *, xcb_button_press_event_t *, void * );
|
||||||
|
|
||||||
|
listview *listview_create ( listview_update_callback cb, void *udata, unsigned int eh );
|
||||||
|
|
||||||
|
void listview_set_num_elements ( listview *lv, unsigned int rows );
|
||||||
|
void listview_set_selected ( listview *lv, unsigned int selected );
|
||||||
|
unsigned int listview_get_selected ( listview *lv );
|
||||||
|
unsigned int listview_get_desired_height ( listview *lv );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param state The listview handle
|
||||||
|
*
|
||||||
|
* Move the selection one row up.
|
||||||
|
* - Wrap around.
|
||||||
|
*/
|
||||||
|
void listview_nav_up ( listview *lv );
|
||||||
|
/**
|
||||||
|
* @param lv listview handle.
|
||||||
|
*
|
||||||
|
* Move the selection one row down.
|
||||||
|
* - Wrap around.
|
||||||
|
*/
|
||||||
|
void listview_nav_down ( listview *lv );
|
||||||
|
/**
|
||||||
|
* @param state The listview handle
|
||||||
|
*
|
||||||
|
* Move the selection one column to the right.
|
||||||
|
* - No wrap around.
|
||||||
|
* - Do not move to top row when at start.
|
||||||
|
*/
|
||||||
|
void listview_nav_right ( listview *lv );
|
||||||
|
/**
|
||||||
|
* @param state The listview handle
|
||||||
|
*
|
||||||
|
* Move the selection one column to the left.
|
||||||
|
* - No wrap around.
|
||||||
|
*/
|
||||||
|
void listview_nav_left ( listview *lv );
|
||||||
|
/**
|
||||||
|
* @param state The listview handle
|
||||||
|
*
|
||||||
|
* Move the selection one page down.
|
||||||
|
* - No wrap around.
|
||||||
|
* - Clip at top/bottom
|
||||||
|
*/
|
||||||
|
void listview_nav_page_next ( listview *lv );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param state The current RofiViewState
|
||||||
|
*
|
||||||
|
* Move the selection one page up.
|
||||||
|
* - No wrap around.
|
||||||
|
* - Clip at top/bottom
|
||||||
|
*/
|
||||||
|
void listview_nav_page_prev ( listview *lv );
|
||||||
|
/**
|
||||||
|
* Configuration.
|
||||||
|
*/
|
||||||
|
void listview_set_padding ( listview *lv, unsigned int padding );
|
||||||
|
void listview_set_max_lines ( listview *lv, unsigned int lines );
|
||||||
|
void listview_set_max_columns ( listview *lv, unsigned int columns );
|
||||||
|
void listview_set_fixed_num_lines ( listview *lv, gboolean enabled );
|
||||||
|
void listview_set_hide_scrollbar ( listview *lv, gboolean enabled );
|
||||||
|
void listview_set_scrollbar_width ( listview *lv, unsigned int width );
|
||||||
|
void listview_set_cycle ( listview *lv, gboolean cycle );
|
||||||
|
void listview_set_scroll_type ( listview *lv, ScrollType type );
|
||||||
|
void listview_set_mouse_activated_cb ( listview *lv, listview_mouse_activated_cb cb, void *udata );
|
||||||
|
void listview_set_multi_select ( listview *lv, gboolean enable );
|
||||||
|
/* @} */
|
||||||
|
|
||||||
|
#endif // ROFI_LISTVIEW_H
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup Scrollbar Scrollbar
|
* @defgroup Scrollbar Scrollbar
|
||||||
* @ingroup Widgets
|
* @ingroup widgets
|
||||||
*
|
*
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
*/
|
*/
|
||||||
typedef struct _scrollbar
|
typedef struct _scrollbar
|
||||||
{
|
{
|
||||||
Widget widget;
|
widget widget;
|
||||||
unsigned int length;
|
unsigned int length;
|
||||||
unsigned int pos;
|
unsigned int pos;
|
||||||
unsigned int pos_length;
|
unsigned int pos_length;
|
||||||
|
@ -64,14 +64,5 @@ void scrollbar_set_max_value ( scrollbar *sb, unsigned int max );
|
||||||
*/
|
*/
|
||||||
unsigned int scrollbar_clicked ( const scrollbar *sb, int y );
|
unsigned int scrollbar_clicked ( const scrollbar *sb, int y );
|
||||||
|
|
||||||
/**
|
|
||||||
* @param sb scrollbar object
|
|
||||||
* @param w new width in pixels
|
|
||||||
* @param h new height in pixels
|
|
||||||
*
|
|
||||||
* Resize the scrollbar.
|
|
||||||
*/
|
|
||||||
void scrollbar_resize ( scrollbar *sb, int w, int h );
|
|
||||||
|
|
||||||
/*@}*/
|
/*@}*/
|
||||||
#endif // ROFI_SCROLLBAR_H
|
#endif // ROFI_SCROLLBAR_H
|
24
include/widgets/separator.h
Normal file
24
include/widgets/separator.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef ROFI_SEPARATOR_H
|
||||||
|
#define ROFI_SEPARATOR_H
|
||||||
|
#include <cairo.h>
|
||||||
|
#include "widget.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup separator separator
|
||||||
|
* @ingroup widgets
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
typedef struct _separator separator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param h The height of the separator.
|
||||||
|
*
|
||||||
|
* Create a horizontal separator with height h.
|
||||||
|
*
|
||||||
|
* @returns a new separator, free with ::widget_free
|
||||||
|
*/
|
||||||
|
separator *separator_create ( short h );
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
#endif // ROFI_SEPARATOR_H
|
|
@ -12,14 +12,13 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup Textbox Textbox
|
* @defgroup Textbox Textbox
|
||||||
* @ingroup Widgets
|
* @ingroup widgets
|
||||||
*
|
*
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
Widget widget;
|
widget widget;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
short cursor;
|
short cursor;
|
||||||
Color color_fg, color_bg;
|
Color color_fg, color_bg;
|
||||||
|
@ -146,15 +145,6 @@ void textbox_cleanup ( void );
|
||||||
*/
|
*/
|
||||||
int textbox_get_height ( const textbox *tb );
|
int textbox_get_height ( const textbox *tb );
|
||||||
|
|
||||||
/**
|
|
||||||
* @param tb Handle to the textbox
|
|
||||||
*
|
|
||||||
* Get the width of the textbox
|
|
||||||
*
|
|
||||||
* @returns the width of the textbox in pixels.
|
|
||||||
*/
|
|
||||||
int textbox_get_width ( const textbox *tb );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param tb Handle to the textbox
|
* @param tb Handle to the textbox
|
||||||
*
|
*
|
115
include/widgets/widget.h
Normal file
115
include/widgets/widget.h
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
#ifndef ROFI_WIDGET_H
|
||||||
|
#define ROFI_WIDGET_H
|
||||||
|
#include <glib.h>
|
||||||
|
#include <cairo.h>
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
#include <xcb/xproto.h>
|
||||||
|
/**
|
||||||
|
* @defgroup widgets widgets
|
||||||
|
*
|
||||||
|
* Generic widget class
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
typedef struct _widget widget;
|
||||||
|
typedef gboolean ( *widget_clicked_cb )( widget *, xcb_button_press_event_t *, void * );
|
||||||
|
struct _widget
|
||||||
|
{
|
||||||
|
/** X position relative to parent */
|
||||||
|
short x;
|
||||||
|
/** Y position relative to parent */
|
||||||
|
short y;
|
||||||
|
/** Width of the widget */
|
||||||
|
short w;
|
||||||
|
/** Height of the widget */
|
||||||
|
short h;
|
||||||
|
/** enabled or not */
|
||||||
|
gboolean enabled;
|
||||||
|
/** Information about packing. */
|
||||||
|
gboolean expand;
|
||||||
|
gboolean end;
|
||||||
|
|
||||||
|
struct _widget *parent;
|
||||||
|
/** Internal */
|
||||||
|
gboolean need_redraw;
|
||||||
|
/** Function prototypes */
|
||||||
|
int ( *get_width )( struct _widget * );
|
||||||
|
int ( *get_height )( struct _widget * );
|
||||||
|
|
||||||
|
void ( *draw )( struct _widget *widget, cairo_t *draw );
|
||||||
|
void ( *resize )( struct _widget *, short, short );
|
||||||
|
void ( *update )( struct _widget * );
|
||||||
|
|
||||||
|
// Signals.
|
||||||
|
widget_clicked_cb clicked;
|
||||||
|
void *clicked_cb_data;
|
||||||
|
|
||||||
|
// Free
|
||||||
|
void ( *free )( struct _widget *widget );
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Macro to get widget from an implementation (e.g. textbox/scrollbar) */
|
||||||
|
#define WIDGET( a ) ( ( a ) != NULL ? (widget *) ( a ) : NULL )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param widget The widget to check
|
||||||
|
* @param x The X position relative to parent window
|
||||||
|
* @param y the Y position relative to parent window
|
||||||
|
*
|
||||||
|
* Check if x,y falls within the widget.
|
||||||
|
*
|
||||||
|
* @return TRUE if x,y falls within the widget
|
||||||
|
*/
|
||||||
|
int widget_intersect ( const widget *widget, int x, int y );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param widget The widget to move
|
||||||
|
* @param x The new X position relative to parent window
|
||||||
|
* @param y The new Y position relative to parent window
|
||||||
|
*
|
||||||
|
* Moves the widget.
|
||||||
|
*/
|
||||||
|
void widget_move ( widget *widget, short x, short y );
|
||||||
|
|
||||||
|
gboolean widget_enabled ( widget *widget );
|
||||||
|
void widget_disable ( widget *widget );
|
||||||
|
void widget_enable ( widget *widget );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tb Handle to the widget
|
||||||
|
* @param draw The cairo object used to draw itself.
|
||||||
|
*
|
||||||
|
* Render the textbox.
|
||||||
|
*/
|
||||||
|
void widget_draw ( widget *widget, cairo_t *d );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tb Handle to the widget
|
||||||
|
*
|
||||||
|
* Free the widget and all allocated memory.
|
||||||
|
*/
|
||||||
|
void widget_free ( widget *widget );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param widget The widget toresize
|
||||||
|
* @param w The new width
|
||||||
|
* @param h The new height
|
||||||
|
*
|
||||||
|
* Resizes the widget.
|
||||||
|
*/
|
||||||
|
void widget_resize ( widget *widget, short w, short h );
|
||||||
|
|
||||||
|
int widget_get_height ( widget *widget );
|
||||||
|
int widget_get_width ( widget *widget );
|
||||||
|
|
||||||
|
void widget_update ( widget *widget );
|
||||||
|
void widget_queue_redraw ( widget *widget );
|
||||||
|
gboolean widget_need_redraw ( widget *wid );
|
||||||
|
|
||||||
|
gboolean widget_clicked ( widget *wid, xcb_button_press_event_t *xbe );
|
||||||
|
|
||||||
|
// Signal!
|
||||||
|
void widget_set_clicked_handler ( widget *wid, widget_clicked_cb cb, void *udata );
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
#endif // ROFI_WIDGET_H
|
|
@ -169,6 +169,9 @@ static ModeMode combi_mode_result ( Mode *sw, int mretv, char **input, unsigned
|
||||||
return MODE_EXIT;
|
return MODE_EXIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ( mretv & MENU_QUICK_SWITCH ) {
|
||||||
|
return mretv & MENU_LOWER_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
for ( unsigned i = 0; i < pd->num_switchers; i++ ) {
|
for ( unsigned i = 0; i < pd->num_switchers; i++ ) {
|
||||||
if ( selected_line >= pd->starts[i] &&
|
if ( selected_line >= pd->starts[i] &&
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include "rofi.h"
|
#include "rofi.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "textbox.h"
|
#include "widgets/textbox.h"
|
||||||
#include "dialogs/dmenu.h"
|
#include "dialogs/dmenu.h"
|
||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
#include "xrmoptions.h"
|
#include "xrmoptions.h"
|
||||||
|
@ -72,8 +72,6 @@ static inline void bittoggle ( uint32_t *array, unsigned int index )
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
/** Settings */
|
/** Settings */
|
||||||
// Prompt
|
|
||||||
char *prompt;
|
|
||||||
// Separator.
|
// Separator.
|
||||||
char separator;
|
char separator;
|
||||||
|
|
||||||
|
@ -364,7 +362,6 @@ static int dmenu_mode_init ( Mode *sw )
|
||||||
mode_set_private_data ( sw, g_malloc0 ( sizeof ( DmenuModePrivateData ) ) );
|
mode_set_private_data ( sw, g_malloc0 ( sizeof ( DmenuModePrivateData ) ) );
|
||||||
DmenuModePrivateData *pd = (DmenuModePrivateData *) mode_get_private_data ( sw );
|
DmenuModePrivateData *pd = (DmenuModePrivateData *) mode_get_private_data ( sw );
|
||||||
|
|
||||||
pd->prompt = "dmenu ";
|
|
||||||
pd->separator = '\n';
|
pd->separator = '\n';
|
||||||
pd->selected_line = UINT32_MAX;
|
pd->selected_line = UINT32_MAX;
|
||||||
|
|
||||||
|
@ -373,8 +370,6 @@ static int dmenu_mode_init ( Mode *sw )
|
||||||
// Input data separator.
|
// Input data separator.
|
||||||
find_arg_char ( "-sep", &( pd->separator ) );
|
find_arg_char ( "-sep", &( pd->separator ) );
|
||||||
|
|
||||||
// Check prompt
|
|
||||||
find_arg_str ( "-p", &( pd->prompt ) );
|
|
||||||
find_arg_uint ( "-selected-row", &( pd->selected_line ) );
|
find_arg_uint ( "-selected-row", &( pd->selected_line ) );
|
||||||
// By default we print the unescaped line back.
|
// By default we print the unescaped line back.
|
||||||
pd->format = "s";
|
pd->format = "s";
|
||||||
|
@ -663,7 +658,8 @@ int dmenu_switcher_dialog ( void )
|
||||||
g_free ( input );
|
g_free ( input );
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
RofiViewState *state = rofi_view_create ( &dmenu_mode, input, pd->prompt, pd->message, menu_flags, dmenu_finalize );
|
find_arg_str ( "-p", &( dmenu_mode.display_name ) );
|
||||||
|
RofiViewState *state = rofi_view_create ( &dmenu_mode, input, pd->message, menu_flags, dmenu_finalize );
|
||||||
// @TODO we should do this better.
|
// @TODO we should do this better.
|
||||||
if ( async ) {
|
if ( async ) {
|
||||||
rofi_view_set_overlay ( state, "Loading.. " );
|
rofi_view_set_overlay ( state, "Loading.. " );
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
#include "rofi.h"
|
#include "rofi.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
#include "textbox.h"
|
#include "widgets/textbox.h"
|
||||||
#include "history.h"
|
#include "history.h"
|
||||||
#include "dialogs/drun.h"
|
#include "dialogs/drun.h"
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
#include "xrmoptions.h"
|
#include "xrmoptions.h"
|
||||||
#include "dialogs/help-keys.h"
|
#include "dialogs/help-keys.h"
|
||||||
#include "textbox.h"
|
#include "widgets/textbox.h"
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
#include "rofi.h"
|
#include "rofi.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
#include "textbox.h"
|
#include "widgets/textbox.h"
|
||||||
#include "x11-helper.h"
|
#include "x11-helper.h"
|
||||||
#include "dialogs/window.h"
|
#include "dialogs/window.h"
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
#include "mode.h"
|
#include "mode.h"
|
||||||
#include "rofi.h"
|
#include "rofi.h"
|
||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
#include "textbox.h"
|
#include "widgets/textbox.h"
|
||||||
#include "x11-helper.h"
|
#include "x11-helper.h"
|
||||||
#include "xrmoptions.h"
|
#include "xrmoptions.h"
|
||||||
#include "dialogs/dialogs.h"
|
#include "dialogs/dialogs.h"
|
||||||
|
@ -157,24 +157,6 @@ static void teardown ( int pfd )
|
||||||
// Cleanup pid file.
|
// Cleanup pid file.
|
||||||
remove_pid_file ( pfd );
|
remove_pid_file ( pfd );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __run_switcher_internal ( ModeMode mode, char *input )
|
|
||||||
{
|
|
||||||
char *prompt = g_strdup_printf ( "%s:", mode_get_display_name ( modi[mode] ) );
|
|
||||||
curr_switcher = mode;
|
|
||||||
RofiViewState * state = rofi_view_create ( modi[mode], input, prompt, NULL, MENU_NORMAL, process_result );
|
|
||||||
g_free ( prompt );
|
|
||||||
if ( state ) {
|
|
||||||
rofi_view_set_active ( state );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rofi_view_set_active ( NULL );
|
|
||||||
|
|
||||||
if ( rofi_view_get_active () == NULL ) {
|
|
||||||
g_main_loop_quit ( main_loop );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static void run_switcher ( ModeMode mode )
|
static void run_switcher ( ModeMode mode )
|
||||||
{
|
{
|
||||||
// Otherwise check if requested mode is enabled.
|
// Otherwise check if requested mode is enabled.
|
||||||
|
@ -184,9 +166,14 @@ static void run_switcher ( ModeMode mode )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
char *input = g_strdup ( config.filter );
|
curr_switcher = mode;
|
||||||
__run_switcher_internal ( mode, input );
|
RofiViewState * state = rofi_view_create ( modi[mode], config.filter, NULL, MENU_NORMAL, process_result );
|
||||||
g_free ( input );
|
if ( state ) {
|
||||||
|
rofi_view_set_active ( state );
|
||||||
|
}
|
||||||
|
if ( rofi_view_get_active () == NULL ) {
|
||||||
|
g_main_loop_quit ( main_loop );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void process_result ( RofiViewState *state )
|
void process_result ( RofiViewState *state )
|
||||||
{
|
{
|
||||||
|
@ -197,6 +184,7 @@ void process_result ( RofiViewState *state )
|
||||||
MenuReturn mretv = rofi_view_get_return_value ( state );
|
MenuReturn mretv = rofi_view_get_return_value ( state );
|
||||||
char *input = g_strdup ( rofi_view_get_user_input ( state ) );
|
char *input = g_strdup ( rofi_view_get_user_input ( state ) );
|
||||||
ModeMode retv = mode_result ( sw, mretv, &input, selected_line );
|
ModeMode retv = mode_result ( sw, mretv, &input, selected_line );
|
||||||
|
g_free ( input );
|
||||||
|
|
||||||
ModeMode mode = curr_switcher;
|
ModeMode mode = curr_switcher;
|
||||||
// Find next enabled
|
// Find next enabled
|
||||||
|
@ -224,9 +212,11 @@ void process_result ( RofiViewState *state )
|
||||||
/**
|
/**
|
||||||
* Load in the new mode.
|
* Load in the new mode.
|
||||||
*/
|
*/
|
||||||
__run_switcher_internal ( mode, input );
|
rofi_view_switch_mode ( state, modi[mode] );
|
||||||
|
rofi_view_set_active ( state );
|
||||||
|
curr_switcher = mode;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
g_free ( input );
|
|
||||||
}
|
}
|
||||||
rofi_view_free ( state );
|
rofi_view_free ( state );
|
||||||
}
|
}
|
||||||
|
@ -543,19 +533,18 @@ static gboolean startup ( G_GNUC_UNUSED gpointer data )
|
||||||
* Create window (without showing)
|
* Create window (without showing)
|
||||||
*/
|
*/
|
||||||
__create_window ( window_flags );
|
__create_window ( window_flags );
|
||||||
|
TICK_N ( "Create Window" );
|
||||||
//
|
|
||||||
// Sanity check
|
|
||||||
if ( config_sanity_check ( ) ) {
|
|
||||||
return G_SOURCE_REMOVE;
|
|
||||||
}
|
|
||||||
TICK_N ( "Config sanity check" );
|
|
||||||
// Parse the keybindings.
|
// Parse the keybindings.
|
||||||
if ( !parse_keys_abe () ) {
|
if ( !parse_keys_abe () ) {
|
||||||
// Error dialog
|
// Error dialog
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
TICK_N ( "Parse ABE" );
|
TICK_N ( "Parse ABE" );
|
||||||
|
// Sanity check
|
||||||
|
if ( config_sanity_check ( ) ) {
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
TICK_N ( "Config sanity check" );
|
||||||
// Dmenu mode.
|
// Dmenu mode.
|
||||||
if ( dmenu_mode == TRUE ) {
|
if ( dmenu_mode == TRUE ) {
|
||||||
// force off sidebar mode:
|
// force off sidebar mode:
|
||||||
|
|
849
source/view.c
849
source/view.c
File diff suppressed because it is too large
Load diff
|
@ -1,58 +0,0 @@
|
||||||
#include <glib.h>
|
|
||||||
#include "widget.h"
|
|
||||||
|
|
||||||
int widget_intersect ( const Widget *widget, int x, int y )
|
|
||||||
{
|
|
||||||
if ( widget == NULL ) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( x >= ( widget->x ) && x < ( widget->x + widget->w ) ) {
|
|
||||||
if ( y >= ( widget->y ) && y < ( widget->y + widget->h ) ) {
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void widget_move ( Widget *widget, short x, short y )
|
|
||||||
{
|
|
||||||
if ( widget != NULL ) {
|
|
||||||
widget->x = x;
|
|
||||||
widget->y = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean widget_enabled ( Widget *widget )
|
|
||||||
{
|
|
||||||
if ( widget != NULL ) {
|
|
||||||
return widget->enabled;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void widget_enable ( Widget *widget )
|
|
||||||
{
|
|
||||||
if ( widget ) {
|
|
||||||
widget->enabled = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void widget_disable ( Widget *widget )
|
|
||||||
{
|
|
||||||
if ( widget ) {
|
|
||||||
widget->enabled = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void widget_draw ( Widget *widget, cairo_t *d )
|
|
||||||
{
|
|
||||||
// Check if enabled and if draw is implemented.
|
|
||||||
if ( widget && widget->enabled && widget->draw ) {
|
|
||||||
widget->draw ( widget, d );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void widget_free ( Widget *widget )
|
|
||||||
{
|
|
||||||
if ( widget ) {
|
|
||||||
widget->free ( widget );
|
|
||||||
}
|
|
||||||
}
|
|
291
source/widgets/box.c
Normal file
291
source/widgets/box.c
Normal file
|
@ -0,0 +1,291 @@
|
||||||
|
/**
|
||||||
|
* 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/box.h"
|
||||||
|
|
||||||
|
#define LOG_DOMAIN "Widgets.Box"
|
||||||
|
|
||||||
|
struct _box
|
||||||
|
{
|
||||||
|
widget widget;
|
||||||
|
boxType type;
|
||||||
|
int max_size;
|
||||||
|
// Padding between elements
|
||||||
|
int padding;
|
||||||
|
|
||||||
|
GList *children;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void box_update ( widget *wid );
|
||||||
|
|
||||||
|
static void vert_calculate_size ( box *b )
|
||||||
|
{
|
||||||
|
int expanding_widgets = 0;
|
||||||
|
int active_widgets = 0;
|
||||||
|
b->max_size = 0;
|
||||||
|
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
|
||||||
|
widget * child = (widget *) iter->data;
|
||||||
|
if ( !child->enabled ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
active_widgets++;
|
||||||
|
if ( child->expand == TRUE ) {
|
||||||
|
expanding_widgets++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
b->max_size += child->h;
|
||||||
|
}
|
||||||
|
b->max_size += MAX ( 0, ( ( active_widgets - 1 ) * b->padding ) );
|
||||||
|
if ( b->max_size > b->widget.h ) {
|
||||||
|
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Widgets to large (height) for box: %d %d", b->max_size, b->widget.h );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( active_widgets > 0 ) {
|
||||||
|
int bottom = b->widget.h;
|
||||||
|
int top = 0;
|
||||||
|
double rem = b->widget.h - b->max_size;
|
||||||
|
int index = 0;
|
||||||
|
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
|
||||||
|
widget * child = (widget *) iter->data;
|
||||||
|
if ( child->enabled == FALSE ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( child->expand == TRUE ) {
|
||||||
|
// Re-calculate to avoid round issues leaving one pixel left.
|
||||||
|
int expanding_widgets_size = ( rem ) / ( expanding_widgets - index );
|
||||||
|
if ( child->end ) {
|
||||||
|
bottom -= expanding_widgets_size;
|
||||||
|
widget_move ( child, child->x, bottom );
|
||||||
|
widget_resize ( child, b->widget.w, expanding_widgets_size );
|
||||||
|
bottom -= b->padding;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
widget_move ( child, child->x, top );
|
||||||
|
top += expanding_widgets_size;
|
||||||
|
widget_resize ( child, b->widget.w, expanding_widgets_size );
|
||||||
|
top += b->padding;
|
||||||
|
}
|
||||||
|
rem -= expanding_widgets_size;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
else if ( child->end ) {
|
||||||
|
bottom -= widget_get_height ( child );
|
||||||
|
widget_move ( child, child->x, bottom );
|
||||||
|
widget_resize ( child, b->widget.w, child->h );
|
||||||
|
bottom -= b->padding;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
widget_move ( child, child->x, top );
|
||||||
|
top += widget_get_height ( child );
|
||||||
|
widget_resize ( child, b->widget.w, child->h );
|
||||||
|
top += b->padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void hori_calculate_size ( box *b )
|
||||||
|
{
|
||||||
|
int expanding_widgets = 0;
|
||||||
|
int active_widgets = 0;
|
||||||
|
b->max_size = 0;
|
||||||
|
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
|
||||||
|
widget * child = (widget *) iter->data;
|
||||||
|
if ( !child->enabled ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
active_widgets++;
|
||||||
|
if ( child->expand == TRUE ) {
|
||||||
|
expanding_widgets++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Size used by fixed width widgets.
|
||||||
|
b->max_size += child->w;
|
||||||
|
}
|
||||||
|
b->max_size += MAX ( 0, ( ( active_widgets - 1 ) * b->padding ) );
|
||||||
|
if ( b->max_size > b->widget.w ) {
|
||||||
|
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Widgets to large (width) for box: %d %d", b->max_size, b->widget.w );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( active_widgets > 0 ) {
|
||||||
|
int right = b->widget.w;
|
||||||
|
int left = 0;
|
||||||
|
double rem = b->widget.w - b->max_size;
|
||||||
|
int index = 0;
|
||||||
|
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
|
||||||
|
widget * child = (widget *) iter->data;
|
||||||
|
if ( child->enabled == FALSE ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( child->expand == TRUE ) {
|
||||||
|
// Re-calculate to avoid round issues leaving one pixel left.
|
||||||
|
int expanding_widgets_size = ( rem ) / ( expanding_widgets - index );
|
||||||
|
if ( child->end ) {
|
||||||
|
right -= expanding_widgets_size;
|
||||||
|
widget_move ( child, right, child->y );
|
||||||
|
widget_resize ( child, expanding_widgets_size, b->widget.h );
|
||||||
|
right -= b->padding;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
widget_move ( child, left, child->y );
|
||||||
|
left += expanding_widgets_size;
|
||||||
|
widget_resize ( child, expanding_widgets_size, b->widget.h );
|
||||||
|
left += b->padding;
|
||||||
|
}
|
||||||
|
rem -= expanding_widgets_size;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
else if ( child->end ) {
|
||||||
|
right -= widget_get_width ( child );
|
||||||
|
widget_move ( child, right, child->y );
|
||||||
|
widget_resize ( child, child->w, b->widget.h );
|
||||||
|
right -= b->padding;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
widget_move ( child, left, child->y );
|
||||||
|
left += widget_get_width ( child );
|
||||||
|
widget_resize ( child, child->w, b->widget.h );
|
||||||
|
left += b->padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void box_draw ( widget *wid, cairo_t *draw )
|
||||||
|
{
|
||||||
|
box *b = (box *) wid;
|
||||||
|
// Store current state.
|
||||||
|
cairo_save ( draw );
|
||||||
|
// Define a clipmask so we won't draw outside out widget.
|
||||||
|
cairo_rectangle ( draw, wid->x, wid->y, wid->w, wid->h );
|
||||||
|
cairo_clip ( draw );
|
||||||
|
// Set new x/y possition.
|
||||||
|
cairo_translate ( draw, wid->x, wid->y );
|
||||||
|
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
|
||||||
|
widget * child = (widget *) iter->data;
|
||||||
|
widget_draw ( child, draw );
|
||||||
|
}
|
||||||
|
cairo_restore ( draw );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void box_free ( widget *wid )
|
||||||
|
{
|
||||||
|
box *b = (box *) wid;
|
||||||
|
|
||||||
|
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
|
||||||
|
widget * child = (widget *) iter->data;
|
||||||
|
widget_free ( child );
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free ( b );
|
||||||
|
}
|
||||||
|
|
||||||
|
void box_add ( box *box, widget *child, gboolean expand, gboolean end )
|
||||||
|
{
|
||||||
|
child->expand = expand;
|
||||||
|
child->end = end;
|
||||||
|
child->parent = WIDGET ( box );
|
||||||
|
if ( end ) {
|
||||||
|
box->children = g_list_prepend ( box->children, (void *) child );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
box->children = g_list_append ( box->children, (void *) child );
|
||||||
|
}
|
||||||
|
widget_update ( WIDGET ( box ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void box_resize ( widget *widget, short w, short h )
|
||||||
|
{
|
||||||
|
box *b = (box *) widget;
|
||||||
|
if ( b->widget.w != w || b->widget.h != h ) {
|
||||||
|
b->widget.w = w;
|
||||||
|
b->widget.h = h;
|
||||||
|
widget_update ( widget );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean box_clicked ( widget *wid, xcb_button_press_event_t *xbe, G_GNUC_UNUSED void *udata )
|
||||||
|
{
|
||||||
|
box *b = (box *) wid;
|
||||||
|
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
|
||||||
|
widget * child = (widget *) iter->data;
|
||||||
|
if ( !child->enabled ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( widget_intersect ( child, xbe->event_x, xbe->event_y ) ) {
|
||||||
|
xcb_button_press_event_t rel = *xbe;
|
||||||
|
rel.event_x -= child->x;
|
||||||
|
rel.event_y -= child->y;
|
||||||
|
return widget_clicked ( child, &rel );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
box * box_create ( boxType type, short x, short y, short w, short h )
|
||||||
|
{
|
||||||
|
box *b = g_malloc0 ( sizeof ( box ) );
|
||||||
|
b->type = type;
|
||||||
|
b->widget.x = x;
|
||||||
|
b->widget.y = y;
|
||||||
|
b->widget.w = w;
|
||||||
|
b->widget.h = h;
|
||||||
|
b->widget.draw = box_draw;
|
||||||
|
b->widget.free = box_free;
|
||||||
|
b->widget.resize = box_resize;
|
||||||
|
b->widget.update = box_update;
|
||||||
|
b->widget.clicked = box_clicked;
|
||||||
|
b->widget.enabled = TRUE;
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void box_update ( widget *wid )
|
||||||
|
{
|
||||||
|
box *b = (box *) wid;
|
||||||
|
switch ( b->type )
|
||||||
|
{
|
||||||
|
case BOX_VERTICAL:
|
||||||
|
vert_calculate_size ( b );
|
||||||
|
break;
|
||||||
|
case BOX_HORIZONTAL:
|
||||||
|
default:
|
||||||
|
hori_calculate_size ( b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int box_get_fixed_pixels ( box *box )
|
||||||
|
{
|
||||||
|
return box->max_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void box_set_padding ( box * box, unsigned int padding )
|
||||||
|
{
|
||||||
|
if ( box ) {
|
||||||
|
box->padding = padding;
|
||||||
|
widget_queue_redraw ( WIDGET ( box ) );
|
||||||
|
}
|
||||||
|
}
|
488
source/widgets/listview.c
Normal file
488
source/widgets/listview.c
Normal file
|
@ -0,0 +1,488 @@
|
||||||
|
/**
|
||||||
|
* MIT/X11 License
|
||||||
|
* Modified (c) 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 <glib.h>
|
||||||
|
#include <widgets/widget.h>
|
||||||
|
#include <widgets/textbox.h>
|
||||||
|
#include <widgets/listview.h>
|
||||||
|
#include <widgets/scrollbar.h>
|
||||||
|
|
||||||
|
struct _listview
|
||||||
|
{
|
||||||
|
widget widget;
|
||||||
|
// RChanged
|
||||||
|
// Text needs to be repainted.
|
||||||
|
unsigned int rchanged;
|
||||||
|
// Administration
|
||||||
|
|
||||||
|
unsigned int cur_page;
|
||||||
|
unsigned int last_offset;
|
||||||
|
unsigned int selected;
|
||||||
|
|
||||||
|
unsigned int element_height;
|
||||||
|
unsigned int element_width;
|
||||||
|
unsigned int max_rows;
|
||||||
|
unsigned int max_elements;
|
||||||
|
|
||||||
|
//
|
||||||
|
unsigned int cur_columns;
|
||||||
|
unsigned int req_elements;
|
||||||
|
unsigned int cur_elements;
|
||||||
|
|
||||||
|
unsigned int padding;
|
||||||
|
unsigned int menu_lines;
|
||||||
|
unsigned int menu_columns;
|
||||||
|
unsigned int fixed_num_lines;
|
||||||
|
gboolean cycle;
|
||||||
|
gboolean multi_select;
|
||||||
|
|
||||||
|
ScrollType scroll_type;
|
||||||
|
|
||||||
|
textbox **boxes;
|
||||||
|
scrollbar *scrollbar;
|
||||||
|
|
||||||
|
listview_update_callback callback;
|
||||||
|
void *udata;
|
||||||
|
|
||||||
|
xcb_timestamp_t last_click;
|
||||||
|
listview_mouse_activated_cb mouse_activated;
|
||||||
|
void *mouse_activated_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void listview_free ( widget *widget )
|
||||||
|
{
|
||||||
|
listview *lv = (listview *) widget;
|
||||||
|
g_free ( lv );
|
||||||
|
}
|
||||||
|
static unsigned int scroll_per_page ( listview * lv )
|
||||||
|
{
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
// selected row is always visible.
|
||||||
|
// If selected is visible do not scroll.
|
||||||
|
if ( ( ( lv->selected - ( lv->last_offset ) ) < ( lv->max_elements ) ) && ( lv->selected >= ( lv->last_offset ) ) ) {
|
||||||
|
offset = lv->last_offset;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// Do paginating
|
||||||
|
unsigned int page = ( lv->max_elements > 0 ) ? ( lv->selected / lv->max_elements ) : 0;
|
||||||
|
offset = page * lv->max_elements;
|
||||||
|
if ( page != lv->cur_page ) {
|
||||||
|
lv->cur_page = page;
|
||||||
|
lv->rchanged = TRUE;
|
||||||
|
}
|
||||||
|
// Set the position
|
||||||
|
scrollbar_set_handle ( lv->scrollbar, page * lv->max_elements );
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int scroll_continious ( listview *lv )
|
||||||
|
{
|
||||||
|
unsigned int middle = ( lv->max_rows - ( ( lv->max_rows & 1 ) == 0 ) ) / 2;
|
||||||
|
unsigned int offset = 0;
|
||||||
|
if ( lv->selected > middle ) {
|
||||||
|
if ( lv->selected < ( lv->req_elements - ( lv->max_rows - middle ) ) ) {
|
||||||
|
offset = lv->selected - middle;
|
||||||
|
}
|
||||||
|
// Don't go below zero.
|
||||||
|
else if ( lv->req_elements > lv->max_rows ) {
|
||||||
|
offset = lv->req_elements - lv->max_rows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( offset != lv->cur_page ) {
|
||||||
|
scrollbar_set_handle ( lv->scrollbar, offset );
|
||||||
|
lv->cur_page = offset;
|
||||||
|
lv->rchanged = TRUE;
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_element ( listview *lv, unsigned int tb, unsigned int index, gboolean full )
|
||||||
|
{
|
||||||
|
// Select drawing mode
|
||||||
|
TextBoxFontType type = ( index & 1 ) == 0 ? NORMAL : ALT;
|
||||||
|
type = ( index ) == lv->selected ? HIGHLIGHT : type;
|
||||||
|
|
||||||
|
if ( lv->callback ) {
|
||||||
|
lv->callback ( lv->boxes[tb], index, lv->udata, type, full );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void listview_draw ( widget *wid, cairo_t *draw )
|
||||||
|
{
|
||||||
|
unsigned int offset = 0;
|
||||||
|
listview *lv = (listview *) wid;
|
||||||
|
if ( lv->scroll_type == LISTVIEW_SCROLL_CONTINIOUS ) {
|
||||||
|
offset = scroll_continious ( lv );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
offset = scroll_per_page ( lv );
|
||||||
|
}
|
||||||
|
lv->last_offset = offset;
|
||||||
|
if ( lv->cur_elements > 0 && lv->max_rows > 0 ) {
|
||||||
|
cairo_save ( draw );
|
||||||
|
// Set new x/y possition.
|
||||||
|
cairo_translate ( draw, wid->x, wid->y );
|
||||||
|
unsigned int max = MIN ( lv->cur_elements, lv->req_elements - offset );
|
||||||
|
if ( lv->rchanged ) {
|
||||||
|
unsigned int width = lv->widget.w - lv->padding * ( lv->cur_columns - 1 );
|
||||||
|
if ( widget_enabled ( WIDGET ( lv->scrollbar ) ) ) {
|
||||||
|
width -= lv->padding;
|
||||||
|
width -= lv->scrollbar->widget.w;
|
||||||
|
}
|
||||||
|
unsigned int element_width = ( width ) / lv->cur_columns;
|
||||||
|
for ( unsigned int i = 0; i < max; i++ ) {
|
||||||
|
unsigned int ex = ( ( i ) / lv->max_rows ) * ( element_width + lv->padding );
|
||||||
|
unsigned int ey = ( ( i ) % lv->max_rows ) * ( lv->element_height + lv->padding );
|
||||||
|
textbox_moveresize ( lv->boxes[i], ex, ey, element_width, lv->element_height );
|
||||||
|
|
||||||
|
update_element ( lv, i, i + offset, TRUE );
|
||||||
|
widget_draw ( WIDGET ( lv->boxes[i] ), 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->scrollbar ), draw );
|
||||||
|
cairo_restore ( draw );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void listview_recompute_elements ( listview *lv )
|
||||||
|
{
|
||||||
|
unsigned int newne = 0;
|
||||||
|
if ( lv->max_rows == 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( 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;
|
||||||
|
lv->cur_columns = lv->menu_columns;
|
||||||
|
}
|
||||||
|
for ( unsigned int i = newne; i < lv->cur_elements; i++ ) {
|
||||||
|
widget_free ( WIDGET ( lv->boxes[i] ) );
|
||||||
|
}
|
||||||
|
lv->boxes = g_realloc ( lv->boxes, newne * sizeof ( textbox* ) );
|
||||||
|
if ( newne > 0 ) {
|
||||||
|
for ( unsigned int i = lv->cur_elements; i < newne; i++ ) {
|
||||||
|
TextboxFlags flags = ( lv->multi_select ) ? TB_INDICATOR : 0;
|
||||||
|
lv->boxes[i] = textbox_create ( flags, 0, 0, 0, lv->element_height, NORMAL, "" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lv->rchanged = TRUE;
|
||||||
|
scrollbar_set_handle_length ( lv->scrollbar, lv->cur_columns * lv->max_rows );
|
||||||
|
lv->cur_elements = newne;
|
||||||
|
}
|
||||||
|
|
||||||
|
void listview_set_num_elements ( listview *lv, unsigned int rows )
|
||||||
|
{
|
||||||
|
lv->req_elements = rows;
|
||||||
|
listview_set_selected ( lv, lv->selected );
|
||||||
|
listview_recompute_elements ( lv );
|
||||||
|
scrollbar_set_max_value ( lv->scrollbar, lv->req_elements );
|
||||||
|
widget_queue_redraw ( WIDGET ( lv ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int listview_get_selected ( listview *lv )
|
||||||
|
{
|
||||||
|
if ( lv != NULL ) {
|
||||||
|
return lv->selected;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void listview_set_selected ( listview *lv, unsigned int selected )
|
||||||
|
{
|
||||||
|
if ( lv && lv->req_elements > 0 ) {
|
||||||
|
lv->selected = MIN ( selected, lv->req_elements - 1 );
|
||||||
|
widget_queue_redraw ( WIDGET ( lv ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 );
|
||||||
|
lv->max_rows = ( lv->padding + lv->widget.h ) / ( lv->element_height + lv->padding );
|
||||||
|
lv->max_elements = lv->max_rows * lv->menu_columns;
|
||||||
|
|
||||||
|
widget_move ( WIDGET ( lv->scrollbar ), lv->widget.w - lv->scrollbar->widget.w, 0 );
|
||||||
|
widget_resize ( WIDGET ( lv->scrollbar ), lv->scrollbar->widget.w, h );
|
||||||
|
|
||||||
|
listview_recompute_elements ( lv );
|
||||||
|
widget_queue_redraw ( wid );
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean listview_scrollbar_clicked ( widget *sb, xcb_button_press_event_t * xce, void *udata )
|
||||||
|
{
|
||||||
|
listview *lv = (listview *) udata;
|
||||||
|
|
||||||
|
unsigned int sel = scrollbar_clicked ( (scrollbar *) sb, xce->event_y );
|
||||||
|
listview_set_selected ( lv, sel );
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean listview_clicked ( widget *wid, xcb_button_press_event_t *xce, G_GNUC_UNUSED void *udata )
|
||||||
|
{
|
||||||
|
listview *lv = (listview *) wid;
|
||||||
|
if ( widget_enabled ( WIDGET ( lv->scrollbar ) ) && widget_intersect ( WIDGET ( lv->scrollbar ), xce->event_x, xce->event_y ) ) {
|
||||||
|
// Forward to handler of scrollbar.
|
||||||
|
xcb_button_press_event_t xce2 = *xce;
|
||||||
|
xce->event_x -= lv->scrollbar->widget.x;
|
||||||
|
xce->event_y -= lv->scrollbar->widget.y;
|
||||||
|
return widget_clicked ( WIDGET ( lv->scrollbar ), &xce2 );
|
||||||
|
}
|
||||||
|
// Handle the boxes.
|
||||||
|
unsigned int max = MIN ( lv->cur_elements, lv->req_elements - lv->last_offset );
|
||||||
|
for ( unsigned int i = 0; i < max; i++ ) {
|
||||||
|
widget *w = WIDGET ( lv->boxes[i] );
|
||||||
|
if ( widget_intersect ( w, xce->event_x, xce->event_y ) ) {
|
||||||
|
if ( ( lv->last_offset + i ) == lv->selected ) {
|
||||||
|
if ( ( xce->time - lv->last_click ) < 200 ) {
|
||||||
|
// Somehow signal we accepted item.
|
||||||
|
lv->mouse_activated ( lv, xce, lv->mouse_activated_data );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
listview_set_selected ( lv, lv->last_offset + i );
|
||||||
|
}
|
||||||
|
lv->last_click = xce->time;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
listview *listview_create ( listview_update_callback cb, void *udata, unsigned int eh )
|
||||||
|
{
|
||||||
|
listview *lv = g_malloc0 ( sizeof ( listview ) );
|
||||||
|
lv->widget.free = listview_free;
|
||||||
|
lv->widget.resize = listview_resize;
|
||||||
|
lv->widget.draw = listview_draw;
|
||||||
|
lv->widget.clicked = listview_clicked;
|
||||||
|
lv->widget.enabled = TRUE;
|
||||||
|
|
||||||
|
lv->scrollbar = scrollbar_create ( 0, 0, 4, 0 );
|
||||||
|
widget_set_clicked_handler ( WIDGET ( lv->scrollbar ), listview_scrollbar_clicked, lv );
|
||||||
|
lv->scrollbar->widget.parent = WIDGET ( lv );
|
||||||
|
// Calculate height of an element.
|
||||||
|
lv->element_height = textbox_get_estimated_char_height () * eh;
|
||||||
|
|
||||||
|
lv->callback = cb;
|
||||||
|
lv->udata = udata;
|
||||||
|
return lv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigation commands.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void listview_nav_up ( listview *lv )
|
||||||
|
{
|
||||||
|
if ( lv == NULL ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( lv->req_elements == 0 || ( lv->selected == 0 && !lv->cycle ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( lv->selected == 0 ) {
|
||||||
|
lv->selected = lv->req_elements;
|
||||||
|
}
|
||||||
|
lv->selected--;
|
||||||
|
widget_queue_redraw ( WIDGET ( lv ) );
|
||||||
|
}
|
||||||
|
void listview_nav_down ( listview *lv )
|
||||||
|
{
|
||||||
|
if ( lv == NULL ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( lv->req_elements == 0 || ( lv->selected == ( lv->req_elements - 1 ) && !lv->cycle ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lv->selected = lv->selected < lv->req_elements - 1 ? MIN ( lv->req_elements - 1, lv->selected + 1 ) : 0;
|
||||||
|
|
||||||
|
widget_queue_redraw ( WIDGET ( lv ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void listview_nav_left ( listview *lv )
|
||||||
|
{
|
||||||
|
if ( lv == NULL ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( lv->selected >= lv->max_rows ) {
|
||||||
|
lv->selected -= lv->max_rows;
|
||||||
|
widget_queue_redraw ( WIDGET ( lv ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void listview_nav_right ( listview *lv )
|
||||||
|
{
|
||||||
|
if ( lv == NULL ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( ( lv->selected + lv->max_rows ) < lv->req_elements ) {
|
||||||
|
lv->selected += lv->max_rows;
|
||||||
|
widget_queue_redraw ( WIDGET ( lv ) );
|
||||||
|
}
|
||||||
|
else if ( lv->selected < ( lv->req_elements - 1 ) ) {
|
||||||
|
// We do not want to move to last item, UNLESS the last column is only
|
||||||
|
// partially filled, then we still want to move column and select last entry.
|
||||||
|
// First check the column we are currently in.
|
||||||
|
int col = lv->selected / lv->max_rows;
|
||||||
|
// Check total number of columns.
|
||||||
|
int ncol = lv->req_elements / lv->max_rows;
|
||||||
|
// If there is an extra column, move.
|
||||||
|
if ( col != ncol ) {
|
||||||
|
lv->selected = lv->req_elements - 1;
|
||||||
|
widget_queue_redraw ( WIDGET ( lv ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void listview_nav_page_prev ( listview *lv )
|
||||||
|
{
|
||||||
|
if ( lv == NULL ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( lv->selected < lv->max_elements ) {
|
||||||
|
lv->selected = 0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
lv->selected -= ( lv->max_elements );
|
||||||
|
}
|
||||||
|
widget_queue_redraw ( WIDGET ( lv ) );
|
||||||
|
}
|
||||||
|
void listview_nav_page_next ( listview *lv )
|
||||||
|
{
|
||||||
|
if ( lv == NULL ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( lv->req_elements == 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lv->selected += ( lv->max_elements );
|
||||||
|
if ( lv->selected >= lv->req_elements ) {
|
||||||
|
lv->selected = lv->req_elements - 1;
|
||||||
|
}
|
||||||
|
widget_queue_redraw ( WIDGET ( lv ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int listview_get_desired_height ( listview *lv )
|
||||||
|
{
|
||||||
|
if ( lv == NULL ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int h = lv->menu_lines;
|
||||||
|
if ( !( lv->fixed_num_lines ) ) {
|
||||||
|
h = MIN ( lv->menu_lines, lv->req_elements );
|
||||||
|
}
|
||||||
|
if ( h == 0 ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return h * lv->element_height + ( h - 1 ) * lv->padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the widget!
|
||||||
|
*/
|
||||||
|
void listview_set_padding ( listview *lv, unsigned int padding )
|
||||||
|
{
|
||||||
|
if ( lv ) {
|
||||||
|
lv->padding = padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void listview_set_max_lines ( listview *lv, unsigned int lines )
|
||||||
|
{
|
||||||
|
if ( lv ) {
|
||||||
|
lv->menu_lines = lines;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void listview_set_max_columns ( listview *lv, unsigned int columns )
|
||||||
|
{
|
||||||
|
if ( lv ) {
|
||||||
|
lv->menu_columns = columns;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void listview_set_fixed_num_lines ( listview *lv, gboolean enabled )
|
||||||
|
{
|
||||||
|
if ( lv ) {
|
||||||
|
lv->fixed_num_lines = enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void listview_set_hide_scrollbar ( listview *lv, gboolean enabled )
|
||||||
|
{
|
||||||
|
if ( lv ) {
|
||||||
|
if ( enabled ) {
|
||||||
|
widget_enable ( WIDGET ( lv->scrollbar ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
widget_disable ( WIDGET ( lv->scrollbar ) );
|
||||||
|
}
|
||||||
|
listview_recompute_elements ( lv );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void listview_set_scrollbar_width ( listview *lv, unsigned int width )
|
||||||
|
{
|
||||||
|
if ( lv ) {
|
||||||
|
widget_resize ( WIDGET ( lv->scrollbar ), width, widget_get_height ( WIDGET ( lv->scrollbar ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void listview_set_cycle ( listview *lv, gboolean cycle )
|
||||||
|
{
|
||||||
|
if ( lv ) {
|
||||||
|
lv->cycle = cycle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void listview_set_scroll_type ( listview *lv, ScrollType type )
|
||||||
|
{
|
||||||
|
if ( lv ) {
|
||||||
|
lv->scroll_type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void listview_set_mouse_activated_cb ( listview *lv, listview_mouse_activated_cb cb, void *udata )
|
||||||
|
{
|
||||||
|
if ( lv ) {
|
||||||
|
lv->mouse_activated = cb;
|
||||||
|
lv->mouse_activated_data = udata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void listview_set_multi_select ( listview *lv, gboolean enable )
|
||||||
|
{
|
||||||
|
if ( lv ) {
|
||||||
|
lv->multi_select = enable;
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,12 +25,12 @@
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include "scrollbar.h"
|
#include "widgets/scrollbar.h"
|
||||||
#include "x11-helper.h"
|
#include "x11-helper.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
static void scrollbar_draw ( Widget *widget, cairo_t *draw );
|
static void scrollbar_draw ( widget *, cairo_t * );
|
||||||
static void scrollbar_free ( Widget * );
|
static void scrollbar_free ( widget * );
|
||||||
|
|
||||||
scrollbar *scrollbar_create ( short x, short y, short w, short h )
|
scrollbar *scrollbar_create ( short x, short y, short w, short h )
|
||||||
{
|
{
|
||||||
|
@ -53,9 +53,9 @@ scrollbar *scrollbar_create ( short x, short y, short w, short h )
|
||||||
return sb;
|
return sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scrollbar_free ( Widget *widget )
|
static void scrollbar_free ( widget *wid )
|
||||||
{
|
{
|
||||||
scrollbar *sb = (scrollbar *) widget;
|
scrollbar *sb = (scrollbar *) wid;
|
||||||
g_free ( sb );
|
g_free ( sb );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,9 +80,9 @@ void scrollbar_set_handle_length ( scrollbar *sb, unsigned int pos_length )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scrollbar_draw ( Widget *widget, cairo_t *draw )
|
static void scrollbar_draw ( widget *wid, cairo_t *draw )
|
||||||
{
|
{
|
||||||
scrollbar *sb = (scrollbar *) widget;
|
scrollbar *sb = (scrollbar *) wid;
|
||||||
// Calculate position and size.
|
// Calculate position and size.
|
||||||
const short bh = sb->widget.h - 0;
|
const short bh = sb->widget.h - 0;
|
||||||
float sec = ( ( bh ) / (float) sb->length );
|
float sec = ( ( bh ) / (float) sb->length );
|
||||||
|
@ -97,20 +97,10 @@ static void scrollbar_draw ( Widget *widget, cairo_t *draw )
|
||||||
// Redraw base window
|
// Redraw base window
|
||||||
color_separator ( draw );
|
color_separator ( draw );
|
||||||
|
|
||||||
cairo_rectangle ( draw, sb->widget.x + config.line_margin, sb->widget.y + y, sb->widget.w - config.line_margin, height );
|
cairo_rectangle ( draw, sb->widget.x, sb->widget.y + y, sb->widget.w, height );
|
||||||
cairo_fill ( draw );
|
cairo_fill ( draw );
|
||||||
}
|
}
|
||||||
void scrollbar_resize ( scrollbar *sb, int w, int h )
|
|
||||||
{
|
|
||||||
if ( sb != NULL ) {
|
|
||||||
if ( h > 0 ) {
|
|
||||||
sb->widget.h = h;
|
|
||||||
}
|
|
||||||
if ( w > 0 ) {
|
|
||||||
sb->widget.w = w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsigned int scrollbar_clicked ( const scrollbar *sb, int y )
|
unsigned int scrollbar_clicked ( const scrollbar *sb, int y )
|
||||||
{
|
{
|
||||||
if ( sb != NULL ) {
|
if ( sb != NULL ) {
|
84
source/widgets/separator.c
Normal file
84
source/widgets/separator.c
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
/**
|
||||||
|
* MIT/X11 License
|
||||||
|
* Modified (c) 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 <xkbcommon/xkbcommon.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "widgets/separator.h"
|
||||||
|
#include "x11-helper.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal structure for the separator.
|
||||||
|
*/
|
||||||
|
struct _separator
|
||||||
|
{
|
||||||
|
widget widget;
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *const _separator_style_none = "none";
|
||||||
|
const char *const _separator_style_dash = "dash";
|
||||||
|
static void separator_draw ( widget *, cairo_t * );
|
||||||
|
static void separator_free ( widget * );
|
||||||
|
|
||||||
|
separator *separator_create ( short h )
|
||||||
|
{
|
||||||
|
separator *sb = g_malloc0 ( sizeof ( separator ) );
|
||||||
|
|
||||||
|
sb->widget.x = 0;
|
||||||
|
sb->widget.y = 0;
|
||||||
|
sb->widget.w = 1;
|
||||||
|
sb->widget.h = MAX ( 1, h );
|
||||||
|
|
||||||
|
sb->widget.draw = separator_draw;
|
||||||
|
sb->widget.free = separator_free;
|
||||||
|
|
||||||
|
// Enabled by default
|
||||||
|
sb->widget.enabled = TRUE;
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void separator_free ( widget *wid )
|
||||||
|
{
|
||||||
|
separator *sb = (separator *) wid;
|
||||||
|
g_free ( sb );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void separator_draw ( widget *wid, cairo_t *draw )
|
||||||
|
{
|
||||||
|
if ( strcmp ( config.separator_style, _separator_style_none ) ) {
|
||||||
|
cairo_set_line_width ( draw, wid->h );
|
||||||
|
color_separator ( draw );
|
||||||
|
if ( strcmp ( config.separator_style, _separator_style_dash ) == 0 ) {
|
||||||
|
const double dashes[1] = { 4 };
|
||||||
|
cairo_set_dash ( draw, dashes, 1, 0.0 );
|
||||||
|
}
|
||||||
|
double half = wid->h / 2.0;
|
||||||
|
cairo_move_to ( draw, wid->x, wid->y + half );
|
||||||
|
cairo_line_to ( draw, wid->x + wid->w, wid->y + half );
|
||||||
|
cairo_stroke ( draw );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "textbox.h"
|
#include "widgets/textbox.h"
|
||||||
#include "keyb.h"
|
#include "keyb.h"
|
||||||
#include "x11-helper.h"
|
#include "x11-helper.h"
|
||||||
#include "mode.h"
|
#include "mode.h"
|
||||||
|
@ -38,8 +38,10 @@
|
||||||
|
|
||||||
#define DOT_OFFSET 15
|
#define DOT_OFFSET 15
|
||||||
|
|
||||||
static void textbox_draw ( Widget *, cairo_t * );
|
static void textbox_draw ( widget *, cairo_t * );
|
||||||
static void textbox_free ( Widget * );
|
static void textbox_free ( widget * );
|
||||||
|
static int textbox_get_width ( widget * );
|
||||||
|
static int _textbox_get_height ( widget * );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Font + font color cache.
|
* Font + font color cache.
|
||||||
|
@ -65,6 +67,7 @@ static gboolean textbox_blink ( gpointer data )
|
||||||
if ( tb->blink < 2 ) {
|
if ( tb->blink < 2 ) {
|
||||||
tb->blink = !tb->blink;
|
tb->blink = !tb->blink;
|
||||||
tb->update = TRUE;
|
tb->update = TRUE;
|
||||||
|
widget_queue_redraw ( WIDGET ( tb ) );
|
||||||
rofi_view_queue_redraw ( );
|
rofi_view_queue_redraw ( );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -73,6 +76,12 @@ static gboolean textbox_blink ( gpointer data )
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void textbox_resize ( widget *wid, short w, short h )
|
||||||
|
{
|
||||||
|
textbox *tb = (textbox *) wid;
|
||||||
|
textbox_moveresize ( tb, tb->widget.x, tb->widget.y, w, h );
|
||||||
|
}
|
||||||
|
|
||||||
textbox* textbox_create ( TextboxFlags flags, short x, short y, short w, short h,
|
textbox* textbox_create ( TextboxFlags flags, short x, short y, short w, short h,
|
||||||
TextBoxFontType tbft, const char *text )
|
TextBoxFontType tbft, const char *text )
|
||||||
{
|
{
|
||||||
|
@ -80,6 +89,9 @@ textbox* textbox_create ( TextboxFlags flags, short x, short y, short w, short h
|
||||||
|
|
||||||
tb->widget.draw = textbox_draw;
|
tb->widget.draw = textbox_draw;
|
||||||
tb->widget.free = textbox_free;
|
tb->widget.free = textbox_free;
|
||||||
|
tb->widget.resize = textbox_resize;
|
||||||
|
tb->widget.get_width = textbox_get_width;
|
||||||
|
tb->widget.get_height = _textbox_get_height;
|
||||||
tb->flags = flags;
|
tb->flags = flags;
|
||||||
|
|
||||||
tb->widget.x = x;
|
tb->widget.x = x;
|
||||||
|
@ -117,6 +129,9 @@ textbox* textbox_create ( TextboxFlags flags, short x, short y, short w, short h
|
||||||
void textbox_font ( textbox *tb, TextBoxFontType tbft )
|
void textbox_font ( textbox *tb, TextBoxFontType tbft )
|
||||||
{
|
{
|
||||||
TextBoxFontType t = tbft & STATE_MASK;
|
TextBoxFontType t = tbft & STATE_MASK;
|
||||||
|
if ( tb == NULL ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// ACTIVE has priority over URGENT if both set.
|
// ACTIVE has priority over URGENT if both set.
|
||||||
if ( t == ( URGENT | ACTIVE ) ) {
|
if ( t == ( URGENT | ACTIVE ) ) {
|
||||||
t = ACTIVE;
|
t = ACTIVE;
|
||||||
|
@ -139,6 +154,7 @@ void textbox_font ( textbox *tb, TextBoxFontType tbft )
|
||||||
}
|
}
|
||||||
if ( tb->tbft != tbft ) {
|
if ( tb->tbft != tbft ) {
|
||||||
tb->update = TRUE;
|
tb->update = TRUE;
|
||||||
|
widget_need_redraw ( WIDGET ( tb ) );
|
||||||
}
|
}
|
||||||
tb->tbft = tbft;
|
tb->tbft = tbft;
|
||||||
}
|
}
|
||||||
|
@ -202,9 +218,11 @@ void textbox_text ( textbox *tb, const char *text )
|
||||||
__textbox_update_pango_text ( tb );
|
__textbox_update_pango_text ( tb );
|
||||||
if ( tb->flags & TB_AUTOWIDTH ) {
|
if ( tb->flags & TB_AUTOWIDTH ) {
|
||||||
textbox_moveresize ( tb, tb->widget.x, tb->widget.y, tb->widget.w, tb->widget.h );
|
textbox_moveresize ( tb, tb->widget.x, tb->widget.y, tb->widget.w, tb->widget.h );
|
||||||
|
widget_update ( WIDGET ( tb ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
tb->cursor = MAX ( 0, MIN ( ( int ) g_utf8_strlen ( tb->text, -1 ), tb->cursor ) );
|
tb->cursor = MAX ( 0, MIN ( ( int ) g_utf8_strlen ( tb->text, -1 ), tb->cursor ) );
|
||||||
|
widget_need_redraw ( WIDGET ( tb ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// within the parent handled auto width/height modes
|
// within the parent handled auto width/height modes
|
||||||
|
@ -213,7 +231,8 @@ void textbox_moveresize ( textbox *tb, int x, int y, int w, int h )
|
||||||
unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0;
|
unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0;
|
||||||
if ( tb->flags & TB_AUTOWIDTH ) {
|
if ( tb->flags & TB_AUTOWIDTH ) {
|
||||||
pango_layout_set_width ( tb->layout, -1 );
|
pango_layout_set_width ( tb->layout, -1 );
|
||||||
w = textbox_get_width ( tb );
|
unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0;
|
||||||
|
w = textbox_get_font_width ( tb ) + 2 * config.line_padding + offset;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// set ellipsize
|
// set ellipsize
|
||||||
|
@ -242,12 +261,13 @@ void textbox_moveresize ( textbox *tb, int x, int y, int w, int h )
|
||||||
// We always want to update this
|
// We always want to update this
|
||||||
pango_layout_set_width ( tb->layout, PANGO_SCALE * ( tb->widget.w - 2 * config.line_padding - offset ) );
|
pango_layout_set_width ( tb->layout, PANGO_SCALE * ( tb->widget.w - 2 * config.line_padding - offset ) );
|
||||||
tb->update = TRUE;
|
tb->update = TRUE;
|
||||||
|
widget_need_redraw ( WIDGET ( tb ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// will also unmap the window if still displayed
|
// will also unmap the window if still displayed
|
||||||
static void textbox_free ( Widget *widget )
|
static void textbox_free ( widget *wid )
|
||||||
{
|
{
|
||||||
textbox *tb = (textbox *) widget;
|
textbox *tb = (textbox *) wid;
|
||||||
if ( tb->blink_timeout > 0 ) {
|
if ( tb->blink_timeout > 0 ) {
|
||||||
g_source_remove ( tb->blink_timeout );
|
g_source_remove ( tb->blink_timeout );
|
||||||
tb->blink_timeout = 0;
|
tb->blink_timeout = 0;
|
||||||
|
@ -356,9 +376,9 @@ static void texbox_update ( textbox *tb )
|
||||||
tb->update = FALSE;
|
tb->update = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void textbox_draw ( Widget *widget, cairo_t *draw )
|
static void textbox_draw ( widget *wid, cairo_t *draw )
|
||||||
{
|
{
|
||||||
textbox *tb = (textbox *) widget;
|
textbox *tb = (textbox *) wid;
|
||||||
texbox_update ( tb );
|
texbox_update ( tb );
|
||||||
|
|
||||||
/* Write buffer */
|
/* Write buffer */
|
||||||
|
@ -374,6 +394,7 @@ void textbox_cursor ( textbox *tb, int pos )
|
||||||
int length = ( tb->text == NULL ) ? 0 : g_utf8_strlen ( tb->text, -1 );
|
int length = ( tb->text == NULL ) ? 0 : g_utf8_strlen ( tb->text, -1 );
|
||||||
tb->cursor = MAX ( 0, MIN ( length, pos ) );
|
tb->cursor = MAX ( 0, MIN ( length, pos ) );
|
||||||
tb->update = TRUE;
|
tb->update = TRUE;
|
||||||
|
widget_need_redraw ( WIDGET ( tb ) );
|
||||||
// Stop blink!
|
// Stop blink!
|
||||||
tb->blink = 2;
|
tb->blink = 2;
|
||||||
}
|
}
|
||||||
|
@ -458,10 +479,12 @@ void textbox_cursor_end ( textbox *tb )
|
||||||
if ( tb->text == NULL ) {
|
if ( tb->text == NULL ) {
|
||||||
tb->cursor = 0;
|
tb->cursor = 0;
|
||||||
tb->update = TRUE;
|
tb->update = TRUE;
|
||||||
|
widget_need_redraw ( WIDGET ( tb ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tb->cursor = ( int ) g_utf8_strlen ( tb->text, -1 );
|
tb->cursor = ( int ) g_utf8_strlen ( tb->text, -1 );
|
||||||
tb->update = TRUE;
|
tb->update = TRUE;
|
||||||
|
widget_need_redraw ( WIDGET ( tb ) );
|
||||||
// Stop blink!
|
// Stop blink!
|
||||||
tb->blink = 2;
|
tb->blink = 2;
|
||||||
}
|
}
|
||||||
|
@ -718,12 +741,30 @@ void textbox_cleanup ( void )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int textbox_get_width ( const textbox *tb )
|
int textbox_get_width ( widget *wid )
|
||||||
{
|
{
|
||||||
|
textbox *tb = (textbox *) wid;
|
||||||
|
if ( !wid->expand ) {
|
||||||
|
if ( tb->flags & TB_AUTOWIDTH ) {
|
||||||
unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0;
|
unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0;
|
||||||
return textbox_get_font_width ( tb ) + 2 * config.line_padding + offset;
|
return textbox_get_font_width ( tb ) + 2 * config.line_padding + offset;
|
||||||
}
|
}
|
||||||
|
return tb->widget.w;
|
||||||
|
}
|
||||||
|
return tb->widget.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _textbox_get_height ( widget *wid )
|
||||||
|
{
|
||||||
|
textbox *tb = (textbox *) wid;
|
||||||
|
if ( !wid->expand ) {
|
||||||
|
if ( tb->flags & TB_AUTOHEIGHT ) {
|
||||||
|
return textbox_get_height ( tb );
|
||||||
|
}
|
||||||
|
return tb->widget.h;
|
||||||
|
}
|
||||||
|
return tb->widget.h;
|
||||||
|
}
|
||||||
int textbox_get_height ( const textbox *tb )
|
int textbox_get_height ( const textbox *tb )
|
||||||
{
|
{
|
||||||
return textbox_get_font_height ( tb ) + 2 * config.line_padding;
|
return textbox_get_font_height ( tb ) + 2 * config.line_padding;
|
142
source/widgets/widget.c
Normal file
142
source/widgets/widget.c
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include "widgets/widget.h"
|
||||||
|
|
||||||
|
int widget_intersect ( const widget *widget, int x, int y )
|
||||||
|
{
|
||||||
|
if ( widget == NULL ) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( x >= ( widget->x ) && x < ( widget->x + widget->w ) ) {
|
||||||
|
if ( y >= ( widget->y ) && y < ( widget->y + widget->h ) ) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void widget_resize ( widget *widget, short w, short h )
|
||||||
|
{
|
||||||
|
if ( widget != NULL ) {
|
||||||
|
if ( widget->resize != NULL ) {
|
||||||
|
widget->resize ( widget, w, h );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
widget->w = w;
|
||||||
|
widget->h = h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void widget_move ( widget *widget, short x, short y )
|
||||||
|
{
|
||||||
|
if ( widget != NULL ) {
|
||||||
|
widget->x = x;
|
||||||
|
widget->y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean widget_enabled ( widget *widget )
|
||||||
|
{
|
||||||
|
if ( widget != NULL ) {
|
||||||
|
return widget->enabled;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void widget_enable ( widget *widget )
|
||||||
|
{
|
||||||
|
if ( widget && !widget->enabled ) {
|
||||||
|
widget->enabled = TRUE;
|
||||||
|
widget_update ( widget );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void widget_disable ( widget *widget )
|
||||||
|
{
|
||||||
|
if ( widget && widget->enabled ) {
|
||||||
|
widget->enabled = FALSE;
|
||||||
|
widget_update ( widget );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void widget_draw ( widget *widget, cairo_t *d )
|
||||||
|
{
|
||||||
|
// Check if enabled and if draw is implemented.
|
||||||
|
if ( widget && widget->enabled && widget->draw ) {
|
||||||
|
widget->draw ( widget, d );
|
||||||
|
widget->need_redraw = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void widget_free ( widget *widget )
|
||||||
|
{
|
||||||
|
if ( widget ) {
|
||||||
|
widget->free ( widget );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int widget_get_height ( widget *widget )
|
||||||
|
{
|
||||||
|
if ( widget ) {
|
||||||
|
if ( widget->get_height ) {
|
||||||
|
return widget->get_height ( widget );
|
||||||
|
}
|
||||||
|
return widget->h;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int widget_get_width ( widget *widget )
|
||||||
|
{
|
||||||
|
if ( widget ) {
|
||||||
|
if ( widget->get_width ) {
|
||||||
|
return widget->get_width ( widget );
|
||||||
|
}
|
||||||
|
return widget->w;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void widget_update ( widget *widget )
|
||||||
|
{
|
||||||
|
// When (desired )size of widget changes.
|
||||||
|
if ( widget ) {
|
||||||
|
if ( widget->update ) {
|
||||||
|
widget->update ( widget );
|
||||||
|
}
|
||||||
|
// Recurse back.
|
||||||
|
if ( widget->parent && widget->parent->update ) {
|
||||||
|
widget->parent->update ( widget->parent );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void widget_queue_redraw ( widget *wid )
|
||||||
|
{
|
||||||
|
if ( wid ) {
|
||||||
|
widget *iter = wid;
|
||||||
|
// Find toplevel widget.
|
||||||
|
while ( iter->parent != NULL ) {
|
||||||
|
iter = iter->parent;
|
||||||
|
}
|
||||||
|
iter->need_redraw = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean widget_need_redraw ( widget *wid )
|
||||||
|
{
|
||||||
|
if ( wid ) {
|
||||||
|
return wid->need_redraw;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
gboolean widget_clicked ( widget *wid, xcb_button_press_event_t *xbe )
|
||||||
|
{
|
||||||
|
if ( wid && wid->clicked ) {
|
||||||
|
return wid->clicked ( wid, xbe, wid->clicked_cb_data );
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
void widget_set_clicked_handler ( widget *wid, widget_clicked_cb cb, void *udata )
|
||||||
|
{
|
||||||
|
if ( wid ) {
|
||||||
|
wid->clicked = cb;
|
||||||
|
wid->clicked_cb_data = udata;
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@
|
||||||
#include <history.h>
|
#include <history.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <textbox.h>
|
#include <widgets/textbox.h>
|
||||||
#include <rofi.h>
|
#include <rofi.h>
|
||||||
#include <cairo-xlib.h>
|
#include <cairo-xlib.h>
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
@ -70,10 +70,10 @@ int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )
|
||||||
textbox_cursor_end ( box );
|
textbox_cursor_end ( box );
|
||||||
TASSERT ( box->cursor == 6 );
|
TASSERT ( box->cursor == 6 );
|
||||||
|
|
||||||
TASSERT ( textbox_get_width ( box ) > 0 );
|
TASSERT ( widget_get_width ( WIDGET ( box ) ) > 0 );
|
||||||
TASSERT ( textbox_get_height ( box ) > 0 );
|
TASSERT ( textbox_get_height ( box ) > 0 );
|
||||||
|
|
||||||
TASSERT ( textbox_get_width ( box ) >= textbox_get_font_width ( box ) );
|
TASSERT ( widget_get_width ( WIDGET ( box ) ) >= textbox_get_font_width ( box ) );
|
||||||
TASSERT ( textbox_get_height ( box ) >= textbox_get_font_height ( box ) );
|
TASSERT ( textbox_get_height ( box ) >= textbox_get_font_height ( box ) );
|
||||||
|
|
||||||
TASSERT ( textbox_get_estimated_char_width ( ) > 0 );
|
TASSERT ( textbox_get_estimated_char_width ( ) > 0 );
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <widget.h>
|
#include <widgets/widget.h>
|
||||||
unsigned int test =0;
|
unsigned int test =0;
|
||||||
#define TASSERT( a ) { \
|
#define TASSERT( a ) { \
|
||||||
assert ( a ); \
|
assert ( a ); \
|
||||||
|
@ -16,7 +16,7 @@ unsigned int test =0;
|
||||||
int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )
|
int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )
|
||||||
{
|
{
|
||||||
// box 20 by 40
|
// box 20 by 40
|
||||||
Widget widget = { 10,10,20,40 };
|
widget widget = { 10,10,20,40 };
|
||||||
|
|
||||||
// Left of box
|
// Left of box
|
||||||
TASSERT ( widget_intersect ( &widget, 0, 0) == 0 );
|
TASSERT ( widget_intersect ( &widget, 0, 0) == 0 );
|
||||||
|
|
Loading…
Reference in a new issue