summaryrefslogtreecommitdiff
path: root/scene/gui
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui')
-rw-r--r--scene/gui/base_button.cpp1
-rw-r--r--scene/gui/button.cpp11
-rw-r--r--scene/gui/color_ramp_edit.cpp368
-rw-r--r--scene/gui/color_ramp_edit.h52
-rw-r--r--scene/gui/control.cpp7
-rw-r--r--scene/gui/grid_container.cpp18
-rw-r--r--scene/gui/item_list.cpp1048
-rw-r--r--scene/gui/item_list.h132
-rw-r--r--scene/gui/popup.cpp42
-rw-r--r--scene/gui/popup.h1
-rw-r--r--scene/gui/rich_text_label.cpp58
-rw-r--r--scene/gui/rich_text_label.h13
-rw-r--r--scene/gui/split_container.cpp3
-rw-r--r--scene/gui/tab_container.cpp120
-rw-r--r--scene/gui/tab_container.h11
-rw-r--r--scene/gui/text_edit.cpp4
16 files changed, 1850 insertions, 39 deletions
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index dff2377766..8b6f433c9c 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -148,6 +148,7 @@ void BaseButton::_input_event(InputEvent p_event) {
update();
}
} break;
+ case InputEvent::ACTION:
case InputEvent::JOYSTICK_BUTTON:
case InputEvent::KEY: {
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 5b837d699c..b465db5c80 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -97,6 +97,13 @@ void Button::_notification(int p_what) {
} break;
}
+
+ if (has_focus()) {
+
+ Ref<StyleBox> style = get_stylebox("focus");
+ style->draw(ci,Rect2(Point2(),size));
+ }
+
Ref<StyleBox> style = get_stylebox("normal" );
Ref<Font> font=get_font("font");
Ref<Texture> _icon;
@@ -134,11 +141,7 @@ void Button::_notification(int p_what) {
_icon->draw(ci,Point2(style->get_offset().x, Math::floor( (size.height-_icon->get_height())/2.0 ) ),is_disabled()?Color(1,1,1,0.4):Color(1,1,1) );
}
- if (has_focus()) {
- Ref<StyleBox> style = get_stylebox("focus");
- style->draw(ci,Rect2(Point2(),size));
- }
}
}
diff --git a/scene/gui/color_ramp_edit.cpp b/scene/gui/color_ramp_edit.cpp
new file mode 100644
index 0000000000..382c0dc103
--- /dev/null
+++ b/scene/gui/color_ramp_edit.cpp
@@ -0,0 +1,368 @@
+#include "color_ramp_edit.h"
+#include "os/keyboard.h"
+
+ColorRampEdit::ColorRampEdit(){
+ grabbed=-1;
+ grabbing=false;
+ set_focus_mode(FOCUS_ALL);
+
+ popup = memnew( PopupPanel );
+ picker = memnew( ColorPicker );
+ popup->add_child(picker);
+ popup->set_child_rect(picker);
+ add_child(popup);
+
+ checker = Ref<ImageTexture>(memnew( ImageTexture ));
+ checker->create_from_image( Image(checker_bg_png),ImageTexture::FLAG_REPEAT );
+}
+
+int ColorRampEdit::_get_point_from_pos(int x) {
+ int result = -1;
+ int total_w = get_size().width-get_size().height-3;
+ for(int i=0;i<points.size();i++) {
+ //Check if we clicked at point
+ if (ABS(x-points[i].offset*total_w+1)<(POINT_WIDTH/2+1)) {
+ result=i;
+ }
+ }
+ return result;
+}
+
+void ColorRampEdit::_show_color_picker() {
+ if (grabbed==-1)
+ return;
+ Size2 ms = Size2(350, picker->get_combined_minimum_size().height+10);
+ picker->set_color(points[grabbed].color);
+ popup->set_pos(get_global_pos()-Vector2(ms.width-get_size().width,ms.height));
+ popup->set_size(ms);
+ popup->popup();
+}
+
+ColorRampEdit::~ColorRampEdit() {
+
+}
+
+void ColorRampEdit::_input_event(const InputEvent& p_event) {
+
+ if (p_event.type==InputEvent::KEY && p_event.key.pressed && p_event.key.scancode==KEY_DELETE && grabbed!=-1) {
+
+ points.remove(grabbed);
+ grabbed=-1;
+ update();
+ emit_signal("ramp_changed");
+ accept_event();
+ }
+
+ //Show color picker on double click.
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.doubleclick && p_event.mouse_button.pressed) {
+ grabbed=_get_point_from_pos(p_event.mouse_button.x);
+ _show_color_picker();
+ accept_event();
+ }
+
+ //Delete point on right click
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==2 && p_event.mouse_button.pressed) {
+ grabbed=_get_point_from_pos(p_event.mouse_button.x);
+ if(grabbed != -1)
+ {
+ points.remove(grabbed);
+ grabbed=-1;
+ update();
+ emit_signal("ramp_changed");
+ accept_event();
+ }
+ }
+
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) {
+
+ update();
+ int x = p_event.mouse_button.x;
+ int total_w = get_size().width-get_size().height-3;
+
+ //Check if color selector was clicked.
+ if (x>total_w+3) {
+ _show_color_picker();
+ return;
+ }
+
+ grabbing=true;
+
+ grabbed=_get_point_from_pos(x);
+ //grab or select
+ if (grabbed!=-1) {
+ return;
+ }
+
+ //insert
+ ColorRamp::Point newPoint;
+ newPoint.offset=CLAMP(x/float(total_w),0,1);
+
+ ColorRamp::Point prev;
+ ColorRamp::Point next;
+
+ int pos=-1;
+ for(int i=0;i<points.size();i++) {
+ if (points[i].offset<newPoint.offset)
+ pos=i;
+ }
+
+ if (pos==-1) {
+
+ prev.color=Color(0,0,0);
+ prev.offset=0;
+ if (points.size()) {
+ next=points[0];
+ } else {
+ next.color=Color(1,1,1);
+ next.offset=1.0;
+ }
+ } else {
+
+ if (pos==points.size()-1) {
+ next.color=Color(1,1,1);
+ next.offset=1.0;
+ } else {
+ next=points[pos+1];
+ }
+ prev=points[pos];
+
+ }
+
+ newPoint.color=prev.color.linear_interpolate(next.color,(newPoint.offset-prev.offset)/(next.offset-prev.offset));
+
+ points.push_back(newPoint);
+ points.sort();
+ for(int i=0;i<points.size();i++) {
+ if (points[i].offset==newPoint.offset) {
+ grabbed=i;
+ break;
+ }
+ }
+
+ emit_signal("ramp_changed");
+
+ }
+
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && !p_event.mouse_button.pressed) {
+
+ if (grabbing) {
+ grabbing=false;
+ emit_signal("ramp_changed");
+ }
+ update();
+ }
+
+ if (p_event.type==InputEvent::MOUSE_MOTION && grabbing) {
+
+ int total_w = get_size().width-get_size().height-3;
+
+ int x = p_event.mouse_motion.x;
+ float newofs = CLAMP(x/float(total_w),0,1);
+
+ bool valid=true;
+ for(int i=0;i<points.size();i++) {
+
+ if (points[i].offset==newofs && i!=grabbed) {
+ valid=false;
+ }
+ }
+
+ if (!valid)
+ return;
+
+ points[grabbed].offset=newofs;
+
+ points.sort();
+ for(int i=0;i<points.size();i++) {
+ if (points[i].offset==newofs) {
+ grabbed=i;
+ break;
+ }
+ }
+
+ emit_signal("ramp_changed");
+
+ update();
+ }
+}
+
+void ColorRampEdit::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+ picker->connect("color_changed",this,"_color_changed");
+ }
+ if (p_what==NOTIFICATION_DRAW) {
+
+ int w = get_size().x;
+ int h = get_size().y;
+
+ if (w == 0 || h == 0)
+ return; //Safety check. We have division by 'h'. And in any case there is nothing to draw with such size
+
+ int total_w = get_size().width-get_size().height-3;
+
+ //Draw checker pattern for ramp
+ _draw_checker(0,0, total_w, h);
+
+ //Draw color ramp
+ ColorRamp::Point prev;
+ prev.offset=0;
+ if(points.size() == 0)
+ prev.color=Color(0,0,0); //Draw black rectangle if we have no points
+ else
+ prev.color = points[0].color; //Extend color of first point to the beginning.
+
+ for(int i=-1;i<points.size();i++) {
+
+ ColorRamp::Point next;
+ //If there is no next point
+ if (i+1 == points.size()) {
+ if(points.size() == 0)
+ next.color=Color(0,0,0); //Draw black rectangle if we have no points
+ else
+ next.color=points[i].color; //Extend color of last point to the end.
+ next.offset=1;
+ } else {
+ next=points[i+1];
+ }
+
+ if (prev.offset==next.offset) {
+ prev=next;
+ continue;
+ }
+
+ Vector<Vector2> points;
+ Vector<Color> colors;
+ points.push_back(Vector2(prev.offset*total_w,h));
+ points.push_back(Vector2(prev.offset*total_w,0));
+ points.push_back(Vector2(next.offset*total_w,0));
+ points.push_back(Vector2(next.offset*total_w,h));
+ colors.push_back(prev.color);
+ colors.push_back(prev.color);
+ colors.push_back(next.color);
+ colors.push_back(next.color);
+ draw_primitive(points,colors,Vector<Point2>());
+ prev=next;
+ }
+
+ //Draw point markers
+ for(int i=0;i<points.size();i++) {
+
+ Color col = i==grabbed?Color(1,0.0,0.0,0.9):points[i].color.contrasted();
+ col.a = 0.9;
+
+ draw_line(Vector2(points[i].offset*total_w,0),Vector2(points[i].offset*total_w,h/2),col);
+ draw_rect(Rect2(points[i].offset*total_w-POINT_WIDTH/2, h/2, POINT_WIDTH, h/2), Color(0.6, 0.6, 0.6, i==grabbed?0.9:0.4));
+ draw_line(Vector2(points[i].offset*total_w-POINT_WIDTH/2,h/2),Vector2(points[i].offset*total_w-POINT_WIDTH/2,h-1),col);
+ draw_line(Vector2(points[i].offset*total_w+POINT_WIDTH/2,h/2),Vector2(points[i].offset*total_w+POINT_WIDTH/2,h-1),col);
+ draw_line(Vector2(points[i].offset*total_w-POINT_WIDTH/2,h/2),Vector2(points[i].offset*total_w+POINT_WIDTH/2,h/2),col);
+ draw_line(Vector2(points[i].offset*total_w-POINT_WIDTH/2,h-1),Vector2(points[i].offset*total_w+POINT_WIDTH/2,h-1),col);
+
+ }
+
+
+ //Draw "button" for color selector
+ _draw_checker(total_w+3,0, h, h);
+ if (grabbed!=-1) {
+ //Draw with selection color
+ draw_rect(Rect2(total_w+3,0,h,h),points[grabbed].color);
+ } else {
+ //if no color selected draw grey color with 'X' on top.
+ draw_rect(Rect2(total_w+3,0,h,h), Color(0.5, 0.5, 0.5, 1));
+ draw_line(Vector2(total_w+3,0),Vector2(total_w+3+h,h),Color(1,1,1,0.6));
+ draw_line(Vector2(total_w+3,h),Vector2(total_w+3+h,0),Color(1,1,1,0.6));
+ }
+
+ //Draw borders around color ramp if in focus
+ if (has_focus()) {
+
+ draw_line(Vector2(-1,-1),Vector2(total_w+1,-1),Color(1,1,1,0.6));
+ draw_line(Vector2(total_w+1,-1),Vector2(total_w+1,h+1),Color(1,1,1,0.6));
+ draw_line(Vector2(total_w+1,h+1),Vector2(-1,h+1),Color(1,1,1,0.6));
+ draw_line(Vector2(-1,-1),Vector2(-1,h+1),Color(1,1,1,0.6));
+ }
+
+ }
+}
+
+void ColorRampEdit::_draw_checker(int x, int y, int w, int h) {
+ //Draw it with polygon to insert UVs for scale
+ Vector<Vector2> backPoints;
+ backPoints.push_back(Vector2(x, y));
+ backPoints.push_back(Vector2(x, y+h));
+ backPoints.push_back(Vector2(x+w, y+h));
+ backPoints.push_back(Vector2(x+w, y));
+ Vector<Color> colorPoints;
+ colorPoints.push_back(Color(1, 1, 1, 1));
+ colorPoints.push_back(Color(1, 1, 1, 1));
+ colorPoints.push_back(Color(1, 1, 1, 1));
+ colorPoints.push_back(Color(1, 1, 1, 1));
+ Vector<Vector2> uvPoints;
+ //Draw checker pattern pixel-perfect and scale it by 2.
+ uvPoints.push_back(Vector2(x, y));
+ uvPoints.push_back(Vector2(x, y+h*.5f/checker->get_height()));
+ uvPoints.push_back(Vector2(x+w*.5f/checker->get_width(), y+h*.5f/checker->get_height()));
+ uvPoints.push_back(Vector2(x+w*.5f/checker->get_width(), y));
+ draw_polygon(backPoints, colorPoints, uvPoints, checker);
+}
+
+Size2 ColorRampEdit::get_minimum_size() const {
+
+ return Vector2(0,16);
+}
+
+void ColorRampEdit::_color_changed(const Color& p_color) {
+
+ if (grabbed==-1)
+ return;
+ points[grabbed].color=p_color;
+ update();
+ emit_signal("ramp_changed");
+
+}
+
+void ColorRampEdit::set_ramp(const Vector<float>& p_offsets,const Vector<Color>& p_colors) {
+
+ ERR_FAIL_COND(p_offsets.size()!=p_colors.size());
+ points.clear();
+ for(int i=0;i<p_offsets.size();i++) {
+ ColorRamp::Point p;
+ p.offset=p_offsets[i];
+ p.color=p_colors[i];
+ points.push_back(p);
+ }
+
+ points.sort();
+ update();
+}
+
+Vector<float> ColorRampEdit::get_offsets() const {
+ Vector<float> ret;
+ for(int i=0;i<points.size();i++)
+ ret.push_back(points[i].offset);
+ return ret;
+}
+
+Vector<Color> ColorRampEdit::get_colors() const {
+ Vector<Color> ret;
+ for(int i=0;i<points.size();i++)
+ ret.push_back(points[i].color);
+ return ret;
+}
+
+void ColorRampEdit::set_points(Vector<ColorRamp::Point>& p_points) {
+ if(points.size() != p_points.size())
+ grabbed = -1;
+ points.clear();
+ points = p_points;
+}
+
+Vector<ColorRamp::Point>& ColorRampEdit::get_points() {
+ return points;
+}
+
+void ColorRampEdit::_bind_methods() {
+ ObjectTypeDB::bind_method(_MD("_input_event"),&ColorRampEdit::_input_event);
+ ObjectTypeDB::bind_method(_MD("_color_changed"),&ColorRampEdit::_color_changed);
+ ADD_SIGNAL(MethodInfo("ramp_changed"));
+}
diff --git a/scene/gui/color_ramp_edit.h b/scene/gui/color_ramp_edit.h
new file mode 100644
index 0000000000..91292eed0d
--- /dev/null
+++ b/scene/gui/color_ramp_edit.h
@@ -0,0 +1,52 @@
+#ifndef SCENE_GUI_COLOR_RAMP_EDIT_H_
+#define SCENE_GUI_COLOR_RAMP_EDIT_H_
+
+#include "scene/gui/popup.h"
+#include "scene/gui/color_picker.h"
+#include "scene/resources/color_ramp.h"
+#include "scene/resources/default_theme/theme_data.h"
+
+#define POINT_WIDTH 8
+
+class ColorRampEdit : public Control {
+
+ OBJ_TYPE(ColorRampEdit,Control);
+
+ PopupPanel *popup;
+ ColorPicker *picker;
+
+ Ref<ImageTexture> checker;
+
+ bool grabbing;
+ int grabbed;
+ Vector<ColorRamp::Point> points;
+
+ void _draw_checker(int x, int y, int w, int h);
+ void _color_changed(const Color& p_color);
+ int _get_point_from_pos(int x);
+ void _show_color_picker();
+
+protected:
+ void _input_event(const InputEvent& p_event);
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_ramp(const Vector<float>& p_offsets,const Vector<Color>& p_colors);
+ Vector<float> get_offsets() const;
+ Vector<Color> get_colors() const;
+ void set_points(Vector<ColorRamp::Point>& p_points);
+ Vector<ColorRamp::Point>& get_points();
+ virtual Size2 get_minimum_size() const;
+
+ ColorRampEdit();
+ virtual ~ColorRampEdit();
+};
+
+/*class ColorRampEditPanel : public Panel
+{
+ OBJ_TYPE(ColorRampEditPanel, Panel );
+};*/
+
+
+#endif /* SCENE_GUI_COLOR_RAMP_EDIT_H_ */
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 22559c238c..2367c03e99 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -548,15 +548,18 @@ void Control::_notification(int p_notification) {
Control * parent = get_parent()->cast_to<Control>();
//make children reference them theme
- if (parent && data.theme.is_null() && parent->data.theme_owner)
+
+ if (parent && data.theme.is_null() && parent->data.theme_owner) {
_propagate_theme_changed(parent->data.theme_owner);
+ }
} break;
case NOTIFICATION_UNPARENTED: {
//make children unreference the theme
- if (data.theme.is_null() && data.theme_owner)
+ if (data.theme.is_null() && data.theme_owner) {
_propagate_theme_changed(NULL);
+ }
} break;
case NOTIFICATION_MOVED_IN_PARENT: {
diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp
index 214d874675..105f66f368 100644
--- a/scene/gui/grid_container.cpp
+++ b/scene/gui/grid_container.cpp
@@ -40,7 +40,8 @@ void GridContainer::_notification(int p_what) {
Set<int> col_expanded;
Set<int> row_expanded;
- int sep=get_constant("separation");
+ int hsep=get_constant("hseparation");
+ int vsep=get_constant("vseparation");
int idx=0;
int max_row=0;
@@ -97,8 +98,8 @@ void GridContainer::_notification(int p_what) {
expand_rows++;
}
- ms.height+=sep*max_row;
- ms.width+=sep*max_col;
+ ms.height+=vsep*max_row;
+ ms.width+=hsep*max_col;
int row_expand = expand_rows?(size.y-ms.y)/expand_rows:0;
int col_expand = expand_cols?(size.x-ms.x)/expand_cols:0;
@@ -119,7 +120,7 @@ void GridContainer::_notification(int p_what) {
if (col==0) {
col_ofs=0;
if (row>0 && row_minh.has(row-1))
- row_ofs+=row_minh[row-1]+sep+(row_expanded.has(row-1)?row_expand:0);
+ row_ofs+=row_minh[row-1]+vsep+(row_expanded.has(row-1)?row_expand:0);
}
Size2 s;
@@ -140,7 +141,7 @@ void GridContainer::_notification(int p_what) {
//print_line("col: "+itos(col)+" row: "+itos(row)+" rect: "+Rect2(p,s));
if (col_minw.has(col)) {
- col_ofs+=col_minw[col]+sep+(col_expanded.has(col)?col_expand:0);
+ col_ofs+=col_minw[col]+hsep+(col_expanded.has(col)?col_expand:0);
}
idx++;
@@ -178,7 +179,8 @@ Size2 GridContainer::get_minimum_size() const {
Map<int,int> col_minw;
Map<int,int> row_minh;
- int sep=get_constant("separation");
+ int hsep=get_constant("hseparation");
+ int vsep=get_constant("vseparation");
int idx=0;
int max_row=0;
@@ -216,8 +218,8 @@ Size2 GridContainer::get_minimum_size() const {
ms.height+=E->get();
}
- ms.height+=sep*max_row;
- ms.width+=sep*max_col;
+ ms.height+=vsep*max_row;
+ ms.width+=hsep*max_col;
return ms;
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
new file mode 100644
index 0000000000..2fd4d810de
--- /dev/null
+++ b/scene/gui/item_list.cpp
@@ -0,0 +1,1048 @@
+#include "item_list.h"
+#include "os/os.h"
+#include "globals.h"
+
+
+void ItemList::add_item(const String& p_item,const Ref<Texture>& p_texture,bool p_selectable) {
+
+ Item item;
+ item.icon=p_texture;
+ item.text=p_item;
+ item.selectable=p_selectable;
+ item.selected=false;
+ item.disabled=false;
+ items.push_back(item);
+
+ update();
+ shape_changed=true;
+
+}
+
+void ItemList::add_icon_item(const Ref<Texture>& p_item,bool p_selectable){
+
+ Item item;
+ item.icon=p_item;
+ //item.text=p_item;
+ item.selectable=p_selectable;
+ item.selected=false;
+ item.disabled=false;
+ items.push_back(item);
+
+ update();
+ shape_changed=true;
+
+}
+
+void ItemList::set_item_text(int p_idx,const String& p_text){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].text=p_text;
+ update();
+ shape_changed=true;
+
+}
+
+String ItemList::get_item_text(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),String());
+ return items[p_idx].text;
+
+}
+
+void ItemList::set_item_tooltip(int p_idx,const String& p_tooltip){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].tooltip=p_tooltip;
+ update();
+ shape_changed=true;
+
+}
+
+String ItemList::get_item_tooltip(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),String());
+ return items[p_idx].tooltip;
+
+}
+
+void ItemList::set_item_icon(int p_idx,const Ref<Texture>& p_icon){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].icon=p_icon;
+ update();
+ shape_changed=true;
+
+
+}
+Ref<Texture> ItemList::get_item_icon(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),Ref<Texture>());
+
+ return items[p_idx].icon;
+
+}
+
+
+void ItemList::set_item_tag_icon(int p_idx,const Ref<Texture>& p_tag_icon){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].tag_icon=p_tag_icon;
+ update();
+ shape_changed=true;
+
+
+}
+Ref<Texture> ItemList::get_item_tag_icon(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),Ref<Texture>());
+
+ return items[p_idx].tag_icon;
+
+}
+
+void ItemList::set_item_selectable(int p_idx,bool p_selectable){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].selectable=p_selectable;
+
+
+}
+
+
+bool ItemList::is_item_selectable(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),false);
+ return items[p_idx].selectable;
+}
+
+void ItemList::set_item_disabled(int p_idx,bool p_disabled){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].disabled=p_disabled;
+
+
+}
+
+
+bool ItemList::is_item_disabled(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),false);
+ return items[p_idx].disabled;
+}
+
+
+void ItemList::set_item_metadata(int p_idx,const Variant& p_metadata){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items[p_idx].metadata=p_metadata;
+ update();
+ shape_changed=true;
+
+}
+
+Variant ItemList::get_item_metadata(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),Variant());
+ return items[p_idx].metadata;
+
+}
+void ItemList::select(int p_idx,bool p_single){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ if (p_single || select_mode==SELECT_SINGLE) {
+
+ if (!items[p_idx].selectable) {
+ return;
+ }
+
+ for(int i=0;i<items.size();i++) {
+ items[i].selected=p_idx==i;
+ }
+
+ current=p_idx;
+ } else {
+
+ if (items[p_idx].selectable) {
+ items[p_idx].selected=true;
+ }
+ }
+ update();
+
+}
+void ItemList::unselect(int p_idx){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ if (select_mode!=SELECT_MULTI) {
+ items[p_idx].selected=false;
+ current=-1;
+ } else {
+ items[p_idx].selected=false;
+ }
+ update();
+
+}
+bool ItemList::is_selected(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,items.size(),false);
+
+ return items[p_idx].selected;
+
+}
+
+void ItemList::set_current(int p_current) {
+ ERR_FAIL_INDEX(p_current,items.size());
+
+ if (select_mode==SELECT_SINGLE)
+ select(p_current,true);
+ else {
+ current=p_current;
+ update();
+ }
+}
+
+int ItemList::get_current() const {
+
+ return current;
+}
+
+
+int ItemList::get_item_count() const{
+
+ return items.size();
+}
+void ItemList::remove_item(int p_idx){
+
+ ERR_FAIL_INDEX(p_idx,items.size());
+
+ items.remove(p_idx);
+ update();
+ shape_changed=true;
+
+}
+
+void ItemList::clear(){
+
+ items.clear();
+ current=-1;
+ update();
+
+}
+
+void ItemList::set_fixed_column_width(int p_size){
+
+ ERR_FAIL_COND(p_size<0);
+ fixed_column_width=p_size;
+ update();
+ shape_changed=true;
+
+}
+int ItemList::get_fixed_column_width() const{
+
+ return fixed_column_width;
+}
+
+void ItemList::set_max_text_lines(int p_lines){
+
+ ERR_FAIL_COND(p_lines<1);
+ max_text_lines=p_lines;
+ update();
+ shape_changed=true;
+
+}
+int ItemList::get_max_text_lines() const{
+
+ return max_text_lines;
+}
+
+void ItemList::set_max_columns(int p_amount){
+
+ ERR_FAIL_COND(p_amount<0);
+ max_columns=p_amount;
+ update();
+}
+int ItemList::get_max_columns() const{
+
+ return max_columns;
+}
+
+void ItemList::set_select_mode(SelectMode p_mode) {
+
+ select_mode=p_mode;
+ update();
+}
+
+ItemList::SelectMode ItemList::get_select_mode() const {
+
+ return select_mode;
+}
+
+void ItemList::set_icon_mode(IconMode p_mode){
+
+ icon_mode=p_mode;
+ update();
+ shape_changed=true;
+
+}
+ItemList::IconMode ItemList::get_icon_mode() const{
+
+ return icon_mode;
+}
+
+void ItemList::set_min_icon_size(const Size2& p_size) {
+
+ min_icon_size=p_size;
+ update();
+}
+
+Size2 ItemList::get_min_icon_size() const {
+
+ return min_icon_size;
+}
+
+
+
+void ItemList::_input_event(const InputEvent& p_event) {
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==BUTTON_LEFT && p_event.mouse_button.pressed) {
+
+ const InputEventMouseButton &mb = p_event.mouse_button;
+
+ search_string=""; //any mousepress cancels
+ Vector2 pos(mb.x,mb.y);
+ Ref<StyleBox> bg = get_stylebox("bg");
+ pos-=bg->get_offset();
+ pos.y+=scroll_bar->get_val();
+
+ int closest = -1;
+ int closest_dist=0x7FFFFFFF;
+
+ for(int i=0;i<items.size();i++) {
+
+ Rect2 rc = items[i].rect_cache;
+ if (i%current_columns==current_columns-1) {
+ rc.size.width=get_size().width; //not right but works
+ }
+
+ if (rc.has_point(pos)) {
+ closest=i;
+ break;
+ }
+
+ float dist = rc.distance_to(pos);
+ if (dist<closest_dist) {
+ closest=i;
+ closest_dist=dist;
+ }
+ }
+
+ if (closest!=-1) {
+
+ int i = closest;
+
+ if (select_mode==SELECT_MULTI && items[i].selected && mb.mod.command) {
+ unselect(i);
+ emit_signal("multi_selected",i,false);
+ } else if (select_mode==SELECT_MULTI && mb.mod.shift && current>=0 && current<items.size() && current!=i) {
+
+ int from = current;
+ int to = i;
+ if (i<current) {
+ SWAP(from,to);
+ }
+ for(int j=from;j<=to;j++) {
+ bool selected = !items[j].selected;
+ select(j,false);
+ if (selected)
+ emit_signal("multi_selected",i,true);
+ }
+ } else {
+ bool selected = !items[i].selected;
+ select(i,select_mode==SELECT_SINGLE || !mb.mod.command);
+ if (selected) {
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",i);
+ } else
+ emit_signal("multi_selected",i,true);
+ }
+
+ if (/*select_mode==SELECT_SINGLE &&*/ mb.doubleclick) {
+
+ emit_signal("item_activated",i);
+
+ }
+
+
+ }
+
+
+ return;
+ }
+ }
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==BUTTON_WHEEL_UP && p_event.mouse_button.pressed) {
+
+ scroll_bar->set_val( scroll_bar->get_val()-scroll_bar->get_page()/8 );
+
+ }
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==BUTTON_WHEEL_DOWN && p_event.mouse_button.pressed) {
+
+ scroll_bar->set_val( scroll_bar->get_val()+scroll_bar->get_page()/8 );
+
+ }
+
+ if (p_event.is_pressed() && items.size()>0) {
+ if (p_event.is_action("ui_up")) {
+
+ if (search_string!="") {
+
+ uint64_t now = OS::get_singleton()->get_ticks_msec();
+ uint64_t diff = now-search_time_msec;
+
+ if (diff<int(Globals::get_singleton()->get("gui/incr_search_max_interval_msec"))*2) {
+
+ for(int i=current-1;i>=0;i--) {
+
+ if (items[i].text.begins_with(search_string)) {
+
+ set_current(i);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+
+
+ break;
+ }
+ }
+ accept_event();
+ return;
+ }
+ }
+
+ if (current>=current_columns) {
+ set_current(current-current_columns);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ accept_event();
+ }
+ } else if (p_event.is_action("ui_down")) {
+
+ if (search_string!="") {
+
+ uint64_t now = OS::get_singleton()->get_ticks_msec();
+ uint64_t diff = now-search_time_msec;
+
+ if (diff<int(Globals::get_singleton()->get("gui/incr_search_max_interval_msec"))*2) {
+
+ for(int i=current+1;i<items.size();i++) {
+
+ if (items[i].text.begins_with(search_string)) {
+
+ set_current(i);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ break;
+ }
+ }
+ accept_event();
+ return;
+ }
+ }
+
+ if (current<items.size()-current_columns) {
+ set_current(current+current_columns);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ accept_event();
+
+ }
+ } else if (p_event.is_action("ui_page_up")) {
+
+ search_string=""; //any mousepress cancels
+
+ for(int i=4;i>0;i--) {
+ if (current-current_columns*i >=0 ) {
+ set_current( current- current_columns*i);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ accept_event();
+ break;
+ }
+ }
+ } else if (p_event.is_action("ui_page_down")) {
+
+ search_string=""; //any mousepress cancels
+
+ for(int i=4;i>0;i--) {
+ if (current+current_columns*i < items.size() ) {
+ set_current( current+ current_columns*i);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ accept_event();
+
+ break;
+ }
+ }
+ } else if (p_event.is_action("ui_left")) {
+
+ search_string=""; //any mousepress cancels
+
+ if (current%current_columns!=0) {
+ set_current(current-1);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ accept_event();
+
+ }
+ } else if (p_event.is_action("ui_right")) {
+
+ search_string=""; //any mousepress cancels
+
+ if (current%current_columns!=(current_columns-1)) {
+ set_current(current+1);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ accept_event();
+
+ }
+ } else if (p_event.is_action("ui_cancel")) {
+ search_string="";
+ } else if (p_event.is_action("ui_select")) {
+
+
+ if (select_mode==SELECT_MULTI && current>=0 && current<items.size()) {
+ if (items[current].selectable && !items[current].selected) {
+ select(current,false);
+ emit_signal("multi_selected",current,true);
+ } else if (items[current].selected) {
+ unselect(current);
+ emit_signal("multi_selected",current,false);
+ }
+ }
+ } else if (p_event.is_action("ui_accept")) {
+ search_string=""; //any mousepress cance
+
+ if (current>=0 && current<items.size()) {
+ emit_signal("item_activated",current);
+ }
+ } else if (p_event.type==InputEvent::KEY) {
+
+ if (p_event.key.unicode) {
+
+ uint64_t now = OS::get_singleton()->get_ticks_msec();
+ uint64_t diff = now-search_time_msec;
+ uint64_t max_interval = uint64_t(GLOBAL_DEF("gui/incr_search_max_interval_msec",2000));
+ search_time_msec = now;
+
+ if (diff>max_interval) {
+ search_string="";
+ }
+
+ search_string+=String::chr(p_event.key.unicode);
+ for(int i=0;i<items.size();i++) {
+ if (items[i].text.begins_with(search_string)) {
+ set_current(i);
+ ensure_current_is_visible();
+ if (select_mode==SELECT_SINGLE) {
+ emit_signal("item_selected",current);
+ }
+ break;
+ }
+ }
+
+ }
+
+ }
+ }
+
+
+
+
+}
+
+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));
+ }
+ }
+}
+
+void ItemList::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_RESIZED) {
+ shape_changed=true;
+ update();
+ }
+
+ if (p_what==NOTIFICATION_DRAW) {
+
+ VS::get_singleton()->canvas_item_set_clip(get_canvas_item(),true);
+ Ref<StyleBox> bg = get_stylebox("bg");
+
+ int mw = scroll_bar->get_minimum_size().x;
+ scroll_bar->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_END,mw+bg->get_margin(MARGIN_RIGHT));
+ scroll_bar->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,bg->get_margin(MARGIN_RIGHT));
+ scroll_bar->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN,bg->get_margin(MARGIN_TOP));
+ scroll_bar->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,bg->get_margin(MARGIN_BOTTOM));
+
+
+ Size2 size = get_size();
+
+ float page = size.height-bg->get_minimum_size().height;
+ int width = size.width - mw - bg->get_minimum_size().width;
+ scroll_bar->set_page(page);
+
+ draw_style_box(bg,Rect2(Point2(),size));
+
+ int hseparation = get_constant("hseparation");
+ int vseparation = get_constant("vseparation");
+ int icon_margin = get_constant("icon_margin");
+ int line_separation = get_constant("line_separation");
+
+ Ref<StyleBox> sbsel = has_focus()?get_stylebox("selected_focus"):get_stylebox("selected");
+ Ref<StyleBox> cursor = has_focus()?get_stylebox("cursor"):get_stylebox("cursor_unfocused");
+
+ Ref<Font> font = get_font("font");
+ Color guide_color = get_color("guide_color");
+ Color font_color = get_color("font_color");
+ int font_height = font->get_height();
+ Vector<int> line_size_cache;
+ Vector<int> line_limit_cache;
+
+ if (max_text_lines) {
+ line_size_cache.resize(max_text_lines);
+ line_limit_cache.resize(max_text_lines);
+ }
+
+ if (has_focus()) {
+ VisualServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(),true);
+ draw_style_box(get_stylebox("bg_focus"),Rect2(Point2(),size));
+ VisualServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(),false);
+ }
+
+ if (shape_changed) {
+
+ //1- compute item minimum sizes
+ for(int i=0;i<items.size();i++) {
+
+ Size2 minsize;
+ if (items[i].icon.is_valid()) {
+ minsize=items[i].icon->get_size();
+ if (min_icon_size.x!=0)
+ minsize.x = MAX(minsize.x,min_icon_size.x);
+ if (min_icon_size.y!=0)
+ minsize.y = MAX(minsize.y,min_icon_size.y);
+
+ if (items[i].text!="") {
+ if (icon_mode==ICON_MODE_TOP) {
+ minsize.y+=icon_margin;
+ } else {
+ minsize.x+=icon_margin;
+ }
+ }
+ }
+
+ if (items[i].text!="") {
+
+ Size2 s = font->get_string_size(items[i].text);
+ //s.width=MIN(s.width,fixed_column_width);
+
+
+
+ if (icon_mode==ICON_MODE_TOP) {
+ minsize.x=MAX(minsize.x,s.width);
+ if (max_text_lines>0) {
+ minsize.y+=(font_height+line_separation)*max_text_lines;
+ } else {
+ minsize.y+=s.height;
+ }
+
+ } else {
+ minsize.y=MAX(minsize.y,s.height);
+ minsize.x+=s.width;
+ }
+ }
+
+
+
+ items[i].rect_cache.size=minsize;
+ if (fixed_column_width>0)
+ items[i].rect_cache.size.x=fixed_column_width;
+
+ }
+
+ int fit_size = size.x - bg->get_minimum_size().width - mw;
+
+ //2-attempt best fit
+ current_columns = 0x7FFFFFFF;
+ if (max_columns>0)
+ current_columns=max_columns;
+
+
+ while(true) {
+ //repeat util all fits
+ //print_line("try with "+itos(current_columns));
+ bool all_fit=true;
+ Vector2 ofs;
+ int col=0;
+ int max_h=0;
+ separators.clear();;
+ for(int i=0;i<items.size();i++) {
+
+ if (current_columns>1 && items[i].rect_cache.size.width+ofs.x > fit_size) {
+ //went past
+ current_columns=MAX(col,1);
+ all_fit=false;
+ break;
+ }
+
+ items[i].rect_cache.pos=ofs;
+ max_h=MAX(max_h,items[i].rect_cache.size.y);
+ ofs.x+=items[i].rect_cache.size.x;
+ //print_line("item "+itos(i)+" ofs "+rtos(items[i].rect_cache.size.x));
+ if (col>0)
+ ofs.x+=hseparation;
+ col++;
+ if (col==current_columns) {
+
+ if (i<items.size()-1)
+ separators.push_back(ofs.y+max_h+vseparation/2);
+ ofs.x=0;
+ ofs.y+=max_h+vseparation;
+ col=0;
+ max_h=0;
+ }
+ }
+
+ if (all_fit) {
+ float max = MAX(page,ofs.y+max_h);
+ scroll_bar->set_max(max);
+ //print_line("max: "+rtos(max)+" page "+rtos(page));
+ if (max<=page) {
+ scroll_bar->set_val(0);
+ scroll_bar->hide();
+ } else {
+ scroll_bar->show();
+ }
+ break;
+ }
+ }
+
+
+ shape_changed=false;
+ }
+
+
+
+ Vector2 base_ofs = bg->get_offset();
+ base_ofs.y-=int(scroll_bar->get_val());
+
+ Rect2 clip(Point2(),size-bg->get_minimum_size()+Vector2(0,scroll_bar->get_val()));
+
+ for(int i=0;i<items.size();i++) {
+
+
+ Rect2 rcache = items[i].rect_cache;
+
+ if (!clip.intersects(rcache))
+ continue;
+
+
+ if (current_columns==1) {
+ rcache.size.width = width-rcache.pos.x;
+ }
+ if (items[i].selected) {
+ Rect2 r=rcache;
+ r.pos+=base_ofs;
+
+ r.pos.x-=sbsel->get_margin(MARGIN_LEFT);
+ r.size.x+=sbsel->get_margin(MARGIN_LEFT)+sbsel->get_margin(MARGIN_RIGHT);
+ r.pos.y-=sbsel->get_margin(MARGIN_TOP);
+ r.size.y+=sbsel->get_margin(MARGIN_TOP)+sbsel->get_margin(MARGIN_BOTTOM);
+
+ draw_style_box(sbsel,r);
+
+ }
+
+
+ Vector2 text_ofs;
+ if (items[i].icon.is_valid()) {
+
+ Vector2 icon_ofs;
+ if (min_icon_size!=Vector2()) {
+ icon_ofs = (min_icon_size - items[i].icon->get_size())/2;
+ }
+
+ if (icon_mode==ICON_MODE_TOP) {
+ draw_texture(items[i].icon,icon_ofs+items[i].rect_cache.pos+Vector2(items[i].rect_cache.size.width/2-items[i].icon->get_width()/2,0).floor()+base_ofs);
+ text_ofs.y = MAX(items[i].icon->get_height(),min_icon_size.y)+icon_margin;
+ } else {
+ draw_texture(items[i].icon,icon_ofs+items[i].rect_cache.pos+Vector2(0,items[i].rect_cache.size.height/2-items[i].icon->get_height()/2).floor()+base_ofs);
+ text_ofs.x = MAX(items[i].icon->get_width(),min_icon_size.x)+icon_margin;
+ }
+ }
+
+ if (items[i].tag_icon.is_valid()) {
+
+ draw_texture(items[i].tag_icon,items[i].rect_cache.pos+base_ofs);
+ }
+
+ if (items[i].text!="") {
+
+ int max_len=-1;
+
+ Vector2 size = font->get_string_size(items[i].text);
+ if (fixed_column_width)
+ max_len=fixed_column_width;
+ else
+ max_len=size.x;
+
+ if (icon_mode==ICON_MODE_TOP && max_text_lines>0) {
+
+ int ss = items[i].text.length();
+ float ofs=0;
+ int line=0;
+ for(int j=0;j<=ss;j++) {
+
+ int cs = j<ss?font->get_char_size(items[i].text[j],items[i].text[j+1]).x:0;
+ if (ofs+cs>max_len || j==ss) {
+ line_limit_cache[line]=j;
+ line_size_cache[line]=ofs;
+ line++;
+ ofs=0;
+ if (line>=max_text_lines)
+ break;
+ } else {
+ ofs+=cs;
+ }
+
+ }
+
+ line=0;
+ ofs=0;
+
+ text_ofs.y+=font->get_ascent();
+ text_ofs=text_ofs.floor();
+ text_ofs+=base_ofs;
+ text_ofs+=items[i].rect_cache.pos;
+
+ for(int j=0;j<ss;j++) {
+
+ if (j==line_limit_cache[line]) {
+ line++;
+ ofs=0;
+ if (line>=max_text_lines)
+ break;
+ }
+ ofs+=font->draw_char(get_canvas_item(),text_ofs+Vector2(ofs+(max_len-line_size_cache[line])/2,line*(font_height+line_separation)).floor(),items[i].text[j],items[i].text[j+1],font_color);
+ }
+
+ //special multiline mode
+ } else {
+
+ if (fixed_column_width>0)
+ size.x=MIN(size.x,fixed_column_width);
+
+ if (icon_mode==ICON_MODE_TOP) {
+ text_ofs.x+=(items[i].rect_cache.size.width-size.x)/2;
+ } else {
+ text_ofs.y+=(items[i].rect_cache.size.height-size.y)/2;
+ }
+
+ text_ofs.y+=font->get_ascent();
+ text_ofs=text_ofs.floor();
+ text_ofs+=base_ofs;
+ text_ofs+=items[i].rect_cache.pos;
+
+ draw_string(font,text_ofs,items[i].text,font_color,max_len+1);
+ }
+
+
+ }
+
+ if (select_mode==SELECT_MULTI && i==current) {
+
+ Rect2 r=rcache;
+ r.pos+=base_ofs;
+ draw_style_box(cursor,r);
+
+ }
+ }
+
+ for(int i=0;i<separators.size();i++) {
+ 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);
+ }
+
+ }
+}
+
+void ItemList::_scroll_changed(double) {
+ update();
+}
+
+
+String ItemList::get_tooltip(const Point2& p_pos) const {
+
+ Vector2 pos=p_pos;
+ Ref<StyleBox> bg = get_stylebox("bg");
+ pos-=bg->get_offset();
+ pos.y+=scroll_bar->get_val();
+
+ int closest = -1;
+ int closest_dist=0x7FFFFFFF;
+
+ for(int i=0;i<items.size();i++) {
+
+ Rect2 rc = items[i].rect_cache;
+ if (i%current_columns==current_columns-1) {
+ rc.size.width=get_size().width; //not right but works
+ }
+
+ if (rc.has_point(pos)) {
+ closest=i;
+ break;
+ }
+
+ float dist = rc.distance_to(pos);
+ if (dist<closest_dist) {
+ closest=i;
+ closest_dist=dist;
+ }
+ }
+
+ if (closest!=-1) {
+ if (items[closest].tooltip!="") {
+ return items[closest].tooltip;
+ }
+ if (items[closest].text!="") {
+ return items[closest].text;
+ }
+ }
+
+ return Control::get_tooltip(p_pos);
+
+
+}
+
+
+void ItemList::_bind_methods(){
+
+ ObjectTypeDB::bind_method(_MD("add_item","text","icon:Texture","selectable"),&ItemList::add_item,DEFVAL(Ref<Texture>()),DEFVAL(true));
+ ObjectTypeDB::bind_method(_MD("add_icon_item","icon:Texture","selectable"),&ItemList::add_icon_item,DEFVAL(true));
+
+ ObjectTypeDB::bind_method(_MD("set_item_text","idx","text"),&ItemList::set_item_text);
+ 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("set_item_selectable","idx","selectable"),&ItemList::set_item_selectable);
+ ObjectTypeDB::bind_method(_MD("is_item_selectable","idx"),&ItemList::is_item_selectable);
+
+ ObjectTypeDB::bind_method(_MD("set_item_disabled","idx","disabled"),&ItemList::set_item_disabled);
+ ObjectTypeDB::bind_method(_MD("is_item_disabled","idx"),&ItemList::is_item_disabled);
+
+ ObjectTypeDB::bind_method(_MD("set_item_tooltip","idx","tooltip"),&ItemList::set_item_tooltip);
+ ObjectTypeDB::bind_method(_MD("get_item_tooltip","idx"),&ItemList::get_item_tooltip);
+
+ ObjectTypeDB::bind_method(_MD("select","idx","single"),&ItemList::select,DEFVAL(true));
+ ObjectTypeDB::bind_method(_MD("unselect","idx"),&ItemList::unselect);
+ ObjectTypeDB::bind_method(_MD("is_selected","idx"),&ItemList::is_selected);
+
+ ObjectTypeDB::bind_method(_MD("get_item_count"),&ItemList::get_item_count);
+ ObjectTypeDB::bind_method(_MD("remove_item","idx"),&ItemList::remove_item);
+
+ ObjectTypeDB::bind_method(_MD("clear"),&ItemList::clear);
+
+ ObjectTypeDB::bind_method(_MD("set_fixed_column_width","width"),&ItemList::set_fixed_column_width);
+ ObjectTypeDB::bind_method(_MD("get_fixed_column_width"),&ItemList::get_fixed_column_width);
+
+ ObjectTypeDB::bind_method(_MD("set_max_text_lines","lines"),&ItemList::set_max_text_lines);
+ ObjectTypeDB::bind_method(_MD("get_max_text_lines"),&ItemList::get_max_text_lines);
+
+ ObjectTypeDB::bind_method(_MD("set_max_columns","amount"),&ItemList::set_max_columns);
+ ObjectTypeDB::bind_method(_MD("get_max_columns"),&ItemList::get_max_columns);
+
+ ObjectTypeDB::bind_method(_MD("set_select_mode","mode"),&ItemList::set_select_mode);
+ ObjectTypeDB::bind_method(_MD("get_select_mode"),&ItemList::get_select_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_icon_mode","mode"),&ItemList::set_icon_mode);
+ ObjectTypeDB::bind_method(_MD("get_icon_mode"),&ItemList::get_icon_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_min_icon_size","size"),&ItemList::set_min_icon_size);
+ ObjectTypeDB::bind_method(_MD("get_min_icon_size"),&ItemList::get_min_icon_size);
+
+ ObjectTypeDB::bind_method(_MD("ensure_current_is_visible"),&ItemList::ensure_current_is_visible);
+
+ ObjectTypeDB::bind_method(_MD("_scroll_changed"),&ItemList::_scroll_changed);
+ ObjectTypeDB::bind_method(_MD("_input_event"),&ItemList::_input_event);
+
+ BIND_CONSTANT( ICON_MODE_TOP );
+ BIND_CONSTANT( ICON_MODE_LEFT );
+ BIND_CONSTANT( SELECT_SINGLE );
+ BIND_CONSTANT( SELECT_MULTI );
+
+ ADD_SIGNAL( MethodInfo("item_selected",PropertyInfo(Variant::INT,"index")));
+ ADD_SIGNAL( MethodInfo("multi_selected",PropertyInfo(Variant::INT,"index"),PropertyInfo(Variant::BOOL,"selected")));
+ ADD_SIGNAL( MethodInfo("item_activated",PropertyInfo(Variant::INT,"index")));
+}
+
+
+
+ItemList::ItemList() {
+
+ current=-1;
+
+ select_mode=SELECT_SINGLE;
+ icon_mode=ICON_MODE_LEFT;
+
+ fixed_column_width=0;
+ max_text_lines=1;
+ max_columns=1;
+
+ scroll_bar = memnew( VScrollBar );
+ add_child(scroll_bar);
+
+ shape_changed=true;
+ scroll_bar->connect("value_changed",this,"_scroll_changed");
+
+ set_focus_mode(FOCUS_ALL);
+ current_columns=1;
+ search_time_msec=0;
+
+}
+
+ItemList::~ItemList() {
+
+}
+
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
new file mode 100644
index 0000000000..6bbb416970
--- /dev/null
+++ b/scene/gui/item_list.h
@@ -0,0 +1,132 @@
+#ifndef ITEMLIST_H
+#define ITEMLIST_H
+
+#include "scene/gui/control.h"
+#include "scene/gui/scroll_bar.h"
+
+class ItemList : public Control {
+
+ OBJ_TYPE( ItemList, Control );
+public:
+
+ enum IconMode {
+ ICON_MODE_TOP,
+ ICON_MODE_LEFT
+ };
+
+ enum SelectMode {
+ SELECT_SINGLE,
+ SELECT_MULTI
+ };
+private:
+ struct Item {
+
+ Ref<Texture> icon;
+ Ref<Texture> tag_icon;
+ String text;
+ bool selectable;
+ bool selected;
+ bool disabled;
+ Variant metadata;
+ String tooltip;
+
+ Rect2 rect_cache;
+ };
+
+ int current;
+
+ bool shape_changed;
+
+ Vector<Item> items;
+ Vector<int> separators;
+
+ SelectMode select_mode;
+ IconMode icon_mode;
+ VScrollBar *scroll_bar;
+
+ uint64_t search_time_msec;
+ String search_string;
+
+ int current_columns;
+ int fixed_column_width;
+ int max_text_lines;
+ int max_columns;
+ Size2 min_icon_size;
+
+ void _scroll_changed(double);
+ void _input_event(const InputEvent& p_event);
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void add_item(const String& p_item,const Ref<Texture>& p_texture=Ref<Texture>(),bool p_selectable=true);
+ void add_icon_item(const Ref<Texture>& p_item,bool p_selectable=true);
+
+ void set_item_text(int p_idx,const String& p_text);
+ String get_item_text(int p_idx) const;
+
+ void set_item_icon(int p_idx,const Ref<Texture>& p_icon);
+ Ref<Texture> get_item_icon(int p_idx) const;
+
+ void set_item_selectable(int p_idx,bool p_selectable);
+ bool is_item_selectable(int p_idx) const;
+
+ void set_item_disabled(int p_idx,bool p_disabled);
+ bool is_item_disabled(int p_idx) const;
+
+ void set_item_metadata(int p_idx,const Variant& p_metadata);
+ Variant get_item_metadata(int p_idx) const;
+
+ void set_item_tag_icon(int p_idx,const Ref<Texture>& p_tag_icon);
+ Ref<Texture> get_item_tag_icon(int p_idx) const;
+
+ void set_item_tooltip(int p_idx,const String& p_tooltip);
+ String get_item_tooltip(int p_idx) const;
+
+ void select(int p_idx,bool p_single=true);
+ void unselect(int p_idx);
+ bool is_selected(int p_idx) const;
+
+ void set_current(int p_current);
+ int get_current() const;
+
+
+ int get_item_count() const;
+ void remove_item(int p_idx);
+
+ void clear();
+
+ void set_fixed_column_width(int p_size);
+ int get_fixed_column_width() const;
+
+ void set_max_text_lines(int p_amount);
+ int get_max_text_lines() const;
+
+ void set_max_columns(int p_amount);
+ int get_max_columns() const;
+
+ void set_select_mode(SelectMode p_mode);
+ SelectMode get_select_mode() const;
+
+ void set_icon_mode(IconMode p_mode);
+ IconMode get_icon_mode() const;
+
+ void set_min_icon_size(const Size2& p_size);
+ Size2 get_min_icon_size() const;
+
+ void ensure_current_is_visible();
+
+
+ virtual String get_tooltip(const Point2& p_pos) const;
+
+ ItemList();
+ ~ItemList();
+};
+
+VARIANT_ENUM_CAST(ItemList::SelectMode);
+VARIANT_ENUM_CAST(ItemList::IconMode);
+
+
+#endif // ITEMLIST_H
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index c73af74426..5ce7e2e0d3 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -84,6 +84,48 @@ void Popup::_fix_size() {
}
+void Popup::set_as_minsize() {
+
+ Size2 total_minsize;
+
+ for(int i=0;i<get_child_count();i++) {
+
+ Control *c=get_child(i)->cast_to<Control>();
+ if (!c)
+ continue;
+ if (c->is_hidden())
+ continue;
+
+ Size2 minsize = c->get_combined_minimum_size();
+
+ for(int j=0;j<2;j++) {
+
+ Margin m_beg = Margin(0+j);
+ Margin m_end = Margin(2+j);
+
+ float margin_begin = c->get_margin(m_beg);
+ float margin_end = c->get_margin(m_end);
+ AnchorType anchor_begin = c->get_anchor(m_beg);
+ AnchorType anchor_end = c->get_anchor(m_end);
+
+ if (anchor_begin == ANCHOR_BEGIN)
+ minsize[j]+=margin_begin;
+ if (anchor_end == ANCHOR_END)
+ minsize[j]+=margin_end;
+
+ }
+
+ print_line(String(c->get_type())+": "+minsize);
+
+ total_minsize.width = MAX( total_minsize.width, minsize.width );
+ total_minsize.height = MAX( total_minsize.height, minsize.height );
+ }
+
+ set_size(total_minsize);
+
+}
+
+
void Popup::popup_centered_minsize(const Size2& p_minsize) {
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index c2de6c8cf7..6c72a3c82b 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -62,6 +62,7 @@ public:
void popup_centered_ratio(float p_screen_ratio=0.75);
void popup_centered(const Size2& p_size=Size2());
void popup_centered_minsize(const Size2& p_minsize=Size2());
+ void set_as_minsize();
virtual void popup();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 987a2ed800..7a607786ee 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -58,7 +58,7 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item* p_item) {
}
-void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos,Item **r_click_item,int *r_click_char,bool *r_outside) {
+void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos,Item **r_click_item,int *r_click_char,bool *r_outside,int p_char_count) {
RID ci;
if (r_outside)
@@ -80,6 +80,7 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p
int line=0;
int spaces=0;
+
if (p_mode!=PROCESS_CACHE) {
ERR_FAIL_INDEX(line,l.offset_caches.size());
@@ -89,6 +90,7 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p
if (p_mode==PROCESS_CACHE) {
l.offset_caches.clear();
l.height_caches.clear();
+ l.char_count=0;
}
int wofs=margin;
@@ -216,6 +218,8 @@ if (m_height > line_height) {\
underline=true;
}
+ } else if (p_mode==PROCESS_CACHE) {
+ l.char_count+=text->text.length();
}
rchar=0;
@@ -326,18 +330,23 @@ if (m_height > line_height) {\
}
}
- int cw;
+ int cw=0;
+
+ bool visible = visible_characters<0 || p_char_count<visible_characters;
if (selected) {
cw = font->get_char_size(c[i],c[i+1]).x;
draw_rect(Rect2(pofs,y,cw,lh),selection_bg);
- font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],selection_fg);
+ if (visible)
+ font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],selection_fg);
} else {
- cw=font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],color);
+ if (visible)
+ cw=font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],color);
}
+ p_char_count++;
if (c[i]=='\t') {
cw=tab_size*font->get_char_size(' ').width;
}
@@ -371,6 +380,8 @@ if (m_height > line_height) {\
lh=0;
if (p_mode!=PROCESS_CACHE)
lh = line<l.height_caches.size()?l.height_caches[line]:1;
+ else
+ l.char_count+=1; //images count as chars too
ItemImage *img = static_cast<ItemImage*>(it);
@@ -383,9 +394,12 @@ if (m_height > line_height) {\
ENSURE_WIDTH( img->image->get_width() );
- if (p_mode==PROCESS_DRAW) {
+ bool visible = visible_characters<0 || p_char_count<visible_characters;
+
+ if (p_mode==PROCESS_DRAW && visible) {
img->image->draw(ci,Point2(wofs,y+lh-font->get_descent()-img->image->get_height()));
}
+ p_char_count++;
ADVANCE( img->image->get_width() );
CHECK_HEIGHT( (img->image->get_height()+font->get_descent()) );
@@ -556,11 +570,13 @@ void RichTextLabel::_notification(int p_what) {
//todo, change to binary search
int from_line = 0;
+ int total_chars = 0;
while (from_line<lines.size()) {
if (lines[from_line].height_accum_cache>=ofs)
break;
from_line++;
+ total_chars+=lines[from_line].char_count;
}
if (from_line>=lines.size())
@@ -572,7 +588,8 @@ void RichTextLabel::_notification(int p_what) {
while (y<size.height && from_line<lines.size()) {
- _process_line(y,size.width-scroll_w,from_line,PROCESS_DRAW,base_font,base_color);
+ _process_line(y,size.width-scroll_w,from_line,PROCESS_DRAW,base_font,base_color,Point2i(),NULL,NULL,NULL,total_chars);
+ total_chars+=lines[from_line].char_count;
from_line++;
}
}
@@ -1688,11 +1705,17 @@ void RichTextLabel::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_bbcode","text"),&RichTextLabel::set_bbcode);
ObjectTypeDB::bind_method(_MD("get_bbcode"),&RichTextLabel::get_bbcode);
+ ObjectTypeDB::bind_method(_MD("set_visible_characters","amount"),&RichTextLabel::set_visible_characters);
+ ObjectTypeDB::bind_method(_MD("get_visible_characters"),&RichTextLabel::get_visible_characters);
+
+ ObjectTypeDB::bind_method(_MD("get_total_character_count"),&RichTextLabel::get_total_character_count);
+
ObjectTypeDB::bind_method(_MD("set_use_bbcode","enable"),&RichTextLabel::set_use_bbcode);
ObjectTypeDB::bind_method(_MD("is_using_bbcode"),&RichTextLabel::is_using_bbcode);
ADD_PROPERTY(PropertyInfo(Variant::BOOL,"bbcode/enabled"),_SCS("set_use_bbcode"),_SCS("is_using_bbcode"));
ADD_PROPERTY(PropertyInfo(Variant::STRING,"bbcode/bbcode",PROPERTY_HINT_MULTILINE_TEXT),_SCS("set_bbcode"),_SCS("get_bbcode"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"visible_characters",PROPERTY_HINT_RANGE,"-1,128000,1"),_SCS("set_visible_characters"),_SCS("get_visible_characters"));
ADD_SIGNAL( MethodInfo("meta_clicked",PropertyInfo(Variant::NIL,"meta")));
@@ -1719,6 +1742,27 @@ void RichTextLabel::_bind_methods() {
}
+
+void RichTextLabel::set_visible_characters(int p_visible) {
+
+ visible_characters=p_visible;
+ update();
+}
+
+int RichTextLabel::get_visible_characters() const {
+
+ return visible_characters;
+}
+int RichTextLabel::get_total_character_count() const {
+
+ int tc=0;
+ for(int i=0;i<lines.size();i++)
+ tc+=lines[i].char_count;
+
+ return tc;
+}
+
+
RichTextLabel::RichTextLabel() {
@@ -1756,6 +1800,8 @@ RichTextLabel::RichTextLabel() {
selection.active=false;
selection.enabled=false;
+ visible_characters=-1;
+
}
RichTextLabel::~RichTextLabel() {
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 7172e8e500..eaa8d5d60a 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -171,8 +171,9 @@ private:
Vector<int> space_caches;
int height_cache;
int height_accum_cache;
+ int char_count;
- Line() { from=NULL; }
+ Line() { from=NULL; char_count=0; }
};
@@ -223,10 +224,10 @@ private:
Selection selection;
+ int visible_characters;
-
- void _process_line(int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos=Point2i(),Item **r_click_item=NULL,int *r_click_char=NULL,bool *r_outside=NULL);
+ void _process_line(int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos=Point2i(),Item **r_click_item=NULL,int *r_click_char=NULL,bool *r_outside=NULL,int p_char_count=0);
void _find_click(const Point2i& p_click,Item **r_click_item=NULL,int *r_click_char=NULL,bool *r_outside=NULL);
@@ -246,6 +247,8 @@ private:
bool use_bbcode;
String bbcode;
+
+
protected:
void _notification(int p_what);
@@ -304,6 +307,10 @@ public:
void set_bbcode(const String& p_bbcode);
String get_bbcode() const;
+ void set_visible_characters(int p_visible);
+ int get_visible_characters() const;
+ int get_total_character_count() const;
+
RichTextLabel();
~RichTextLabel();
};
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index d02c833be9..d7ee7a6b86 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -345,6 +345,7 @@ void SplitContainer::_input_event(const InputEvent& p_event) {
expand_ofs=drag_ofs+((vertical?mm.y:mm.x)-drag_from);
queue_sort();
+ emit_signal("dragged",get_split_offset());
}
}
@@ -431,11 +432,13 @@ void SplitContainer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_dragger_visible","visible"),&SplitContainer::set_dragger_visible);
ObjectTypeDB::bind_method(_MD("is_dragger_visible"),&SplitContainer::is_dragger_visible);
+ ADD_SIGNAL( MethodInfo("dragged",PropertyInfo(Variant::INT,"offset")));
ADD_PROPERTY( PropertyInfo(Variant::INT,"split/offset"),_SCS("set_split_offset"),_SCS("get_split_offset"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"split/collapsed"),_SCS("set_collapsed"),_SCS("is_collapsed"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"split/dragger_visible"),_SCS("set_dragger_visible"),_SCS("is_dragger_visible"));
+
}
SplitContainer::SplitContainer(bool p_vertical) {
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 1db4998a27..3ed182c017 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -88,7 +88,22 @@ void TabContainer::_input_event(const InputEvent& p_event) {
Ref<Font> font = get_font("font");
Ref<Texture> incr = get_icon("increment");
Ref<Texture> decr = get_icon("decrement");
+ Ref<Texture> menu = get_icon("menu");
+ Ref<Texture> menu_hl = get_icon("menu_hl");
+ if (popup && pos.x>get_size().width-menu->get_width()) {
+
+
+ emit_signal("pre_popup_pressed");
+ Vector2 pp_pos = get_global_pos();
+ pp_pos.x+=get_size().width;
+ pp_pos.x-=popup->get_size().width;
+ pp_pos.y+=menu->get_height();
+
+ popup->set_global_pos( pp_pos );
+ popup->popup();;
+ return;
+ }
pos.x-=tabs_ofs_cache;
int idx=0;
@@ -116,17 +131,17 @@ void TabContainer::_input_event(const InputEvent& p_event) {
String s = c->has_meta("_tab_name")?String(XL_MESSAGE(String(c->get_meta("_tab_name")))):String(c->get_name());
int tab_width=font->get_string_size(s).width;
- if (c->has_meta("_tab_icon")) {
- Ref<Texture> icon = c->get_meta("_tab_icon");
- if (icon.is_valid()) {
- tab_width+=icon->get_width();
- if (s!="")
- tab_width+=get_constant("hseparation");
+ if (c->has_meta("_tab_icon")) {
+ Ref<Texture> icon = c->get_meta("_tab_icon");
+ if (icon.is_valid()) {
+ tab_width+=icon->get_width();
+ if (s!="")
+ tab_width+=get_constant("hseparation");
- }
- }
+ }
+ }
- if (idx==current) {
+ if (idx==current) {
tab_width+=tab_fg->get_minimum_size().width;
} else {
@@ -163,7 +178,7 @@ void TabContainer::_input_event(const InputEvent& p_event) {
if (found!=-1) {
- set_current_tab(found);
+ set_current_tab(found);
}
}
@@ -194,7 +209,9 @@ void TabContainer::_notification(int p_what) {
Ref<Texture> incr = get_icon("increment");
Ref<Texture> incr_hl = get_icon("increment_hilite");
Ref<Texture> decr = get_icon("decrement");
- Ref<Texture> decr_hl = get_icon("decrement_hilite");
+ Ref<Texture> decr_hl = get_icon("decrement_hilite");
+ Ref<Texture> menu = get_icon("menu");
+ Ref<Texture> menu_hl = get_icon("menu_hl");
Ref<Font> font = get_font("font");
Color color_fg = get_color("font_color_fg");
Color color_bg = get_color("font_color_bg");
@@ -209,6 +226,7 @@ void TabContainer::_notification(int p_what) {
Size2 top_size = Size2( size.width, top_margin );
+
int w=0;
int idx=0;
for(int i=0;i<get_child_count();i++) {
@@ -227,7 +245,7 @@ void TabContainer::_notification(int p_what) {
if (icon.is_valid()) {
w+=icon->get_width();
if (s!="")
- w+=get_constant("hseparation");
+ w+=get_constant("hseparation");
}
}
@@ -245,14 +263,18 @@ void TabContainer::_notification(int p_what) {
int ofs;
int limit=get_size().width;
+ if (popup) {
+ top_size.width-=menu->get_width();
+ limit-=menu->get_width();
+ }
- if (w<=get_size().width) {
+ if (w<=limit) {
switch(align) {
case ALIGN_LEFT: ofs = side_margin; break;
- case ALIGN_CENTER: ofs = (int(top_size.width) - w)/2; break;
- case ALIGN_RIGHT: ofs = int(top_size.width) - w - side_margin; break;
+ case ALIGN_CENTER: ofs = (int(limit) - w)/2; break;
+ case ALIGN_RIGHT: ofs = int(limit) - w - side_margin; break;
};
tab_display_ofs=0;
@@ -364,6 +386,15 @@ void TabContainer::_notification(int p_what) {
incr->draw(ci,Point2(limit+incr->get_width(),vofs),Color(1,1,1,notdone?1.0:0.5));
}
+ if (popup) {
+ int from = get_size().width-menu->get_width();
+
+ if (mouse_x_cache > from)
+ menu_hl->draw(get_canvas_item(),Size2(from,0));
+ else
+ menu->draw(get_canvas_item(),Size2(from,0));
+ }
+
panel->draw(ci, Rect2( 0, top_size.height, size.width, size.height-top_size.height));
} break;
@@ -465,6 +496,48 @@ int TabContainer::get_current_tab() const {
return current;
}
+Control* TabContainer::get_tab_control(int p_idx) const {
+
+ int idx=0;
+
+
+ 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;
+ if (idx==p_idx) {
+ return c;
+
+ }
+ idx++;
+ }
+
+ return NULL;
+}
+Control* TabContainer::get_current_tab_control() const {
+
+ int idx=0;
+
+
+ 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;
+ if (idx==current) {
+ return c;
+
+ }
+ idx++;
+ }
+
+ return NULL;
+}
void TabContainer::remove_child_notify(Node *p_child) {
@@ -635,12 +708,25 @@ Size2 TabContainer::get_minimum_size() const {
return ms;
}
+void TabContainer::set_popup(Node *p_popup) {
+ ERR_FAIL_NULL(p_popup);
+ popup=p_popup->cast_to<Popup>();
+ update();
+}
+
+Popup* TabContainer::get_popup() const {
+ return popup;
+}
+
+
void TabContainer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_input_event"),&TabContainer::_input_event);
ObjectTypeDB::bind_method(_MD("get_tab_count"),&TabContainer::get_tab_count);
ObjectTypeDB::bind_method(_MD("set_current_tab","tab_idx"),&TabContainer::set_current_tab);
ObjectTypeDB::bind_method(_MD("get_current_tab"),&TabContainer::get_current_tab);
+ ObjectTypeDB::bind_method(_MD("get_current_tab_control:Control"),&TabContainer::get_current_tab_control);
+ ObjectTypeDB::bind_method(_MD("get_tab_control:Control","idx"),&TabContainer::get_tab_control);
ObjectTypeDB::bind_method(_MD("set_tab_align","align"),&TabContainer::set_tab_align);
ObjectTypeDB::bind_method(_MD("get_tab_align"),&TabContainer::get_tab_align);
ObjectTypeDB::bind_method(_MD("set_tabs_visible","visible"),&TabContainer::set_tabs_visible);
@@ -649,10 +735,13 @@ void TabContainer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_tab_title","tab_idx"),&TabContainer::get_tab_title);
ObjectTypeDB::bind_method(_MD("set_tab_icon","tab_idx","icon:Texture"),&TabContainer::set_tab_icon);
ObjectTypeDB::bind_method(_MD("get_tab_icon:Texture","tab_idx"),&TabContainer::get_tab_icon);
+ ObjectTypeDB::bind_method(_MD("set_popup","popup:Popup"),&TabContainer::set_popup);
+ ObjectTypeDB::bind_method(_MD("get_popup:Popup"),&TabContainer::get_popup);
ObjectTypeDB::bind_method(_MD("_child_renamed_callback"),&TabContainer::_child_renamed_callback);
ADD_SIGNAL(MethodInfo("tab_changed",PropertyInfo(Variant::INT,"tab")));
+ ADD_SIGNAL(MethodInfo("pre_popup_pressed"));
ADD_PROPERTY( PropertyInfo(Variant::INT, "tab_align", PROPERTY_HINT_ENUM,"Left,Center,Right"), _SCS("set_tab_align"), _SCS("get_tab_align") );
ADD_PROPERTY( PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE,"-1,4096,1",PROPERTY_USAGE_EDITOR), _SCS("set_current_tab"), _SCS("get_current_tab") );
@@ -669,5 +758,6 @@ TabContainer::TabContainer() {
mouse_x_cache=0;
align=ALIGN_CENTER;
tabs_visible=true;
+ popup=NULL;
}
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index 43314b026d..602d248b46 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -31,7 +31,7 @@
#include "scene/gui/control.h"
-
+#include "scene/gui/popup.h"
class TabContainer : public Control {
OBJ_TYPE( TabContainer, Control );
@@ -55,6 +55,8 @@ private:
TabAlign align;
Control *_get_tab(int idx) const;
int _get_top_margin() const;
+ Popup *popup;
+
protected:
@@ -85,10 +87,17 @@ public:
void set_current_tab(int p_current);
int get_current_tab() const;
+ Control* get_tab_control(int p_idx) const;
+ Control* get_current_tab_control() const;
+
virtual Size2 get_minimum_size() const;
virtual void get_translatable_strings(List<String> *p_strings) const;
+ void set_popup(Node *p_popup);
+ Popup* get_popup() const;
+
+
TabContainer();
};
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 0c15f99509..c497bc5363 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -3601,6 +3601,10 @@ TextEdit::TextEdit() {
set_focus_mode(FOCUS_ALL);
_update_caches();
cache.size=Size2(1,1);
+ cache.row_height=1;
+ cache.line_spacing=1;
+ cache.line_number_w=1;
+
tab_size=4;
text.set_tab_size(tab_size);
text.clear();