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"
42 #define VERTICAL_MARGIN 2
43 #define VERTICAL_MARGIN_NOBORDER 0
44 #define HORIZONTAL_MARGIN 4
45 #define HORIZONTAL_MARGIN_NOBORDER 2
47 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
48 int size, char *text, int has_border, int font)
49 : BC_SubWindow(x, y, w, 0, -1)
53 reset_parameters(rows, has_border, font, size);
56 else // text referenced directly
60 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
61 int size, wchar_t *wtext, int has_border, int font)
62 : BC_SubWindow(x, y, w, 0, -1)
66 wsize = size > 0 ? size : wcslen(wtext);
67 if( size <= 0 ) size = 2*wsize;
68 reset_parameters(rows, has_border, font, size);
69 this->wtext = new wchar_t[wsize+1];
70 wcsncpy(this->wtext, wtext, wsize);
71 this->wtext[wsize] = 0;
74 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
75 const char *text, int has_border, int font, int is_utf8)
76 : BC_SubWindow(x, y, w, 0, -1)
78 this->is_utf8 = is_utf8;
80 reset_parameters(rows, has_border, font, BCTEXTLEN);
84 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
85 const wchar_t *wtext, int has_border, int font, int is_utf8)
86 : BC_SubWindow(x, y, w, 0, -1)
88 this->is_utf8 = is_utf8;
90 reset_parameters(rows, has_border, font, BCTEXTLEN);
92 wtext = new wchar_t[wsize+1];
93 wcsncpy(this->wtext, wtext, wsize);
94 this->wtext[wsize] = 0;
97 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
98 int64_t text, int has_border, int font)
99 : BC_SubWindow(x, y, w, 0, -1)
103 reset_parameters(rows, has_border, font, BCSTRLEN);
104 snprintf(this->text, this->tsize, "%jd", text);
105 dirty = 1; wtext_update();
108 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
109 float text, int has_border, int font, int precision)
110 : BC_SubWindow(x, y, w, 0, -1)
114 reset_parameters(rows, has_border, font, BCSTRLEN);
115 this->precision = precision;
116 snprintf(this->text, this->tsize, "%0.*f", precision, text);
117 dirty = 1; wtext_update();
120 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
121 int text, int has_border, int font)
122 : BC_SubWindow(x, y, w, 0, -1)
126 reset_parameters(rows, has_border, font, BCSTRLEN);
127 snprintf(this->text, this->tsize, "%d", text);
128 dirty = 1; wtext_update();
131 BC_TextBox::~BC_TextBox()
133 if(skip_cursor) delete skip_cursor;
134 delete suggestions_popup;
135 suggestions->remove_all_objects();
143 int BC_TextBox::reset_parameters(int rows, int has_border, int font, int size)
145 suggestions = new ArrayList<BC_ListBoxItem*>;
146 suggestions_popup = 0;
147 suggestion_column = 0;
150 this->has_border = has_border;
153 this->tsize = size >= 0 ? size : -size;
154 this->text = size > 0 ? new char[size+1] : 0;
155 if( this->text ) this->text[0] = 0;
158 highlight_letter1 = highlight_letter2 = 0;
159 highlight_letter3 = highlight_letter4 = 0;
173 skip_cursor = new Timer;
184 selection_active = 0;
188 int BC_TextBox::tstrlen()
190 if( !tsize ) return strlen(text);
191 return strnlen(text, tsize);
194 int BC_TextBox::tstrcmp(const char *cp)
196 const char *tp = get_text();
197 if( !tsize ) return strcmp(tp, cp);
198 return strncmp(tp, cp, tsize);
201 char *BC_TextBox::tstrcpy(const char *cp)
206 return strcpy(text, cp);
207 strncpy(text, cp, tsize);
215 char *BC_TextBox::tstrcat(const char *cp)
218 if( !tsize ) return strcat(text, cp);
219 char *result = strncat(text, cp, tsize);
224 int BC_TextBox::wtext_update()
227 const char *src_enc = is_utf8 ? "UTF8" : BC_Resources::encoding;
228 const char *dst_enc = BC_Resources::wide_encoding;
229 int nsize = tsize > 0 ? tsize : strlen(text) + BCTEXTLEN;
230 if( nsize > wsize || !wtext ) {
231 wchar_t *ntext = new wchar_t[nsize+1];
232 memcpy(ntext, wtext, wsize*sizeof(wtext[0]));
233 delete [] wtext; wtext = ntext; wsize = nsize;
235 wlen = BC_Resources::encode(src_enc, dst_enc, text, strlen(text),
236 (char*)wtext, wsize*sizeof(wchar_t)) / sizeof(wchar_t);
243 int BC_TextBox::text_update(const wchar_t *wcp, int wsz, char *tcp, int tsz)
245 const char *src_enc = BC_Resources::wide_encoding;
246 const char *dst_enc = BC_Resources::encoding;
247 if( wsz < 0 ) wsz = wcslen(wcp);
248 int len = BC_Resources::encode(src_enc, dst_enc,
249 (char*)wcp, wsz*sizeof(wchar_t), tcp, tsz);
254 int BC_TextBox::initialize()
258 skip_cursor = new Timer;
259 skip_cursor->update();
261 text_ascent = get_text_ascent(font) + 1;
262 text_descent = get_text_descent(font) + 1;
263 text_height = text_ascent + text_descent;
264 ibeam_letter = wtext_update();
267 left_margin = right_margin = HORIZONTAL_MARGIN;
268 top_margin = bottom_margin = VERTICAL_MARGIN;
272 left_margin = right_margin = HORIZONTAL_MARGIN_NOBORDER;
273 top_margin = bottom_margin = VERTICAL_MARGIN_NOBORDER;
276 text_x = left_margin;
280 // Create the subwindow
281 BC_SubWindow::initialize();
283 BC_Resources *resources = get_resources();
286 if( back_color < 0 ) back_color = resources->text_background;
287 if( high_color < 0 ) high_color = resources->text_background_hi;
291 if( back_color < 0 ) back_color = bg_color;
292 if( high_color < 0 ) high_color = resources->text_background_noborder_hi;
296 set_cursor(IBEAM_CURSOR, 0, 0);
299 add_subwindow(menu = new BC_TextMenu(this));
300 menu->create_objects();
305 int BC_TextBox::calculate_h(BC_WindowBase *gui,
310 return rows * (gui->get_text_ascent(font) + 1 +
311 gui->get_text_descent(font) + 1) +
312 2 * (has_border ? VERTICAL_MARGIN : VERTICAL_MARGIN_NOBORDER);
315 void BC_TextBox::set_precision(int precision)
317 this->precision = precision;
320 // Compute suggestions for a path
321 int BC_TextBox::calculate_suggestions(ArrayList<BC_ListBoxItem*> *entries, const char *filter)
323 // Let user delete suggestion
324 if(get_last_keypress() != BACKSPACE) {
325 // Compute suggestions
327 ArrayList<char*> suggestions;
328 const char *current_text = get_text();
329 int suggestion_column = 0;
330 char dirname[BCTEXTLEN]; dirname[0] = 0;
331 if( current_text[0] == '/' || current_text[0] == '~' )
332 strncpy(dirname, current_text, sizeof(dirname));
334 getcwd(dirname, sizeof(dirname));
335 // If directory, tabulate it
337 if( filter ) fs.set_filter(filter);
339 strncpy(dirname, current_text, sizeof(dirname));
340 if( (cp=strrchr(dirname, '/')) ||
341 (cp=strrchr(dirname, '~')) ) *++cp = 0;
342 fs.parse_tildas(dirname);
344 cp = (char *)current_text;
345 if( (prefix=strrchr(cp, '/')) ||
346 (prefix=strrchr(cp, '~')) ) ++prefix;
347 suggestion_column = !prefix ? 0 : prefix - cp;
348 int prefix_len = prefix ? strlen(prefix) : 0;
349 // only include items where the filename matches the basename prefix
350 for(int i = 0; i < fs.total_files(); i++) {
351 char *current_name = fs.get_entry(i)->name;
352 if( prefix_len>0 && strncmp(prefix, current_name, prefix_len) ) continue;
353 suggestions.append(current_name);
357 char *prefix = (char *)current_text;
358 int prefix_len = strlen(prefix);
359 for(int i = 0; i < entries->size(); i++) {
360 char *current_name = entries->get(i)->get_text();
361 if( prefix_len>0 && strncmp(prefix, current_name, prefix_len) ) continue;
362 suggestions.append(current_name);
365 set_suggestions(&suggestions, suggestion_column);
371 void BC_TextBox::no_suggestions()
373 if( suggestions_popup ) {
374 delete suggestions_popup;
375 suggestions_popup = 0;
380 void BC_TextBox::set_suggestions(ArrayList<char*> *suggestions, int column)
383 this->suggestions->remove_all_objects();
384 this->suggestion_column = column;
387 for(int i = 0; i < suggestions->size(); i++) {
388 this->suggestions->append(new BC_ListBoxItem(suggestions->get(i)));
391 // Show the popup without taking focus
392 if( suggestions->size() > 1 ) {
393 if( !suggestions_popup ) {
394 suggestions_popup = new BC_TextBoxSuggestions(this, x, y);
395 get_parent()->add_subwindow(suggestions_popup);
396 suggestions_popup->set_is_suggestions(1);
399 suggestions_popup->update(this->suggestions, 0, 0, 1);
401 suggestions_popup->activate(0);
404 // Show the highlighted text
405 if( suggestions->size() == 1 ) {
406 highlight_letter1 = wtext_update();
407 int len = text_update(wtext,wlen, text,tsize);
408 char *current_suggestion = suggestions->get(0);
409 int col = len - suggestion_column;
410 if( col < 0 ) col = 0;
411 char *cur = current_suggestion + col;
413 highlight_letter2 = wtext_update();
414 //printf("BC_TextBox::set_suggestions %d %d\n", __LINE__, suggestion_column);
422 if( !suggestions || !this->suggestions->size() )
426 void BC_TextBox::wset_selection(int char1, int char2, int ibeam)
428 highlight_letter1 = char1;
429 highlight_letter2 = char2;
430 ibeam_letter = ibeam;
434 // count utf8 chars in text which occur before cp
435 int BC_TextBox::wcpos(const char *text, const char *cp)
438 const unsigned char *bp = (const unsigned char *)text;
439 const unsigned char *ep = (const unsigned char *)cp;
440 while( bp < ep && *bp != 0 ) {
443 if( ch < 0x80 ) continue;
445 int n = i<0? 0 : i<32? 1 : i<48? 2 : i<56? 3 : i<60? 4 : 5;
446 for( i=n; bp < ep && --i>=0 && (*bp&0xc0) == 0x80; ++bp );
451 void BC_TextBox::set_selection(int char1, int char2, int ibeam)
453 const char *cp = get_text();
454 wset_selection(wcpos(cp, cp+char1), wcpos(cp, cp+char2), wcpos(cp, cp+ibeam));
457 int BC_TextBox::update(const char *text)
459 //printf("BC_TextBox::update 1 %d %s %s\n", tstrcmp(text), text, this->text);
460 // Don't update if contents are the same
461 int bg_color = has_border || !highlighted ? back_color : high_color;
462 if( bg_color == background_color && !tstrcmp(text)) return 0;
464 int wtext_len = wtext_update();
465 if(highlight_letter1 > wtext_len) highlight_letter1 = wtext_len;
466 if(highlight_letter2 > wtext_len) highlight_letter2 = wtext_len;
467 if(ibeam_letter > wtext_len) ibeam_letter = wtext_len;
472 int BC_TextBox::update(const wchar_t *wtext)
474 int wtext_len = wcslen(wtext);
475 if( wtext_len >= wsize ) wtext_len = wsize;
476 wcsncpy(this->wtext, wtext, wtext_len);
478 if(highlight_letter1 > wtext_len) highlight_letter1 = wtext_len;
479 if(highlight_letter2 > wtext_len) highlight_letter2 = wtext_len;
480 if(ibeam_letter > wtext_len) ibeam_letter = wtext_len;
485 int BC_TextBox::update(int64_t value)
487 char string[BCTEXTLEN];
488 sprintf(string, "%jd", value);
493 int BC_TextBox::update(float value)
495 char string[BCTEXTLEN];
496 sprintf(string, "%0.*f", precision, value);
501 void BC_TextBox::disable()
510 void BC_TextBox::enable()
520 int BC_TextBox::get_enabled() { return enabled; }
521 int BC_TextBox::get_text_x() { return text_x; }
522 int BC_TextBox::get_text_y() { return text_y; }
523 void BC_TextBox::set_text_x(int v) { text_x = v; }
524 void BC_TextBox::set_text_y(int v) { text_y = v; }
525 int BC_TextBox::get_back_color() { return back_color; }
526 void BC_TextBox::set_back_color(int v) { back_color = v; }
528 int BC_TextBox::pixels_to_rows(BC_WindowBase *window, int font, int pixels)
530 return (pixels - 4) /
531 (window->get_text_ascent(font) + 1 +
532 window->get_text_descent(font) + 1);
535 int BC_TextBox::calculate_row_h(int rows,
536 BC_WindowBase *parent_window,
541 (parent_window->get_text_ascent(font) + 1 +
542 parent_window->get_text_descent(font) + 1) +
543 (has_border ? 4 : 0);
546 const char* BC_TextBox::get_text()
548 int wtext_len = wtext_update();
549 text_update(wtext,wtext_len, text,tsize);
553 const wchar_t* BC_TextBox::get_wtext()
559 void BC_TextBox::set_text(char *text, int isz)
561 if( size > 0 || isz < 0 ) return;
570 int BC_TextBox::get_text_rows()
572 int wtext_len = wtext_update();
574 for(int i = 0; i < wtext_len; i++) {
575 if(wtext[i] == '\n') result++;
581 int BC_TextBox::get_row_h(int rows)
583 return rows * text_height + top_margin + bottom_margin;
586 int BC_TextBox::reposition_window(int x, int y, int w, int rows)
589 if(w < 0) w = get_w();
592 new_h = get_row_h(rows);
601 // printf("BC_TextBox::reposition_window 1 %d %d %d %d %d %d %d %d\n",
602 // x, get_x(), y, get_y(), w, get_w(), new_h, get_h());
603 BC_WindowBase::reposition_window(x, y, w, new_h);
609 void BC_TextBox::draw_border()
611 BC_Resources *resources = get_resources();
613 set_color(background_color);
614 draw_box(0, 0, left_margin, get_h());
615 draw_box(get_w() - right_margin, 0, right_margin, get_h());
620 draw_3d_border(0, 0, w, h,
621 resources->text_border1,
622 resources->text_border2_hi,
623 resources->text_border3_hi,
624 resources->text_border4);
626 draw_3d_border(0, 0, w, h,
627 resources->text_border1,
628 resources->text_border2,
629 resources->text_border3,
630 resources->text_border4);
634 void BC_TextBox::draw_cursor()
636 // set_color(background_color);
644 draw_box(ibeam_x + text_x,
653 void BC_TextBox::draw(int flush)
656 int row_begin, row_end;
657 int highlight_x1, highlight_x2;
659 BC_Resources *resources = get_resources();
661 //printf("BC_TextBox::draw %d %s\n", __LINE__, text);
663 background_color = has_border || !highlighted ? back_color : high_color;
664 set_color(background_color);
665 draw_box(0, 0, w, h);
667 int wtext_len = wtext_update();
669 // Draw text with selection
672 for(i=0, j=0, k=text_y; i < wtext_len && k < get_h(); k += text_height) {
675 wchar_t *wtext_row = &wtext[i];
676 for(j=0; j<BCTEXTLEN-1 && i<wtext_len && wtext[i]!='\n'; ++i, ++j);
677 if( (row_end=i) < wtext_len ) ++i;
679 if(k > top_margin-text_height && k < get_h()-bottom_margin) {
680 // Draw highlighted region of row
681 if( highlight_letter2 > highlight_letter1 &&
682 highlight_letter2 > row_begin &&
683 highlight_letter1 <= row_end ) {
684 int color = active && enabled && get_has_focus() ?
685 resources->text_highlight :
687 resources->text_selected_highlight :
688 resources->text_inactive_highlight;
689 if( unicode_active >= 0 )
692 if(highlight_letter1 >= row_begin &&
693 highlight_letter1 <= row_end)
694 highlight_x1 = get_x_position(highlight_letter1, row_begin);
698 if(highlight_letter2 > row_begin &&
699 highlight_letter2 <= row_end)
700 highlight_x2 = get_x_position(highlight_letter2, row_begin);
702 highlight_x2 = get_w();
704 draw_box(highlight_x1 + text_x, k,
705 highlight_x2 - highlight_x1, text_height);
708 // Draw text over highlight
709 int len = row_end - row_begin;
711 set_color(enabled ? resources->text_default : DMGREY);
712 draw_single_text(1, font, text_x, k + text_ascent, wtext_row, len);
715 // Get ibeam location
716 if(ibeam_letter >= row_begin && ibeam_letter <= row_end) {
718 ibeam_y = k - text_y;
719 ibeam_x = get_x_position(ibeam_letter, row_begin);
724 //printf("BC_TextBox::draw 3 %d\n", ibeam_y);
726 // ibeam_x = ibeam_y = !wtext_len ? 0 : -1;
727 ibeam_x = 0; ibeam_y = k - text_y;
730 //printf("BC_TextBox::draw 4 %d\n", ibeam_y);
740 int BC_TextBox::focus_in_event()
746 int BC_TextBox::focus_out_event()
752 int BC_TextBox::cursor_enter_event()
754 if( top_level->event_win == win && enabled &&
755 !(top_level->get_resources()->textbox_focus_policy & CLICK_ACTIVATE) )
758 top_level->deactivate();
771 int BC_TextBox::cursor_leave_event()
780 if( !suggestions_popup && !get_button_down() &&
781 !(top_level->get_resources()->textbox_focus_policy & CLICK_DEACTIVATE) )
786 int BC_TextBox::button_press_event()
790 if(!enabled) return 0;
791 // if(get_buttonpress() != WHEEL_UP &&
792 // get_buttonpress() != WHEEL_DOWN &&
793 // get_buttonpress() != LEFT_BUTTON &&
794 // get_buttonpress() != MIDDLE_BUTTON) return 0;
796 if(debug) printf("BC_TextBox::button_press_event %d\n", __LINE__);
798 int cursor_letter = 0;
799 int wtext_len = wtext_update();
800 int update_scroll = 0;
803 if(top_level->event_win == win)
808 top_level->deactivate();
813 if(get_buttonpress() == WHEEL_UP)
815 text_y += text_height;
816 text_y = MIN(text_y, top_margin);
820 if(get_buttonpress() == WHEEL_DOWN)
822 int min_y = -(get_text_rows() *
826 text_y -= text_height;
827 text_y = MAX(text_y, min_y);
828 text_y = MIN(text_y, top_margin);
832 if(get_buttonpress() == RIGHT_BUTTON)
834 menu->activate_menu();
839 cursor_letter = get_cursor_letter(top_level->cursor_x, top_level->cursor_y);
841 //printf("BC_TextBox::button_press_event %d %d\n", __LINE__, cursor_letter);
844 if(get_triple_click())
846 //printf("BC_TextBox::button_press_event %d\n", __LINE__);
848 select_line(highlight_letter1, highlight_letter2, cursor_letter);
849 highlight_letter3 = highlight_letter1;
850 highlight_letter4 = highlight_letter2;
851 ibeam_letter = highlight_letter2;
852 copy_selection(PRIMARY_SELECTION);
855 if(get_double_click())
858 select_word(highlight_letter1, highlight_letter2, cursor_letter);
859 highlight_letter3 = highlight_letter1;
860 highlight_letter4 = highlight_letter2;
861 ibeam_letter = highlight_letter2;
862 copy_selection(PRIMARY_SELECTION);
865 if(get_buttonpress() == MIDDLE_BUTTON)
867 highlight_letter3 = highlight_letter4 =
868 ibeam_letter = highlight_letter1 =
869 highlight_letter2 = cursor_letter;
870 paste_selection(PRIMARY_SELECTION);
875 highlight_letter3 = highlight_letter4 =
876 ibeam_letter = highlight_letter1 =
877 highlight_letter2 = cursor_letter;
881 // Handle scrolling by highlighting text
882 if(text_selected || word_selected || line_selected)
884 set_repeat(top_level->get_resources()->scroll_repeat);
887 if(ibeam_letter < 0) ibeam_letter = 0;
888 if(ibeam_letter > wtext_len) ibeam_letter = wtext_len;
892 if(update_scroll && yscroll)
894 yscroll->update_length(get_text_rows(),
896 yscroll->get_handlelength(),
904 if( suggestions_popup && (!yscroll || !yscroll->is_event_win())) {
905 if( suggestions_popup->button_press_event() )
906 return suggestions_popup->handle_event();
908 else if( (top_level->get_resources()->textbox_focus_policy & CLICK_DEACTIVATE) )
915 int BC_TextBox::button_release_event()
920 if(text_selected || word_selected || line_selected)
926 // Stop scrolling by highlighting text
927 unset_repeat(top_level->get_resources()->scroll_repeat);
933 int BC_TextBox::cursor_motion_event()
935 int cursor_letter, letter1, letter2;
938 if(text_selected || word_selected || line_selected)
940 cursor_letter = get_cursor_letter(top_level->cursor_x,
941 top_level->cursor_y);
943 //printf("BC_TextBox::cursor_motion_event %d cursor_letter=%d\n", __LINE__, cursor_letter);
947 select_line(letter1, letter2, cursor_letter);
952 select_word(letter1, letter2, cursor_letter);
957 letter1 = letter2 = cursor_letter;
960 if(letter1 <= highlight_letter3)
962 highlight_letter1 = letter1;
963 highlight_letter2 = highlight_letter4;
964 ibeam_letter = letter1;
967 if(letter2 >= highlight_letter4)
969 highlight_letter2 = letter2;
970 highlight_letter1 = highlight_letter3;
971 ibeam_letter = letter2;
974 copy_selection(PRIMARY_SELECTION);
987 int BC_TextBox::activate()
991 top_level->set_active_subwindow(this);
992 top_level->set_repeat(top_level->get_resources()->blink_rate);
998 int BC_TextBox::deactivate()
1002 text_selected = word_selected = line_selected = 0;
1003 top_level->set_active_subwindow(0);
1004 top_level->unset_repeat(top_level->get_resources()->blink_rate);
1010 int BC_TextBox::repeat_event(int64_t duration)
1013 int cursor_y = get_cursor_y();
1014 //int cursor_x = get_cursor_x();
1016 if(duration == top_level->get_resources()->tooltip_delay &&
1017 tooltip_text && tooltip_text[0] != 0 && highlighted)
1023 if(duration == top_level->get_resources()->blink_rate &&
1027 // don't flash if keypress
1028 if(skip_cursor->get_difference() < 500)
1030 // printf("BC_TextBox::repeat_event 1 %lld %lld\n",
1031 // skip_cursor->get_difference(),
1037 if(!(text_selected || word_selected || line_selected))
1046 if(duration == top_level->get_resources()->scroll_repeat &&
1047 (text_selected || word_selected || line_selected))
1050 if(get_cursor_y() < top_margin)
1052 difference = get_cursor_y() - top_margin ;
1055 if(get_cursor_y() > get_h() - bottom_margin)
1057 difference = get_cursor_y() -
1058 (get_h() - bottom_margin);
1060 if(difference != 0) {
1061 int min_y = -(get_text_rows() * text_height -
1062 get_h() + bottom_margin);
1064 text_y -= difference;
1065 // printf("BC_TextBox::repeat_event %d %d %d\n",
1069 text_y = MAX(min_y, text_y);
1070 text_y = MIN(text_y, top_margin);
1077 if(get_cursor_x() < left_margin)
1079 int difference = left_margin - get_cursor_x();
1081 text_x += difference;
1082 text_x = MIN(text_x, left_margin);
1086 else if(get_cursor_x() > get_w() - right_margin)
1088 int difference = get_cursor_x() - (get_w() - right_margin);
1089 int new_text_x = text_x - difference;
1091 // Get width of current row
1094 int wtext_len = wtext_update();
1097 for(int i = 0, k = text_y; i < wtext_len; k += text_height)
1100 while(wtext[i] != '\n' && i < wtext_len) {
1104 if(wtext[i] == '\n') i++;
1106 if(cursor_y >= k && cursor_y < k + text_height) {
1107 row_width = get_text_width(font,
1109 row_end - row_begin);
1115 min_x = -row_width + get_w() - left_margin - BCCURSORW;
1116 new_text_x = MAX(new_text_x, min_x);
1117 new_text_x = MIN(new_text_x, left_margin);
1119 if(new_text_x < text_x) text_x = new_text_x;
1128 void BC_TextBox::default_keypress(int &dispatch_event, int &result)
1130 int key = top_level->get_keypress(), len;
1131 wchar_t *wkeys = top_level->get_wkeystring(&len);
1133 case KPENTER: key = '\n'; goto kpchr;
1134 case KPMINUS: key = '-'; goto kpchr;
1135 case KPPLUS: key = '+'; goto kpchr;
1136 case KPDEL: key = '.'; goto kpchr;
1137 case RETURN: key = '\n'; goto kpchr;
1138 case KPINS: key = '0'; goto kpchr;
1139 case KP1: case KP2: case KP3: case KP4: case KP5:
1140 case KP6: case KP7: case KP8: case KP9:
1141 key = key - KP1 + '1'; goto kpchr;
1143 if( key < 32 || key > 255 ) return;
1145 wkeys[0] = key; wkeys[1] = 0; len = 1;
1148 insert_text(wkeys, len);
1155 int BC_TextBox::keypress_event()
1157 // Result == 2 contents changed
1158 // Result == 1 trapped keypress
1159 // Result == 0 nothing
1161 int dispatch_event = 0;
1163 if(!active || !enabled) return 0;
1165 int wtext_len = wtext_update();
1166 last_keypress = get_keypress();
1168 if( unicode_active >= 0 ) {
1171 switch( last_keypress ) {
1172 //unicode active acitons
1174 for( int i=highlight_letter1+1; i<highlight_letter2; ++i ) {
1175 int ch = nib(wtext[i]);
1176 if( ch < 0 ) return 1;
1177 wch = (wch<<4) + ch;
1181 unicode_active = -1;
1187 unicode_active = -1;
1192 if(ibeam_letter > 0) {
1193 delete_selection(ibeam_letter - 1, ibeam_letter, wtext_len);
1194 highlight_letter2 = --ibeam_letter;
1195 if( highlight_letter1 >= highlight_letter2 )
1196 unicode_active = -1;
1201 case KPINS: last_keypress = KP1-'1'+'0'; // fall thru
1202 case KP1: case KP2: case KP3: case KP4: case KP5:
1203 case KP6: case KP7: case KP8: case KP9:
1204 last_keypress = last_keypress-KP1 + '1';
1205 case '0': case '1': case '2': case '3': case '4':
1206 case '5': case '6': case '7': case '8': case '9':
1207 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
1208 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': {
1209 int n = nib(last_keypress);
1210 wch = n < 10 ? '0'+n : 'A'+n-10;
1224 insert_text(&wch, wlen);
1226 if( unicode_active >= 0 )
1227 highlight_letter2 = ibeam_letter;
1229 highlight_letter1 = highlight_letter2 = 0;
1235 //printf("BC_TextBox::keypress_event %d %x\n", __LINE__, last_keypress)
1236 switch(last_keypress) {
1238 // Deactivate the suggestions
1239 if( suggestions_popup ) {
1244 top_level->deactivate();
1251 highlight_letter1 = highlight_letter2 = 0;
1252 ibeam_letter = wtext_update();
1253 top_level->deactivate();
1258 default_keypress(dispatch_event, result);
1263 // Handle like a default keypress
1265 top_level->cycle_textboxes(1);
1270 top_level->cycle_textboxes(-1);
1275 if(ibeam_letter > 0) {
1276 int old_ibeam_letter = ibeam_letter;
1284 while(ibeam_letter > 0 && isalnum(wtext[ibeam_letter - 1]))
1289 if(top_level->shift_down()) {
1290 // Initialize highlighting
1291 if(highlight_letter1 == highlight_letter2) {
1292 highlight_letter1 = ibeam_letter;
1293 highlight_letter2 = old_ibeam_letter;
1295 else if(highlight_letter1 == old_ibeam_letter) {
1296 // Extend left highlight
1297 highlight_letter1 = ibeam_letter;
1299 else if(highlight_letter2 == old_ibeam_letter) {
1300 // Shrink right highlight
1301 highlight_letter2 = ibeam_letter;
1305 highlight_letter1 = highlight_letter2 = ibeam_letter;
1310 if(keypress_draw) draw(1);
1316 if(ibeam_letter < wtext_len) {
1317 int old_ibeam_letter = ibeam_letter;
1324 while(ibeam_letter < wtext_len && isalnum(wtext[ibeam_letter++]));
1330 if(top_level->shift_down()) {
1331 // Initialize highlighting
1332 if(highlight_letter1 == highlight_letter2) {
1333 highlight_letter1 = old_ibeam_letter;
1334 highlight_letter2 = ibeam_letter;
1336 else if(highlight_letter1 == old_ibeam_letter) {
1337 // Shrink left highlight
1338 highlight_letter1 = ibeam_letter;
1340 else if(highlight_letter2 == old_ibeam_letter) {
1341 // Expand right highlight
1342 highlight_letter2 = ibeam_letter;
1346 highlight_letter1 = highlight_letter2 = ibeam_letter;
1350 if(keypress_draw) draw(1);
1356 if( suggestions && suggestions_popup ) {
1357 // Pass to suggestions popup
1358 //printf("BC_TextBox::keypress_event %d\n", __LINE__);
1359 suggestions_popup->activate(1);
1360 suggestions_popup->keypress_event();
1363 else if(ibeam_letter > 0) {
1364 //printf("BC_TextBox::keypress_event 1 %d %d %d\n", ibeam_x, ibeam_y, ibeam_letter);
1365 int new_letter = get_cursor_letter2(ibeam_x + text_x,
1366 ibeam_y + text_y - text_height);
1367 //printf("BC_TextBox::keypress_event 2 %d %d %d\n", ibeam_x, ibeam_y, new_letter);
1370 if(top_level->shift_down()) {
1371 // Initialize highlighting
1372 if(highlight_letter1 == highlight_letter2) {
1373 highlight_letter1 = new_letter;
1374 highlight_letter2 = ibeam_letter;
1376 else if(highlight_letter1 == ibeam_letter) {
1377 // Expand left highlight
1378 highlight_letter1 = new_letter;
1380 else if(highlight_letter2 == ibeam_letter) {
1381 // Shrink right highlight
1382 highlight_letter2 = new_letter;
1386 highlight_letter1 = highlight_letter2 = new_letter;
1388 if(highlight_letter1 > highlight_letter2) {
1389 int temp = highlight_letter1;
1390 highlight_letter1 = highlight_letter2;
1391 highlight_letter2 = temp;
1393 ibeam_letter = new_letter;
1396 if(keypress_draw) draw(1);
1402 if(ibeam_letter > 0) {
1403 int new_letter = get_cursor_letter2(ibeam_x + text_x,
1404 ibeam_y + text_y - get_h());
1407 if(top_level->shift_down()) {
1408 // Initialize highlighting
1409 if(highlight_letter1 == highlight_letter2) {
1410 highlight_letter1 = new_letter;
1411 highlight_letter2 = ibeam_letter;
1413 else if(highlight_letter1 == ibeam_letter) {
1414 // Expand left highlight
1415 highlight_letter1 = new_letter;
1417 else if(highlight_letter2 == ibeam_letter) {
1418 // Shrink right highlight
1419 highlight_letter2 = new_letter;
1423 highlight_letter1 = highlight_letter2 = new_letter;
1425 if(highlight_letter1 > highlight_letter2) {
1426 int temp = highlight_letter1;
1427 highlight_letter1 = highlight_letter2;
1428 highlight_letter2 = temp;
1430 ibeam_letter = new_letter;
1433 if(keypress_draw) draw(1);
1439 // printf("BC_TextBox::keypress_event %d %p %p\n",
1442 // suggestions_popup);
1443 if( suggestions && suggestions_popup ) {
1444 // Pass to suggestions popup
1445 suggestions_popup->activate(1);
1446 suggestions_popup->keypress_event();
1450 // if(ibeam_letter > 0)
1453 int new_letter = get_cursor_letter2(ibeam_x + text_x,
1454 ibeam_y + text_y + text_height);
1455 //printf("BC_TextBox::keypress_event 10 %d\n", new_letter);
1457 if(top_level->shift_down()) {
1458 // Initialize highlighting
1459 if(highlight_letter1 == highlight_letter2) {
1460 highlight_letter1 = new_letter;
1461 highlight_letter2 = ibeam_letter;
1463 else if(highlight_letter1 == ibeam_letter) {
1464 // Shrink left highlight
1465 highlight_letter1 = new_letter;
1467 else if(highlight_letter2 == ibeam_letter) {
1468 // Expand right highlight
1469 highlight_letter2 = new_letter;
1473 highlight_letter1 = highlight_letter2 = new_letter;
1475 if(highlight_letter1 > highlight_letter2) {
1476 int temp = highlight_letter1;
1477 highlight_letter1 = highlight_letter2;
1478 highlight_letter2 = temp;
1480 ibeam_letter = new_letter;
1483 if(keypress_draw) draw(1);
1485 //printf("BC_TextBox::keypress_event 20 %d\n", ibeam_letter);
1492 int new_letter = get_cursor_letter2(ibeam_x + text_x,
1493 ibeam_y + text_y + get_h());
1494 //printf("BC_TextBox::keypress_event 10 %d\n", new_letter);
1496 if(top_level->shift_down()) {
1497 // Initialize highlighting
1498 if(highlight_letter1 == highlight_letter2) {
1499 highlight_letter1 = new_letter;
1500 highlight_letter2 = ibeam_letter;
1502 else if(highlight_letter1 == ibeam_letter) {
1503 // Shrink left highlight
1504 highlight_letter1 = new_letter;
1506 else if(highlight_letter2 == ibeam_letter) {
1507 // Expand right highlight
1508 highlight_letter2 = new_letter;
1512 highlight_letter1 = highlight_letter2 = new_letter;
1514 if(highlight_letter1 > highlight_letter2) {
1515 int temp = highlight_letter1;
1516 highlight_letter1 = highlight_letter2;
1517 highlight_letter2 = temp;
1519 ibeam_letter = new_letter;
1522 if(keypress_draw) draw(1);
1524 //printf("BC_TextBox::keypress_event 20 %d\n", ibeam_letter);
1531 int old_ibeam_letter = ibeam_letter;
1533 while(ibeam_letter < wtext_len && wtext[ibeam_letter] != '\n')
1536 if(top_level->shift_down()) {
1538 if(highlight_letter1 == highlight_letter2) {
1539 highlight_letter2 = ibeam_letter;
1540 highlight_letter1 = old_ibeam_letter;
1542 else if(highlight_letter1 == old_ibeam_letter) {
1544 highlight_letter1 = highlight_letter2;
1545 highlight_letter2 = ibeam_letter;
1547 else if(highlight_letter2 == old_ibeam_letter) {
1549 highlight_letter2 = ibeam_letter;
1553 highlight_letter1 = highlight_letter2 = ibeam_letter;
1556 if(keypress_draw) draw(1);
1563 int old_ibeam_letter = ibeam_letter;
1565 while(ibeam_letter > 0 && wtext[ibeam_letter - 1] != '\n')
1568 if(top_level->shift_down())
1571 if(highlight_letter1 == highlight_letter2)
1573 highlight_letter2 = old_ibeam_letter;
1574 highlight_letter1 = ibeam_letter;
1578 if(highlight_letter1 == old_ibeam_letter)
1580 highlight_letter1 = ibeam_letter;
1584 if(highlight_letter2 == old_ibeam_letter)
1586 highlight_letter2 = highlight_letter1;
1587 highlight_letter1 = ibeam_letter;
1591 highlight_letter1 = highlight_letter2 = ibeam_letter;
1594 if(keypress_draw) draw(1);
1601 if(highlight_letter1 == highlight_letter2) {
1602 if(ibeam_letter > 0) {
1603 delete_selection(ibeam_letter - 1, ibeam_letter, wtext_len);
1608 delete_selection(highlight_letter1, highlight_letter2, wtext_len);
1609 highlight_letter2 = ibeam_letter = highlight_letter1;
1613 if(keypress_draw) draw(1);
1619 //printf("BC_TextBox::keypress_event %d\n", __LINE__);
1620 if(highlight_letter1 == highlight_letter2) {
1621 if(ibeam_letter < wtext_len) {
1622 delete_selection(ibeam_letter, ibeam_letter + 1, wtext_len);
1626 delete_selection(highlight_letter1, highlight_letter2, wtext_len);
1627 highlight_letter2 = ibeam_letter = highlight_letter1;
1631 if(keypress_draw) draw(1);
1638 switch( last_keypress ) {
1639 case 'c': case 'C': {
1642 case 'v': case 'V': {
1646 case 'x': case 'X': {
1650 case 'u': case 'U': {
1651 if( shift_down() ) {
1652 unicode_active = ibeam_letter;
1654 insert_text(&wkey, 1);
1656 highlight_letter1 = unicode_active;
1657 highlight_letter2 = ibeam_letter;
1666 default_keypress(dispatch_event, result);
1671 if(result) skip_cursor->update();
1672 if(dispatch_event && handle_event())
1679 int BC_TextBox::cut(int do_update)
1681 if( highlight_letter1 != highlight_letter2 ) {
1682 int wtext_len = wtext_update();
1683 copy_selection(SECONDARY_SELECTION);
1684 delete_selection(highlight_letter1, highlight_letter2, wtext_len);
1685 highlight_letter2 = ibeam_letter = highlight_letter1;
1693 skip_cursor->update();
1699 int BC_TextBox::copy(int do_update)
1702 if( highlight_letter1 != highlight_letter2 ) {
1703 copy_selection(SECONDARY_SELECTION);
1706 skip_cursor->update();
1712 int BC_TextBox::paste(int do_update)
1714 paste_selection(SECONDARY_SELECTION);
1719 skip_cursor->update();
1726 int BC_TextBox::uses_text()
1732 void BC_TextBox::delete_selection(int letter1, int letter2, int wtext_len)
1735 for(i=letter1, j=letter2; j<wtext_len; i++, j++) {
1736 wtext[i] = wtext[j];
1744 void BC_TextBox::insert_text(const wchar_t *wcp, int len)
1746 if( len < 0 ) len = wcslen(wcp);
1747 int wtext_len = wtext_update();
1748 if( unicode_active < 0 && highlight_letter1 < highlight_letter2 ) {
1749 delete_selection(highlight_letter1, highlight_letter2, wtext_len);
1750 highlight_letter2 = ibeam_letter = highlight_letter1;
1751 wtext_len = wtext_update();
1755 for(i=wtext_len-1, j=wtext_len+len-1; i>=ibeam_letter; i--, j--) {
1756 if( j >= wsize ) continue;
1757 wtext[j] = wtext[i];
1760 for(i = ibeam_letter, j = 0; j < len; j++, i++) {
1761 if( i >= wsize ) break;
1764 if( (wlen+=len) > wsize ) wlen = wsize;
1765 if( (ibeam_letter+=len) > wsize ) ibeam_letter = wsize;
1766 wtext[wlen] = 0; // wtext allocated wsize+1
1770 int BC_TextBox::is_separator(const char *txt, int i)
1772 if( i != 0 || separators[0] != '+' ) return !isalnum(txt[i]);
1773 return txt[0] != '+' && txt[0] != '-' && !isalnum(txt[0]);
1776 // used for time entry
1777 void BC_TextBox::do_separators(int ibeam_left)
1781 // Remove separators from text
1782 int wtext_len = wtext_update();
1783 for(int i = 0; i < wtext_len; ) {
1784 if( !iswalnum(wtext[i]) ) {
1785 for(int j = i; j < wtext_len - 1; j++)
1786 wtext[j] = wtext[j + 1];
1787 if(!ibeam_left && i < ibeam_letter) ibeam_letter--;
1793 wtext[wtext_len] = 0;
1799 // Insert separators into text
1800 int separator_len = strlen(separators);
1801 for(int i = 0; i < separator_len; i++) {
1803 // Insert a separator
1804 if( is_separator(separators,i) ) {
1805 for(int j = wtext_len; j >= i; j--) {
1806 wtext[j + 1] = wtext[j];
1808 if(!ibeam_left && i < ibeam_letter) ibeam_letter++;
1810 wtext[i] = separators[i];
1814 wtext[i] = separators[i];
1819 wtext[separator_len] = 0;
1820 wlen = separator_len;
1824 int BC_TextBox::get_x_position(int i, int start)
1826 return get_text_width(font, &wtext[start], i - start);
1829 void BC_TextBox::get_ibeam_position(int &x, int &y)
1831 int i, row_begin, row_end;
1832 int wtext_len = wtext_update();
1835 for( i=0; i<wtext_len; ) {
1837 for(; i<wtext_len && wtext[i]!='\n'; i++);
1840 if( ibeam_letter >= row_begin && ibeam_letter <= row_end ) {
1841 x = get_x_position(ibeam_letter, row_begin);
1842 //printf("BC_TextBox::get_ibeam_position %d %d %d %d %d\n", ibeam_letter, row_begin, row_end, x, y);
1846 if( i < wtext_len && wtext[i] == '\n' ) {
1851 //printf("BC_TextBox::get_ibeam_position 10 %d %d\n", x, y);
1857 void BC_TextBox::set_text_row(int row)
1859 text_x = left_margin;
1860 text_y = -(row * text_height) + top_margin;
1864 int BC_TextBox::get_text_row()
1866 return -(text_y - top_margin) / text_height;
1869 void BC_TextBox::find_ibeam(int dispatch_event)
1872 int old_x = text_x, old_y = text_y;
1874 get_ibeam_position(x, y);
1876 if(left_margin + text_x + x >= get_w() - right_margin - BCCURSORW)
1878 text_x = -(x - (get_w() - get_w() / 4)) + left_margin;
1879 if(text_x > left_margin) text_x = left_margin;
1882 if(left_margin + text_x + x < left_margin)
1884 text_x = -(x - (get_w() / 4)) + left_margin;
1885 if(text_x > left_margin) text_x = left_margin;
1888 int text_row = y / text_height;
1889 if( text_row < rows ) text_y = top_margin;
1891 int pix_rows = get_h() - bottom_margin - (y + text_y);
1892 if( pix_rows < text_height )
1893 text_y -= text_height * ((2*text_height-1-pix_rows) / text_height);
1895 pix_rows = y + text_y - top_margin;
1896 if( pix_rows < 0 ) {
1897 text_y += text_height * ((text_height-1-pix_rows) / text_height);
1898 if( text_y > top_margin ) text_y = top_margin;
1901 if(dispatch_event && (old_x != text_x || old_y != text_y)) motion_event();
1905 int BC_TextBox::get_cursor_letter(int cursor_x, int cursor_y)
1907 int i, j, k, row_begin, row_end, result = 0, done = 0;
1908 int column1, column2;
1909 int got_visible_row = 0;
1911 // Select complete row if cursor above the window
1912 //printf("BC_TextBox::get_cursor_letter %d %d\n", __LINE__, text_y);
1913 if(cursor_y < text_y - text_height)
1919 int wtext_len = wtext_update();
1921 for(i=0, k=text_y; i<wtext_len && k<get_h() && !done; k+=text_height) {
1922 // Simulate drawing of 1 row
1924 for(j = 0; wtext[i]!='\n' && i<wtext_len; i++);
1928 int first_visible_row = 0;
1929 int last_visible_row = 0;
1930 if( k+text_height > top_margin && !got_visible_row) {
1931 first_visible_row = 1;
1932 got_visible_row = 1;
1935 if( (k+text_height >= get_h() - bottom_margin ||
1936 (row_end >= wtext_len && k < get_h() - bottom_margin &&
1937 k + text_height > 0)) )
1938 last_visible_row = 1;
1940 // Cursor is inside vertical range of row
1941 if((cursor_y >= top_margin &&
1942 cursor_y < get_h() - bottom_margin &&
1943 cursor_y >= k && cursor_y < k + text_height) ||
1944 // Cursor is above 1st row
1945 (cursor_y < k + text_height && first_visible_row) ||
1946 // Cursor is below last row
1947 (cursor_y >= k && last_visible_row))
1949 column1 = column2 = 0;
1950 for(j = row_begin; j<wsize && j<=row_end && !done; j++) {
1951 column2 = get_text_width(font, &wtext[row_begin], j-row_begin) + text_x;
1952 if((column2 + column1) / 2 >= cursor_x) {
1955 // printf("BC_TextBox::get_cursor_letter %d %d %d %d\n",
1956 // __LINE__, result, first_visible_row, last_visible_row);
1967 if(wtext[i] == '\n') i++;
1969 // Select complete row if last visible & cursor is below window
1970 if(last_visible_row && cursor_y > k + text_height * 2)
1973 if(i >= wtext_len && !done) {
1979 // printf("BC_TextBox::get_cursor_letter %d cursor_y=%d k=%d h=%d %d %d\n",
1980 // __LINE__, cursor_y, k, get_h(), first_visible_row, last_visible_row);
1981 if(result < 0) result = 0;
1982 if(result > wtext_len) {
1983 //printf("BC_TextBox::get_cursor_letter %d\n", __LINE__);
1991 int BC_TextBox::get_cursor_letter2(int cursor_x, int cursor_y)
1993 int i, j, k, row_begin, row_end, result = 0, done = 0;
1994 int column1, column2;
1995 int wtext_len = wtext_update();
1997 if(cursor_y < text_y) {
2002 for(i = 0, k = text_y; i < wtext_len && !done; k += text_height) {
2004 for(; wtext[i] != '\n' && i < wtext_len; i++);
2007 if(cursor_y >= k && cursor_y < k + text_height) {
2008 column1 = column2 = 0;
2009 for(j = 0; j <= row_end - row_begin && !done; j++) {
2010 column2 = get_text_width(font, &wtext[row_begin], j) + text_x;
2011 if((column2 + column1) / 2 >= cursor_x) {
2012 result = row_begin + j - 1;
2023 if(wtext[i] == '\n') i++;
2025 if(i >= wtext_len && !done) {
2029 if(result < 0) result = 0;
2030 if(result > wtext_len) result = wtext_len;
2035 void BC_TextBox::select_word(int &letter1, int &letter2, int ibeam_letter)
2037 int wtext_len = wtext_update();
2038 letter1 = letter2 = ibeam_letter;
2039 if( letter1 < 0 ) letter1 = 0;
2040 if( letter2 < 0 ) letter2 = 0;
2041 if( letter1 > wtext_len ) letter1 = wtext_len;
2042 if( letter2 > wtext_len ) letter2 = wtext_len;
2043 if( !wtext_len ) return;
2044 for( int i=letter1; i>=0 && iswalnum(wtext[i]); --i ) letter1 = i;
2045 for( int i=letter2; i<wtext_len && iswalnum(wtext[i]); ) letter2 = ++i;
2046 if( letter2 < wtext_len && wtext[letter2] == ' ' ) ++letter2;
2050 void BC_TextBox::select_line(int &letter1, int &letter2, int ibeam_letter)
2052 int wtext_len = wtext_update();
2053 letter1 = letter2 = ibeam_letter;
2054 if( letter1 < 0 ) letter1 = 0;
2055 if( letter2 < 0 ) letter2 = 0;
2056 if( letter1 > wtext_len ) letter1 = wtext_len;
2057 if( letter2 > wtext_len ) letter2 = wtext_len;
2058 if( !wtext_len ) return;
2059 for( int i=letter1; i>=0 && wtext[i]!='\n'; --i ) letter1 = i;
2060 for( int i=letter2; i<wtext_len && wtext[i]!='\n'; ) letter2 = ++i;
2063 void BC_TextBox::copy_selection(int clipboard_num)
2065 int wtext_len = wtext_update();
2066 if(!wtext_len) return;
2068 if(highlight_letter1 >= wtext_len || highlight_letter2 > wtext_len ||
2069 highlight_letter1 < 0 || highlight_letter2 < 0 ||
2070 highlight_letter2 - highlight_letter1 <= 0) return;
2071 int clip_len = highlight_letter2 - highlight_letter1;
2072 //printf(" BC_TextBox::copy_selection %d %d %d\n",highlight_letter1, highlight_letter2, clip_len);
2073 char ctext[4*clip_len+4];
2074 clip_len = text_update(&wtext[highlight_letter1],clip_len, ctext,4*clip_len+4);
2075 to_clipboard(ctext, clip_len, clipboard_num);
2076 selection_active = 1;
2079 int BC_TextBox::selection_clear_event()
2081 if( !is_event_win() ) return 0;
2082 selection_active = 0;
2087 void BC_TextBox::paste_selection(int clipboard_num)
2089 int len = clipboard_len(clipboard_num);
2092 char cstring[len]; wchar_t wstring[len];
2093 from_clipboard(cstring, len, clipboard_num); --len;
2094 //printf("BC_TextBox::paste_selection %d '%*.*s'\n",len,len,len,cstring);
2095 len = BC_Resources::encode(BC_Resources::encoding, BC_Resources::wide_encoding,
2096 cstring,len, (char *)wstring,(len+1)*sizeof(wchar_t)) / sizeof(wchar_t);
2097 insert_text(wstring, len);
2102 void BC_TextBox::set_keypress_draw(int value)
2104 keypress_draw = value;
2107 int BC_TextBox::get_last_keypress()
2109 return last_keypress;
2112 int BC_TextBox::get_ibeam_letter()
2114 return ibeam_letter;
2117 void BC_TextBox::set_ibeam_letter(int number, int redraw)
2119 this->ibeam_letter = number;
2126 void BC_TextBox::set_separators(const char *separators)
2128 this->separators = (char*)separators;
2131 int BC_TextBox::get_rows()
2142 BC_TextBoxSuggestions::BC_TextBoxSuggestions(BC_TextBox *text_box, int x, int y)
2143 : BC_ListBox(x, y, text_box->get_w(), 200, LISTBOX_TEXT,
2144 text_box->suggestions, 0, 0, 1, 0, 1)
2146 this->text_box = text_box;
2148 set_justify(LISTBOX_LEFT);
2151 BC_TextBoxSuggestions::~BC_TextBoxSuggestions()
2155 int BC_TextBoxSuggestions::handle_event()
2157 char *current_suggestion = 0;
2158 BC_ListBoxItem *item = get_selection(0, 0);
2159 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2160 if(item && (current_suggestion=item->get_text()) != 0)
2162 int col = text_box->suggestion_column;
2163 int len = BCTEXTLEN-1 - col;
2164 char *cp = &text_box->text[col];
2165 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2166 strncpy(cp, current_suggestion, len);
2167 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2168 if( (col=strlen(current_suggestion)) >= len )
2170 text_box->dirty = 1;
2174 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2175 text_box->highlight_letter1 =
2176 text_box->highlight_letter2 =
2177 text_box->ibeam_letter = text_box->tstrlen();
2178 text_box->wtext_update();
2180 text_box->handle_event();
2181 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2186 BC_ScrollTextBox::BC_ScrollTextBox(BC_WindowBase *parent_window,
2187 int x, int y, int w, int rows,
2188 const char *default_text, int default_size)
2190 this->parent_window = parent_window;
2195 xscroll = 0; yscroll = 0;
2196 this->default_text = default_text;
2197 this->default_wtext = 0;
2198 this->default_size = default_size;
2201 BC_ScrollTextBox::BC_ScrollTextBox(BC_WindowBase *parent_window,
2202 int x, int y, int w, int rows,
2203 const wchar_t *default_wtext, int default_size)
2205 this->parent_window = parent_window;
2210 xscroll = 0; yscroll = 0;
2211 this->default_text = 0;
2212 this->default_wtext = default_wtext;
2213 this->default_size = default_size;
2216 BC_ScrollTextBox::~BC_ScrollTextBox()
2226 void BC_ScrollTextBox::create_objects()
2228 // Must be created first
2229 parent_window->add_subwindow(text = default_wtext ?
2230 new BC_ScrollTextBoxText(this, default_wtext) :
2231 new BC_ScrollTextBoxText(this, default_text));
2235 void BC_ScrollTextBox::set_text(char *text, int isz)
2237 this->text->set_text(text, isz);
2238 update_scrollbars();
2241 int BC_ScrollTextBox::set_text_row(int n)
2243 text->set_text_row(n);
2244 update_scrollbars();
2248 void BC_ScrollTextBox::update(const char *text)
2250 this->text->update(text);
2251 update_scrollbars();
2254 void BC_ScrollTextBox::update(const wchar_t *wtext)
2256 this->text->update(wtext);
2257 update_scrollbars();
2260 void BC_ScrollTextBox::reposition_window(int x, int y, int w, int rows)
2266 update_scrollbars();
2269 int BC_ScrollTextBox::button_press_event()
2271 return text->BC_TextBox::button_press_event();
2273 int BC_ScrollTextBox::button_release_event()
2275 return text->BC_TextBox::button_release_event();
2278 int BC_ScrollTextBox::get_h() { return text->get_h(); }
2279 const char *BC_ScrollTextBox::get_text() { return text->get_text(); }
2280 const wchar_t *BC_ScrollTextBox::get_wtext() { return text->get_wtext(); }
2282 int BC_ScrollTextBox::get_buttonpress()
2284 return text->BC_TextBox::get_buttonpress();
2286 void BC_ScrollTextBox::wset_selection(int char1, int char2, int ibeam)
2288 text->wset_selection(char1, char2, ibeam);
2290 void BC_ScrollTextBox::set_selection(int char1, int char2, int ibeam)
2292 text->set_selection(char1, char2, ibeam);
2294 int BC_ScrollTextBox::get_ibeam_letter()
2296 return text->get_ibeam_letter();
2298 int BC_ScrollTextBox::get_x_pos()
2300 return text->left_margin - text->get_text_x();
2302 void BC_ScrollTextBox::set_x_pos(int x)
2304 text->set_text_x(text->left_margin - x);
2308 BC_ScrollTextBoxText::BC_ScrollTextBoxText(BC_ScrollTextBox *gui, const char *text)
2309 : BC_TextBox(gui->x, gui->y,
2310 gui->w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
2311 gui->rows, gui->default_size, (char*)text, 1, MEDIUMFONT)
2316 BC_ScrollTextBoxText::BC_ScrollTextBoxText(BC_ScrollTextBox *gui, const wchar_t *wtext)
2317 : BC_TextBox(gui->x, gui->y,
2318 gui->w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
2319 gui->rows, gui->default_size, (wchar_t*)wtext, 1, MEDIUMFONT)
2324 BC_ScrollTextBoxText::~BC_ScrollTextBoxText()
2333 void BC_ScrollTextBox::update_scrollbars()
2335 int view_w = w, view_rows = rows;
2336 int view_h = BC_TextBox::calculate_row_h(view_rows, parent_window);
2337 int text_rows = text->get_text_rows();
2338 int text_width = parent_window->get_text_width(text->font, text->get_wtext());
2339 BC_Resources *resources = parent_window->get_resources();
2340 int need_xscroll = 0, need_yscroll = 0;
2342 // Create scrollbars as needed
2346 if( !need_xscroll && (text->get_text_x() != text->left_margin ||
2347 text_width >= view_w - text->left_margin - text->right_margin) ) {
2348 resize = need_xscroll = 1;
2349 view_h -= resources->hscroll_data[SCROLL_HANDLE_UP]->get_h();
2350 view_rows = BC_TextBox::pixels_to_rows(parent_window, text->font, view_h);
2352 if( !need_yscroll && (text->get_text_y() != text->top_margin ||
2353 text_rows > view_rows) ) {
2354 resize = need_yscroll = 1;
2355 view_w -= resources->vscroll_data[SCROLL_HANDLE_UP]->get_w();
2359 if( !need_xscroll && xscroll ) {
2361 delete xscroll; xscroll = 0;
2363 if( !need_yscroll && yscroll ) {
2365 delete yscroll; yscroll = 0;
2368 if( view_rows != text->get_rows() || view_w != text->get_w() ) {
2369 text->reposition_window(x, y, view_w, view_rows);
2371 if( need_xscroll && !xscroll ) {
2372 xscroll = new BC_ScrollTextBoxXScroll(this);
2373 parent_window->add_subwindow(xscroll);
2374 text->xscroll = xscroll;
2375 xscroll->bound_to = text;
2376 xscroll->show_window();
2378 if( need_yscroll && !yscroll ) {
2379 yscroll = new BC_ScrollTextBoxYScroll(this);
2380 parent_window->add_subwindow(yscroll);
2381 text->yscroll = yscroll;
2382 yscroll->bound_to = text;
2383 yscroll->show_window();
2386 xscroll->reposition_window(x, y + text->get_h(), view_w);
2387 int xpos = get_x_pos();
2388 if( xpos != xscroll->get_value() )
2389 xscroll->update_value(xpos);
2390 if( text_width != xscroll->get_length() ||
2391 view_w != xscroll->get_handlelength() )
2392 xscroll->update_length(text_width, xpos, view_w, 0);
2395 yscroll->reposition_window(x + w - yscroll->get_span(), y, text->get_h());
2396 int text_row = text->get_text_row();
2397 if( text_row != yscroll->get_value() )
2398 yscroll->update_value(text_row);
2399 if( text_rows != yscroll->get_length() ||
2400 view_rows != yscroll->get_handlelength() )
2401 yscroll->update_length(text_rows, text_row, view_rows, 0);
2405 int BC_ScrollTextBoxText::handle_event()
2407 gui->update_scrollbars();
2408 return gui->handle_event();
2411 int BC_ScrollTextBoxText::motion_event()
2413 gui->update_scrollbars();
2417 BC_ScrollTextBoxXScroll::BC_ScrollTextBoxXScroll(BC_ScrollTextBox *gui)
2418 : BC_ScrollBar(gui->x, gui->y + gui->text->get_h(), SCROLL_HORIZ + SCROLL_STRETCH,
2419 gui->text->get_w(), gui->text->get_text_width(MEDIUMFONT, gui->get_wtext()),
2425 BC_ScrollTextBoxXScroll::~BC_ScrollTextBoxXScroll()
2429 int BC_ScrollTextBoxXScroll::handle_event()
2431 gui->set_x_pos(get_position());
2435 BC_ScrollTextBoxYScroll::BC_ScrollTextBoxYScroll(BC_ScrollTextBox *gui)
2436 : BC_ScrollBar(gui->x + gui->text->get_w(), gui->y, SCROLL_VERT,
2437 gui->text->get_h(), gui->text->get_text_rows(), 0, gui->rows)
2442 BC_ScrollTextBoxYScroll::~BC_ScrollTextBoxYScroll()
2446 int BC_ScrollTextBoxYScroll::handle_event()
2448 gui->text->set_text_row(get_position());
2454 BC_PopupTextBoxText::BC_PopupTextBoxText(BC_PopupTextBox *popup, int x, int y, const char *text)
2455 : BC_TextBox(x, y, popup->text_w, 1, text, BCTEXTLEN)
2457 this->popup = popup;
2460 BC_PopupTextBoxText::BC_PopupTextBoxText(BC_PopupTextBox *popup, int x, int y, const wchar_t *wtext)
2461 : BC_TextBox(x, y, popup->text_w, 1, wtext, BCTEXTLEN)
2463 this->popup = popup;
2466 BC_PopupTextBoxText::~BC_PopupTextBoxText()
2476 int BC_PopupTextBoxText::handle_event()
2478 popup->handle_event();
2482 BC_PopupTextBoxList::BC_PopupTextBoxList(BC_PopupTextBox *popup, int x, int y)
2484 popup->text_w + BC_WindowBase::get_resources()->listbox_button[0]->get_w(),
2485 popup->list_h, popup->list_format, popup->list_items, 0, 0, 1, 0, 1)
2487 this->popup = popup;
2489 int BC_PopupTextBoxList::handle_event()
2491 BC_ListBoxItem *item = get_selection(0, 0);
2494 popup->textbox->update(item->get_text());
2495 popup->textbox->set_text_row(0);
2496 popup->handle_event();
2504 BC_PopupTextBox::BC_PopupTextBox(BC_WindowBase *parent_window,
2505 ArrayList<BC_ListBoxItem*> *list_items,
2506 const char *default_text, int x, int y,
2507 int text_w, int list_h, int list_format)
2511 this->list_h = list_h;
2512 this->list_format = list_format;
2513 this->default_text = (char*)default_text;
2514 this->default_wtext = 0;
2515 this->text_w = text_w;
2516 this->parent_window = parent_window;
2517 this->list_items = list_items;
2520 BC_PopupTextBox::~BC_PopupTextBox()
2530 int BC_PopupTextBox::create_objects()
2532 int x = this->x, y = this->y;
2533 parent_window->add_subwindow(textbox = default_wtext ?
2534 new BC_PopupTextBoxText(this, x, y, default_wtext) :
2535 new BC_PopupTextBoxText(this, x, y, default_text));
2536 x += textbox->get_w();
2537 parent_window->add_subwindow(listbox = new BC_PopupTextBoxList(this, x, y));
2541 void BC_PopupTextBox::update(const char *text)
2543 textbox->update(text);
2544 textbox->set_text_row(0);
2547 void BC_PopupTextBox::update_list(ArrayList<BC_ListBoxItem*> *data)
2549 listbox->update(data, 0, 0, 1);
2553 const char* BC_PopupTextBox::get_text()
2555 return textbox->get_text();
2558 const wchar_t* BC_PopupTextBox::get_wtext()
2560 return textbox->get_wtext();
2563 int BC_PopupTextBox::get_number()
2565 return listbox->get_selection_number(0, 0);
2568 int BC_PopupTextBox::get_x()
2573 int BC_PopupTextBox::get_y()
2578 int BC_PopupTextBox::get_w()
2580 return textbox->get_w() + listbox->get_w();
2583 int BC_PopupTextBox::get_h()
2585 return textbox->get_h();
2588 int BC_PopupTextBox::get_show_query()
2590 return listbox->get_show_query();
2593 void BC_PopupTextBox::set_show_query(int v)
2595 listbox->set_show_query(v);
2598 int BC_PopupTextBox::handle_event()
2603 void BC_PopupTextBox::reposition_window(int x, int y)
2608 textbox->reposition_window(x1,
2611 textbox->get_rows());
2612 x1 += textbox->get_w();
2613 listbox->reposition_window(x1, y1, -1, -1, 0);
2614 // if(flush) parent_window->flush();
2630 BC_TumbleTextBoxText::BC_TumbleTextBoxText(BC_TumbleTextBox *popup,
2631 int64_t default_value, int x, int y)
2632 : BC_TextBox(x, y, popup->text_w, 1, default_value)
2634 this->popup = popup;
2637 BC_TumbleTextBoxText::BC_TumbleTextBoxText(BC_TumbleTextBox *popup,
2638 float default_value, int x, int y, int precision)
2639 : BC_TextBox(x, y, popup->text_w, 1, default_value, 1, MEDIUMFONT, precision)
2641 this->popup = popup;
2644 BC_TumbleTextBoxText::~BC_TumbleTextBoxText()
2656 int BC_TumbleTextBoxText::handle_event()
2658 popup->handle_event();
2662 int BC_TumbleTextBoxText::button_press_event()
2664 if( get_enabled() && is_event_win() ) {
2665 if( get_buttonpress() < 4 ) return BC_TextBox::button_press_event();
2666 if( get_buttonpress() == 4 ) popup->tumbler->handle_up_event();
2667 else if( get_buttonpress() == 5 ) popup->tumbler->handle_down_event();
2676 BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window,
2677 int64_t default_value,
2689 this->default_value = default_value;
2690 this->text_w = text_w;
2691 this->parent_window = parent_window;
2697 BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window,
2710 this->default_value = default_value;
2711 this->text_w = text_w;
2712 this->parent_window = parent_window;
2718 BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window,
2719 float default_value_f,
2729 this->min_f = min_f;
2730 this->max_f = max_f;
2731 this->default_value_f = default_value_f;
2732 this->text_w = text_w;
2733 this->parent_window = parent_window;
2739 BC_TumbleTextBox::~BC_TumbleTextBox()
2741 // Recursive delete. Normally ~BC_TumbleTextBox is never called but textbox
2742 // is deleted anyway by the windowbase so textbox deletes this.
2743 if(tumbler) delete tumbler;
2745 // Don't delete text here if we were called by ~BC_TumbleTextBoxText
2754 void BC_TumbleTextBox::reset()
2761 void BC_TumbleTextBox::set_precision(int precision)
2763 this->precision = precision;
2766 void BC_TumbleTextBox::set_increment(float value)
2768 this->increment = value;
2769 if(tumbler) tumbler->set_increment(value);
2772 void BC_TumbleTextBox::set_log_floatincrement(int value)
2774 this->log_floatincrement = value;
2775 if(tumbler) tumbler->set_log_floatincrement(value);
2778 int BC_TumbleTextBox::create_objects()
2780 int x = this->x, y = this->y;
2782 textbox = use_float ?
2783 new BC_TumbleTextBoxText(this, default_value_f, x, y, precision) :
2784 new BC_TumbleTextBoxText(this, default_value, x, y);
2786 parent_window->add_subwindow(textbox);
2787 x += textbox->get_w();
2789 tumbler = use_float ?
2790 (BC_Tumbler *)new BC_FTumbler(textbox, min_f, max_f, x, y) :
2791 (BC_Tumbler *)new BC_ITumbler(textbox, min, max, x, y);
2792 parent_window->add_subwindow(tumbler);
2793 tumbler->set_increment(increment);
2797 const char* BC_TumbleTextBox::get_text()
2799 return textbox->get_text();
2802 const wchar_t* BC_TumbleTextBox::get_wtext()
2804 return textbox->get_wtext();
2807 BC_TextBox* BC_TumbleTextBox::get_textbox()
2812 int BC_TumbleTextBox::update(const char *value)
2814 textbox->update(value);
2815 textbox->set_text_row(0);
2819 int BC_TumbleTextBox::update(int64_t value)
2821 textbox->update(value);
2822 textbox->set_text_row(0);
2826 int BC_TumbleTextBox::update(float value)
2828 textbox->update(value);
2829 textbox->set_text_row(0);
2834 int BC_TumbleTextBox::get_x()
2839 int BC_TumbleTextBox::get_y()
2844 int BC_TumbleTextBox::get_w()
2846 return textbox->get_w() + tumbler->get_w();
2849 int BC_TumbleTextBox::get_h()
2851 return textbox->get_h();
2854 void BC_TumbleTextBox::disable(int hide_text)
2856 if( hide_text && !textbox->is_hidden() )
2857 textbox->hide_window(0);
2858 if( !tumbler->is_hidden() )
2859 tumbler->hide_window(0);
2860 if( !get_enabled() ) return;
2861 return textbox->disable();
2864 void BC_TumbleTextBox::enable()
2866 if( textbox->is_hidden() )
2867 textbox->show_window(0);
2868 if( tumbler->is_hidden() )
2869 tumbler->show_window(0);
2870 if( get_enabled() ) return;
2871 return textbox->enable();
2874 int BC_TumbleTextBox::get_enabled()
2876 return textbox->get_enabled();
2879 int BC_TumbleTextBox::handle_event()
2884 void BC_TumbleTextBox::reposition_window(int x, int y)
2889 textbox->reposition_window(x,
2893 tumbler->reposition_window(x + textbox->get_w(),
2895 // if(flush) parent_window->flush();
2899 void BC_TumbleTextBox::set_boundaries(int64_t min, int64_t max)
2901 tumbler->set_boundaries(min, max);
2904 void BC_TumbleTextBox::set_boundaries(float min, float max)
2906 tumbler->set_boundaries(min, max);
2911 BC_TextMenu::BC_TextMenu(BC_TextBox *textbox)
2912 : BC_PopupMenu(0, 0, 0, "", 0)
2914 this->textbox = textbox;
2917 BC_TextMenu::~BC_TextMenu()
2921 void BC_TextMenu::create_objects()
2923 add_item(new BC_TextMenuCut(this));
2924 add_item(new BC_TextMenuCopy(this));
2925 add_item(new BC_TextMenuPaste(this));
2929 BC_TextMenuCut::BC_TextMenuCut(BC_TextMenu *menu)
2930 : BC_MenuItem(_("Cut"))
2935 int BC_TextMenuCut::handle_event()
2937 menu->textbox->cut(1);
2943 BC_TextMenuCopy::BC_TextMenuCopy(BC_TextMenu *menu)
2944 : BC_MenuItem(_("Copy"))
2949 int BC_TextMenuCopy::handle_event()
2951 menu->textbox->copy(1);
2956 BC_TextMenuPaste::BC_TextMenuPaste(BC_TextMenu *menu)
2957 : BC_MenuItem(_("Paste"))
2962 int BC_TextMenuPaste::handle_event()
2964 menu->textbox->paste(1);
2969 void BC_TumbleTextBox::set_tooltip(const char *text)
2971 textbox->set_tooltip(text);