summaryrefslogtreecommitdiff
path: root/scene/gui
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui')
-rw-r--r--scene/gui/dialogs.cpp237
-rw-r--r--scene/gui/dialogs.h20
-rw-r--r--scene/gui/popup.cpp10
-rw-r--r--scene/gui/popup.h4
-rw-r--r--scene/gui/tree.cpp5
-rw-r--r--scene/gui/tree.h1
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;