3 * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "bcclipboard.h"
22 #include "bclistboxitem.h"
23 #include "bcresources.h"
24 #include "bcsignals.h"
25 #include "bctextbox.h"
30 #include "filesystem.h"
41 #define VERTICAL_MARGIN 2
42 #define VERTICAL_MARGIN_NOBORDER 0
43 #define HORIZONTAL_MARGIN 4
44 #define HORIZONTAL_MARGIN_NOBORDER 2
46 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
47 int size, char *text, int has_border, int font)
48 : BC_SubWindow(x, y, w, 0, -1)
52 reset_parameters(rows, has_border, font, size);
55 else // text referenced directly
59 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
60 int size, wchar_t *wtext, int has_border, int font)
61 : BC_SubWindow(x, y, w, 0, -1)
65 wsize = size > 0 ? size : wcslen(wtext);
66 if( size <= 0 ) size = 2*wsize;
67 reset_parameters(rows, has_border, font, size);
68 this->wtext = new wchar_t[wsize+1];
69 wcsncpy(this->wtext, wtext, wsize);
70 this->wtext[wsize] = 0;
73 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
74 const char *text, int has_border, int font, int is_utf8)
75 : BC_SubWindow(x, y, w, 0, -1)
77 this->is_utf8 = is_utf8;
79 reset_parameters(rows, has_border, font, BCTEXTLEN);
83 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
84 const wchar_t *wtext, int has_border, int font, int is_utf8)
85 : BC_SubWindow(x, y, w, 0, -1)
87 this->is_utf8 = is_utf8;
89 reset_parameters(rows, has_border, font, BCTEXTLEN);
91 wtext = new wchar_t[wsize+1];
92 wcsncpy(this->wtext, wtext, wsize);
93 this->wtext[wsize] = 0;
96 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
97 int64_t text, int has_border, int font)
98 : BC_SubWindow(x, y, w, 0, -1)
102 reset_parameters(rows, has_border, font, BCSTRLEN);
103 snprintf(this->text, this->tsize, "%jd", text);
104 dirty = 1; wtext_update();
107 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
108 float text, int has_border, int font, int precision)
109 : BC_SubWindow(x, y, w, 0, -1)
113 reset_parameters(rows, has_border, font, BCSTRLEN);
114 this->precision = precision;
115 snprintf(this->text, this->tsize, "%0.*f", precision, text);
116 dirty = 1; wtext_update();
119 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
120 int text, int has_border, int font)
121 : BC_SubWindow(x, y, w, 0, -1)
125 reset_parameters(rows, has_border, font, BCSTRLEN);
126 snprintf(this->text, this->tsize, "%d", text);
127 dirty = 1; wtext_update();
130 BC_TextBox::~BC_TextBox()
132 if(skip_cursor) delete skip_cursor;
133 delete suggestions_popup;
134 suggestions->remove_all_objects();
141 int BC_TextBox::reset_parameters(int rows, int has_border, int font, int size)
143 suggestions = new ArrayList<BC_ListBoxItem*>;
144 suggestions_popup = 0;
145 suggestion_column = 0;
148 this->has_border = has_border;
151 this->tsize = size >= 0 ? size : -size;
152 this->text = size > 0 ? new char[size+1] : 0;
153 if( this->text ) this->text[0] = 0;
156 highlight_letter1 = highlight_letter2 = 0;
157 highlight_letter3 = highlight_letter4 = 0;
169 skip_cursor = new Timer;
179 selection_active = 0;
183 int BC_TextBox::tstrlen()
185 if( !tsize ) return strlen(text);
186 return strnlen(text, tsize);
189 int BC_TextBox::tstrcmp(const char *cp)
191 if( !tsize ) return strcmp(text, cp);
192 return strncmp(text, cp, tsize);
195 char *BC_TextBox::tstrcpy(const char *cp)
200 return strcpy(text, cp);
201 strncpy(text, cp, tsize);
209 char *BC_TextBox::tstrcat(const char *cp)
212 if( !tsize ) return strcat(text, cp);
213 char *result = strncat(text, cp, tsize);
218 int BC_TextBox::wtext_update()
221 const char *src_enc = is_utf8 ? "UTF8" : BC_Resources::encoding;
222 const char *dst_enc = BC_Resources::wide_encoding;
223 int nsize = tsize > 0 ? tsize : strlen(text) + BCTEXTLEN;
224 if( nsize > wsize || !wtext ) {
225 wchar_t *ntext = new wchar_t[nsize+1];
226 memcpy(ntext, wtext, wsize*sizeof(wtext[0]));
227 delete [] wtext; wtext = ntext; wsize = nsize;
229 wlen = BC_Resources::encode(src_enc, dst_enc, text, strlen(text),
230 (char*)wtext, wsize*sizeof(wchar_t)) / sizeof(wchar_t);
237 int BC_TextBox::text_update(const wchar_t *wcp, int wsz, char *tcp, int tsz)
239 const char *src_enc = BC_Resources::wide_encoding;
240 const char *dst_enc = BC_Resources::encoding;
241 if( wsz < 0 ) wsz = wcslen(wcp);
242 int len = BC_Resources::encode(src_enc, dst_enc,
243 (char*)wcp, wsz*sizeof(wchar_t), tcp, tsz);
248 int BC_TextBox::initialize()
251 skip_cursor = new Timer;
252 skip_cursor->update();
254 text_ascent = get_text_ascent(font) + 1;
255 text_descent = get_text_descent(font) + 1;
256 text_height = text_ascent + text_descent;
257 ibeam_letter = wtext_update();
260 left_margin = right_margin = HORIZONTAL_MARGIN;
261 top_margin = bottom_margin = VERTICAL_MARGIN;
265 left_margin = right_margin = HORIZONTAL_MARGIN_NOBORDER;
266 top_margin = bottom_margin = VERTICAL_MARGIN_NOBORDER;
269 text_x = left_margin;
273 // Create the subwindow
274 BC_SubWindow::initialize();
276 BC_Resources *resources = get_resources();
279 back_color = resources->text_background;
280 high_color = resources->text_background_hi;
284 high_color = resources->text_background_noborder_hi;
285 back_color = bg_color;
289 set_cursor(IBEAM_CURSOR, 0, 0);
294 int BC_TextBox::calculate_h(BC_WindowBase *gui,
299 return rows * (gui->get_text_ascent(font) + 1 +
300 gui->get_text_descent(font) + 1) +
301 2 * (has_border ? VERTICAL_MARGIN : VERTICAL_MARGIN_NOBORDER);
304 void BC_TextBox::set_precision(int precision)
306 this->precision = precision;
309 // Compute suggestions for a path
310 int BC_TextBox::calculate_suggestions(ArrayList<BC_ListBoxItem*> *entries, const char *filter)
312 // Let user delete suggestion
313 if(get_last_keypress() != BACKSPACE) {
314 // Compute suggestions
316 ArrayList<char*> suggestions;
317 const char *current_text = get_text();
318 int suggestion_column = 0;
319 char dirname[BCTEXTLEN]; dirname[0] = 0;
320 if( current_text[0] == '/' || current_text[0] == '~' )
321 strncpy(dirname, current_text, sizeof(dirname));
323 getcwd(dirname, sizeof(dirname));
324 // If directory, tabulate it
326 if( filter ) fs.set_filter(filter);
328 strncpy(dirname, current_text, sizeof(dirname));
329 if( (cp=strrchr(dirname, '/')) ||
330 (cp=strrchr(dirname, '~')) ) *++cp = 0;
331 fs.parse_tildas(dirname);
333 cp = (char *)current_text;
334 if( (prefix=strrchr(cp, '/')) ||
335 (prefix=strrchr(cp, '~')) ) ++prefix;
336 suggestion_column = !prefix ? 0 : prefix - cp;
337 int prefix_len = prefix ? strlen(prefix) : 0;
338 // only include items where the filename matches the basename prefix
339 for(int i = 0; i < fs.total_files(); i++) {
340 char *current_name = fs.get_entry(i)->name;
341 if( prefix_len>0 && strncmp(prefix, current_name, prefix_len) ) continue;
342 suggestions.append(current_name);
346 char *prefix = (char *)current_text;
347 int prefix_len = strlen(prefix);
348 for(int i = 0; i < entries->size(); i++) {
349 char *current_name = entries->get(i)->get_text();
350 if( prefix_len>0 && strncmp(prefix, current_name, prefix_len) ) continue;
351 suggestions.append(current_name);
354 set_suggestions(&suggestions, suggestion_column);
360 void BC_TextBox::no_suggestions()
362 if( suggestions_popup ) {
363 delete suggestions_popup;
364 suggestions_popup = 0;
369 void BC_TextBox::set_suggestions(ArrayList<char*> *suggestions, int column)
372 this->suggestions->remove_all_objects();
373 this->suggestion_column = column;
376 for(int i = 0; i < suggestions->size(); i++) {
377 this->suggestions->append(new BC_ListBoxItem(suggestions->get(i)));
380 // Show the popup without taking focus
381 if( suggestions->size() > 1 ) {
382 if( !suggestions_popup ) {
383 suggestions_popup = new BC_TextBoxSuggestions(this, x, y);
384 get_parent()->add_subwindow(suggestions_popup);
385 suggestions_popup->set_is_suggestions(1);
388 suggestions_popup->update(this->suggestions, 0, 0, 1);
390 suggestions_popup->activate(0);
393 // Show the highlighted text
394 if( suggestions->size() == 1 ) {
395 highlight_letter1 = wtext_update();
396 text_update(wtext,wlen, text,tsize);
397 char *current_suggestion = suggestions->get(0);
398 int col = highlight_letter1 - suggestion_column;
399 if( col < 0 ) col = 0;
400 char *cur = current_suggestion + col;
402 highlight_letter2 = wtext_update();
403 //printf("BC_TextBox::set_suggestions %d %d\n", __LINE__, suggestion_column);
411 if( !suggestions || !this->suggestions->size() )
415 void BC_TextBox::wset_selection(int char1, int char2, int ibeam)
417 highlight_letter1 = char1;
418 highlight_letter2 = char2;
419 ibeam_letter = ibeam;
423 // count utf8 chars in text which occur before cp
424 int BC_TextBox::wcpos(const char *text, const char *cp)
427 const unsigned char *bp = (const unsigned char *)text;
428 const unsigned char *ep = (const unsigned char *)cp;
429 while( bp < ep && *bp != 0 ) {
432 if( ch < 0x80 ) continue;
434 int n = i<0? 0 : i<32? 1 : i<48? 2 : i<56? 3 : i<60? 4 : 5;
435 for( i=n; bp < ep && --i>=0 && (*bp&0xc0) == 0x80; ++bp );
440 void BC_TextBox::set_selection(int char1, int char2, int ibeam)
442 const char *cp = get_text();
443 wset_selection(wcpos(cp, cp+char1), wcpos(cp, cp+char2), wcpos(cp, cp+ibeam));
446 int BC_TextBox::update(const char *text)
448 //printf("BC_TextBox::update 1 %d %s %s\n", tstrcmp(text), text, this->text);
449 // Don't update if contents are the same
450 if(!tstrcmp(text)) return 0;
452 int wtext_len = wtext_update();
453 if(highlight_letter1 > wtext_len) highlight_letter1 = wtext_len;
454 if(highlight_letter2 > wtext_len) highlight_letter2 = wtext_len;
455 if(ibeam_letter > wtext_len) ibeam_letter = wtext_len;
460 int BC_TextBox::update(const wchar_t *wtext)
462 int wtext_len = wcslen(wtext);
463 if( wtext_len >= wsize ) wtext_len = wsize;
464 wcsncpy(this->wtext, wtext, wtext_len);
466 if(highlight_letter1 > wtext_len) highlight_letter1 = wtext_len;
467 if(highlight_letter2 > wtext_len) highlight_letter2 = wtext_len;
468 if(ibeam_letter > wtext_len) ibeam_letter = wtext_len;
473 int BC_TextBox::update(int64_t value)
475 char string[BCTEXTLEN];
476 sprintf(string, "%jd", value);
481 int BC_TextBox::update(float value)
483 char string[BCTEXTLEN];
484 sprintf(string, "%0.*f", precision, value);
489 void BC_TextBox::disable()
498 void BC_TextBox::enable()
508 int BC_TextBox::get_enabled() { return enabled; }
509 int BC_TextBox::get_text_x() { return text_x; }
510 int BC_TextBox::get_text_y() { return text_y; }
511 void BC_TextBox::set_text_x(int v) { text_x = v; }
512 void BC_TextBox::set_text_y(int v) { text_y = v; }
514 int BC_TextBox::pixels_to_rows(BC_WindowBase *window, int font, int pixels)
516 return (pixels - 4) /
517 (window->get_text_ascent(font) + 1 +
518 window->get_text_descent(font) + 1);
521 int BC_TextBox::calculate_row_h(int rows,
522 BC_WindowBase *parent_window,
527 (parent_window->get_text_ascent(font) + 1 +
528 parent_window->get_text_descent(font) + 1) +
529 (has_border ? 4 : 0);
532 const char* BC_TextBox::get_text()
534 int wtext_len = wtext_update();
535 text_update(wtext,wtext_len, text,tsize);
539 const wchar_t* BC_TextBox::get_wtext()
545 void BC_TextBox::set_text(char *text, int isz)
547 if( size > 0 || isz < 0 ) return;
556 int BC_TextBox::get_text_rows()
558 int wtext_len = wtext_update();
560 for(int i = 0; i < wtext_len; i++) {
561 if(wtext[i] == '\n') result++;
567 int BC_TextBox::get_row_h(int rows)
569 return rows * text_height + top_margin + bottom_margin;
572 int BC_TextBox::reposition_window(int x, int y, int w, int rows)
575 if(w < 0) w = get_w();
578 new_h = get_row_h(rows);
587 // printf("BC_TextBox::reposition_window 1 %d %d %d %d %d %d %d %d\n",
588 // x, get_x(), y, get_y(), w, get_w(), new_h, get_h());
589 BC_WindowBase::reposition_window(x, y, w, new_h);
595 void BC_TextBox::draw_border()
597 BC_Resources *resources = get_resources();
599 set_color(background_color);
600 draw_box(0, 0, left_margin, get_h());
601 draw_box(get_w() - right_margin, 0, right_margin, get_h());
606 draw_3d_border(0, 0, w, h,
607 resources->text_border1,
608 resources->text_border2_hi,
609 resources->text_border3_hi,
610 resources->text_border4);
612 draw_3d_border(0, 0, w, h,
613 resources->text_border1,
614 resources->text_border2,
615 resources->text_border3,
616 resources->text_border4);
620 void BC_TextBox::draw_cursor()
622 // set_color(background_color);
630 draw_box(ibeam_x + text_x,
639 void BC_TextBox::draw(int flush)
642 int row_begin, row_end;
643 int highlight_x1, highlight_x2;
645 BC_Resources *resources = get_resources();
647 //printf("BC_TextBox::draw %d %s\n", __LINE__, text);
650 background_color = resources->text_background;
652 background_color = high_color;
654 background_color = back_color;
655 set_color(background_color);
656 draw_box(0, 0, w, h);
658 int wtext_len = wtext_update();
660 // Draw text with selection
663 for(i=0, j=0, k=text_y; i < wtext_len && k < get_h(); k += text_height) {
666 wchar_t *wtext_row = &wtext[i];
667 for(j=0; j<BCTEXTLEN-1 && i<wtext_len && wtext[i]!='\n'; ++i, ++j);
668 if( (row_end=i) < wtext_len ) ++i;
670 if(k > top_margin-text_height && k < get_h()-bottom_margin) {
671 // Draw highlighted region of row
672 if( highlight_letter2 > highlight_letter1 &&
673 highlight_letter2 > row_begin &&
674 highlight_letter1 <= row_end ) {
675 int color = active && enabled && get_has_focus() ?
676 resources->text_highlight :
678 resources->text_selected_highlight :
679 resources->text_inactive_highlight;
680 if( unicode_active >= 0 )
683 if(highlight_letter1 >= row_begin &&
684 highlight_letter1 <= row_end)
685 highlight_x1 = get_x_position(highlight_letter1, row_begin);
689 if(highlight_letter2 > row_begin &&
690 highlight_letter2 <= row_end)
691 highlight_x2 = get_x_position(highlight_letter2, row_begin);
693 highlight_x2 = get_w();
695 draw_box(highlight_x1 + text_x, k,
696 highlight_x2 - highlight_x1, text_height);
699 // Draw text over highlight
700 int len = row_end - row_begin;
702 set_color(enabled ? resources->text_default : DMGREY);
703 draw_single_text(1, font, text_x, k + text_ascent, wtext_row, len);
706 // Get ibeam location
707 if(ibeam_letter >= row_begin && ibeam_letter <= row_end) {
709 ibeam_y = k - text_y;
710 ibeam_x = get_x_position(ibeam_letter, row_begin);
715 //printf("BC_TextBox::draw 3 %d\n", ibeam_y);
717 // ibeam_x = ibeam_y = !wtext_len ? 0 : -1;
718 ibeam_x = 0; ibeam_y = k - text_y;
721 //printf("BC_TextBox::draw 4 %d\n", ibeam_y);
731 int BC_TextBox::focus_in_event()
737 int BC_TextBox::focus_out_event()
743 int BC_TextBox::cursor_enter_event()
745 if( top_level->event_win == win && enabled &&
746 !(top_level->get_resources()->textbox_focus_policy & CLICK_ACTIVATE) )
749 top_level->deactivate();
762 int BC_TextBox::cursor_leave_event()
771 if( !suggestions_popup && !get_button_down() &&
772 !(top_level->get_resources()->textbox_focus_policy & CLICK_DEACTIVATE) )
777 int BC_TextBox::button_press_event()
781 if(!enabled) return 0;
782 if(get_buttonpress() != WHEEL_UP &&
783 get_buttonpress() != WHEEL_DOWN &&
784 get_buttonpress() != LEFT_BUTTON &&
785 get_buttonpress() != MIDDLE_BUTTON) return 0;
789 if(debug) printf("BC_TextBox::button_press_event %d\n", __LINE__);
791 int cursor_letter = 0;
792 int wtext_len = wtext_update();
793 int update_scroll = 0;
796 if(top_level->event_win == win)
801 top_level->deactivate();
806 if(get_buttonpress() == WHEEL_UP)
808 text_y += text_height;
809 text_y = MIN(text_y, top_margin);
813 if(get_buttonpress() == WHEEL_DOWN)
815 int min_y = -(get_text_rows() *
819 text_y -= text_height;
820 text_y = MAX(text_y, min_y);
821 text_y = MIN(text_y, top_margin);
827 cursor_letter = get_cursor_letter(top_level->cursor_x, top_level->cursor_y);
829 //printf("BC_TextBox::button_press_event %d %d\n", __LINE__, cursor_letter);
832 if(get_triple_click())
834 //printf("BC_TextBox::button_press_event %d\n", __LINE__);
836 select_line(highlight_letter1, highlight_letter2, cursor_letter);
837 highlight_letter3 = highlight_letter1;
838 highlight_letter4 = highlight_letter2;
839 ibeam_letter = highlight_letter2;
840 copy_selection(PRIMARY_SELECTION);
843 if(get_double_click())
846 select_word(highlight_letter1, highlight_letter2, cursor_letter);
847 highlight_letter3 = highlight_letter1;
848 highlight_letter4 = highlight_letter2;
849 ibeam_letter = highlight_letter2;
850 copy_selection(PRIMARY_SELECTION);
853 if(get_buttonpress() == MIDDLE_BUTTON)
855 highlight_letter3 = highlight_letter4 =
856 ibeam_letter = highlight_letter1 =
857 highlight_letter2 = cursor_letter;
858 paste_selection(PRIMARY_SELECTION);
863 highlight_letter3 = highlight_letter4 =
864 ibeam_letter = highlight_letter1 =
865 highlight_letter2 = cursor_letter;
869 // Handle scrolling by highlighting text
870 if(text_selected || word_selected || line_selected)
872 set_repeat(top_level->get_resources()->scroll_repeat);
875 if(ibeam_letter < 0) ibeam_letter = 0;
876 if(ibeam_letter > wtext_len) ibeam_letter = wtext_len;
880 if(update_scroll && yscroll)
882 yscroll->update_length(get_text_rows(),
884 yscroll->get_handlelength(),
892 if( suggestions_popup && (!yscroll || !yscroll->is_event_win())) {
893 if( suggestions_popup->button_press_event() )
894 return suggestions_popup->handle_event();
896 else if( (top_level->get_resources()->textbox_focus_policy & CLICK_DEACTIVATE) )
903 int BC_TextBox::button_release_event()
908 if(text_selected || word_selected || line_selected)
914 // Stop scrolling by highlighting text
915 unset_repeat(top_level->get_resources()->scroll_repeat);
921 int BC_TextBox::cursor_motion_event()
923 int cursor_letter, letter1, letter2;
926 if(text_selected || word_selected || line_selected)
928 cursor_letter = get_cursor_letter(top_level->cursor_x,
929 top_level->cursor_y);
931 //printf("BC_TextBox::cursor_motion_event %d cursor_letter=%d\n", __LINE__, cursor_letter);
935 select_line(letter1, letter2, cursor_letter);
940 select_word(letter1, letter2, cursor_letter);
945 letter1 = letter2 = cursor_letter;
948 if(letter1 <= highlight_letter3)
950 highlight_letter1 = letter1;
951 highlight_letter2 = highlight_letter4;
952 ibeam_letter = letter1;
955 if(letter2 >= highlight_letter4)
957 highlight_letter2 = letter2;
958 highlight_letter1 = highlight_letter3;
959 ibeam_letter = letter2;
962 copy_selection(PRIMARY_SELECTION);
975 int BC_TextBox::activate()
979 top_level->set_active_subwindow(this);
980 top_level->set_repeat(top_level->get_resources()->blink_rate);
986 int BC_TextBox::deactivate()
990 text_selected = word_selected = line_selected = 0;
991 top_level->set_active_subwindow(0);
992 top_level->unset_repeat(top_level->get_resources()->blink_rate);
998 int BC_TextBox::repeat_event(int64_t duration)
1001 int cursor_y = get_cursor_y();
1002 //int cursor_x = get_cursor_x();
1004 if(duration == top_level->get_resources()->tooltip_delay &&
1005 tooltip_text && tooltip_text[0] != 0 && highlighted)
1011 if(duration == top_level->get_resources()->blink_rate &&
1015 // don't flash if keypress
1016 if(skip_cursor->get_difference() < 500)
1018 // printf("BC_TextBox::repeat_event 1 %lld %lld\n",
1019 // skip_cursor->get_difference(),
1025 if(!(text_selected || word_selected || line_selected))
1034 if(duration == top_level->get_resources()->scroll_repeat &&
1035 (text_selected || word_selected || line_selected))
1038 if(get_cursor_y() < top_margin)
1040 difference = get_cursor_y() - top_margin ;
1043 if(get_cursor_y() > get_h() - bottom_margin)
1045 difference = get_cursor_y() -
1046 (get_h() - bottom_margin);
1048 if(difference != 0) {
1049 int min_y = -(get_text_rows() * text_height -
1050 get_h() + bottom_margin);
1052 text_y -= difference;
1053 // printf("BC_TextBox::repeat_event %d %d %d\n",
1057 text_y = MAX(min_y, text_y);
1058 text_y = MIN(text_y, top_margin);
1065 if(get_cursor_x() < left_margin)
1067 int difference = left_margin - get_cursor_x();
1069 text_x += difference;
1070 text_x = MIN(text_x, left_margin);
1074 else if(get_cursor_x() > get_w() - right_margin)
1076 int difference = get_cursor_x() - (get_w() - right_margin);
1077 int new_text_x = text_x - difference;
1079 // Get width of current row
1082 int wtext_len = wtext_update();
1085 for(int i = 0, k = text_y; i < wtext_len; k += text_height)
1088 while(wtext[i] != '\n' && i < wtext_len) {
1092 if(wtext[i] == '\n') i++;
1094 if(cursor_y >= k && cursor_y < k + text_height) {
1095 row_width = get_text_width(font,
1097 row_end - row_begin);
1103 min_x = -row_width + get_w() - left_margin - BCCURSORW;
1104 new_text_x = MAX(new_text_x, min_x);
1105 new_text_x = MIN(new_text_x, left_margin);
1107 if(new_text_x < text_x) text_x = new_text_x;
1116 void BC_TextBox::default_keypress(int &dispatch_event, int &result)
1118 int key = top_level->get_keypress(), len;
1119 if( (key == RETURN) || ( key >= 32 && key <= 255 ) ) {
1120 wchar_t *wkeys = top_level->get_wkeystring(&len);
1121 if( key == RETURN ) { wkeys[0] = '\n'; wkeys[1] = 0; len = 1; }
1122 insert_text(wkeys, len);
1130 int BC_TextBox::keypress_event()
1132 // Result == 2 contents changed
1133 // Result == 1 trapped keypress
1134 // Result == 0 nothing
1136 int dispatch_event = 0;
1138 if(!active || !enabled) return 0;
1140 int wtext_len = wtext_update();
1141 last_keypress = get_keypress();
1143 if( unicode_active >= 0 ) {
1146 switch( last_keypress ) {
1147 //unicode active acitons
1149 for( int i=highlight_letter1+1; i<highlight_letter2; ++i ) {
1150 int ch = nib(wtext[i]);
1151 if( ch < 0 ) return 1;
1152 wch = (wch<<4) + ch;
1156 unicode_active = -1;
1162 unicode_active = -1;
1167 if(ibeam_letter > 0) {
1168 delete_selection(ibeam_letter - 1, ibeam_letter, wtext_len);
1169 highlight_letter2 = --ibeam_letter;
1170 if( highlight_letter1 >= highlight_letter2 )
1171 unicode_active = -1;
1176 case '0': case '1': case '2': case '3': case '4':
1177 case '5': case '6': case '7': case '8': case '9':
1178 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
1179 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': {
1180 int n = nib(last_keypress);
1181 wch = n < 10 ? '0'+n : 'A'+n-10;
1195 insert_text(&wch, wlen);
1197 if( unicode_active >= 0 )
1198 highlight_letter2 = ibeam_letter;
1200 highlight_letter1 = highlight_letter2 = 0;
1206 //printf("BC_TextBox::keypress_event %d %x\n", __LINE__, last_keypress)
1207 switch(last_keypress) {
1209 // Deactivate the suggestions
1210 if( suggestions_popup ) {
1215 top_level->deactivate();
1222 highlight_letter1 = highlight_letter2 = 0;
1223 ibeam_letter = wtext_update();
1224 top_level->deactivate();
1229 default_keypress(dispatch_event, result);
1234 // Handle like a default keypress
1236 top_level->cycle_textboxes(1);
1241 top_level->cycle_textboxes(-1);
1246 if(ibeam_letter > 0) {
1247 int old_ibeam_letter = ibeam_letter;
1255 while(ibeam_letter > 0 && isalnum(wtext[ibeam_letter - 1]))
1260 if(top_level->shift_down()) {
1261 // Initialize highlighting
1262 if(highlight_letter1 == highlight_letter2) {
1263 highlight_letter1 = ibeam_letter;
1264 highlight_letter2 = old_ibeam_letter;
1266 else if(highlight_letter1 == old_ibeam_letter) {
1267 // Extend left highlight
1268 highlight_letter1 = ibeam_letter;
1270 else if(highlight_letter2 == old_ibeam_letter) {
1271 // Shrink right highlight
1272 highlight_letter2 = ibeam_letter;
1276 highlight_letter1 = highlight_letter2 = ibeam_letter;
1281 if(keypress_draw) draw(1);
1287 if(ibeam_letter < wtext_len) {
1288 int old_ibeam_letter = ibeam_letter;
1295 while(ibeam_letter < wtext_len && isalnum(wtext[ibeam_letter++]));
1301 if(top_level->shift_down()) {
1302 // Initialize highlighting
1303 if(highlight_letter1 == highlight_letter2) {
1304 highlight_letter1 = old_ibeam_letter;
1305 highlight_letter2 = ibeam_letter;
1307 else if(highlight_letter1 == old_ibeam_letter) {
1308 // Shrink left highlight
1309 highlight_letter1 = ibeam_letter;
1311 else if(highlight_letter2 == old_ibeam_letter) {
1312 // Expand right highlight
1313 highlight_letter2 = ibeam_letter;
1317 highlight_letter1 = highlight_letter2 = ibeam_letter;
1321 if(keypress_draw) draw(1);
1327 if( suggestions && suggestions_popup ) {
1328 // Pass to suggestions popup
1329 //printf("BC_TextBox::keypress_event %d\n", __LINE__);
1330 suggestions_popup->activate(1);
1331 suggestions_popup->keypress_event();
1334 else if(ibeam_letter > 0) {
1335 //printf("BC_TextBox::keypress_event 1 %d %d %d\n", ibeam_x, ibeam_y, ibeam_letter);
1336 int new_letter = get_cursor_letter2(ibeam_x + text_x,
1337 ibeam_y + text_y - text_height);
1338 //printf("BC_TextBox::keypress_event 2 %d %d %d\n", ibeam_x, ibeam_y, new_letter);
1341 if(top_level->shift_down()) {
1342 // Initialize highlighting
1343 if(highlight_letter1 == highlight_letter2) {
1344 highlight_letter1 = new_letter;
1345 highlight_letter2 = ibeam_letter;
1347 else if(highlight_letter1 == ibeam_letter) {
1348 // Expand left highlight
1349 highlight_letter1 = new_letter;
1351 else if(highlight_letter2 == ibeam_letter) {
1352 // Shrink right highlight
1353 highlight_letter2 = new_letter;
1357 highlight_letter1 = highlight_letter2 = new_letter;
1359 if(highlight_letter1 > highlight_letter2) {
1360 int temp = highlight_letter1;
1361 highlight_letter1 = highlight_letter2;
1362 highlight_letter2 = temp;
1364 ibeam_letter = new_letter;
1367 if(keypress_draw) draw(1);
1373 if(ibeam_letter > 0) {
1374 int new_letter = get_cursor_letter2(ibeam_x + text_x,
1375 ibeam_y + text_y - get_h());
1378 if(top_level->shift_down()) {
1379 // Initialize highlighting
1380 if(highlight_letter1 == highlight_letter2) {
1381 highlight_letter1 = new_letter;
1382 highlight_letter2 = ibeam_letter;
1384 else if(highlight_letter1 == ibeam_letter) {
1385 // Expand left highlight
1386 highlight_letter1 = new_letter;
1388 else if(highlight_letter2 == ibeam_letter) {
1389 // Shrink right highlight
1390 highlight_letter2 = new_letter;
1394 highlight_letter1 = highlight_letter2 = new_letter;
1396 if(highlight_letter1 > highlight_letter2) {
1397 int temp = highlight_letter1;
1398 highlight_letter1 = highlight_letter2;
1399 highlight_letter2 = temp;
1401 ibeam_letter = new_letter;
1404 if(keypress_draw) draw(1);
1410 // printf("BC_TextBox::keypress_event %d %p %p\n",
1413 // suggestions_popup);
1414 if( suggestions && suggestions_popup ) {
1415 // Pass to suggestions popup
1416 suggestions_popup->activate(1);
1417 suggestions_popup->keypress_event();
1421 // if(ibeam_letter > 0)
1424 int new_letter = get_cursor_letter2(ibeam_x + text_x,
1425 ibeam_y + text_y + text_height);
1426 //printf("BC_TextBox::keypress_event 10 %d\n", new_letter);
1428 if(top_level->shift_down()) {
1429 // Initialize highlighting
1430 if(highlight_letter1 == highlight_letter2) {
1431 highlight_letter1 = new_letter;
1432 highlight_letter2 = ibeam_letter;
1434 else if(highlight_letter1 == ibeam_letter) {
1435 // Shrink left highlight
1436 highlight_letter1 = new_letter;
1438 else if(highlight_letter2 == ibeam_letter) {
1439 // Expand right highlight
1440 highlight_letter2 = new_letter;
1444 highlight_letter1 = highlight_letter2 = new_letter;
1446 if(highlight_letter1 > highlight_letter2) {
1447 int temp = highlight_letter1;
1448 highlight_letter1 = highlight_letter2;
1449 highlight_letter2 = temp;
1451 ibeam_letter = new_letter;
1454 if(keypress_draw) draw(1);
1456 //printf("BC_TextBox::keypress_event 20 %d\n", ibeam_letter);
1463 int new_letter = get_cursor_letter2(ibeam_x + text_x,
1464 ibeam_y + text_y + get_h());
1465 //printf("BC_TextBox::keypress_event 10 %d\n", new_letter);
1467 if(top_level->shift_down()) {
1468 // Initialize highlighting
1469 if(highlight_letter1 == highlight_letter2) {
1470 highlight_letter1 = new_letter;
1471 highlight_letter2 = ibeam_letter;
1473 else if(highlight_letter1 == ibeam_letter) {
1474 // Shrink left highlight
1475 highlight_letter1 = new_letter;
1477 else if(highlight_letter2 == ibeam_letter) {
1478 // Expand right highlight
1479 highlight_letter2 = new_letter;
1483 highlight_letter1 = highlight_letter2 = new_letter;
1485 if(highlight_letter1 > highlight_letter2) {
1486 int temp = highlight_letter1;
1487 highlight_letter1 = highlight_letter2;
1488 highlight_letter2 = temp;
1490 ibeam_letter = new_letter;
1493 if(keypress_draw) draw(1);
1495 //printf("BC_TextBox::keypress_event 20 %d\n", ibeam_letter);
1502 int old_ibeam_letter = ibeam_letter;
1504 while(ibeam_letter < wtext_len && wtext[ibeam_letter] != '\n')
1507 if(top_level->shift_down()) {
1509 if(highlight_letter1 == highlight_letter2) {
1510 highlight_letter2 = ibeam_letter;
1511 highlight_letter1 = old_ibeam_letter;
1513 else if(highlight_letter1 == old_ibeam_letter) {
1515 highlight_letter1 = highlight_letter2;
1516 highlight_letter2 = ibeam_letter;
1518 else if(highlight_letter2 == old_ibeam_letter) {
1520 highlight_letter2 = ibeam_letter;
1524 highlight_letter1 = highlight_letter2 = ibeam_letter;
1527 if(keypress_draw) draw(1);
1534 int old_ibeam_letter = ibeam_letter;
1536 while(ibeam_letter > 0 && wtext[ibeam_letter - 1] != '\n')
1539 if(top_level->shift_down())
1542 if(highlight_letter1 == highlight_letter2)
1544 highlight_letter2 = old_ibeam_letter;
1545 highlight_letter1 = ibeam_letter;
1549 if(highlight_letter1 == old_ibeam_letter)
1551 highlight_letter1 = ibeam_letter;
1555 if(highlight_letter2 == old_ibeam_letter)
1557 highlight_letter2 = highlight_letter1;
1558 highlight_letter1 = ibeam_letter;
1562 highlight_letter1 = highlight_letter2 = ibeam_letter;
1565 if(keypress_draw) draw(1);
1572 if(highlight_letter1 == highlight_letter2) {
1573 if(ibeam_letter > 0) {
1574 delete_selection(ibeam_letter - 1, ibeam_letter, wtext_len);
1579 delete_selection(highlight_letter1, highlight_letter2, wtext_len);
1580 highlight_letter2 = ibeam_letter = highlight_letter1;
1584 if(keypress_draw) draw(1);
1590 //printf("BC_TextBox::keypress_event %d\n", __LINE__);
1591 if(highlight_letter1 == highlight_letter2) {
1592 if(ibeam_letter < wtext_len) {
1593 delete_selection(ibeam_letter, ibeam_letter + 1, wtext_len);
1597 delete_selection(highlight_letter1, highlight_letter2, wtext_len);
1598 highlight_letter2 = ibeam_letter = highlight_letter1;
1602 if(keypress_draw) draw(1);
1609 switch( get_keypress() ) {
1610 case 'c': case 'C': {
1611 if(highlight_letter1 != highlight_letter2) {
1612 copy_selection(SECONDARY_SELECTION);
1616 case 'v': case 'V': {
1617 paste_selection(SECONDARY_SELECTION);
1619 if(keypress_draw) draw(1);
1623 case 'x': case 'X': {
1624 if(highlight_letter1 != highlight_letter2) {
1625 copy_selection(SECONDARY_SELECTION);
1626 delete_selection(highlight_letter1, highlight_letter2, wtext_len);
1627 highlight_letter2 = ibeam_letter = highlight_letter1;
1631 if(keypress_draw) draw(1);
1635 case 'u': case 'U': {
1636 if( shift_down() ) {
1637 unicode_active = ibeam_letter;
1639 insert_text(&wkey, 1);
1641 highlight_letter1 = unicode_active;
1642 highlight_letter2 = ibeam_letter;
1651 default_keypress(dispatch_event, result);
1656 if(result) skip_cursor->update();
1657 if(dispatch_event && handle_event())
1664 int BC_TextBox::uses_text()
1670 void BC_TextBox::delete_selection(int letter1, int letter2, int wtext_len)
1673 for(i=letter1, j=letter2; j<wtext_len; i++, j++) {
1674 wtext[i] = wtext[j];
1682 void BC_TextBox::insert_text(const wchar_t *wcp, int len)
1684 if( len < 0 ) len = wcslen(wcp);
1685 int wtext_len = wtext_update();
1686 if( unicode_active < 0 && highlight_letter1 < highlight_letter2 ) {
1687 delete_selection(highlight_letter1, highlight_letter2, wtext_len);
1688 highlight_letter2 = ibeam_letter = highlight_letter1;
1689 wtext_len = wtext_update();
1693 for(i=wtext_len-1, j=wtext_len+len-1; i>=ibeam_letter; i--, j--) {
1694 if( j >= wsize ) continue;
1695 wtext[j] = wtext[i];
1698 for(i = ibeam_letter, j = 0; j < len; j++, i++) {
1699 if( i >= wsize ) break;
1702 if( (wlen+=len) > wsize ) wlen = wsize;
1703 if( (ibeam_letter+=len) > wsize ) ibeam_letter = wsize;
1704 wtext[wlen] = 0; // wtext allocated wsize+1
1708 int BC_TextBox::is_separator(const char *txt, int i)
1710 if( i != 0 || separators[0] != '+' ) return !isalnum(txt[i]);
1711 return txt[0] != '+' && txt[0] != '-' && !isalnum(txt[0]);
1714 // used for time entry
1715 void BC_TextBox::do_separators(int ibeam_left)
1719 // Remove separators from text
1720 int wtext_len = wtext_update();
1721 for(int i = 0; i < wtext_len; ) {
1722 if( !iswalnum(wtext[i]) ) {
1723 for(int j = i; j < wtext_len - 1; j++)
1724 wtext[j] = wtext[j + 1];
1725 if(!ibeam_left && i < ibeam_letter) ibeam_letter--;
1731 wtext[wtext_len] = 0;
1737 // Insert separators into text
1738 int separator_len = strlen(separators);
1739 for(int i = 0; i < separator_len; i++) {
1741 // Insert a separator
1742 if( is_separator(separators,i) ) {
1743 for(int j = wtext_len; j >= i; j--) {
1744 wtext[j + 1] = wtext[j];
1746 if(!ibeam_left && i < ibeam_letter) ibeam_letter++;
1748 wtext[i] = separators[i];
1752 wtext[i] = separators[i];
1757 wtext[separator_len] = 0;
1758 wlen = separator_len;
1762 int BC_TextBox::get_x_position(int i, int start)
1764 return get_text_width(font, &wtext[start], i - start);
1767 void BC_TextBox::get_ibeam_position(int &x, int &y)
1769 int i, row_begin, row_end;
1770 int wtext_len = wtext_update();
1773 for( i=0; i<wtext_len; ) {
1775 for(; i<wtext_len && wtext[i]!='\n'; i++);
1778 if( ibeam_letter >= row_begin && ibeam_letter <= row_end ) {
1779 x = get_x_position(ibeam_letter, row_begin);
1780 //printf("BC_TextBox::get_ibeam_position %d %d %d %d %d\n", ibeam_letter, row_begin, row_end, x, y);
1784 if( i < wtext_len && wtext[i] == '\n' ) {
1789 //printf("BC_TextBox::get_ibeam_position 10 %d %d\n", x, y);
1795 void BC_TextBox::set_text_row(int row)
1797 text_x = left_margin;
1798 text_y = -(row * text_height) + top_margin;
1802 int BC_TextBox::get_text_row()
1804 return -(text_y - top_margin) / text_height;
1807 void BC_TextBox::find_ibeam(int dispatch_event)
1810 int old_x = text_x, old_y = text_y;
1812 get_ibeam_position(x, y);
1814 if(left_margin + text_x + x >= get_w() - right_margin - BCCURSORW)
1816 text_x = -(x - (get_w() - get_w() / 4)) + left_margin;
1817 if(text_x > left_margin) text_x = left_margin;
1820 if(left_margin + text_x + x < left_margin)
1822 text_x = -(x - (get_w() / 4)) + left_margin;
1823 if(text_x > left_margin) text_x = left_margin;
1826 int text_row = y / text_height;
1827 if( text_row < rows ) text_y = top_margin;
1829 int pix_rows = get_h() - bottom_margin - (y + text_y);
1830 if( pix_rows < text_height )
1831 text_y -= text_height * ((2*text_height-1-pix_rows) / text_height);
1833 pix_rows = y + text_y - top_margin;
1834 if( pix_rows < 0 ) {
1835 text_y += text_height * ((text_height-1-pix_rows) / text_height);
1836 if( text_y > top_margin ) text_y = top_margin;
1839 if(dispatch_event && (old_x != text_x || old_y != text_y)) motion_event();
1843 int BC_TextBox::get_cursor_letter(int cursor_x, int cursor_y)
1845 int i, j, k, row_begin, row_end, result = 0, done = 0;
1846 int column1, column2;
1847 int got_visible_row = 0;
1849 // Select complete row if cursor above the window
1850 //printf("BC_TextBox::get_cursor_letter %d %d\n", __LINE__, text_y);
1851 if(cursor_y < text_y - text_height)
1857 int wtext_len = wtext_update();
1859 for(i=0, k=text_y; i<wtext_len && k<get_h() && !done; k+=text_height) {
1860 // Simulate drawing of 1 row
1862 for(j = 0; wtext[i]!='\n' && i<wtext_len; i++);
1866 int first_visible_row = 0;
1867 int last_visible_row = 0;
1868 if( k+text_height > top_margin && !got_visible_row) {
1869 first_visible_row = 1;
1870 got_visible_row = 1;
1873 if( (k+text_height >= get_h() - bottom_margin ||
1874 (row_end >= wtext_len && k < get_h() - bottom_margin &&
1875 k + text_height > 0)) )
1876 last_visible_row = 1;
1878 // Cursor is inside vertical range of row
1879 if((cursor_y >= top_margin &&
1880 cursor_y < get_h() - bottom_margin &&
1881 cursor_y >= k && cursor_y < k + text_height) ||
1882 // Cursor is above 1st row
1883 (cursor_y < k + text_height && first_visible_row) ||
1884 // Cursor is below last row
1885 (cursor_y >= k && last_visible_row))
1887 column1 = column2 = 0;
1888 for(j = row_begin; j<wsize && j<=row_end && !done; j++) {
1889 column2 = get_text_width(font, &wtext[row_begin], j-row_begin) + text_x;
1890 if((column2 + column1) / 2 >= cursor_x) {
1893 // printf("BC_TextBox::get_cursor_letter %d %d %d %d\n",
1894 // __LINE__, result, first_visible_row, last_visible_row);
1905 if(wtext[i] == '\n') i++;
1907 // Select complete row if last visible & cursor is below window
1908 if(last_visible_row && cursor_y > k + text_height * 2)
1911 if(i >= wtext_len && !done) {
1917 // printf("BC_TextBox::get_cursor_letter %d cursor_y=%d k=%d h=%d %d %d\n",
1918 // __LINE__, cursor_y, k, get_h(), first_visible_row, last_visible_row);
1919 if(result < 0) result = 0;
1920 if(result > wtext_len) {
1921 //printf("BC_TextBox::get_cursor_letter %d\n", __LINE__);
1929 int BC_TextBox::get_cursor_letter2(int cursor_x, int cursor_y)
1931 int i, j, k, row_begin, row_end, result = 0, done = 0;
1932 int column1, column2;
1933 int wtext_len = wtext_update();
1935 if(cursor_y < text_y) {
1940 for(i = 0, k = text_y; i < wtext_len && !done; k += text_height) {
1942 for(; wtext[i] != '\n' && i < wtext_len; i++);
1945 if(cursor_y >= k && cursor_y < k + text_height) {
1946 column1 = column2 = 0;
1947 for(j = 0; j <= row_end - row_begin && !done; j++) {
1948 column2 = get_text_width(font, &wtext[row_begin], j) + text_x;
1949 if((column2 + column1) / 2 >= cursor_x) {
1950 result = row_begin + j - 1;
1961 if(wtext[i] == '\n') i++;
1963 if(i >= wtext_len && !done) {
1967 if(result < 0) result = 0;
1968 if(result > wtext_len) result = wtext_len;
1973 void BC_TextBox::select_word(int &letter1, int &letter2, int ibeam_letter)
1975 int wtext_len = wtext_update();
1976 letter1 = letter2 = ibeam_letter;
1977 if( letter1 < 0 ) letter1 = 0;
1978 if( letter2 < 0 ) letter2 = 0;
1979 if( letter1 > wtext_len ) letter1 = wtext_len;
1980 if( letter2 > wtext_len ) letter2 = wtext_len;
1981 if( !wtext_len ) return;
1982 for( int i=letter1; i>=0 && iswalnum(wtext[i]); --i ) letter1 = i;
1983 for( int i=letter2; i<wtext_len && iswalnum(wtext[i]); ) letter2 = ++i;
1984 if( letter2 < wtext_len && wtext[letter2] == ' ' ) ++letter2;
1988 void BC_TextBox::select_line(int &letter1, int &letter2, int ibeam_letter)
1990 int wtext_len = wtext_update();
1991 letter1 = letter2 = ibeam_letter;
1992 if( letter1 < 0 ) letter1 = 0;
1993 if( letter2 < 0 ) letter2 = 0;
1994 if( letter1 > wtext_len ) letter1 = wtext_len;
1995 if( letter2 > wtext_len ) letter2 = wtext_len;
1996 if( !wtext_len ) return;
1997 for( int i=letter1; i>=0 && wtext[i]!='\n'; --i ) letter1 = i;
1998 for( int i=letter2; i<wtext_len && wtext[i]!='\n'; ) letter2 = ++i;
2001 void BC_TextBox::copy_selection(int clipboard_num)
2003 int wtext_len = wtext_update();
2004 if(!wtext_len) return;
2006 if(highlight_letter1 >= wtext_len || highlight_letter2 > wtext_len ||
2007 highlight_letter1 < 0 || highlight_letter2 < 0 ||
2008 highlight_letter2 - highlight_letter1 <= 0) return;
2009 int clip_len = highlight_letter2 - highlight_letter1;
2010 //printf(" BC_TextBox::copy_selection %d %d %d\n",highlight_letter1, highlight_letter2, clip_len);
2011 char ctext[4*clip_len+4];
2012 clip_len = text_update(&wtext[highlight_letter1],clip_len, ctext,4*clip_len+4);
2013 to_clipboard(ctext, clip_len, clipboard_num);
2014 selection_active = 1;
2017 int BC_TextBox::selection_clear_event()
2019 if( !is_event_win() ) return 0;
2020 selection_active = 0;
2025 void BC_TextBox::paste_selection(int clipboard_num)
2027 int len = clipboard_len(clipboard_num);
2030 char cstring[len]; wchar_t wstring[len];
2031 from_clipboard(cstring, len, clipboard_num); --len;
2032 //printf("BC_TextBox::paste_selection %d '%*.*s'\n",len,len,len,cstring);
2033 len = BC_Resources::encode(BC_Resources::encoding, BC_Resources::wide_encoding,
2034 cstring,len, (char *)wstring,(len+1)*sizeof(wchar_t)) / sizeof(wchar_t);
2035 insert_text(wstring, len);
2039 void BC_TextBox::set_keypress_draw(int value)
2041 keypress_draw = value;
2044 int BC_TextBox::get_last_keypress()
2046 return last_keypress;
2049 int BC_TextBox::get_ibeam_letter()
2051 return ibeam_letter;
2054 void BC_TextBox::set_ibeam_letter(int number, int redraw)
2056 this->ibeam_letter = number;
2063 void BC_TextBox::set_separators(const char *separators)
2065 this->separators = (char*)separators;
2068 int BC_TextBox::get_rows()
2079 BC_TextBoxSuggestions::BC_TextBoxSuggestions(BC_TextBox *text_box, int x, int y)
2080 : BC_ListBox(x, y, text_box->get_w(), 200, LISTBOX_TEXT,
2081 text_box->suggestions, 0, 0, 1, 0, 1)
2083 this->text_box = text_box;
2085 set_justify(LISTBOX_LEFT);
2088 BC_TextBoxSuggestions::~BC_TextBoxSuggestions()
2092 int BC_TextBoxSuggestions::handle_event()
2094 char *current_suggestion = 0;
2095 BC_ListBoxItem *item = get_selection(0, 0);
2096 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2097 if(item && (current_suggestion=item->get_text()) != 0)
2099 int col = text_box->suggestion_column;
2100 int len = BCTEXTLEN-1 - col;
2101 char *cp = &text_box->text[col];
2102 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2103 strncpy(cp, current_suggestion, len);
2104 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2105 if( (col=strlen(current_suggestion)) >= len )
2107 text_box->dirty = 1;
2111 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2112 text_box->highlight_letter1 =
2113 text_box->highlight_letter2 =
2114 text_box->ibeam_letter = text_box->tstrlen();
2115 text_box->wtext_update();
2117 text_box->handle_event();
2118 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2123 BC_ScrollTextBox::BC_ScrollTextBox(BC_WindowBase *parent_window,
2124 int x, int y, int w, int rows,
2125 const char *default_text, int default_size)
2127 this->parent_window = parent_window;
2132 xscroll = 0; yscroll = 0;
2133 this->default_text = default_text;
2134 this->default_wtext = 0;
2135 this->default_size = default_size;
2138 BC_ScrollTextBox::BC_ScrollTextBox(BC_WindowBase *parent_window,
2139 int x, int y, int w, int rows,
2140 const wchar_t *default_wtext, int default_size)
2142 this->parent_window = parent_window;
2147 xscroll = 0; yscroll = 0;
2148 this->default_text = 0;
2149 this->default_wtext = default_wtext;
2150 this->default_size = default_size;
2153 BC_ScrollTextBox::~BC_ScrollTextBox()
2163 void BC_ScrollTextBox::create_objects()
2165 // Must be created first
2166 parent_window->add_subwindow(text = default_wtext ?
2167 new BC_ScrollTextBoxText(this, default_wtext) :
2168 new BC_ScrollTextBoxText(this, default_text));
2172 void BC_ScrollTextBox::set_text(char *text, int isz)
2174 this->text->set_text(text, isz);
2175 update_scrollbars();
2178 int BC_ScrollTextBox::set_text_row(int n)
2180 text->set_text_row(n);
2181 update_scrollbars();
2185 void BC_ScrollTextBox::update(const char *text)
2187 this->text->update(text);
2188 update_scrollbars();
2191 void BC_ScrollTextBox::update(const wchar_t *wtext)
2193 this->text->update(wtext);
2194 update_scrollbars();
2197 void BC_ScrollTextBox::reposition_window(int x, int y, int w, int rows)
2203 update_scrollbars();
2206 int BC_ScrollTextBox::button_press_event()
2208 return text->BC_TextBox::button_press_event();
2210 int BC_ScrollTextBox::button_release_event()
2212 return text->BC_TextBox::button_release_event();
2215 int BC_ScrollTextBox::get_h() { return text->get_h(); }
2216 const char *BC_ScrollTextBox::get_text() { return text->get_text(); }
2217 const wchar_t *BC_ScrollTextBox::get_wtext() { return text->get_wtext(); }
2219 int BC_ScrollTextBox::get_buttonpress()
2221 return text->BC_TextBox::get_buttonpress();
2223 void BC_ScrollTextBox::wset_selection(int char1, int char2, int ibeam)
2225 text->wset_selection(char1, char2, ibeam);
2227 void BC_ScrollTextBox::set_selection(int char1, int char2, int ibeam)
2229 text->set_selection(char1, char2, ibeam);
2231 int BC_ScrollTextBox::get_ibeam_letter()
2233 return text->get_ibeam_letter();
2235 int BC_ScrollTextBox::get_x_pos()
2237 return text->left_margin - text->get_text_x();
2239 void BC_ScrollTextBox::set_x_pos(int x)
2241 text->set_text_x(text->left_margin - x);
2245 BC_ScrollTextBoxText::BC_ScrollTextBoxText(BC_ScrollTextBox *gui, const char *text)
2246 : BC_TextBox(gui->x, gui->y,
2247 gui->w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
2248 gui->rows, gui->default_size, (char*)text, 1, MEDIUMFONT)
2253 BC_ScrollTextBoxText::BC_ScrollTextBoxText(BC_ScrollTextBox *gui, const wchar_t *wtext)
2254 : BC_TextBox(gui->x, gui->y,
2255 gui->w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
2256 gui->rows, gui->default_size, (wchar_t*)wtext, 1, MEDIUMFONT)
2261 BC_ScrollTextBoxText::~BC_ScrollTextBoxText()
2270 void BC_ScrollTextBox::update_scrollbars()
2272 int view_w = w, view_rows = rows;
2273 int view_h = BC_TextBox::calculate_row_h(view_rows, parent_window);
2274 int text_rows = text->get_text_rows();
2275 int text_width = parent_window->get_text_width(text->font, text->get_wtext());
2276 BC_Resources *resources = parent_window->get_resources();
2277 int need_xscroll = 0, need_yscroll = 0;
2279 // Create scrollbars as needed
2283 if( !need_xscroll && (text->get_text_x() != text->left_margin ||
2284 text_width >= view_w - text->left_margin - text->right_margin) ) {
2285 resize = need_xscroll = 1;
2286 view_h -= resources->hscroll_data[SCROLL_HANDLE_UP]->get_h();
2287 view_rows = BC_TextBox::pixels_to_rows(parent_window, text->font, view_h);
2289 if( !need_yscroll && (text->get_text_y() != text->top_margin ||
2290 text_rows > view_rows) ) {
2291 resize = need_yscroll = 1;
2292 view_w -= resources->vscroll_data[SCROLL_HANDLE_UP]->get_w();
2296 if( !need_xscroll && xscroll ) {
2298 delete xscroll; xscroll = 0;
2300 if( !need_yscroll && yscroll ) {
2302 delete yscroll; yscroll = 0;
2305 if( view_rows != text->get_rows() || view_w != text->get_w() ) {
2306 text->reposition_window(x, y, view_w, view_rows);
2308 if( need_xscroll && !xscroll ) {
2309 xscroll = new BC_ScrollTextBoxXScroll(this);
2310 parent_window->add_subwindow(xscroll);
2311 text->xscroll = xscroll;
2312 xscroll->bound_to = text;
2313 xscroll->show_window();
2315 if( need_yscroll && !yscroll ) {
2316 yscroll = new BC_ScrollTextBoxYScroll(this);
2317 parent_window->add_subwindow(yscroll);
2318 text->yscroll = yscroll;
2319 yscroll->bound_to = text;
2320 yscroll->show_window();
2323 xscroll->reposition_window(x, y + text->get_h(), view_w);
2324 int xpos = get_x_pos();
2325 if( xpos != xscroll->get_value() )
2326 xscroll->update_value(xpos);
2327 if( text_width != xscroll->get_length() ||
2328 view_w != xscroll->get_handlelength() )
2329 xscroll->update_length(text_width, xpos, view_w, 0);
2332 yscroll->reposition_window(x + w - yscroll->get_span(), y, text->get_h());
2333 int text_row = text->get_text_row();
2334 if( text_row != yscroll->get_value() )
2335 yscroll->update_value(text_row);
2336 if( text_rows != yscroll->get_length() ||
2337 view_rows != yscroll->get_handlelength() )
2338 yscroll->update_length(text_rows, text_row, view_rows, 0);
2342 int BC_ScrollTextBoxText::handle_event()
2344 gui->update_scrollbars();
2345 return gui->handle_event();
2348 int BC_ScrollTextBoxText::motion_event()
2350 gui->update_scrollbars();
2354 BC_ScrollTextBoxXScroll::BC_ScrollTextBoxXScroll(BC_ScrollTextBox *gui)
2355 : BC_ScrollBar(gui->x, gui->y + gui->text->get_h(), SCROLL_HORIZ + SCROLL_STRETCH,
2356 gui->text->get_w(), gui->text->get_text_width(MEDIUMFONT, gui->get_wtext()),
2362 BC_ScrollTextBoxXScroll::~BC_ScrollTextBoxXScroll()
2366 int BC_ScrollTextBoxXScroll::handle_event()
2368 gui->set_x_pos(get_position());
2372 BC_ScrollTextBoxYScroll::BC_ScrollTextBoxYScroll(BC_ScrollTextBox *gui)
2373 : BC_ScrollBar(gui->x + gui->text->get_w(), gui->y, SCROLL_VERT,
2374 gui->text->get_h(), gui->text->get_text_rows(), 0, gui->rows)
2379 BC_ScrollTextBoxYScroll::~BC_ScrollTextBoxYScroll()
2383 int BC_ScrollTextBoxYScroll::handle_event()
2385 gui->text->set_text_row(get_position());
2391 BC_PopupTextBoxText::BC_PopupTextBoxText(BC_PopupTextBox *popup, int x, int y, const char *text)
2392 : BC_TextBox(x, y, popup->text_w, 1, text, BCTEXTLEN)
2394 this->popup = popup;
2397 BC_PopupTextBoxText::BC_PopupTextBoxText(BC_PopupTextBox *popup, int x, int y, const wchar_t *wtext)
2398 : BC_TextBox(x, y, popup->text_w, 1, wtext, BCTEXTLEN)
2400 this->popup = popup;
2403 BC_PopupTextBoxText::~BC_PopupTextBoxText()
2413 int BC_PopupTextBoxText::handle_event()
2415 popup->handle_event();
2419 BC_PopupTextBoxList::BC_PopupTextBoxList(BC_PopupTextBox *popup, int x, int y)
2421 popup->text_w + BC_WindowBase::get_resources()->listbox_button[0]->get_w(),
2422 popup->list_h, popup->list_format, popup->list_items, 0, 0, 1, 0, 1)
2424 this->popup = popup;
2426 int BC_PopupTextBoxList::handle_event()
2428 BC_ListBoxItem *item = get_selection(0, 0);
2431 popup->textbox->update(item->get_text());
2432 popup->textbox->set_text_row(0);
2433 popup->handle_event();
2441 BC_PopupTextBox::BC_PopupTextBox(BC_WindowBase *parent_window,
2442 ArrayList<BC_ListBoxItem*> *list_items,
2443 const char *default_text, int x, int y,
2444 int text_w, int list_h, int list_format)
2448 this->list_h = list_h;
2449 this->list_format = list_format;
2450 this->default_text = (char*)default_text;
2451 this->default_wtext = 0;
2452 this->text_w = text_w;
2453 this->parent_window = parent_window;
2454 this->list_items = list_items;
2457 BC_PopupTextBox::~BC_PopupTextBox()
2467 int BC_PopupTextBox::create_objects()
2469 int x = this->x, y = this->y;
2470 parent_window->add_subwindow(textbox = default_wtext ?
2471 new BC_PopupTextBoxText(this, x, y, default_wtext) :
2472 new BC_PopupTextBoxText(this, x, y, default_text));
2473 x += textbox->get_w();
2474 parent_window->add_subwindow(listbox = new BC_PopupTextBoxList(this, x, y));
2478 void BC_PopupTextBox::update(const char *text)
2480 textbox->update(text);
2481 textbox->set_text_row(0);
2484 void BC_PopupTextBox::update_list(ArrayList<BC_ListBoxItem*> *data)
2486 listbox->update(data, 0, 0, 1);
2490 const char* BC_PopupTextBox::get_text()
2492 return textbox->get_text();
2495 const wchar_t* BC_PopupTextBox::get_wtext()
2497 return textbox->get_wtext();
2500 int BC_PopupTextBox::get_number()
2502 return listbox->get_selection_number(0, 0);
2505 int BC_PopupTextBox::get_x()
2510 int BC_PopupTextBox::get_y()
2515 int BC_PopupTextBox::get_w()
2517 return textbox->get_w() + listbox->get_w();
2520 int BC_PopupTextBox::get_h()
2522 return textbox->get_h();
2525 int BC_PopupTextBox::get_show_query()
2527 return listbox->get_show_query();
2530 void BC_PopupTextBox::set_show_query(int v)
2532 listbox->set_show_query(v);
2535 int BC_PopupTextBox::handle_event()
2540 void BC_PopupTextBox::reposition_window(int x, int y)
2545 textbox->reposition_window(x1,
2548 textbox->get_rows());
2549 x1 += textbox->get_w();
2550 listbox->reposition_window(x1, y1, -1, -1, 0);
2551 // if(flush) parent_window->flush();
2567 BC_TumbleTextBoxText::BC_TumbleTextBoxText(BC_TumbleTextBox *popup,
2568 int64_t default_value, int x, int y)
2569 : BC_TextBox(x, y, popup->text_w, 1, default_value)
2571 this->popup = popup;
2574 BC_TumbleTextBoxText::BC_TumbleTextBoxText(BC_TumbleTextBox *popup,
2575 float default_value, int x, int y, int precision)
2576 : BC_TextBox(x, y, popup->text_w, 1, default_value, 1, MEDIUMFONT, precision)
2578 this->popup = popup;
2581 BC_TumbleTextBoxText::~BC_TumbleTextBoxText()
2593 int BC_TumbleTextBoxText::handle_event()
2595 popup->handle_event();
2599 int BC_TumbleTextBoxText::button_press_event()
2601 if( get_enabled() && is_event_win() ) {
2602 if( get_buttonpress() < 4 ) return BC_TextBox::button_press_event();
2603 if( get_buttonpress() == 4 ) popup->tumbler->handle_up_event();
2604 else if( get_buttonpress() == 5 ) popup->tumbler->handle_down_event();
2613 BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window,
2614 int64_t default_value,
2626 this->default_value = default_value;
2627 this->text_w = text_w;
2628 this->parent_window = parent_window;
2634 BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window,
2647 this->default_value = default_value;
2648 this->text_w = text_w;
2649 this->parent_window = parent_window;
2655 BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window,
2656 float default_value_f,
2666 this->min_f = min_f;
2667 this->max_f = max_f;
2668 this->default_value_f = default_value_f;
2669 this->text_w = text_w;
2670 this->parent_window = parent_window;
2676 BC_TumbleTextBox::~BC_TumbleTextBox()
2678 // Recursive delete. Normally ~BC_TumbleTextBox is never called but textbox
2679 // is deleted anyway by the windowbase so textbox deletes this.
2680 if(tumbler) delete tumbler;
2682 // Don't delete text here if we were called by ~BC_TumbleTextBoxText
2691 void BC_TumbleTextBox::reset()
2698 void BC_TumbleTextBox::set_precision(int precision)
2700 this->precision = precision;
2703 void BC_TumbleTextBox::set_increment(float value)
2705 this->increment = value;
2706 if(tumbler) tumbler->set_increment(value);
2709 void BC_TumbleTextBox::set_log_floatincrement(int value)
2711 this->log_floatincrement = value;
2712 if(tumbler) tumbler->set_log_floatincrement(value);
2715 int BC_TumbleTextBox::create_objects()
2717 int x = this->x, y = this->y;
2719 textbox = use_float ?
2720 new BC_TumbleTextBoxText(this, default_value_f, x, y, precision) :
2721 new BC_TumbleTextBoxText(this, default_value, x, y);
2723 parent_window->add_subwindow(textbox);
2724 x += textbox->get_w();
2726 tumbler = use_float ?
2727 (BC_Tumbler *)new BC_FTumbler(textbox, min_f, max_f, x, y) :
2728 (BC_Tumbler *)new BC_ITumbler(textbox, min, max, x, y);
2729 parent_window->add_subwindow(tumbler);
2730 tumbler->set_increment(increment);
2734 const char* BC_TumbleTextBox::get_text()
2736 return textbox->get_text();
2739 const wchar_t* BC_TumbleTextBox::get_wtext()
2741 return textbox->get_wtext();
2744 BC_TextBox* BC_TumbleTextBox::get_textbox()
2749 int BC_TumbleTextBox::update(const char *value)
2751 textbox->update(value);
2752 textbox->set_text_row(0);
2756 int BC_TumbleTextBox::update(int64_t value)
2758 textbox->update(value);
2759 textbox->set_text_row(0);
2763 int BC_TumbleTextBox::update(float value)
2765 textbox->update(value);
2766 textbox->set_text_row(0);
2771 int BC_TumbleTextBox::get_x()
2776 int BC_TumbleTextBox::get_y()
2781 int BC_TumbleTextBox::get_w()
2783 return textbox->get_w() + tumbler->get_w();
2786 int BC_TumbleTextBox::get_h()
2788 return textbox->get_h();
2791 void BC_TumbleTextBox::disable(int hide_text)
2793 if( hide_text && !textbox->is_hidden() )
2794 textbox->hide_window(0);
2795 if( !tumbler->is_hidden() )
2796 tumbler->hide_window(0);
2797 if( !get_enabled() ) return;
2798 return textbox->disable();
2801 void BC_TumbleTextBox::enable()
2803 if( textbox->is_hidden() )
2804 textbox->show_window(0);
2805 if( tumbler->is_hidden() )
2806 tumbler->show_window(0);
2807 if( get_enabled() ) return;
2808 return textbox->enable();
2811 int BC_TumbleTextBox::get_enabled()
2813 return textbox->get_enabled();
2816 int BC_TumbleTextBox::handle_event()
2821 void BC_TumbleTextBox::reposition_window(int x, int y)
2826 textbox->reposition_window(x,
2830 tumbler->reposition_window(x + textbox->get_w(),
2832 // if(flush) parent_window->flush();
2836 void BC_TumbleTextBox::set_boundaries(int64_t min, int64_t max)
2838 tumbler->set_boundaries(min, max);
2841 void BC_TumbleTextBox::set_boundaries(float min, float max)
2843 tumbler->set_boundaries(min, max);
2846 void BC_TumbleTextBox::set_tooltip(const char *text)
2848 textbox->set_tooltip(text);