GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_multi_line_text_input_draw.c Lines: 133 133 100.0 %
Date: 2024-12-05 08:52:37 Branches: 59 59 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 *
4
 * This program and the accompanying materials are made available under the
5
 * terms of the MIT License which is available at
6
 * https://opensource.org/licenses/MIT.
7
 *
8
 * SPDX-License-Identifier: MIT
9
 **************************************************************************/
10
11
12
/**************************************************************************/
13
/**************************************************************************/
14
/**                                                                       */
15
/** GUIX Component                                                        */
16
/**                                                                       */
17
/**   Multi Line Text Input Management (Multi Line Text Input)            */
18
/**                                                                       */
19
/**************************************************************************/
20
21
#define GX_SOURCE_CODE
22
23
24
/* Include necessary system files.  */
25
26
#include "gx_api.h"
27
#include "gx_system.h"
28
#include "gx_multi_line_text_view.h"
29
#include "gx_text_input_cursor.h"
30
#include "gx_multi_line_text_input.h"
31
#include "gx_context.h"
32
#include "gx_window.h"
33
#include "gx_widget.h"
34
#include "gx_utility.h"
35
#include "gx_canvas.h"
36
#include "gx_scrollbar.h"
37
38
/**************************************************************************/
39
/*                                                                        */
40
/*  FUNCTION                                               RELEASE        */
41
/*                                                                        */
42
/*    _gx_multi_line_text_input_draw                      PORTABLE C      */
43
/*                                                           6.1          */
44
/*  AUTHOR                                                                */
45
/*                                                                        */
46
/*    Kenneth Maxwell, Microsoft Corporation                              */
47
/*                                                                        */
48
/*  DESCRIPTION                                                           */
49
/*                                                                        */
50
/*    This function draws the multi-line text input widget, which is a    */
51
/*    special type of widget.                                             */
52
/*                                                                        */
53
/*  INPUT                                                                 */
54
/*                                                                        */
55
/*    text_input                            Multi line text input         */
56
/*                                            control block               */
57
/*                                                                        */
58
/*  OUTPUT                                                                */
59
/*                                                                        */
60
/*    None                                                                */
61
/*                                                                        */
62
/*  CALLS                                                                 */
63
/*                                                                        */
64
/*    _gx_context_font_get                  Retrieve font                 */
65
/*    _gx_multi_line_text_view_draw         Draw the text view area       */
66
/*    _gx_text_input_cursor_draw            Draw the cursor               */
67
/*                                                                        */
68
/*  CALLED BY                                                             */
69
/*                                                                        */
70
/*    Application Code                                                    */
71
/*    GUIX Internal Code                                                  */
72
/*                                                                        */
73
/*  RELEASE HISTORY                                                       */
74
/*                                                                        */
75
/*    DATE              NAME                      DESCRIPTION             */
76
/*                                                                        */
77
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
78
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
79
/*                                            resulting in version 6.1    */
80
/*                                                                        */
81
/**************************************************************************/
82
18207
VOID  _gx_multi_line_text_input_draw(GX_MULTI_LINE_TEXT_INPUT *input)
83
{
84
18207
GX_TEXT_INPUT_CURSOR *cursor_ptr = &input -> gx_multi_line_text_input_cursor_instance;
85
18207
GX_VALUE              line_height = 0;
86
GX_FONT              *font;
87
GX_RESOURCE_ID        fill_color;
88
GX_RESOURCE_ID        text_color;
89
UINT                  line_start_mark;
90
UINT                  line_end_mark;
91
UINT                  end_mark;
92
93
UINT                  index;
94
GX_STRING             private_string;
95
GX_STRING             draw_string;
96
INT                   x_pos;
97
INT                   y_pos;
98
GX_RECTANGLE          client;
99
GX_RECTANGLE          draw_area;
100
GX_CANVAS            *canvas;
101
UINT                  first_visible_line;
102
UINT                  last_visible_line;
103
UINT                  line_start_index;
104
UINT                  line_end_index;
105
UINT                  line_cache_start;
106
GX_VALUE              text_width;
107
GX_VALUE              client_width;
108
GX_SCROLLBAR         *scroll;
109
GX_VALUE              space_width;
110
111
18207
    if (input -> gx_widget_style & GX_STYLE_ENABLED)
112
    {
113
18199
        if (input -> gx_widget_style & GX_STYLE_TEXT_INPUT_READONLY)
114
        {
115
6
            fill_color = input -> gx_multi_line_text_input_readonly_fill_color;
116
6
            text_color = input -> gx_multi_line_text_input_readonly_text_color;
117
        }
118
        else
119
        {
120
18193
            fill_color = input -> gx_widget_normal_fill_color;
121
18193
            text_color = input -> gx_multi_line_text_view_normal_text_color;
122
        }
123
    }
124
    else
125
    {
126
8
        fill_color = input -> gx_widget_disabled_fill_color;
127
8
        text_color = input -> gx_multi_line_text_view_disabled_text_color;
128
    }
129
130
    /* Draw background. */
131
18207
    _gx_window_border_draw((GX_WINDOW *)input, fill_color);
132
133
18207
    if (input -> gx_multi_line_text_view_line_index_old)
134
    {
135
        /* Get visible rows. */
136
178
        _gx_multi_line_text_view_visible_rows_compute((GX_MULTI_LINE_TEXT_VIEW *)input);
137
138
        /* Calculate text total rows. */
139
178
        _gx_multi_line_text_view_string_total_rows_compute((GX_MULTI_LINE_TEXT_VIEW *)input);
140
141
178
        _gx_window_scrollbar_find((GX_WINDOW *)input, GX_TYPE_VERTICAL_SCROLL, &scroll);
142
178
        if (scroll)
143
        {
144
            /* Reset scrollbar.  */
145
81
            _gx_scrollbar_reset(scroll, GX_NULL);
146
        }
147
        else
148
        {
149
150
97
            if (input -> gx_multi_line_text_view_text_total_rows >
151
97
                input -> gx_multi_line_text_view_cache_size)
152
            {
153
                /* Update line cache. */
154
10
                _gx_multi_line_text_view_line_cache_update((GX_MULTI_LINE_TEXT_VIEW *)input);
155
            }
156
        }
157
158
178
        _gx_multi_line_text_input_cursor_pos_update(input, GX_TRUE);
159
    }
160
161
18207
    if ((input -> gx_multi_line_text_input_start_mark == input -> gx_multi_line_text_input_end_mark) ||
162
3145
        !(input -> gx_widget_style & GX_STYLE_ENABLED))
163
    {
164
        /* Draw text. */
165
15064
        _gx_multi_line_text_view_text_draw((GX_MULTI_LINE_TEXT_VIEW *)input, text_color);
166
167
        /* Draw the cursor. */
168
15064
        if ((input -> gx_widget_status & GX_STATUS_CURSOR_SHOW) &&
169
9496
            (input -> gx_widget_status & GX_STATUS_CURSOR_DRAW))
170
        {
171
9492
            _gx_context_font_get(input -> gx_multi_line_text_view_font_id, &font);
172
173
9492
            if (font)
174
            {
175
9482
                line_height = (GX_VALUE)(font -> gx_font_line_height +
176
9482
                                         input -> gx_multi_line_text_view_line_space);
177
            }
178
179
9492
            if (!(cursor_ptr -> gx_text_input_cursor_flags & GX_CURSOR_USE_CUSTOM_HEIGHT))
180
            {
181
8996
                cursor_ptr -> gx_text_input_cursor_height = line_height;
182
            }
183
184
9492
            _gx_text_input_cursor_draw(cursor_ptr);
185
        }
186
    }
187
    else
188
    {
189
3143
        line_start_mark = input -> gx_multi_line_text_input_start_mark;
190
3143
        end_mark = input -> gx_multi_line_text_input_end_mark;
191
192
3143
        if (line_start_mark > end_mark)
193
        {
194
1534
            GX_SWAP_VALS(line_start_mark, end_mark);
195
        }
196
197
3143
        _gx_context_font_get(input -> gx_multi_line_text_view_font_id, &font);
198
3143
        _gx_context_font_set(input -> gx_multi_line_text_view_font_id);
199
3143
        _gx_context_brush_width_set(0);
200
201
        /* Is there a string and font?  */
202

3143
        if ((input -> gx_multi_line_text_view_text.gx_string_length) && (font))
203
        {
204
            /* pick up current canvas */
205
3138
            canvas = _gx_system_current_draw_context -> gx_draw_context_canvas;
206
207
            /* Pick up client area.  */
208
3138
            client = input -> gx_window_client;
209
210
            /* Offset client area by the size of whitespace.  */
211
3138
            _gx_utility_rectangle_resize(&client, (GX_VALUE)(-input -> gx_multi_line_text_view_whitespace));
212
213
3138
            _gx_utility_rectangle_overlap_detect(&_gx_system_current_draw_context -> gx_draw_context_dirty, &client, &draw_area);
214
3138
            _gx_canvas_drawing_initiate(canvas, (GX_WIDGET *)input, &draw_area);
215
216
            /* Pickup text height. */
217
3138
            line_height = (GX_VALUE)(font -> gx_font_line_height + input -> gx_multi_line_text_view_line_space);
218
219
3138
            if (line_height)
220
            {
221
222
3132
                first_visible_line = ((UINT)(-input -> gx_multi_line_text_view_text_scroll_shift)) / (UINT)line_height;
223
3132
                last_visible_line = first_visible_line + input -> gx_multi_line_text_view_text_visible_rows;
224
225
3132
                if (last_visible_line > input -> gx_multi_line_text_view_text_total_rows - 1)
226
                {
227
1173
                    last_visible_line = input -> gx_multi_line_text_view_text_total_rows - 1;
228
                }
229
230
                /* Compute the start displaying position of pixels in x direction and y direction. */
231
3132
                y_pos = client.gx_rectangle_top;
232
3132
                y_pos += input -> gx_multi_line_text_view_text_scroll_shift;
233
3132
                y_pos += (input -> gx_multi_line_text_view_line_space >> 1);
234
3132
                y_pos += (INT)first_visible_line * line_height;
235
236
3132
                _gx_system_private_string_get(&input -> gx_multi_line_text_view_text, &private_string, input -> gx_widget_style);
237
238
3132
                draw_string.gx_string_ptr = " ";
239
3132
                draw_string.gx_string_length = 1;
240
3132
                _gx_system_string_width_get_ext(font, &draw_string, &space_width);
241
242
34845
                for (index = first_visible_line; index <= last_visible_line; index++)
243
                {
244
31713
                    line_cache_start = input -> gx_multi_line_text_view_first_cache_line;
245
246
31713
                    line_start_index = input -> gx_multi_line_text_view_line_index[index - line_cache_start];
247
248
31713
                    if ((INT)(index - line_cache_start) >= (INT)(input -> gx_multi_line_text_view_cache_size - 1))
249
                    {
250
1248
                        line_end_index = input -> gx_multi_line_text_view_text.gx_string_length;
251
                    }
252
                    else
253
                    {
254
30465
                        line_end_index = input -> gx_multi_line_text_view_line_index[index - line_cache_start + 1];
255
                    }
256
257
31713
                    switch (input -> gx_widget_style & GX_STYLE_TEXT_ALIGNMENT_MASK)
258
                    {
259
10406
                    case GX_STYLE_TEXT_RIGHT:
260
10406
                        draw_string.gx_string_ptr = private_string.gx_string_ptr + line_start_index;
261
10406
                        draw_string.gx_string_length = line_end_index - line_start_index;
262
10406
                        _gx_system_string_width_get_ext(font, &draw_string, &text_width);
263
10671
                        while (text_width > (client.gx_rectangle_right - client.gx_rectangle_left - 2))
264
                        {
265
265
                            text_width = (GX_VALUE)(text_width - space_width);
266
                        }
267
10406
                        x_pos = client.gx_rectangle_right - 1;
268
10406
                        x_pos = (GX_VALUE)(x_pos - text_width);
269
10406
                        break;
270
10879
                    case GX_STYLE_TEXT_LEFT:
271
10879
                        x_pos = client.gx_rectangle_left + 1;
272
10879
                        break;
273
10428
                    case GX_STYLE_TEXT_CENTER:
274
                    default:
275
10428
                        draw_string.gx_string_ptr = private_string.gx_string_ptr + line_start_index;
276
10428
                        draw_string.gx_string_length = line_end_index - line_start_index;
277
10428
                        _gx_system_string_width_get_ext(font, &draw_string, &text_width);
278
10428
                        client_width = (GX_VALUE)(client.gx_rectangle_right - client.gx_rectangle_left + 1);
279
280
10693
                        while (text_width > (client_width - 3))
281
                        {
282
265
                            text_width = (GX_VALUE)(text_width - space_width);
283
                        }
284
285
10428
                        x_pos = (GX_VALUE)(client.gx_rectangle_left + ((client_width - text_width) / 2));
286
10428
                        break;
287
                    }
288
289

31713
                    if ((line_start_mark < line_end_index) && (end_mark > line_start_index))
290
                    {
291
10077
                        if (line_start_mark < line_start_index)
292
                        {
293
486
                            line_start_mark = line_start_index;
294
                        }
295
296
10077
                        if (line_start_mark > line_start_index)
297
                        {
298
                            /* Draw text[line_start_index : start_mark - 1] with normal text color. */
299
1265
                            _gx_context_line_color_set(text_color);
300
1265
                            draw_string.gx_string_ptr = private_string.gx_string_ptr + line_start_index;
301
1265
                            draw_string.gx_string_length = line_start_mark - line_start_index;
302
1265
                            _gx_system_string_width_get_ext(font, &draw_string, &text_width);
303
1265
                            _gx_canvas_text_draw_ext((GX_VALUE)x_pos, (GX_VALUE)y_pos, &draw_string);
304
1265
                            x_pos += text_width;
305
                        }
306
307
10077
                        if (end_mark < line_end_index)
308
                        {
309
1307
                            line_end_mark = end_mark;
310
                        }
311
                        else
312
                        {
313
8770
                            line_end_mark = line_end_index;
314
                        }
315
316
                        /* Draw text[start_mark: end_mark - 1] with hightlight text color. */
317
10077
                        _gx_context_line_color_set(input -> gx_multi_line_text_view_selected_text_color);
318
10077
                        _gx_context_fill_color_set(input -> gx_widget_selected_fill_color);
319
320
10077
                        draw_string.gx_string_ptr = private_string.gx_string_ptr + line_start_mark;
321
10077
                        draw_string.gx_string_length = line_end_mark - line_start_mark;
322
10077
                        _gx_system_string_width_get_ext(font, &draw_string, &text_width);
323
324
10077
                        draw_area.gx_rectangle_left = (GX_VALUE)x_pos;
325
10077
                        draw_area.gx_rectangle_right = (GX_VALUE)(x_pos + text_width - 1);
326
10077
                        draw_area.gx_rectangle_top = (GX_VALUE)(y_pos - (input -> gx_multi_line_text_view_line_space >> 1));
327
10077
                        draw_area.gx_rectangle_bottom = (GX_VALUE)(draw_area.gx_rectangle_top + line_height - 1);
328
329
10527
                        while (draw_area.gx_rectangle_right > client.gx_rectangle_right - 1)
330
                        {
331
450
                            draw_area.gx_rectangle_right = (GX_VALUE)(draw_area.gx_rectangle_right - space_width);
332
                        }
333
334
10077
                        _gx_canvas_rectangle_draw(&draw_area);
335
336
10077
                        draw_string.gx_string_ptr = private_string.gx_string_ptr + line_start_mark;
337
10077
                        draw_string.gx_string_length = line_end_mark - line_start_mark;
338
10077
                        _gx_canvas_text_draw_ext((GX_VALUE)x_pos, (GX_VALUE)y_pos, &draw_string);
339
340
10077
                        x_pos += text_width;
341
342
                        /* Draw text[end_mark : line_end_index] width normal text color. */
343
10077
                        if (line_end_mark < line_end_index)
344
                        {
345
1307
                            _gx_context_line_color_set(text_color);
346
1307
                            draw_string.gx_string_ptr = private_string.gx_string_ptr + line_end_mark;
347
1307
                            draw_string.gx_string_length = line_end_index - line_end_mark;
348
1307
                            _gx_canvas_text_draw_ext((GX_VALUE)x_pos, (GX_VALUE)y_pos, &draw_string);
349
                        }
350
351
10077
                        if (end_mark > line_end_index)
352
                        {
353
7799
                            line_start_mark = line_end_index;
354
                        }
355
                    }
356
                    else
357
                    {
358
21636
                        _gx_context_line_color_set(text_color);
359
360
                        /* Draw the text. */
361
21636
                        draw_string.gx_string_ptr = private_string.gx_string_ptr + line_start_index;
362
21636
                        draw_string.gx_string_length = line_end_index - line_start_index;
363
21636
                        _gx_canvas_text_draw_ext((GX_VALUE)x_pos, (GX_VALUE)y_pos, &draw_string);
364
                    }
365
366
31713
                    y_pos += line_height;
367
                }
368
            }
369
370
3138
            _gx_canvas_drawing_complete(canvas, GX_FALSE);
371
        }
372
    }
373
374
    /* Draw widget's children.  */
375
18207
    _gx_widget_children_draw((GX_WIDGET *)input);
376
18207
}
377