microui  14.4.1
microui
ui_display_brs_single.c
1 /*
2  * Copyright 2023-2025 MicroEJ Corp. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be found with this software.
4  */
5 
6 /*
7  * @file
8  * @brief This file implements all the LLUI_DISPLAY_impl.h functions relating to the
9  * display buffer strategy (BRS) "single"
10  * @see UI_FEATURE_BRS_SINGLE comment
11  * @author MicroEJ Developer Team
12  * @version 14.4.1
13  */
14 
15 #include "ui_display_brs.h"
16 #if defined UI_FEATURE_BRS && UI_FEATURE_BRS == UI_FEATURE_BRS_SINGLE
17 
18 // --------------------------------------------------------------------------------
19 // Includes
20 // --------------------------------------------------------------------------------
21 
22 #include "ui_rect_collection.h"
23 
24 // --------------------------------------------------------------------------------
25 // Defines
26 // --------------------------------------------------------------------------------
27 
28 /*
29  * @brief This strategy uses only one buffer
30  * @see the comment of UI_FEATURE_BRS_SINGLE.
31  */
32 #if defined UI_FEATURE_BRS_DRAWING_BUFFER_COUNT && UI_FEATURE_BRS_DRAWING_BUFFER_COUNT != 1
33 #error "This strategy uses always the same back buffer."
34 #endif
35 
36 // --------------------------------------------------------------------------------
37 // Private fields
38 // --------------------------------------------------------------------------------
39 
40 #ifndef UI_FEATURE_BRS_FLUSH_SINGLE_RECTANGLE
41 
42 /*
43  * @brief A collection of rectangles to transmit to the LCD
44  */
45 static ui_rect_collection_t dirty_regions;
46 
47 #else // UI_FEATURE_BRS_FLUSH_SINGLE_RECTANGLE
48 
49 /*
50  * @brief Rectangle given to LLUI_DISPLAY_IMPL_flush(): it includes all dirty regions since
51  * last call to flush().
52  */
53 static ui_rect_t flush_bounds = {
54  .x1 = INT16_MAX,
55  .y1 = INT16_MAX,
56  .x2 = 0,
57  .y2 = 0,
58 };
59 
60 #endif // UI_FEATURE_BRS_FLUSH_SINGLE_RECTANGLE
61 
62 // --------------------------------------------------------------------------------
63 // LLUI_DISPLAY_impl.h API
64 // --------------------------------------------------------------------------------
65 
66 /*
67  * @brief See the header file for the function documentation.
68  *
69  * This function stores the new region as new region to transmit to the LCD at next call to flush().
70  */
71 DRAWING_Status LLUI_DISPLAY_IMPL_newDrawingRegion(MICROUI_GraphicsContext *gc, ui_rect_t *region, bool drawing_now) {
72  (void)drawing_now;
73 
74 #ifndef UI_FEATURE_BRS_FLUSH_SINGLE_RECTANGLE
75 
76  ui_rect_t *previous = UI_RECT_COLLECTION_get_last(&dirty_regions);
77  if ((NULL == previous) || !UI_RECT_contains_rect(previous, region)) {
78  // add the dirty region if and only if previous dirty region does not
79  // include the new dirty region
80  ui_rect_t new_region;
81  if (!UI_RECT_COLLECTION_is_full(&dirty_regions)) {
82  new_region = *region;
83  } else {
84  // too many rectangles: replace them by only one whose fits the full display
85  UI_RECT_COLLECTION_clear(&dirty_regions);
86  new_region = UI_RECT_new_xyxy(0, 0, gc->image.width - 1, gc->image.height - 1);
87  }
88  UI_RECT_COLLECTION_add_rect(&dirty_regions, new_region);
89  }
90 #else // UI_FEATURE_BRS_FLUSH_SINGLE_RECTANGLE
91  (void)gc;
92 
93  flush_bounds.x1 = MIN(flush_bounds.x1, region->x1);
94  flush_bounds.y1 = MIN(flush_bounds.y1, region->y1);
95  flush_bounds.x2 = MAX(flush_bounds.x2, region->x2);
96  flush_bounds.y2 = MAX(flush_bounds.y2, region->y2);
97 
98 #endif // UI_FEATURE_BRS_FLUSH_SINGLE_RECTANGLE
99 
100  return DRAWING_DONE;
101 }
102 
103 /*
104  * @brief See the header file for the function documentation.
105  *
106  * This function calls LLUI_DISPLAY_IMPL_flush() with the rectangle that includes all dirty regions.
107  */
108 DRAWING_Status LLUI_DISPLAY_IMPL_refresh(MICROUI_GraphicsContext *gc, uint8_t flushIdentifier) {
109 #ifndef UI_FEATURE_BRS_FLUSH_SINGLE_RECTANGLE
110 
111  size_t size = UI_RECT_COLLECTION_get_length(&dirty_regions);
112  if (1u == size) {
113  ui_rect_t *rect = &dirty_regions.data[0];
114  UI_LOG_START(BRS_FlushSingle, flushIdentifier, UI_LOG_BUFFER(&gc->image), rect->x1, rect->y1, UI_RECT_get_width(rect),
115  UI_RECT_get_height(rect));
116  } else {
117  UI_LOG_START(BRS_FlushMulti, flushIdentifier, UI_LOG_BUFFER(&gc->image), size);
118  }
119 
120  LLUI_DISPLAY_IMPL_flush(gc, flushIdentifier, dirty_regions.data, UI_RECT_COLLECTION_get_length(&dirty_regions));
121  UI_RECT_COLLECTION_clear(&dirty_regions);
122 
123 #else // UI_FEATURE_BRS_FLUSH_SINGLE_RECTANGLE
124 
125  UI_LOG_START(BRS_FlushSingle, flushIdentifier, UI_LOG_BUFFER(&gc->image), flush_bounds.x1, flush_bounds.y1,
126  UI_RECT_get_width(&flush_bounds), UI_RECT_get_height(&flush_bounds));
127 
128  // refresh the LCD; use the flush_bounds as dirty region (includes all dirty regions)
129  LLUI_DISPLAY_IMPL_flush(gc, flushIdentifier, &flush_bounds, 1);
130 
131  // reset flush bounds to no flush again if there is no drawing until next flush
132  flush_bounds.x1 = INT16_MAX;
133  flush_bounds.y1 = INT16_MAX;
134  flush_bounds.x2 = 0;
135  flush_bounds.y2 = 0;
136 
137 #endif // UI_FEATURE_BRS_FLUSH_SINGLE_RECTANGLE
138 
139  return DRAWING_DONE;
140 }
141 
142 #endif // UI_FEATURE_BRS_SINGLE
143 
144 // --------------------------------------------------------------------------------
145 // EOF
146 // --------------------------------------------------------------------------------