2016-06-18 14:46:12 +02:00
/*************************************************************************/
/* item_list.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2016-06-18 14:46:12 +02:00
/*************************************************************************/
2019-01-01 12:53:14 +01:00
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
2016-06-18 14:46:12 +02:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2018-01-05 00:50:27 +01:00
2015-06-06 14:44:38 +02:00
# include "item_list.h"
2018-09-11 18:13:45 +02:00
# include "core/os/os.h"
# include "core/project_settings.h"
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
void ItemList : : add_item ( const String & p_item , const Ref < Texture > & p_texture , bool p_selectable ) {
2015-06-06 14:44:38 +02:00
Item item ;
2017-03-05 16:44:50 +01:00
item . icon = p_texture ;
2018-10-29 17:16:18 +01:00
item . icon_transposed = false ;
2017-03-05 16:44:50 +01:00
item . icon_region = Rect2i ( ) ;
2018-03-11 15:59:50 +01:00
item . icon_modulate = Color ( 1 , 1 , 1 , 1 ) ;
2017-03-05 16:44:50 +01:00
item . text = p_item ;
item . selectable = p_selectable ;
item . selected = false ;
item . disabled = false ;
item . tooltip_enabled = true ;
item . custom_bg = Color ( 0 , 0 , 0 , 0 ) ;
2015-06-06 14:44:38 +02:00
items . push_back ( item ) ;
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
void ItemList : : add_icon_item ( const Ref < Texture > & p_item , bool p_selectable ) {
2015-06-06 14:44:38 +02:00
Item item ;
2017-03-05 16:44:50 +01:00
item . icon = p_item ;
2018-10-29 17:16:18 +01:00
item . icon_transposed = false ;
2017-03-05 16:44:50 +01:00
item . icon_region = Rect2i ( ) ;
2018-03-11 15:59:50 +01:00
item . icon_modulate = Color ( 1 , 1 , 1 , 1 ) ;
2015-06-06 14:44:38 +02:00
//item.text=p_item;
2017-03-05 16:44:50 +01:00
item . selectable = p_selectable ;
item . selected = false ;
item . disabled = false ;
item . tooltip_enabled = true ;
item . custom_bg = Color ( 0 , 0 , 0 , 0 ) ;
2015-06-06 14:44:38 +02:00
items . push_back ( item ) ;
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_item_text ( int p_idx , const String & p_text ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2015-06-06 14:44:38 +02:00
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . text = p_text ;
2015-06-06 14:44:38 +02:00
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
String ItemList : : get_item_text ( int p_idx ) const {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , items . size ( ) , String ( ) ) ;
2015-06-06 14:44:38 +02:00
return items [ p_idx ] . text ;
}
2016-09-07 17:21:20 +02:00
void ItemList : : set_item_tooltip_enabled ( int p_idx , const bool p_enabled ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . tooltip_enabled = p_enabled ;
2016-09-07 17:21:20 +02:00
}
bool ItemList : : is_item_tooltip_enabled ( int p_idx ) const {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , items . size ( ) , false ) ;
2016-09-07 17:21:20 +02:00
return items [ p_idx ] . tooltip_enabled ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_item_tooltip ( int p_idx , const String & p_tooltip ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2015-06-06 14:44:38 +02:00
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . tooltip = p_tooltip ;
2015-06-06 14:44:38 +02:00
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
String ItemList : : get_item_tooltip ( int p_idx ) const {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , items . size ( ) , String ( ) ) ;
2015-06-06 14:44:38 +02:00
return items [ p_idx ] . tooltip ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_item_icon ( int p_idx , const Ref < Texture > & p_icon ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2015-06-06 14:44:38 +02:00
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . icon = p_icon ;
2015-06-06 14:44:38 +02:00
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
2015-06-06 14:44:38 +02:00
}
2016-03-13 16:23:49 +01:00
2017-03-05 16:44:50 +01:00
Ref < Texture > ItemList : : get_item_icon ( int p_idx ) const {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , items . size ( ) , Ref < Texture > ( ) ) ;
2015-06-06 14:44:38 +02:00
return items [ p_idx ] . icon ;
}
2018-10-29 17:16:18 +01:00
void ItemList : : set_item_icon_transposed ( int p_idx , const bool p_transposed ) {
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
items . write [ p_idx ] . icon_transposed = p_transposed ;
update ( ) ;
shape_changed = true ;
}
bool ItemList : : is_item_icon_transposed ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , items . size ( ) , false ) ;
return items [ p_idx ] . icon_transposed ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_item_icon_region ( int p_idx , const Rect2 & p_region ) {
2016-03-13 16:23:49 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2016-03-13 16:23:49 +01:00
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . icon_region = p_region ;
2016-03-13 16:23:49 +01:00
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
2016-03-13 16:23:49 +01:00
}
Rect2 ItemList : : get_item_icon_region ( int p_idx ) const {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , items . size ( ) , Rect2 ( ) ) ;
2016-03-13 16:23:49 +01:00
return items [ p_idx ] . icon_region ;
}
2018-03-11 15:59:50 +01:00
void ItemList : : set_item_icon_modulate ( int p_idx , const Color & p_modulate ) {
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . icon_modulate = p_modulate ;
2018-03-11 15:59:50 +01:00
update ( ) ;
}
Color ItemList : : get_item_icon_modulate ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , items . size ( ) , Color ( ) ) ;
return items [ p_idx ] . icon_modulate ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_item_custom_bg_color ( int p_idx , const Color & p_custom_bg_color ) {
2015-06-22 05:03:19 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2015-06-22 05:03:19 +02:00
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . custom_bg = p_custom_bg_color ;
2015-06-22 05:03:19 +02:00
}
Color ItemList : : get_item_custom_bg_color ( int p_idx ) const {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , items . size ( ) , Color ( ) ) ;
2015-06-22 05:03:19 +02:00
return items [ p_idx ] . custom_bg ;
}
2017-09-03 09:44:59 +02:00
void ItemList : : set_item_custom_fg_color ( int p_idx , const Color & p_custom_fg_color ) {
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . custom_fg = p_custom_fg_color ;
2017-09-03 09:44:59 +02:00
}
Color ItemList : : get_item_custom_fg_color ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , items . size ( ) , Color ( ) ) ;
return items [ p_idx ] . custom_fg ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_item_tag_icon ( int p_idx , const Ref < Texture > & p_tag_icon ) {
2015-06-22 05:03:19 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2015-06-06 14:44:38 +02:00
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . tag_icon = p_tag_icon ;
2015-06-06 14:44:38 +02:00
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
Ref < Texture > ItemList : : get_item_tag_icon ( int p_idx ) const {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , items . size ( ) , Ref < Texture > ( ) ) ;
2015-06-06 14:44:38 +02:00
return items [ p_idx ] . tag_icon ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_item_selectable ( int p_idx , bool p_selectable ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2015-06-06 14:44:38 +02:00
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . selectable = p_selectable ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
bool ItemList : : is_item_selectable ( int p_idx ) const {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , items . size ( ) , false ) ;
2015-06-06 14:44:38 +02:00
return items [ p_idx ] . selectable ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_item_disabled ( int p_idx , bool p_disabled ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2015-06-06 14:44:38 +02:00
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . disabled = p_disabled ;
2016-07-21 23:24:56 +02:00
update ( ) ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
bool ItemList : : is_item_disabled ( int p_idx ) const {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , items . size ( ) , false ) ;
2015-06-06 14:44:38 +02:00
return items [ p_idx ] . disabled ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_item_metadata ( int p_idx , const Variant & p_metadata ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2015-06-06 14:44:38 +02:00
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . metadata = p_metadata ;
2015-06-06 14:44:38 +02:00
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
Variant ItemList : : get_item_metadata ( int p_idx ) const {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , items . size ( ) , Variant ( ) ) ;
2015-06-06 14:44:38 +02:00
return items [ p_idx ] . metadata ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : select ( int p_idx , bool p_single ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
if ( p_single | | select_mode = = SELECT_SINGLE ) {
2015-06-06 14:44:38 +02:00
2016-07-21 23:24:56 +02:00
if ( ! items [ p_idx ] . selectable | | items [ p_idx ] . disabled ) {
2015-06-06 14:44:38 +02:00
return ;
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < items . size ( ) ; i + + ) {
2018-07-25 03:11:03 +02:00
items . write [ i ] . selected = p_idx = = i ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
current = p_idx ;
ensure_selected_visible = false ;
2015-06-06 14:44:38 +02:00
} else {
2016-07-21 23:24:56 +02:00
if ( items [ p_idx ] . selectable & & ! items [ p_idx ] . disabled ) {
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . selected = true ;
2015-06-06 14:44:38 +02:00
}
}
update ( ) ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : unselect ( int p_idx ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
if ( select_mode ! = SELECT_MULTI ) {
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . selected = false ;
2017-03-05 16:44:50 +01:00
current = - 1 ;
2015-06-06 14:44:38 +02:00
} else {
2018-07-25 03:11:03 +02:00
items . write [ p_idx ] . selected = false ;
2015-06-06 14:44:38 +02:00
}
update ( ) ;
}
2017-11-24 14:39:02 +01:00
void ItemList : : unselect_all ( ) {
if ( items . size ( ) < 1 )
return ;
for ( int i = 0 ; i < items . size ( ) ; i + + ) {
2018-07-25 03:11:03 +02:00
items . write [ i ] . selected = false ;
2017-11-24 14:39:02 +01:00
}
2018-07-18 13:46:02 +02:00
current = - 1 ;
2017-11-24 14:39:02 +01:00
update ( ) ;
}
2017-03-05 16:44:50 +01:00
bool ItemList : : is_selected ( int p_idx ) const {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , items . size ( ) , false ) ;
2015-06-06 14:44:38 +02:00
return items [ p_idx ] . selected ;
}
void ItemList : : set_current ( int p_current ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_current , items . size ( ) ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
if ( select_mode = = SELECT_SINGLE )
select ( p_current , true ) ;
2015-06-06 14:44:38 +02:00
else {
2017-03-05 16:44:50 +01:00
current = p_current ;
2015-06-06 14:44:38 +02:00
update ( ) ;
}
}
int ItemList : : get_current ( ) const {
return current ;
}
2018-03-13 15:19:04 +01:00
void ItemList : : move_item ( int p_from_idx , int p_to_idx ) {
2015-11-17 13:46:08 +01:00
2018-03-13 15:19:04 +01:00
ERR_FAIL_INDEX ( p_from_idx , items . size ( ) ) ;
ERR_FAIL_INDEX ( p_to_idx , items . size ( ) ) ;
2015-11-17 13:46:08 +01:00
2018-03-13 15:19:04 +01:00
if ( is_anything_selected ( ) & & get_selected_items ( ) [ 0 ] = = p_from_idx ) {
current = p_to_idx ;
2015-11-17 13:46:08 +01:00
}
2018-03-13 15:19:04 +01:00
Item item = items [ p_from_idx ] ;
items . remove ( p_from_idx ) ;
items . insert ( p_to_idx , item ) ;
2015-11-17 13:46:08 +01:00
update ( ) ;
2018-03-13 15:19:04 +01:00
shape_changed = true ;
2015-11-17 13:46:08 +01:00
}
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
int ItemList : : get_item_count ( ) const {
2015-06-06 14:44:38 +02:00
return items . size ( ) ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : remove_item ( int p_idx ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX ( p_idx , items . size ( ) ) ;
2015-06-06 14:44:38 +02:00
items . remove ( p_idx ) ;
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
defer_select_single = - 1 ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
void ItemList : : clear ( ) {
2015-06-06 14:44:38 +02:00
items . clear ( ) ;
2017-03-05 16:44:50 +01:00
current = - 1 ;
ensure_selected_visible = false ;
2015-06-06 14:44:38 +02:00
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
defer_select_single = - 1 ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_fixed_column_width ( int p_size ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( p_size < 0 ) ;
fixed_column_width = p_size ;
2015-06-06 14:44:38 +02:00
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
int ItemList : : get_fixed_column_width ( ) const {
2015-06-06 14:44:38 +02:00
return fixed_column_width ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_same_column_width ( bool p_enable ) {
2016-05-27 21:42:51 +02:00
2017-03-05 16:44:50 +01:00
same_column_width = p_enable ;
2016-05-27 21:42:51 +02:00
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
2016-05-27 21:42:51 +02:00
}
2017-08-11 13:34:06 +02:00
bool ItemList : : is_same_column_width ( ) const {
2016-05-27 21:42:51 +02:00
return same_column_width ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_max_text_lines ( int p_lines ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( p_lines < 1 ) ;
max_text_lines = p_lines ;
2015-06-06 14:44:38 +02:00
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
int ItemList : : get_max_text_lines ( ) const {
2015-06-06 14:44:38 +02:00
return max_text_lines ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_max_columns ( int p_amount ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( p_amount < 0 ) ;
max_columns = p_amount ;
2015-06-06 14:44:38 +02:00
update ( ) ;
}
2017-03-05 16:44:50 +01:00
int ItemList : : get_max_columns ( ) const {
2015-06-06 14:44:38 +02:00
return max_columns ;
}
void ItemList : : set_select_mode ( SelectMode p_mode ) {
2017-03-05 16:44:50 +01:00
select_mode = p_mode ;
2015-06-06 14:44:38 +02:00
update ( ) ;
}
ItemList : : SelectMode ItemList : : get_select_mode ( ) const {
return select_mode ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_icon_mode ( IconMode p_mode ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
icon_mode = p_mode ;
2015-06-06 14:44:38 +02:00
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
2015-06-06 14:44:38 +02:00
}
2018-10-29 17:16:18 +01:00
2017-03-05 16:44:50 +01:00
ItemList : : IconMode ItemList : : get_icon_mode ( ) const {
2015-06-06 14:44:38 +02:00
return icon_mode ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : set_fixed_icon_size ( const Size2 & p_size ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
fixed_icon_size = p_size ;
2016-05-15 04:48:23 +02:00
update ( ) ;
}
2016-06-12 21:51:27 +02:00
Size2 ItemList : : get_fixed_icon_size ( ) const {
2016-05-15 04:48:23 +02:00
2016-06-12 21:51:27 +02:00
return fixed_icon_size ;
2016-05-15 04:48:23 +02:00
}
2016-03-13 16:23:49 +01:00
Size2 ItemList : : Item : : get_icon_size ( ) const {
2015-06-06 14:44:38 +02:00
2016-03-13 16:23:49 +01:00
if ( icon . is_null ( ) )
return Size2 ( ) ;
2018-10-29 17:16:18 +01:00
Size2 size_result = Size2 ( icon_region . size ) . abs ( ) ;
2018-11-07 18:29:24 +01:00
if ( icon_region . size . x = = 0 | | icon_region . size . y = = 0 )
size_result = icon - > get_size ( ) ;
2018-10-29 17:16:18 +01:00
if ( icon_transposed ) {
Size2 size_tmp = size_result ;
size_result . x = size_tmp . y ;
size_result . y = size_tmp . x ;
}
return size_result ;
2016-03-13 16:23:49 +01:00
}
2015-06-06 14:44:38 +02:00
2017-05-20 17:38:03 +02:00
void ItemList : : _gui_input ( const Ref < InputEvent > & p_event ) {
2016-05-04 22:41:58 +02:00
2019-05-21 18:53:29 +02:00
double prev_scroll = scroll_bar - > get_value ( ) ;
2017-05-20 17:38:03 +02:00
Ref < InputEventMouseMotion > mm = p_event ;
if ( defer_select_single > = 0 & & mm . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
defer_select_single = - 1 ;
2016-05-04 22:41:58 +02:00
return ;
}
2016-05-16 01:25:51 +02:00
2017-05-20 17:38:03 +02:00
Ref < InputEventMouseButton > mb = p_event ;
if ( defer_select_single > = 0 & & mb . is_valid ( ) & & mb - > get_button_index ( ) = = BUTTON_LEFT & & ! mb - > is_pressed ( ) ) {
2016-05-04 22:41:58 +02:00
2017-03-05 16:44:50 +01:00
select ( defer_select_single , true ) ;
2016-05-16 01:25:51 +02:00
2017-03-05 16:44:50 +01:00
emit_signal ( " multi_selected " , defer_select_single , true ) ;
defer_select_single = - 1 ;
2016-05-04 22:41:58 +02:00
return ;
}
2017-05-20 17:38:03 +02:00
if ( mb . is_valid ( ) & & ( mb - > get_button_index ( ) = = BUTTON_LEFT | | ( allow_rmb_select & & mb - > get_button_index ( ) = = BUTTON_RIGHT ) ) & & mb - > is_pressed ( ) ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
search_string = " " ; //any mousepress cancels
2017-08-02 21:48:50 +02:00
Vector2 pos = mb - > get_position ( ) ;
2015-06-06 14:44:38 +02:00
Ref < StyleBox > bg = get_stylebox ( " bg " ) ;
2017-03-05 16:44:50 +01:00
pos - = bg - > get_offset ( ) ;
pos . y + = scroll_bar - > get_value ( ) ;
2015-06-06 14:44:38 +02:00
int closest = - 1 ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < items . size ( ) ; i + + ) {
2015-06-06 14:44:38 +02:00
Rect2 rc = items [ i ] . rect_cache ;
2017-03-05 16:44:50 +01:00
if ( i % current_columns = = current_columns - 1 ) {
rc . size . width = get_size ( ) . width ; //not right but works
2015-06-06 14:44:38 +02:00
}
if ( rc . has_point ( pos ) ) {
2017-03-05 16:44:50 +01:00
closest = i ;
2015-06-06 14:44:38 +02:00
break ;
}
}
2017-03-05 16:44:50 +01:00
if ( closest ! = - 1 ) {
2015-06-06 14:44:38 +02:00
int i = closest ;
2017-05-20 17:38:03 +02:00
if ( select_mode = = SELECT_MULTI & & items [ i ] . selected & & mb - > get_command ( ) ) {
2015-06-06 14:44:38 +02:00
unselect ( i ) ;
2017-03-05 16:44:50 +01:00
emit_signal ( " multi_selected " , i , false ) ;
2016-05-16 01:25:51 +02:00
2017-05-20 17:38:03 +02:00
} else if ( select_mode = = SELECT_MULTI & & mb - > get_shift ( ) & & current > = 0 & & current < items . size ( ) & & current ! = i ) {
2015-06-06 14:44:38 +02:00
int from = current ;
int to = i ;
2017-03-05 16:44:50 +01:00
if ( i < current ) {
SWAP ( from , to ) ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
for ( int j = from ; j < = to ; j + + ) {
2015-06-06 14:44:38 +02:00
bool selected = ! items [ j ] . selected ;
2017-03-05 16:44:50 +01:00
select ( j , false ) ;
2015-06-06 14:44:38 +02:00
if ( selected )
2018-08-24 23:05:17 +02:00
emit_signal ( " multi_selected " , j , true ) ;
2015-06-06 14:44:38 +02:00
}
2016-05-16 01:25:51 +02:00
2017-05-20 17:38:03 +02:00
if ( mb - > get_button_index ( ) = = BUTTON_RIGHT ) {
2016-05-16 01:25:51 +02:00
2017-10-18 14:56:38 +02:00
emit_signal ( " item_rmb_selected " , i , get_local_mouse_position ( ) ) ;
2016-05-16 01:25:51 +02:00
}
2015-06-06 14:44:38 +02:00
} else {
2016-05-04 22:41:58 +02:00
2017-05-20 17:38:03 +02:00
if ( ! mb - > is_doubleclick ( ) & & ! mb - > get_command ( ) & & select_mode = = SELECT_MULTI & & items [ i ] . selectable & & ! items [ i ] . disabled & & items [ i ] . selected & & mb - > get_button_index ( ) = = BUTTON_LEFT ) {
2017-03-05 16:44:50 +01:00
defer_select_single = i ;
2016-05-04 22:41:58 +02:00
return ;
}
2017-05-20 17:38:03 +02:00
if ( items [ i ] . selected & & mb - > get_button_index ( ) = = BUTTON_RIGHT ) {
2015-06-06 14:44:38 +02:00
2017-10-18 14:56:38 +02:00
emit_signal ( " item_rmb_selected " , i , get_local_mouse_position ( ) ) ;
2016-05-16 01:25:51 +02:00
} else {
2018-02-14 04:24:57 +01:00
bool selected = items [ i ] . selected ;
2015-06-06 14:44:38 +02:00
2017-05-20 17:38:03 +02:00
select ( i , select_mode = = SELECT_SINGLE | | ! mb - > get_command ( ) ) ;
2016-05-16 01:25:51 +02:00
2018-02-14 04:24:57 +01:00
if ( ! selected | | allow_reselect ) {
2017-03-05 16:44:50 +01:00
if ( select_mode = = SELECT_SINGLE ) {
emit_signal ( " item_selected " , i ) ;
2016-05-16 01:25:51 +02:00
} else
2017-03-05 16:44:50 +01:00
emit_signal ( " multi_selected " , i , true ) ;
2016-05-16 01:25:51 +02:00
}
2017-05-20 17:38:03 +02:00
if ( mb - > get_button_index ( ) = = BUTTON_RIGHT ) {
2016-05-16 01:25:51 +02:00
2017-10-18 14:56:38 +02:00
emit_signal ( " item_rmb_selected " , i , get_local_mouse_position ( ) ) ;
2017-05-20 17:38:03 +02:00
} else if ( /*select_mode==SELECT_SINGLE &&*/ mb - > is_doubleclick ( ) ) {
2016-05-16 01:25:51 +02:00
2017-03-05 16:44:50 +01:00
emit_signal ( " item_activated " , i ) ;
2016-05-16 01:25:51 +02:00
}
}
2015-06-06 14:44:38 +02:00
}
2017-11-20 19:25:13 +01:00
return ;
}
if ( mb - > get_button_index ( ) = = BUTTON_RIGHT ) {
emit_signal ( " rmb_clicked " , mb - > get_position ( ) ) ;
2015-06-06 14:44:38 +02:00
return ;
}
2017-11-24 14:39:02 +01:00
// Since closest is null, more likely we clicked on empty space, so send signal to interested controls. Allows, for example, implement items deselecting.
emit_signal ( " nothing_selected " ) ;
2015-06-06 14:44:38 +02:00
}
2017-05-20 17:38:03 +02:00
if ( mb . is_valid ( ) & & mb - > get_button_index ( ) = = BUTTON_WHEEL_UP & & mb - > is_pressed ( ) ) {
2015-06-06 14:44:38 +02:00
2017-05-20 17:38:03 +02:00
scroll_bar - > set_value ( scroll_bar - > get_value ( ) - scroll_bar - > get_page ( ) * mb - > get_factor ( ) / 8 ) ;
2015-06-06 14:44:38 +02:00
}
2017-05-20 17:38:03 +02:00
if ( mb . is_valid ( ) & & mb - > get_button_index ( ) = = BUTTON_WHEEL_DOWN & & mb - > is_pressed ( ) ) {
2015-06-06 14:44:38 +02:00
2017-05-20 17:38:03 +02:00
scroll_bar - > set_value ( scroll_bar - > get_value ( ) + scroll_bar - > get_page ( ) * mb - > get_factor ( ) / 8 ) ;
2015-06-06 14:44:38 +02:00
}
2017-05-20 17:38:03 +02:00
if ( p_event - > is_pressed ( ) & & items . size ( ) > 0 ) {
if ( p_event - > is_action ( " ui_up " ) ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
if ( search_string ! = " " ) {
2015-06-06 14:44:38 +02:00
uint64_t now = OS : : get_singleton ( ) - > get_ticks_msec ( ) ;
2017-03-05 16:44:50 +01:00
uint64_t diff = now - search_time_msec ;
2015-06-06 14:44:38 +02:00
2017-08-31 23:30:35 +02:00
if ( diff < uint64_t ( ProjectSettings : : get_singleton ( ) - > get ( " gui/timers/incremental_search_max_interval_msec " ) ) * 2 ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = current - 1 ; i > = 0 ; i - - ) {
2015-06-06 14:44:38 +02:00
if ( items [ i ] . text . begins_with ( search_string ) ) {
set_current ( i ) ;
ensure_current_is_visible ( ) ;
2017-03-05 16:44:50 +01:00
if ( select_mode = = SELECT_SINGLE ) {
emit_signal ( " item_selected " , current ) ;
2015-06-06 14:44:38 +02:00
}
break ;
}
}
accept_event ( ) ;
return ;
}
}
2017-03-05 16:44:50 +01:00
if ( current > = current_columns ) {
set_current ( current - current_columns ) ;
2015-06-06 14:44:38 +02:00
ensure_current_is_visible ( ) ;
2017-03-05 16:44:50 +01:00
if ( select_mode = = SELECT_SINGLE ) {
emit_signal ( " item_selected " , current ) ;
2015-06-06 14:44:38 +02:00
}
accept_event ( ) ;
}
2017-05-20 17:38:03 +02:00
} else if ( p_event - > is_action ( " ui_down " ) ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
if ( search_string ! = " " ) {
2015-06-06 14:44:38 +02:00
uint64_t now = OS : : get_singleton ( ) - > get_ticks_msec ( ) ;
2017-03-05 16:44:50 +01:00
uint64_t diff = now - search_time_msec ;
2015-06-06 14:44:38 +02:00
2017-08-31 23:30:35 +02:00
if ( diff < uint64_t ( ProjectSettings : : get_singleton ( ) - > get ( " gui/timers/incremental_search_max_interval_msec " ) ) * 2 ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = current + 1 ; i < items . size ( ) ; i + + ) {
2015-06-06 14:44:38 +02:00
if ( items [ i ] . text . begins_with ( search_string ) ) {
set_current ( i ) ;
ensure_current_is_visible ( ) ;
2017-03-05 16:44:50 +01:00
if ( select_mode = = SELECT_SINGLE ) {
emit_signal ( " item_selected " , current ) ;
2015-06-06 14:44:38 +02:00
}
break ;
}
}
accept_event ( ) ;
return ;
}
}
2017-03-05 16:44:50 +01:00
if ( current < items . size ( ) - current_columns ) {
set_current ( current + current_columns ) ;
2015-06-06 14:44:38 +02:00
ensure_current_is_visible ( ) ;
2017-03-05 16:44:50 +01:00
if ( select_mode = = SELECT_SINGLE ) {
emit_signal ( " item_selected " , current ) ;
2015-06-06 14:44:38 +02:00
}
accept_event ( ) ;
}
2017-05-20 17:38:03 +02:00
} else if ( p_event - > is_action ( " ui_page_up " ) ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
search_string = " " ; //any mousepress cancels
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 4 ; i > 0 ; i - - ) {
if ( current - current_columns * i > = 0 ) {
set_current ( current - current_columns * i ) ;
2015-06-06 14:44:38 +02:00
ensure_current_is_visible ( ) ;
2017-03-05 16:44:50 +01:00
if ( select_mode = = SELECT_SINGLE ) {
emit_signal ( " item_selected " , current ) ;
2015-06-06 14:44:38 +02:00
}
accept_event ( ) ;
break ;
}
}
2017-05-20 17:38:03 +02:00
} else if ( p_event - > is_action ( " ui_page_down " ) ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
search_string = " " ; //any mousepress cancels
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 4 ; i > 0 ; i - - ) {
if ( current + current_columns * i < items . size ( ) ) {
set_current ( current + current_columns * i ) ;
2015-06-06 14:44:38 +02:00
ensure_current_is_visible ( ) ;
2017-03-05 16:44:50 +01:00
if ( select_mode = = SELECT_SINGLE ) {
emit_signal ( " item_selected " , current ) ;
2015-06-06 14:44:38 +02:00
}
accept_event ( ) ;
break ;
}
}
2017-05-20 17:38:03 +02:00
} else if ( p_event - > is_action ( " ui_left " ) ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
search_string = " " ; //any mousepress cancels
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
if ( current % current_columns ! = 0 ) {
set_current ( current - 1 ) ;
2015-06-06 14:44:38 +02:00
ensure_current_is_visible ( ) ;
2017-03-05 16:44:50 +01:00
if ( select_mode = = SELECT_SINGLE ) {
emit_signal ( " item_selected " , current ) ;
2015-06-06 14:44:38 +02:00
}
accept_event ( ) ;
}
2017-05-20 17:38:03 +02:00
} else if ( p_event - > is_action ( " ui_right " ) ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
search_string = " " ; //any mousepress cancels
2015-06-06 14:44:38 +02:00
2018-04-14 14:36:53 +02:00
if ( current % current_columns ! = ( current_columns - 1 ) & & current + 1 < items . size ( ) ) {
2017-03-05 16:44:50 +01:00
set_current ( current + 1 ) ;
2015-06-06 14:44:38 +02:00
ensure_current_is_visible ( ) ;
2017-03-05 16:44:50 +01:00
if ( select_mode = = SELECT_SINGLE ) {
emit_signal ( " item_selected " , current ) ;
2015-06-06 14:44:38 +02:00
}
accept_event ( ) ;
}
2017-05-20 17:38:03 +02:00
} else if ( p_event - > is_action ( " ui_cancel " ) ) {
2017-03-05 16:44:50 +01:00
search_string = " " ;
2019-01-17 15:54:24 +01:00
} else if ( p_event - > is_action ( " ui_select " ) & & select_mode = = SELECT_MULTI ) {
2015-06-06 14:44:38 +02:00
2019-01-17 15:54:24 +01:00
if ( current > = 0 & & current < items . size ( ) ) {
2016-07-21 23:24:56 +02:00
if ( items [ current ] . selectable & & ! items [ current ] . disabled & & ! items [ current ] . selected ) {
2017-03-05 16:44:50 +01:00
select ( current , false ) ;
emit_signal ( " multi_selected " , current , true ) ;
2015-06-06 14:44:38 +02:00
} else if ( items [ current ] . selected ) {
unselect ( current ) ;
2017-03-05 16:44:50 +01:00
emit_signal ( " multi_selected " , current , false ) ;
2015-06-06 14:44:38 +02:00
}
}
2017-05-20 17:38:03 +02:00
} else if ( p_event - > is_action ( " ui_accept " ) ) {
2017-03-05 16:44:50 +01:00
search_string = " " ; //any mousepress cance
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
if ( current > = 0 & & current < items . size ( ) ) {
emit_signal ( " item_activated " , current ) ;
2015-06-06 14:44:38 +02:00
}
2017-05-20 17:38:03 +02:00
} else {
Ref < InputEventKey > k = p_event ;
2015-06-06 14:44:38 +02:00
2017-05-20 17:38:03 +02:00
if ( k . is_valid ( ) & & k - > get_unicode ( ) ) {
2015-06-06 14:44:38 +02:00
uint64_t now = OS : : get_singleton ( ) - > get_ticks_msec ( ) ;
2017-03-05 16:44:50 +01:00
uint64_t diff = now - search_time_msec ;
uint64_t max_interval = uint64_t ( GLOBAL_DEF ( " gui/timers/incremental_search_max_interval_msec " , 2000 ) ) ;
2015-06-06 14:44:38 +02:00
search_time_msec = now ;
2017-03-05 16:44:50 +01:00
if ( diff > max_interval ) {
search_string = " " ;
2015-06-06 14:44:38 +02:00
}
2019-05-11 18:32:53 +02:00
if ( String : : chr ( k - > get_unicode ( ) ) ! = search_string )
search_string + = String : : chr ( k - > get_unicode ( ) ) ;
for ( int i = current + 1 ; i < = items . size ( ) ; i + + ) {
if ( i = = items . size ( ) ) {
2019-07-06 07:14:49 +02:00
if ( current = = 0 | | current = = - 1 )
2019-05-11 18:32:53 +02:00
break ;
else
i = 0 ;
}
if ( i = = current )
break ;
if ( items [ i ] . text . findn ( search_string ) = = 0 ) {
2015-06-06 14:44:38 +02:00
set_current ( i ) ;
ensure_current_is_visible ( ) ;
2017-03-05 16:44:50 +01:00
if ( select_mode = = SELECT_SINGLE ) {
emit_signal ( " item_selected " , current ) ;
2015-06-06 14:44:38 +02:00
}
break ;
}
}
}
}
}
2017-11-01 21:49:39 +01:00
Ref < InputEventPanGesture > pan_gesture = p_event ;
if ( pan_gesture . is_valid ( ) ) {
scroll_bar - > set_value ( scroll_bar - > get_value ( ) + scroll_bar - > get_page ( ) * pan_gesture - > get_delta ( ) . y / 8 ) ;
}
2019-05-21 18:53:29 +02:00
if ( scroll_bar - > get_value ( ) ! = prev_scroll )
accept_event ( ) ; //accept event if scroll changed
2015-06-06 14:44:38 +02:00
}
void ItemList : : ensure_current_is_visible ( ) {
2017-03-05 16:44:50 +01:00
ensure_selected_visible = true ;
2015-08-24 01:15:56 +02:00
update ( ) ;
2015-06-06 14:44:38 +02:00
}
2016-06-12 21:51:27 +02:00
static Rect2 _adjust_to_max_size ( Size2 p_size , Size2 p_max_size ) {
2016-05-15 04:48:23 +02:00
2017-03-05 16:44:50 +01:00
Size2 size = p_max_size ;
2016-06-12 21:51:27 +02:00
int tex_width = p_size . width * size . height / p_size . height ;
int tex_height = size . height ;
2016-05-15 04:48:23 +02:00
2017-03-05 16:44:50 +01:00
if ( tex_width > size . width ) {
tex_width = size . width ;
tex_height = p_size . height * tex_width / p_size . width ;
2016-05-15 04:48:23 +02:00
}
2017-03-05 16:44:50 +01:00
int ofs_x = ( size . width - tex_width ) / 2 ;
int ofs_y = ( size . height - tex_height ) / 2 ;
2016-05-15 04:48:23 +02:00
2017-03-05 16:44:50 +01:00
return Rect2 ( ofs_x , ofs_y , tex_width , tex_height ) ;
2016-05-15 04:48:23 +02:00
}
2015-06-06 14:44:38 +02:00
void ItemList : : _notification ( int p_what ) {
2017-03-05 16:44:50 +01:00
if ( p_what = = NOTIFICATION_RESIZED ) {
shape_changed = true ;
2015-06-06 14:44:38 +02:00
update ( ) ;
}
2017-03-05 16:44:50 +01:00
if ( p_what = = NOTIFICATION_DRAW ) {
2015-06-06 14:44:38 +02:00
Ref < StyleBox > bg = get_stylebox ( " bg " ) ;
int mw = scroll_bar - > get_minimum_size ( ) . x ;
2017-09-27 21:44:48 +02:00
scroll_bar - > set_anchor_and_margin ( MARGIN_LEFT , ANCHOR_END , - mw ) ;
scroll_bar - > set_anchor_and_margin ( MARGIN_RIGHT , ANCHOR_END , 0 ) ;
2017-03-05 16:44:50 +01:00
scroll_bar - > set_anchor_and_margin ( MARGIN_TOP , ANCHOR_BEGIN , bg - > get_margin ( MARGIN_TOP ) ) ;
2017-07-06 09:16:27 +02:00
scroll_bar - > set_anchor_and_margin ( MARGIN_BOTTOM , ANCHOR_END , - bg - > get_margin ( MARGIN_BOTTOM ) ) ;
2015-06-06 14:44:38 +02:00
Size2 size = get_size ( ) ;
2017-03-05 16:44:50 +01:00
int width = size . width - bg - > get_minimum_size ( ) . width ;
if ( scroll_bar - > is_visible ( ) ) {
2017-11-13 14:24:58 +01:00
width - = mw ;
2016-10-31 23:45:37 +01:00
}
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
draw_style_box ( bg , Rect2 ( Point2 ( ) , size ) ) ;
2015-06-06 14:44:38 +02:00
int hseparation = get_constant ( " hseparation " ) ;
int vseparation = get_constant ( " vseparation " ) ;
int icon_margin = get_constant ( " icon_margin " ) ;
int line_separation = get_constant ( " line_separation " ) ;
2017-03-05 16:44:50 +01:00
Ref < StyleBox > sbsel = has_focus ( ) ? get_stylebox ( " selected_focus " ) : get_stylebox ( " selected " ) ;
Ref < StyleBox > cursor = has_focus ( ) ? get_stylebox ( " cursor " ) : get_stylebox ( " cursor_unfocused " ) ;
2015-06-06 14:44:38 +02:00
Ref < Font > font = get_font ( " font " ) ;
Color guide_color = get_color ( " guide_color " ) ;
Color font_color = get_color ( " font_color " ) ;
2015-06-22 05:03:19 +02:00
Color font_color_selected = get_color ( " font_color_selected " ) ;
2015-06-06 14:44:38 +02:00
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 ( ) ) {
2017-10-31 10:58:53 +01:00
VisualServer : : get_singleton ( ) - > canvas_item_add_clip_ignore ( get_canvas_item ( ) , true ) ;
2017-03-05 16:44:50 +01:00
draw_style_box ( get_stylebox ( " bg_focus " ) , Rect2 ( Point2 ( ) , size ) ) ;
2017-10-31 10:58:53 +01:00
VisualServer : : get_singleton ( ) - > canvas_item_add_clip_ignore ( get_canvas_item ( ) , false ) ;
2015-06-06 14:44:38 +02:00
}
if ( shape_changed ) {
2016-07-19 20:50:01 +02:00
2016-05-27 21:42:51 +02:00
float max_column_width = 0 ;
2015-06-06 14:44:38 +02:00
//1- compute item minimum sizes
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < items . size ( ) ; i + + ) {
2015-06-06 14:44:38 +02:00
Size2 minsize ;
if ( items [ i ] . icon . is_valid ( ) ) {
2016-03-13 16:23:49 +01:00
2017-03-05 16:44:50 +01:00
if ( fixed_icon_size . x > 0 & & fixed_icon_size . y > 0 ) {
minsize = fixed_icon_size * icon_scale ;
2016-06-12 21:51:27 +02:00
} else {
2017-03-05 16:44:50 +01:00
minsize = items [ i ] . get_icon_size ( ) * icon_scale ;
2016-06-12 21:51:27 +02:00
}
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
if ( items [ i ] . text ! = " " ) {
if ( icon_mode = = ICON_MODE_TOP ) {
minsize . y + = icon_margin ;
2015-06-06 14:44:38 +02:00
} else {
2017-03-05 16:44:50 +01:00
minsize . x + = icon_margin ;
2015-06-06 14:44:38 +02:00
}
}
}
2017-03-05 16:44:50 +01:00
if ( items [ i ] . text ! = " " ) {
2015-06-06 14:44:38 +02:00
Size2 s = font - > get_string_size ( items [ i ] . text ) ;
//s.width=MIN(s.width,fixed_column_width);
2017-03-05 16:44:50 +01:00
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 ;
2015-06-06 14:44:38 +02:00
} else {
2017-03-05 16:44:50 +01:00
minsize . y + = s . height ;
2015-06-06 14:44:38 +02:00
}
} else {
2017-03-05 16:44:50 +01:00
minsize . y = MAX ( minsize . y , s . height ) ;
minsize . x + = s . width ;
2015-06-06 14:44:38 +02:00
}
}
2017-03-05 16:44:50 +01:00
if ( fixed_column_width > 0 )
minsize . x = fixed_column_width ;
max_column_width = MAX ( max_column_width , minsize . x ) ;
2017-09-27 21:44:48 +02:00
// elements need to adapt to the selected size
minsize . y + = vseparation ;
minsize . x + = hseparation ;
2018-07-25 03:11:03 +02:00
items . write [ i ] . rect_cache . size = minsize ;
items . write [ i ] . min_rect_cache . size = minsize ;
2015-06-06 14:44:38 +02:00
}
int fit_size = size . x - bg - > get_minimum_size ( ) . width - mw ;
//2-attempt best fit
current_columns = 0x7FFFFFFF ;
2017-03-05 16:44:50 +01:00
if ( max_columns > 0 )
current_columns = max_columns ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
while ( true ) {
2015-06-06 14:44:38 +02:00
//repeat util all fits
2017-03-05 16:44:50 +01:00
bool all_fit = true ;
2015-06-06 14:44:38 +02:00
Vector2 ofs ;
2017-03-05 16:44:50 +01:00
int col = 0 ;
int max_h = 0 ;
2017-01-14 18:03:38 +01:00
separators . clear ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < items . size ( ) ; i + + ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
if ( current_columns > 1 & & items [ i ] . rect_cache . size . width + ofs . x > fit_size ) {
2015-06-06 14:44:38 +02:00
//went past
2017-03-05 16:44:50 +01:00
current_columns = MAX ( col , 1 ) ;
all_fit = false ;
2015-06-06 14:44:38 +02:00
break ;
}
2017-03-05 16:44:50 +01:00
if ( same_column_width )
2018-07-25 03:11:03 +02:00
items . write [ i ] . rect_cache . size . x = max_column_width ;
items . write [ i ] . rect_cache . position = ofs ;
2017-03-05 16:44:50 +01:00
max_h = MAX ( max_h , items [ i ] . rect_cache . size . y ) ;
ofs . x + = items [ i ] . rect_cache . size . x + hseparation ;
2015-06-06 14:44:38 +02:00
col + + ;
2017-03-05 16:44:50 +01:00
if ( col = = current_columns ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
if ( i < items . size ( ) - 1 )
separators . push_back ( ofs . y + max_h + vseparation / 2 ) ;
2016-07-19 20:50:01 +02:00
2017-03-05 16:44:50 +01:00
for ( int j = i ; j > = 0 & & col > 0 ; j - - , col - - ) {
2018-07-25 03:11:03 +02:00
items . write [ j ] . rect_cache . size . y = max_h ;
2016-05-27 21:42:51 +02:00
}
2016-07-19 20:50:01 +02:00
2017-03-05 16:44:50 +01:00
ofs . x = 0 ;
ofs . y + = max_h + vseparation ;
col = 0 ;
max_h = 0 ;
2015-06-06 14:44:38 +02:00
}
}
2017-03-05 16:44:50 +01:00
for ( int j = items . size ( ) - 1 ; j > = 0 & & col > 0 ; j - - , col - - ) {
2018-07-25 03:11:03 +02:00
items . write [ j ] . rect_cache . size . y = max_h ;
2016-05-27 21:42:51 +02:00
}
2015-06-06 14:44:38 +02:00
if ( all_fit ) {
2017-07-21 08:17:06 +02:00
float page = size . height - bg - > get_minimum_size ( ) . height ;
2017-03-05 16:44:50 +01:00
float max = MAX ( page , ofs . y + max_h ) ;
2017-07-21 08:17:06 +02:00
if ( auto_height )
auto_height_value = ofs . y + max_h + bg - > get_minimum_size ( ) . height ;
2015-06-06 14:44:38 +02:00
scroll_bar - > set_max ( max ) ;
2017-07-21 08:17:06 +02:00
scroll_bar - > set_page ( page ) ;
2017-03-05 16:44:50 +01:00
if ( max < = page ) {
2017-01-04 05:16:14 +01:00
scroll_bar - > set_value ( 0 ) ;
2015-06-06 14:44:38 +02:00
scroll_bar - > hide ( ) ;
} else {
scroll_bar - > show ( ) ;
2017-12-17 23:16:11 +01:00
if ( do_autoscroll_to_bottom )
scroll_bar - > set_value ( max ) ;
2015-06-06 14:44:38 +02:00
}
break ;
}
}
2018-07-01 02:36:54 +02:00
minimum_size_changed ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = false ;
2015-06-06 14:44:38 +02:00
}
2016-09-16 17:25:07 +02:00
//ensure_selected_visible needs to be checked before we draw the list.
2017-03-05 16:44:50 +01:00
if ( ensure_selected_visible & & current > = 0 & & current < = items . size ( ) ) {
2015-06-06 14:44:38 +02:00
2016-09-16 17:25:07 +02:00
Rect2 r = items [ current ] . rect_cache ;
2017-01-04 05:16:14 +01:00
int from = scroll_bar - > get_value ( ) ;
2016-09-16 17:25:07 +02:00
int to = from + scroll_bar - > get_page ( ) ;
2017-06-04 00:25:13 +02:00
if ( r . position . y < from ) {
scroll_bar - > set_value ( r . position . y ) ;
} else if ( r . position . y + r . size . y > to ) {
scroll_bar - > set_value ( r . position . y + r . size . y - ( to - from ) ) ;
2016-09-16 17:25:07 +02:00
}
}
2017-03-05 16:44:50 +01:00
ensure_selected_visible = false ;
2015-06-06 14:44:38 +02:00
Vector2 base_ofs = bg - > get_offset ( ) ;
2017-03-05 16:44:50 +01:00
base_ofs . y - = int ( scroll_bar - > get_value ( ) ) ;
2015-06-06 14:44:38 +02:00
2018-01-03 21:11:50 +01:00
const Rect2 clip ( - base_ofs , size ) ; // visible frame, don't need to draw outside of there
int first_item_visible ;
{
// do a binary search to find the first item whose rect reaches below clip.position.y
int lo = 0 ;
int hi = items . size ( ) ;
while ( lo < hi ) {
const int mid = ( lo + hi ) / 2 ;
const Rect2 & rcache = items [ mid ] . rect_cache ;
if ( rcache . position . y + rcache . size . y < clip . position . y ) {
lo = mid + 1 ;
} else {
hi = mid ;
}
}
// we might have ended up with column 2, or 3, ..., so let's find the first column
while ( lo > 0 & & items [ lo - 1 ] . rect_cache . position . y = = items [ lo ] . rect_cache . position . y ) {
lo - = 1 ;
}
first_item_visible = lo ;
}
2015-06-06 14:44:38 +02:00
2018-01-03 21:11:50 +01:00
for ( int i = first_item_visible ; i < items . size ( ) ; i + + ) {
2015-06-06 14:44:38 +02:00
Rect2 rcache = items [ i ] . rect_cache ;
2018-01-03 21:11:50 +01:00
if ( rcache . position . y > clip . position . y + clip . size . y )
break ; // done
2015-06-06 14:44:38 +02:00
if ( ! clip . intersects ( rcache ) )
continue ;
2017-03-05 16:44:50 +01:00
if ( current_columns = = 1 ) {
2017-06-04 00:25:13 +02:00
rcache . size . width = width - rcache . position . x ;
2015-06-06 14:44:38 +02:00
}
2016-01-22 00:21:44 +01:00
if ( items [ i ] . selected ) {
2017-06-05 02:58:29 +02:00
Rect2 r = rcache ;
r . position + = base_ofs ;
2017-09-27 21:44:48 +02:00
r . position . y - = vseparation / 2 ;
r . size . y + = vseparation ;
r . position . x - = hseparation / 2 ;
r . size . x + = hseparation ;
2017-06-05 02:58:29 +02:00
2017-03-05 16:44:50 +01:00
draw_style_box ( sbsel , r ) ;
2016-01-22 00:21:44 +01:00
}
2017-03-05 16:44:50 +01:00
if ( items [ i ] . custom_bg . a > 0.001 ) {
2017-06-05 02:58:29 +02:00
Rect2 r = rcache ;
r . position + = base_ofs ;
// Size rect to make the align the temperature colors
r . position . y - = vseparation / 2 ;
r . size . y + = vseparation ;
2017-09-27 21:44:48 +02:00
r . position . x - = hseparation / 2 ;
r . size . x + = hseparation ;
2017-03-05 16:44:50 +01:00
draw_rect ( r , items [ i ] . custom_bg ) ;
2015-06-06 14:44:38 +02:00
}
Vector2 text_ofs ;
if ( items [ i ] . icon . is_valid ( ) ) {
2016-06-12 21:51:27 +02:00
Size2 icon_size ;
//= _adjust_to_max_size(items[i].get_icon_size(),fixed_icon_size) * icon_scale;
2017-03-05 16:44:50 +01:00
if ( fixed_icon_size . x > 0 & & fixed_icon_size . y > 0 ) {
icon_size = fixed_icon_size * icon_scale ;
2016-06-12 21:51:27 +02:00
} else {
2017-03-05 16:44:50 +01:00
icon_size = items [ i ] . get_icon_size ( ) * icon_scale ;
2015-06-06 14:44:38 +02:00
}
2016-06-12 21:51:27 +02:00
Vector2 icon_ofs ;
2017-06-04 00:25:13 +02:00
Point2 pos = items [ i ] . rect_cache . position + icon_ofs + base_ofs ;
2016-03-13 16:23:49 +01:00
2017-03-05 16:44:50 +01:00
if ( icon_mode = = ICON_MODE_TOP ) {
2016-03-13 16:23:49 +01:00
2017-03-05 16:44:50 +01:00
pos . x + = Math : : floor ( ( items [ i ] . rect_cache . size . width - icon_size . width ) / 2 ) ;
2016-05-27 21:42:51 +02:00
pos . y + = MIN (
2017-03-05 16:44:50 +01:00
Math : : floor ( ( items [ i ] . rect_cache . size . height - icon_size . height ) / 2 ) ,
items [ i ] . rect_cache . size . height - items [ i ] . min_rect_cache . size . height ) ;
2016-06-12 21:51:27 +02:00
text_ofs . y = icon_size . height + icon_margin ;
2016-05-27 21:42:51 +02:00
text_ofs . y + = items [ i ] . rect_cache . size . height - items [ i ] . min_rect_cache . size . height ;
2015-06-06 14:44:38 +02:00
} else {
2016-03-13 16:23:49 +01:00
2017-03-05 16:44:50 +01:00
pos . y + = Math : : floor ( ( items [ i ] . rect_cache . size . height - icon_size . height ) / 2 ) ;
2016-06-12 21:51:27 +02:00
text_ofs . x = icon_size . width + icon_margin ;
}
2017-03-05 16:44:50 +01:00
Rect2 draw_rect = Rect2 ( pos , icon_size ) ;
2016-06-12 21:51:27 +02:00
2017-03-05 16:44:50 +01:00
if ( fixed_icon_size . x > 0 & & fixed_icon_size . y > 0 ) {
Rect2 adj = _adjust_to_max_size ( items [ i ] . get_icon_size ( ) * icon_scale , icon_size ) ;
2017-06-04 00:25:13 +02:00
draw_rect . position + = adj . position ;
2017-03-05 16:44:50 +01:00
draw_rect . size = adj . size ;
2015-06-06 14:44:38 +02:00
}
2016-03-13 16:23:49 +01:00
2018-03-11 15:59:50 +01:00
Color modulate = items [ i ] . icon_modulate ;
2016-07-21 23:24:56 +02:00
if ( items [ i ] . disabled )
2017-03-05 16:44:50 +01:00
modulate . a * = 0.5 ;
2016-07-21 23:24:56 +02:00
2019-02-13 09:23:29 +01:00
// If the icon is transposed, we have to switch the size so that it is drawn correctly
2018-10-29 17:16:18 +01:00
if ( items [ i ] . icon_transposed ) {
Size2 size_tmp = draw_rect . size ;
draw_rect . size . x = size_tmp . y ;
draw_rect . size . y = size_tmp . x ;
}
2018-11-07 18:29:24 +01:00
Rect2 region = ( items [ i ] . icon_region . size . x = = 0 | | items [ i ] . icon_region . size . y = = 0 ) ? Rect2 ( Vector2 ( ) , items [ i ] . icon - > get_size ( ) ) : Rect2 ( items [ i ] . icon_region ) ;
draw_texture_rect_region ( items [ i ] . icon , draw_rect , region , modulate , items [ i ] . icon_transposed ) ;
2015-06-06 14:44:38 +02:00
}
if ( items [ i ] . tag_icon . is_valid ( ) ) {
2017-06-04 00:25:13 +02:00
draw_texture ( items [ i ] . tag_icon , items [ i ] . rect_cache . position + base_ofs ) ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
if ( items [ i ] . text ! = " " ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
int max_len = - 1 ;
2015-06-06 14:44:38 +02:00
2019-02-12 21:10:08 +01:00
Vector2 size2 = font - > get_string_size ( items [ i ] . text ) ;
2015-06-06 14:44:38 +02:00
if ( fixed_column_width )
2017-03-05 16:44:50 +01:00
max_len = fixed_column_width ;
else if ( same_column_width )
max_len = items [ i ] . rect_cache . size . x ;
2015-06-06 14:44:38 +02:00
else
2019-02-12 21:10:08 +01:00
max_len = size2 . x ;
2015-06-06 14:44:38 +02:00
2017-09-03 09:44:59 +02:00
Color modulate = items [ i ] . selected ? font_color_selected : ( items [ i ] . custom_fg ! = Color ( ) ? items [ i ] . custom_fg : font_color ) ;
2016-07-21 23:24:56 +02:00
if ( items [ i ] . disabled )
2017-03-05 16:44:50 +01:00
modulate . a * = 0.5 ;
2016-07-21 23:24:56 +02:00
2017-03-05 16:44:50 +01:00
if ( icon_mode = = ICON_MODE_TOP & & max_text_lines > 0 ) {
2015-06-06 14:44:38 +02:00
int ss = items [ i ] . text . length ( ) ;
2017-03-05 16:44:50 +01:00
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 ) {
2018-07-25 03:11:03 +02:00
line_limit_cache . write [ line ] = j ;
line_size_cache . write [ line ] = ofs ;
2015-06-06 14:44:38 +02:00
line + + ;
2017-03-05 16:44:50 +01:00
ofs = 0 ;
if ( line > = max_text_lines )
2015-06-06 14:44:38 +02:00
break ;
} else {
2017-03-05 16:44:50 +01:00
ofs + = cs ;
2015-06-06 14:44:38 +02:00
}
}
2017-03-05 16:44:50 +01:00
line = 0 ;
ofs = 0 ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
text_ofs . y + = font - > get_ascent ( ) ;
text_ofs = text_ofs . floor ( ) ;
text_ofs + = base_ofs ;
2017-06-04 00:25:13 +02:00
text_ofs + = items [ i ] . rect_cache . position ;
2015-06-06 14:44:38 +02:00
2018-03-17 09:44:34 +01:00
FontDrawer drawer ( font , Color ( 1 , 1 , 1 ) ) ;
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < ss ; j + + ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
if ( j = = line_limit_cache [ line ] ) {
2015-06-06 14:44:38 +02:00
line + + ;
2017-03-05 16:44:50 +01:00
ofs = 0 ;
if ( line > = max_text_lines )
2015-06-06 14:44:38 +02:00
break ;
}
2018-03-17 09:44:34 +01:00
ofs + = drawer . 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 ] , modulate ) ;
2015-06-06 14:44:38 +02:00
}
//special multiline mode
} else {
2017-03-05 16:44:50 +01:00
if ( fixed_column_width > 0 )
2019-02-12 21:10:08 +01:00
size2 . x = MIN ( size2 . x , fixed_column_width ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
if ( icon_mode = = ICON_MODE_TOP ) {
2019-02-12 21:10:08 +01:00
text_ofs . x + = ( items [ i ] . rect_cache . size . width - size2 . x ) / 2 ;
2015-06-06 14:44:38 +02:00
} else {
2019-02-12 21:10:08 +01:00
text_ofs . y + = ( items [ i ] . rect_cache . size . height - size2 . y ) / 2 ;
2015-06-06 14:44:38 +02:00
}
2017-03-05 16:44:50 +01:00
text_ofs . y + = font - > get_ascent ( ) ;
text_ofs = text_ofs . floor ( ) ;
text_ofs + = base_ofs ;
2017-06-04 00:25:13 +02:00
text_ofs + = items [ i ] . rect_cache . position ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
draw_string ( font , text_ofs , items [ i ] . text , modulate , max_len + 1 ) ;
2015-06-06 14:44:38 +02:00
}
}
2017-03-05 16:44:50 +01:00
if ( select_mode = = SELECT_MULTI & & i = = current ) {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
Rect2 r = rcache ;
2017-06-04 00:25:13 +02:00
r . position + = base_ofs ;
2017-09-27 21:44:48 +02:00
r . position . y - = vseparation / 2 ;
r . size . y + = vseparation ;
r . position . x - = hseparation / 2 ;
r . size . x + = hseparation ;
2017-03-05 16:44:50 +01:00
draw_style_box ( cursor , r ) ;
2015-06-06 14:44:38 +02:00
}
}
2018-01-03 21:11:50 +01:00
int first_visible_separator = 0 ;
{
// do a binary search to find the first separator that is below clip_position.y
int lo = 0 ;
int hi = separators . size ( ) ;
while ( lo < hi ) {
const int mid = ( lo + hi ) / 2 ;
if ( separators [ mid ] < clip . position . y ) {
lo = mid + 1 ;
} else {
hi = mid ;
}
}
first_visible_separator = lo ;
}
for ( int i = first_visible_separator ; i < separators . size ( ) ; i + + ) {
if ( separators [ i ] > clip . position . y + clip . size . y )
break ; // done
const int y = base_ofs . y + separators [ i ] ;
draw_line ( Vector2 ( bg - > get_margin ( MARGIN_LEFT ) , y ) , Vector2 ( width , y ) , guide_color ) ;
2015-06-06 14:44:38 +02:00
}
}
}
void ItemList : : _scroll_changed ( double ) {
update ( ) ;
}
2017-09-10 15:37:49 +02:00
int ItemList : : get_item_at_position ( const Point2 & p_pos , bool p_exact ) const {
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
Vector2 pos = p_pos ;
2015-06-06 14:44:38 +02:00
Ref < StyleBox > bg = get_stylebox ( " bg " ) ;
2017-03-05 16:44:50 +01:00
pos - = bg - > get_offset ( ) ;
pos . y + = scroll_bar - > get_value ( ) ;
2015-06-06 14:44:38 +02:00
int closest = - 1 ;
2017-03-05 16:44:50 +01:00
int closest_dist = 0x7FFFFFFF ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < items . size ( ) ; i + + ) {
2015-06-06 14:44:38 +02:00
Rect2 rc = items [ i ] . rect_cache ;
2017-03-05 16:44:50 +01:00
if ( i % current_columns = = current_columns - 1 ) {
2019-06-01 14:42:13 +02:00
rc . size . width = get_size ( ) . width - rc . position . x ; //make sure you can still select the last item when clicking past the column
2015-06-06 14:44:38 +02:00
}
if ( rc . has_point ( pos ) ) {
2017-03-05 16:44:50 +01:00
closest = i ;
2015-06-06 14:44:38 +02:00
break ;
}
float dist = rc . distance_to ( pos ) ;
2017-03-05 16:44:50 +01:00
if ( ! p_exact & & dist < closest_dist ) {
closest = i ;
closest_dist = dist ;
2015-06-06 14:44:38 +02:00
}
}
2016-05-11 16:46:08 +02:00
return closest ;
}
2017-03-05 16:44:50 +01:00
bool ItemList : : is_pos_at_end_of_items ( const Point2 & p_pos ) const {
2017-02-20 03:19:30 +01:00
if ( items . empty ( ) )
return true ;
2017-03-05 16:44:50 +01:00
Vector2 pos = p_pos ;
2017-02-20 03:19:30 +01:00
Ref < StyleBox > bg = get_stylebox ( " bg " ) ;
2017-03-05 16:44:50 +01:00
pos - = bg - > get_offset ( ) ;
pos . y + = scroll_bar - > get_value ( ) ;
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
Rect2 endrect = items [ items . size ( ) - 1 ] . rect_cache ;
2017-06-04 00:25:13 +02:00
return ( pos . y > endrect . position . y + endrect . size . y ) ;
2017-02-20 03:19:30 +01:00
}
2017-03-05 16:44:50 +01:00
String ItemList : : get_tooltip ( const Point2 & p_pos ) const {
2016-05-11 16:46:08 +02:00
2018-01-02 04:46:32 +01:00
int closest = get_item_at_position ( p_pos , true ) ;
2016-05-11 16:46:08 +02:00
2017-03-05 16:44:50 +01:00
if ( closest ! = - 1 ) {
2016-09-07 17:21:20 +02:00
if ( ! items [ closest ] . tooltip_enabled ) {
return " " ;
}
2017-03-05 16:44:50 +01:00
if ( items [ closest ] . tooltip ! = " " ) {
2015-06-06 14:44:38 +02:00
return items [ closest ] . tooltip ;
}
2017-03-05 16:44:50 +01:00
if ( items [ closest ] . text ! = " " ) {
2015-06-06 14:44:38 +02:00
return items [ closest ] . text ;
}
}
return Control : : get_tooltip ( p_pos ) ;
}
2015-06-22 05:03:19 +02:00
void ItemList : : sort_items_by_text ( ) {
2016-07-22 07:45:52 +02:00
2015-06-22 05:03:19 +02:00
items . sort ( ) ;
update ( ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
2016-07-22 07:45:52 +02:00
2017-03-05 16:44:50 +01:00
if ( select_mode = = SELECT_SINGLE ) {
for ( int i = 0 ; i < items . size ( ) ; i + + ) {
2015-06-22 05:03:19 +02:00
if ( items [ i ] . selected ) {
select ( i ) ;
return ;
}
}
}
}
2017-03-05 16:44:50 +01:00
int ItemList : : find_metadata ( const Variant & p_metadata ) const {
2015-06-22 05:03:19 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < items . size ( ) ; i + + ) {
if ( items [ i ] . metadata = = p_metadata ) {
2015-06-22 05:03:19 +02:00
return i ;
}
}
return - 1 ;
}
2015-06-06 14:44:38 +02:00
2016-05-16 01:25:51 +02:00
void ItemList : : set_allow_rmb_select ( bool p_allow ) {
2018-02-14 04:24:57 +01:00
2017-03-05 16:44:50 +01:00
allow_rmb_select = p_allow ;
2016-05-16 01:25:51 +02:00
}
bool ItemList : : get_allow_rmb_select ( ) const {
return allow_rmb_select ;
}
2018-02-14 04:24:57 +01:00
void ItemList : : set_allow_reselect ( bool p_allow ) {
allow_reselect = p_allow ;
}
bool ItemList : : get_allow_reselect ( ) const {
return allow_reselect ;
}
2016-05-27 18:54:46 +02:00
void ItemList : : set_icon_scale ( real_t p_scale ) {
icon_scale = p_scale ;
2016-05-24 19:09:58 +02:00
}
2016-05-27 18:54:46 +02:00
real_t ItemList : : get_icon_scale ( ) const {
return icon_scale ;
2016-05-24 19:09:58 +02:00
}
2016-06-28 19:09:17 +02:00
Vector < int > ItemList : : get_selected_items ( ) {
Vector < int > selected ;
for ( int i = 0 ; i < items . size ( ) ; i + + ) {
if ( items [ i ] . selected ) {
selected . push_back ( i ) ;
if ( this - > select_mode = = SELECT_SINGLE ) {
break ;
}
}
}
return selected ;
}
2017-11-24 14:39:02 +01:00
bool ItemList : : is_anything_selected ( ) {
for ( int i = 0 ; i < items . size ( ) ; i + + ) {
if ( items [ i ] . selected )
return true ;
}
return false ;
}
2017-07-04 13:38:56 +02:00
void ItemList : : _set_items ( const Array & p_items ) {
ERR_FAIL_COND ( p_items . size ( ) % 3 ) ;
clear ( ) ;
for ( int i = 0 ; i < p_items . size ( ) ; i + = 3 ) {
String text = p_items [ i + 0 ] ;
Ref < Texture > icon = p_items [ i + 1 ] ;
bool disabled = p_items [ i + 2 ] ;
int idx = get_item_count ( ) ;
add_item ( text , icon ) ;
set_item_disabled ( idx , disabled ) ;
}
}
Array ItemList : : _get_items ( ) const {
Array items ;
for ( int i = 0 ; i < get_item_count ( ) ; i + + ) {
items . push_back ( get_item_text ( i ) ) ;
items . push_back ( get_item_icon ( i ) ) ;
items . push_back ( is_item_disabled ( i ) ) ;
}
return items ;
}
2017-07-21 08:17:06 +02:00
Size2 ItemList : : get_minimum_size ( ) const {
if ( auto_height ) {
return Size2 ( 0 , auto_height_value ) ;
}
return Size2 ( ) ;
}
2017-12-17 23:16:11 +01:00
void ItemList : : set_autoscroll_to_bottom ( const bool p_enable ) {
do_autoscroll_to_bottom = p_enable ;
}
2017-07-21 08:17:06 +02:00
void ItemList : : set_auto_height ( bool p_enable ) {
auto_height = p_enable ;
shape_changed = true ;
update ( ) ;
}
bool ItemList : : has_auto_height ( ) const {
return auto_height ;
}
2017-03-05 16:44:50 +01:00
void ItemList : : _bind_methods ( ) {
2015-06-06 14:44:38 +02:00
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_item " , " text " , " icon " , " selectable " ) , & ItemList : : add_item , DEFVAL ( Variant ( ) ) , DEFVAL ( true ) ) ;
ClassDB : : bind_method ( D_METHOD ( " add_icon_item " , " icon " , " selectable " ) , & ItemList : : add_icon_item , DEFVAL ( true ) ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_item_text " , " idx " , " text " ) , & ItemList : : set_item_text ) ;
ClassDB : : bind_method ( D_METHOD ( " get_item_text " , " idx " ) , & ItemList : : get_item_text ) ;
2015-06-06 14:44:38 +02:00
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_item_icon " , " idx " , " icon " ) , & ItemList : : set_item_icon ) ;
ClassDB : : bind_method ( D_METHOD ( " get_item_icon " , " idx " ) , & ItemList : : get_item_icon ) ;
2015-06-06 14:44:38 +02:00
2018-10-29 17:16:18 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_item_icon_transposed " , " idx " , " rect " ) , & ItemList : : set_item_icon_transposed ) ;
ClassDB : : bind_method ( D_METHOD ( " is_item_icon_transposed " , " idx " ) , & ItemList : : is_item_icon_transposed ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_item_icon_region " , " idx " , " rect " ) , & ItemList : : set_item_icon_region ) ;
ClassDB : : bind_method ( D_METHOD ( " get_item_icon_region " , " idx " ) , & ItemList : : get_item_icon_region ) ;
2016-03-13 16:23:49 +01:00
2018-03-11 15:59:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_item_icon_modulate " , " idx " , " modulate " ) , & ItemList : : set_item_icon_modulate ) ;
ClassDB : : bind_method ( D_METHOD ( " get_item_icon_modulate " , " idx " ) , & ItemList : : get_item_icon_modulate ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_item_selectable " , " idx " , " selectable " ) , & ItemList : : set_item_selectable ) ;
ClassDB : : bind_method ( D_METHOD ( " is_item_selectable " , " idx " ) , & ItemList : : is_item_selectable ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_item_disabled " , " idx " , " disabled " ) , & ItemList : : set_item_disabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_item_disabled " , " idx " ) , & ItemList : : is_item_disabled ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_item_metadata " , " idx " , " metadata " ) , & ItemList : : set_item_metadata ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_item_metadata " , " idx " ) , & ItemList : : get_item_metadata ) ;
2015-06-22 05:03:19 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_item_custom_bg_color " , " idx " , " custom_bg_color " ) , & ItemList : : set_item_custom_bg_color ) ;
ClassDB : : bind_method ( D_METHOD ( " get_item_custom_bg_color " , " idx " ) , & ItemList : : get_item_custom_bg_color ) ;
2015-06-22 05:03:19 +02:00
2018-08-17 13:46:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_item_custom_fg_color " , " idx " , " custom_fg_color " ) , & ItemList : : set_item_custom_fg_color ) ;
ClassDB : : bind_method ( D_METHOD ( " get_item_custom_fg_color " , " idx " ) , & ItemList : : get_item_custom_fg_color ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_item_tooltip_enabled " , " idx " , " enable " ) , & ItemList : : set_item_tooltip_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_item_tooltip_enabled " , " idx " ) , & ItemList : : is_item_tooltip_enabled ) ;
2016-09-07 17:21:20 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_item_tooltip " , " idx " , " tooltip " ) , & ItemList : : set_item_tooltip ) ;
ClassDB : : bind_method ( D_METHOD ( " get_item_tooltip " , " idx " ) , & ItemList : : get_item_tooltip ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " select " , " idx " , " single " ) , & ItemList : : select , DEFVAL ( true ) ) ;
ClassDB : : bind_method ( D_METHOD ( " unselect " , " idx " ) , & ItemList : : unselect ) ;
2018-03-13 16:46:25 +01:00
ClassDB : : bind_method ( D_METHOD ( " unselect_all " ) , & ItemList : : unselect_all ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " is_selected " , " idx " ) , & ItemList : : is_selected ) ;
ClassDB : : bind_method ( D_METHOD ( " get_selected_items " ) , & ItemList : : get_selected_items ) ;
2015-06-06 14:44:38 +02:00
2018-03-23 18:57:58 +01:00
ClassDB : : bind_method ( D_METHOD ( " move_item " , " from_idx " , " to_idx " ) , & ItemList : : move_item ) ;
2018-03-13 15:19:04 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_item_count " ) , & ItemList : : get_item_count ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_item " , " idx " ) , & ItemList : : remove_item ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " clear " ) , & ItemList : : clear ) ;
ClassDB : : bind_method ( D_METHOD ( " sort_items_by_text " ) , & ItemList : : sort_items_by_text ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_fixed_column_width " , " width " ) , & ItemList : : set_fixed_column_width ) ;
ClassDB : : bind_method ( D_METHOD ( " get_fixed_column_width " ) , & ItemList : : get_fixed_column_width ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_same_column_width " , " enable " ) , & ItemList : : set_same_column_width ) ;
ClassDB : : bind_method ( D_METHOD ( " is_same_column_width " ) , & ItemList : : is_same_column_width ) ;
2016-05-27 21:42:51 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_max_text_lines " , " lines " ) , & ItemList : : set_max_text_lines ) ;
ClassDB : : bind_method ( D_METHOD ( " get_max_text_lines " ) , & ItemList : : get_max_text_lines ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_max_columns " , " amount " ) , & ItemList : : set_max_columns ) ;
ClassDB : : bind_method ( D_METHOD ( " get_max_columns " ) , & ItemList : : get_max_columns ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_select_mode " , " mode " ) , & ItemList : : set_select_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_select_mode " ) , & ItemList : : get_select_mode ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_icon_mode " , " mode " ) , & ItemList : : set_icon_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_icon_mode " ) , & ItemList : : get_icon_mode ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_fixed_icon_size " , " size " ) , & ItemList : : set_fixed_icon_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_fixed_icon_size " ) , & ItemList : : get_fixed_icon_size ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_icon_scale " , " scale " ) , & ItemList : : set_icon_scale ) ;
ClassDB : : bind_method ( D_METHOD ( " get_icon_scale " ) , & ItemList : : get_icon_scale ) ;
2016-05-15 04:48:23 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_allow_rmb_select " , " allow " ) , & ItemList : : set_allow_rmb_select ) ;
ClassDB : : bind_method ( D_METHOD ( " get_allow_rmb_select " ) , & ItemList : : get_allow_rmb_select ) ;
2016-05-24 19:09:58 +02:00
2018-02-14 04:24:57 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_allow_reselect " , " allow " ) , & ItemList : : set_allow_reselect ) ;
ClassDB : : bind_method ( D_METHOD ( " get_allow_reselect " ) , & ItemList : : get_allow_reselect ) ;
2017-07-21 08:17:06 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_auto_height " , " enable " ) , & ItemList : : set_auto_height ) ;
ClassDB : : bind_method ( D_METHOD ( " has_auto_height " ) , & ItemList : : has_auto_height ) ;
2018-03-11 03:01:16 +01:00
ClassDB : : bind_method ( D_METHOD ( " is_anything_selected " ) , & ItemList : : is_anything_selected ) ;
2017-09-10 15:37:49 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_item_at_position " , " position " , " exact " ) , & ItemList : : get_item_at_position , DEFVAL ( false ) ) ;
2016-05-16 01:25:51 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " ensure_current_is_visible " ) , & ItemList : : ensure_current_is_visible ) ;
2016-05-11 16:46:08 +02:00
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_v_scroll " ) , & ItemList : : get_v_scroll ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " _scroll_changed " ) , & ItemList : : _scroll_changed ) ;
ClassDB : : bind_method ( D_METHOD ( " _gui_input " ) , & ItemList : : _gui_input ) ;
2016-09-09 16:20:57 +02:00
2017-07-04 13:38:56 +02:00
ClassDB : : bind_method ( D_METHOD ( " _set_items " ) , & ItemList : : _set_items ) ;
ClassDB : : bind_method ( D_METHOD ( " _get_items " ) , & ItemList : : _get_items ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : ARRAY , " items " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL ) , " _set_items " , " _get_items " ) ;
2017-07-04 13:38:56 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " select_mode " , PROPERTY_HINT_ENUM , " Single,Multi " ) , " set_select_mode " , " get_select_mode " ) ;
2018-02-14 04:24:57 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " allow_reselect " ) , " set_allow_reselect " , " get_allow_reselect " ) ;
2018-11-08 15:30:02 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " allow_rmb_select " ) , " set_allow_rmb_select " , " get_allow_rmb_select " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " max_text_lines " ) , " set_max_text_lines " , " get_max_text_lines " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " auto_height " ) , " set_auto_height " , " has_auto_height " ) ;
2017-07-04 13:38:56 +02:00
ADD_GROUP ( " Columns " , " " ) ;
2018-11-08 15:30:02 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " max_columns " ) , " set_max_columns " , " get_max_columns " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " same_column_width " ) , " set_same_column_width " , " is_same_column_width " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " fixed_column_width " ) , " set_fixed_column_width " , " get_fixed_column_width " ) ;
2017-07-04 13:38:56 +02:00
ADD_GROUP ( " Icon " , " " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " icon_mode " , PROPERTY_HINT_ENUM , " Top,Left " ) , " set_icon_mode " , " get_icon_mode " ) ;
2018-11-08 15:30:02 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : REAL , " icon_scale " ) , " set_icon_scale " , " get_icon_scale " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " fixed_icon_size " ) , " set_fixed_icon_size " , " get_fixed_icon_size " ) ;
2017-07-04 13:38:56 +02:00
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( ICON_MODE_TOP ) ;
BIND_ENUM_CONSTANT ( ICON_MODE_LEFT ) ;
BIND_ENUM_CONSTANT ( SELECT_SINGLE ) ;
BIND_ENUM_CONSTANT ( SELECT_MULTI ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
ADD_SIGNAL ( MethodInfo ( " item_selected " , PropertyInfo ( Variant : : INT , " index " ) ) ) ;
2017-09-10 15:37:49 +02:00
ADD_SIGNAL ( MethodInfo ( " item_rmb_selected " , PropertyInfo ( Variant : : INT , " index " ) , PropertyInfo ( Variant : : VECTOR2 , " at_position " ) ) ) ;
2017-03-05 16:44:50 +01:00
ADD_SIGNAL ( MethodInfo ( " multi_selected " , PropertyInfo ( Variant : : INT , " index " ) , PropertyInfo ( Variant : : BOOL , " selected " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " item_activated " , PropertyInfo ( Variant : : INT , " index " ) ) ) ;
2017-11-20 19:25:13 +01:00
ADD_SIGNAL ( MethodInfo ( " rmb_clicked " , PropertyInfo ( Variant : : VECTOR2 , " at_position " ) ) ) ;
2017-11-24 14:39:02 +01:00
ADD_SIGNAL ( MethodInfo ( " nothing_selected " ) ) ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
GLOBAL_DEF ( " gui/timers/incremental_search_max_interval_msec " , 2000 ) ;
2018-10-05 18:43:53 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " gui/timers/incremental_search_max_interval_msec " , PropertyInfo ( Variant : : INT , " gui/timers/incremental_search_max_interval_msec " , PROPERTY_HINT_RANGE , " 0,10000,1,or_greater " ) ) ; // No negative numbers
2015-06-06 14:44:38 +02:00
}
ItemList : : ItemList ( ) {
2017-03-05 16:44:50 +01:00
current = - 1 ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
select_mode = SELECT_SINGLE ;
icon_mode = ICON_MODE_LEFT ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
fixed_column_width = 0 ;
2016-05-27 21:42:51 +02:00
same_column_width = false ;
2017-03-05 16:44:50 +01:00
max_text_lines = 1 ;
max_columns = 1 ;
2017-07-21 08:17:06 +02:00
auto_height = false ;
auto_height_value = 0.0f ;
2015-06-06 14:44:38 +02:00
2017-03-05 16:44:50 +01:00
scroll_bar = memnew ( VScrollBar ) ;
2015-06-06 14:44:38 +02:00
add_child ( scroll_bar ) ;
2017-03-05 16:44:50 +01:00
shape_changed = true ;
scroll_bar - > connect ( " value_changed " , this , " _scroll_changed " ) ;
2015-06-06 14:44:38 +02:00
set_focus_mode ( FOCUS_ALL ) ;
2017-03-05 16:44:50 +01:00
current_columns = 1 ;
search_time_msec = 0 ;
ensure_selected_visible = false ;
defer_select_single = - 1 ;
allow_rmb_select = false ;
2018-02-14 04:24:57 +01:00
allow_reselect = false ;
2017-12-17 23:16:11 +01:00
do_autoscroll_to_bottom = false ;
2015-06-06 14:44:38 +02:00
2016-05-27 18:54:46 +02:00
icon_scale = 1.0f ;
2017-10-31 10:58:53 +01:00
set_clip_contents ( true ) ;
2015-06-06 14:44:38 +02:00
}
ItemList : : ~ ItemList ( ) {
}