diff options
Diffstat (limited to 'scene/gui/dialogs.cpp')
-rw-r--r-- | scene/gui/dialogs.cpp | 285 |
1 files changed, 209 insertions, 76 deletions
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index cc6fe7cae8..6d06f8c59c 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -33,76 +33,173 @@ void WindowDialog::_post_popup() { - dragging=false; //just in case + drag_type = DRAG_NONE; // just in case +} + +void WindowDialog::_fix_size() { + + // Perhaps this should be called when the viewport resizes aswell or windows go out of bounds... + + // Ensure the whole window is visible. + Point2i pos = get_global_pos(); + Size2i size = get_size(); + Size2i viewport_size = get_viewport_rect().size; + + // Windows require additional padding to keep the window chrome visible. + Ref<StyleBox> panel = get_stylebox("panel", "WindowDialog"); + float top = panel->get_margin(MARGIN_TOP); + float left = panel->get_margin(MARGIN_LEFT); + float bottom = panel->get_margin(MARGIN_BOTTOM); + float right = panel->get_margin(MARGIN_RIGHT); + + pos.x = MAX(left, MIN(pos.x, viewport_size.x - size.x - right)); + pos.y = MAX(top, MIN(pos.y, viewport_size.y - size.y - bottom)); + set_global_pos(pos); + + // Also resize the window to fit if a resize should be possible at all. + if (resizable) { + size.x = MIN(size.x, viewport_size.x - left - right); + size.y = MIN(size.y, viewport_size.y - top - bottom); + set_size(size); + } } bool WindowDialog::has_point(const Point2& p_point) const { + Rect2 r(Point2(), get_size()); - 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); + // 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; + } + + 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.mouse_button.pressed && p_event.mouse_button.y < 0) - dragging=true; - else if (dragging && !p_event.mouse_button.pressed) - dragging=false; + if (p_event.type == InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index == BUTTON_LEFT) { + + 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 && dragging) { - - Point2 rel( p_event.mouse_motion.relative_x, p_event.mouse_motion.relative_y ); - Point2 pos = get_pos(); - - pos+=rel; - - if (pos.y<0) - pos.y=0; - - set_pos(pos); + if (p_event.type == InputEvent::MOUSE_MOTION) { + + 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. + + Rect2 rect = get_rect(); + Size2 min_size = get_minimum_size(); + + 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; + } + } + + 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 +208,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 +261,6 @@ Size2 WindowDialog::get_minimum_size() const { } -String WindowDialog::get_title() const { - - return title; -} - TextureButton *WindowDialog::get_close_button() { @@ -141,22 +270,26 @@ TextureButton *WindowDialog::get_close_button() { void WindowDialog::_bind_methods() { - ClassDB::bind_method( _MD("_gui_input"),&WindowDialog::_gui_input); - ClassDB::bind_method( _MD("set_title","title"),&WindowDialog::set_title); - ClassDB::bind_method( _MD("get_title"),&WindowDialog::get_title); - ClassDB::bind_method( _MD("_closed"),&WindowDialog::_closed); - ClassDB::bind_method( _MD("get_close_button:TextureButton"),&WindowDialog::get_close_button); + 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),_SCS("set_title"),_SCS("get_title")); + 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 +319,7 @@ PopupDialog::~PopupDialog() { } -// +// AcceptDialog void AcceptDialog::_post_popup() { @@ -201,7 +334,7 @@ void AcceptDialog::_notification(int p_what) { if (p_what==NOTIFICATION_MODAL_CLOSE) { cancel_pressed(); - } if (p_what==NOTIFICATION_RESIZED) { + } else if (p_what==NOTIFICATION_RESIZED) { _update_child_rects(); } @@ -272,7 +405,7 @@ void AcceptDialog::_update_child_rects() { if (!c) continue; - if (c==hbc || c==label || c==get_close_button()) + if (c==hbc || c==label || c==get_close_button() || c->is_set_as_toplevel()) continue; c->set_pos(cpos); @@ -299,7 +432,7 @@ Size2 AcceptDialog::get_minimum_size() const { if (!c) continue; - if (c==hbc || c==label || c==const_cast<AcceptDialog*>(this)->get_close_button()) + if (c==hbc || c==label || c==const_cast<AcceptDialog*>(this)->get_close_button() || c->is_set_as_toplevel()) continue; Size2 cminsize = c->get_combined_minimum_size(); @@ -361,25 +494,25 @@ Button* AcceptDialog::add_cancel(const String &p_cancel) { void AcceptDialog::_bind_methods() { - ClassDB::bind_method(_MD("_ok"),&AcceptDialog::_ok_pressed); - ClassDB::bind_method(_MD("get_ok"),&AcceptDialog::get_ok); - ClassDB::bind_method(_MD("get_label"),&AcceptDialog::get_label); - ClassDB::bind_method(_MD("set_hide_on_ok","enabled"),&AcceptDialog::set_hide_on_ok); - ClassDB::bind_method(_MD("get_hide_on_ok"),&AcceptDialog::get_hide_on_ok); - ClassDB::bind_method(_MD("add_button:Button","text","right","action"),&AcceptDialog::add_button,DEFVAL(false),DEFVAL("")); - ClassDB::bind_method(_MD("add_cancel:Button","name"),&AcceptDialog::add_cancel); - ClassDB::bind_method(_MD("_builtin_text_entered"),&AcceptDialog::_builtin_text_entered); - ClassDB::bind_method(_MD("register_text_enter:LineEdit","line_edit"),&AcceptDialog::register_text_enter); - ClassDB::bind_method(_MD("_custom_action"),&AcceptDialog::_custom_action); - ClassDB::bind_method(_MD("set_text","text"),&AcceptDialog::set_text); - ClassDB::bind_method(_MD("get_text"),&AcceptDialog::get_text); + ClassDB::bind_method(D_METHOD("_ok"),&AcceptDialog::_ok_pressed); + ClassDB::bind_method(D_METHOD("get_ok"),&AcceptDialog::get_ok); + ClassDB::bind_method(D_METHOD("get_label"),&AcceptDialog::get_label); + ClassDB::bind_method(D_METHOD("set_hide_on_ok","enabled"),&AcceptDialog::set_hide_on_ok); + ClassDB::bind_method(D_METHOD("get_hide_on_ok"),&AcceptDialog::get_hide_on_ok); + ClassDB::bind_method(D_METHOD("add_button:Button","text","right","action"),&AcceptDialog::add_button,DEFVAL(false),DEFVAL("")); + ClassDB::bind_method(D_METHOD("add_cancel:Button","name"),&AcceptDialog::add_cancel); + ClassDB::bind_method(D_METHOD("_builtin_text_entered"),&AcceptDialog::_builtin_text_entered); + ClassDB::bind_method(D_METHOD("register_text_enter:LineEdit","line_edit"),&AcceptDialog::register_text_enter); + ClassDB::bind_method(D_METHOD("_custom_action"),&AcceptDialog::_custom_action); + ClassDB::bind_method(D_METHOD("set_text","text"),&AcceptDialog::set_text); + ClassDB::bind_method(D_METHOD("get_text"),&AcceptDialog::get_text); ADD_SIGNAL( MethodInfo("confirmed") ); ADD_SIGNAL( MethodInfo("custom_action",PropertyInfo(Variant::STRING,"action")) ); ADD_GROUP("Dialog","dialog"); - ADD_PROPERTYNZ( PropertyInfo(Variant::STRING,"dialog_text",PROPERTY_HINT_MULTILINE_TEXT,"",PROPERTY_USAGE_DEFAULT_INTL),_SCS("set_text"),_SCS("get_text")); - ADD_PROPERTY( PropertyInfo(Variant::BOOL, "dialog_hide_on_ok"),_SCS("set_hide_on_ok"),_SCS("get_hide_on_ok") ); + ADD_PROPERTYNZ( PropertyInfo(Variant::STRING,"dialog_text",PROPERTY_HINT_MULTILINE_TEXT,"",PROPERTY_USAGE_DEFAULT_INTL),"set_text","get_text"); + ADD_PROPERTY( PropertyInfo(Variant::BOOL, "dialog_hide_on_ok"),"set_hide_on_ok","get_hide_on_ok") ; } @@ -429,7 +562,7 @@ AcceptDialog::~AcceptDialog() void ConfirmationDialog::_bind_methods() { - ClassDB::bind_method(_MD("get_cancel:Button"),&ConfirmationDialog::get_cancel); + ClassDB::bind_method(D_METHOD("get_cancel:Button"),&ConfirmationDialog::get_cancel); } Button *ConfirmationDialog::get_cancel() { |