/** 将 widget 与 sruface 进行绑定 */ static void LCUIDisplay_BindSurface( LCUI_Widget widget ) { LCUI_Rect *p_rect; SurfaceRecord *p_sr; if( LCUIDisplay_GetBindSurface(widget) ) { return; } p_sr = NEW( SurfaceRecord, 1 ); p_sr->widget = widget; p_sr->surface = Surface_New(); Surface_SetCaptionW( p_sr->surface, widget->title ); p_rect = &widget->box.graph; if( widget->style->sheet[key_top].is_valid && widget->style->sheet[key_left].is_valid ) { Surface_Move( p_sr->surface, p_rect->x, p_rect->y ); } Surface_Resize( p_sr->surface, p_rect->w, p_rect->h ); if( widget->computed_style.visible ) { Surface_Show( p_sr->surface ); } else { Surface_Hide( p_sr->surface ); } Widget_InvalidateArea( widget, NULL, SV_GRAPH_BOX ); LinkedList_Append( &display.surfaces, p_sr ); }
void Widget_UpdateOpacity(LCUI_Widget w) { float opacity = 1.0; LCUI_Style s = &w->style->sheet[key_opacity]; if (s->is_valid) { switch (s->type) { case LCUI_STYPE_VALUE: opacity = 1.0f * s->value; break; case LCUI_STYPE_SCALE: opacity = s->val_scale; break; default: opacity = 1.0f; break; } if (opacity > 1.0) { opacity = 1.0; } else if (opacity < 0.0) { opacity = 0.0; } } w->computed_style.opacity = opacity; Widget_InvalidateArea(w, NULL, SV_GRAPH_BOX); DEBUG_MSG("opacity: %0.2f\n", opacity); }
void Widget_Destroy(LCUI_Widget w) { LCUI_Widget root = w; assert(w->state != LCUI_WSTATE_DELETED); while (root->parent) { root = root->parent; } /* If this widget is not mounted in the root widget tree */ if (root != LCUIWidget.root) { w->state = LCUI_WSTATE_DELETED; Widget_ExecDestroy(w); return; } if (w->parent) { LCUI_Widget child; LinkedListNode *node; /* Update the index of the siblings behind it */ node = w->node.next; while (node) { child = node->data; child->index -= 1; node = node->next; } if (w->computed_style.position != SV_ABSOLUTE) { Widget_UpdateLayout(w->parent); } Widget_InvalidateArea(w, NULL, SV_GRAPH_BOX); Widget_AddToTrash(w); } }
void Widget_UpdateVisibility(LCUI_Widget w) { LCUI_Style s = &w->style->sheet[key_visibility]; LCUI_BOOL visible = w->computed_style.visible; if (w->computed_style.display == SV_NONE) { w->computed_style.visible = FALSE; } else if (s->is_valid && s->type == LCUI_STYPE_STRING && strcmp(s->val_string, "hidden") == 0) { w->computed_style.visible = FALSE; } else { w->computed_style.visible = TRUE; } if (visible == w->computed_style.visible) { return; } if (w->parent) { Widget_InvalidateArea(w, NULL, SV_GRAPH_BOX); } visible = w->computed_style.visible; if (visible) { Widget_PostSurfaceEvent(w, LCUI_WEVENT_SHOW, TRUE); } else { Widget_PostSurfaceEvent(w, LCUI_WEVENT_HIDE, TRUE); } }
/** 将 widget 与 sruface 进行绑定 */ static void LCUIDisplay_BindSurface( LCUI_Widget widget ) { SurfaceRecord *p_sr; LCUI_Rect *p_rect; if( LCUIDisplay_GetBindSurface(widget) ) { return; } p_sr = (SurfaceRecord*)LinkedList_Alloc( &display.surfaces ); p_sr->widget = widget; /** * 初次调用 Surface_New() 耗时较长, 所以先为 p_sr->surface 设置初 * 始值,避免在 Surface_New() 返回前被当成正常指针使用。 */ p_sr->surface = NULL; p_sr->surface = Surface_New(); Surface_SetCaptionW( p_sr->surface, widget->title ); p_rect = &widget->base.box.graph; Surface_Move( p_sr->surface, p_rect->x, p_rect->y ); Surface_Resize( p_sr->surface, p_rect->w, p_rect->h ); if( widget->style.visible ) { Surface_Show( p_sr->surface ); } else { Surface_Hide( p_sr->surface ); } Widget_InvalidateArea( widget, NULL, SV_GRAPH_BOX ); }
/** 响应顶级部件的各种事件 */ static void OnTopLevelWidgetEvent( LCUI_Widget w, LCUI_WidgetEvent *e, void *arg ) { int e_type = *((int*)&arg); LCUI_Surface surface; LCUI_Rect *p_rect; DEBUG_MSG("tip, e_type = %d\n", e_type); surface = LCUIDisplay_GetBindSurface( e->target ); if( display.mode == LDM_SEAMLESS ) { if( !surface && e_type != WET_ADD ) { return; } } else if ( e->target == LCUIRootWidget ) { if( !surface && e_type != WET_ADD ) { return; } } else { return; } p_rect = &e->target->base.box.graph; switch( e_type ) { case WET_ADD: LCUIDisplay_BindSurface( e->target ); break; case WET_REMOVE: case WET_DESTROY: LCUIDisplay_UnbindSurface( e->target ); break; case WET_SHOW: Surface_Show( surface ); break; case WET_HIDE: Surface_Hide( surface ); break; case WET_TITLE: //_DEBUG_MSG("%S\n", e->target->title ); Surface_SetCaptionW( surface, e->target->title ); break; case WET_RESIZE: DEBUG_MSG( "resize, w: %d, h: %d\n", p_rect->w, p_rect->h ); Surface_Resize( surface, p_rect->w, p_rect->h ); Widget_InvalidateArea( w, NULL, SV_GRAPH_BOX ); if( w == LCUIRootWidget && display.mode != LDM_SEAMLESS ) { LCUIDisplay_ExecResize( p_rect->w, p_rect->h ); } break; case WET_MOVE: DEBUG_MSG( "x: %d, y: %d\n", p_rect->left, p_rect->top ); Surface_Move( surface, p_rect->left, p_rect->top ); break; default: break; } }
/** 在 surface 主动产生无效区域的时候 */ static void OnInvalidRect( LCUI_Surface surface, LCUI_Rect *rect ) { int i, n; SurfaceRecord *p_sr; n = LinkedList_GetTotal( &display.surfaces ); for( i=0; i<n; ++i ) { LinkedList_Goto( &display.surfaces, i ); p_sr = (SurfaceRecord*) LinkedList_Get( &display.surfaces ); if( p_sr->surface != surface ) { continue; } Widget_InvalidateArea( p_sr->widget, rect, SV_GRAPH_BOX ); continue; } }
void Widget_Empty(LCUI_Widget w) { LCUI_Widget root = w; while (root->parent) { root = root->parent; } if (root == LCUIWidget.root) { LinkedListNode *next, *node; node = w->children.head.next; while (node) { next = node->next; Widget_AddToTrash(node->data); node = next; } Widget_InvalidateArea(w, NULL, SV_GRAPH_BOX); Widget_AddTask(w, LCUI_WTASK_LAYOUT); } else { Widget_DestroyChildren(w); } }
/** 处理刷新(标记整个部件区域为脏矩形) */ static void HandleRefresh(LCUI_Widget w) { DEBUG_MSG("refresh\n"); Widget_InvalidateArea(w, NULL, SV_GRAPH_BOX); }
/** 处理主体刷新(标记主体区域为脏矩形,但不包括阴影区域) */ static void HandleBody(LCUI_Widget w) { Widget_InvalidateArea(w, NULL, SV_BORDER_BOX); }
void Widget_UpdatePosition(LCUI_Widget w) { LCUI_RectF rect; int position = ComputeStyleOption(w, key_position, SV_STATIC); int valign = ComputeStyleOption(w, key_vertical_align, SV_TOP); w->computed_style.vertical_align = valign; w->computed_style.left = ComputeXMetric(w, key_left); w->computed_style.right = ComputeXMetric(w, key_right); w->computed_style.top = ComputeYMetric(w, key_top); w->computed_style.bottom = ComputeYMetric(w, key_bottom); if (w->parent && w->computed_style.position != position) { w->computed_style.position = position; Widget_UpdateLayout(w->parent); Widget_ClearComputedSize(w); Widget_UpdateChildrenSize(w); /* 当部件尺寸是按百分比动态计算的时候需要重新计算尺寸 */ if (Widget_CheckStyleType(w, key_width, scale) || Widget_CheckStyleType(w, key_height, scale)) { Widget_UpdateSize(w); } } w->computed_style.position = position; Widget_UpdateZIndex(w); rect = w->box.canvas; w->x = w->origin_x; w->y = w->origin_y; switch (position) { case SV_ABSOLUTE: w->x = w->y = 0; if (!Widget_HasAutoStyle(w, key_left)) { w->x = w->computed_style.left; } else if (!Widget_HasAutoStyle(w, key_right)) { if (w->parent) { w->x = w->parent->box.border.width; w->x -= w->width; } w->x -= w->computed_style.right; } if (!Widget_HasAutoStyle(w, key_top)) { w->y = w->computed_style.top; } else if (!Widget_HasAutoStyle(w, key_bottom)) { if (w->parent) { w->y = w->parent->box.border.height; w->y -= w->height; } w->y -= w->computed_style.bottom; } break; case SV_RELATIVE: if (!Widget_HasAutoStyle(w, key_left)) { w->x += w->computed_style.left; } else if (!Widget_HasAutoStyle(w, key_right)) { w->x -= w->computed_style.right; } if (!Widget_HasAutoStyle(w, key_top)) { w->y += w->computed_style.top; } else if (!Widget_HasAutoStyle(w, key_bottom)) { w->y -= w->computed_style.bottom; } default: if (w->parent) { w->x += w->parent->padding.left; w->y += w->parent->padding.top; } break; } switch (valign) { case SV_MIDDLE: if (!w->parent) { break; } w->y += (w->parent->box.content.height - w->height) / 2; break; case SV_BOTTOM: if (!w->parent) { break; } w->y += w->parent->box.content.height - w->height; case SV_TOP: default: break; } w->box.outer.x = w->x; w->box.outer.y = w->y; w->x += w->margin.left; w->y += w->margin.top; /* 以x、y为基础 */ w->box.padding.x = w->x; w->box.padding.y = w->y; w->box.border.x = w->x; w->box.border.y = w->y; w->box.canvas.x = w->x; w->box.canvas.y = w->y; /* 计算各个框的坐标 */ w->box.padding.x += w->computed_style.border.left.width; w->box.padding.y += w->computed_style.border.top.width; w->box.content.x = w->box.padding.x + w->padding.left; w->box.content.y = w->box.padding.y + w->padding.top; w->box.canvas.x -= Widget_GetBoxShadowOffsetX(w); w->box.canvas.y -= Widget_GetBoxShadowOffsetY(w); if (w->parent) { /* 标记移动前后的区域 */ Widget_InvalidateArea(w, NULL, SV_GRAPH_BOX); Widget_InvalidateArea(w->parent, &rect, SV_PADDING_BOX); } /* 检测是否为顶级部件并做相应处理 */ Widget_PostSurfaceEvent(w, LCUI_WEVENT_MOVE, TRUE); }
void Widget_UpdateSize(LCUI_Widget w) { int box_sizing; LCUI_RectF rect = w->box.canvas; LCUI_Rect2F padding = w->padding; box_sizing = ComputeStyleOption(w, key_box_sizing, SV_CONTENT_BOX); w->computed_style.box_sizing = box_sizing; Widget_ComputePadding(w); Widget_ComputeSize(w); /* 如果左右外间距是 auto 类型的,则需要计算外间距 */ if (w->style->sheet[key_margin_left].is_valid && w->style->sheet[key_margin_left].type == LCUI_STYPE_AUTO) { Widget_UpdateMargin(w); } else if (w->style->sheet[key_margin_right].is_valid && w->style->sheet[key_margin_right].type == LCUI_STYPE_AUTO) { Widget_UpdateMargin(w); } /* 若尺寸无变化则不继续处理 */ if (rect.width == w->box.canvas.width && rect.height == w->box.canvas.height && padding.top == w->padding.top && padding.right == w->padding.right && padding.bottom == w->padding.bottom && padding.left == w->padding.left) { return; } /* 若在变化前后的宽高中至少有一个为 0,则不继续处理 */ if ((w->box.canvas.width <= 0 || w->box.canvas.height <= 0) && (rect.width <= 0 || rect.height <= 0)) { return; } Widget_UpdateLayout(w); /* 如果垂直对齐方式不为顶部对齐 */ if (w->computed_style.vertical_align != SV_TOP) { Widget_UpdatePosition(w); } else if (w->computed_style.position == SV_ABSOLUTE) { /* 如果是绝对定位,且指定了右间距或底间距 */ if (!Widget_HasAutoStyle(w, key_right) || !Widget_HasAutoStyle(w, key_bottom)) { Widget_UpdatePosition(w); } } if (w->parent) { /* Mark old area and new area need to repaint */ Widget_InvalidateArea(w->parent, &rect, SV_PADDING_BOX); rect.width = w->box.canvas.width; rect.height = w->box.canvas.height; Widget_InvalidateArea(w->parent, &rect, SV_PADDING_BOX); /* If its width depends on the parent, there is no need to * repeatedly update the parent size and layout. * See Widget_ComputeStaticSize() for more details. */ if (!Widget_HasParentDependentWidth(w)) { if (Widget_HasAutoStyle(w->parent, key_width) || Widget_HasAutoStyle(w->parent, key_height)) { Widget_AddTask(w->parent, LCUI_WTASK_RESIZE); } if (w->computed_style.display != SV_NONE && w->computed_style.position == SV_STATIC) { Widget_UpdateLayout(w->parent); } } } Widget_SendResizeEvent(w); Widget_UpdateChildrenSize(w); }