예제 #1
0
파일: widget_base.c 프로젝트: lc-soft/LCUI
void Widget_UpdateMargin(LCUI_Widget w)
{
	int i;
	LCUI_BoundBox *mbox = &w->computed_style.margin;
	struct {
		LCUI_Style sval;
		float *fval;
		int key;
	} pd_map[4] = { { &mbox->top, &w->margin.top, key_margin_top },
			{ &mbox->right, &w->margin.right, key_margin_right },
			{ &mbox->bottom, &w->margin.bottom, key_margin_bottom },
			{ &mbox->left, &w->margin.left, key_margin_left } };
	for (i = 0; i < 4; ++i) {
		LCUI_Style s = &w->style->sheet[pd_map[i].key];
		if (!s->is_valid) {
			pd_map[i].sval->type = LCUI_STYPE_PX;
			pd_map[i].sval->px = 0.0;
			*pd_map[i].fval = 0.0;
			continue;
		}
		*pd_map[i].sval = *s;
		*pd_map[i].fval = LCUIMetrics_Compute(s->value, s->type);
	}
	/* 如果有父级部件,则处理 margin-left 和 margin-right 的值 */
	if (w->parent) {
		float width = w->parent->box.content.width;
		if (Widget_HasAutoStyle(w, key_margin_left)) {
			if (Widget_HasAutoStyle(w, key_margin_right)) {
				w->margin.left = (width - w->width) / 2;
				if (w->margin.left < 0) {
					w->margin.left = 0;
				}
				w->margin.right = w->margin.left;
			} else {
				w->margin.left = width - w->width;
				w->margin.left -= w->margin.right;
				if (w->margin.left < 0) {
					w->margin.left = 0;
				}
			}
		} else if (Widget_HasAutoStyle(w, key_margin_right)) {
			w->margin.right = width - w->width;
			w->margin.right -= w->margin.left;
			if (w->margin.right < 0) {
				w->margin.right = 0;
			}
		}
	}
	if (w->parent) {
		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_AddTask(w, LCUI_WTASK_POSITION);
}
예제 #2
0
파일: widget_base.c 프로젝트: lc-soft/LCUI
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);
		}
	}
}
예제 #3
0
static void AsyncLoadImage( LCUI_Widget widget, const char *path )
{
	ImageCache cache;
	LCUI_Task task = {0};
	LCUI_Style *s = &widget->cached_style->sheet[key_background_image];

	if( !is_inited ) {
		RBTree_Init( &images );
		RBTree_Init( &refs );
		RBTree_OnJudge( &refs, OnCompareWidget );
		RBTree_OnJudge( &images, OnComparePath );
		RBTree_OnDestroy( &refs, free );
		RBTree_OnDestroy( &images, OnDestroyCache );
		is_inited = TRUE;
	}
	if( s->is_valid && s->type == SVT_STRING ) {
		cache = RBTree_CustomGetData( &images, s->string );
		if( cache ) {
			DelRef( widget, cache );
		}
	}
	cache = RBTree_CustomGetData( &images, path );
	if( cache ) {
		AddRef( widget, cache );
		Graph_Quote( &widget->computed_style.background.image,
			     &cache->image, NULL );
		Widget_AddTask( widget, WTT_BODY );
		return;
	}
	task.func = ExecLoadImage;
	task.arg[0] = widget;
	task.arg[1] = strdup( path );
	LCUI_AddTask( &task );
}
예제 #4
0
/** 计算背景样式 */
void Widget_ComputeBackgroundStyle( LCUI_Widget widget )
{
	LCUI_Style *s;
	LCUI_StyleSheet ss = widget->style;
	LCUI_Background *bg = &widget->computed_style.background;
	int key = key_background_start + 1;

	for( ; key < key_background_end; ++key ) {
		s = &ss->sheet[key];
		if( !s->is_valid ) {
			continue;
		}
		switch( key ) {
		case key_background_color:
			bg->color = s->color;
			break;
		case key_background_image:
			switch( s->type ) {
			case SVT_IMAGE:
				if( !s->image ) {
					Graph_Init( &bg->image );
					break;
				}
				Graph_Quote( &bg->image, s->image, NULL );
				break;
			case SVT_STRING:
				AsyncLoadImage( widget, s->string );
			default: break;
			}
			break;
		case key_background_position:
			bg->position.using_value = TRUE;
			bg->position.value = s->value;
			break;
		case key_background_position_x:
			bg->position.using_value = FALSE;
			bg->position.x = *s;
			break;
		case key_background_position_y:
			bg->position.using_value = FALSE;
			bg->position.y = *s;
			break;
		case key_background_size:
			bg->size.using_value = TRUE;
			bg->position.value = s->value;
			break;
		case key_background_size_width:
			bg->size.using_value = FALSE;
			bg->size.w = *s;
			break;
		case key_background_size_height:
			bg->size.using_value = FALSE;
			bg->size.h = *s;
			break;
		default: break;
		}
	}
	Widget_AddTask( widget, WTT_BODY );
}
예제 #5
0
파일: widget_task.c 프로젝트: lc-soft/LCUI
/** 更新当前任务状态,确保部件的任务能够被处理到 */
void Widget_UpdateTaskStatus( LCUI_Widget widget )
{
    int i;
    for( i = 0; i < WTT_TOTAL_NUM; ++i ) {
        if( widget->task.buffer[i] ) {
            widget->task.for_self = TRUE;
            Widget_AddTask( widget, widget->task.buffer[i] );
        }
    }
}
예제 #6
0
파일: widget_task.c 프로젝트: lc-soft/LCUI
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);
	}
}
예제 #7
0
파일: widget_base.c 프로젝트: lc-soft/LCUI
static void Widget_SendResizeEvent(LCUI_Widget w)
{
	LCUI_WidgetEventRec e;
	e.target = w;
	e.data = NULL;
	e.type = LCUI_WEVENT_RESIZE;
	e.cancel_bubble = TRUE;
	Widget_TriggerEvent(w, &e, NULL);
	Widget_AddTask(w, LCUI_WTASK_REFRESH);
	Widget_PostSurfaceEvent(w, LCUI_WEVENT_RESIZE, FALSE);
}
예제 #8
0
파일: widget_base.c 프로젝트: lc-soft/LCUI
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);
	}
}
예제 #9
0
파일: widget_base.c 프로젝트: lc-soft/LCUI
static LCUI_BOOL Widget_ComputeStaticSize(LCUI_Widget w, float *width,
					  float *height)
{
	LCUI_WidgetBoxModelRec *box = &w->box;
	LCUI_WidgetStyle *style = &w->computed_style;

	/* If it is non-static layout */
	if (style->display == SV_NONE || style->position == SV_ABSOLUTE) {
		return FALSE;
	}
	if (Widget_HasParentDependentWidth(w)) {
		/* Compute the full size of child widget */
		Widget_AutoSize(w);
		/* Recompute the actual size of child widget later */
		Widget_AddTask(w, LCUI_WTASK_RESIZE);
	}
	/* If its width is a percentage, it ignores the effect of its outer
	 * and inner spacing on the static width. */
	if (Widget_CheckStyleType(w, key_width, scale)) {
		if (style->box_sizing == SV_BORDER_BOX) {
			*width = box->border.x + box->border.width;
		} else {
			*width = box->content.x + box->content.width;
			*width -= box->content.x - box->border.x;
		}
		*width -= box->outer.x - box->border.x;
	} else if (box->outer.width <= 0) {
		return FALSE;
	} else {
		*width = box->outer.x + box->outer.width;
	}
	if (Widget_CheckStyleType(w, key_height, scale)) {
		if (style->box_sizing == SV_BORDER_BOX) {
			*height = box->border.y + box->border.height;
		} else {
			*height = box->content.y + box->content.height;
			*height -= box->content.y - box->border.y;
		}
		*height -= box->outer.y - box->border.y;
	} else if (box->outer.height <= 0) {
		return FALSE;
	} else {
		*height = box->outer.y + box->outer.height;
	}
	return TRUE;
}
예제 #10
0
파일: widget_base.c 프로젝트: lc-soft/LCUI
void Widget_SetTitleW(LCUI_Widget w, const wchar_t *title)
{
	int len;
	wchar_t *new_title, *old_title;

	len = wcslen(title) + 1;
	new_title = (wchar_t *)malloc(sizeof(wchar_t) * len);
	if (!new_title) {
		return;
	}
	wcsncpy(new_title, title, len);
	old_title = w->title;
	w->title = new_title;
	if (old_title) {
		free(old_title);
	}
	Widget_AddTask(w, LCUI_WTASK_TITLE);
}
예제 #11
0
파일: widget_base.c 프로젝트: lc-soft/LCUI
LCUI_Widget LCUIWidget_New(const char *type)
{
	ASSIGN(widget, LCUI_Widget);
	Widget_Init(widget);
	widget->node.data = widget;
	widget->node_show.data = widget;
	widget->node.next = widget->node.prev = NULL;
	widget->node_show.next = widget->node_show.prev = NULL;
	if (type) {
		widget->proto = LCUIWidget_GetPrototype(type);
		if (widget->proto) {
			widget->type = widget->proto->name;
			widget->proto->init(widget);
		} else {
			widget->type = strdup2(type);
		}
	}
	Widget_AddTask(widget, LCUI_WTASK_REFRESH_STYLE);
	return widget;
}
예제 #12
0
static void ExecLoadImage( void *arg1, void *arg2 )
{
	char *path = arg2;
	LCUI_Graph image;
	LCUI_Widget widget = arg1;
	ImageCache cache;

	Graph_Init( &image );
	if( Graph_LoadImage( path, &image ) != 0 ) {
		return;
	}
	cache = NEW(ImageCacheRec, 1);
	cache->ref_count = 0;
	cache->image = image;
	cache->path = path;
	RBTree_CustomInsert( &images, path, cache );
	AddRef( widget, cache );
	Graph_Quote( &widget->computed_style.background.image,
		     &cache->image, NULL );
	Widget_AddTask( widget, WTT_BODY );
}
예제 #13
0
파일: widget_base.c 프로젝트: lc-soft/LCUI
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);
	}
}
예제 #14
0
파일: widget_base.c 프로젝트: lc-soft/LCUI
void Widget_UpdateZIndex(LCUI_Widget w)
{
	Widget_AddTask(w, LCUI_WTASK_ZINDEX);
}
예제 #15
0
파일: widget_base.c 프로젝트: lc-soft/LCUI
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);
}