From f6b7a380df24d131c75ea5a57e4f256261da9934 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Thu, 29 Jan 2015 00:36:28 +0000 Subject: [PATCH] elm_code: initial work on line numbers --- elm_code/bin/elm_code_test_main.c | 7 +-- elm_code/lib/Elm_Code.h | 1 + elm_code/lib/Makefile.am | 1 + elm_code/lib/elm_code_private.h | 14 ++++++ elm_code/lib/elm_code_widget.c | 73 +++++++++++++++++------------ elm_code/lib/elm_code_widget.eo | 20 ++++++++ elm_code/lib/elm_code_widget.eo.c | 10 ++++ elm_code/lib/elm_code_widget.eo.h | 29 ++++++++++-- elm_code/lib/elm_code_widget_text.c | 35 ++++++++++++++ elm_code/lib/elm_code_widget_text.h | 30 ++++++++++++ 10 files changed, 183 insertions(+), 37 deletions(-) create mode 100644 elm_code/lib/elm_code_widget_text.c create mode 100644 elm_code/lib/elm_code_widget_text.h diff --git a/elm_code/bin/elm_code_test_main.c b/elm_code/bin/elm_code_test_main.c index 2897c3c..b15bea8 100644 --- a/elm_code/bin/elm_code_test_main.c +++ b/elm_code/bin/elm_code_test_main.c @@ -53,9 +53,10 @@ _elm_code_test_welcome_setup(Evas_Object *parent) code = elm_code_create(); widget = eo_add(ELM_CODE_WIDGET_CLASS, parent); eo_do(widget, - elm_code_widget_code_set(code); - elm_code_widget_font_size_set(14); - elm_code_widget_editable_set(EINA_TRUE); + elm_code_widget_code_set(code), + elm_code_widget_font_size_set(14), + elm_code_widget_editable_set(EINA_TRUE), + elm_code_widget_line_numbers_set(EINA_TRUE), eo_event_callback_add(ELM_CODE_WIDGET_EVENT_LINE_CLICKED, _elm_code_test_line_cb, code)); _append_line(code->file, "Hello World, Elm Code!"); diff --git a/elm_code/lib/Elm_Code.h b/elm_code/lib/Elm_Code.h index 016f315..d60f2f4 100644 --- a/elm_code/lib/Elm_Code.h +++ b/elm_code/lib/Elm_Code.h @@ -37,6 +37,7 @@ #include "elm_code_file.h" #include "elm_code_parse.h" #include "elm_code_widget.eo.h" +#include "elm_code_widget_text.h" #include "elm_code_diff_widget.h" #ifdef __cplusplus diff --git a/elm_code/lib/Makefile.am b/elm_code/lib/Makefile.am index 447e052..932696a 100644 --- a/elm_code/lib/Makefile.am +++ b/elm_code/lib/Makefile.am @@ -20,6 +20,7 @@ includesdir = $(includedir)/edi-@VMAJ@ libelm_code_la_SOURCES = \ elm_code_file.c \ elm_code_parse.c \ +elm_code_widget_text.c \ elm_code_widget.c \ elm_code_diff_widget.c \ elm_code.c \ diff --git a/elm_code/lib/elm_code_private.h b/elm_code/lib/elm_code_private.h index d1ff328..c464d95 100644 --- a/elm_code/lib/elm_code_private.h +++ b/elm_code/lib/elm_code_private.h @@ -25,3 +25,17 @@ extern int _elm_code_lib_log_dom; #define DBG(...) EINA_LOG_DOM_DBG(_elm_code_lib_log_dom, __VA_ARGS__) #endif + +typedef struct +{ + Elm_Code *code; + Evas_Object *grid, *scroller; + + Evas_Font_Size font_size; + double gravity_x, gravity_y; + + unsigned int cursor_line, cursor_col; + Eina_Bool cursor_move_vetoed; + Eina_Bool editable, focussed; + Eina_Bool show_line_numbers; +} Elm_Code_Widget_Data; diff --git a/elm_code/lib/elm_code_widget.c b/elm_code/lib/elm_code_widget.c index 1dcd351..2a3cb36 100644 --- a/elm_code/lib/elm_code_widget.c +++ b/elm_code/lib/elm_code_widget.c @@ -5,19 +5,6 @@ #include #include "elm_code_private.h" -typedef struct -{ - Elm_Code *code; - Evas_Object *grid, *scroller; - - Evas_Font_Size font_size; - double gravity_x, gravity_y; - - unsigned int cursor_line, cursor_col; - Eina_Bool cursor_move_vetoed; - Eina_Bool editable, focussed; -} Elm_Code_Widget_Data; - Eina_Unicode status_icons[] = { ' ', '!', @@ -69,10 +56,11 @@ _elm_code_widget_resize(Elm_Code_Widget *widget) Elm_Code_Line *line; Eina_List *item; Evas_Coord ww, wh, old_width, old_height; - int w, h, cw, ch; + int w, h, cw, ch, gutter; Elm_Code_Widget_Data *pd; pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS); + gutter = elm_code_widget_text_left_gutter_width_get(widget); if (!pd->code) return EINA_FALSE; @@ -85,8 +73,8 @@ _elm_code_widget_resize(Elm_Code_Widget *widget) w = 0; h = elm_code_file_lines_get(pd->code->file); EINA_LIST_FOREACH(pd->code->file->lines, item, line) - if (line->length + 2 > w) - w = line->length + 2; + if (line->length + gutter + 1 > w) + w = line->length + gutter + 1; if (w*cw > ww) ww = w*cw; @@ -116,24 +104,26 @@ _elm_code_widget_fill_line_token(Evas_Textgrid_Cell *cells, int count, int start } static void -_elm_code_widget_fill_line_tokens(Evas_Textgrid_Cell *cells, unsigned int count, Elm_Code_Line *line) +_elm_code_widget_fill_line_tokens(Elm_Code_Widget *widget, Evas_Textgrid_Cell *cells, + unsigned int count, Elm_Code_Line *line) { Eina_List *item; Elm_Code_Token *token; - int start, length; + int start, length, offset; - start = 1; - length = line->length; + offset = elm_code_widget_text_left_gutter_width_get(widget) - 1; + start = offset + 1; + length = line->length + offset; EINA_LIST_FOREACH(line->tokens, item, token) { - _elm_code_widget_fill_line_token(cells, count, start, token->start, ELM_CODE_TOKEN_TYPE_DEFAULT); + _elm_code_widget_fill_line_token(cells, count, start, token->start + offset, ELM_CODE_TOKEN_TYPE_DEFAULT); // TODO handle a token starting before the previous finishes - _elm_code_widget_fill_line_token(cells, count, token->start, token->end, token->type); + _elm_code_widget_fill_line_token(cells, count, token->start + offset, token->end + offset, token->type); - start = token->end + 1; + start = token->end + offset + 1; } _elm_code_widget_fill_line_token(cells, count, start, length, ELM_CODE_TOKEN_TYPE_DEFAULT); @@ -144,10 +134,11 @@ _elm_code_widget_fill_line(Elm_Code_Widget *widget, Evas_Textgrid_Cell *cells, E { char *chr; unsigned int length, x; - int w; + int w, gutter, g; Elm_Code_Widget_Data *pd; pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS); + gutter = elm_code_widget_text_left_gutter_width_get(widget); if (!_elm_code_widget_resize(widget)) return; @@ -160,11 +151,19 @@ _elm_code_widget_fill_line(Elm_Code_Widget *widget, Evas_Textgrid_Cell *cells, E cells[0].fg = ELM_CODE_TOKEN_TYPE_DEFAULT; cells[0].bg = line->status; + for (g = 1; g < gutter; g++) + { +// TODO figure what our actual line number is as a string! (of length g) + cells[g].codepoint = (g == gutter - 1) ? '|' : '_'; + cells[g].fg = ELM_CODE_TOKEN_TYPE_DEFAULT; + cells[g].bg = ELM_CODE_STATUS_TYPE_DEFAULT; + } + if (line->modified) chr = line->modified; else chr = (char *)line->content; - for (x = 1; x < (unsigned int) w && x <= length; x++) + for (x = gutter; x < (unsigned int) w && x < length + gutter; x++) { cells[x].codepoint = *chr; cells[x].bg = line->status; @@ -177,11 +176,11 @@ _elm_code_widget_fill_line(Elm_Code_Widget *widget, Evas_Textgrid_Cell *cells, E cells[x].bg = line->status; } - _elm_code_widget_fill_line_tokens(cells, w, line); + _elm_code_widget_fill_line_tokens(widget, cells, w, line); if (pd->editable && pd->focussed && pd->cursor_line == line->number) { - if (pd->cursor_col < (unsigned int) w) - cells[pd->cursor_col].bg = ELM_CODE_TOKEN_TYPE_CURSOR; + if (pd->cursor_col + gutter - 1 < (unsigned int) w) + cells[pd->cursor_col + gutter - 1].bg = ELM_CODE_TOKEN_TYPE_CURSOR; } evas_object_textgrid_update_add(pd->grid, 0, line->number - 1, w, 1); @@ -269,7 +268,7 @@ _elm_code_widget_clicked_editable_cb(Elm_Code_Widget *widget, Evas_Coord x, Evas pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS); evas_object_textgrid_cell_size_get(pd->grid, &cw, &ch); - col = ((double) x / cw) + 2; + col = ((double) x / cw) - elm_code_widget_text_left_gutter_width_get(widget) + 1; row = ((double) y / ch) + 1; line = elm_code_file_line_get(pd->code->file, row); @@ -277,8 +276,8 @@ _elm_code_widget_clicked_editable_cb(Elm_Code_Widget *widget, Evas_Coord x, Evas { pd->cursor_line = row; - if (col <= (unsigned int) line->length + 2) - pd->cursor_col = col - 2; + if (col <= (unsigned int) line->length + 1) + pd->cursor_col = col; else pd->cursor_col = line->length + 1; } @@ -571,6 +570,18 @@ _elm_code_widget_editable_get(Eo *obj EINA_UNUSED, Elm_Code_Widget_Data *pd) return pd->editable; } +EOLIAN static void +_elm_code_widget_line_numbers_set(Eo *obj EINA_UNUSED, Elm_Code_Widget_Data *pd, Eina_Bool line_numbers) +{ + pd->show_line_numbers = line_numbers; +} + +EOLIAN static Eina_Bool +_elm_code_widget_line_numbers_get(Eo *obj EINA_UNUSED, Elm_Code_Widget_Data *pd) +{ + return pd->show_line_numbers; +} + static void _elm_code_widget_setup_palette(Evas_Object *o) { diff --git a/elm_code/lib/elm_code_widget.eo b/elm_code/lib/elm_code_widget.eo index 804b40e..2d92386 100644 --- a/elm_code/lib/elm_code_widget.eo +++ b/elm_code/lib/elm_code_widget.eo @@ -84,6 +84,26 @@ class Elm_Code_Widget (Elm_Box, Elm_Interface_Scrollable, Eina_Bool editable; /*@ The editable state of the widget */ } } + line_numbers { + set { + /*@ + Set whether line numbers should be displayed in the left gutter. + + Passing EINA_TRUE will reserve a space for showing line numbers, + EINA_FALSE will turn this off. + + @ingroup Features */ + } + get { + /*@ + Get the status of line number display for this widget. + + @ingroup Features */ + } + values { + Eina_Bool line_numbers; /*@ Whether or not line numbers (or their placeholder) should be shown */ + } + } } methods { } diff --git a/elm_code/lib/elm_code_widget.eo.c b/elm_code/lib/elm_code_widget.eo.c index ed7092f..0affce2 100644 --- a/elm_code/lib/elm_code_widget.eo.c +++ b/elm_code/lib/elm_code_widget.eo.c @@ -33,6 +33,14 @@ Eina_Bool _elm_code_widget_editable_get(Eo *obj, Elm_Code_Widget_Data *pd); EOAPI EO_FUNC_BODY(elm_code_widget_editable_get, Eina_Bool, 0); +void _elm_code_widget_line_numbers_set(Eo *obj, Elm_Code_Widget_Data *pd, Eina_Bool line_numbers); + +EOAPI EO_VOID_FUNC_BODYV(elm_code_widget_line_numbers_set, EO_FUNC_CALL(line_numbers), Eina_Bool line_numbers); + +Eina_Bool _elm_code_widget_line_numbers_get(Eo *obj, Elm_Code_Widget_Data *pd); + +EOAPI EO_FUNC_BODY(elm_code_widget_line_numbers_get, Eina_Bool, 0); + void _elm_code_widget_eo_base_constructor(Eo *obj, Elm_Code_Widget_Data *pd); @@ -58,6 +66,8 @@ static Eo_Op_Description _elm_code_widget_op_desc[] = { EO_OP_FUNC(elm_code_widget_gravity_get, _elm_code_widget_gravity_get, "Get the current x and y gravity of the widget's scroller"), EO_OP_FUNC(elm_code_widget_editable_set, _elm_code_widget_editable_set, "Set whether this widget allows editing"), EO_OP_FUNC(elm_code_widget_editable_get, _elm_code_widget_editable_get, "Get the current editable state of this widget"), + EO_OP_FUNC(elm_code_widget_line_numbers_set, _elm_code_widget_line_numbers_set, "Set whether line numbers should be displayed in the left gutter."), + EO_OP_FUNC(elm_code_widget_line_numbers_get, _elm_code_widget_line_numbers_get, "Get the status of line number display for this widget."), EO_OP_SENTINEL }; diff --git a/elm_code/lib/elm_code_widget.eo.h b/elm_code/lib/elm_code_widget.eo.h index 8dadcc0..2730ddd 100644 --- a/elm_code/lib/elm_code_widget.eo.h +++ b/elm_code/lib/elm_code_widget.eo.h @@ -63,8 +63,7 @@ EOAPI Evas_Font_Size elm_code_widget_font_size_get(void); * * Set how this widget's scroller should respond to new lines being added. * - * An x value of 0.0 will maintain the distance from the left edge, 1.0 - will ensure the rightmost edge (of the longest line) is respected + * An x value of 0.0 will maintain the distance from the left edge, 1.0 will ensure the rightmost edge (of the longest line) is respected * With 0.0 for y the view will keep it's position relative to the top whereas 1.0 will scroll downward as lines are added. * * @ingroup Layout @@ -81,7 +80,7 @@ EOAPI void elm_code_widget_gravity_set(double x, double y); * * @ingroup Layout * - * @param[out] x The horizontal value of the scroller gravity, currently ignored + * @param[out] x The horizontal value of the scroller gravity - valid values are 0.0 and 1.0 * @param[out] y The vertical gravity of the widget's scroller - valid values are 0.0 and 1.0 * */ @@ -117,6 +116,30 @@ EOAPI void elm_code_widget_editable_set(Eina_Bool editable); */ EOAPI Eina_Bool elm_code_widget_editable_get(void); +/** + * + * Set whether line numbers should be displayed in the left gutter. + * + * Passing EINA_TRUE will reserve a space for showing line numbers, + * EINA_FALSE will turn this off. + * + * @ingroup Features + * + * @param[in] line_numbers Whether or not line numbers (or their placeholder) should be shown + * + */ +EOAPI void elm_code_widget_line_numbers_set(Eina_Bool line_numbers); + +/** + * + * Get the status of line number display for this widget. + * + * @ingroup Features + * + * + */ +EOAPI Eina_Bool elm_code_widget_line_numbers_get(void); + EOAPI extern const Eo_Event_Description _ELM_CODE_WIDGET_EVENT_LINE_CLICKED; /** diff --git a/elm_code/lib/elm_code_widget_text.c b/elm_code/lib/elm_code_widget_text.c new file mode 100644 index 0000000..53d2ef5 --- /dev/null +++ b/elm_code/lib/elm_code_widget_text.c @@ -0,0 +1,35 @@ +#ifdef HAVE_CONFIG +# include "config.h" +#endif + +#include "Elm_Code.h" + +#include "elm_code_private.h" + +EAPI int +elm_code_widget_text_line_number_width_get(Elm_Code_Widget *widget) +{ + Elm_Code_Widget_Data *pd; + int max; + + pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS); + max = elm_code_file_lines_get(pd->code->file); + if (max < 1) + max = 1; + + return ceil(log10(max)); +} + +EAPI int +elm_code_widget_text_left_gutter_width_get(Elm_Code_Widget *widget) +{ + Elm_Code_Widget_Data *pd; + int width = 1; // the status icon, for now + + pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS); + + if (pd->show_line_numbers) + width += elm_code_widget_text_line_number_width_get(widget) + 1; + + return width; +} diff --git a/elm_code/lib/elm_code_widget_text.h b/elm_code/lib/elm_code_widget_text.h new file mode 100644 index 0000000..5ac983e --- /dev/null +++ b/elm_code/lib/elm_code_widget_text.h @@ -0,0 +1,30 @@ +#ifndef ELM_CODE_WIDGET_TEXT_H_ +# define ELM_CODE_WIDGET_TEXT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Text layout handling functions. + * @defgroup Managing the complexities of layout out text in an Elm_Code_Widget + * + * @{ + * + * Functions for text layout handling + * + */ + +EAPI int elm_code_widget_text_left_gutter_width_get(Elm_Code_Widget *widget); + +EAPI int elm_code_widget_text_line_number_width_get(Elm_Code_Widget *widget); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ELM_CODE_WIDGET_TEXT_H_ */