|
@@ -359,385 +359,445 @@ void TextEdit::_update_scrollbars() {
|
|
|
|
|
|
void TextEdit::_notification(int p_what) {
|
|
|
|
|
|
- switch(p_what) {
|
|
|
- case NOTIFICATION_ENTER_TREE: {
|
|
|
+ switch(p_what) {
|
|
|
+ case NOTIFICATION_ENTER_TREE: {
|
|
|
|
|
|
- _update_caches();
|
|
|
- if (cursor_changed_dirty)
|
|
|
- MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit");
|
|
|
- if (text_changed_dirty)
|
|
|
- MessageQueue::get_singleton()->push_call(this,"_text_changed_emit");
|
|
|
+ _update_caches();
|
|
|
+ if (cursor_changed_dirty)
|
|
|
+ MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit");
|
|
|
+ if (text_changed_dirty)
|
|
|
+ MessageQueue::get_singleton()->push_call(this,"_text_changed_emit");
|
|
|
|
|
|
- } break;
|
|
|
- case NOTIFICATION_RESIZED: {
|
|
|
+ } break;
|
|
|
+ case NOTIFICATION_RESIZED: {
|
|
|
|
|
|
- cache.size=get_size();
|
|
|
- adjust_viewport_to_cursor();
|
|
|
+ cache.size=get_size();
|
|
|
+ adjust_viewport_to_cursor();
|
|
|
|
|
|
|
|
|
- } break;
|
|
|
- case NOTIFICATION_THEME_CHANGED: {
|
|
|
+ } break;
|
|
|
+ case NOTIFICATION_THEME_CHANGED: {
|
|
|
|
|
|
- _update_caches();
|
|
|
- };
|
|
|
- case NOTIFICATION_DRAW: {
|
|
|
+ _update_caches();
|
|
|
+ };
|
|
|
+ case NOTIFICATION_DRAW: {
|
|
|
|
|
|
- int line_number_char_count=0;
|
|
|
+ int line_number_char_count=0;
|
|
|
|
|
|
- {
|
|
|
- int lc=text.size()+1;
|
|
|
- cache.line_number_w=0;
|
|
|
- while(lc) {
|
|
|
- cache.line_number_w+=1;
|
|
|
- lc/=10;
|
|
|
- };
|
|
|
+ {
|
|
|
+ int lc=text.size()+1;
|
|
|
+ cache.line_number_w=0;
|
|
|
+ while(lc) {
|
|
|
+ cache.line_number_w+=1;
|
|
|
+ lc/=10;
|
|
|
+ };
|
|
|
|
|
|
- if (line_numbers) {
|
|
|
+ if (line_numbers) {
|
|
|
|
|
|
- line_number_char_count=cache.line_number_w;
|
|
|
- cache.line_number_w=(cache.line_number_w+1)*cache.font->get_char_size('0').width;
|
|
|
- } else {
|
|
|
- cache.line_number_w=0;
|
|
|
- }
|
|
|
+ line_number_char_count=cache.line_number_w;
|
|
|
+ cache.line_number_w=(cache.line_number_w+1)*cache.font->get_char_size('0').width;
|
|
|
+ } else {
|
|
|
+ cache.line_number_w=0;
|
|
|
+ }
|
|
|
|
|
|
|
|
|
- }
|
|
|
- _update_scrollbars();
|
|
|
+ }
|
|
|
+ _update_scrollbars();
|
|
|
|
|
|
|
|
|
- RID ci = get_canvas_item();
|
|
|
- int xmargin_beg=cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w;
|
|
|
- int xmargin_end=cache.size.width-cache.style_normal->get_margin(MARGIN_RIGHT);
|
|
|
- //let's do it easy for now:
|
|
|
- cache.style_normal->draw(ci,Rect2(Point2(),cache.size));
|
|
|
- if (has_focus())
|
|
|
- cache.style_focus->draw(ci,Rect2(Point2(),cache.size));
|
|
|
+ RID ci = get_canvas_item();
|
|
|
+ int xmargin_beg=cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w;
|
|
|
+ int xmargin_end=cache.size.width-cache.style_normal->get_margin(MARGIN_RIGHT);
|
|
|
+ //let's do it easy for now:
|
|
|
+ cache.style_normal->draw(ci,Rect2(Point2(),cache.size));
|
|
|
+ if (has_focus())
|
|
|
+ cache.style_focus->draw(ci,Rect2(Point2(),cache.size));
|
|
|
|
|
|
|
|
|
- int ascent=cache.font->get_ascent();
|
|
|
+ int ascent=cache.font->get_ascent();
|
|
|
|
|
|
- int visible_rows = get_visible_rows();
|
|
|
+ int visible_rows = get_visible_rows();
|
|
|
|
|
|
- int tab_w = cache.font->get_char_size(' ').width*tab_size;
|
|
|
+ int tab_w = cache.font->get_char_size(' ').width*tab_size;
|
|
|
|
|
|
- Color color = cache.font_color;
|
|
|
- int in_region=-1;
|
|
|
+ Color color = cache.font_color;
|
|
|
+ int in_region=-1;
|
|
|
|
|
|
- if (syntax_coloring) {
|
|
|
+ if (syntax_coloring) {
|
|
|
|
|
|
- if (custom_bg_color.a>0.01) {
|
|
|
+ if (custom_bg_color.a>0.01) {
|
|
|
|
|
|
- Point2i ofs = Point2i(cache.style_normal->get_offset())/2.0;
|
|
|
- VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(ofs, get_size()-cache.style_normal->get_minimum_size()+ofs),custom_bg_color);
|
|
|
- }
|
|
|
- //compute actual region to start (may be inside say, a comment).
|
|
|
- //slow in very large documments :( but ok for source!
|
|
|
+ Point2i ofs = Point2i(cache.style_normal->get_offset())/2.0;
|
|
|
+ VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(ofs, get_size()-cache.style_normal->get_minimum_size()+ofs),custom_bg_color);
|
|
|
+ }
|
|
|
+ //compute actual region to start (may be inside say, a comment).
|
|
|
+ //slow in very large documments :( but ok for source!
|
|
|
|
|
|
- for(int i=0;i<cursor.line_ofs;i++) {
|
|
|
+ for(int i=0;i<cursor.line_ofs;i++) {
|
|
|
|
|
|
- const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(i);
|
|
|
+ const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(i);
|
|
|
|
|
|
- if (in_region>=0 && color_regions[in_region].line_only) {
|
|
|
- in_region=-1; //reset regions that end at end of line
|
|
|
- }
|
|
|
+ if (in_region>=0 && color_regions[in_region].line_only) {
|
|
|
+ in_region=-1; //reset regions that end at end of line
|
|
|
+ }
|
|
|
|
|
|
- for( const Map<int,Text::ColorRegionInfo>::Element* E= cri_map.front();E;E=E->next() ) {
|
|
|
+ for( const Map<int,Text::ColorRegionInfo>::Element* E= cri_map.front();E;E=E->next() ) {
|
|
|
|
|
|
- const Text::ColorRegionInfo &cri=E->get();
|
|
|
+ const Text::ColorRegionInfo &cri=E->get();
|
|
|
|
|
|
- if (in_region==-1) {
|
|
|
+ if (in_region==-1) {
|
|
|
|
|
|
- if (!cri.end) {
|
|
|
+ if (!cri.end) {
|
|
|
|
|
|
- in_region=cri.region;
|
|
|
- }
|
|
|
- } else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise
|
|
|
+ in_region=cri.region;
|
|
|
+ }
|
|
|
+ } else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise
|
|
|
|
|
|
- if (cri.end || color_regions[cri.region].eq) {
|
|
|
+ if (cri.end || color_regions[cri.region].eq) {
|
|
|
|
|
|
- in_region=-1;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ in_region=-1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- int deregion=0; //force it to clear inrgion
|
|
|
- Point2 cursor_pos;
|
|
|
+ int deregion=0; //force it to clear inrgion
|
|
|
+ Point2 cursor_pos;
|
|
|
|
|
|
- for (int i=0;i<visible_rows;i++) {
|
|
|
+ for (int i=0;i<visible_rows;i++) {
|
|
|
|
|
|
- int line=i+cursor.line_ofs;
|
|
|
+ int line=i+cursor.line_ofs;
|
|
|
|
|
|
- if (line<0 || line>=(int)text.size())
|
|
|
- continue;
|
|
|
+ if (line<0 || line>=(int)text.size())
|
|
|
+ continue;
|
|
|
|
|
|
- const String &str=text[line];
|
|
|
+ const String &str=text[line];
|
|
|
|
|
|
- int char_margin=xmargin_beg-cursor.x_ofs;
|
|
|
- int char_ofs=0;
|
|
|
- int ofs_y=i*get_row_height()+cache.line_spacing/2;
|
|
|
- bool prev_is_char=false;
|
|
|
- bool in_keyword=false;
|
|
|
- Color keyword_color;
|
|
|
+ int char_margin=xmargin_beg-cursor.x_ofs;
|
|
|
+ int char_ofs=0;
|
|
|
+ int ofs_y=i*get_row_height()+cache.line_spacing/2;
|
|
|
+ bool prev_is_char=false;
|
|
|
+ bool in_keyword=false;
|
|
|
+ Color keyword_color;
|
|
|
|
|
|
- if (cache.line_number_w) {
|
|
|
- Color fcol = cache.font_color;
|
|
|
- fcol.a*=0.4;
|
|
|
- String fc = String::num(line+1);
|
|
|
- while (fc.length() < line_number_char_count) {
|
|
|
- fc="0"+fc;
|
|
|
- }
|
|
|
+ if (cache.line_number_w) {
|
|
|
+ Color fcol = cache.font_color;
|
|
|
+ fcol.a*=0.4;
|
|
|
+ String fc = String::num(line+1);
|
|
|
+ while (fc.length() < line_number_char_count) {
|
|
|
+ fc="0"+fc;
|
|
|
+ }
|
|
|
|
|
|
- cache.font->draw(ci,Point2(cache.style_normal->get_margin(MARGIN_LEFT),ofs_y+cache.font->get_ascent()),fc,fcol);
|
|
|
- }
|
|
|
+ cache.font->draw(ci,Point2(cache.style_normal->get_margin(MARGIN_LEFT),ofs_y+cache.font->get_ascent()),fc,fcol);
|
|
|
+ }
|
|
|
|
|
|
- const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(line);
|
|
|
+ const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(line);
|
|
|
|
|
|
|
|
|
- if (text.is_marked(line)) {
|
|
|
+ if (text.is_marked(line)) {
|
|
|
|
|
|
- VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.mark_color);
|
|
|
- }
|
|
|
+ VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.mark_color);
|
|
|
+ }
|
|
|
|
|
|
- if (text.is_breakpoint(line)) {
|
|
|
+ if (text.is_breakpoint(line)) {
|
|
|
|
|
|
- VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.breakpoint_color);
|
|
|
- }
|
|
|
+ VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.breakpoint_color);
|
|
|
+ }
|
|
|
|
|
|
|
|
|
- if (line==cursor.line) {
|
|
|
+ if (line==cursor.line) {
|
|
|
|
|
|
- VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.current_line_color);
|
|
|
+ VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.current_line_color);
|
|
|
|
|
|
- }
|
|
|
- for (int j=0;j<str.length();j++) {
|
|
|
+ }
|
|
|
+ for (int j=0;j<str.length();j++) {
|
|
|
|
|
|
- //look for keyword
|
|
|
+ //look for keyword
|
|
|
|
|
|
- if (deregion>0) {
|
|
|
- deregion--;
|
|
|
- if (deregion==0)
|
|
|
- in_region=-1;
|
|
|
- }
|
|
|
- if (syntax_coloring && deregion==0) {
|
|
|
+ if (deregion>0) {
|
|
|
+ deregion--;
|
|
|
+ if (deregion==0)
|
|
|
+ in_region=-1;
|
|
|
+ }
|
|
|
+ if (syntax_coloring && deregion==0) {
|
|
|
|
|
|
|
|
|
- color = cache.font_color; //reset
|
|
|
- //find keyword
|
|
|
- bool is_char = _is_text_char(str[j]);
|
|
|
- bool is_symbol=_is_symbol(str[j]);
|
|
|
+ color = cache.font_color; //reset
|
|
|
+ //find keyword
|
|
|
+ bool is_char = _is_text_char(str[j]);
|
|
|
+ bool is_symbol=_is_symbol(str[j]);
|
|
|
|
|
|
- if (j==0 && in_region>=0 && color_regions[in_region].line_only) {
|
|
|
- in_region=-1; //reset regions that end at end of line
|
|
|
- }
|
|
|
+ if (j==0 && in_region>=0 && color_regions[in_region].line_only) {
|
|
|
+ in_region=-1; //reset regions that end at end of line
|
|
|
+ }
|
|
|
|
|
|
- if (is_symbol && cri_map.has(j)) {
|
|
|
+ if (is_symbol && cri_map.has(j)) {
|
|
|
|
|
|
|
|
|
- const Text::ColorRegionInfo &cri=cri_map[j];
|
|
|
+ const Text::ColorRegionInfo &cri=cri_map[j];
|
|
|
|
|
|
- if (in_region==-1) {
|
|
|
+ if (in_region==-1) {
|
|
|
|
|
|
- if (!cri.end) {
|
|
|
+ if (!cri.end) {
|
|
|
|
|
|
- in_region=cri.region;
|
|
|
- }
|
|
|
- } else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise
|
|
|
+ in_region=cri.region;
|
|
|
+ }
|
|
|
+ } else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise
|
|
|
|
|
|
- if (cri.end || color_regions[cri.region].eq) {
|
|
|
+ if (cri.end || color_regions[cri.region].eq) {
|
|
|
|
|
|
- deregion=color_regions[cri.region].eq?color_regions[cri.region].begin_key.length():color_regions[cri.region].end_key.length();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ deregion=color_regions[cri.region].eq?color_regions[cri.region].begin_key.length():color_regions[cri.region].end_key.length();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (!is_char)
|
|
|
- in_keyword=false;
|
|
|
+ if (!is_char)
|
|
|
+ in_keyword=false;
|
|
|
|
|
|
- if (in_region==-1 && !in_keyword && is_char && !prev_is_char) {
|
|
|
+ if (in_region==-1 && !in_keyword && is_char && !prev_is_char) {
|
|
|
|
|
|
- int to=j;
|
|
|
- while(_is_text_char(str[to]) && to<str.length())
|
|
|
- to++;
|
|
|
+ int to=j;
|
|
|
+ while(_is_text_char(str[to]) && to<str.length())
|
|
|
+ to++;
|
|
|
|
|
|
- uint32_t hash = String::hash(&str[j],to-j);
|
|
|
- StrRange range(&str[j],to-j);
|
|
|
+ uint32_t hash = String::hash(&str[j],to-j);
|
|
|
+ StrRange range(&str[j],to-j);
|
|
|
|
|
|
- const Color *col=keywords.custom_getptr(range,hash);
|
|
|
+ const Color *col=keywords.custom_getptr(range,hash);
|
|
|
|
|
|
- if (col) {
|
|
|
+ if (col) {
|
|
|
|
|
|
- in_keyword=true;
|
|
|
- keyword_color=*col;
|
|
|
- }
|
|
|
- }
|
|
|
+ in_keyword=true;
|
|
|
+ keyword_color=*col;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
|
|
|
- if (in_region>=0)
|
|
|
- color=color_regions[in_region].color;
|
|
|
- else if (in_keyword)
|
|
|
- color=keyword_color;
|
|
|
- else if (is_symbol)
|
|
|
- color=symbol_color;
|
|
|
+ if (in_region>=0)
|
|
|
+ color=color_regions[in_region].color;
|
|
|
+ else if (in_keyword)
|
|
|
+ color=keyword_color;
|
|
|
+ else if (is_symbol)
|
|
|
+ color=symbol_color;
|
|
|
|
|
|
- prev_is_char=is_char;
|
|
|
+ prev_is_char=is_char;
|
|
|
|
|
|
- }
|
|
|
- int char_w;
|
|
|
+ }
|
|
|
+ int char_w;
|
|
|
|
|
|
- //handle tabulator
|
|
|
+ //handle tabulator
|
|
|
|
|
|
|
|
|
- if (str[j]=='\t') {
|
|
|
- int left = char_ofs%tab_w;
|
|
|
- if (left==0)
|
|
|
- char_w=tab_w;
|
|
|
- else
|
|
|
- char_w=tab_w-char_ofs%tab_w; // is right...
|
|
|
+ if (str[j]=='\t') {
|
|
|
+ int left = char_ofs%tab_w;
|
|
|
+ if (left==0)
|
|
|
+ char_w=tab_w;
|
|
|
+ else
|
|
|
+ char_w=tab_w-char_ofs%tab_w; // is right...
|
|
|
|
|
|
- } else {
|
|
|
- char_w=cache.font->get_char_size(str[j],str[j+1]).width;
|
|
|
- }
|
|
|
+ } else {
|
|
|
+ char_w=cache.font->get_char_size(str[j],str[j+1]).width;
|
|
|
+ }
|
|
|
|
|
|
- if ( (char_ofs+char_margin)<xmargin_beg) {
|
|
|
- char_ofs+=char_w;
|
|
|
- continue;
|
|
|
- }
|
|
|
+ if ( (char_ofs+char_margin)<xmargin_beg) {
|
|
|
+ char_ofs+=char_w;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- if ( (char_ofs+char_margin+char_w)>=xmargin_end) {
|
|
|
- if (syntax_coloring)
|
|
|
- continue;
|
|
|
- else
|
|
|
- break;
|
|
|
- }
|
|
|
+ if ( (char_ofs+char_margin+char_w)>=xmargin_end) {
|
|
|
+ if (syntax_coloring)
|
|
|
+ continue;
|
|
|
+ else
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- bool in_selection = (selection.active && line>=selection.from_line && line<=selection.to_line && (line>selection.from_line || j>=selection.from_column) && (line<selection.to_line || j<selection.to_column));
|
|
|
+ bool in_selection = (selection.active && line>=selection.from_line && line<=selection.to_line && (line>selection.from_line || j>=selection.from_column) && (line<selection.to_line || j<selection.to_column));
|
|
|
|
|
|
|
|
|
- if (in_selection) {
|
|
|
- //inside selection!
|
|
|
- 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 (in_selection) {
|
|
|
+ //inside selection!
|
|
|
+ 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 (str[j]>=32)
|
|
|
- cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),str[j],str[j+1],in_selection?cache.font_selected_color:color);
|
|
|
- else if (draw_tabs && str[j]=='\t') {
|
|
|
- int yofs= (get_row_height() - cache.tab_icon->get_height())/2;
|
|
|
- cache.tab_icon->draw(ci, Point2(char_ofs+char_margin,ofs_y+yofs),in_selection?cache.font_selected_color:color);
|
|
|
- }
|
|
|
+ if (str[j]>=32)
|
|
|
+ cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),str[j],str[j+1],in_selection?cache.font_selected_color:color);
|
|
|
+ else if (draw_tabs && str[j]=='\t') {
|
|
|
+ int yofs= (get_row_height() - cache.tab_icon->get_height())/2;
|
|
|
+ cache.tab_icon->draw(ci, Point2(char_ofs+char_margin,ofs_y+yofs),in_selection?cache.font_selected_color:color);
|
|
|
+ }
|
|
|
|
|
|
|
|
|
- if (cursor.column==j && cursor.line==line) {
|
|
|
+ if (cursor.column==j && cursor.line==line) {
|
|
|
|
|
|
- cursor_pos = Point2i( char_ofs+char_margin, ofs_y );
|
|
|
- VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color);
|
|
|
+ cursor_pos = Point2i( char_ofs+char_margin, ofs_y );
|
|
|
+ VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color);
|
|
|
|
|
|
|
|
|
- }
|
|
|
- char_ofs+=char_w;
|
|
|
+ }
|
|
|
+ char_ofs+=char_w;
|
|
|
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- if (cursor.column==str.length() && cursor.line==line) {
|
|
|
+ if (cursor.column==str.length() && cursor.line==line) {
|
|
|
|
|
|
- cursor_pos=Point2i( char_ofs+char_margin, ofs_y );
|
|
|
- VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color);
|
|
|
+ cursor_pos=Point2i( char_ofs+char_margin, ofs_y );
|
|
|
+ VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color);
|
|
|
|
|
|
- }
|
|
|
- }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (completion_active) {
|
|
|
- // code completion box
|
|
|
- Ref<StyleBox> csb = get_stylebox("completion");
|
|
|
- Ref<StyleBox> csel = get_stylebox("completion_selected");
|
|
|
- int maxlines = get_constant("completion_lines");
|
|
|
- int cmax_width = get_constant("completion_max_width")*cache.font->get_char_size('x').x;
|
|
|
- Color existing = get_color("completion_existing");
|
|
|
- int scrollw = get_constant("completion_scroll_width");
|
|
|
- Color scrollc = get_color("completion_scroll_color");
|
|
|
|
|
|
+ if (completion_active) {
|
|
|
+ // code completion box
|
|
|
+ Ref<StyleBox> csb = get_stylebox("completion");
|
|
|
+ Ref<StyleBox> csel = get_stylebox("completion_selected");
|
|
|
+ int maxlines = get_constant("completion_lines");
|
|
|
+ int cmax_width = get_constant("completion_max_width")*cache.font->get_char_size('x').x;
|
|
|
+ Color existing = get_color("completion_existing");
|
|
|
+ int scrollw = get_constant("completion_scroll_width");
|
|
|
+ Color scrollc = get_color("completion_scroll_color");
|
|
|
|
|
|
|
|
|
- int lines = MIN(completion_options.size(),maxlines);
|
|
|
- int w=0;
|
|
|
- int h=lines*get_row_height();
|
|
|
- int nofs = cache.font->get_string_size(completion_base).width;
|
|
|
|
|
|
+ int lines = MIN(completion_options.size(),maxlines);
|
|
|
+ int w=0;
|
|
|
+ int h=lines*get_row_height();
|
|
|
+ int nofs = cache.font->get_string_size(completion_base).width;
|
|
|
|
|
|
- if (completion_options.size() < 50) {
|
|
|
- for(int i=0;i<completion_options.size();i++) {
|
|
|
- int w2=MIN(cache.font->get_string_size(completion_options[i]).x,cmax_width);
|
|
|
- if (w2>w)
|
|
|
- w=w2;
|
|
|
- }
|
|
|
- } else {
|
|
|
- w=cmax_width;
|
|
|
- }
|
|
|
|
|
|
- int th = h + csb->get_minimum_size().y;
|
|
|
- if (cursor_pos.y+get_row_height()+th > get_size().height) {
|
|
|
- completion_rect.pos.y=cursor_pos.y-th;
|
|
|
- } else {
|
|
|
- completion_rect.pos.y=cursor_pos.y+get_row_height()+csb->get_offset().y;
|
|
|
- }
|
|
|
+ if (completion_options.size() < 50) {
|
|
|
+ for(int i=0;i<completion_options.size();i++) {
|
|
|
+ int w2=MIN(cache.font->get_string_size(completion_options[i]).x,cmax_width);
|
|
|
+ if (w2>w)
|
|
|
+ w=w2;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ w=cmax_width;
|
|
|
+ }
|
|
|
|
|
|
- if (cursor_pos.x-nofs+w+scrollw > get_size().width) {
|
|
|
- completion_rect.pos.x=get_size().width-w-scrollw;
|
|
|
- } else {
|
|
|
- completion_rect.pos.x=cursor_pos.x-nofs;
|
|
|
- }
|
|
|
+ int th = h + csb->get_minimum_size().y;
|
|
|
+ if (cursor_pos.y+get_row_height()+th > get_size().height) {
|
|
|
+ completion_rect.pos.y=cursor_pos.y-th;
|
|
|
+ } else {
|
|
|
+ completion_rect.pos.y=cursor_pos.y+get_row_height()+csb->get_offset().y;
|
|
|
|
|
|
- completion_rect.size.width=w;
|
|
|
- completion_rect.size.height=h;
|
|
|
- if (completion_options.size()<=maxlines)
|
|
|
- scrollw=0;
|
|
|
+ }
|
|
|
|
|
|
- draw_style_box(csb,Rect2(completion_rect.pos-csb->get_offset(),completion_rect.size+csb->get_minimum_size()+Size2(scrollw,0)));
|
|
|
+ if (cursor_pos.x-nofs+w+scrollw > get_size().width) {
|
|
|
+ completion_rect.pos.x=get_size().width-w-scrollw;
|
|
|
+ } else {
|
|
|
+ completion_rect.pos.x=cursor_pos.x-nofs;
|
|
|
+ }
|
|
|
|
|
|
+ completion_rect.size.width=w;
|
|
|
+ completion_rect.size.height=h;
|
|
|
+ if (completion_options.size()<=maxlines)
|
|
|
+ scrollw=0;
|
|
|
|
|
|
- int line_from = CLAMP(completion_index - lines/2, 0, completion_options.size() - lines);
|
|
|
- draw_style_box(csel,Rect2(Point2(completion_rect.pos.x,completion_rect.pos.y+(completion_index-line_from)*get_row_height()),Size2(completion_rect.size.width,get_row_height())));
|
|
|
+ draw_style_box(csb,Rect2(completion_rect.pos-csb->get_offset(),completion_rect.size+csb->get_minimum_size()+Size2(scrollw,0)));
|
|
|
|
|
|
- draw_rect(Rect2(completion_rect.pos,Size2(nofs,completion_rect.size.height)),existing);
|
|
|
|
|
|
- for(int i=0;i<lines;i++) {
|
|
|
+ int line_from = CLAMP(completion_index - lines/2, 0, completion_options.size() - lines);
|
|
|
+ draw_style_box(csel,Rect2(Point2(completion_rect.pos.x,completion_rect.pos.y+(completion_index-line_from)*get_row_height()),Size2(completion_rect.size.width,get_row_height())));
|
|
|
|
|
|
- int l = line_from + i;
|
|
|
- ERR_CONTINUE( l < 0 || l>= completion_options.size());
|
|
|
- draw_string(cache.font,Point2(completion_rect.pos.x,completion_rect.pos.y+i*get_row_height()+cache.font->get_ascent()),completion_options[l],cache.font_color,completion_rect.size.width);
|
|
|
- }
|
|
|
+ draw_rect(Rect2(completion_rect.pos,Size2(nofs,completion_rect.size.height)),existing);
|
|
|
|
|
|
- if (scrollw) {
|
|
|
- //draw a small scroll rectangle to show a position in the options
|
|
|
- float r = maxlines / (float)completion_options.size();
|
|
|
- float o = line_from / (float)completion_options.size();
|
|
|
- draw_rect(Rect2(completion_rect.pos.x+completion_rect.size.width,completion_rect.pos.y+o*completion_rect.size.y,scrollw,completion_rect.size.y*r),scrollc);
|
|
|
- }
|
|
|
+ for(int i=0;i<lines;i++) {
|
|
|
|
|
|
- completion_line_ofs=line_from;
|
|
|
+ int l = line_from + i;
|
|
|
+ ERR_CONTINUE( l < 0 || l>= completion_options.size());
|
|
|
+ draw_string(cache.font,Point2(completion_rect.pos.x,completion_rect.pos.y+i*get_row_height()+cache.font->get_ascent()),completion_options[l],cache.font_color,completion_rect.size.width);
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ if (scrollw) {
|
|
|
+ //draw a small scroll rectangle to show a position in the options
|
|
|
+ float r = maxlines / (float)completion_options.size();
|
|
|
+ float o = line_from / (float)completion_options.size();
|
|
|
+ draw_rect(Rect2(completion_rect.pos.x+completion_rect.size.width,completion_rect.pos.y+o*completion_rect.size.y,scrollw,completion_rect.size.y*r),scrollc);
|
|
|
+ }
|
|
|
|
|
|
+ completion_line_ofs=line_from;
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- } break;
|
|
|
- case NOTIFICATION_FOCUS_ENTER: {
|
|
|
+ if (completion_hint!="") {
|
|
|
|
|
|
- if (OS::get_singleton()->has_virtual_keyboard())
|
|
|
- OS::get_singleton()->show_virtual_keyboard(get_text(),get_global_rect());
|
|
|
+ Ref<StyleBox> sb = get_stylebox("panel","TooltipPanel");
|
|
|
+ Ref<Font> font = cache.font;
|
|
|
+ Color font_color = get_color("font_color","TooltipLabel");
|
|
|
|
|
|
- } break;
|
|
|
- case NOTIFICATION_FOCUS_EXIT: {
|
|
|
|
|
|
- if (OS::get_singleton()->has_virtual_keyboard())
|
|
|
- OS::get_singleton()->hide_virtual_keyboard();
|
|
|
+ int max_w=0;
|
|
|
+ int sc = completion_hint.get_slice_count("\n");
|
|
|
+ int offset=0;
|
|
|
+ int spacing=0;
|
|
|
+ for(int i=0;i<sc;i++) {
|
|
|
|
|
|
- } break;
|
|
|
+ String l = completion_hint.get_slice("\n",i);
|
|
|
+ int len = font->get_string_size(l).x;
|
|
|
+ max_w = MAX(len,max_w);
|
|
|
+ if (i==0) {
|
|
|
+ offset = font->get_string_size(l.substr(0,l.find(String::chr(0xFFFF)))).x;
|
|
|
+ } else {
|
|
|
+ spacing+=cache.line_spacing;
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ Size2 size = Size2(max_w,sc*font->get_height()+spacing);
|
|
|
+ Size2 minsize = size+sb->get_minimum_size();
|
|
|
+
|
|
|
+
|
|
|
+ if (completion_hint_offset==-0xFFFF) {
|
|
|
+ completion_hint_offset=cursor_pos.x-offset;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ Point2 hint_ofs = Vector2(completion_hint_offset,cursor_pos.y-minsize.y);
|
|
|
+ draw_style_box(sb,Rect2(hint_ofs,minsize));
|
|
|
+
|
|
|
+ spacing=0;
|
|
|
+ for(int i=0;i<sc;i++) {
|
|
|
+ int begin=0;
|
|
|
+ int end=0;
|
|
|
+ String l = completion_hint.get_slice("\n",i);
|
|
|
+
|
|
|
+ if (l.find(String::chr(0xFFFF))!=-1) {
|
|
|
+ begin = font->get_string_size(l.substr(0,l.find(String::chr(0xFFFF)))).x;
|
|
|
+ end = font->get_string_size(l.substr(0,l.rfind(String::chr(0xFFFF)))).x;
|
|
|
+ }
|
|
|
+
|
|
|
+ draw_string(font,hint_ofs+sb->get_offset()+Vector2(0,font->get_ascent()+font->get_height()*i+spacing),l.replace(String::chr(0xFFFF),""),font_color);
|
|
|
+ if (end>0) {
|
|
|
+ Vector2 b = hint_ofs+sb->get_offset()+Vector2(begin,font->get_height()+font->get_height()*i+spacing-1);
|
|
|
+ draw_line(b,b+Vector2(end-begin,0),font_color);
|
|
|
+ }
|
|
|
+ spacing+=cache.line_spacing;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ } break;
|
|
|
+ case NOTIFICATION_FOCUS_ENTER: {
|
|
|
+
|
|
|
+ if (OS::get_singleton()->has_virtual_keyboard())
|
|
|
+ OS::get_singleton()->show_virtual_keyboard(get_text(),get_global_rect());
|
|
|
+
|
|
|
+ } break;
|
|
|
+ case NOTIFICATION_FOCUS_EXIT: {
|
|
|
+
|
|
|
+ if (OS::get_singleton()->has_virtual_keyboard())
|
|
|
+ OS::get_singleton()->hide_virtual_keyboard();
|
|
|
+
|
|
|
+ } break;
|
|
|
+
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void TextEdit::_consume_pair_symbol(CharType ch) {
|
|
@@ -918,6 +978,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
|
|
|
return;
|
|
|
} else {
|
|
|
_cancel_completion();
|
|
|
+ _cancel_code_hint();
|
|
|
}
|
|
|
|
|
|
if (mb.pressed) {
|
|
@@ -1172,6 +1233,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
|
|
|
}
|
|
|
|
|
|
_cancel_completion();
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/* TEST CONTROL FIRST!! */
|
|
@@ -1268,6 +1330,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
|
|
|
break;
|
|
|
unselect=true;
|
|
|
break;
|
|
|
+
|
|
|
default:
|
|
|
if (k.unicode>=32 && !k.mod.command && !k.mod.alt && !k.mod.meta)
|
|
|
clear=true;
|
|
@@ -1318,6 +1381,13 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
|
|
|
_push_current_op();
|
|
|
|
|
|
} break;
|
|
|
+ case KEY_ESCAPE: {
|
|
|
+ if (completion_hint!="") {
|
|
|
+ completion_hint="";
|
|
|
+ update();
|
|
|
+
|
|
|
+ }
|
|
|
+ } break;
|
|
|
case KEY_TAB: {
|
|
|
|
|
|
if (readonly)
|
|
@@ -1454,6 +1524,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
|
|
|
|
|
|
if (k.mod.shift)
|
|
|
_post_shift_selection();
|
|
|
+ _cancel_code_hint();
|
|
|
|
|
|
} break;
|
|
|
case KEY_DOWN: {
|
|
@@ -1473,6 +1544,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
|
|
|
|
|
|
if (k.mod.shift)
|
|
|
_post_shift_selection();
|
|
|
+ _cancel_code_hint();
|
|
|
|
|
|
} break;
|
|
|
|
|
@@ -2333,6 +2405,30 @@ String TextEdit::get_text() {
|
|
|
|
|
|
};
|
|
|
|
|
|
+String TextEdit::get_text_for_completion() {
|
|
|
+
|
|
|
+ String longthing;
|
|
|
+ int len = text.size();
|
|
|
+ for (int i=0;i<len;i++) {
|
|
|
+
|
|
|
+ if (i==cursor.line) {
|
|
|
+ longthing+=text[i].substr(0,cursor.column);
|
|
|
+ longthing+=String::chr(0xFFFF); //not unicode, represents the cursor
|
|
|
+ longthing+=text[i].substr(cursor.column,text[i].size());
|
|
|
+ } else {
|
|
|
+
|
|
|
+ longthing+=text[i];
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (i!=len-1)
|
|
|
+ longthing+="\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ return longthing;
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
|
|
|
String TextEdit::get_line(int line) const {
|
|
|
|
|
@@ -2966,33 +3062,56 @@ void TextEdit::_confirm_completion() {
|
|
|
|
|
|
if (same)
|
|
|
cursor_set_column(cursor.column+remaining.length());
|
|
|
- else
|
|
|
+ else {
|
|
|
insert_text_at_cursor(remaining);
|
|
|
+ if (remaining.ends_with("(") && auto_brace_completion_enabled) {
|
|
|
+ insert_text_at_cursor(")");
|
|
|
+ cursor.column--;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
_cancel_completion();
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+void TextEdit::_cancel_code_hint() {
|
|
|
+ completion_hint="";
|
|
|
+ update();
|
|
|
+}
|
|
|
+
|
|
|
void TextEdit::_cancel_completion() {
|
|
|
|
|
|
if (!completion_active)
|
|
|
return;
|
|
|
|
|
|
- completion_active=false;
|
|
|
+ completion_active=false;
|
|
|
update();
|
|
|
|
|
|
}
|
|
|
|
|
|
+static bool _is_completable(CharType c) {
|
|
|
+
|
|
|
+ return !_is_symbol(c) || c=='"' || c=='\'';
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
void TextEdit::_update_completion_candidates() {
|
|
|
|
|
|
String l = text[cursor.line];
|
|
|
int cofs = CLAMP(cursor.column,0,l.length());
|
|
|
|
|
|
+
|
|
|
String s;
|
|
|
- while(cofs>0 && l[cofs-1]>32 && !_is_symbol(l[cofs-1])) {
|
|
|
- s=String::chr(l[cofs-1])+s;
|
|
|
+
|
|
|
+ while(cofs>0 && l[cofs-1]>32 && _is_completable(l[cofs-1])) {
|
|
|
+ s=String::chr(l[cofs-1])+s;
|
|
|
+ if (l[cofs-1]=='\'' || l[cofs-1]=='"')
|
|
|
+ break;
|
|
|
+
|
|
|
cofs--;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
update();
|
|
|
|
|
|
if (s=="" && (cofs==0 || !completion_prefixes.has(String::chr(l[cofs-1])))) {
|
|
@@ -3055,36 +3174,24 @@ void TextEdit::_update_completion_candidates() {
|
|
|
completion_enabled=true;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
void TextEdit::query_code_comple() {
|
|
|
|
|
|
- String l = text[cursor.line];
|
|
|
- int ofs = CLAMP(cursor.column,0,l.length());
|
|
|
- String cs;
|
|
|
- while(ofs>0 && l[ofs-1]>32) {
|
|
|
-
|
|
|
- if (_is_symbol(l[ofs-1])) {
|
|
|
- String s;
|
|
|
- while(ofs>0 && l[ofs-1]>32 && _is_symbol(l[ofs-1])) {
|
|
|
- s=String::chr(l[ofs-1])+s;
|
|
|
- ofs--;
|
|
|
- }
|
|
|
- if (completion_prefixes.has(s))
|
|
|
- cs=s+cs;
|
|
|
- else
|
|
|
- break;
|
|
|
- } else {
|
|
|
+ String l = text[cursor.line];
|
|
|
+ int ofs = CLAMP(cursor.column,0,l.length());
|
|
|
|
|
|
- cs=String::chr(l[ofs-1])+cs;
|
|
|
- ofs--;
|
|
|
- }
|
|
|
+ if (ofs>0 && (_is_completable(l[ofs-1]) || completion_prefixes.has(String::chr(l[ofs-1]))))
|
|
|
+ emit_signal("request_completion");
|
|
|
|
|
|
- }
|
|
|
+}
|
|
|
|
|
|
- if (cs!="") {
|
|
|
- emit_signal("request_completion",cs,cursor.line);
|
|
|
|
|
|
- }
|
|
|
+void TextEdit::set_code_hint(const String& p_hint) {
|
|
|
|
|
|
+ completion_hint=p_hint;
|
|
|
+ completion_hint_offset=-0xFFFF;
|
|
|
+ update();
|
|
|
}
|
|
|
|
|
|
void TextEdit::code_complete(const Vector<String> &p_strings) {
|
|
@@ -3236,7 +3343,7 @@ void TextEdit::_bind_methods() {
|
|
|
|
|
|
ADD_SIGNAL(MethodInfo("cursor_changed"));
|
|
|
ADD_SIGNAL(MethodInfo("text_changed"));
|
|
|
- ADD_SIGNAL(MethodInfo("request_completion",PropertyInfo(Variant::STRING,"keyword"),PropertyInfo(Variant::INT,"line")));
|
|
|
+ ADD_SIGNAL(MethodInfo("request_completion"));
|
|
|
|
|
|
}
|
|
|
|