Blender  V3.3
textview.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "MEM_guardedalloc.h"
8 
9 #include "BLF_api.h"
10 
11 #include "BLI_math.h"
12 #include "BLI_string_utf8.h"
13 #include "BLI_utildefines.h"
14 
15 #include "GPU_immediate.h"
16 #include "GPU_state.h"
17 
18 #include "DNA_userdef_types.h" /* For 'U.dpi_fac' */
19 
20 #include "UI_interface.h"
21 #include "UI_interface_icons.h"
22 
23 #include "textview.h"
24 
25 static void textview_font_begin(const int font_id, const int lheight)
26 {
27  /* Font size in relation to line height. */
28  BLF_size(font_id, 0.8f * lheight, 72);
29 }
30 
31 typedef struct TextViewDrawState {
32  int font_id;
33  int cwidth;
34  int lheight;
36  int lofs;
39  int columns;
41  const rcti *draw_rect;
45  int *xy; // [2]
46  int *sel; // [2]
47  /* Bottom of view == 0, top of file == combine chars, end of line is lower than start. */
49  const int *mval; // [2]
50  bool do_draw;
52 
54 {
55  tds->sel[0] += step;
56  tds->sel[1] += step;
57 }
58 
59 static void textview_draw_sel(const char *str,
60  const int xy[2],
61  const int str_len_draw,
62  TextViewDrawState *tds,
63  const uchar bg_sel[4])
64 {
65  const int sel[2] = {tds->sel[0], tds->sel[1]};
66  const int cwidth = tds->cwidth;
67  const int lheight = tds->lheight;
68 
69  if (sel[0] <= str_len_draw && sel[1] >= 0) {
70  const int sta = BLI_str_utf8_offset_to_column(str, max_ii(sel[0], 0));
71  const int end = BLI_str_utf8_offset_to_column(str, min_ii(sel[1], str_len_draw));
72 
74 
78 
79  immUniformColor4ubv(bg_sel);
80  immRecti(pos, xy[0] + (cwidth * sta), xy[1] + lheight, xy[0] + (cwidth * end), xy[1]);
81 
83 
85  }
86 }
87 
93  const char *str, int len, int width, int *r_lines, int **r_offsets)
94 {
95  int i, end; /* Offset as unicode code-point. */
96  int j; /* Offset as bytes. */
97 
98  *r_lines = 1;
99 
100  *r_offsets = MEM_callocN(
101  sizeof(**r_offsets) *
102  (len * BLI_UTF8_WIDTH_MAX / MAX2(1, width - (BLI_UTF8_WIDTH_MAX - 1)) + 1),
103  __func__);
104  (*r_offsets)[0] = 0;
105 
106  for (i = 0, end = width, j = 0; j < len && str[j]; j += BLI_str_utf8_size_safe(str + j)) {
107  int columns = BLI_str_utf8_char_width_safe(str + j);
108 
109  if (i + columns > end) {
110  (*r_offsets)[*r_lines] = j;
111  (*r_lines)++;
112 
113  end = i + width;
114  }
115  i += columns;
116  }
117  return j;
118 }
119 
125  const char *str,
126  int str_len,
127  const uchar fg[4],
128  const uchar bg[4],
129  int icon,
130  const uchar icon_fg[4],
131  const uchar icon_bg[4],
132  const uchar bg_sel[4])
133 {
134  int tot_lines; /* Total number of lines for wrapping. */
135  int *offsets; /* Offsets of line beginnings for wrapping. */
136 
137  str_len = textview_wrap_offsets(str, str_len, tds->columns, &tot_lines, &offsets);
138 
139  int line_height = (tot_lines * tds->lheight) + (tds->row_vpadding * 2);
140  int line_bottom = tds->xy[1];
141  int line_top = line_bottom + line_height;
142 
143  int y_next = line_top;
144 
145  /* Just advance the height. */
146  if (tds->do_draw == false) {
147  if (tds->mval_pick_offset && tds->mval[1] != INT_MAX && line_bottom <= tds->mval[1]) {
148  if (y_next >= tds->mval[1]) {
149  int ofs = 0;
150 
151  /* Wrap. */
152  if (tot_lines > 1) {
153  int iofs = (int)((float)(y_next - tds->mval[1]) / tds->lheight);
154  ofs += offsets[MIN2(iofs, tot_lines - 1)];
155  }
156 
157  /* Last part. */
159  (int)floor((float)tds->mval[0] / tds->cwidth));
160 
161  CLAMP(ofs, 0, str_len);
162  *tds->mval_pick_offset += str_len - ofs;
163  }
164  else {
165  *tds->mval_pick_offset += str_len + 1;
166  }
167  }
168 
169  tds->xy[1] = y_next;
170  MEM_freeN(offsets);
171  return true;
172  }
173  if (y_next < tds->scroll_ymin) {
174  /* Have not reached the drawable area so don't break. */
175  tds->xy[1] = y_next;
176 
177  /* Adjust selection even if not drawing. */
178  if (tds->sel[0] != tds->sel[1]) {
179  textview_step_sel(tds, -(str_len + 1));
180  }
181 
182  MEM_freeN(offsets);
183  return true;
184  }
185 
186  size_t len;
187  const char *s;
188  int i;
189 
190  int sel_orig[2];
191  copy_v2_v2_int(sel_orig, tds->sel);
192 
193  /* Invert and swap for wrapping. */
194  tds->sel[0] = str_len - sel_orig[1];
195  tds->sel[1] = str_len - sel_orig[0];
196 
197  if (bg) {
202  immRecti(pos, tds->draw_rect_outer->xmin, line_bottom, tds->draw_rect_outer->xmax, line_top);
204  }
205 
206  if (icon_bg) {
207  float col[4];
208  int bg_size = UI_DPI_ICON_SIZE * 1.2;
209  float vpadding = (tds->lheight + (tds->row_vpadding * 2) - bg_size) / 2;
210  float hpadding = tds->draw_rect->xmin - (bg_size * 1.2f);
211 
212  rgba_uchar_to_float(col, icon_bg);
215  &(const rctf){
216  .xmin = hpadding,
217  .xmax = bg_size + hpadding,
218  .ymin = line_top - bg_size - vpadding,
219  .ymax = line_top - vpadding,
220  },
221  true,
222  4 * UI_DPI_FAC,
223  col);
224  }
225 
226  if (icon) {
227  int vpadding = (tds->lheight + (tds->row_vpadding * 2) - UI_DPI_ICON_SIZE) / 2;
228  int hpadding = tds->draw_rect->xmin - (UI_DPI_ICON_SIZE * 1.3f);
229 
231  UI_icon_draw_ex(hpadding,
232  line_top - UI_DPI_ICON_SIZE - vpadding,
233  icon,
234  (16 / UI_DPI_ICON_SIZE),
235  1.0f,
236  0.0f,
237  icon_fg,
238  false);
240  }
241 
242  tds->xy[1] += tds->row_vpadding;
243 
244  /* Last part needs no clipping. */
245  const int final_offset = offsets[tot_lines - 1];
246  len = str_len - final_offset;
247  s = str + final_offset;
248 
249  if (tds->sel[0] != tds->sel[1]) {
250  textview_step_sel(tds, -final_offset);
251  const int pos[2] = {tds->xy[0], line_bottom};
252  textview_draw_sel(s, pos, len, tds, bg_sel);
253  }
254 
255  BLF_position(tds->font_id, tds->xy[0], tds->lofs + line_bottom + tds->row_vpadding, 0);
256  BLF_color4ubv(tds->font_id, fg);
257  BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
258 
259  tds->xy[1] += tds->lheight;
260 
261  BLF_color4ubv(tds->font_id, fg);
262 
263  for (i = tot_lines - 1; i > 0; i--) {
264  len = offsets[i] - offsets[i - 1];
265  s = str + offsets[i - 1];
266 
267  if (tds->sel[0] != tds->sel[1]) {
268  textview_step_sel(tds, len);
269  textview_draw_sel(s, tds->xy, len, tds, bg_sel);
270  }
271 
272  BLF_position(tds->font_id, tds->xy[0], tds->lofs + tds->xy[1], 0);
273  BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
274 
275  tds->xy[1] += tds->lheight;
276 
277  /* Check if we're out of view bounds. */
278  if (tds->xy[1] > tds->scroll_ymax) {
279  MEM_freeN(offsets);
280  return false;
281  }
282  }
283 
284  tds->xy[1] = y_next;
285 
286  copy_v2_v2_int(tds->sel, sel_orig);
287  textview_step_sel(tds, -(str_len + 1));
288 
289  MEM_freeN(offsets);
290  return true;
291 }
292 
294  const bool do_draw,
295  const int mval_init[2],
296  void **r_mval_pick_item,
297  int *r_mval_pick_offset)
298 {
299  TextViewDrawState tds = {0};
300 
301  const int x_orig = tvc->draw_rect.xmin, y_orig = tvc->draw_rect.ymin;
302  int xy[2];
303  /* Disable selection by. */
304  int sel[2] = {-1, -1};
305  uchar fg[4], bg[4], icon_fg[4], icon_bg[4];
306  int icon = 0;
307  const int font_id = blf_mono_font;
308 
309  textview_font_begin(font_id, tvc->lheight);
310 
311  xy[0] = x_orig;
312  xy[1] = y_orig;
313 
314  /* Offset and clamp the results,
315  * clamping so moving the cursor out of the bounds doesn't wrap onto the other lines. */
316  const int mval[2] = {
317  (mval_init[0] == INT_MAX) ?
318  INT_MAX :
319  CLAMPIS(mval_init[0], tvc->draw_rect.xmin, tvc->draw_rect.xmax) - tvc->draw_rect.xmin,
320  (mval_init[1] == INT_MAX) ?
321  INT_MAX :
322  CLAMPIS(mval_init[1], tvc->draw_rect.ymin, tvc->draw_rect.ymax) + tvc->scroll_ymin,
323  };
324 
325  if (r_mval_pick_offset != NULL) {
326  *r_mval_pick_offset = 0;
327  }
328 
329  /* Constants for the text-view context. */
330  tds.font_id = font_id;
331  tds.cwidth = (int)BLF_fixed_width(font_id);
332  BLI_assert(tds.cwidth > 0);
333  tds.lheight = tvc->lheight;
334  tds.row_vpadding = tvc->row_vpadding;
335  tds.lofs = -BLF_descender(font_id);
336  /* NOTE: scroll bar must be already subtracted. */
337  tds.columns = (tvc->draw_rect.xmax - tvc->draw_rect.xmin) / tds.cwidth;
338  /* Avoid divide by zero on small windows. */
339  if (tds.columns < 1) {
340  tds.columns = 1;
341  }
342  tds.draw_rect = &tvc->draw_rect;
343  tds.draw_rect_outer = &tvc->draw_rect_outer;
344  tds.scroll_ymin = tvc->scroll_ymin;
345  tds.scroll_ymax = tvc->scroll_ymax;
346  tds.xy = xy;
347  tds.sel = sel;
348  tds.mval_pick_offset = r_mval_pick_offset;
349  tds.mval = mval;
350  tds.do_draw = do_draw;
351 
352  if (tvc->sel_start != tvc->sel_end) {
353  sel[0] = tvc->sel_start;
354  sel[1] = tvc->sel_end;
355  }
356 
357  if (tvc->begin(tvc)) {
358  uchar bg_sel[4] = {0};
359 
360  if (do_draw && tvc->const_colors) {
361  tvc->const_colors(tvc, bg_sel);
362  }
363 
364  int iter_index = 0;
365  do {
366  const char *ext_line;
367  int ext_len;
368  int data_flag = 0;
369 
370  const int y_prev = xy[1];
371 
372  if (do_draw) {
373  data_flag = tvc->line_data(tvc, fg, bg, &icon, icon_fg, icon_bg);
374  }
375 
376  tvc->line_get(tvc, &ext_line, &ext_len);
377 
378  const bool is_out_of_view_y = !textview_draw_string(
379  &tds,
380  ext_line,
381  ext_len,
382  (data_flag & TVC_LINE_FG) ? fg : NULL,
383  (data_flag & TVC_LINE_BG) ? bg : NULL,
384  (data_flag & TVC_LINE_ICON) ? icon : 0,
385  (data_flag & TVC_LINE_ICON_FG) ? icon_fg : NULL,
386  (data_flag & TVC_LINE_ICON_BG) ? icon_bg : NULL,
387  bg_sel);
388 
389  if (do_draw) {
390  /* We always want the cursor to draw. */
391  if (tvc->draw_cursor && iter_index == 0) {
392  tvc->draw_cursor(tvc, tds.cwidth, tds.columns);
393  }
394 
395  /* When drawing, if we pass v2d->cur.ymax, then quit. */
396  if (is_out_of_view_y) {
397  break;
398  }
399  }
400 
401  if ((mval[1] != INT_MAX) && (mval[1] >= y_prev && mval[1] <= xy[1])) {
402  *r_mval_pick_item = (void *)tvc->iter;
403  break;
404  }
405 
406  iter_index++;
407 
408  } while (tvc->step(tvc));
409  }
410 
411  tvc->end(tvc);
412 
413  /* Sanity checks (bugs here can be tricky to track down). */
414  BLI_assert(tds.lheight == tvc->lheight);
415  BLI_assert(tds.row_vpadding == tvc->row_vpadding);
416  BLI_assert(tds.do_draw == do_draw);
417 
418  xy[1] += tvc->lheight * 2;
419 
420  return xy[1] - y_orig;
421 }
int BLF_descender(int fontid) ATTR_WARN_UNUSED_RESULT
Definition: blf.c:744
int BLF_draw_mono(int fontid, const char *str, size_t str_len, int cwidth) ATTR_NONNULL(2)
Definition: blf.c:550
float BLF_fixed_width(int fontid) ATTR_WARN_UNUSED_RESULT
Definition: blf.c:693
int blf_mono_font
Definition: blf.c:48
void BLF_color4ubv(int fontid, const unsigned char rgba[4])
Definition: blf.c:383
void BLF_size(int fontid, float size, int dpi)
Definition: blf.c:363
void BLF_position(int fontid, float x, float y, float z)
Definition: blf.c:308
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
Definition: math_color.c:383
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
int BLI_str_utf8_offset_from_column(const char *str, int column) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: string_utf8.c:791
#define BLI_UTF8_WIDTH_MAX
int BLI_str_utf8_char_width_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: string_utf8.c:388
int BLI_str_utf8_offset_to_column(const char *str, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: string_utf8.c:781
int BLI_str_utf8_size_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: string_utf8.c:466
unsigned char uchar
Definition: BLI_sys_types.h:70
unsigned int uint
Definition: BLI_sys_types.h:67
#define CLAMPIS(a, b, c)
#define MAX2(a, b)
#define MIN2(a, b)
void immUniformColor4ubv(const unsigned char rgba[4])
void immUnbindProgram(void)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
GPUVertFormat * immVertexFormat(void)
void immRecti(uint pos, int x1, int y1, int x2, int y2)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
@ GPU_SHADER_2D_UNIFORM_COLOR
Definition: GPU_shader.h:201
@ GPU_BLEND_NONE
Definition: GPU_state.h:60
@ GPU_BLEND_ALPHA
Definition: GPU_state.h:62
void GPU_blend(eGPUBlend blend)
Definition: gpu_state.cc:39
@ GPU_FETCH_INT_TO_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_I32
Read Guarded memory(de)allocation.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
void UI_draw_roundbox_4fv(const struct rctf *rect, bool filled, float rad, const float col[4])
void UI_draw_roundbox_corner_set(int type)
#define UI_DPI_ICON_SIZE
Definition: UI_interface.h:307
#define UI_DPI_FAC
Definition: UI_interface.h:305
@ UI_CNR_ALL
void UI_icon_draw_ex(float x, float y, int icon_id, float aspect, float alpha, float desaturate, const uchar mono_color[4], bool mono_border)
int len
Definition: draw_manager.c:108
#define str(s)
uint pos
uint col
format
Definition: logImageCore.h:38
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
T floor(const T &a)
rcti draw_rect
Definition: textview.h:26
void(* line_get)(struct TextViewContext *tvc, const char **r_line, int *r_len)
Definition: textview.h:41
const void * iter
Definition: textview.h:51
int row_vpadding
Definition: textview.h:23
int(* begin)(struct TextViewContext *tvc)
Definition: textview.h:34
void(* const_colors)(struct TextViewContext *tvc, unsigned char bg_sel[4])
Definition: textview.h:50
enum eTextViewContext_LineFlag(* line_data)(struct TextViewContext *tvc, uchar fg[4], uchar bg[4], int *r_icon, uchar r_icon_fg[4], uchar r_icon_bg[4])
Definition: textview.h:42
void(* end)(struct TextViewContext *tvc)
Definition: textview.h:35
int(* step)(struct TextViewContext *tvc)
Definition: textview.h:40
void(* draw_cursor)(struct TextViewContext *tvc, int cwidth, int columns)
Definition: textview.h:48
rcti draw_rect_outer
Definition: textview.h:28
const rcti * draw_rect
Definition: textview.c:41
const rcti * draw_rect_outer
Definition: textview.c:43
const int * mval
Definition: textview.c:49
int * mval_pick_offset
Definition: textview.c:48
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63
static bool textview_draw_string(TextViewDrawState *tds, const char *str, int str_len, const uchar fg[4], const uchar bg[4], int icon, const uchar icon_fg[4], const uchar icon_bg[4], const uchar bg_sel[4])
Definition: textview.c:124
static void textview_draw_sel(const char *str, const int xy[2], const int str_len_draw, TextViewDrawState *tds, const uchar bg_sel[4])
Definition: textview.c:59
static void textview_font_begin(const int font_id, const int lheight)
Definition: textview.c:25
int textview_draw(TextViewContext *tvc, const bool do_draw, const int mval_init[2], void **r_mval_pick_item, int *r_mval_pick_offset)
Definition: textview.c:293
BLI_INLINE void textview_step_sel(TextViewDrawState *tds, const int step)
Definition: textview.c:53
static int textview_wrap_offsets(const char *str, int len, int width, int *r_lines, int **r_offsets)
Definition: textview.c:92
struct TextViewDrawState TextViewDrawState
@ TVC_LINE_ICON
Definition: textview.h:12
@ TVC_LINE_ICON_FG
Definition: textview.h:13
@ TVC_LINE_ICON_BG
Definition: textview.h:14
@ TVC_LINE_BG
Definition: textview.h:11
@ TVC_LINE_FG
Definition: textview.h:10
int xy[2]
Definition: wm_draw.c:135