Merge pull request #7628 from RayKoopa/gui_resizable_popups

Added functionality for resizable WindowDialogs
This commit is contained in:
Rémi Verschelde 2017-03-02 07:57:26 +01:00 committed by GitHub
commit f592d1ebfc
3 changed files with 180 additions and 64 deletions

View file

@ -33,76 +33,145 @@
void WindowDialog::_post_popup() {
dragging=false; //just in case
drag_type = DRAG_NONE; // just in case
}
bool WindowDialog::has_point(const Point2& p_point) const {
Rect2 r(Point2(), get_size());
// Enlarge upwards for title bar.
int titlebar_height = get_constant("titlebar_height", "WindowDialog");
r.pos.y -= titlebar_height;
r.size.y += titlebar_height;
// Inflate by the resizable border thickness.
if (resizable) {
int scaleborder_size = get_constant("scaleborder_size", "WindowDialog");
r.pos.x -= scaleborder_size;
r.size.width += scaleborder_size * 2;
r.pos.y -= scaleborder_size;
r.size.height += scaleborder_size * 2;
}
int extra = get_constant("titlebar_height","WindowDialog");
Rect2 r( Point2(), get_size() );
r.pos.y-=extra;
r.size.y+=extra;
return r.has_point(p_point);
}
void WindowDialog::_gui_input(const InputEvent& p_event) {
if (p_event.type == InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==BUTTON_LEFT) {
if (p_event.type == InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index == BUTTON_LEFT) {
if (p_event.mouse_button.pressed && p_event.mouse_button.y < 0)
dragging=true;
else if (dragging && !p_event.mouse_button.pressed)
dragging=false;
if (p_event.mouse_button.pressed) {
// Begin a possible dragging operation.
drag_type = _drag_hit_test(Point2(p_event.mouse_button.x, p_event.mouse_button.y));
if (drag_type != DRAG_NONE)
drag_offset = get_global_mouse_pos() - get_pos();
drag_offset_far = get_pos() + get_size() - get_global_mouse_pos();
} else if (drag_type != DRAG_NONE && !p_event.mouse_button.pressed) {
// End a dragging operation.
drag_type = DRAG_NONE;
}
}
if (p_event.type == InputEvent::MOUSE_MOTION) {
if (p_event.type == InputEvent::MOUSE_MOTION && dragging) {
if (drag_type == DRAG_NONE) {
// Update the cursor while moving along the borders.
CursorShape cursor = CURSOR_ARROW;
if (resizable) {
int preview_drag_type = _drag_hit_test(Point2(p_event.mouse_button.x, p_event.mouse_button.y));
switch (preview_drag_type) {
case DRAG_RESIZE_TOP:
case DRAG_RESIZE_BOTTOM:
cursor = CURSOR_VSIZE;
break;
case DRAG_RESIZE_LEFT:
case DRAG_RESIZE_RIGHT:
cursor = CURSOR_HSIZE;
break;
case DRAG_RESIZE_TOP + DRAG_RESIZE_LEFT:
case DRAG_RESIZE_BOTTOM + DRAG_RESIZE_RIGHT:
cursor = CURSOR_FDIAGSIZE;
break;
case DRAG_RESIZE_TOP + DRAG_RESIZE_RIGHT:
case DRAG_RESIZE_BOTTOM + DRAG_RESIZE_LEFT:
cursor = CURSOR_BDIAGSIZE;
break;
}
}
if (get_cursor_shape() != cursor)
set_default_cursor_shape(cursor);
} else {
// Update while in a dragging operation.
Point2 global_pos = get_global_mouse_pos();
global_pos.y = MAX(global_pos.y, 0); // Ensure title bar stays visible.
Point2 rel( p_event.mouse_motion.relative_x, p_event.mouse_motion.relative_y );
Point2 pos = get_pos();
Rect2 rect = get_rect();
Size2 min_size = get_minimum_size();
pos+=rel;
if (drag_type == DRAG_MOVE) {
rect.pos = global_pos - drag_offset;
} else {
if (drag_type & DRAG_RESIZE_TOP) {
int bottom = rect.pos.y + rect.size.height;
int max_y = bottom - min_size.height;
rect.pos.y = MIN(global_pos.y - drag_offset.y, max_y);
rect.size.height = bottom - rect.pos.y;
} else if (drag_type & DRAG_RESIZE_BOTTOM) {
rect.size.height = global_pos.y - rect.pos.y + drag_offset_far.y;
}
if (drag_type & DRAG_RESIZE_LEFT) {
int right = rect.pos.x + rect.size.width;
int max_x = right - min_size.width;
rect.pos.x = MIN(global_pos.x - drag_offset.x, max_x);
rect.size.width = right - rect.pos.x;
} else if (drag_type & DRAG_RESIZE_RIGHT) {
rect.size.width = global_pos.x - rect.pos.x + drag_offset_far.x;
}
}
if (pos.y<0)
pos.y=0;
set_pos(pos);
set_size(rect.size);
set_pos(rect.pos);
}
}
}
void WindowDialog::_notification(int p_what) {
switch(p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
RID ci = get_canvas_item();
Size2 s = get_size();
Ref<StyleBox> st = get_stylebox("panel","WindowDialog");
st->draw(ci,Rect2(Point2(),s));
int th = get_constant("title_height","WindowDialog");
Color tc = get_color("title_color","WindowDialog");
Ref<Font> font = get_font("title_font","WindowDialog");
int ofs = (s.width-font->get_string_size(title).width)/2;
//int ofs = st->get_margin(MARGIN_LEFT);
draw_string(font,Point2(ofs,-th+font->get_ascent()),title,tc,s.width - st->get_minimum_size().width);
RID canvas = get_canvas_item();
Size2 size = get_size();
Ref<StyleBox> panel = get_stylebox("panel", "WindowDialog");
panel->draw(canvas, Rect2(Point2(), size));
int title_height = get_constant("title_height", "WindowDialog");
Color title_color = get_color("title_color", "WindowDialog");
Ref<Font> font = get_font("title_font", "WindowDialog");
int ofs = (size.width - font->get_string_size(title).width) / 2;
draw_string(font, Point2(ofs, -title_height + font->get_ascent()), title, title_color, size.width - panel->get_minimum_size().width);
} break;
case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_ENTER_TREE: {
close_button->set_normal_texture(get_icon("close", "WindowDialog"));
close_button->set_pressed_texture(get_icon("close", "WindowDialog"));
close_button->set_hover_texture(get_icon("close_hilite", "WindowDialog"));
close_button->set_anchor(MARGIN_LEFT, ANCHOR_END);
close_button->set_begin(Point2(get_constant("close_h_ofs", "WindowDialog"), -get_constant("close_v_ofs", "WindowDialog")));
} break;
close_button->set_normal_texture( get_icon("close","WindowDialog"));
close_button->set_pressed_texture( get_icon("close","WindowDialog"));
close_button->set_hover_texture( get_icon("close_hilite","WindowDialog"));
close_button->set_anchor(MARGIN_LEFT,ANCHOR_END);
close_button->set_begin( Point2( get_constant("close_h_ofs","WindowDialog"), -get_constant("close_v_ofs","WindowDialog") ));
case NOTIFICATION_MOUSE_EXIT: {
// Reset the mouse cursor when leaving the resizable window border.
if (resizable && !drag_type) {
if (get_default_cursor_shape() != CURSOR_ARROW)
set_default_cursor_shape(CURSOR_ARROW);
}
} break;
}
}
void WindowDialog::_closed() {
@ -111,11 +180,48 @@ void WindowDialog::_closed() {
hide();
}
int WindowDialog::_drag_hit_test(const Point2& pos) const {
int drag_type = DRAG_NONE;
if (resizable) {
int titlebar_height = get_constant("titlebar_height", "WindowDialog");
int scaleborder_size = get_constant("scaleborder_size", "WindowDialog");
Rect2 rect = get_rect();
if (pos.y < (-titlebar_height + scaleborder_size))
drag_type = DRAG_RESIZE_TOP;
else if (pos.y >= (rect.size.height - scaleborder_size))
drag_type = DRAG_RESIZE_BOTTOM;
if (pos.x < scaleborder_size)
drag_type |= DRAG_RESIZE_LEFT;
else if (pos.x >= (rect.size.width - scaleborder_size))
drag_type |= DRAG_RESIZE_RIGHT;
}
if (drag_type == DRAG_NONE && pos.y < 0)
drag_type = DRAG_MOVE;
return drag_type;
}
void WindowDialog::set_title(const String& p_title) {
title=XL_MESSAGE(p_title);
update();
}
String WindowDialog::get_title() const {
return title;
}
void WindowDialog::set_resizable(bool p_resizable) {
resizable = p_resizable;
}
bool WindowDialog::get_resizable() const {
return resizable;
}
Size2 WindowDialog::get_minimum_size() const {
@ -127,11 +233,6 @@ Size2 WindowDialog::get_minimum_size() const {
}
String WindowDialog::get_title() const {
return title;
}
TextureButton *WindowDialog::get_close_button() {
@ -144,19 +245,23 @@ void WindowDialog::_bind_methods() {
ClassDB::bind_method( D_METHOD("_gui_input"),&WindowDialog::_gui_input);
ClassDB::bind_method( D_METHOD("set_title","title"),&WindowDialog::set_title);
ClassDB::bind_method( D_METHOD("get_title"),&WindowDialog::get_title);
ClassDB::bind_method( D_METHOD("set_resizable","resizable"),&WindowDialog::set_resizable);
ClassDB::bind_method( D_METHOD("get_resizable"), &WindowDialog::get_resizable);
ClassDB::bind_method( D_METHOD("_closed"),&WindowDialog::_closed);
ClassDB::bind_method( D_METHOD("get_close_button:TextureButton"),&WindowDialog::get_close_button);
ADD_PROPERTY( PropertyInfo(Variant::STRING,"window_title",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_DEFAULT_INTL),"set_title","get_title");
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"resizable",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_DEFAULT_INTL),"set_resizable","get_resizable");
}
WindowDialog::WindowDialog() {
//title="Hello!";
dragging=false;
close_button = memnew( TextureButton );
drag_type = DRAG_NONE;
resizable = false;
close_button = memnew(TextureButton);
add_child(close_button);
close_button->connect("pressed",this,"_closed");
close_button->connect("pressed", this, "_closed");
}
@ -186,7 +291,7 @@ PopupDialog::~PopupDialog() {
}
//
// AcceptDialog
void AcceptDialog::_post_popup() {

View file

@ -44,12 +44,26 @@ class WindowDialog : public Popup {
GDCLASS(WindowDialog,Popup);
enum DRAG_TYPE {
DRAG_NONE = 0,
DRAG_MOVE = 1,
DRAG_RESIZE_TOP = 1 << 1,
DRAG_RESIZE_RIGHT = 1 << 2,
DRAG_RESIZE_BOTTOM = 1 << 3,
DRAG_RESIZE_LEFT = 1 << 4
};
TextureButton *close_button;
String title;
bool dragging;
int drag_type;
Point2 drag_offset;
Point2 drag_offset_far;
bool resizable;
void _gui_input(const InputEvent& p_event);
void _closed();
int _drag_hit_test(const Point2& pos) const;
protected:
virtual void _post_popup();
@ -63,6 +77,8 @@ public:
void set_title(const String& p_title);
String get_title() const;
void set_resizable(bool p_resizable);
bool get_resizable() const;
Size2 get_minimum_size() const;

View file

@ -583,24 +583,19 @@ void fill_default_theme(Ref<Theme>& t, const Ref<Font> & default_font, const Ref
// WindowDialog
Ref<StyleBoxTexture> style_pp_win = sb_expand(make_stylebox( popup_window_png,10,30,10,8),8,26,8,4);
/*for(int i=0;i<4;i++)
style_pp_win->set_expand_margin_size((Margin)i,3);
style_pp_win->set_expand_margin_size(MARGIN_TOP,26);*/
Ref<StyleBoxTexture> style_pp_win = sb_expand(make_stylebox(popup_window_png, 10, 26, 10, 8), 8, 24, 8, 6);
t->set_stylebox("panel", "WindowDialog", style_pp_win);
t->set_constant("titlebar_height", "WindowDialog", 20 * scale);
t->set_constant("scaleborder_size", "WindowDialog", 4);
t->set_stylebox("panel","WindowDialog", style_pp_win );
t->set_font("title_font", "WindowDialog", large_font);
t->set_color("title_color", "WindowDialog", Color(0, 0, 0));
t->set_constant("title_height", "WindowDialog", 18 * scale);
t->set_icon("close","WindowDialog", make_icon( close_png ) );
t->set_icon("close_hilite","WindowDialog", make_icon( close_hl_png ) );
t->set_font("title_font","WindowDialog", large_font );
t->set_color("title_color","WindowDialog", Color(0,0,0) );
t->set_constant("close_h_ofs","WindowDialog", 22 *scale);
t->set_constant("close_v_ofs","WindowDialog", 20 *scale);
t->set_constant("titlebar_height","WindowDialog", 18 *scale);
t->set_constant("title_height","WindowDialog", 20 *scale);
t->set_icon("close", "WindowDialog", make_icon(close_png));
t->set_icon("close_hilite", "WindowDialog", make_icon(close_hl_png));
t->set_constant("close_h_ofs", "WindowDialog", 18 * scale);
t->set_constant("close_v_ofs", "WindowDialog", 18 * scale);
// File Dialog