static void Widget_UpdateChildrenSize(LCUI_Widget w) { LinkedListNode *node; for (LinkedList_Each(node, &w->children)) { LCUI_Widget child = node->data; LCUI_StyleSheet s = child->style; if (Widget_HasFillAvailableWidth(child)) { Widget_AddTask(child, LCUI_WTASK_RESIZE); } else if (Widget_HasScaleSize(child)) { Widget_AddTask(child, LCUI_WTASK_RESIZE); } if (Widget_HasAbsolutePosition(child)) { if (s->sheet[key_right].is_valid || s->sheet[key_bottom].is_valid || CheckStyleType(s, key_left, scale) || CheckStyleType(s, key_top, scale)) { Widget_AddTask(child, LCUI_WTASK_POSITION); } } if (Widget_HasAutoStyle(child, key_margin_left) || Widget_HasAutoStyle(child, key_margin_right)) { Widget_AddTask(child, LCUI_WTASK_MARGIN); } if (child->computed_style.vertical_align != SV_TOP) { Widget_AddTask(child, LCUI_WTASK_POSITION); } } }
static void LCUIDisplay_CleanSurfaces( void ) { SurfaceRecord *sr; LinkedListNode *node; for( LinkedList_Each( node, &display.surfaces ) ) { sr = node->data; Surface_Delete( sr->surface ); LinkedList_DeleteNode( &display.surfaces, node ); } }
void Widget_AddTaskForChildren(LCUI_Widget widget, int task) { LCUI_Widget child; LinkedListNode *node; widget->task.for_children = TRUE; for (LinkedList_Each(node, &widget->children)) { child = node->data; Widget_AddTask(child, task); Widget_AddTaskForChildren(child, task); } }
static LCUI_Surface LCUIDisplay_GetBindSurface( LCUI_Widget widget ) { SurfaceRecord *sr; LinkedListNode *node; for( LinkedList_Each( node, &display.surfaces ) ) { sr = node->data; if( sr && sr->widget == widget ) { return sr->surface; } } return NULL; }
/** 更新各种图形元素的显示 */ static void LCUIDisplay_Update(void) { LinkedList rlist; SurfaceRecord *p_sr; LinkedListNode *sn, *rn; LCUI_PaintContext paint; LinkedList_Init( &rlist ); /* 遍历当前的 surface 记录列表 */ for( LinkedList_Each( sn, &display.surfaces ) ) { p_sr = sn->data; if( !p_sr->widget || !p_sr->surface || !Surface_IsReady(p_sr->surface) ) { continue; } Surface_Update( p_sr->surface ); /* 收集无效区域记录 */ Widget_ProcInvalidArea( p_sr->widget, &rlist ); /* 在 surface 上逐个重绘无效区域 */ for( LinkedList_Each( rn, &rlist ) ) { paint = Surface_BeginPaint( p_sr->surface, rn->data ); if( !paint ) { continue; } DEBUG_MSG( "[%s]: render rect: (%d,%d,%d,%d)\n", p_sr->widget->type, paint->rect.left, paint->rect.top, paint->rect.w, paint->rect.h ); Widget_Render( p_sr->widget, paint ); if( display.show_rect_border ) { DrawBorder( paint ); } Surface_EndPaint( p_sr->surface, paint ); } if( rlist.length > 0 ) { Surface_Present( p_sr->surface ); } RectList_Clear( &rlist ); } RectList_Clear( &rlist ); }
/** 解除 widget 与 sruface 的绑定 */ static void LCUIDisplay_UnbindSurface( LCUI_Widget widget ) { SurfaceRecord *sr; LinkedListNode *node; for( LinkedList_Each( node, &display.surfaces ) ) { sr = node->data; if( sr && sr->widget == widget ) { Surface_Delete( sr->surface ); LinkedList_DeleteNode( &display.surfaces, node ); break; } } }
void Widget_ExecUpdateZIndex(LCUI_Widget w) { int z_index; LinkedList *list; LinkedListNode *cnode, *csnode, *snode; LCUI_Style s = &w->style->sheet[key_z_index]; if (s->is_valid && s->type == LCUI_STYPE_VALUE) { z_index = s->val_int; } else { z_index = 0; } if (!w->parent) { return; } if (w->state == LCUI_WSTATE_NORMAL) { if (w->computed_style.z_index == z_index) { return; } } w->computed_style.z_index = z_index; snode = &w->node_show; list = &w->parent->children_show; LinkedList_Unlink(list, snode); for (LinkedList_Each(cnode, list)) { LCUI_Widget child = cnode->data; LCUI_WidgetStyle *ccs = &child->computed_style; csnode = &child->node_show; if (w->computed_style.z_index < ccs->z_index) { continue; } else if (w->computed_style.z_index == ccs->z_index) { if (w->computed_style.position == ccs->position) { if (w->index < child->index) { continue; } } else if (w->computed_style.position < ccs->position) { continue; } } LinkedList_Link(list, csnode->prev, snode); break; } if (!cnode) { LinkedList_AppendNode(list, snode); } if (w->computed_style.position != SV_STATIC) { Widget_AddTask(w, LCUI_WTASK_REFRESH); } }
/** 清除已记录的无效矩形 */ void TextLayer_ClearInvalidRect( LCUI_TextLayer layer ) { LinkedListNode *node; LCUI_Graph invalid_graph; if( !layer->is_using_buffer ) { RectList_Clear( &layer->dirty_rect ); return; } for( LinkedList_Each( node, &layer->dirty_rect ) ) { Graph_Quote( &invalid_graph, &layer->graph, node->data ); Graph_FillAlpha( &invalid_graph, 0 ); } RectList_Clear( &layer->dirty_rect ); }
static int LCUIDisplay_Seamless( void ) { LinkedListNode *node; LCUI_Widget root = LCUIWidget_GetRoot(); DEBUG_MSG("display.mode: %d\n", display.mode); switch( display.mode ) { case LCDM_SEAMLESS: return 0; case LCDM_FULLSCREEN: case LCDM_WINDOWED: default: LCUIDisplay_CleanSurfaces(); break; } for( LinkedList_Each( node, &root->children ) ) { LCUIDisplay_BindSurface( node->data ); } display.mode = LCDM_SEAMLESS; return 0; }
static void Widget_ComputeStaticContentSize(LCUI_Widget w, float *out_width, float *out_height) { LinkedListNode *node; float content_width = 0, content_height = 0, width, height; for (LinkedList_Each(node, &w->children_show)) { if (!Widget_ComputeStaticSize(node->data, &width, &height)) { continue; } content_width = max(content_width, width); content_height = max(content_height, height); } /* The child widget's coordinates are relative to the padding box, * not the content box, so it needs to be converted */ content_width -= w->padding.left; content_height -= w->padding.top; if (out_width && *out_width <= 0) { *out_width = content_width; } if (out_height && *out_height <= 0) { *out_height = content_height; } }
/** 载入CSS代码块,用于实现CSS代码的分块载入 */ static int LCUI_LoadCSSBlock( CSSParserContext ctx, const char *str ) { size_t size = 0; LCUI_Selector s; LinkedListNode *node; ctx->ptr = str; for( ; *ctx->ptr && size < ctx->buffer_size; ++ctx->ptr, ++size ) { switch( ctx->target ) { case TARGET_SELECTOR: switch( *ctx->ptr ) { case '/': goto proc_comment; case '{': ctx->target = TARGET_KEY; ctx->css = StyleSheet(); case ',': ctx->buffer[ctx->pos] = 0; ctx->pos = 0; DEBUG_MSG("selector: %s\n", ctx->buffer); s = Selector( ctx->buffer ); if( !s ) { // 解析出错 ... break; } LinkedList_Append( &ctx->selectors, s ); break; default: ctx->buffer[ctx->pos++] = *ctx->ptr; break; } break; case TARGET_KEY: switch( *ctx->ptr ) { case '/': goto proc_comment; case ' ': case '\n': case '\r': case '\t': case ';': ctx->pos = 0; continue; case ':': break; case '}': ctx->target = TARGET_NONE; goto put_css; default: ctx->buffer[ctx->pos++] = *ctx->ptr; continue; } goto select_parser; case TARGET_VALUE: switch( *ctx->ptr ) { case '/': goto proc_comment; case '}': case ';': goto parse_value; case '\n': case '\r': case '\t': case ' ': if( ctx->pos == 0 ) { continue; } default: ctx->buffer[ctx->pos++] = *ctx->ptr; continue; } break; case TARGET_COMMENT: if( ctx->is_line_comment ) { if( *ctx->ptr == '\n' ) { ctx->target = ctx->target_bak; } break; } if( *ctx->ptr == '/' && *(ctx->ptr - 1) == '*' ) { ctx->target = ctx->target_bak; } break; case TARGET_NONE: default: switch( *ctx->ptr ) { case '/': goto proc_comment; case '\n': case '\t': case '\r': case ' ': case ',': case '{': case '\\': case '"': case '}': continue; default: break; } ctx->pos = 0; ctx->buffer[ctx->pos++] = *ctx->ptr; ctx->target = TARGET_SELECTOR; break; } continue; proc_comment: switch( *(ctx->ptr + 1) ) { case '/': ctx->is_line_comment = TRUE; break; case '*': ctx->is_line_comment = FALSE; break; default: ctx->buffer[ctx->pos++] = *ctx->ptr; continue; } if( ctx->target_bak != TARGET_COMMENT ) { ctx->target_bak = ctx->target; ctx->target = TARGET_COMMENT; } continue; put_css: DEBUG_MSG("put css\n"); /* 将记录的样式表添加至匹配到的选择器中 */ for( LinkedList_Each( node, &ctx->selectors ) ) { LCUI_PutStyleSheet( node->data, ctx->css, ctx->space ); } LinkedList_Clear( &ctx->selectors, (FuncPtr)Selector_Delete ); StyleSheet_Delete( ctx->css ); continue; select_parser: ctx->target = TARGET_VALUE; ctx->buffer[ctx->pos] = 0; ctx->pos = 0; ctx->parser = Dict_FetchValue( self.parsers, ctx->buffer ); DEBUG_MSG("select style: %s, parser: %p\n", ctx->buffer, ctx->parser); continue; parse_value: if( *ctx->ptr == ';' ) { ctx->target = TARGET_KEY; } if( !ctx->parser ) { continue; } ctx->buffer[ctx->pos] = 0; ctx->pos = 0; ctx->parser->parse( ctx->css, ctx->parser->key, ctx->buffer ); DEBUG_MSG("parse style value: %s, result: %d\n", ctx->buffer); if( *ctx->ptr == '}' ) { ctx->target = TARGET_NONE; goto put_css; } } return size; }