diff options
-rw-r--r-- | core/bind/core_bind.cpp | 181 | ||||
-rw-r--r-- | core/bind/core_bind.h | 4 | ||||
-rw-r--r-- | doc/base/classes.xml | 32 | ||||
-rw-r--r-- | drivers/unix/os_unix.cpp | 1 | ||||
-rw-r--r-- | scene/gui/text_edit.cpp | 58 | ||||
-rw-r--r-- | scene/gui/text_edit.h | 5 | ||||
-rw-r--r-- | scene/gui/tree.cpp | 10 | ||||
-rw-r--r-- | tools/editor/editor_settings.cpp | 3 | ||||
-rw-r--r-- | tools/editor/plugins/script_editor_plugin.cpp | 6 |
9 files changed, 269 insertions, 31 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 915cbc0578..1eb7f790a3 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -14,6 +14,20 @@ #define SECS_DAY (24L * 60L * 60L) #define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400))) #define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365) +#define SECOND_KEY "second" +#define MINUTE_KEY "minute" +#define HOUR_KEY "hour" +#define DAY_KEY "day" +#define MONTH_KEY "month" +#define YEAR_KEY "year" +#define WEEKDAY_KEY "weekday" +#define DST_KEY "dst" + +/// Table of number of days in each month (for regular year and leap year) +static const unsigned int MONTH_DAYS_TABLE[2][12] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; _ResourceLoader *_ResourceLoader::singleton=NULL; @@ -485,15 +499,34 @@ void _OS::set_icon(const Image& p_icon) { OS::get_singleton()->set_icon(p_icon); } +/** + * Get current datetime with consideration for utc and + * dst + */ +Dictionary _OS::get_datetime(bool utc) const { + + Dictionary dated = get_date(utc); + Dictionary timed = get_time(utc); + + List<Variant> keys; + timed.get_key_list(&keys); + + for(int i = 0; i < keys.size(); i++) { + dated[keys[i]] = timed[keys[i]]; + } + + return dated; +} + Dictionary _OS::get_date(bool utc) const { OS::Date date = OS::get_singleton()->get_date(utc); Dictionary dated; - dated["year"]=date.year; - dated["month"]=date.month; - dated["day"]=date.day; - dated["weekday"]=date.weekday; - dated["dst"]=date.dst; + dated[YEAR_KEY]=date.year; + dated[MONTH_KEY]=date.month; + dated[DAY_KEY]=date.day; + dated[WEEKDAY_KEY]=date.weekday; + dated[DST_KEY]=date.dst; return dated; } @@ -501,20 +534,117 @@ Dictionary _OS::get_time(bool utc) const { OS::Time time = OS::get_singleton()->get_time(utc); Dictionary timed; - timed["hour"]=time.hour; - timed["minute"]=time.min; - timed["second"]=time.sec; + timed[HOUR_KEY]=time.hour; + timed[MINUTE_KEY]=time.min; + timed[SECOND_KEY]=time.sec; return timed; } /** + * Get a epoch time value from a dictionary of time values + * @p datetime must be populated with the following keys: + * day, hour, minute, month, second, year. (dst is ignored). + * + * You can pass the output from + * get_datetime_from_unix_time directly into this function + * + * @param datetime dictionary of date and time values to convert + * + * @return epoch calculated + */ +uint64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { + + // Bunch of conversion constants + static const unsigned int SECONDS_PER_MINUTE = 60; + static const unsigned int MINUTES_PER_HOUR = 60; + static const unsigned int HOURS_PER_DAY = 24; + static const unsigned int SECONDS_PER_HOUR = MINUTES_PER_HOUR * + SECONDS_PER_MINUTE; + static const unsigned int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY; + + // Get all time values from the dictionary, set to zero if it doesn't exist. + // Risk incorrect calculation over throwing errors + unsigned int second = ((datetime.has(SECOND_KEY))? + static_cast<unsigned int>(datetime[SECOND_KEY]): 0); + unsigned int minute = ((datetime.has(MINUTE_KEY))? + static_cast<unsigned int>(datetime[MINUTE_KEY]): 0); + unsigned int hour = ((datetime.has(HOUR_KEY))? + static_cast<unsigned int>(datetime[HOUR_KEY]): 0); + unsigned int day = ((datetime.has(DAY_KEY))? + static_cast<unsigned int>(datetime[DAY_KEY]): 0); + unsigned int month = ((datetime.has(MONTH_KEY))? + static_cast<unsigned int>(datetime[MONTH_KEY]) -1: 0); + unsigned int year = ((datetime.has(YEAR_KEY))? + static_cast<unsigned int>(datetime[YEAR_KEY]):0); + + /// How many days come before each month (0-12) + static const unsigned short int DAYS_PAST_THIS_YEAR_TABLE[2][13] = + { + /* Normal years. */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* Leap years. */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } + }; + + ERR_EXPLAIN("Invalid second value of: " + itos(second)); + ERR_FAIL_COND_V( second > 59, 0); + + ERR_EXPLAIN("Invalid minute value of: " + itos(minute)); + ERR_FAIL_COND_V( minute > 59, 0); + + ERR_EXPLAIN("Invalid hour value of: " + itos(hour)); + ERR_FAIL_COND_V( hour > 23, 0); + + ERR_EXPLAIN("Invalid month value of: " + itos(month+1)); + ERR_FAIL_COND_V( month+1 > 12, 0); + + // Do this check after month is tested as valid + ERR_EXPLAIN("Invalid day value of: " + itos(day) + " which is larger " + "than "+ itos(MONTH_DAYS_TABLE[LEAPYEAR(year)][month])); + ERR_FAIL_COND_V( day > MONTH_DAYS_TABLE[LEAPYEAR(year)][month], 0); + + // Calculate all the seconds from months past in this year + uint64_t SECONDS_FROM_MONTHS_PAST_THIS_YEAR = + DAYS_PAST_THIS_YEAR_TABLE[LEAPYEAR(year)][month] * SECONDS_PER_DAY; + + uint64_t SECONDS_FROM_YEARS_PAST = 0; + for(unsigned int iyear = EPOCH_YR; iyear < year; iyear++) { + + SECONDS_FROM_YEARS_PAST += YEARSIZE(iyear) * + SECONDS_PER_DAY; + } + + uint64_t epoch = + second + + minute * SECONDS_PER_MINUTE + + hour * SECONDS_PER_HOUR + + // Subtract 1 from day, since the current day isn't over yet + // and we cannot count all 24 hours. + (day-1) * SECONDS_PER_DAY + + SECONDS_FROM_MONTHS_PAST_THIS_YEAR + + SECONDS_FROM_YEARS_PAST; + return epoch; + +} + +/** * Get a dictionary of time values when given epoch time * * Dictionary Time values will be a union if values from #get_time * and #get_date dictionaries (with the exception of dst = * day light standard time, as it cannot be determined from epoch) + * + * @param unix_time_val epoch time to convert + * + * @return dictionary of date and time values */ -Dictionary _OS::get_time_from_unix_time( uint64_t unix_time_val) const { +Dictionary _OS::get_datetime_from_unix_time( uint64_t unix_time_val) const { + + // Just fail if unix time is negative (when interpreted as an int). + // This means the user passed in a negative value by accident + ERR_EXPLAIN("unix_time_val was really huge!"+ itos(unix_time_val) + + " You probably passed in a negative value!"); + ERR_FAIL_COND_V( (int64_t)unix_time_val < 0, Dictionary()); OS::Date date; OS::Time time; @@ -539,16 +669,10 @@ Dictionary _OS::get_time_from_unix_time( uint64_t unix_time_val) const { date.year = year; - // Table of number of days in each month (for regular year and leap year) - const unsigned int _ytab[2][12] = { - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } - }; - size_t imonth = 0; - while (dayno >= _ytab[LEAPYEAR(year)][imonth]) { - dayno -= _ytab[LEAPYEAR(year)][imonth]; + while (dayno >= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]) { + dayno -= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]; imonth++; } @@ -558,13 +682,13 @@ Dictionary _OS::get_time_from_unix_time( uint64_t unix_time_val) const { date.day = dayno + 1; Dictionary timed; - timed["hour"]=time.hour; - timed["minute"]=time.min; - timed["second"]=time.sec; - timed["year"]=date.year; - timed["month"]=date.month; - timed["day"]=date.day; - timed["weekday"]=date.weekday; + timed[HOUR_KEY]=time.hour; + timed[MINUTE_KEY]=time.min; + timed[SECOND_KEY]=time.sec; + timed[YEAR_KEY]=date.year; + timed[MONTH_KEY]=date.month; + timed[DAY_KEY]=date.day; + timed[WEEKDAY_KEY]=date.weekday; return timed; } @@ -580,7 +704,7 @@ Dictionary _OS::get_time_zone_info() const { uint64_t _OS::get_unix_time() const { return OS::get_singleton()->get_unix_time(); -}; +} uint64_t _OS::get_system_time_secs() const { return OS::get_singleton()->get_system_time_secs(); @@ -912,12 +1036,15 @@ void _OS::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_cmdline_args"),&_OS::get_cmdline_args); ObjectTypeDB::bind_method(_MD("get_main_loop"),&_OS::get_main_loop); + ObjectTypeDB::bind_method(_MD("get_datetime","utc"),&_OS::get_datetime,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("get_date","utc"),&_OS::get_date,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("get_time","utc"),&_OS::get_time,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("get_time_zone_info"),&_OS::get_time_zone_info); ObjectTypeDB::bind_method(_MD("get_unix_time"),&_OS::get_unix_time); - ObjectTypeDB::bind_method(_MD("get_time_from_unix_time", "unix_time_val"), - &_OS::get_time_from_unix_time); + ObjectTypeDB::bind_method(_MD("get_datetime_from_unix_time", "unix_time_val"), + &_OS::get_datetime_from_unix_time); + ObjectTypeDB::bind_method(_MD("get_unix_time_from_datetime", "datetime"), + &_OS::get_unix_time_from_datetime); ObjectTypeDB::bind_method(_MD("get_system_time_secs"), &_OS::get_system_time_secs); ObjectTypeDB::bind_method(_MD("set_icon","icon"),&_OS::set_icon); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index db5ff42cfe..0c768651ff 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -212,7 +212,9 @@ public: void set_icon(const Image& p_icon); Dictionary get_date(bool utc) const; Dictionary get_time(bool utc) const; - Dictionary get_time_from_unix_time(uint64_t unix_time_val) const; + Dictionary get_datetime(bool utc) const; + Dictionary get_datetime_from_unix_time(uint64_t unix_time_val) const; + uint64_t get_unix_time_from_datetime(Dictionary datetime) const; Dictionary get_time_zone_info() const; uint64_t get_unix_time() const; uint64_t get_system_time_secs() const; diff --git a/doc/base/classes.xml b/doc/base/classes.xml index bc8bec4bbf..0a4ed7c845 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -20629,6 +20629,18 @@ Example: (content-length:12), (Content-Type:application/json; charset=UTF-8) <argument index="0" name="utc" type="bool" default="false"> </argument> <description> + Returns current date in a dictionary of keys: year, month, + day, weekday, dst (daylight savings time). + </description> + </method> + <method name="get_datetime" qualifiers="const"> + <return type="Dictionary"> + </return> + <argument index="0" name="utc" type="bool" default="false"> + </argument> + <description> + Returns current datetime in a dictionary of keys: year, + month, day, weekday, dst (daylight savings time), hour, minute, second </description> </method> <method name="get_time" qualifiers="const"> @@ -20637,9 +20649,11 @@ Example: (content-length:12), (Content-Type:application/json; charset=UTF-8) <argument index="0" name="utc" type="bool" default="false"> </argument> <description> + Returns current time in a dictionary of keys: + hour, minute, second </description> </method> - <method name="get_time_from_unix_time" qualifiers="const"> + <method name="get_datetime_from_unix_time" qualifiers="const"> <return type="Dictionary"> </return> <argument index="0" name="unix_time_val" type="int"> @@ -20651,6 +20665,22 @@ Example: (content-length:12), (Content-Type:application/json; charset=UTF-8) day light standard time, as it cannot be determined from epoc) </description> </method> + <method name="get_unix_time_from_datetime" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="datetime" type="Dictionary"> + </argument> + <description> + Get an epoch time value from a dictionary of time values + datetime must be populated with the following keys: + day, hour, minute, month, second, year. You can pass the output from + [method get_datetime_from_unix_time] directly into this function. Day + light savings time (dst), if present, is ignored. + + To be accurate, datetime dictionary must have keys for: year, month, day, + hour, minute, second + </description> + </method> <method name="get_time_zone_info" qualifiers="const"> <return type="Dictionary"> </return> diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 84b6dc24dc..359758290f 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -261,6 +261,7 @@ OS::Date OS_Unix::get_date(bool utc) const { return ret; } + OS::Time OS_Unix::get_time(bool utc) const { time_t t=time(NULL); struct tm *lt; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index b80597560d..0fc8e39fef 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -643,6 +643,9 @@ void TextEdit::_notification(int p_what) { int deregion=0; //force it to clear inrgion Point2 cursor_pos; + // get the highlighted words + String highlighted_text = get_selection_text(); + for (int i=0;i<visible_rows;i++) { int line=i+cursor.line_ofs; @@ -659,6 +662,12 @@ void TextEdit::_notification(int p_what) { bool in_keyword=false; Color keyword_color; + // check if line contains highlighted word + int highlighted_text_col = -1; + if (highlighted_text.length() != 0) { + highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, 0); + } + if (cache.line_number_w) { Color fcol = cache.font_color; fcol.a*=0.4; @@ -798,6 +807,20 @@ void TextEdit::_notification(int p_what) { VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w,get_row_height())),cache.selection_color); } + if (highlight_all_occurrences) { + if (highlighted_text_col != -1) { + + // if we are at the end check for new word on same line + if (j > highlighted_text_col+highlighted_text.length()) { + highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, j); + } + + bool in_highlighted_word = (j >= highlighted_text_col && j < highlighted_text_col+highlighted_text.length()); + if (in_highlighted_word) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w, get_row_height())),cache.word_highlighted_color); + } + } + } if (brace_matching_enabled) { if ( (brace_open_match_line==line && brace_open_match_column==j) || @@ -2921,6 +2944,7 @@ void TextEdit::_update_caches() { cache.current_line_color=get_color("current_line_color"); cache.breakpoint_color=get_color("breakpoint_color"); cache.brace_mismatch_color=get_color("brace_mismatch_color"); + cache.word_highlighted_color=get_color("word_highlighted_color"); cache.line_spacing=get_constant("line_spacing"); cache.row_height = cache.font->get_height() + cache.line_spacing; cache.tab_icon=get_icon("tab"); @@ -3182,6 +3206,40 @@ String TextEdit::get_word_under_cursor() const { return text[cursor.line].substr(prev_cc, next_cc-prev_cc); } +void TextEdit::set_highlight_all_occurrences(const bool p_enabled) { + highlight_all_occurrences = p_enabled; + update(); +} + +int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_search, int p_from_column) { + int col = -1; + + if (p_key.length() > 0 && p_search.length() > 0) { + if (p_from_column < 0 || p_from_column > p_search.length()) { + p_from_column = 0; + } + + while (col == -1 && p_from_column <= p_search.length()) { + // match case + col = p_search.findn(p_key, p_from_column); + + // whole words only + if (col != -1) { + p_from_column=col; + + if (col > 0 && _is_text_char(p_search[col-1])) { + col = -1; + } else if (_is_text_char(p_search[col+p_key.length()])) { + col = -1; + } + } + + p_from_column+=1; + } + } + return col; +} + DVector<int> TextEdit::_search_bind(const String &p_key,uint32_t p_search_flags, int p_from_line,int p_from_column) const { int col,line; diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index d38c57804d..86696ca5a5 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -81,6 +81,7 @@ class TextEdit : public Control { Color breakpoint_color; Color current_line_color; Color brace_mismatch_color; + Color word_highlighted_color; int row_height; int line_spacing; @@ -212,6 +213,7 @@ class TextEdit : public Control { bool undo_enabled; bool line_numbers; + bool highlight_all_occurrences; bool scroll_past_end_of_file_enabled; bool auto_brace_completion_enabled; bool brace_matching_enabled; @@ -270,6 +272,8 @@ class TextEdit : public Control { String _base_get_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) const; void _base_remove_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column); + int _get_column_pos_of_word(const String &p_key, const String &p_search, int p_from_column); + DVector<int> _search_bind(const String &p_key,uint32_t p_search_flags, int p_from_line,int p_from_column) const; void _clear(); @@ -364,6 +368,7 @@ public: void select(int p_from_line,int p_from_column,int p_to_line,int p_to_column); void deselect(); + void set_highlight_all_occurrences(const bool p_enabled); bool is_selection_active() const; int get_selection_from_line() const; int get_selection_from_column() const; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 483aa47f35..718206dee1 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -2750,6 +2750,15 @@ void Tree::clear() { ERR_FAIL_COND(blocked>0); } + if (pressing_for_editor) { + if (range_drag_enabled) { + range_drag_enabled = false; + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + warp_mouse(range_drag_capture_pos); + } + pressing_for_editor = false; + } + if (root) { memdelete( root ); root = NULL; @@ -2759,7 +2768,6 @@ void Tree::clear() { edited_item=NULL; popup_edited_item=NULL; selected_item=NULL; - pressing_for_editor=false; update(); }; diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp index 1133acb48c..6f1e90936a 100644 --- a/tools/editor/editor_settings.cpp +++ b/tools/editor/editor_settings.cpp @@ -403,11 +403,14 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { set("text_editor/selection_color",Color::html("7b5dbe")); set("text_editor/brace_mismatch_color",Color(1,0.2,0.2)); set("text_editor/current_line_color",Color(0.3,0.5,0.8,0.15)); + set("text_editor/word_highlighted_color",Color(0.8,0.9,0.9,0.15)); + set("text_editor/highlight_all_occurrences", true); set("text_editor/scroll_past_end_of_file", false); set("text_editor/tab_size", 4); hints["text_editor/tab_size"]=PropertyInfo(Variant::INT,"text_editor/tab_size",PROPERTY_HINT_RANGE,"1, 64, 1"); // size of 0 crashes. + set("text_editor/draw_tabs", true); set("text_editor/idle_parse_delay",2); set("text_editor/create_signal_callbacks",true); diff --git a/tools/editor/plugins/script_editor_plugin.cpp b/tools/editor/plugins/script_editor_plugin.cpp index 03db293959..b03a9301b3 100644 --- a/tools/editor/plugins/script_editor_plugin.cpp +++ b/tools/editor/plugins/script_editor_plugin.cpp @@ -292,6 +292,7 @@ void ScriptTextEditor::_load_theme_settings() { get_text_edit()->add_color_override("selection_color",EDITOR_DEF("text_editor/selection_color",Color(0.2,0.2,1))); get_text_edit()->add_color_override("brace_mismatch_color",EDITOR_DEF("text_editor/brace_mismatch_color",Color(1,0.2,0.2))); get_text_edit()->add_color_override("current_line_color",EDITOR_DEF("text_editor/current_line_color",Color(0.3,0.5,0.8,0.15))); + get_text_edit()->add_color_override("word_highlighted_color",EDITOR_DEF("text_editor/word_highlighted_color",Color(0.8,0.9,0.9,0.15))); Color keyword_color= EDITOR_DEF("text_editor/keyword_color",Color(0.5,0.0,0.2)); @@ -580,7 +581,6 @@ void ScriptTextEditor::_bind_methods() { ScriptTextEditor::ScriptTextEditor() { - get_text_edit()->set_draw_tabs(true); } /*** SCRIPT EDITOR ******/ @@ -1931,6 +1931,8 @@ void ScriptEditor::edit(const Ref<Script>& p_script) { ste->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file")); ste->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete")); ste->get_text_edit()->set_tab_size(EditorSettings::get_singleton()->get("text_editor/tab_size")); + ste->get_text_edit()->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/draw_tabs")); + ste->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); ste->get_text_edit()->set_callhint_settings( EditorSettings::get_singleton()->get("text_editor/put_callhint_tooltip_below_current_line"), EditorSettings::get_singleton()->get("text_editor/callhint_tooltip_offset")); @@ -2069,6 +2071,8 @@ void ScriptEditor::_editor_settings_changed() { ste->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete")); ste->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file")); ste->get_text_edit()->set_tab_size(EditorSettings::get_singleton()->get("text_editor/tab_size")); + ste->get_text_edit()->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/draw_tabs")); + ste->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); } } |