Skip to content

Commit 5ad4fec

Browse files
vbalyasnyylc-soft
authored andcommitted
feat(display): flashing rendered rects (#180) (#190)
Signed-off-by: Vasilyy Balyasnyy <v.balyasnyy@gmail.com>
1 parent 02c03c7 commit 5ad4fec

File tree

1 file changed

+101
-21
lines changed

1 file changed

+101
-21
lines changed

src/display.c

+101-21
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@
2929

3030
#include "config.h"
3131

32-
#include <time.h>
33-
#include <stdio.h>
34-
#include <stdlib.h>
3532
#ifdef USE_OPENMP
3633
#include <omp.h>
3734
#endif
35+
#include <time.h>
36+
#include <stdio.h>
37+
#include <stdlib.h>
38+
#include <string.h>
3839
#include <LCUI_Build.h>
3940
#include <LCUI/LCUI.h>
4041
#include <LCUI/input.h>
@@ -62,13 +63,23 @@
6263
#define PARALLEL_RENDERING_THREADS 1
6364
#endif
6465

66+
#define FLASH_DURATION 1000.0
67+
68+
typedef struct FlashRectRec_ {
69+
int64_t paint_time;
70+
LCUI_Rect rect;
71+
} FlashRectRec, *FlashRect;
72+
6573
typedef struct SurfaceRecordRec_ {
66-
/**< whether new content has been rendered */
74+
/** whether new content has been rendered */
6775
LCUI_BOOL rendered;
6876

6977
/** dirty rectangles for rendering */
7078
LinkedList rects;
7179

80+
/** flashing rect list */
81+
LinkedList flash_rects;
82+
7283
LCUI_Surface surface;
7384
LCUI_Widget widget;
7485
} SurfaceRecordRec, *SurfaceRecord;
@@ -88,29 +99,102 @@ static struct LCUI_DisplayModule {
8899
#define LCUIDisplay_CleanSurfaces() \
89100
LinkedList_Clear(&display.surfaces, OnDestroySurfaceRecord)
90101

102+
INLINE int is_rect_equals(const LCUI_Rect *a, const LCUI_Rect *b)
103+
{
104+
return a->x == b->x && a->y == b->y && a->width == b->width &&
105+
a->height == b->height;
106+
}
107+
91108
static void OnDestroySurfaceRecord(void *data)
92109
{
93110
SurfaceRecord record = data;
111+
94112
Surface_Close(record->surface);
95113
LinkedList_Clear(&record->rects, free);
114+
LinkedList_Clear(&record->flash_rects, free);
96115
free(record);
97116
}
98117

99-
static void DrawBorder(LCUI_PaintContext paint)
118+
static void DrawBorder(LCUI_Graph *mask)
100119
{
101120
LCUI_Pos pos;
102121
LCUI_Color color;
103-
int end_x = paint->rect.width - 1;
104-
int end_y = paint->rect.height - 1;
122+
int end_x = mask->width - 1;
123+
int end_y = mask->height - 1;
105124
pos.x = pos.y = 0;
106-
color = RGB(255, 0, 0);
107-
Graph_DrawHorizLine(&paint->canvas, color, 1, pos, end_x);
108-
Graph_DrawVertiLine(&paint->canvas, color, 1, pos, end_y);
109-
pos.x = paint->rect.width - 1;
110-
Graph_DrawVertiLine(&paint->canvas, color, 1, pos, end_y);
125+
color = RGB(124, 179, 5);
126+
Graph_DrawHorizLine(mask, color, 1, pos, end_x);
127+
Graph_DrawVertiLine(mask, color, 1, pos, end_y);
128+
pos.x = mask->width - 1;
129+
Graph_DrawVertiLine(mask, color, 1, pos, end_y);
111130
pos.x = 0;
112-
pos.y = paint->rect.height - 1;
113-
Graph_DrawHorizLine(&paint->canvas, color, 1, pos, end_x);
131+
pos.y = mask->height - 1;
132+
Graph_DrawHorizLine(mask, color, 1, pos, end_x);
133+
}
134+
135+
static size_t LCUIDisplay_UpdateFlashRects(SurfaceRecord record)
136+
{
137+
int64_t period;
138+
size_t count = 0;
139+
LCUI_Graph mask;
140+
LCUI_PaintContext paint;
141+
FlashRect flash_rect;
142+
LinkedListNode *node, *prev;
143+
144+
for (LinkedList_Each(node, &record->flash_rects)) {
145+
flash_rect = node->data;
146+
if (flash_rect->paint_time == 0) {
147+
prev = node->prev;
148+
free(node->data);
149+
LinkedList_DeleteNode(&record->flash_rects, node);
150+
node = prev;
151+
continue;
152+
}
153+
period = LCUI_GetTimeDelta(flash_rect->paint_time);
154+
if (period >= FLASH_DURATION) {
155+
flash_rect->paint_time = 0;
156+
} else {
157+
Graph_Init(&mask);
158+
mask.color_type = LCUI_COLOR_TYPE_ARGB;
159+
Graph_Create(&mask, flash_rect->rect.width,
160+
flash_rect->rect.height);
161+
Graph_FillRect(&mask, ARGB(125, 124, 179, 5), NULL, TRUE);
162+
mask.opacity =
163+
0.6 * (FLASH_DURATION - (float)period) / FLASH_DURATION;
164+
}
165+
paint = Surface_BeginPaint(record->surface, &flash_rect->rect);
166+
if (!paint) {
167+
continue;
168+
}
169+
count += Widget_Render(record->widget, paint);
170+
if (flash_rect->paint_time != 0) {
171+
DrawBorder(&mask);
172+
Graph_Mix(&paint->canvas, &mask, 0, 0, TRUE);
173+
Graph_Free(&mask);
174+
}
175+
Surface_EndPaint(record->surface, paint);
176+
record->rendered = TRUE;
177+
}
178+
return count;
179+
}
180+
181+
static void LCUIDisplay_AppendFlashRects(SurfaceRecord record, LCUI_Rect *rect)
182+
{
183+
LinkedListNode *node;
184+
FlashRect flash_rect;
185+
186+
for (LinkedList_Each(node, &record->flash_rects)) {
187+
flash_rect = node->data;
188+
if (is_rect_equals(&flash_rect->rect, rect)) {
189+
flash_rect->paint_time = LCUI_GetTime();
190+
return;
191+
}
192+
}
193+
194+
flash_rect = NEW(FlashRectRec, 1);
195+
flash_rect->rect = *rect;
196+
flash_rect->paint_time = LCUI_GetTime();
197+
LinkedList_Append(&record->flash_rects, flash_rect);
114198
}
115199

116200
static void SurfaceRecord_DumpRects(SurfaceRecord record, LinkedList *rects)
@@ -227,13 +311,8 @@ static size_t LCUIDisplay_RenderSurface(SurfaceRecord record)
227311
DEBUG_MSG("rect: (%d,%d,%d,%d)\n", paint->rect.x, paint->rect.y,
228312
paint->rect.width, paint->rect.height);
229313
count += Widget_Render(record->widget, paint);
230-
/**
231-
* FIXME: Improve highlighting of repainted areas
232-
* Let the highlighted areas disappear after a short
233-
* period of time, just like flashing
234-
*/
235314
if (display.show_rect_border) {
236-
DrawBorder(paint);
315+
LCUIDisplay_AppendFlashRects(record, &paint->rect);
237316
}
238317
if (display.mode != LCUI_DMODE_SEAMLESS) {
239318
LCUICursor_Paint(paint);
@@ -242,6 +321,7 @@ static size_t LCUIDisplay_RenderSurface(SurfaceRecord record)
242321
}
243322
RectList_Clear(&rects);
244323
record->rendered = count > 0;
324+
count += LCUIDisplay_UpdateFlashRects(record);
245325
return count;
246326
}
247327

@@ -260,7 +340,6 @@ void LCUIDisplay_Update(void)
260340
if (record->widget && surface && Surface_IsReady(surface)) {
261341
Surface_Update(surface);
262342
}
263-
/* 收集无效区域记录 */
264343
Widget_GetInvalidArea(record->widget, &record->rects);
265344
}
266345
if (display.mode == LCUI_DMODE_SEAMLESS || !record) {
@@ -387,6 +466,7 @@ static void LCUIDisplay_BindSurface(LCUI_Widget widget)
387466
record->surface = Surface_New();
388467
record->widget = widget;
389468
record->rendered = FALSE;
469+
LinkedList_Init(&record->flash_rects);
390470
LCUIMetrics_ComputeRectActual(&rect, &widget->box.canvas);
391471
if (Widget_CheckStyleValid(widget, key_top) &&
392472
Widget_CheckStyleValid(widget, key_left)) {

0 commit comments

Comments
 (0)