void GraphNode::_resort() {



	int sep=get_constant("separation");
	Ref<StyleBox> sb=get_stylebox("frame");
	bool first=true;

	Size2 minsize;

	for(int i=0;i<get_child_count();i++) {
		Control *c=get_child(i)->cast_to<Control>();
		if (!c)
			continue;
		if (c->is_set_as_toplevel())
			continue;

		Size2i size=c->get_combined_minimum_size();

		minsize.y+=size.y;
		minsize.x=MAX(minsize.x,size.x);

		if (first)
			first=false;
		else
			minsize.y+=sep;

	}


	int vofs=0;
	int w = get_size().x - sb->get_minimum_size().x;


	cache_y.clear();
	for(int i=0;i<get_child_count();i++) {
		Control *c=get_child(i)->cast_to<Control>();
		if (!c)
			continue;
		if (c->is_set_as_toplevel())
			continue;

		Size2i size=c->get_combined_minimum_size();

		Rect2 r(sb->get_margin(MARGIN_LEFT),sb->get_margin(MARGIN_TOP)+vofs,w,size.y);

		fit_child_in_rect(c,r);
		cache_y.push_back(vofs+size.y*0.5);

		if (vofs>0)
			vofs+=sep;
		vofs+=size.y;


	}

	_change_notify();
	update();
	connpos_dirty=true;


}
Exemple #2
0
void ScrollContainer::_notification(int p_what) {

	if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {

		call_deferred("_update_scrollbar_pos");
	};

	if (p_what == NOTIFICATION_SORT_CHILDREN) {

		child_max_size = Size2(0, 0);
		Size2 size = get_size();
		if (h_scroll->is_visible_in_tree())
			size.y -= h_scroll->get_minimum_size().y;

		if (v_scroll->is_visible_in_tree())
			size.x -= h_scroll->get_minimum_size().x;

		for (int i = 0; i < get_child_count(); i++) {

			Control *c = get_child(i)->cast_to<Control>();
			if (!c)
				continue;
			if (c->is_set_as_toplevel())
				continue;
			if (c == h_scroll || c == v_scroll)
				continue;
			Size2 minsize = c->get_combined_minimum_size();
			child_max_size.x = MAX(child_max_size.x, minsize.x);
			child_max_size.y = MAX(child_max_size.y, minsize.y);

			Rect2 r = Rect2(-scroll, minsize);
			if (!scroll_h || (!h_scroll->is_visible_in_tree() && c->get_h_size_flags() & SIZE_EXPAND)) {
				r.position.x = 0;
				if (c->get_h_size_flags() & SIZE_EXPAND)
					r.size.width = MAX(size.width, minsize.width);
				else
					r.size.width = minsize.width;
			}
			if (!scroll_v || (!v_scroll->is_visible_in_tree() && c->get_v_size_flags() & SIZE_EXPAND)) {
				r.position.y = 0;
				r.size.height = size.height;
				if (c->get_v_size_flags() & SIZE_EXPAND)
					r.size.height = MAX(size.height, minsize.height);
				else
					r.size.height = minsize.height;
			}
			fit_child_in_rect(c, r);
		}
		update();
	};

	if (p_what == NOTIFICATION_DRAW) {

		update_scrollbars();
	}

	if (p_what == NOTIFICATION_FIXED_PROCESS) {

		if (drag_touching) {

			if (drag_touching_deaccel) {

				Vector2 pos = Vector2(h_scroll->get_value(), v_scroll->get_value());
				pos += drag_speed * get_fixed_process_delta_time();

				bool turnoff_h = false;
				bool turnoff_v = false;

				if (pos.x < 0) {
					pos.x = 0;
					turnoff_h = true;
				}
				if (pos.x > (h_scroll->get_max() - h_scroll->get_page())) {
					pos.x = h_scroll->get_max() - h_scroll->get_page();
					turnoff_h = true;
				}

				if (pos.y < 0) {
					pos.y = 0;
					turnoff_v = true;
				}
				if (pos.y > (v_scroll->get_max() - v_scroll->get_page())) {
					pos.y = v_scroll->get_max() - v_scroll->get_page();
					turnoff_v = true;
				}

				if (scroll_h)
					h_scroll->set_value(pos.x);
				if (scroll_v)
					v_scroll->set_value(pos.y);

				float sgn_x = drag_speed.x < 0 ? -1 : 1;
				float val_x = Math::abs(drag_speed.x);
				val_x -= 1000 * get_fixed_process_delta_time();

				if (val_x < 0) {
					turnoff_h = true;
				}

				float sgn_y = drag_speed.y < 0 ? -1 : 1;
				float val_y = Math::abs(drag_speed.y);
				val_y -= 1000 * get_fixed_process_delta_time();

				if (val_y < 0) {
					turnoff_v = true;
				}

				drag_speed = Vector2(sgn_x * val_x, sgn_y * val_y);

				if (turnoff_h && turnoff_v) {
					set_fixed_process(false);
					drag_touching = false;
					drag_touching_deaccel = false;
				}

			} else {

				if (time_since_motion == 0 || time_since_motion > 0.1) {

					Vector2 diff = drag_accum - last_drag_accum;
					last_drag_accum = drag_accum;
					drag_speed = diff / get_fixed_process_delta_time();
				}

				time_since_motion += get_fixed_process_delta_time();
			}
		}
	}
};
void BoxContainer::_resort() {

	/** First pass, determine minimum size AND amount of stretchable elements */


	Size2i new_size=get_size();;

	int sep=get_constant("separation");//,vertical?"VBoxContainer":"HBoxContainer");

	bool first=true;
	int children_count=0;
	int stretch_min=0;
	int stretch_avail=0;
	float stretch_ratio_total=0;
	Map<Control*,_MinSizeCache> min_size_cache;

	for(int i=0;i<get_child_count();i++) {
		Control *c=get_child(i)->cast_to<Control>();
		if (!c || !c->is_visible())
			continue;
		if (c->is_set_as_toplevel())
			continue;

		Size2i size=c->get_combined_minimum_size();
		_MinSizeCache msc;

		if (vertical) { /* VERTICAL */
			stretch_min+=size.height;
			msc.min_size=size.height;
			msc.will_stretch=c->get_v_size_flags() & SIZE_EXPAND;

		} else { /* HORIZONTAL */
			stretch_min+=size.width;
			msc.min_size=size.width;
			msc.will_stretch=c->get_h_size_flags() & SIZE_EXPAND;
		}

		if (msc.will_stretch) {
			stretch_avail+=msc.min_size;
			stretch_ratio_total+=c->get_stretch_ratio();
		}
		msc.final_size=msc.min_size;
		min_size_cache[c]=msc;
		children_count++;
	}

	if (children_count==0)
		return;

	int stretch_max =  (vertical? new_size.height : new_size.width ) - (children_count-1) * sep;
	int stretch_diff = stretch_max - stretch_min;
	if (stretch_diff<0) {
		//avoid negative stretch space
		stretch_max=stretch_min;
		stretch_diff=0;
	}

	stretch_avail+=stretch_diff; //available stretch space.
	/** Second, pass sucessively to discard elements that can't be stretched, this will run while stretchable
		elements exist */


	bool has_stretched = false;
	while(stretch_ratio_total>0) { // first of all, dont even be here if no stretchable objects exist

		has_stretched = true;
		bool refit_successful=true; //assume refit-test will go well

		for(int i=0;i<get_child_count();i++) {

			Control *c=get_child(i)->cast_to<Control>();
			if (!c || !c->is_visible())
				continue;
			if (c->is_set_as_toplevel())
				continue;

			ERR_FAIL_COND(!min_size_cache.has(c));
			_MinSizeCache &msc=min_size_cache[c];

			if (msc.will_stretch) { //wants to stretch
				//let's see if it can really stretch

				int final_pixel_size=stretch_avail * c->get_stretch_ratio() / stretch_ratio_total;
				if (final_pixel_size<msc.min_size) {
					//if available stretching area is too small for widget,
					//then remove it from stretching area
					msc.will_stretch=false;
					stretch_ratio_total-=c->get_stretch_ratio();
					refit_successful=false;
					stretch_avail-=msc.min_size;
					msc.final_size=msc.min_size;
					break;
				} else {
					msc.final_size=final_pixel_size;
				}
			}
		}

		if (refit_successful) //uf refit went well, break
			break;

	}


	/** Final pass, draw and stretch elements **/


	int ofs=0;
	if (!has_stretched) {
		switch (align) {
			case ALIGN_BEGIN:
				break;
			case ALIGN_CENTER:
				ofs = stretch_diff / 2;
				break;
			case ALIGN_END:
				ofs = stretch_diff;
				break;
		}
	}

	first=true;
	int idx=0;

	for(int i=0;i<get_child_count();i++) {

		Control *c=get_child(i)->cast_to<Control>();
		if (!c || !c->is_visible())
			continue;
		if (c->is_set_as_toplevel())
			continue;

		_MinSizeCache &msc=min_size_cache[c];


		if (first)
			first=false;
		else
			ofs+=sep;

		int from=ofs;
		int to=ofs+msc.final_size;


		if (msc.will_stretch && idx==children_count-1) {
			//adjust so the last one always fits perfect
			//compensating for numerical imprecision

			to=vertical?new_size.height:new_size.width;

		}

		int size=to-from;

		Rect2 rect;

		if (vertical) {

			rect=Rect2(0,from,new_size.width,size);
		} else {

			rect=Rect2(from,0,size,new_size.height);

		}

		fit_child_in_rect(c,rect);

		ofs=to;
		idx++;
	}

}