diff options
Diffstat (limited to 'scene/gui')
| -rw-r--r-- | scene/gui/dialogs.cpp | 237 | ||||
| -rw-r--r-- | scene/gui/dialogs.h | 20 | ||||
| -rw-r--r-- | scene/gui/popup.cpp | 10 | ||||
| -rw-r--r-- | scene/gui/popup.h | 4 | ||||
| -rw-r--r-- | scene/gui/tree.cpp | 5 | ||||
| -rw-r--r-- | scene/gui/tree.h | 1 |
6 files changed, 216 insertions, 61 deletions
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index e08d933e03..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() { @@ -144,19 +273,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 +319,7 @@ PopupDialog::~PopupDialog() { } -// +// AcceptDialog void AcceptDialog::_post_popup() { diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h index 6650c5eb5d..dd75b76c8e 100644 --- a/scene/gui/dialogs.h +++ b/scene/gui/dialogs.h @@ -44,15 +44,29 @@ 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(); - + virtual void _fix_size(); virtual void _close_pressed() {} virtual bool has_point(const Point2& p_point) const; void _notification(int p_what); @@ -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; diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 60ecd775f7..1f0daa99ba 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -226,12 +226,16 @@ void Popup::popup_centered_ratio(float p_screen_ratio) { } -void Popup::popup() { +void Popup::popup(const Rect2& bounds) { emit_signal("about_to_show"); show_modal(exclusive); - + // Fit the popup into the optionally provided bounds. + if (!bounds.has_no_area()) { + set_pos(bounds.pos); + set_size(bounds.size); + } _fix_size(); Control *focusable = find_next_valid_focus(); @@ -260,7 +264,7 @@ void Popup::_bind_methods() { ClassDB::bind_method(D_METHOD("popup_centered","size"),&Popup::popup_centered,DEFVAL(Size2())); ClassDB::bind_method(D_METHOD("popup_centered_ratio","ratio"),&Popup::popup_centered_ratio,DEFVAL(0.75)); ClassDB::bind_method(D_METHOD("popup_centered_minsize","minsize"),&Popup::popup_centered_minsize,DEFVAL(Size2())); - ClassDB::bind_method(D_METHOD("popup"),&Popup::popup); + ClassDB::bind_method(D_METHOD("popup","bounds"),&Popup::popup,DEFVAL(Rect2())); ClassDB::bind_method(D_METHOD("set_exclusive","enable"),&Popup::set_exclusive); ClassDB::bind_method(D_METHOD("is_exclusive"),&Popup::is_exclusive); ADD_SIGNAL( MethodInfo("about_to_show") ); diff --git a/scene/gui/popup.h b/scene/gui/popup.h index 17ae4a938a..4e4c8b0292 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -47,7 +47,7 @@ protected: void _gui_input(InputEvent p_event); void _notification(int p_what); - void _fix_size(); + virtual void _fix_size(); static void _bind_methods(); public: @@ -63,7 +63,7 @@ public: void popup_centered(const Size2& p_size=Size2()); void popup_centered_minsize(const Size2& p_minsize=Size2()); void set_as_minsize(); - virtual void popup(); + virtual void popup(const Rect2& p_bounds=Rect2()); virtual String get_configuration_warning() const; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index cd93c13c99..292efdcc01 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -848,7 +848,6 @@ void Tree::update_cache() { cache.title_button_color = get_color("title_button_color"); v_scroll->set_custom_step(cache.font->get_height()); - cache.click_item=get_selected(); } @@ -1611,6 +1610,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ cache.click_id=c.buttons[j].id; cache.click_item=p_item; cache.click_column=col; + cache.click_pos=get_global_mouse_pos()-get_global_pos(); update(); //emit_signal("button_pressed"); return -1; @@ -2391,6 +2391,8 @@ void Tree::_gui_input(InputEvent p_event) { if (cache.click_type==Cache::CLICK_BUTTON) { + // make sure in case of wrong reference after reconstructing whole TreeItems + cache.click_item=get_item_at_pos(cache.click_pos); emit_signal("button_pressed",cache.click_item,cache.click_column,cache.click_id); } @@ -2971,7 +2973,6 @@ void Tree::clear() { selected_item=NULL; edited_item=NULL; popup_edited_item=NULL; - selected_item=NULL; update(); }; diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 351cc4cb50..14bd2efbaa 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -409,6 +409,7 @@ friend class TreeItem; TreeItem *click_item; int click_column; int hover_index; + Point2 click_pos; } cache; |