diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index 27b75f49b44..f5a7598bf9e 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -310,8 +310,9 @@ static void text_cursor(wmWindow *win, ScrArea *sa, ARegion *ar) { SpaceText *st = sa->spacedata.first; int wmcursor = BC_TEXTEDITCURSOR; - - if (st->text && BLI_rcti_isect_pt(&st->txtbar, win->eventstate->x - ar->winrct.xmin, st->txtbar.ymin)) { + int x = win->eventstate->x - ar->winrct.xmin; + int y = win->eventstate->y - ar->winrct.ymin; + if (st->text && (BLI_rcti_isect_pt(&st->txtbar, x, st->txtbar.ymin) || (!st->wordwrap && BLI_rcti_isect_pt(&st->htxtbar, st->htxtbar.xmin, y))) ) { wmcursor = CURSOR_STD; } diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index aa499d52589..ab36e48fa96 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -524,7 +524,7 @@ static void text_draw( typedef struct DrawCache { int *line_height; - int total_lines, nlines; + int total_lines, nlines, longest_line_len; /* this is needed to check cache relevance */ int winx, wordwrap, showlinenrs, tabnumber; @@ -542,7 +542,14 @@ static void text_drawcache_init(SpaceText *st) DrawCache *drawcache = MEM_callocN(sizeof(DrawCache), "text draw cache"); drawcache->winx = -1; - drawcache->nlines = BLI_listbase_count(&st->text->lines); + drawcache->nlines = 0; + + TextLine *start = st->text->lines.first; + while (start) { + drawcache->longest_line_len = MAX2(drawcache->longest_line_len, start->len); + drawcache->nlines++; + start = start->next; + } drawcache->text_id[0] = '\0'; st->drawcache = drawcache; @@ -551,7 +558,7 @@ static void text_drawcache_init(SpaceText *st) static void text_update_drawcache(SpaceText *st, ARegion *ar) { DrawCache *drawcache; - int full_update = 0, nlines = 0; + int full_update = 0, nlines = 0, longest_line_len = 0; Text *txt = st->text; if (!st->drawcache) text_drawcache_init(st); @@ -560,6 +567,7 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar) drawcache = (DrawCache *)st->drawcache; nlines = drawcache->nlines; + longest_line_len = drawcache->longest_line_len; /* check if full cache update is needed */ full_update |= drawcache->winx != ar->winx; /* area was resized */ @@ -628,12 +636,21 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar) } if (full_update || drawcache->update_flag) { - nlines = BLI_listbase_count(&txt->lines); + nlines = 0; + longest_line_len = 0; + + TextLine *start = st->text->lines.first; + while (start) { + longest_line_len = MAX2(longest_line_len, start->len); + nlines++; + start = start->next; + } if (st->showlinenrs) st->linenrs_tot = integer_digits_i(nlines); } + drawcache->longest_line_len = longest_line_len; drawcache->total_lines = nlines; } @@ -790,6 +807,15 @@ int text_get_total_lines(SpaceText *st, ARegion *ar) return drawcache->total_lines; } +int text_get_longest_line_length(SpaceText *st, ARegion *ar) +{ + DrawCache *drawcache; + text_update_drawcache(st, ar); + drawcache = st->drawcache; + + return drawcache->longest_line_len; +} + /************************ draw scrollbar *****************************/ static void calc_text_rcts(SpaceText *st, ARegion *ar, rcti *scroll, rcti *back) @@ -837,8 +863,8 @@ static void calc_text_rcts(SpaceText *st, ARegion *ar, rcti *scroll, rcti *back) CLAMP(st->txtbar.ymin, pix_bottom_margin, ar->winy - pix_top_margin); CLAMP(st->txtbar.ymax, pix_bottom_margin, ar->winy - pix_top_margin); - st->pix_per_line = (pix_available > 0) ? (float) ltexth / pix_available : 0; - if (st->pix_per_line < 0.1f) st->pix_per_line = 0.1f; + st->bar_pix_per_line = (pix_available > 0) ? (float) ltexth / pix_available : 0; + if (st->bar_pix_per_line < 0.1f) st->bar_pix_per_line = 0.1f; curl_off = text_get_span_wrap(st, ar, st->text->lines.first, st->text->curl); sell_off = text_get_span_wrap(st, ar, st->text->lines.first, st->text->sell); @@ -905,7 +931,56 @@ static void calc_text_rcts(SpaceText *st, ARegion *ar, rcti *scroll, rcti *back) CLAMP(st->txtscroll.ymax, pix_bottom_margin, ar->winy - pix_top_margin); } -static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back) +static void calc_horizontal_text_rcts(SpaceText *st, ARegion *ar, rcti *hscroll, rcti *hback) +{ + int longest_line_len; + short barlength, barstart, view_line_len, blank_chars; + short pix_available, pix_left_margin, pix_right_margin, pix_bardiff; + + pix_left_margin = 8; + pix_right_margin = 4; + pix_available = ar->winx - pix_left_margin - pix_right_margin; + longest_line_len = text_get_longest_line_length(st, ar); + view_line_len = wrap_width(st, ar); + blank_chars = view_line_len / 2; + + /* nicer code: use scroll rect for entire bar */ + hback->xmin = 0; + hback->xmax = ar->winx; + hback->ymin = 0; + hback->ymax = (V2D_SCROLL_WIDTH + 1); + + hscroll->xmin = 4; + hscroll->xmax = 4 + pix_available; + hscroll->ymin = 5; + hscroll->ymax = V2D_SCROLL_WIDTH; + + if (longest_line_len + blank_chars < st->left + view_line_len) { + blank_chars = st->left + view_line_len - longest_line_len; + } + + longest_line_len += blank_chars; + + barlength = (longest_line_len > 0) ? (view_line_len * pix_available) / longest_line_len : 0; + pix_bardiff = 0; + if (barlength < 20) { + pix_bardiff = 20 - barlength; /* take into account the now non-linear sizing of the bar */ + barlength = 20; + } + barstart = (longest_line_len > 0) ? ((pix_available - pix_bardiff) * st->left) / longest_line_len : 0; + + st->htxtbar = *hscroll; + st->htxtbar.xmin += barstart; + st->htxtbar.xmax = st->htxtbar.xmin + barlength; + + CLAMP(st->htxtbar.xmin, pix_right_margin, ar->winx - pix_left_margin); + CLAMP(st->htxtbar.xmax, pix_right_margin, ar->winx - pix_left_margin); + + st->bar_pix_per_col = (pix_available > 0) ? (float)longest_line_len / pix_available : 0; + if (st->bar_pix_per_col < 0.1f) st->bar_pix_per_col = 0.1f; +} + +static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back, rcti *txtbar, bool highlighting) { bTheme *btheme = UI_GetTheme(); uiWidgetColors wcol = btheme->tui.wcol_scroll; @@ -919,13 +994,16 @@ static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back) immRecti(pos, back->xmin, back->ymin, back->xmax, back->ymax); immUnbindProgram(); - UI_draw_widget_scroll(&wcol, scroll, &st->txtbar, (st->flags & ST_SCROLL_SELECT) ? UI_SCROLL_PRESSED : 0); + UI_draw_widget_scroll(&wcol, scroll, txtbar, (st->flags & ST_SCROLL_SELECT) ? UI_SCROLL_PRESSED : 0); - UI_draw_roundbox_corner_set(UI_CNR_ALL); - rad = 0.4f * min_ii(BLI_rcti_size_x(&st->txtscroll), BLI_rcti_size_y(&st->txtscroll)); - UI_GetThemeColor3fv(TH_HILITE, col); - col[3] = 0.18f; - UI_draw_roundbox_aa(true, st->txtscroll.xmin + 1, st->txtscroll.ymin, st->txtscroll.xmax - 1, st->txtscroll.ymax, rad, col); + if (highlighting) + { + UI_draw_roundbox_corner_set(UI_CNR_ALL); + rad = 0.4f * min_ii(BLI_rcti_size_x(&st->txtscroll), BLI_rcti_size_y(&st->txtscroll)); + UI_GetThemeColor3fv(TH_HILITE, col); + col[3] = 0.18f; + UI_draw_roundbox_aa(true, st->txtscroll.xmin + 1, st->txtscroll.ymin, st->txtscroll.xmax - 1, st->txtscroll.ymax, rad, col); + } } /*********************** draw documentation *******************************/ @@ -1376,6 +1454,7 @@ void draw_text_main(SpaceText *st, ARegion *ar) TextFormatType *tft; TextLine *tmp; rcti scroll, back; + rcti hscroll, hback; char linenr[12]; int i, x, y, winx, linecount = 0, lineno = 0; int wraplinecount = 0, wrap_skip = 0; @@ -1403,6 +1482,7 @@ void draw_text_main(SpaceText *st, ARegion *ar) /* update rects for scroll */ calc_text_rcts(st, ar, &scroll, &back); /* scroll will hold the entire bar size */ + calc_horizontal_text_rcts(st, ar, &hscroll, &hback); /* update syntax formatting if needed */ tft = ED_text_format_get(text); @@ -1525,7 +1605,9 @@ void draw_text_main(SpaceText *st, ARegion *ar) /* draw other stuff */ draw_brackets(st, &tdc, ar); - draw_textscroll(st, &scroll, &back); + draw_textscroll(st, &scroll, &back, &st->txtbar, true); + if (!st->wordwrap) + draw_textscroll(st, &hscroll, &hback, &st->htxtbar, false); /* draw_documentation(st, ar); - No longer supported */ draw_suggestion_list(st, &tdc, ar); diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h index 02948d35623..af991ef7b11 100644 --- a/source/blender/editors/space_text/text_intern.h +++ b/source/blender/editors/space_text/text_intern.h @@ -79,6 +79,7 @@ void text_pop_suggest_list(void); int text_get_visible_lines(const struct SpaceText *st, struct ARegion *ar, const char *str); int text_get_span_wrap(const struct SpaceText *st, struct ARegion *ar, struct TextLine *from, struct TextLine *to); int text_get_total_lines(struct SpaceText *st, struct ARegion *ar); +int text_get_longest_line_length(struct SpaceText *st, struct ARegion *ar); /* text_ops.c */ enum { LINE_BEGIN, LINE_END, FILE_TOP, FILE_BOTTOM, PREV_CHAR, NEXT_CHAR, diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 61c7b479826..e2a55986825 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -2116,6 +2116,18 @@ static void txt_screen_clamp(SpaceText *st, ARegion *ar) st->top = last; } } + + if (st->wordwrap || st->left < 0) { + st->left = 0; + } + else { + int last; + last = text_get_longest_line_length(st, ar); + last = last - (wrap_width(st, ar) / 2); + if (last > 0 && st->left > last) { + st->left = last; + } + } } /* Moves the view vertically by the specified number of lines */ @@ -2125,6 +2137,13 @@ static void txt_screen_skip(SpaceText *st, ARegion *ar, int lines) txt_screen_clamp(st, ar); } +/* Moves the view horizontally by the specified number of columns */ +static void txt_screen_horizontal_skip(SpaceText *st, ARegion *ar, int cols) +{ + st->left += cols; + txt_screen_clamp(st, ar); +} + /* quick enum for tsc->zone (scroller handles) */ enum { SCROLLHANDLE_BAR, @@ -2132,6 +2151,12 @@ enum { SCROLLHANDLE_MAX_OUTSIDE }; +enum { + SCROLL_HORIZONTAL, + SCROLL_VERTICAL, + SCROLL_BOTH +}; + typedef struct TextScroll { int old[2]; int delta[2]; @@ -2140,6 +2165,7 @@ typedef struct TextScroll { int scrollbar; int zone; + int direction; } TextScroll; static bool text_scroll_poll(bContext *C) @@ -2194,7 +2220,8 @@ static void text_scroll_apply(bContext *C, wmOperator *op, const wmEvent *event) st->scroll_accum[1] += tsc->delta[1] / (float)(st->lheight_dpi + TXT_LINE_SPACING); } else { - st->scroll_accum[1] += -tsc->delta[1] * st->pix_per_line; + st->scroll_accum[0] += tsc->delta[0] * st->bar_pix_per_col; + st->scroll_accum[1] += -tsc->delta[1] * st->bar_pix_per_line; } /* round to number of lines to scroll */ @@ -2206,15 +2233,10 @@ static void text_scroll_apply(bContext *C, wmOperator *op, const wmEvent *event) /* perform vertical and/or horizontal scroll */ if (scroll_steps[0] || scroll_steps[1]) { - txt_screen_skip(st, ar, scroll_steps[1]); - - if (st->wordwrap) { - st->left = 0; - } - else { - st->left += scroll_steps[0]; - if (st->left < 0) st->left = 0; - } + if (ELEM(tsc->direction, SCROLL_VERTICAL, SCROLL_BOTH)) + txt_screen_skip(st, ar, scroll_steps[1]); + if (ELEM(tsc->direction, SCROLL_HORIZONTAL, SCROLL_BOTH)) + txt_screen_horizontal_skip(st, ar, scroll_steps[0]); ED_area_tag_redraw(CTX_wm_area(C)); } @@ -2247,8 +2269,10 @@ static int text_scroll_modal(bContext *C, wmOperator *op, const wmEvent *event) case MIDDLEMOUSE: if (event->val == KM_RELEASE) { if (ELEM(tsc->zone, SCROLLHANDLE_MIN_OUTSIDE, SCROLLHANDLE_MAX_OUTSIDE)) { - txt_screen_skip(st, ar, st->viewlines * (tsc->zone == SCROLLHANDLE_MIN_OUTSIDE ? 1 : -1)); - + if (ELEM(tsc->direction, SCROLL_VERTICAL, SCROLL_BOTH)) + txt_screen_skip(st, ar, st->viewlines * (tsc->zone == SCROLLHANDLE_MIN_OUTSIDE ? 1 : -1)); + if (ELEM(tsc->direction, SCROLL_HORIZONTAL, SCROLL_BOTH)) + txt_screen_horizontal_skip(st, ar, -1 * wrap_width(st, ar) * (tsc->zone == SCROLLHANDLE_MIN_OUTSIDE ? 1 : -1)); ED_area_tag_redraw(CTX_wm_area(C)); } scroll_exit(C, op); @@ -2275,6 +2299,7 @@ static int text_scroll_invoke(bContext *C, wmOperator *op, const wmEvent *event) tsc = MEM_callocN(sizeof(TextScroll), "TextScroll"); tsc->first = 1; tsc->zone = SCROLLHANDLE_BAR; + tsc->direction = SCROLL_BOTH; op->customdata = tsc; st->flags |= ST_SCROLL_SELECT; @@ -2347,12 +2372,24 @@ static int text_scroll_bar_invoke(bContext *C, wmOperator *op, const wmEvent *ev TextScroll *tsc; const int *mval = event->mval; int zone = -1; + int direction = -1; if (RNA_struct_property_is_set(op->ptr, "lines")) return text_scroll_exec(C, op); - /* verify we are in the right zone */ + /* verify we are in the right zone - and check which zone */ + if (mval[1] > st->htxtbar.ymin && mval[1] < st->htxtbar.ymax) { + direction = SCROLL_HORIZONTAL; + if (mval[0] >= st->htxtbar.xmin && mval[0] <= st->htxtbar.xmax) { + zone = SCROLLHANDLE_BAR; + } + else if (mval[0] > TXT_SCROLL_SPACE && mval[0] < ar->winx - TXT_SCROLL_SPACE) { + if (mval[0] < st->htxtbar.xmin) zone = SCROLLHANDLE_MIN_OUTSIDE; + else zone = SCROLLHANDLE_MAX_OUTSIDE; + } + } if (mval[0] > st->txtbar.xmin && mval[0] < st->txtbar.xmax) { + direction = SCROLL_VERTICAL; if (mval[1] >= st->txtbar.ymin && mval[1] <= st->txtbar.ymax) { /* mouse inside scroll handle */ zone = SCROLLHANDLE_BAR; @@ -2372,13 +2409,20 @@ static int text_scroll_bar_invoke(bContext *C, wmOperator *op, const wmEvent *ev tsc->first = 1; tsc->scrollbar = 1; tsc->zone = zone; + tsc->direction = direction; op->customdata = tsc; st->flags |= ST_SCROLL_SELECT; /* jump scroll, works in v2d but needs to be added here too :S */ if (event->type == MIDDLEMOUSE) { - tsc->old[0] = ar->winrct.xmin + BLI_rcti_cent_x(&st->txtbar); - tsc->old[1] = ar->winrct.ymin + BLI_rcti_cent_y(&st->txtbar); + if (tsc->direction == SCROLL_HORIZONTAL) { + tsc->old[0] = ar->winrct.xmin + BLI_rcti_cent_x(&st->htxtbar); + tsc->old[1] = ar->winrct.ymin + BLI_rcti_cent_y(&st->htxtbar); + } + else { + tsc->old[0] = ar->winrct.xmin + BLI_rcti_cent_x(&st->txtbar); + tsc->old[1] = ar->winrct.ymin + BLI_rcti_cent_y(&st->txtbar); + } tsc->first = 0; tsc->zone = SCROLLHANDLE_BAR; @@ -2727,7 +2771,7 @@ static int text_set_selection_invoke(bContext *C, wmOperator *op, const wmEvent SpaceText *st = CTX_wm_space_text(C); SetSelection *ssel; - if (event->mval[0] >= st->txtbar.xmin) + if (event->mval[0] >= st->txtbar.xmin || (!st->wordwrap && event->mval[1] <= st->htxtbar.ymax)) return OPERATOR_PASS_THROUGH; op->customdata = MEM_callocN(sizeof(SetSelection), "SetCursor"); @@ -2807,7 +2851,7 @@ static int text_cursor_set_invoke(bContext *C, wmOperator *op, const wmEvent *ev { SpaceText *st = CTX_wm_space_text(C); - if (event->mval[0] >= st->txtbar.xmin) + if (event->mval[0] >= st->txtbar.xmin || (!st->wordwrap && event->mval[1] <= st->htxtbar.ymax)) return OPERATOR_PASS_THROUGH; RNA_int_set(op->ptr, "x", event->mval[0]); diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 43781c47828..77f8cbbd650 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1039,9 +1039,10 @@ typedef struct SpaceText { short line_hlight; short overwrite; short live_edit; /* run python while editing, evil */ - float pix_per_line; + float bar_pix_per_line; struct rcti txtscroll, txtbar; + struct rcti htxtbar; int wordwrap, doplugins; @@ -1050,7 +1051,7 @@ typedef struct SpaceText { short margin_column; /* column number to show right margin at */ short lheight_dpi; /* actual lineheight, dpi controlled */ - char pad[4]; + float bar_pix_per_col; void *drawcache; /* cache for faster drawing */