summaryrefslogtreecommitdiff
path: root/scene/gui
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui')
-rw-r--r--scene/gui/SCsub2
-rw-r--r--scene/gui/base_button.cpp10
-rw-r--r--scene/gui/box_container.cpp36
-rw-r--r--scene/gui/box_container.h17
-rw-r--r--scene/gui/button_group.cpp2
-rw-r--r--scene/gui/button_group.h6
-rw-r--r--scene/gui/control.cpp15
-rw-r--r--scene/gui/control.h2
-rw-r--r--scene/gui/dialogs.cpp2
-rw-r--r--scene/gui/graph_edit.cpp199
-rw-r--r--scene/gui/graph_edit.h13
-rw-r--r--scene/gui/graph_node.cpp62
-rw-r--r--scene/gui/graph_node.h11
-rw-r--r--scene/gui/item_list.cpp70
-rw-r--r--scene/gui/item_list.h3
-rw-r--r--scene/gui/label.cpp275
-rw-r--r--scene/gui/label.h40
-rw-r--r--scene/gui/line_edit.cpp163
-rw-r--r--scene/gui/line_edit.h23
-rw-r--r--scene/gui/menu_button.cpp4
-rw-r--r--scene/gui/patch_9_frame.cpp132
-rw-r--r--scene/gui/patch_9_frame.h40
-rw-r--r--scene/gui/popup_menu.cpp23
-rw-r--r--scene/gui/range.cpp2
-rw-r--r--scene/gui/rich_text_label.cpp21
-rw-r--r--scene/gui/scroll_container.cpp10
-rw-r--r--scene/gui/spin_box.cpp54
-rw-r--r--scene/gui/spin_box.h12
-rw-r--r--scene/gui/tab_container.cpp89
-rw-r--r--scene/gui/tabs.cpp257
-rw-r--r--scene/gui/tabs.h20
-rw-r--r--scene/gui/text_edit.cpp131
-rw-r--r--scene/gui/text_edit.h1
-rw-r--r--scene/gui/texture_progress.cpp182
-rw-r--r--scene/gui/texture_progress.h31
-rw-r--r--scene/gui/tree.cpp486
-rw-r--r--scene/gui/tree.h19
-rw-r--r--scene/gui/video_player.cpp197
-rw-r--r--scene/gui/video_player.h34
39 files changed, 2182 insertions, 514 deletions
diff --git a/scene/gui/SCsub b/scene/gui/SCsub
index 055d2f2474..bbe59b3054 100644
--- a/scene/gui/SCsub
+++ b/scene/gui/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.scene_sources,"*.cpp")
Export('env')
-
-
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 965e7f399d..0c63a3bc74 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -255,6 +255,16 @@ void BaseButton::_notification(int p_what) {
group->_remove_button(this);
}
+ if (p_what==NOTIFICATION_VISIBILITY_CHANGED && !is_visible()) {
+
+ if (!toggle_mode) {
+ status.pressed = false;
+ }
+ status.hovering = false;
+ status.press_attempt = false;
+ status.pressing_inside = false;
+ status.pressing_button = 0;
+ }
}
void BaseButton::pressed() {
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index 6489cbccd5..b63b3de530 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -99,8 +99,10 @@ void BoxContainer::_resort() {
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++) {
@@ -143,6 +145,18 @@ void BoxContainer::_resort() {
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;
@@ -254,6 +268,15 @@ void BoxContainer::_notification(int p_what) {
}
}
+void BoxContainer::set_alignment(AlignMode p_align) {
+ align = p_align;
+ _resort();
+}
+
+BoxContainer::AlignMode BoxContainer::get_alignment() const {
+ return align;
+}
+
void BoxContainer::add_spacer(bool p_begin) {
Control *c = memnew( Control );
@@ -270,10 +293,23 @@ void BoxContainer::add_spacer(bool p_begin) {
BoxContainer::BoxContainer(bool p_vertical) {
vertical=p_vertical;
+ align = ALIGN_BEGIN;
// set_ignore_mouse(true);
set_stop_mouse(false);
}
+void BoxContainer::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("get_alignment"),&BoxContainer::get_alignment);
+ ObjectTypeDB::bind_method(_MD("set_alignment","alignment"),&BoxContainer::set_alignment);
+
+ BIND_CONSTANT( ALIGN_BEGIN );
+ BIND_CONSTANT( ALIGN_CENTER );
+ BIND_CONSTANT( ALIGN_END );
+
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"alignment", PROPERTY_HINT_ENUM, "Begin,Center,End"), _SCS("set_alignment"),_SCS("get_alignment") );
+
+}
MarginContainer* VBoxContainer::add_margin_child(const String& p_label,Control *p_control,bool p_expand) {
diff --git a/scene/gui/box_container.h b/scene/gui/box_container.h
index d461b4aebe..c357814baf 100644
--- a/scene/gui/box_container.h
+++ b/scene/gui/box_container.h
@@ -35,16 +35,31 @@ class BoxContainer : public Container {
OBJ_TYPE(BoxContainer,Container);
+public:
+
+ enum AlignMode {
+ ALIGN_BEGIN,
+ ALIGN_CENTER,
+ ALIGN_END
+ };
+
+private:
bool vertical;
+ AlignMode align;
void _resort();
protected:
void _notification(int p_what);
+
+ static void _bind_methods();
public:
void add_spacer(bool p_begin=false);
+ void set_alignment(AlignMode p_align);
+ AlignMode get_alignment() const;
+
virtual Size2 get_minimum_size() const;
BoxContainer(bool p_vertical=false);
@@ -73,4 +88,6 @@ public:
VBoxContainer() : BoxContainer(true) {}
};
+VARIANT_ENUM_CAST(BoxContainer::AlignMode);
+
#endif // BOX_CONTAINER_H
diff --git a/scene/gui/button_group.cpp b/scene/gui/button_group.cpp
index 8d1fa80b84..c92d7f2696 100644
--- a/scene/gui/button_group.cpp
+++ b/scene/gui/button_group.cpp
@@ -155,6 +155,6 @@ void ButtonGroup::_bind_methods() {
}
-ButtonGroup::ButtonGroup()
+ButtonGroup::ButtonGroup() : BoxContainer(true)
{
}
diff --git a/scene/gui/button_group.h b/scene/gui/button_group.h
index 24edf94994..74e847e937 100644
--- a/scene/gui/button_group.h
+++ b/scene/gui/button_group.h
@@ -29,14 +29,14 @@
#ifndef BUTTON_GROUP_H
#define BUTTON_GROUP_H
-#include "scene/gui/control.h"
+#include "scene/gui/box_container.h"
class BaseButton;
-class ButtonGroup : public Control {
+class ButtonGroup : public BoxContainer {
- OBJ_TYPE(ButtonGroup,Control);
+ OBJ_TYPE(ButtonGroup,BoxContainer);
Set<BaseButton*> buttons;
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index a1c0644650..bd6b8078ff 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -2713,6 +2713,21 @@ void Control::warp_mouse(const Point2& p_to_pos) {
get_viewport()->warp_mouse(get_global_transform().xform(p_to_pos));
}
+
+bool Control::is_text_field() const {
+/*
+ if (get_script_instance()) {
+ Variant v=p_point;
+ const Variant *p[2]={&v,&p_data};
+ Variant::CallError ce;
+ Variant ret = get_script_instance()->call("is_text_field",p,2,ce);
+ if (ce.error==Variant::CallError::CALL_OK)
+ return ret;
+ }
+ */
+ return false;
+}
+
void Control::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_window_input_event"),&Control::_window_input_event);
diff --git a/scene/gui/control.h b/scene/gui/control.h
index a759fafbc9..4311b299c8 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -382,6 +382,8 @@ public:
void warp_mouse(const Point2& p_to_pos);
+ virtual bool is_text_field() const;
+
Control();
~Control();
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 3ddf23fc4a..0c0f924f52 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -274,7 +274,7 @@ Button* AcceptDialog::add_button(const String& p_text,bool p_right,const String&
}
if (p_action!="") {
- button->connect("pressed",this,"_custom_action",make_binds(p_action));
+ button->connect("pressed",this,"_custom_action",varray(p_action));
}
return button;
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 3cd0dd3d16..deb3151798 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -141,9 +141,6 @@ void GraphEdit::_graph_node_moved(Node *p_gn) {
GraphNode *gn=p_gn->cast_to<GraphNode>();
ERR_FAIL_COND(!gn);
-
- //gn->set_pos(gn->get_offset()+scroll_offset);
-
top_layer->update();
}
@@ -172,7 +169,6 @@ void GraphEdit::remove_child_notify(Node *p_child) {
void GraphEdit::_notification(int p_what) {
if (p_what==NOTIFICATION_READY) {
- Size2 size = top_layer->get_size();
Size2 hmin = h_scroll->get_combined_minimum_size();
Size2 vmin = v_scroll->get_combined_minimum_size();
@@ -491,7 +487,8 @@ void GraphEdit::_top_layer_draw() {
connections.erase(to_erase.front()->get());
to_erase.pop_front();
}
- //draw connections
+ if (box_selecting)
+ top_layer->draw_rect(box_selecting_rect,Color(0.7,0.7,1.0,0.3));
}
void GraphEdit::_input_event(const InputEvent& p_ev) {
@@ -500,6 +497,187 @@ void GraphEdit::_input_event(const InputEvent& p_ev) {
h_scroll->set_val( h_scroll->get_val() - p_ev.mouse_motion.relative_x );
v_scroll->set_val( v_scroll->get_val() - p_ev.mouse_motion.relative_y );
}
+
+ if (p_ev.type==InputEvent::MOUSE_MOTION && dragging) {
+
+ just_selected=true;
+ drag_accum+=Vector2(p_ev.mouse_motion.relative_x,p_ev.mouse_motion.relative_y);
+ for(int i=get_child_count()-1;i>=0;i--) {
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (gn && gn->is_selected())
+ gn->set_offset(gn->get_drag_from()+drag_accum);
+ }
+ }
+
+ if (p_ev.type==InputEvent::MOUSE_MOTION && box_selecting) {
+ box_selecting_to = get_local_mouse_pos();
+
+ box_selecting_rect = Rect2(MIN(box_selecting_from.x,box_selecting_to.x),
+ MIN(box_selecting_from.y,box_selecting_to.y),
+ ABS(box_selecting_from.x-box_selecting_to.x),
+ ABS(box_selecting_from.y-box_selecting_to.y));
+
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn)
+ continue;
+
+ bool in_box = gn->get_rect().intersects(box_selecting_rect);
+
+ if (in_box)
+ gn->set_selected(box_selection_mode_aditive);
+ else
+ gn->set_selected(previus_selected.find(gn)!=NULL);
+ }
+
+ top_layer->update();
+ }
+
+ if (p_ev.type==InputEvent::MOUSE_BUTTON) {
+
+ const InputEventMouseButton &b=p_ev.mouse_button;
+
+ if (b.button_index==BUTTON_RIGHT && b.pressed)
+ {
+ if (box_selecting) {
+ box_selecting = false;
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn)
+ continue;
+
+ gn->set_selected(previus_selected.find(gn)!=NULL);
+ }
+ top_layer->update();
+ } else {
+ emit_signal("popup_request", Vector2(b.global_x, b.global_y));
+ }
+ }
+
+ if (b.button_index==BUTTON_LEFT && !b.pressed && dragging) {
+ if (!just_selected && drag_accum==Vector2() && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ //deselect current node
+ for(int i=get_child_count()-1;i>=0;i--) {
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+
+ if (gn && gn->get_rect().has_point(get_local_mouse_pos()))
+ gn->set_selected(false);
+ }
+ }
+
+ if (drag_accum!=Vector2()) {
+
+ emit_signal("_begin_node_move");
+
+ for(int i=get_child_count()-1;i>=0;i--) {
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (gn && gn->is_selected())
+ gn->set_drag(false);
+ }
+
+ emit_signal("_end_node_move");
+ }
+
+ dragging = false;
+
+ top_layer->update();
+ }
+
+ if (b.button_index==BUTTON_LEFT && b.pressed) {
+
+ GraphNode *gn;
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ gn=get_child(i)->cast_to<GraphNode>();
+
+ if (gn && gn->get_rect().has_point(get_local_mouse_pos()))
+ break;
+ }
+
+ if (gn) {
+
+ if (_filter_input(Vector2(b.x,b.y)))
+ return;
+
+ dragging = true;
+ drag_accum = Vector2();
+ just_selected = !gn->is_selected();
+ if(!gn->is_selected() && !Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ for (int i = 0; i < get_child_count(); i++) {
+ GraphNode *o_gn = get_child(i)->cast_to<GraphNode>();
+ if (o_gn)
+ o_gn->set_selected(o_gn == gn);
+ }
+ }
+
+ gn->set_selected(true);
+ for (int i = 0; i < get_child_count(); i++) {
+ GraphNode *o_gn = get_child(i)->cast_to<GraphNode>();
+ if (!o_gn)
+ continue;
+ if (o_gn->is_selected())
+ o_gn->set_drag(true);
+ }
+
+ } else {
+ box_selecting = true;
+ box_selecting_from = get_local_mouse_pos();
+ if (b.mod.control) {
+ box_selection_mode_aditive = true;
+ previus_selected.clear();
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn || !gn->is_selected())
+ continue;
+
+ previus_selected.push_back(gn);
+ }
+ } else if (b.mod.shift) {
+ box_selection_mode_aditive = false;
+ previus_selected.clear();
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn || !gn->is_selected())
+ continue;
+
+ previus_selected.push_back(gn);
+ }
+ } else {
+ box_selection_mode_aditive = true;
+ previus_selected.clear();
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn)
+ continue;
+
+ gn->set_selected(false);
+ }
+ }
+ }
+ }
+
+ if (b.button_index==BUTTON_LEFT && !b.pressed && box_selecting) {
+ box_selecting = false;
+ previus_selected.clear();
+ top_layer->update();
+ }
+ }
+
+ if (p_ev.type==InputEvent::KEY && p_ev.key.scancode==KEY_D && p_ev.key.pressed && p_ev.key.mod.command) {
+ emit_signal("duplicate_nodes_request");
+ accept_event();
+ }
+
+ if (p_ev.type==InputEvent::KEY && p_ev.key.scancode==KEY_DELETE && p_ev.key.pressed) {
+ emit_signal("delete_nodes_request");
+ accept_event();
+ }
+
}
void GraphEdit::clear_connections() {
@@ -555,12 +733,18 @@ void GraphEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("connection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot")));
ADD_SIGNAL(MethodInfo("disconnection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot")));
-
+ ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2,"p_position")));
+ ADD_SIGNAL(MethodInfo("duplicate_nodes_request"));
+ ADD_SIGNAL(MethodInfo("delete_nodes_request"));
+ ADD_SIGNAL(MethodInfo("_begin_node_move"));
+ ADD_SIGNAL(MethodInfo("_end_node_move"));
}
GraphEdit::GraphEdit() {
+ set_focus_mode(FOCUS_ALL);
+
top_layer=NULL;
top_layer=memnew(GraphEditFilter(this));
add_child(top_layer);
@@ -581,6 +765,9 @@ GraphEdit::GraphEdit() {
connecting=false;
right_disconnects=false;
+ box_selecting = false;
+ dragging = false;
+
h_scroll->connect("value_changed", this,"_scroll_moved");
v_scroll->connect("value_changed", this,"_scroll_moved");
}
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 0a9da73ab6..44f5a369c2 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -10,7 +10,7 @@ class GraphEditFilter : public Control {
OBJ_TYPE(GraphEditFilter,Control);
-friend class GraphEdit;
+ friend class GraphEdit;
GraphEdit *ge;
virtual bool has_point(const Point2& p_point) const;
@@ -49,7 +49,16 @@ private:
String connecting_target_to;
int connecting_target_index;
+ bool dragging;
+ bool just_selected;
+ Vector2 drag_accum;
+ bool box_selecting;
+ bool box_selection_mode_aditive;
+ Point2 box_selecting_from;
+ Point2 box_selecting_to;
+ Rect2 box_selecting_rect;
+ List<GraphNode*> previus_selected;
bool right_disconnects;
bool updating;
@@ -71,7 +80,7 @@ private:
Array _get_connection_list() const;
-friend class GraphEditFilter;
+ friend class GraphEditFilter;
bool _filter_input(const Point2& p_point);
protected:
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 444b37855f..5efc9757b7 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -40,7 +40,7 @@ bool GraphNode::_get(const StringName& p_name,Variant &r_ret) const{
- if (!p_name.operator String().begins_with("slot/")) {
+ if (!p_name.operator String().begins_with("slot/")) {
return false;
}
@@ -160,7 +160,7 @@ void GraphNode::_notification(int p_what) {
if (p_what==NOTIFICATION_DRAW) {
- Ref<StyleBox> sb=get_stylebox("frame");
+ Ref<StyleBox> sb=get_stylebox(selected ? "selectedframe" : "frame");
Ref<Texture> port =get_icon("port");
Ref<Texture> close =get_icon("close");
int close_offset = get_constant("close_offset");
@@ -360,6 +360,29 @@ Vector2 GraphNode::get_offset() const {
return offset;
}
+void GraphNode::set_selected(bool p_selected)
+{
+ selected = p_selected;
+ update();
+}
+
+bool GraphNode::is_selected()
+{
+ return selected;
+}
+
+void GraphNode::set_drag(bool p_drag)
+{
+ if (p_drag)
+ drag_from=get_offset();
+ else
+ emit_signal("dragged",drag_from,get_offset()); //useful for undo/redo
+}
+
+Vector2 GraphNode::get_drag_from()
+{
+ return drag_from;
+}
void GraphNode::set_show_close_button(bool p_enable){
@@ -379,7 +402,6 @@ void GraphNode::_connpos_update() {
int sep=get_constant("separation");
Ref<StyleBox> sb=get_stylebox("frame");
- Ref<Texture> port =get_icon("port");
conn_input_cache.clear();
conn_output_cache.clear();
int vofs=0;
@@ -503,31 +525,17 @@ Color GraphNode::get_connection_output_color(int p_idx) {
void GraphNode::_input_event(const InputEvent& p_ev) {
- if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
+ if (p_ev.type==InputEvent::MOUSE_BUTTON) {
+ get_parent_control()->grab_focus();
+ if(p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
- Vector2 mpos = Vector2(p_ev.mouse_button.x,p_ev.mouse_button.y);
- if (close_rect.size!=Size2() && close_rect.has_point(mpos)) {
- emit_signal("close_request");
- return;
+ Vector2 mpos = Vector2(p_ev.mouse_button.x,p_ev.mouse_button.y);
+ if (close_rect.size!=Size2() && close_rect.has_point(mpos)) {
+ emit_signal("close_request");
+ return;
+ }
+ emit_signal("raise_request");
}
-
- drag_from=get_offset();
- drag_accum=Vector2();
- dragging=true;
- emit_signal("raise_request");
-
- }
-
- if (p_ev.type==InputEvent::MOUSE_BUTTON && !p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
-
- dragging=false;
- emit_signal("dragged",drag_from,get_offset()); //useful for undo/redo
- }
-
- if (p_ev.type==InputEvent::MOUSE_MOTION && dragging) {
-
- drag_accum+=Vector2(p_ev.mouse_motion.relative_x,p_ev.mouse_motion.relative_y);
- set_offset(drag_from+drag_accum);
}
}
@@ -576,8 +584,6 @@ void GraphNode::_bind_methods() {
}
GraphNode::GraphNode() {
-
- dragging=false;
show_close=false;
connpos_dirty=true;
}
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index 0d5cbf8dd3..201529380d 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -18,7 +18,7 @@ class GraphNode : public Container {
Color color_right;
- Slot() { enable_left=false; type_left=0; color_left=Color(1,1,1,1); enable_right=false; type_right=0; color_right=Color(1,1,1,1); };
+ Slot() { enable_left=false; type_left=0; color_left=Color(1,1,1,1); enable_right=false; type_right=0; color_right=Color(1,1,1,1); }
};
String title;
@@ -46,8 +46,7 @@ class GraphNode : public Container {
void _resort();
Vector2 drag_from;
- Vector2 drag_accum;
- bool dragging;
+ bool selected;
protected:
void _input_event(const InputEvent& p_ev);
@@ -79,6 +78,12 @@ public:
void set_offset(const Vector2& p_offset);
Vector2 get_offset() const;
+ void set_selected(bool p_selected);
+ bool is_selected();
+
+ void set_drag(bool p_drag);
+ Vector2 get_drag_from();
+
void set_show_close_button(bool p_enable);
bool is_close_button_visible() const;
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index c29f6625d3..f035cb7722 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -187,6 +187,7 @@ void ItemList::select(int p_idx,bool p_single){
}
current=p_idx;
+ ensure_selected_visible=false;
} else {
if (items[p_idx].selectable) {
@@ -195,6 +196,7 @@ void ItemList::select(int p_idx,bool p_single){
}
update();
+
}
void ItemList::unselect(int p_idx){
@@ -233,6 +235,37 @@ int ItemList::get_current() const {
return current;
}
+void ItemList::move_item(int p_item,int p_to_pos) {
+
+ ERR_FAIL_INDEX(p_item,items.size());
+ ERR_FAIL_INDEX(p_to_pos,items.size()+1);
+
+ Item it=items[p_item];
+ items.remove(p_item);;
+
+ if (p_to_pos>p_item) {
+ p_to_pos--;
+ }
+
+ if (p_to_pos>=items.size()) {
+ items.push_back(it);
+ } else {
+ items.insert(p_to_pos,it);
+ }
+
+ if (current<0) {
+ //do none
+ } if (p_item==current) {
+ current=p_to_pos;
+ } else if (p_to_pos>p_item && current>p_item && current<p_to_pos) {
+ current--;
+ } else if (p_to_pos<p_item && current<p_item && current>p_to_pos) {
+ current++;
+ }
+
+
+ update();
+}
int ItemList::get_item_count() const{
@@ -246,12 +279,14 @@ void ItemList::remove_item(int p_idx){
update();
shape_changed=true;
+
}
void ItemList::clear(){
items.clear();
current=-1;
+ ensure_selected_visible=false;
update();
}
@@ -602,18 +637,8 @@ void ItemList::_input_event(const InputEvent& p_event) {
void ItemList::ensure_current_is_visible() {
- if (current>=0 && current <=items.size()) {
-
- Rect2 r = items[current].rect_cache;
- int from = scroll_bar->get_val();
- int to = from + scroll_bar->get_page();
-
- if (r.pos.y < from) {
- scroll_bar->set_val(r.pos.y);
- } else if (r.pos.y+r.size.y > to) {
- scroll_bar->set_val(r.pos.y+r.size.y - (to-from));
- }
- }
+ ensure_selected_visible=true;
+ update();
}
void ItemList::_notification(int p_what) {
@@ -928,6 +953,24 @@ void ItemList::_notification(int p_what) {
draw_line(Vector2(bg->get_margin(MARGIN_LEFT),base_ofs.y+separators[i]),Vector2(size.width-bg->get_margin(MARGIN_LEFT),base_ofs.y+separators[i]),guide_color);
}
+
+ if (ensure_selected_visible && current>=0 && current <=items.size()) {
+
+ Rect2 r = items[current].rect_cache;
+ int from = scroll_bar->get_val();
+ int to = from + scroll_bar->get_page();
+
+ if (r.pos.y < from) {
+ scroll_bar->set_val(r.pos.y);
+ } else if (r.pos.y+r.size.y > to) {
+ scroll_bar->set_val(r.pos.y+r.size.y - (to-from));
+ }
+
+
+ }
+
+ ensure_selected_visible=false;
+
}
}
@@ -1013,7 +1056,7 @@ void ItemList::_bind_methods(){
ObjectTypeDB::bind_method(_MD("get_item_text","idx"),&ItemList::get_item_text);
ObjectTypeDB::bind_method(_MD("set_item_icon","idx","icon:Texture"),&ItemList::set_item_icon);
- ObjectTypeDB::bind_method(_MD("get_item_icon:Tedture","idx"),&ItemList::get_item_icon);
+ ObjectTypeDB::bind_method(_MD("get_item_icon:Texture","idx"),&ItemList::get_item_icon);
ObjectTypeDB::bind_method(_MD("set_item_selectable","idx","selectable"),&ItemList::set_item_selectable);
ObjectTypeDB::bind_method(_MD("is_item_selectable","idx"),&ItemList::is_item_selectable);
@@ -1095,6 +1138,7 @@ ItemList::ItemList() {
set_focus_mode(FOCUS_ALL);
current_columns=1;
search_time_msec=0;
+ ensure_selected_visible=false;
}
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
index 237079c428..bd3cf6484e 100644
--- a/scene/gui/item_list.h
+++ b/scene/gui/item_list.h
@@ -41,6 +41,8 @@ private:
bool shape_changed;
+ bool ensure_selected_visible;
+
Vector<Item> items;
Vector<int> separators;
@@ -99,6 +101,7 @@ public:
void set_current(int p_current);
int get_current() const;
+ void move_item(int p_item,int p_to_pos);
int get_item_count() const;
void remove_item(int p_idx);
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index e7af4fa349..002e49cbcf 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -33,15 +33,15 @@
void Label::set_autowrap(bool p_autowrap) {
-
+
autowrap=p_autowrap;
word_cache_dirty=true;
minimum_size_changed();
-
-
+ update();
+
}
bool Label::has_autowrap() const {
-
+
return autowrap;
}
@@ -51,6 +51,7 @@ void Label::set_uppercase(bool p_uppercase) {
uppercase=p_uppercase;
word_cache_dirty=true;
minimum_size_changed();
+ update();
}
bool Label::is_uppercase() const {
@@ -66,19 +67,18 @@ int Label::get_line_height() const {
void Label::_notification(int p_what) {
-
+
if (p_what==NOTIFICATION_DRAW) {
-
- if (clip && !autowrap)
- VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(),true);
+ if (clip || autowrap)
+ VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(),true);
if (word_cache_dirty)
regenerate_word_cache();
-
+
RID ci = get_canvas_item();
-
+
Size2 string_size;
Size2 size=get_size();
@@ -91,38 +91,43 @@ void Label::_notification(int p_what) {
VisualServer::get_singleton()->canvas_item_set_distance_field_mode(get_canvas_item(),font.is_valid() && font->is_distance_field_hint());
int font_h = font->get_height();
- int line_from=(int)get_val(); // + p_exposed.pos.y / font_h;
int lines_visible = size.y/font_h;
- int line_to=(int)get_val() + lines_visible; //p_exposed.pos.y+p_exposed.size.height / font_h;
int space_w=font->get_char_size(' ').width;
- int lines_total = get_max();
int chars_total=0;
int vbegin=0,vsep=0;
-
- if (lines_total && lines_total < lines_visible) {
+ if (lines_visible > line_count) {
+ lines_visible = line_count;
+
+ }
+
+ if (max_lines_visible >= 0 && lines_visible > max_lines_visible) {
+ lines_visible = max_lines_visible;
+
+ }
+
+ if (lines_visible > 0) {
switch(valign) {
case VALIGN_TOP: {
-
//nothing
} break;
case VALIGN_CENTER: {
-
- vbegin=(lines_visible-lines_total) * font_h / 2;
+ vbegin=(size.y - lines_visible * font_h) / 2;
vsep=0;
+
} break;
case VALIGN_BOTTOM: {
- vbegin=(lines_visible-lines_total) * font_h;
+ vbegin=size.y - lines_visible * font_h;
vsep=0;
} break;
case VALIGN_FILL: {
vbegin=0;
- if (lines_total>1) {
- vsep=(lines_visible-lines_total) * font_h / (lines_total-1);
+ if (lines_visible>1) {
+ vsep=(size.y - lines_visible * font_h) / (lines_visible - 1);
} else {
vsep=0;
}
@@ -130,20 +135,21 @@ void Label::_notification(int p_what) {
} break;
}
}
-
-
+
+
WordCache *wc = word_cache;
if (!wc)
return;
-
+
int c = 0;
int line=0;
+ int line_to=lines_skipped + (lines_visible>0?lines_visible:1);
while(wc) {
/* handle lines not meant to be drawn quickly */
- if (line>line_to)
+ if (line>=line_to)
break;
- if (line<line_from) {
-
+ if (line<lines_skipped) {
+
while (wc && wc->char_pos>=0)
wc=wc->next;
if (wc)
@@ -151,36 +157,36 @@ void Label::_notification(int p_what) {
line++;
continue;
}
-
+
/* handle lines normally */
-
+
if (wc->char_pos<0) {
//empty line
wc=wc->next;
line++;
continue;
}
-
+
WordCache *from=wc;
WordCache *to=wc;
-
+
int taken=0;
int spaces=0;
while(to && to->char_pos>=0) {
-
+
taken+=to->pixel_width;
if (to!=from && to->space_count) {
spaces+=to->space_count;
}
to=to->next;
}
-
+
bool can_fill = to && to->char_pos==WordCache::CHAR_WRAPLINE;
float x_ofs=0;
-
+
switch (align) {
-
+
case ALIGN_FILL:
case ALIGN_LEFT: {
@@ -198,16 +204,16 @@ void Label::_notification(int p_what) {
} break;
}
-
- int y_ofs=(line-(int)get_val())*font_h + font->get_ascent();
+
+ int y_ofs=(line-lines_skipped)*font_h + font->get_ascent();
y_ofs+=vbegin + line*vsep;
-
+
while(from!=to) {
-
+
// draw a word
int pos = from->char_pos;
if (from->char_pos<0) {
-
+
ERR_PRINT("BUG");
return;
}
@@ -221,15 +227,15 @@ void Label::_notification(int p_what) {
}
-
-
-
+
+
+
if (font_color_shadow.a>0) {
-
+
int chars_total_shadow = chars_total; //save chars drawn
float x_ofs_shadow=x_ofs;
for (int i=0;i<from->word_len;i++) {
-
+
if (visible_chars < 0 || chars_total_shadow<visible_chars) {
CharType c = text[i+pos];
CharType n = text[i+pos+1];
@@ -249,7 +255,7 @@ void Label::_notification(int p_what) {
}
}
-
+
}
for (int i=0;i<from->word_len;i++) {
@@ -268,73 +274,73 @@ void Label::_notification(int p_what) {
}
from=from->next;
}
-
+
wc=to?to->next:0;
line++;
-
- }
+
+ }
}
-
+
if (p_what==NOTIFICATION_THEME_CHANGED) {
word_cache_dirty=true;
update();
}
if (p_what==NOTIFICATION_RESIZED) {
-
+
word_cache_dirty=true;
}
-
+
}
Size2 Label::get_minimum_size() const {
-
+
if (autowrap)
return Size2(1,1);
else {
-
+
// don't want to mutable everything
- if(word_cache_dirty)
+ if(word_cache_dirty)
const_cast<Label*>(this)->regenerate_word_cache();
-
+
Size2 ms=minsize;
if (clip)
ms.width=1;
return ms;
- }
+ }
}
int Label::get_longest_line_width() const {
-
+
Ref<Font> font = get_font("font");
int max_line_width=0;
int line_width=0;
-
- for (int i=0;i<text.size()+1;i++) {
-
- CharType current=i<text.length()?text[i]:' '; //always a space at the end, so the algo works
+
+ for (int i=0;i<text.size();i++) {
+
+ CharType current=text[i];
if (uppercase)
current=String::char_uppercase(current);
if (current<32) {
-
+
if (current=='\n') {
-
+
if (line_width>max_line_width)
max_line_width=line_width;
line_width=0;
}
} else {
-
+
int char_width=font->get_char_size(current).width;
- line_width+=char_width;
+ line_width+=char_width;
}
-
+
}
if (line_width>max_line_width)
max_line_width=line_width;
-
+
return max_line_width;
}
@@ -349,15 +355,15 @@ int Label::get_line_count() const {
}
void Label::regenerate_word_cache() {
-
+
while (word_cache) {
-
+
WordCache *current=word_cache;
word_cache=current->next;
memdelete( current );
}
-
-
+
+
int width=autowrap?get_size().width:get_longest_line_width();
Ref<Font> font = get_font("font");
@@ -368,11 +374,11 @@ void Label::regenerate_word_cache() {
int space_width=font->get_char_size(' ').width;
line_count=1;
total_char_cache=0;
-
+
WordCache *last=NULL;
-
+
for (int i=0;i<text.size()+1;i++) {
-
+
CharType current=i<text.length()?text[i]:' '; //always a space at the end, so the algo works
if (uppercase)
@@ -429,12 +435,12 @@ void Label::regenerate_word_cache() {
if (current_word_size==0) {
word_pos=i;
}
-
+
char_width=font->get_char_size(current).width;
current_word_size+=char_width;
line_width+=char_width;
total_char_cache++;
-
+
}
if ((autowrap && (line_width >= width) && ((last && last->char_pos >= 0) || separatable)) || insert_newline) {
@@ -474,29 +480,22 @@ void Label::regenerate_word_cache() {
space_count=0;
}
-
+
}
-
- //total_char_cache -= line_count + 1; // do not count new lines (including the first one)
-
+
if (!autowrap) {
-
minsize.width=width;
- minsize.height=font->get_height()*line_count;
- set_page( line_count );
-
- } else {
-
- set_page( get_size().height / font->get_height() );
+ if (max_lines_visible > 0 && line_count > max_lines_visible) {
+ minsize.height=font->get_height()*max_lines_visible;
+ } else {
+ minsize.height=font->get_height()*line_count;
+ }
}
-
- set_max(line_count);
-
+
word_cache_dirty=false;
}
-
void Label::set_align(Align p_align) {
ERR_FAIL_INDEX(p_align,4);
@@ -505,7 +504,7 @@ void Label::set_align(Align p_align) {
}
Label::Align Label::get_align() const{
-
+
return align;
}
@@ -522,24 +521,23 @@ Label::VAlign Label::get_valign() const{
}
void Label::set_text(const String& p_string) {
-
+
String str = XL_MESSAGE(p_string);
if (text==str)
return;
-
+
text=str;
word_cache_dirty=true;
+ if (percent_visible<1)
+ visible_chars=get_total_character_count()*percent_visible;
update();
- if (!autowrap)
- minimum_size_changed();
-
+ minimum_size_changed();
+
}
void Label::set_clip_text(bool p_clip) {
- if (clip==p_clip)
- return;
clip=p_clip;
update();
minimum_size_changed();
@@ -551,23 +549,39 @@ bool Label::is_clipping_text() const {
}
String Label::get_text() const {
-
+
return text;
}
void Label::set_visible_characters(int p_amount) {
visible_chars=p_amount;
+ if (get_total_character_count() > 0) {
+ percent_visible=(float)p_amount/(float)total_char_cache;
+ }
update();
}
+int Label::get_visible_characters() const {
+
+ return visible_chars;
+}
+
void Label::set_percent_visible(float p_percent) {
- if (p_percent<0)
- set_visible_characters(-1);
- else
- set_visible_characters(get_total_character_count()*p_percent);
- percent_visible=p_percent;
+ if (p_percent<0 || p_percent>=1) {
+
+ visible_chars=-1;
+ percent_visible=1;
+
+ } else {
+
+ visible_chars=get_total_character_count()*p_percent;
+ percent_visible=p_percent;
+
+ }
+ update();
+
}
float Label::get_percent_visible() const{
@@ -575,6 +589,27 @@ float Label::get_percent_visible() const{
return percent_visible;
}
+void Label::set_lines_skipped(int p_lines) {
+
+ lines_skipped=p_lines;
+ update();
+}
+
+int Label::get_lines_skipped() const{
+
+ return lines_skipped;
+}
+
+void Label::set_max_lines_visible(int p_lines) {
+
+ max_lines_visible=p_lines;
+ update();
+}
+
+int Label::get_max_lines_visible() const{
+
+ return max_lines_visible;
+}
int Label::get_total_character_count() const {
@@ -585,7 +620,7 @@ int Label::get_total_character_count() const {
}
void Label::_bind_methods() {
-
+
ObjectTypeDB::bind_method(_MD("set_align","align"),&Label::set_align);
ObjectTypeDB::bind_method(_MD("get_align"),&Label::get_align);
ObjectTypeDB::bind_method(_MD("set_valign","valign"),&Label::set_valign);
@@ -594,14 +629,21 @@ void Label::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_text"),&Label::get_text);
ObjectTypeDB::bind_method(_MD("set_autowrap","enable"),&Label::set_autowrap);
ObjectTypeDB::bind_method(_MD("has_autowrap"),&Label::has_autowrap);
+ ObjectTypeDB::bind_method(_MD("set_clip_text","enable"),&Label::set_clip_text);
+ ObjectTypeDB::bind_method(_MD("is_clipping_text"),&Label::is_clipping_text);
ObjectTypeDB::bind_method(_MD("set_uppercase","enable"),&Label::set_uppercase);
ObjectTypeDB::bind_method(_MD("is_uppercase"),&Label::is_uppercase);
ObjectTypeDB::bind_method(_MD("get_line_height"),&Label::get_line_height);
ObjectTypeDB::bind_method(_MD("get_line_count"),&Label::get_line_count);
ObjectTypeDB::bind_method(_MD("get_total_character_count"),&Label::get_total_character_count);
- ObjectTypeDB::bind_method(_MD("set_visible_characters"),&Label::set_visible_characters);
+ ObjectTypeDB::bind_method(_MD("set_visible_characters","amount"),&Label::set_visible_characters);
+ ObjectTypeDB::bind_method(_MD("get_visible_characters"),&Label::get_visible_characters);
ObjectTypeDB::bind_method(_MD("set_percent_visible","percent_visible"),&Label::set_percent_visible);
ObjectTypeDB::bind_method(_MD("get_percent_visible"),&Label::get_percent_visible);
+ ObjectTypeDB::bind_method(_MD("set_lines_skipped","lines_skipped"),&Label::set_lines_skipped);
+ ObjectTypeDB::bind_method(_MD("get_lines_skipped"),&Label::get_lines_skipped);
+ ObjectTypeDB::bind_method(_MD("set_max_lines_visible","lines_visible"),&Label::set_max_lines_visible);
+ ObjectTypeDB::bind_method(_MD("get_max_lines_visible"),&Label::get_max_lines_visible);
BIND_CONSTANT( ALIGN_LEFT );
BIND_CONSTANT( ALIGN_CENTER );
@@ -617,18 +659,21 @@ void Label::_bind_methods() {
ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "align", PROPERTY_HINT_ENUM,"Left,Center,Right,Fill" ),_SCS("set_align"),_SCS("get_align") );
ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "valign", PROPERTY_HINT_ENUM,"Top,Center,Bottom,Fill" ),_SCS("set_valign"),_SCS("get_valign") );
ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "autowrap"),_SCS("set_autowrap"),_SCS("has_autowrap") );
+ ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "clip_text"),_SCS("set_clip_text"),_SCS("is_clipping_text") );
ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "uppercase"),_SCS("set_uppercase"),_SCS("is_uppercase") );
ADD_PROPERTY( PropertyInfo( Variant::REAL, "percent_visible", PROPERTY_HINT_RANGE,"0,1,0.001"),_SCS("set_percent_visible"),_SCS("get_percent_visible") );
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "lines_skipped", PROPERTY_HINT_RANGE,"0,999,1"),_SCS("set_lines_skipped"),_SCS("get_lines_skipped") );
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "max_lines_visible", PROPERTY_HINT_RANGE,"-1,999,1"),_SCS("set_max_lines_visible"),_SCS("get_max_lines_visible") );
}
Label::Label(const String &p_text) {
-
+
align=ALIGN_LEFT;
valign=VALIGN_TOP;
text="";
word_cache=NULL;
- word_cache_dirty=true;
+ word_cache_dirty=true;
autowrap=false;
line_count=0;
set_v_size_flags(0);
@@ -636,20 +681,22 @@ Label::Label(const String &p_text) {
set_ignore_mouse(true);
total_char_cache=0;
visible_chars=-1;
- percent_visible=-1;
+ percent_visible=1;
+ lines_skipped=0;
+ max_lines_visible=-1;
set_text(p_text);
uppercase=false;
}
Label::~Label() {
-
+
while (word_cache) {
-
+
WordCache *current=word_cache;
word_cache=current->next;
memdelete( current );
- }
+ }
}
diff --git a/scene/gui/label.h b/scene/gui/label.h
index 81e3ab5676..4ea9f5d377 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -29,17 +29,17 @@
#ifndef LABEL_H
#define LABEL_H
-#include "scene/gui/range.h"
+#include "scene/gui/control.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
-class Label : public Range {
-
- OBJ_TYPE( Label, Range );
-public:
-
+class Label : public Control {
+
+ OBJ_TYPE( Label, Control );
+public:
+
enum Align {
-
+
ALIGN_LEFT,
ALIGN_CENTER,
ALIGN_RIGHT,
@@ -63,11 +63,11 @@ private:
Size2 minsize;
int line_count;
bool uppercase;
-
+
int get_longest_line_width() const;
-
+
struct WordCache {
-
+
enum {
CHAR_NEWLINE=-1,
CHAR_WRAPLINE=-2
@@ -78,23 +78,25 @@ private:
int space_count;
WordCache *next;
WordCache() { char_pos=0; word_len=0; pixel_width=0; next=0; space_count=0;}
- };
-
+ };
+
bool word_cache_dirty;
void regenerate_word_cache();
float percent_visible;
-
+
WordCache *word_cache;
int total_char_cache;
int visible_chars;
-protected:
+ int lines_skipped;
+ int max_lines_visible;
+protected:
void _notification(int p_what);
static void _bind_methods();
// bind helpers
public:
-
+
virtual Size2 get_minimum_size() const;
void set_align(Align p_align);
@@ -105,7 +107,7 @@ public:
void set_text(const String& p_string);
String get_text() const;
-
+
void set_autowrap(bool p_autowrap);
bool has_autowrap() const;
@@ -113,6 +115,7 @@ public:
bool is_uppercase() const;
void set_visible_characters(int p_amount);
+ int get_visible_characters() const;
int get_total_character_count() const;
void set_clip_text(bool p_clip);
@@ -121,6 +124,11 @@ public:
void set_percent_visible(float p_percent);
float get_percent_visible() const;
+ void set_lines_skipped(int p_lines);
+ int get_lines_skipped() const;
+
+ void set_max_lines_visible(int p_lines);
+ int get_max_lines_visible() const;
int get_line_height() const;
int get_line_count() const;
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index fec9e401f1..18de8ed568 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -145,6 +145,13 @@ void LineEdit::_input_event(InputEvent p_event) {
int old_cursor_pos = cursor_pos;
text = undo_text;
+
+ Ref<Font> font = get_font("font");
+
+ cached_width = 0;
+ for (int i = 0; i<text.length(); i++)
+ cached_width += font->get_char_size(text[i]).width;
+
if(old_cursor_pos > text.length()) {
set_cursor_pos(text.length());
} else {
@@ -164,6 +171,15 @@ void LineEdit::_input_event(InputEvent p_event) {
selection_clear();
undo_text = text;
text = text.substr(cursor_pos,text.length()-cursor_pos);
+
+ Ref<Font> font = get_font("font");
+
+ cached_width = 0;
+ if (font != NULL) {
+ for (int i = 0; i < text.length(); i++)
+ cached_width += font->get_char_size(text[i]).width;
+ }
+
set_cursor_pos(0);
emit_signal("text_changed",text);
_change_notify("text");
@@ -192,6 +208,9 @@ void LineEdit::_input_event(InputEvent p_event) {
}
} break;
+ case (KEY_A): { //Select All
+ select();
+ } break;
default: { handled=false;}
}
@@ -303,6 +322,18 @@ void LineEdit::_input_event(InputEvent p_event) {
}
}
+void LineEdit::set_align(Align p_align) {
+
+ ERR_FAIL_INDEX(p_align, 4);
+ align = p_align;
+ update();
+}
+
+LineEdit::Align LineEdit::get_align() const{
+
+ return align;
+}
+
Variant LineEdit::get_drag_data(const Point2& p_point) {
if (selection.drag_attempt && selection.enabled) {
@@ -325,7 +356,15 @@ void LineEdit::drop_data(const Point2& p_point,const Variant& p_data){
if (p_data.get_type()==Variant::STRING) {
set_cursor_at_pixel_pos(p_point.x);
int selected = selection.end - selection.begin;
+
+ Ref<Font> font = get_font("font");
+ if (font != NULL) {
+ for (int i = selection.begin; i < selection.end; i++)
+ cached_width -= font->get_char_size(text[i]).width;
+ }
+
text.erase(selection.begin, selected);
+
append_at_cursor(p_data);
selection.begin = cursor_pos-selected;
selection.end = cursor_pos;
@@ -365,8 +404,25 @@ void LineEdit::_notification(int p_what) {
get_stylebox("focus")->draw( ci, Rect2( Point2(), size ) );
}
-
- int ofs=style->get_offset().x;
+ int x_ofs=0;
+
+ switch (align) {
+
+ case ALIGN_FILL:
+ case ALIGN_LEFT: {
+
+ x_ofs=style->get_offset().x;
+ } break;
+ case ALIGN_CENTER: {
+
+ x_ofs=x_ofs=int(size.width-(cached_width))/2;
+ } break;
+ case ALIGN_RIGHT: {
+
+ x_ofs=x_ofs=int(size.width-style->get_offset().x-(cached_width));
+ } break;
+ }
+
int ofs_max=width-style->get_minimum_size().width;
int char_ofs=window_pos;
@@ -391,29 +447,29 @@ void LineEdit::_notification(int p_what) {
int char_width=font->get_char_size( cchar,next ).width;
// end of widget, break!
- if ( (ofs+char_width) > ofs_max )
+ if ((x_ofs + char_width) > ofs_max)
break;
bool selected=selection.enabled && char_ofs>=selection.begin && char_ofs<selection.end;
if (selected)
- VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2( Point2( ofs , y_ofs ),Size2( char_width, y_area )),selection_color);
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(char_width, y_area)), selection_color);
- font->draw_char(ci,Point2( ofs , y_ofs+font_ascent ), cchar, next,selected?font_color_selected:font_color );
+ font->draw_char(ci, Point2(x_ofs, y_ofs + font_ascent), cchar, next, selected ? font_color_selected : font_color);
if (char_ofs==cursor_pos && has_focus())
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(
- Point2( ofs , y_ofs ), Size2( 1, y_area ) ), cursor_color );
+ Point2( x_ofs , y_ofs ), Size2( 1, y_area ) ), cursor_color );
- ofs+=char_width;
+ x_ofs+=char_width;
char_ofs++;
}
if (char_ofs==cursor_pos && has_focus()) //may be at the end
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(
- Point2( ofs , y_ofs ), Size2( 1, y_area ) ), cursor_color );
+ Point2( x_ofs , y_ofs ), Size2( 1, y_area ) ), cursor_color );
} break;
case NOTIFICATION_FOCUS_ENTER: {
@@ -484,13 +540,36 @@ void LineEdit::shift_selection_check_post(bool p_shift) {
void LineEdit::set_cursor_at_pixel_pos(int p_x) {
- int ofs=window_pos;
- int pixel_ofs=get_stylebox("normal")->get_offset().x;
- Ref<Font> font=get_font("font");
+ Ref<Font> font = get_font("font");
+ int ofs = window_pos;
+ Ref<StyleBox> style = get_stylebox("normal");
+ int pixel_ofs = 0;
+ Size2 size = get_size();
+
+ switch (align) {
+
+ case ALIGN_FILL:
+ case ALIGN_LEFT: {
+
+ pixel_ofs = int(style->get_offset().x);
+ } break;
+ case ALIGN_CENTER: {
+
+ pixel_ofs=int(size.width-(cached_width))/2;
+ } break;
+ case ALIGN_RIGHT: {
+
+ pixel_ofs=int(size.width-style->get_offset().x-(cached_width));
+ } break;
+ }
+
while (ofs<text.length()) {
- int char_w=font->get_char_size( text[ofs] ).width;
+ int char_w = 0;
+ if (font != NULL) {
+ int char_w = font->get_char_size(text[ofs]).width;
+ }
pixel_ofs+=char_w;
if (pixel_ofs > p_x) { //found what we look for
@@ -523,6 +602,10 @@ void LineEdit::delete_char() {
if ((text.length()<=0) || (cursor_pos==0)) return;
+ Ref<Font> font = get_font("font");
+ if (font != NULL) {
+ cached_width -= font->get_char_size(text[cursor_pos - 1]).width;
+ }
text.erase( cursor_pos-1, 1 );
@@ -593,13 +676,15 @@ void LineEdit::set_cursor_pos(int p_pos) {
int width_to_cursor=0;
int wp=window_pos;
- for (int i=window_pos;i<cursor_pos;i++)
- width_to_cursor+=font->get_char_size( text[i] ).width;
+ if (font != NULL) {
+ for (int i=window_pos;i<cursor_pos;i++)
+ width_to_cursor+=font->get_char_size( text[i] ).width;
- while(width_to_cursor>=window_width && wp<text.length()) {
-
- width_to_cursor-=font->get_char_size( text[ wp ] ).width;
- wp++;
+ while (width_to_cursor >= window_width && wp < text.length()) {
+
+ width_to_cursor -= font->get_char_size(text[wp]).width;
+ wp++;
+ }
}
if (wp!=window_pos)
@@ -626,17 +711,26 @@ void LineEdit::append_at_cursor(String p_text) {
if ( ( max_length <= 0 ) || (text.length()+p_text.length() <= max_length)) {
undo_text = text;
+
+ Ref<Font> font = get_font("font");
+ if (font != NULL) {
+ for (int i = 0; i < p_text.length(); i++)
+ cached_width += font->get_char_size(p_text[i]).width;
+ }
+ else {
+ cached_width = 0;
+ }
+
String pre = text.substr( 0, cursor_pos );
String post = text.substr( cursor_pos, text.length()-cursor_pos );
text=pre+p_text+post;
set_cursor_pos(cursor_pos+p_text.length());
-
}
-
}
void LineEdit::clear_internal() {
+ cached_width = 0;
cursor_pos=0;
window_pos=0;
undo_text="";
@@ -676,6 +770,20 @@ void LineEdit::selection_delete() {
if (selection.enabled) {
undo_text = text;
+
+ if (text.size() > 0)
+ {
+ Ref<Font> font = get_font("font");
+ if (font != NULL) {
+ for (int i = selection.begin; i < selection.end; i++)
+ cached_width -= font->get_char_size(text[i]).width;
+ }
+ }
+ else
+ {
+ cached_width = 0;
+ }
+
text.erase(selection.begin,selection.end-selection.begin);
cursor_pos-=CLAMP( cursor_pos-selection.begin, 0, selection.end-selection.begin);
@@ -782,9 +890,15 @@ void LineEdit::select(int p_from, int p_to) {
update();
}
+bool LineEdit::is_text_field() const {
+
+ return true;
+}
void LineEdit::_bind_methods() {
+ ObjectTypeDB::bind_method(_MD("set_align", "align"), &LineEdit::set_align);
+ ObjectTypeDB::bind_method(_MD("get_align"), &LineEdit::get_align);
ObjectTypeDB::bind_method(_MD("_input_event"),&LineEdit::_input_event);
ObjectTypeDB::bind_method(_MD("clear"),&LineEdit::clear);
@@ -805,15 +919,22 @@ void LineEdit::_bind_methods() {
ADD_SIGNAL( MethodInfo("text_changed", PropertyInfo( Variant::STRING, "text" )) );
ADD_SIGNAL( MethodInfo("text_entered", PropertyInfo( Variant::STRING, "text" )) );
+ BIND_CONSTANT(ALIGN_LEFT);
+ BIND_CONSTANT(ALIGN_CENTER);
+ BIND_CONSTANT(ALIGN_RIGHT);
+ BIND_CONSTANT(ALIGN_FILL);
+
ADD_PROPERTY( PropertyInfo( Variant::STRING, "text" ), _SCS("set_text"),_SCS("get_text") );
+ ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), _SCS("set_align"), _SCS("get_align"));
ADD_PROPERTY( PropertyInfo( Variant::INT, "max_length" ), _SCS("set_max_length"),_SCS("get_max_length") );
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "editable" ), _SCS("set_editable"),_SCS("is_editable") );
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "secret" ), _SCS("set_secret"),_SCS("is_secret") );
-
}
LineEdit::LineEdit() {
+ align = ALIGN_LEFT;
+ cached_width = 0;
cursor_pos=0;
window_pos=0;
max_length = 0;
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index c19043e826..f28136d66e 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -36,7 +36,18 @@
class LineEdit : public Control {
OBJ_TYPE( LineEdit, Control );
-
+
+public:
+ enum Align {
+
+ ALIGN_LEFT,
+ ALIGN_CENTER,
+ ALIGN_RIGHT,
+ ALIGN_FILL
+ };
+private:
+ Align align;
+
bool editable;
bool pass;
@@ -46,6 +57,8 @@ class LineEdit : public Control {
int cursor_pos;
int window_pos;
int max_length; // 0 for no maximum
+
+ int cached_width;
struct Selection {
@@ -83,7 +96,8 @@ class LineEdit : public Control {
protected:
static void _bind_methods();
public:
-
+ void set_align(Align p_align);
+ Align get_align() const;
virtual Variant get_drag_data(const Point2& p_point);
virtual bool can_drop_data(const Point2& p_point,const Variant& p_data) const;
@@ -112,9 +126,14 @@ public:
void select(int p_from=0, int p_to=-1);
virtual Size2 get_minimum_size() const;
+
+ virtual bool is_text_field() const;
LineEdit();
~LineEdit();
};
+
+VARIANT_ENUM_CAST(LineEdit::Align);
+
#endif
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 68fcb4bda8..be7a6b468a 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -54,6 +54,8 @@ void MenuButton::_unhandled_key_input(InputEvent p_event) {
int item = popup->find_item_by_accelerator(code);
+
+
if (item>=0 && ! popup->is_item_disabled(item))
popup->activate_item(item);
/*
@@ -124,7 +126,7 @@ void MenuButton::_set_items(const Array& p_items) {
void MenuButton::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("get_popup"),&MenuButton::get_popup);
+ ObjectTypeDB::bind_method(_MD("get_popup:PopupMenu"),&MenuButton::get_popup);
ObjectTypeDB::bind_method(_MD("_unhandled_key_input"),&MenuButton::_unhandled_key_input);
ObjectTypeDB::bind_method(_MD("_set_items"),&MenuButton::_set_items);
ObjectTypeDB::bind_method(_MD("_get_items"),&MenuButton::_get_items);
diff --git a/scene/gui/patch_9_frame.cpp b/scene/gui/patch_9_frame.cpp
new file mode 100644
index 0000000000..b6e261714c
--- /dev/null
+++ b/scene/gui/patch_9_frame.cpp
@@ -0,0 +1,132 @@
+#include "patch_9_frame.h"
+
+#include "servers/visual_server.h"
+
+void Patch9Frame::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_DRAW) {
+
+ if (texture.is_null())
+ return;
+
+
+ Size2 s=get_size();
+ RID ci = get_canvas_item();
+ VS::get_singleton()->canvas_item_add_style_box(ci,Rect2(Point2(),s),texture->get_rid(),Vector2(margin[MARGIN_LEFT],margin[MARGIN_TOP]),Vector2(margin[MARGIN_RIGHT],margin[MARGIN_BOTTOM]),draw_center,modulate);
+// draw_texture_rect(texture,Rect2(Point2(),s),false,modulate);
+
+/*
+ Vector<Point2> points;
+ points.resize(4);
+ points[0]=Point2(0,0);
+ points[1]=Point2(s.x,0);
+ points[2]=Point2(s.x,s.y);
+ points[3]=Point2(0,s.y);
+ Vector<Point2> uvs;
+ uvs.resize(4);
+ uvs[0]=Point2(0,0);
+ uvs[1]=Point2(1,0);
+ uvs[2]=Point2(1,1);
+ uvs[3]=Point2(0,1);
+
+ VisualServer::get_singleton()->canvas_item_add_primitive(ci,points,Vector<Color>(),uvs,texture->get_rid());
+*/
+ }
+}
+
+Size2 Patch9Frame::get_minimum_size() const {
+
+ return Size2(margin[MARGIN_LEFT]+margin[MARGIN_RIGHT],margin[MARGIN_TOP]+margin[MARGIN_BOTTOM]);
+}
+void Patch9Frame::_bind_methods() {
+
+
+ ObjectTypeDB::bind_method(_MD("set_texture","texture"), & Patch9Frame::set_texture );
+ ObjectTypeDB::bind_method(_MD("get_texture"), & Patch9Frame::get_texture );
+ ObjectTypeDB::bind_method(_MD("set_modulate","modulate"), & Patch9Frame::set_modulate );
+ ObjectTypeDB::bind_method(_MD("get_modulate"), & Patch9Frame::get_modulate );
+ ObjectTypeDB::bind_method(_MD("set_patch_margin","margin","value"), & Patch9Frame::set_patch_margin );
+ ObjectTypeDB::bind_method(_MD("get_patch_margin","margin"), & Patch9Frame::get_patch_margin );
+ ObjectTypeDB::bind_method(_MD("set_draw_center","draw_center"), & Patch9Frame::set_draw_center );
+ ObjectTypeDB::bind_method(_MD("get_draw_center"), & Patch9Frame::get_draw_center );
+
+ ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_texture"),_SCS("get_texture") );
+ ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate") );
+ ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "draw_center"), _SCS("set_draw_center"),_SCS("get_draw_center") );
+ ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/left",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_LEFT );
+ ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/top",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_TOP );
+ ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/right",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_RIGHT );
+ ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/bottom",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_BOTTOM );
+
+}
+
+
+void Patch9Frame::set_texture(const Ref<Texture>& p_tex) {
+
+ texture=p_tex;
+ update();
+ //if (texture.is_valid())
+ // texture->set_flags(texture->get_flags()&(~Texture::FLAG_REPEAT)); //remove repeat from texture, it looks bad in sprites
+ minimum_size_changed();
+}
+
+Ref<Texture> Patch9Frame::get_texture() const {
+
+ return texture;
+}
+
+void Patch9Frame::set_modulate(const Color& p_tex) {
+
+ modulate=p_tex;
+ update();
+}
+
+Color Patch9Frame::get_modulate() const{
+
+ return modulate;
+}
+
+
+void Patch9Frame::set_patch_margin(Margin p_margin,int p_size) {
+
+ ERR_FAIL_INDEX(p_margin,4);
+ margin[p_margin]=p_size;
+ update();
+ minimum_size_changed();
+}
+
+int Patch9Frame::get_patch_margin(Margin p_margin) const{
+
+ ERR_FAIL_INDEX_V(p_margin,4,0);
+ return margin[p_margin];
+}
+
+void Patch9Frame::set_draw_center(bool p_draw) {
+
+ draw_center=p_draw;
+ update();
+}
+
+bool Patch9Frame::get_draw_center() const{
+
+ return draw_center;
+}
+
+Patch9Frame::Patch9Frame() {
+
+
+ margin[MARGIN_LEFT]=0;
+ margin[MARGIN_RIGHT]=0;
+ margin[MARGIN_BOTTOM]=0;
+ margin[MARGIN_TOP]=0;
+ modulate=Color(1,1,1,1);
+ set_ignore_mouse(true);
+ draw_center=true;
+}
+
+
+Patch9Frame::~Patch9Frame()
+{
+}
+
+
diff --git a/scene/gui/patch_9_frame.h b/scene/gui/patch_9_frame.h
new file mode 100644
index 0000000000..562a5b1d77
--- /dev/null
+++ b/scene/gui/patch_9_frame.h
@@ -0,0 +1,40 @@
+#ifndef PATCH_9_FRAME_H
+#define PATCH_9_FRAME_H
+
+#include "scene/gui/control.h"
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class Patch9Frame : public Control {
+
+ OBJ_TYPE(Patch9Frame,Control);
+
+ bool draw_center;
+ int margin[4];
+ Color modulate;
+ Ref<Texture> texture;
+protected:
+
+ void _notification(int p_what);
+ virtual Size2 get_minimum_size() const;
+ static void _bind_methods();
+
+public:
+
+ void set_texture(const Ref<Texture>& p_tex);
+ Ref<Texture> get_texture() const;
+
+ void set_modulate(const Color& p_tex);
+ Color get_modulate() const;
+
+ void set_patch_margin(Margin p_margin,int p_size);
+ int get_patch_margin(Margin p_margin) const;
+
+ void set_draw_center(bool p_enable);
+ bool get_draw_center() const;
+
+ Patch9Frame();
+ ~Patch9Frame();
+
+};
+#endif // PATCH_9_FRAME_H
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index e706053592..99663fb2e2 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -323,8 +323,13 @@ void PopupMenu::_input_event(const InputEvent &p_event) {
invalidated_click=false;
break;
}
- if (over<0 || items[over].separator || items[over].disabled)
+ if (over<0) {
+ hide();
break; //non-activable
+ }
+
+ if (items[over].separator || items[over].disabled)
+ break;
if (items[over].submenu!="") {
@@ -360,8 +365,11 @@ void PopupMenu::_input_event(const InputEvent &p_event) {
int over=_get_mouse_over(Point2(m.x,m.y));
int id = (over<0 || items[over].separator || items[over].disabled)?-1:items[over].ID;
- if (id<0)
+ if (id<0) {
+ mouse_over=-1;
+ update();
break;
+ }
if (items[over].submenu!="" && submenu_over!=over) {
submenu_over=over;
@@ -738,10 +746,18 @@ int PopupMenu::find_item_by_accelerator(uint32_t p_accel) const {
void PopupMenu::activate_item(int p_item) {
-
ERR_FAIL_INDEX(p_item,items.size());
ERR_FAIL_COND(items[p_item].separator);
emit_signal("item_pressed",items[p_item].ID);
+
+ //hide all parent PopupMenue's
+ Node *next = get_parent();
+ PopupMenu *pop = next->cast_to<PopupMenu>();
+ while (pop) {
+ pop->hide();
+ next = next->get_parent();
+ pop = next->cast_to<PopupMenu>();
+ }
hide();
}
@@ -764,6 +780,7 @@ void PopupMenu::add_separator() {
void PopupMenu::clear() {
items.clear();
+ mouse_over=-1;
update();
idcount=0;
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index ad708d16f0..7103ee651f 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -243,7 +243,7 @@ void Range::_bind_methods() {
ADD_PROPERTY( PropertyInfo( Variant::REAL, "range/step" ), _SCS("set_step"), _SCS("get_step") );
ADD_PROPERTY( PropertyInfo( Variant::REAL, "range/page" ), _SCS("set_page"), _SCS("get_page") );
ADD_PROPERTY( PropertyInfo( Variant::REAL, "range/value" ), _SCS("set_val"), _SCS("get_val") );
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "range/exp_edit" ), _SCS("set_exp_unit_value"), _SCS("is_unit_value_exp") );
+ ADD_PROPERTY( PropertyInfo( Variant::BOOL, "range/exp_edit" ), _SCS("set_exp_unit_value"), _SCS("is_unit_value_exp") );
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "rounded_values" ), _SCS("set_rounded_values"), _SCS("get_rounded_values") );
}
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 7a607786ee..b98fec1bde 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -719,7 +719,7 @@ void RichTextLabel::_input_event(InputEvent p_event) {
case InputEvent::KEY: {
const InputEventKey &k=p_event.key;
- if (k.pressed) {
+ if (k.pressed && !k.mod.alt && !k.mod.shift && !k.mod.command && !k.mod.meta) {
bool handled=true;
switch(k.scancode) {
case KEY_PAGEUP: {
@@ -765,6 +765,7 @@ void RichTextLabel::_input_event(InputEvent p_event) {
default: handled=false;
}
+
if (handled)
accept_event();
}
@@ -1503,10 +1504,10 @@ Error RichTextLabel::append_bbcode(const String& p_bbcode) {
void RichTextLabel::scroll_to_line(int p_line) {
+ p_line -= 1;
ERR_FAIL_INDEX(p_line,lines.size());
_validate_line_caches();
- vscroll->set_val(lines[p_line].height_accum_cache);
-
+ vscroll->set_val(lines[p_line].height_accum_cache-lines[p_line].height_cache);
}
@@ -1569,27 +1570,23 @@ bool RichTextLabel::search(const String& p_string,bool p_from_selection) {
it=_get_next_item(it);
}
- if (!it)
- line=lines.size()-1;
}
- scroll_to_line(line-2);
+ if (line > 1) {
+ line-=1;
+ }
+
+ scroll_to_line(line);
return true;
}
- } else if (it->type==ITEM_NEWLINE) {
-
- line=static_cast<ItemNewline*>(it)->line;
}
-
it=_get_next_item(it);
charidx=0;
}
-
-
return false;
}
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 8f753f51bc..e5b5d531a0 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -195,11 +195,19 @@ void ScrollContainer::_notification(int p_what) {
Rect2 r = Rect2(-scroll,minsize);
if (!scroll_h) {
r.pos.x=0;
- r.size.width=size.width;
+ 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) {
r.pos.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);
}
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 41e775bbff..a48136f541 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -27,7 +27,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "spin_box.h"
-
+#include "os/input.h"
Size2 SpinBox::get_minimum_size() const {
@@ -62,6 +62,13 @@ LineEdit *SpinBox::get_line_edit() {
}
+void SpinBox::_line_edit_input(const InputEvent& p_event) {
+
+
+
+}
+
+
void SpinBox::_input_event(const InputEvent& p_event) {
if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.pressed) {
@@ -94,6 +101,48 @@ void SpinBox::_input_event(const InputEvent& p_event) {
} break;
}
}
+
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.pressed && p_event.mouse_button.button_index==1) {
+
+ //set_default_cursor_shape(CURSOR_VSIZE);
+ Vector2 cpos = Vector2(p_event.mouse_button.x,p_event.mouse_button.y);
+ drag.mouse_pos=cpos;
+ }
+
+ if (p_event.type==InputEvent::MOUSE_BUTTON && !p_event.mouse_button.pressed && p_event.mouse_button.button_index==1) {
+
+ //set_default_cursor_shape(CURSOR_ARROW);
+ if (drag.enabled) {
+ drag.enabled=false;
+ Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+ warp_mouse(drag.capture_pos);
+ }
+ }
+
+ if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_button.button_mask&1) {
+
+ Vector2 cpos = Vector2(p_event.mouse_motion.x,p_event.mouse_motion.y);
+ if (drag.enabled) {
+
+ float diff_y = drag.mouse_pos.y - cpos.y;
+ diff_y=Math::pow(ABS(diff_y),1.8)*SGN(diff_y);
+ diff_y*=0.1;
+
+ drag.mouse_pos=cpos;
+ drag.base_val=CLAMP(drag.base_val + get_step() * diff_y, get_min(), get_max());
+
+ set_val( drag.base_val);
+
+ } else if (drag.mouse_pos.distance_to(cpos)>2) {
+
+ Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
+ drag.enabled=true;
+ drag.base_val=get_val();
+ drag.mouse_pos=cpos;
+ drag.capture_pos=cpos;
+
+ }
+ }
}
@@ -177,6 +226,7 @@ void SpinBox::_bind_methods() {
ObjectTypeDB::bind_method(_MD("is_editable"),&SpinBox::is_editable);
ObjectTypeDB::bind_method(_MD("_line_edit_focus_exit"),&SpinBox::_line_edit_focus_exit);
ObjectTypeDB::bind_method(_MD("get_line_edit"),&SpinBox::get_line_edit);
+ ObjectTypeDB::bind_method(_MD("_line_edit_input"),&SpinBox::_line_edit_input);
ADD_PROPERTY(PropertyInfo(Variant::BOOL,"editable"),_SCS("set_editable"),_SCS("is_editable"));
@@ -196,4 +246,6 @@ SpinBox::SpinBox() {
//connect("value_changed",this,"_value_changed");
line_edit->connect("text_entered",this,"_text_entered",Vector<Variant>(),CONNECT_DEFERRED);
line_edit->connect("focus_exit",this,"_line_edit_focus_exit",Vector<Variant>(),CONNECT_DEFERRED);
+ line_edit->connect("input_event",this,"_line_edit_input");
+ drag.enabled=false;
}
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index 6ebe14631e..4c8cb8432a 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -44,6 +44,18 @@ class SpinBox : public Range {
String prefix;
String suffix;
+ void _line_edit_input(const InputEvent& p_event);
+
+
+ struct Drag {
+ float base_val;
+ bool enabled;
+ Vector2 from;
+ Vector2 mouse_pos;
+ Vector2 capture_pos;
+ } drag;
+
+
void _line_edit_focus_exit();
protected:
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 3ed182c017..6fa701340d 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -229,6 +229,18 @@ void TabContainer::_notification(int p_what) {
int w=0;
int idx=0;
+ Vector<int> offsets;
+ Vector<Control*> controls;
+ int from=0;
+ int limit=get_size().width;
+ if (popup) {
+ top_size.width-=menu->get_width();
+ limit-=menu->get_width();
+ }
+
+ bool notdone=false;
+ last_tab_cache=-1;
+
for(int i=0;i<get_child_count();i++) {
Control *c = get_child(i)->cast_to<Control>();
@@ -236,7 +248,20 @@ void TabContainer::_notification(int p_what) {
continue;
if (c->is_set_as_toplevel())
continue;
+ if (idx<tab_display_ofs) {
+ idx++;
+ from=idx;
+ continue;
+ }
+ if (w>=get_size().width) {
+ buttons_visible_cache=true;
+ notdone=true;
+ break;
+ }
+
+ offsets.push_back(w);
+ controls.push_back(c);
String s = c->has_meta("_tab_name")?String(XL_MESSAGE(String(c->get_meta("_tab_name")))):String(c->get_name());
w+=font->get_string_size(s).width;
@@ -257,55 +282,46 @@ void TabContainer::_notification(int p_what) {
w+=tab_bg->get_minimum_size().width;
}
- idx++;
- }
+ if (idx<tab_display_ofs) {
+ }
+ last_tab_cache=idx;
- int ofs;
- int limit=get_size().width;
- if (popup) {
- top_size.width-=menu->get_width();
- limit-=menu->get_width();
+ idx++;
}
- if (w<=limit) {
- switch(align) {
+ int ofs;
- case ALIGN_LEFT: ofs = side_margin; break;
- case ALIGN_CENTER: ofs = (int(limit) - w)/2; break;
- case ALIGN_RIGHT: ofs = int(limit) - w - side_margin; break;
- };
+ switch(align) {
- tab_display_ofs=0;
- buttons_visible_cache=false;
- } else {
+ case ALIGN_LEFT: ofs = side_margin; break;
+ case ALIGN_CENTER: ofs = (int(limit) - w)/2; break;
+ case ALIGN_RIGHT: ofs = int(limit) - w - side_margin; break;
+ };
- ofs=0;
- limit-=incr->get_width()+decr->get_width();
- buttons_visible_cache=true;
- }
+ tab_display_ofs=0;
tabs_ofs_cache=ofs;
- last_tab_cache=-1;
idx=0;
- bool notdone=false;
- 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;
+ for(int i=0;i<controls.size();i++) {
- if (idx<tab_display_ofs) {
- idx++;
- continue;
+ idx=i+from;
+ if (current>=from && current<from+controls.size()-1) {
+ //current is visible! draw it last.
+ if (i==controls.size()-1) {
+ idx=current;
+ } else if (idx>=current) {
+ idx+=1;
+ }
}
+ Control *c = controls[idx-from];
+
String s = c->has_meta("_tab_name")?String(c->get_meta("_tab_name")):String(c->get_name());
int w=font->get_string_size(s).width;
Ref<Texture> icon;
@@ -336,14 +352,12 @@ void TabContainer::_notification(int p_what) {
col=color_bg;
}
+ int lofs = ofs + offsets[idx-from];
Size2i sb_ms = sb->get_minimum_size();
- Rect2 sb_rect = Rect2( ofs, 0, w+sb_ms.width, top_margin);
+ Rect2 sb_rect = Rect2( lofs, 0, w+sb_ms.width, top_margin);
+
- if (sb_ms.width+w+ofs > limit) {
- notdone=true;
- break;
- }
sb->draw(ci, sb_rect );
Point2i lpos = sb_rect.pos;
@@ -357,8 +371,7 @@ void TabContainer::_notification(int p_what) {
}
font->draw(ci, Point2i( lpos.x, sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-font->get_height())/2+font->get_ascent() ), s, col );
- ofs+=sb_ms.x+w;
- last_tab_cache=idx;
+ //ofs+=sb_ms.x+w;
/*
int sb_mw = sb->get_minimum_size().width;
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index a849d3ae72..47a55e0716 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -58,12 +58,20 @@ Size2 Tabs::get_minimum_size() const {
if (tabs[i].right_button.is_valid()) {
Ref<Texture> rb=tabs[i].right_button;
- Size2 bms = rb->get_size()+get_stylebox("button")->get_minimum_size();
+ Size2 bms = rb->get_size();//+get_stylebox("button")->get_minimum_size();
bms.width+=get_constant("hseparation");
ms.width+=bms.width;
ms.height=MAX(bms.height+tab_bg->get_minimum_size().height,ms.height);
}
+
+ if (tabs[i].close_button.is_valid()) {
+ Ref<Texture> cb=tabs[i].close_button;
+ Size2 bms = cb->get_size();//+get_stylebox("button")->get_minimum_size();
+ bms.width+=get_constant("hseparation");
+ ms.width+=bms.width;
+ ms.height=MAX(bms.height+tab_bg->get_minimum_size().height,ms.height);
+ }
}
return ms;
@@ -77,22 +85,50 @@ void Tabs::_input_event(const InputEvent& p_event) {
Point2 pos( p_event.mouse_motion.x, p_event.mouse_motion.y );
- int hover=-1;
+ int hover_buttons=-1;
+ hover=-1;
for(int i=0;i<tabs.size();i++) {
+ // test hovering tab to display close button if policy says so
+ if (cb_displaypolicy == SHOW_HOVER) {
+ int ofs=tabs[i].ofs_cache;
+ int size = tabs[i].ofs_cache;
+ if (pos.x >=tabs[i].ofs_cache && pos.x<tabs[i].ofs_cache+tabs[i].size_cache) {
+ hover=i;
+ }
+ }
+
+
+ // test hovering right button and close button
if (tabs[i].rb_rect.has_point(pos)) {
- hover=i;
+ rb_hover=i;
+ cb_hover=-1;
+ hover_buttons = i;
+ break;
+ }
+ else if (tabs[i].cb_rect.has_point(pos)) {
+ cb_hover=i;
+ rb_hover=-1;
+ hover_buttons = i;
break;
}
+
+
+
}
- if (hover!=rb_hover) {
- rb_hover=hover;
- update();
+ if (hover_buttons == -1) { // no hover
+ rb_hover= hover_buttons;
+ cb_hover= hover_buttons;
}
+ update();
+
return;
}
+
+
+
if (rb_pressing && p_event.type==InputEvent::MOUSE_BUTTON &&
!p_event.mouse_button.pressed &&
p_event.mouse_button.button_index==BUTTON_LEFT) {
@@ -106,6 +142,20 @@ void Tabs::_input_event(const InputEvent& p_event) {
update();
}
+ if (cb_pressing && p_event.type==InputEvent::MOUSE_BUTTON &&
+ !p_event.mouse_button.pressed &&
+ p_event.mouse_button.button_index==BUTTON_LEFT) {
+
+ if (cb_hover!=-1) {
+ //pressed
+ emit_signal("tab_close",cb_hover);
+ }
+
+ cb_pressing=false;
+ update();
+ }
+
+
if (p_event.type==InputEvent::MOUSE_BUTTON &&
p_event.mouse_button.pressed &&
p_event.mouse_button.button_index==BUTTON_LEFT) {
@@ -122,6 +172,12 @@ void Tabs::_input_event(const InputEvent& p_event) {
return;
}
+ if (tabs[i].cb_rect.has_point(pos)) {
+ cb_pressing=true;
+ update();
+ return;
+ }
+
int ofs=tabs[i].ofs_cache;
int size = tabs[i].ofs_cache;
if (pos.x >=tabs[i].ofs_cache && pos.x<tabs[i].ofs_cache+tabs[i].size_cache) {
@@ -148,6 +204,8 @@ void Tabs::_notification(int p_what) {
case NOTIFICATION_MOUSE_EXIT: {
rb_hover=-1;
+ cb_hover=-1;
+ hover=-1;
update();
} break;
case NOTIFICATION_DRAW: {
@@ -186,7 +244,7 @@ void Tabs::_notification(int p_what) {
String s = tabs[i].text;
int lsize=0;
- int slen=font->get_string_size(s).width;;
+ int slen=font->get_string_size(s).width;
lsize+=slen;
Ref<Texture> icon;
@@ -205,12 +263,62 @@ void Tabs::_notification(int p_what) {
Ref<Texture> rb=tabs[i].right_button;
lsize+=get_constant("hseparation");
- lsize+=style->get_margin(MARGIN_LEFT);
+ //lsize+=style->get_margin(MARGIN_LEFT);
lsize+=rb->get_width();
- lsize+=style->get_margin(MARGIN_RIGHT);
+ //lsize+=style->get_margin(MARGIN_RIGHT);
}
+ // Close button
+ switch (cb_displaypolicy) {
+ case SHOW_ALWAYS: {
+ if (tabs[i].close_button.is_valid()) {
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> rb=tabs[i].close_button;
+
+ lsize+=get_constant("hseparation");
+ //lsize+=style->get_margin(MARGIN_LEFT);
+ lsize+=rb->get_width();
+ //lsize+=style->get_margin(MARGIN_RIGHT);
+
+ }
+ } break;
+ case SHOW_ACTIVE_ONLY: {
+ if (i==current) {
+ if (tabs[i].close_button.is_valid()) {
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> rb=tabs[i].close_button;
+
+ lsize+=get_constant("hseparation");
+ //lsize+=style->get_margin(MARGIN_LEFT);
+ lsize+=rb->get_width();
+ //lsize+=style->get_margin(MARGIN_RIGHT);
+
+ }
+ }
+ } break;
+ case SHOW_HOVER: {
+ if (i==current || i==hover) {
+ if (tabs[i].close_button.is_valid()) {
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> rb=tabs[i].close_button;
+
+ lsize+=get_constant("hseparation");
+ //lsize+=style->get_margin(MARGIN_LEFT);
+ lsize+=rb->get_width();
+ //lsize+=style->get_margin(MARGIN_RIGHT);
+
+ }
+ }
+ } break;
+ case SHOW_NEVER: // by default, never show close button
+ default: {
+ // do nothing
+ } break;
+
+ }
+
+
Ref<StyleBox> sb;
int va;
Color col;
@@ -273,6 +381,103 @@ void Tabs::_notification(int p_what) {
}
+
+
+
+ // Close button
+ switch (cb_displaypolicy) {
+ case SHOW_ALWAYS: {
+ if (tabs[i].close_button.is_valid()) {
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> cb=tabs[i].close_button;
+
+ w+=get_constant("hseparation");
+
+ Rect2 cb_rect;
+ cb_rect.size=style->get_minimum_size()+cb->get_size();
+ cb_rect.pos.x=w;
+ cb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(cb_rect.size.y))/2;
+
+ if (cb_hover==i) {
+ if (cb_pressing)
+ get_stylebox("button_pressed")->draw(ci,cb_rect);
+ else
+ style->draw(ci,cb_rect);
+ }
+
+ //w+=style->get_margin(MARGIN_LEFT);
+
+ cb->draw(ci,Point2i( w,cb_rect.pos.y+style->get_margin(MARGIN_TOP) ));
+ w+=cb->get_width();
+ //w+=style->get_margin(MARGIN_RIGHT);
+ tabs[i].cb_rect=cb_rect;
+ }
+ } break;
+ case SHOW_ACTIVE_ONLY: {
+ if (current==i) {
+ if (tabs[i].close_button.is_valid()) {
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> cb=tabs[i].close_button;
+
+ w+=get_constant("hseparation");
+
+ Rect2 cb_rect;
+ cb_rect.size=style->get_minimum_size()+cb->get_size();
+ cb_rect.pos.x=w;
+ cb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(cb_rect.size.y))/2;
+
+ if (cb_hover==i) {
+ if (cb_pressing)
+ get_stylebox("button_pressed")->draw(ci,cb_rect);
+ else
+ style->draw(ci,cb_rect);
+ }
+
+ //w+=style->get_margin(MARGIN_LEFT);
+
+ cb->draw(ci,Point2i( w,cb_rect.pos.y+style->get_margin(MARGIN_TOP) ));
+ w+=cb->get_width();
+ //w+=style->get_margin(MARGIN_RIGHT);
+ tabs[i].cb_rect=cb_rect;
+ }
+ }
+ } break;
+ case SHOW_HOVER: {
+ if (current==i || hover==i) {
+ if (tabs[i].close_button.is_valid()) {
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> cb=tabs[i].close_button;
+
+ w+=get_constant("hseparation");
+
+ Rect2 cb_rect;
+ cb_rect.size=style->get_minimum_size()+cb->get_size();
+ cb_rect.pos.x=w;
+ cb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(cb_rect.size.y))/2;
+
+ if (cb_hover==i) {
+ if (cb_pressing)
+ get_stylebox("button_pressed")->draw(ci,cb_rect);
+ else
+ style->draw(ci,cb_rect);
+ }
+
+ //w+=style->get_margin(MARGIN_LEFT);
+
+ cb->draw(ci,Point2i( w,cb_rect.pos.y+style->get_margin(MARGIN_TOP) ));
+ w+=cb->get_width();
+ //w+=style->get_margin(MARGIN_RIGHT);
+ tabs[i].cb_rect=cb_rect;
+ }
+ }
+ } break;
+ case SHOW_NEVER:
+ default: {
+ // show nothing
+ } break;
+
+ }
+
w+=sb->get_margin(MARGIN_RIGHT);
tabs[i].size_cache=w-tabs[i].ofs_cache;
@@ -358,11 +563,29 @@ Ref<Texture> Tabs::get_tab_right_button(int p_tab) const{
}
+void Tabs::set_tab_close_button(int p_tab, const Ref<Texture>& p_close_button) {
+ ERR_FAIL_INDEX(p_tab, tabs.size());
+ tabs[p_tab].close_button=p_close_button;
+ update();
+ minimum_size_changed();
+}
+
+
+Ref<Texture> Tabs::get_tab_close_button(int p_tab) const{
+
+ ERR_FAIL_INDEX_V(p_tab,tabs.size(),Ref<Texture>());
+ return tabs[p_tab].close_button;
+
+}
+
void Tabs::add_tab(const String& p_str,const Ref<Texture>& p_icon) {
Tab t;
t.text=p_str;
t.icon=p_icon;
+
+ t.close_button = get_icon("Close","EditorIcons");
+
tabs.push_back(t);
update();
@@ -394,6 +617,11 @@ void Tabs::remove_tab(int p_idx) {
}
+void Tabs::set_tab_close_display_policy(CloseButtonDisplayPolicy p_cb_displaypolicy) {
+ cb_displaypolicy = p_cb_displaypolicy;
+}
+
+
void Tabs::set_tab_align(TabAlign p_align) {
tab_align=p_align;
@@ -423,14 +651,22 @@ void Tabs::_bind_methods() {
ADD_SIGNAL(MethodInfo("tab_changed",PropertyInfo(Variant::INT,"tab")));
ADD_SIGNAL(MethodInfo("right_button_pressed",PropertyInfo(Variant::INT,"tab")));
+ ADD_SIGNAL(MethodInfo("tab_close",PropertyInfo(Variant::INT,"tab")));
+
ADD_PROPERTY( PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE,"-1,4096,1",PROPERTY_USAGE_EDITOR), _SCS("set_current_tab"), _SCS("get_current_tab") );
BIND_CONSTANT( ALIGN_LEFT );
BIND_CONSTANT( ALIGN_CENTER );
BIND_CONSTANT( ALIGN_RIGHT );
+
+ BIND_CONSTANT( SHOW_ACTIVE_ONLY );
+ BIND_CONSTANT( SHOW_ALWAYS );
+ BIND_CONSTANT( SHOW_HOVER );
+ BIND_CONSTANT( SHOW_NEVER );
}
+
Tabs::Tabs() {
current=0;
@@ -438,4 +674,7 @@ Tabs::Tabs() {
rb_hover=-1;
rb_pressing=false;
+ cb_hover=-1;
+ cb_pressing=false;
+ cb_displaypolicy = SHOW_NEVER; // Default : no close button
}
diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h
index 5cb0d9e916..1a8352bc93 100644
--- a/scene/gui/tabs.h
+++ b/scene/gui/tabs.h
@@ -42,6 +42,14 @@ public:
ALIGN_CENTER,
ALIGN_RIGHT
};
+
+ enum CloseButtonDisplayPolicy {
+
+ SHOW_ALWAYS,
+ SHOW_ACTIVE_ONLY,
+ SHOW_HOVER,
+ SHOW_NEVER
+ };
private:
@@ -53,6 +61,8 @@ private:
int size_cache;
Ref<Texture> right_button;
Rect2 rb_rect;
+ Ref<Texture> close_button;
+ Rect2 cb_rect;
};
Vector<Tab> tabs;
@@ -63,6 +73,12 @@ private:
int rb_hover;
bool rb_pressing;
+ int cb_hover;
+ bool cb_pressing;
+ CloseButtonDisplayPolicy cb_displaypolicy;
+
+ int hover; // hovered tab
+
protected:
void _input_event(const InputEvent& p_event);
@@ -82,6 +98,10 @@ public:
void set_tab_right_button(int p_tab,const Ref<Texture>& p_right_button);
Ref<Texture> get_tab_right_button(int p_tab) const;
+ void set_tab_close_button(int p_tab, const Ref<Texture>& p_close_button);
+ Ref<Texture> get_tab_close_button(int p_tab) const;
+ void set_tab_close_display_policy(CloseButtonDisplayPolicy p_cb_displaypolicy);
+
void set_tab_align(TabAlign p_align);
TabAlign get_tab_align() const;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index f1172461d7..5415484009 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -94,9 +94,9 @@ void TextEdit::Text::set_tab_size(int p_tab_size) {
void TextEdit::Text::_update_line_cache(int p_line) const {
- int w =0;
- int tab_w=font->get_char_size(' ').width;
-
+ int w = 0;
+ int tab_w=font->get_char_size(' ').width*tab_size;
+
int len = text[p_line].data.length();
const CharType *str = text[p_line].data.c_str();
@@ -292,7 +292,10 @@ void TextEdit::_update_scrollbars() {
int vscroll_pixels = v_scroll->get_combined_minimum_size().width;
int visible_width = size.width - cache.style_normal->get_minimum_size().width;
- int total_width = text.get_max_width();
+ int total_width = text.get_max_width() + vmin.x;
+
+ if (line_numbers)
+ total_width += cache.line_number_w;
bool use_hscroll=true;
bool use_vscroll=true;
@@ -322,7 +325,6 @@ void TextEdit::_update_scrollbars() {
v_scroll->show();
v_scroll->set_max(total_rows);
v_scroll->set_page(visible_rows);
-
v_scroll->set_val(cursor.line_ofs);
} else {
@@ -336,6 +338,7 @@ void TextEdit::_update_scrollbars() {
h_scroll->set_max(total_width);
h_scroll->set_page(visible_width);
h_scroll->set_val(cursor.x_ofs);
+
} else {
h_scroll->hide();
@@ -706,7 +709,7 @@ void TextEdit::_notification(int p_what) {
if (in_region==-1 && !in_keyword && is_char && !prev_is_char) {
int to=j;
- while(_is_text_char(str[to]) && to<str.length())
+ while(to<str.length() && _is_text_char(str[to]))
to++;
uint32_t hash = String::hash(&str[j],to-j);
@@ -1646,8 +1649,60 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
case KEY_BACKSPACE: {
if (readonly)
break;
- backspace_at_cursor();
-
+
+#ifdef APPLE_STYLE_KEYS
+ if (k.mod.alt) {
+#else
+ if (k.mod.alt) {
+ scancode_handled=false;
+ break;
+ } else if (k.mod.command) {
+#endif
+ int line=cursor.line;
+ int column=cursor.column;
+
+ bool prev_char=false;
+ bool only_whitespace=true;
+
+ while (only_whitespace && line > 0) {
+
+ while (column>0) {
+ CharType c=text[line][column-1];
+
+ if (c != '\t' && c != ' ') {
+ only_whitespace=false;
+ break;
+ }
+
+ column--;
+ }
+
+ if (only_whitespace) {
+ line--;
+ column=text[line].length();
+ }
+ }
+
+ while (column>0) {
+ bool ischar=_is_text_char(text[line][column-1]);
+
+ if (prev_char && !ischar)
+ break;
+
+ prev_char=ischar;
+ column--;
+
+ }
+
+ _remove_text(line, column, cursor.line, cursor.column);
+
+ cursor_set_line(line);
+ cursor_set_column(column);
+
+ } else {
+ backspace_at_cursor();
+ }
+
} break;
case KEY_LEFT: {
@@ -1788,10 +1843,63 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
if (cursor.line==text.size()-1 && cursor.column==curline_len)
break; //nothing to do
- int next_line = cursor.column<curline_len?cursor.line:cursor.line+1;
- int next_column = cursor.column<curline_len?(cursor.column+1):0;
+ int next_line=cursor.column<curline_len?cursor.line:cursor.line+1;
+ int next_column;
+
+#ifdef APPLE_STYLE_KEYS
+ if (k.mod.alt) {
+#else
+ if (k.mod.alt) {
+ scancode_handled=false;
+ break;
+ } else if (k.mod.command) {
+#endif
+ int last_line=text.size()-1;
+
+ int line=cursor.line;
+ int column=cursor.column;
+
+ bool prev_char=false;
+ bool only_whitespace=true;
+
+ while (only_whitespace && line < last_line) {
+
+ while (column<text[line].length()) {
+ CharType c=text[line][column];
+
+ if (c != '\t' && c != ' ') {
+ only_whitespace=false;
+ break;
+ }
+
+ column++;
+ }
+
+ if (only_whitespace) {
+ line++;
+ column=0;
+ }
+ }
+
+ while (column<text[line].length()) {
+
+ bool ischar=_is_text_char(text[line][column]);
+
+ if (prev_char && !ischar)
+ break;
+ prev_char=ischar;
+ column++;
+ }
+
+ next_line=line;
+ next_column=column;
+ } else {
+ next_column=cursor.column<curline_len?(cursor.column+1):0;
+ }
+
_remove_text(cursor.line,cursor.column,next_line,next_column);
update();
+
} break;
#ifdef APPLE_STYLE_KEYS
case KEY_HOME: {
@@ -3566,7 +3674,10 @@ void TextEdit::set_show_line_numbers(bool p_show) {
update();
}
+bool TextEdit::is_text_field() const {
+ return true;
+}
void TextEdit::_bind_methods() {
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 585fbee9bf..059e15dcff 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -393,6 +393,7 @@ public:
String get_text_for_completion();
+ virtual bool is_text_field() const;
TextEdit();
~TextEdit();
};
diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp
index f61d63e4c3..c8930add6e 100644
--- a/scene/gui/texture_progress.cpp
+++ b/scene/gui/texture_progress.cpp
@@ -80,9 +80,50 @@ Ref<Texture> TextureProgress::get_progress_texture() const{
}
+Point2 TextureProgress::unit_val_to_uv(float val) {
+ if (progress.is_null())
+ return Point2();
+
+ if (val<0)
+ val+=1;
+ if (val>1)
+ val-=1;
+
+ Point2 p=get_relative_center();
+
+ if (val<0.125)
+ return Point2(p.x+(1-p.x)*val*8,0);
+ if (val<0.25)
+ return Point2(1,p.y*(val-0.125)*8);
+ if (val<0.375)
+ return Point2(1,p.y+(1-p.y)*(val-0.25)*8);
+ if (val<0.5)
+ return Point2(1-(1-p.x)*(val-0.375)*8,1);
+ if (val<0.625)
+ return Point2(p.x*(1-(val-0.5)*8),1);
+ if (val<0.75)
+ return Point2(0,1-((1-p.y)*(val-0.625)*8));
+ if (val<0.875)
+ return Point2(0,p.y-p.y*(val-0.75)*8);
+ else
+ return Point2(p.x*(val-0.875)*8,0);
+}
-void TextureProgress::_notification(int p_what){
+Point2 TextureProgress::get_relative_center()
+{
+ if (progress.is_null())
+ return Point2();
+ Point2 p = progress->get_size()/2;
+ p+=rad_center_off;
+ p.x/=progress->get_width();
+ p.y/=progress->get_height();
+ p.x=CLAMP(p.x,0,1);
+ p.y=CLAMP(p.y,0,1);
+ return p;
+}
+void TextureProgress::_notification(int p_what){
+ const float corners[12]={-0.125,-0.375,-0.625,-0.875,0.125,0.375,0.625,0.875,1.125,1.375,1.625,1.875};
switch(p_what) {
case NOTIFICATION_DRAW: {
@@ -92,7 +133,69 @@ void TextureProgress::_notification(int p_what){
draw_texture(under,Point2());
if (progress.is_valid()) {
Size2 s = progress->get_size();
- draw_texture_rect_region(progress,Rect2(Point2(),Size2(s.x*get_unit_value(),s.y)),Rect2(Point2(),Size2(s.x*get_unit_value(),s.y)));
+ switch (mode) {
+ case FILL_LEFT_TO_RIGHT: {
+ Rect2 region=Rect2(Point2(),Size2(s.x*get_unit_value(),s.y));
+ draw_texture_rect_region(progress,region,region);
+ } break;
+ case FILL_RIGHT_TO_LEFT: {
+ Rect2 region=Rect2(Point2(s.x-s.x*get_unit_value(),0),Size2(s.x*get_unit_value(),s.y));
+ draw_texture_rect_region(progress,region,region);
+ } break;
+ case FILL_TOP_TO_BOTTOM: {
+ Rect2 region=Rect2(Point2(),Size2(s.x,s.y*get_unit_value()));
+ draw_texture_rect_region(progress,region,region);
+ } break;
+ case FILL_BOTTOM_TO_TOP: {
+ Rect2 region=Rect2(Point2(0,s.y-s.y*get_unit_value()),Size2(s.x,s.y*get_unit_value()));
+ draw_texture_rect_region(progress,region,region);
+ } break;
+ case FILL_CLOCKWISE:
+ case FILL_COUNTER_CLOCKWISE: {
+ float val=get_unit_value()*rad_max_degrees/360;
+ if (val==1) {
+ Rect2 region=Rect2(Point2(),s);
+ draw_texture_rect_region(progress,region,region);
+ } else if (val!=0) {
+ Array pts;
+ float direction=mode==FILL_CLOCKWISE?1:-1;
+ float start=rad_init_angle/360;
+ float end=start+direction*val;
+ pts.append(start);
+ pts.append(end);
+ float from=MIN(start,end);
+ float to=MAX(start,end);
+ for (int i=0;i<12;i++)
+ if (corners[i]>from&&corners[i]<to)
+ pts.append(corners[i]);
+ pts.sort();
+ Vector<Point2> uvs;
+ Vector<Point2> points;
+ uvs.push_back(get_relative_center());
+ points.push_back(Point2(s.x*get_relative_center().x,s.y*get_relative_center().y));
+ for (int i=0;i<pts.size();i++) {
+ Point2 uv=unit_val_to_uv(pts[i]);
+ if (uvs.find(uv)>=0)
+ continue;
+ uvs.push_back(uv);
+ points.push_back(Point2(uv.x*s.x,uv.y*s.y));
+ }
+ draw_polygon(points,Vector<Color>(),uvs,progress);
+ }
+ if (get_tree()->is_editor_hint()) {
+ Point2 p=progress->get_size();
+ p.x*=get_relative_center().x;
+ p.y*=get_relative_center().y;
+ p=p.floor();
+ draw_line(p-Point2(8,0),p+Point2(8,0),Color(0.9,0.5,0.5),2);
+ draw_line(p-Point2(0,8),p+Point2(0,8),Color(0.9,0.5,0.5),2);
+ }
+ } break;
+ default:
+ draw_texture_rect_region(progress,Rect2(Point2(),Size2(s.x*get_unit_value(),s.y)),Rect2(Point2(),Size2(s.x*get_unit_value(),s.y)));
+ }
+
+
}
if (over.is_valid())
draw_texture(over,Point2());
@@ -101,6 +204,55 @@ void TextureProgress::_notification(int p_what){
}
}
+void TextureProgress::set_fill_mode(int p_fill)
+{
+ ERR_FAIL_INDEX(p_fill,6);
+ mode=(FillMode)p_fill;
+ update();
+}
+
+int TextureProgress::get_fill_mode()
+{
+ return mode;
+}
+
+void TextureProgress::set_radial_initial_angle(float p_angle)
+{
+ while(p_angle>360)
+ p_angle-=360;
+ while (p_angle<0)
+ p_angle+=360;
+ rad_init_angle=p_angle;
+ update();
+}
+
+float TextureProgress::get_radial_initial_angle()
+{
+ return rad_init_angle;
+}
+
+void TextureProgress::set_fill_degrees(float p_angle)
+{
+ rad_max_degrees=CLAMP(p_angle,0,360);
+ update();
+}
+
+float TextureProgress::get_fill_degrees()
+{
+ return rad_max_degrees;
+}
+
+void TextureProgress::set_radial_center_offset(const Point2 &p_off)
+{
+ rad_center_off=p_off;
+ update();
+}
+
+Point2 TextureProgress::get_radial_center_offset()
+{
+ return rad_center_off;
+}
+
void TextureProgress::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_under_texture","tex"),&TextureProgress::set_under_texture);
@@ -112,13 +264,39 @@ void TextureProgress::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_over_texture","tex"),&TextureProgress::set_over_texture);
ObjectTypeDB::bind_method(_MD("get_over_texture"),&TextureProgress::get_over_texture);
+ ObjectTypeDB::bind_method(_MD("set_fill_mode","mode"),&TextureProgress::set_fill_mode);
+ ObjectTypeDB::bind_method(_MD("get_fill_mode"), &TextureProgress::get_fill_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_radial_initial_angle","mode"),&TextureProgress::set_radial_initial_angle);
+ ObjectTypeDB::bind_method(_MD("get_radial_initial_angle"), &TextureProgress::get_radial_initial_angle);
+
+ ObjectTypeDB::bind_method(_MD("set_radial_center_offset","mode"),&TextureProgress::set_radial_center_offset);
+ ObjectTypeDB::bind_method(_MD("get_radial_center_offset"), &TextureProgress::get_radial_center_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_fill_degrees","mode"),&TextureProgress::set_fill_degrees);
+ ObjectTypeDB::bind_method(_MD("get_fill_degrees"), &TextureProgress::get_fill_degrees);
+
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture/under",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_under_texture"),_SCS("get_under_texture"));
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture/over",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_over_texture"),_SCS("get_over_texture"));
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture/progress",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_progress_texture"),_SCS("get_progress_texture"));
+ ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise"),_SCS("set_fill_mode"),_SCS("get_fill_mode"));
+ ADD_PROPERTYNZ( PropertyInfo(Variant::REAL,"radial_fill/initial_angle",PROPERTY_HINT_RANGE,"0.0,360.0,0.1,slider"),_SCS("set_radial_initial_angle"),_SCS("get_radial_initial_angle"));
+ ADD_PROPERTYNZ( PropertyInfo(Variant::REAL,"radial_fill/fill_degrees",PROPERTY_HINT_RANGE,"0.0,360.0,0.1,slider"),_SCS("set_fill_degrees"),_SCS("get_fill_degrees"));
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"radial_fill/center_offset"),_SCS("set_radial_center_offset"),_SCS("get_radial_center_offset"));
+
+ BIND_CONSTANT( FILL_LEFT_TO_RIGHT );
+ BIND_CONSTANT( FILL_RIGHT_TO_LEFT );
+ BIND_CONSTANT( FILL_TOP_TO_BOTTOM );
+ BIND_CONSTANT( FILL_BOTTOM_TO_TOP );
+ BIND_CONSTANT( FILL_CLOCKWISE );
+ BIND_CONSTANT( FILL_COUNTER_CLOCKWISE );
}
TextureProgress::TextureProgress()
{
+ mode=FILL_LEFT_TO_RIGHT;
+ rad_center_off=Point2();
+ rad_max_degrees=360;
}
diff --git a/scene/gui/texture_progress.h b/scene/gui/texture_progress.h
index d97ebf27f5..7187fd5f07 100644
--- a/scene/gui/texture_progress.h
+++ b/scene/gui/texture_progress.h
@@ -45,6 +45,27 @@ protected:
void _notification(int p_what);
public:
+ enum FillMode {
+ FILL_LEFT_TO_RIGHT=0,
+ FILL_RIGHT_TO_LEFT,
+ FILL_TOP_TO_BOTTOM,
+ FILL_BOTTOM_TO_TOP,
+ FILL_CLOCKWISE,
+ FILL_COUNTER_CLOCKWISE
+ };
+
+ void set_fill_mode(int p_fill);
+ int get_fill_mode();
+
+ void set_radial_initial_angle(float p_angle);
+ float get_radial_initial_angle();
+
+ void set_fill_degrees(float p_angle);
+ float get_fill_degrees();
+
+ void set_radial_center_offset(const Point2 &p_off);
+ Point2 get_radial_center_offset();
+
void set_under_texture(const Ref<Texture>& p_texture);
Ref<Texture> get_under_texture() const;
@@ -57,6 +78,16 @@ public:
Size2 get_minimum_size() const;
TextureProgress();
+
+private:
+
+ FillMode mode;
+ float rad_init_angle;
+ float rad_max_degrees;
+ Point2 rad_center_off;
+
+ Point2 unit_val_to_uv(float val);
+ Point2 get_relative_center();
};
#endif // TEXTURE_PROGRESS_H
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 6c15f1cae4..16a12fe407 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -31,7 +31,7 @@
#include "os/os.h"
#include "os/keyboard.h"
#include "globals.h"
-
+#include "os/input.h"
@@ -70,6 +70,7 @@ Size2 TreeItem::Cell::get_icon_size() const {
else
return icon_region.size;
}
+
void TreeItem::Cell::draw_icon(const RID& p_where, const Point2& p_pos, const Size2& p_size) const{
if (icon.is_null())
@@ -120,7 +121,7 @@ void TreeItem::set_cell_mode( int p_column, TreeCellMode p_mode ) {
c.val=0;
c.checked=false;
c.icon=Ref<Texture>();
- c.text="";
+ c.text="";
c.icon_max_w=0;
_changed_notify(p_column);
}
@@ -152,9 +153,9 @@ void TreeItem::set_text(int p_column,String p_text) {
ERR_FAIL_INDEX( p_column, cells.size() );
cells[p_column].text=p_text;
-
+
if (cells[p_column].mode==TreeItem::CELL_MODE_RANGE) {
-
+
cells[p_column].min=0;
cells[p_column].max=p_text.get_slice_count(",");
cells[p_column].step=0;
@@ -224,7 +225,7 @@ void TreeItem::set_range(int p_column,double p_value) {
p_value=cells[p_column].min;
if (p_value>cells[p_column].max)
p_value=cells[p_column].max;
-
+
cells[p_column].val=p_value;
_changed_notify(p_column);
@@ -236,7 +237,7 @@ double TreeItem::get_range(int p_column) const {
return cells[p_column].val;
}
-
+
bool TreeItem::is_range_exponential(int p_column) const {
ERR_FAIL_INDEX_V( p_column, cells.size(), false);
@@ -303,7 +304,7 @@ void TreeItem::set_collapsed(bool p_collapsed) {
if (tree->select_mode==Tree::SELECT_MULTI) {
- tree->selected_item=this;
+ tree->selected_item=this;
emit_signal("cell_selected");
} else {
@@ -336,11 +337,11 @@ TreeItem *TreeItem::get_prev() {
if (!parent || parent->childs==this)
return NULL;
-
+
TreeItem *prev = parent->childs;
while(prev && prev->next!=this)
prev=prev->next;
-
+
return prev;
}
@@ -635,14 +636,14 @@ void TreeItem::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_range","column"),&TreeItem::get_range);
ObjectTypeDB::bind_method(_MD("set_range_config","column","min","max","step","expr"),&TreeItem::set_range_config,DEFVAL(false));
ObjectTypeDB::bind_method(_MD("get_range_config","column"),&TreeItem::_get_range_config);
-
+
ObjectTypeDB::bind_method(_MD("set_metadata","column","meta"),&TreeItem::set_metadata);
ObjectTypeDB::bind_method(_MD("get_metadata","column"),&TreeItem::get_metadata);
ObjectTypeDB::bind_method(_MD("set_custom_draw","column","object","callback"),&TreeItem::set_custom_draw);
ObjectTypeDB::bind_method(_MD("set_collapsed","enable"),&TreeItem::set_collapsed);
- ObjectTypeDB::bind_method(_MD("is_collapsed"),&TreeItem::is_collapsed);
+ ObjectTypeDB::bind_method(_MD("is_collapsed"),&TreeItem::is_collapsed);
ObjectTypeDB::bind_method(_MD("get_next:TreeItem"),&TreeItem::get_next);
ObjectTypeDB::bind_method(_MD("get_prev:TreeItem"),&TreeItem::get_prev);
@@ -653,17 +654,17 @@ void TreeItem::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_prev_visible:TreeItem"),&TreeItem::get_prev_visible);
ObjectTypeDB::bind_method(_MD("remove_child:TreeItem","child"),&TreeItem::_remove_child);
-
+
ObjectTypeDB::bind_method(_MD("set_selectable","column","selectable"),&TreeItem::set_selectable);
ObjectTypeDB::bind_method(_MD("is_selectable","column"),&TreeItem::is_selectable);
ObjectTypeDB::bind_method(_MD("is_selected","column"),&TreeItem::is_selected);
ObjectTypeDB::bind_method(_MD("select","column"),&TreeItem::select);
ObjectTypeDB::bind_method(_MD("deselect","column"),&TreeItem::deselect);
-
+
ObjectTypeDB::bind_method(_MD("set_editable","column","enabled"),&TreeItem::set_editable);
ObjectTypeDB::bind_method(_MD("is_editable","column"),&TreeItem::is_editable);
-
+
ObjectTypeDB::bind_method(_MD("set_custom_color","column","color"),&TreeItem::set_custom_color);
ObjectTypeDB::bind_method(_MD("clear_custom_color","column"),&TreeItem::clear_custom_color);
@@ -687,7 +688,7 @@ void TreeItem::_bind_methods() {
BIND_CONSTANT( CELL_MODE_RANGE );
BIND_CONSTANT( CELL_MODE_ICON );
BIND_CONSTANT( CELL_MODE_CUSTOM );
-
+
}
@@ -728,14 +729,20 @@ TreeItem::~TreeItem() {
tree->root=0;
}
- if (tree && tree->popup_edited_item==this)
+ if (tree && tree->popup_edited_item==this) {
tree->popup_edited_item=NULL;
+ tree->pressing_for_editor=false;
+
+ }
if (tree && tree->selected_item==this)
tree->selected_item=NULL;
- if (tree && tree->edited_item==this)
+ if (tree && tree->edited_item==this) {
tree->edited_item=NULL;
+ tree->pressing_for_editor=false;
+ }
+
}
@@ -767,7 +774,7 @@ void Tree::update_cache() {
cache.arrow =get_icon("arrow");
cache.select_arrow =get_icon("select_arrow");
cache.updown=get_icon("updown");
-
+
cache.font_color=get_color("font_color");
cache.font_color_selected=get_color("font_color_selected");
cache.guide_color=get_color("guide_color");
@@ -795,10 +802,10 @@ int Tree::compute_item_height(TreeItem *p_item) const {
if (p_item==root && hide_root)
return 0;
-
+
int height=cache.font->get_height();
-
+
for (int i=0;i<columns.size();i++) {
@@ -812,23 +819,23 @@ int Tree::compute_item_height(TreeItem *p_item) const {
}
switch(p_item->cells[i].mode) {
-
+
case TreeItem::CELL_MODE_CHECK: {
-
+
int check_icon_h = cache.checked->get_height();
if (height<check_icon_h)
height=check_icon_h;
-
-
-
+
+
+
}
case TreeItem::CELL_MODE_STRING:
case TreeItem::CELL_MODE_CUSTOM:
case TreeItem::CELL_MODE_ICON: {
-
+
Ref<Texture> icon = p_item->cells[i].icon;
if (!icon.is_null()) {
-
+
Size2i s = p_item->cells[i].get_icon_size();
if (p_item->cells[i].icon_max_w>0 && s.width > p_item->cells[i].icon_max_w ) {
s.height=s.height * p_item->cells[i].icon_max_w / s.width;
@@ -836,15 +843,15 @@ int Tree::compute_item_height(TreeItem *p_item) const {
if (s.height > height )
height=s.height;
}
-
+
} break;
default: {}
}
}
-
-
+
+
height += cache.vseparation;
-
+
return height;
}
@@ -920,7 +927,7 @@ void Tree::draw_item_text(String p_text,const Ref<Texture>& p_icon,int p_icon_ma
p_rect.size.x-=Math::floor(p_rect.size.y/2);
Ref<Font> font = cache.font;
-
+
p_rect.pos.y+=Math::floor((p_rect.size.y-font->get_height())/2.0) +font->get_ascent();
font->draw(ci,p_rect.pos,p_text,p_color,p_rect.size.x);
}
@@ -943,22 +950,24 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
Point2i guide_from;
- bool skip=(p_item==root && hide_root);
+ bool skip=(p_item==root && hide_root);
// printf("skip (%p == %p && %i) %i\n",p_item,root,hide_root,skip);
if (!skip && (p_pos.y+label_h-cache.offset.y)>0) {
- // printf("entering\n");
+ // printf("entering\n");
int height=label_h;
Point2i guide_space=Point2i( cache.guide_width , height );
- if (p_item->childs) { //has childs, draw the guide box
+
+
+ if (!hide_folding && p_item->childs) { //has childs, draw the guide box
Ref<Texture> arrow;
-
+
if (p_item->collapsed) {
arrow=cache.arrow_collapsed;
@@ -976,10 +985,10 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
// if (p_item->get_parent()!=root || !hide_root)
Ref<Font> font = cache.font;
-
+
int font_ascent=font->get_ascent();
- int ofs = p_pos.x + cache.item_margin;
+ int ofs = p_pos.x + (hide_folding?cache.hseparation:cache.item_margin);
for (int i=0;i<columns.size();i++) {
int w = get_column_width(i);
@@ -1055,11 +1064,14 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
if (p_item->cells[i].custom_bg_color) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci,cell_rect,p_item->cells[i].bg_color);
+ Rect2 r=cell_rect;
+ r.pos.x-=cache.hseparation;
+ r.size.x+=cache.hseparation;
+ VisualServer::get_singleton()->canvas_item_add_rect(ci,r,p_item->cells[i].bg_color);
}
Color col=p_item->cells[i].custom_color?p_item->cells[i].color:get_color( p_item->cells[i].selected?"font_color_selected":"font_color");
-
+
Point2i text_pos=item_rect.pos;
text_pos.y+=Math::floor((item_rect.size.y-font->get_height())/2) + font_ascent;
@@ -1097,7 +1109,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
} break;
case TreeItem::CELL_MODE_RANGE: {
-
+
if (p_item->cells[i].text!="") {
if (!p_item->cells[i].editable)
@@ -1121,7 +1133,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
} else {
Ref<Texture> updown = cache.updown;
-
+
String valtext = String::num( p_item->cells[i].val, Math::decimals( p_item->cells[i].step ) );
font->draw( ci, text_pos, valtext, col, item_rect.size.x-updown->get_width());
@@ -1178,7 +1190,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
Rect2i ir=item_rect;
ir.size.width-=downarrow->get_width();
draw_item_rect(p_item->cells[i],ir,col);
-
+
Point2i arrow_pos=item_rect.pos;
arrow_pos.x+=item_rect.size.x-downarrow->get_width();
arrow_pos.y+=Math::floor(((item_rect.size.y-downarrow->get_height()))/2.0);
@@ -1220,7 +1232,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
children_pos.x+=cache.item_margin;
htotal+=label_h;
children_pos.y+=htotal;
-
+
}
@@ -1265,12 +1277,12 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col
continue;
if (select_mode==SELECT_ROW) {
-
+
if (p_selected==p_current) {
-
+
if (!c.selected) {
-
+
c.selected=true;
selected_item=p_selected;
selected_col=0;
@@ -1279,28 +1291,29 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col
//if (p_col==i)
// p_current->selected_signal.call(p_col);
}
-
+
} else {
-
+
if (c.selected) {
-
- c.selected=false;
+
+ c.selected=false;
//p_current->deselected_signal.call(p_col);
}
-
+
}
-
+
} else if (select_mode==SELECT_SINGLE || select_mode==SELECT_MULTI) {
-
- if (&selected_cell==&c) {
-
+
+ if (!r_in_range && &selected_cell==&c) {
+
if (!selected_cell.selected) {
-
+
selected_cell.selected=true;
-
+
selected_item=p_selected;
selected_col=i;
+
emit_signal("cell_selected");
if (select_mode==SELECT_MULTI)
emit_signal("multi_selected",p_current,i,true);
@@ -1313,10 +1326,11 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col
}
} else {
-
+
if (r_in_range && *r_in_range) {
+
if (!c.selected && c.selectable) {
c.selected=true;
emit_signal("multi_selected",p_current,i,true);
@@ -1363,11 +1377,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
int item_h=compute_item_height( p_item )+cache.vseparation;
bool skip=(p_item==root && hide_root);
-
+
if (!skip && p_pos.y<item_h) {
// check event!
- if (p_pos.x >=x_ofs && p_pos.x < (x_ofs+cache.item_margin) ) {
+ if (!hide_folding && (p_pos.x >=x_ofs && p_pos.x < (x_ofs+cache.item_margin) )) {
if (p_item->childs)
@@ -1375,7 +1389,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
return -1; //handled!
}
-
+
int x=p_pos.x;
/* find clicked column */
int col=-1;
@@ -1394,7 +1408,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
break;
}
-
+
if (col==-1)
return -1;
@@ -1467,7 +1481,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
if (select_mode==SELECT_MULTI && p_mod.shift && selected_item && selected_item!=p_item) {
bool inrange=false;
- print_line("SELECT MULTI AND SHIFT AND ALL");
+
select_single_item( p_item, root, col,selected_item,&inrange );
} else {
select_single_item( p_item, root, col );
@@ -1478,8 +1492,8 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
//}
update();
}
-
-
+
+
}
}
@@ -1490,7 +1504,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
/* editing */
- bool bring_up_editor=c.selected && already_selected;
+ bool bring_up_editor=c.selected;// && already_selected;
bool bring_up_value_editor=false;
String editor_text=c.text;
@@ -1505,14 +1519,14 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
} break;
case TreeItem::CELL_MODE_CHECK: {
-
+
Ref<Texture> checked = cache.checked;
bring_up_editor=false; //checkboxes are not edited with editor
if (x>=0 && x<= checked->get_width()+cache.hseparation ) {
-
+
p_item->set_checked(col,!c.checked);
- item_edited(col,p_item);
+ item_edited(col,p_item);
click_handled=true;
//p_item->edited_signal.call(col);
}
@@ -1540,37 +1554,37 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
//}
bring_up_editor=false;
} else {
-
+
Ref<Texture> updown = cache.updown;
-
-
+
+
if (x >= (col_width-item_h/2)) {
-
+
/* touching the combo */
bool up=p_pos.y < (item_h /2);
-
+
if (p_button==BUTTON_LEFT) {
p_item->set_range( col, c.val + (up?1.0:-1.0) * c.step );
-
- item_edited(col,p_item);
+
+ item_edited(col,p_item);
} else if (p_button==BUTTON_RIGHT) {
-
+
p_item->set_range( col, (up?c.max:c.min) );
- item_edited(col,p_item);
+ item_edited(col,p_item);
} else if (p_button==BUTTON_WHEEL_UP) {
-
+
p_item->set_range( col, c.val + c.step );
- item_edited(col,p_item);
+ item_edited(col,p_item);
} else if (p_button==BUTTON_WHEEL_DOWN) {
-
+
p_item->set_range( col, c.val - c.step );
- item_edited(col,p_item);
+ item_edited(col,p_item);
}
-
- //p_item->edited_signal.call(col);
+
+ //p_item->edited_signal.call(col);
bring_up_editor=false;
-
-
+
+
} else {
editor_text=String::num( p_item->cells[col].val, Math::decimals( p_item->cells[col].step ) );
@@ -1578,7 +1592,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
if (select_mode==SELECT_MULTI && get_tree()->get_last_event_id() == focus_in_id)
bring_up_editor=false;
- }
+ }
}
click_handled=true;
@@ -1589,12 +1603,12 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
} break;
case TreeItem::CELL_MODE_CUSTOM: {
edited_item=p_item;
- edited_col=col;
+ edited_col=col;
custom_popup_rect=Rect2i(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs+item_h-cache.offset.y), Size2(get_column_width(col),item_h));
emit_signal("custom_popup_edited",((bool)(x >= (col_width-item_h/2))));
bring_up_editor=false;
- item_edited(col,p_item);
+ item_edited(col,p_item);
click_handled=true;
return -1;
} break;
@@ -1605,44 +1619,27 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
return -1;
+
click_handled=true;
popup_edited_item=p_item;
popup_edited_item_col=col;
- text_editor->set_pos(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset );
- text_editor->set_size( Size2(col_width,item_h));
- text_editor->clear();
- text_editor->set_text( editor_text );
- text_editor->select_all();
-
- if (bring_up_value_editor) {
- value_editor->set_pos(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset+Point2i(0,text_editor->get_size().height) );
- value_editor->set_size( Size2(col_width,1));
- value_editor->show_modal();
- updating_value_editor=true;
- value_editor->set_min( c.min );
- value_editor->set_max( c.max );
- value_editor->set_step( c.step );
- value_editor->set_val( c.val );
- value_editor->set_exp_unit_value( c.expr );
- updating_value_editor=false;
- }
-
- text_editor->show_modal();
- text_editor->grab_focus();
+ pressing_item_rect=Rect2(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset,Size2(col_width,item_h));
+ pressing_for_editor_text=editor_text;
+ pressing_for_editor=true;
return -1; //select
} else {
Point2i new_pos=p_pos;
-
+
if (!skip) {
x_ofs+=cache.item_margin;
//new_pos.x-=cache.item_margin;
y_ofs+=item_h;
new_pos.y-=item_h;
}
-
+
if (!p_item->collapsed) { /* if not collapsed, check the childs */
@@ -1705,7 +1702,7 @@ void Tree::text_editor_enter(String p_text) {
default: { ERR_FAIL(); }
}
- item_edited(popup_edited_item_col,popup_edited_item);
+ item_edited(popup_edited_item_col,popup_edited_item);
update();
}
@@ -1733,19 +1730,19 @@ void Tree::popup_select(int p_option) {
if (popup_edited_item_col<0 || popup_edited_item_col>columns.size())
return;
-
+
popup_edited_item->cells[popup_edited_item_col].val=p_option;
//popup_edited_item->edited_signal.call( popup_edited_item_col );
update();
- item_edited(popup_edited_item_col,popup_edited_item);
+ item_edited(popup_edited_item_col,popup_edited_item);
}
void Tree::_input_event(InputEvent p_event) {
-
+
switch (p_event.type) {
-
+
case InputEvent::KEY: {
if (!p_event.key.pressed)
@@ -2062,6 +2059,33 @@ void Tree::_input_event(InputEvent p_event) {
update();
}
+ if (pressing_for_editor && popup_edited_item && popup_edited_item->get_cell_mode(popup_edited_item_col)==TreeItem::CELL_MODE_RANGE) {
+ //range drag
+
+ if (!range_drag_enabled) {
+
+ Vector2 cpos = Vector2(b.x,b.y);
+ if (cpos.distance_to(pressing_pos)>2) {
+ range_drag_enabled=true;
+ range_drag_capture_pos=cpos;
+ range_drag_base=popup_edited_item->get_range(popup_edited_item_col);
+ Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
+ }
+ } else {
+
+ TreeItem::Cell &c=popup_edited_item->cells[popup_edited_item_col];
+ float diff_y = -b.relative_y;
+ diff_y=Math::pow(ABS(diff_y),1.8)*SGN(diff_y);
+ diff_y*=0.1;
+ range_drag_base=CLAMP(range_drag_base + c.step * diff_y, c.min, c.max);
+
+ popup_edited_item->set_range(popup_edited_item_col,range_drag_base);
+ item_edited(popup_edited_item_col,popup_edited_item);
+
+ }
+
+ }
+
if (drag_touching && ! drag_touching_deaccel) {
@@ -2072,18 +2096,43 @@ void Tree::_input_event(InputEvent p_event) {
}
} break;
case InputEvent::MOUSE_BUTTON: {
-
+
if (cache.font.is_null()) // avoid a strange case that may fuckup stuff
update_cache();
- const InputEventMouseButton& b=p_event.mouse_button;
+ const InputEventMouseButton& b=p_event.mouse_button;
if (!b.pressed) {
if (b.button_index==BUTTON_LEFT) {
+ if (pressing_for_editor) {
+
+ if (range_drag_enabled) {
+
+ range_drag_enabled=false;
+ Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+ warp_mouse(range_drag_capture_pos);
+ } else {
+ text_editor->set_pos(pressing_item_rect.pos);
+ text_editor->set_size(pressing_item_rect.size);
+
+ text_editor->clear();
+ text_editor->set_text( pressing_for_editor_text );
+ text_editor->select_all();
+
+ text_editor->show_modal();
+ text_editor->grab_focus();
+
+ }
+ pressing_for_editor=false;
+
+ }
+
+
+
if (cache.click_type==Cache::CLICK_BUTTON) {
emit_signal("button_pressed",cache.click_item,cache.click_column,cache.click_id);
@@ -2116,7 +2165,7 @@ void Tree::_input_event(InputEvent p_event) {
switch(b.button_index) {
case BUTTON_LEFT: {
Ref<StyleBox> bg = cache.bg;
-
+
Point2 pos = Point2(b.x,b.y) - bg->get_offset();
cache.click_type=Cache::CLICK_NONE;
if (show_column_titles) {
@@ -2145,11 +2194,15 @@ void Tree::_input_event(InputEvent p_event) {
break;
click_handled=false;
+ pressing_for_editor=false;
blocked++;
bool handled = propagate_mouse_event(pos+cache.offset,0,0,b.doubleclick,root,b.button_index,b.mod);
blocked--;
+ if (pressing_for_editor) {
+ pressing_pos=Point2(b.x,b.y);
+ }
if (drag_touching) {
@@ -2174,18 +2227,18 @@ void Tree::_input_event(InputEvent p_event) {
} break;
- case BUTTON_WHEEL_UP: {
+ case BUTTON_WHEEL_UP: {
v_scroll->set_val( v_scroll->get_val()-v_scroll->get_page()/8 );
} break;
case BUTTON_WHEEL_DOWN: {
-
+
v_scroll->set_val( v_scroll->get_val()+v_scroll->get_page()/8 );
} break;
}
-
+
} break;
}
-
+
}
@@ -2218,9 +2271,12 @@ bool Tree::edit_selected() {
TreeItem::Cell &c = s->cells[col];
+ if (c.mode==TreeItem::CELL_MODE_CHECK) {
-
- if (c.mode==TreeItem::CELL_MODE_CUSTOM) {
+ s->set_checked(col, !c.checked);
+ item_edited(col,s);
+ return true;
+ } else if (c.mode==TreeItem::CELL_MODE_CUSTOM) {
edited_item=s;
edited_col=col;
@@ -2283,10 +2339,10 @@ Size2 Tree::get_internal_min_size() const {
if (root)
size.height+=get_item_height(root);
for (int i=0;i<columns.size();i++) {
-
+
size.width+=columns[i].min_width;
}
-
+
return size;
}
@@ -2305,39 +2361,39 @@ void Tree::update_scrollbars() {
Size2 vmin = v_scroll->get_combined_minimum_size();
-
+
v_scroll->set_begin( Point2(size.width - vmin.width , cache.bg->get_margin(MARGIN_TOP)) );
v_scroll->set_end( Point2(size.width, size.height-cache.bg->get_margin(MARGIN_TOP)-cache.bg->get_margin(MARGIN_BOTTOM)) );
-
+
h_scroll->set_begin( Point2( 0, size.height - hmin.height) );
h_scroll->set_end( Point2(size.width-vmin.width, size.height) );
-
-
+
+
Size2 min = get_internal_min_size();
-
+
if (min.height < size.height - hmin.height) {
-
+
v_scroll->hide();
cache.offset.y=0;
} else {
-
+
v_scroll->show();
v_scroll->set_max(min.height);
v_scroll->set_page(size.height - hmin.height - tbh);
cache.offset.y=v_scroll->get_val();
}
-
+
if (min.width < size.width - vmin.width) {
-
+
h_scroll->hide();
cache.offset.x=0;
} else {
-
+
h_scroll->show();
h_scroll->set_max(min.width);
h_scroll->set_page(size.width - vmin.width);
cache.offset.x=h_scroll->get_val();
- }
+ }
}
@@ -2360,6 +2416,11 @@ void Tree::_notification(int p_what) {
}
}
+ if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
+ drag_touching=false;
+ }
+
if (p_what==NOTIFICATION_ENTER_TREE) {
update_cache();;
@@ -2411,16 +2472,16 @@ void Tree::_notification(int p_what) {
}
if (p_what==NOTIFICATION_DRAW) {
-
+
update_cache();
update_scrollbars();
- RID ci = get_canvas_item();
-
+ RID ci = get_canvas_item();
+
VisualServer::get_singleton()->canvas_item_set_clip(ci,true);
-
+
Ref<StyleBox> bg = cache.bg;
Ref<StyleBox> bg_focus = get_stylebox("bg_focus");
-
+
Point2 draw_ofs;
draw_ofs+=bg->get_offset();
Size2 draw_size=get_size()-bg->get_minimum_size();
@@ -2438,7 +2499,7 @@ void Tree::_notification(int p_what) {
draw_size.y-=tbh;
if (root) {
-
+
draw_item( Point2(),draw_ofs,draw_size,root);
@@ -2449,10 +2510,10 @@ void Tree::_notification(int p_what) {
// int size_y=exposed.size.height-bg->get_minimum_size().height;
for (int i=0;i<(columns.size()-1-1);i++) {
-
+
ofs+=get_column_width(i);
//get_painter()->draw_fill_rect( Point2(ofs+cache.hseparation/2, from_y), Size2( 1, size_y ),color( COLOR_TREE_GRID) );
- }
+ }
if (show_column_titles) {
@@ -2552,7 +2613,7 @@ TreeItem* Tree::get_last_item() {
}
void Tree::item_edited(int p_column,TreeItem *p_item) {
-
+
edited_item=p_item;
edited_col=p_column;
emit_signal("item_edited");
@@ -2560,14 +2621,14 @@ void Tree::item_edited(int p_column,TreeItem *p_item) {
void Tree::item_changed(int p_column,TreeItem *p_item) {
- update();
+ update();
}
void Tree::item_selected(int p_column,TreeItem *p_item) {
if (select_mode==SELECT_MULTI) {
-
+
if (!p_item->cells[p_column].selectable)
return;
@@ -2583,16 +2644,16 @@ void Tree::item_selected(int p_column,TreeItem *p_item) {
void Tree::item_deselected(int p_column,TreeItem *p_item) {
if (select_mode==SELECT_MULTI) {
-
+
p_item->cells[p_column].selected=false;
- }
+ }
update();
}
void Tree::set_select_mode(SelectMode p_mode) {
- select_mode=p_mode;
+ select_mode=p_mode;
}
void Tree::clear() {
@@ -2610,6 +2671,8 @@ void Tree::clear() {
selected_item=NULL;
edited_item=NULL;
popup_edited_item=NULL;
+ selected_item=NULL;
+ pressing_for_editor=false;
update();
};
@@ -2620,15 +2683,15 @@ void Tree::set_hide_root(bool p_enabled) {
- hide_root=p_enabled;
- update();
+ hide_root=p_enabled;
+ update();
}
void Tree::set_column_min_width(int p_column,int p_min_width) {
ERR_FAIL_INDEX(p_column,columns.size());
-
+
if (p_min_width<1)
return;
columns[p_column].min_width=p_min_width;
@@ -2638,8 +2701,8 @@ void Tree::set_column_min_width(int p_column,int p_min_width) {
void Tree::set_column_expand(int p_column,bool p_expand) {
ERR_FAIL_INDEX(p_column,columns.size());
-
- columns[p_column].expand=p_expand;
+
+ columns[p_column].expand=p_expand;
update();
}
@@ -2654,78 +2717,78 @@ int Tree::get_selected_column() const {
}
TreeItem *Tree::get_edited() const {
-
+
return edited_item;
}
int Tree::get_edited_column() const {
-
+
return edited_col;
}
TreeItem* Tree::get_next_selected( TreeItem* p_item) {
-
+
//if (!p_item)
// return NULL;
if (!root)
- return NULL;
-
+ return NULL;
+
while(true) {
-
-
+
+
if (!p_item) {
p_item=root;
} else {
-
+
if (p_item->childs) {
-
+
p_item=p_item->childs;
-
+
} else if (p_item->next) {
-
- p_item=p_item->next;
+
+ p_item=p_item->next;
} else {
-
+
while(!p_item->next) {
-
+
p_item=p_item->parent;
if (p_item==NULL)
return NULL;
}
-
+
p_item=p_item->next;
}
-
+
}
-
+
for (int i=0;i<columns.size();i++)
if (p_item->cells[i].selected)
return p_item;
}
-
+
return NULL;
}
int Tree::get_column_width(int p_column) const {
-
+
ERR_FAIL_INDEX_V(p_column,columns.size(),-1);
-
-
+
+
if (!columns[p_column].expand)
return columns[p_column].min_width;
-
+
Ref<StyleBox> bg = cache.bg;
-
+
int expand_area=get_size().width-(bg->get_margin(MARGIN_LEFT)+bg->get_margin(MARGIN_RIGHT));
-
+
if (v_scroll->is_visible())
expand_area-=v_scroll->get_combined_minimum_size().width;
-
+
int expanding_columns=0;
int expanding_total=0;
-
+
for (int i=0;i<columns.size();i++) {
-
+
if (!columns[i].expand) {
expand_area-=columns[i].min_width;
} else {
@@ -2736,30 +2799,30 @@ int Tree::get_column_width(int p_column) const {
if (expand_area<expanding_total)
return columns[p_column].min_width;
-
+
ERR_FAIL_COND_V(expanding_columns==0,-1); // shouldnt happen
-
+
return expand_area * columns[p_column].min_width / expanding_total;
}
void Tree::propagate_set_columns(TreeItem *p_item) {
-
+
p_item->cells.resize( columns.size() );
-
+
TreeItem *c = p_item->get_children();
while(c) {
-
+
propagate_set_columns(c);
c=c->get_next();
}
}
void Tree::set_columns(int p_columns) {
-
+
ERR_FAIL_COND(p_columns<1);
ERR_FAIL_COND(blocked>0);
columns.resize(p_columns);
-
+
if (root)
propagate_set_columns(root);
if (selected_col>=p_columns)
@@ -2769,17 +2832,17 @@ void Tree::set_columns(int p_columns) {
}
int Tree::get_columns() const {
-
+
return columns.size();
}
void Tree::_scroll_moved(float) {
-
+
update();
}
Rect2 Tree::get_custom_popup_rect() const {
-
+
return custom_popup_rect;
}
@@ -3059,9 +3122,19 @@ bool Tree::can_cursor_exit_tree() const {
return cursor_can_exit_tree;
}
+void Tree::set_hide_folding(bool p_hide) {
+ hide_folding=p_hide;
+ update();
+}
+
+bool Tree::is_folding_hidden() const {
+
+ return hide_folding;
+}
+
void Tree::_bind_methods() {
-
+
ObjectTypeDB::bind_method(_MD("_input_event"),&Tree::_input_event);
ObjectTypeDB::bind_method(_MD("_popup_select"),&Tree::popup_select);
ObjectTypeDB::bind_method(_MD("_text_editor_enter"),&Tree::text_editor_enter);
@@ -3085,7 +3158,7 @@ void Tree::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_columns","amount"),&Tree::set_columns);
ObjectTypeDB::bind_method(_MD("get_columns"),&Tree::get_columns);
-
+
ObjectTypeDB::bind_method(_MD("get_edited:TreeItem"),&Tree::get_edited);
ObjectTypeDB::bind_method(_MD("get_edited_column"),&Tree::get_edited_column);
ObjectTypeDB::bind_method(_MD("get_custom_popup_rect"),&Tree::get_custom_popup_rect);
@@ -3100,6 +3173,9 @@ void Tree::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_column_title","column"),&Tree::get_column_title);
ObjectTypeDB::bind_method(_MD("get_scroll"),&Tree::get_scroll);
+ ObjectTypeDB::bind_method(_MD("set_hide_folding","hide"),&Tree::set_hide_folding);
+ ObjectTypeDB::bind_method(_MD("is_folding_hidden"),&Tree::is_folding_hidden);
+
ADD_SIGNAL( MethodInfo("item_selected"));
ADD_SIGNAL( MethodInfo("cell_selected"));
@@ -3124,7 +3200,7 @@ Tree::Tree() {
edited_item=NULL;
selected_col=-1;
edited_col=-1;
-
+
hide_root=false;
select_mode=SELECT_SINGLE;
root=0;
@@ -3132,8 +3208,8 @@ Tree::Tree() {
popup_edited_item=NULL;
text_editor=NULL;
set_focus_mode(FOCUS_ALL);
-
-
+
+
popup_menu = memnew( PopupMenu );
popup_menu->hide();
add_child(popup_menu);
@@ -3149,7 +3225,7 @@ Tree::Tree() {
h_scroll = memnew( HScrollBar );
v_scroll = memnew( VScrollBar );
-
+
add_child(h_scroll);
add_child(v_scroll);
@@ -3184,6 +3260,10 @@ Tree::Tree() {
drag_speed=0;
drag_touching=false;
drag_touching_deaccel=false;
+ pressing_for_editor=false;
+ range_drag_enabled=false;
+
+ hide_folding=false;
}
@@ -3193,6 +3273,6 @@ Tree::~Tree() {
if (root) {
memdelete( root );
}
-
+
}
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 8ddddd0630..8fb9b802a1 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -228,6 +228,7 @@ public:
void set_tooltip(int p_column, const String& p_tooltip);
String get_tooltip(int p_column) const;
+
void clear_children();
void move_to_top();
@@ -258,7 +259,18 @@ friend class TreeItem;
TreeItem *popup_edited_item;
TreeItem *selected_item;
TreeItem *edited_item;
+
+
int pressed_button;
+ bool pressing_for_editor;
+ String pressing_for_editor_text;
+ Vector2 pressing_pos;
+ Rect2 pressing_item_rect;
+
+ float range_drag_base;
+ bool range_drag_enabled;
+ Vector2 range_drag_capture_pos;
+
//TreeItem *cursor_item;
//int cursor_column;
@@ -399,6 +411,8 @@ friend class TreeItem;
bool drag_touching_deaccel;
bool click_handled;
+ bool hide_folding;
+
protected:
static void _bind_methods();
@@ -456,6 +470,11 @@ public:
VScrollBar *get_vscroll_bar() { return v_scroll; }
+ void set_hide_folding(bool p_hide);
+ bool is_folding_hidden() const;
+
+
+
Tree();
~Tree();
diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp
index c0b971cb33..9b9c797ed9 100644
--- a/scene/gui/video_player.cpp
+++ b/scene/gui/video_player.cpp
@@ -28,6 +28,88 @@
/*************************************************************************/
#include "video_player.h"
+
+
+int VideoPlayer::InternalStream::get_channel_count() const {
+
+ return player->sp_get_channel_count();
+}
+void VideoPlayer::InternalStream::set_mix_rate(int p_rate){
+
+ return player->sp_set_mix_rate(p_rate);
+}
+bool VideoPlayer::InternalStream::mix(int32_t *p_buffer,int p_frames){
+
+ return player->sp_mix(p_buffer,p_frames);
+}
+void VideoPlayer::InternalStream::update(){
+
+ player->sp_update();
+}
+
+
+int VideoPlayer::sp_get_channel_count() const {
+
+ return playback->get_channels();
+}
+
+void VideoPlayer::sp_set_mix_rate(int p_rate){
+
+ server_mix_rate=p_rate;
+}
+
+bool VideoPlayer::sp_mix(int32_t *p_buffer,int p_frames) {
+
+ if (resampler.is_ready()) {
+ return resampler.mix(p_buffer,p_frames);
+ }
+
+ return false;
+}
+
+void VideoPlayer::sp_update() {
+#if 0
+ _THREAD_SAFE_METHOD_
+ //update is unused
+ if (!paused && playback.is_valid()) {
+
+ if (!playback->is_playing()) {
+ //stream depleted data, but there's still audio in the ringbuffer
+ //check that all this audio has been flushed before stopping the stream
+ int to_mix = resampler.get_total() - resampler.get_todo();
+ if (to_mix==0) {
+ stop();
+ return;
+ }
+
+ return;
+ }
+
+ int todo =resampler.get_todo();
+ int wrote = playback->mix(resampler.get_write_buffer(),todo);
+ resampler.write(wrote);
+ }
+#endif
+}
+
+int VideoPlayer::_audio_mix_callback(void* p_udata,const int16_t *p_data,int p_frames) {
+
+ VideoPlayer *vp=(VideoPlayer*)p_udata;
+
+ int todo=MIN(vp->resampler.get_todo(),p_frames);
+
+ int16_t *wb = vp->resampler.get_write_buffer();
+ int c = vp->resampler.get_channel_count();
+
+ for(int i=0;i<todo*c;i++) {
+ wb[i]=p_data[i];
+ }
+ vp->resampler.write(todo);
+ return todo;
+}
+
+
+
void VideoPlayer::_notification(int p_notification) {
switch (p_notification) {
@@ -45,16 +127,25 @@ void VideoPlayer::_notification(int p_notification) {
return;
if (paused)
return;
- if (!stream->is_playing())
+ if (!playback->is_playing())
return;
- stream->update(get_tree()->get_idle_process_time());
- int prev_width = texture->get_width();
+ double audio_time = AudioServer::get_singleton()->get_mix_time();
+
+ double delta = last_audio_time==0?0:audio_time-last_audio_time;
+ last_audio_time=audio_time;
+ if (delta==0)
+ return;
+
+
+ playback->update(delta);
+
+ /*int prev_width = texture->get_width();
stream->pop_frame(texture);
if (prev_width == 0) {
update();
minimum_size_changed();
- };
+ };*/
} break;
@@ -75,6 +166,9 @@ void VideoPlayer::_notification(int p_notification) {
};
+
+
+
Size2 VideoPlayer::get_minimum_size() const {
if (!expand && !texture.is_null())
@@ -100,15 +194,33 @@ void VideoPlayer::set_stream(const Ref<VideoStream> &p_stream) {
stop();
- texture = Ref<ImageTexture>(memnew(ImageTexture));
-
stream=p_stream;
- if (!stream.is_null()) {
-
- stream->set_loop(loops);
- stream->set_paused(paused);
+ if (stream.is_valid()) {
+ stream->set_audio_track(audio_track);
+ playback=stream->instance_playback();
+ } else {
+ playback=Ref<VideoStreamPlayback>();
+ }
+
+ if (!playback.is_null()) {
+ playback->set_loop(loops);
+ playback->set_paused(paused);
+ texture=playback->get_texture();
+
+ AudioServer::get_singleton()->lock();
+ resampler.setup(playback->get_channels(),playback->get_mix_rate(),server_mix_rate,buffering_ms,0);
+ AudioServer::get_singleton()->unlock();
+ playback->set_mix_callback(_audio_mix_callback,this);
+
+ } else {
+ texture.unref();
+ AudioServer::get_singleton()->lock();
+ resampler.clear();
+ AudioServer::get_singleton()->unlock();
}
+ update();
+
};
Ref<VideoStream> VideoPlayer::get_stream() const {
@@ -119,36 +231,43 @@ Ref<VideoStream> VideoPlayer::get_stream() const {
void VideoPlayer::play() {
ERR_FAIL_COND(!is_inside_tree());
- if (stream.is_null())
+ if (playback.is_null())
return;
- stream->play();
+ playback->stop();
+ playback->play();
set_process(true);
+ AudioServer::get_singleton()->stream_set_active(stream_rid,true);
+ AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume);
+ last_audio_time=0;
};
void VideoPlayer::stop() {
if (!is_inside_tree())
return;
- if (stream.is_null())
+ if (playback.is_null())
return;
- stream->stop();
+ playback->stop();
+ AudioServer::get_singleton()->stream_set_active(stream_rid,false);
+ resampler.clear();
set_process(false);
+ last_audio_time=0;
};
bool VideoPlayer::is_playing() const {
- if (stream.is_null())
+ if (playback.is_null())
return false;
- return stream->is_playing();
+ return playback->is_playing();
};
void VideoPlayer::set_paused(bool p_paused) {
paused=p_paused;
- if (stream.is_valid()) {
- stream->set_paused(p_paused);
+ if (playback.is_valid()) {
+ playback->set_paused(p_paused);
set_process(!p_paused);
};
};
@@ -156,7 +275,27 @@ void VideoPlayer::set_paused(bool p_paused) {
bool VideoPlayer::is_paused() const {
return paused;
-};
+}
+
+void VideoPlayer::set_buffering_msec(int p_msec) {
+
+ buffering_ms=p_msec;
+}
+
+int VideoPlayer::get_buffering_msec() const{
+
+ return buffering_ms;
+}
+
+void VideoPlayer::set_audio_track(int p_track) {
+ audio_track=p_track;
+}
+
+int VideoPlayer::get_audio_track() const {
+
+ return audio_track;
+}
+
void VideoPlayer::set_volume(float p_vol) {
@@ -194,9 +333,9 @@ String VideoPlayer::get_stream_name() const {
float VideoPlayer::get_stream_pos() const {
- if (stream.is_null())
+ if (playback.is_null())
return 0;
- return stream->get_pos();
+ return playback->get_pos();
};
@@ -229,6 +368,9 @@ void VideoPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_volume_db","db"),&VideoPlayer::set_volume_db);
ObjectTypeDB::bind_method(_MD("get_volume_db"),&VideoPlayer::get_volume_db);
+ ObjectTypeDB::bind_method(_MD("set_audio_track","track"),&VideoPlayer::set_audio_track);
+ ObjectTypeDB::bind_method(_MD("get_audio_track"),&VideoPlayer::get_audio_track);
+
ObjectTypeDB::bind_method(_MD("get_stream_name"),&VideoPlayer::get_stream_name);
ObjectTypeDB::bind_method(_MD("get_stream_pos"),&VideoPlayer::get_stream_pos);
@@ -239,7 +381,10 @@ void VideoPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_expand","enable"), &VideoPlayer::set_expand );
ObjectTypeDB::bind_method(_MD("has_expand"), &VideoPlayer::has_expand );
+ ObjectTypeDB::bind_method(_MD("set_buffering_msec","msec"),&VideoPlayer::set_buffering_msec);
+ ObjectTypeDB::bind_method(_MD("get_buffering_msec"),&VideoPlayer::get_buffering_msec);
+ ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/audio_track",PROPERTY_HINT_RANGE,"0,128,1"), _SCS("set_audio_track"), _SCS("get_audio_track") );
ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"VideoStream"), _SCS("set_stream"), _SCS("get_stream") );
// ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), _SCS("set_loop"), _SCS("has_loop") );
ADD_PROPERTY( PropertyInfo(Variant::REAL, "stream/volume_db", PROPERTY_HINT_RANGE,"-80,24,0.01"), _SCS("set_volume_db"), _SCS("get_volume_db") );
@@ -257,6 +402,16 @@ VideoPlayer::VideoPlayer() {
autoplay = false;
expand = true;
loops = false;
+
+ audio_track=0;
+
+ buffering_ms=500;
+ server_mix_rate=44100;
+
+ internal_stream.player=this;
+ stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream);
+ last_audio_time=0;
+
};
VideoPlayer::~VideoPlayer() {
diff --git a/scene/gui/video_player.h b/scene/gui/video_player.h
index 2b850ca509..c485e3d6b6 100644
--- a/scene/gui/video_player.h
+++ b/scene/gui/video_player.h
@@ -31,22 +31,50 @@
#include "scene/resources/video_stream.h"
#include "scene/gui/control.h"
+#include "servers/audio/audio_rb_resampler.h"
class VideoPlayer : public Control {
OBJ_TYPE(VideoPlayer,Control);
+ struct InternalStream : public AudioServer::AudioStream {
+ VideoPlayer *player;
+ virtual int get_channel_count() const;
+ virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate
+ virtual bool mix(int32_t *p_buffer,int p_frames);
+ virtual void update();
+ };
+
+
+ InternalStream internal_stream;
+ Ref<VideoStreamPlayback> playback;
Ref<VideoStream> stream;
+
+ int sp_get_channel_count() const;
+ void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate
+ bool sp_mix(int32_t *p_buffer,int p_frames);
+ void sp_update();
+
+
RID stream_rid;
Ref<ImageTexture> texture;
Image last_frame;
+ AudioRBResampler resampler;
+
bool paused;
bool autoplay;
float volume;
+ double last_audio_time;
bool expand;
bool loops;
+ int buffering_ms;
+ int server_mix_rate;
+ int audio_track;
+
+ static int _audio_mix_callback(void* p_udata,const int16_t *p_data,int p_frames);
+
protected:
@@ -82,6 +110,12 @@ public:
void set_autoplay(bool p_vol);
bool has_autoplay() const;
+ void set_audio_track(int p_track);
+ int get_audio_track() const;
+
+ void set_buffering_msec(int p_msec);
+ int get_buffering_msec() const;
+
VideoPlayer();
~VideoPlayer();
};