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 // reference shared directly
60 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
61 int size, wchr_t *wtext, int has_border, int font)
62 : BC_SubWindow(x, y, w, 0, -1)
66 reset_parameters(rows, has_border, font, size);
67 wdemand(wstrlen(wtext));
68 wstrncpy(this->wtext, wtext, wsize);
71 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
72 const char *text, int has_border, int font, int is_utf8)
73 : BC_SubWindow(x, y, w, 0, -1)
75 this->is_utf8 = is_utf8;
77 reset_parameters(rows, has_border, font, BCTEXTLEN);
81 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
82 const wchr_t *wtext, int has_border, int font, int is_utf8)
83 : BC_SubWindow(x, y, w, 0, -1)
85 this->is_utf8 = is_utf8;
87 reset_parameters(rows, has_border, font, BCTEXTLEN);
89 wtext = new wchr_t[wsize+1];
90 wstrncpy(this->wtext, wtext, wsize);
91 this->wtext[wsize] = 0;
94 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
95 int64_t text, int has_border, int font)
96 : BC_SubWindow(x, y, w, 0, -1)
100 reset_parameters(rows, has_border, font, BCSTRLEN);
101 snprintf(this->text, this->tsize, "%jd", text);
102 dirty = 1; wtext_update();
105 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
106 float text, int has_border, int font, int precision)
107 : BC_SubWindow(x, y, w, 0, -1)
111 reset_parameters(rows, has_border, font, BCSTRLEN);
112 this->precision = precision;
113 snprintf(this->text, this->tsize, "%0.*f", precision, text);
114 dirty = 1; wtext_update();
117 BC_TextBox::BC_TextBox(int x, int y, int w, int rows,
118 int text, int has_border, int font)
119 : BC_SubWindow(x, y, w, 0, -1)
123 reset_parameters(rows, has_border, font, BCSTRLEN);
124 snprintf(this->text, this->tsize, "%d", text);
125 dirty = 1; wtext_update();
128 BC_TextBox::~BC_TextBox()
130 if(skip_cursor) delete skip_cursor;
131 delete suggestions_popup;
132 suggestions->remove_all_objects();
140 int BC_TextBox::reset_parameters(int rows, int has_border, int font, int size)
142 suggestions = new ArrayList<BC_ListBoxItem*>;
143 suggestions_popup = 0;
144 suggestion_column = 0;
147 this->has_border = has_border;
149 // size > 0: fixed buffer, size == 0: dynamic buffer
150 // size < 0: fixed shared buffer via set_text
152 this->tsize = size >= 0 ? size : -size;
153 this->text = size > 0 ? new char[this->tsize+1] : 0;
154 if( this->text ) this->text[0] = 0;
157 highlight_letter1 = highlight_letter2 = 0;
158 highlight_letter3 = highlight_letter4 = 0;
172 skip_cursor = new Timer;
183 selection_active = 0;
187 int BC_TextBox::tstrlen()
189 return !text ? 0 : strnlen(text, tsize);
192 int BC_TextBox::tstrcmp(const char *cp)
194 const char *tp = get_text();
195 return strncmp(tp, cp, tsize);
198 char *BC_TextBox::tstrcpy(const char *cp)
202 if( !size ) tdemand(strlen(cp));
203 strncpy(text, cp, tsize);
210 char *BC_TextBox::tstrcat(const char *cp)
213 if( !size ) tdemand(tstrlen() + strlen(cp));
214 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 tlen = tstrlen();
224 int nsize = tsize > 0 ? tsize : tlen + BCTEXTLEN;
226 wlen = BC_Resources::encode(src_enc, dst_enc, text, tlen,
227 (char*)wtext, wsize*sizeof(wchr_t)) / sizeof(wchr_t);
234 int BC_TextBox::text_update(const wchr_t *wcp, int wsz, char *tcp, int tsz)
236 const char *src_enc = BC_Resources::wide_encoding;
237 const char *dst_enc = BC_Resources::encoding;
238 if( wsz < 0 ) wsz = wstrlen(wcp);
239 int len = BC_Resources::encode(src_enc, dst_enc,
240 (char*)wcp, wsz*sizeof(wchr_t), tcp, tsz);
245 int BC_TextBox::initialize()
249 skip_cursor = new Timer;
250 skip_cursor->update();
252 text_ascent = get_text_ascent(font) + 1;
253 text_descent = get_text_descent(font) + 1;
254 text_height = text_ascent + text_descent;
255 ibeam_letter = wtext_update();
258 left_margin = right_margin = HORIZONTAL_MARGIN;
259 top_margin = bottom_margin = VERTICAL_MARGIN;
263 left_margin = right_margin = HORIZONTAL_MARGIN_NOBORDER;
264 top_margin = bottom_margin = VERTICAL_MARGIN_NOBORDER;
267 text_x = left_margin;
271 // Create the subwindow
272 BC_SubWindow::initialize();
274 BC_Resources *resources = get_resources();
277 if( back_color < 0 ) back_color = resources->text_background;
278 if( high_color < 0 ) high_color = resources->text_background_hi;
282 if( back_color < 0 ) back_color = bg_color;
283 if( high_color < 0 ) high_color = resources->text_background_noborder_hi;
287 set_cursor(IBEAM_CURSOR, 0, 0);
290 add_subwindow(menu = new BC_TextMenu(this));
291 menu->create_objects();
296 int BC_TextBox::calculate_h(BC_WindowBase *gui,
301 return rows * (gui->get_text_ascent(font) + 1 +
302 gui->get_text_descent(font) + 1) +
303 2 * (has_border ? VERTICAL_MARGIN : VERTICAL_MARGIN_NOBORDER);
306 void BC_TextBox::set_precision(int precision)
308 this->precision = precision;
311 // Compute suggestions for a path
312 int BC_TextBox::calculate_suggestions(ArrayList<BC_ListBoxItem*> *entries, const char *filter)
314 // Let user delete suggestion
315 if(get_last_keypress() != BACKSPACE) {
316 // Compute suggestions
318 ArrayList<char*> suggestions;
319 const char *current_text = get_text();
320 int suggestion_column = 0;
321 char dirname[BCTEXTLEN]; dirname[0] = 0;
322 if( current_text[0] == '/' || current_text[0] == '~' )
323 strncpy(dirname, current_text, sizeof(dirname));
325 getcwd(dirname, sizeof(dirname));
326 // If directory, tabulate it
328 if( filter ) fs.set_filter(filter);
330 strncpy(dirname, current_text, sizeof(dirname));
331 if( (cp=strrchr(dirname, '/')) ||
332 (cp=strrchr(dirname, '~')) ) *++cp = 0;
333 fs.parse_tildas(dirname);
335 cp = (char *)current_text;
336 if( (prefix=strrchr(cp, '/')) ||
337 (prefix=strrchr(cp, '~')) ) ++prefix;
338 suggestion_column = !prefix ? 0 : prefix - cp;
339 int prefix_len = prefix ? strlen(prefix) : 0;
340 // only include items where the filename matches the basename prefix
341 for(int i = 0; i < fs.total_files(); i++) {
342 char *current_name = fs.get_entry(i)->name;
343 if( prefix_len>0 && strncmp(prefix, current_name, prefix_len) ) continue;
344 suggestions.append(current_name);
348 char *prefix = (char *)current_text;
349 int prefix_len = strlen(prefix);
350 for(int i = 0; i < entries->size(); i++) {
351 char *current_name = entries->get(i)->get_text();
352 if( prefix_len>0 && strncmp(prefix, current_name, prefix_len) ) continue;
353 suggestions.append(current_name);
356 set_suggestions(&suggestions, suggestion_column);
362 void BC_TextBox::no_suggestions()
364 if( suggestions_popup ) {
365 delete suggestions_popup;
366 suggestions_popup = 0;
371 void BC_TextBox::set_suggestions(ArrayList<char*> *suggestions, int column)
374 this->suggestions->remove_all_objects();
375 this->suggestion_column = column;
378 for(int i = 0; i < suggestions->size(); i++) {
379 this->suggestions->append(new BC_ListBoxItem(suggestions->get(i)));
382 // Show the popup without taking focus
383 if( suggestions->size() > 1 ) {
384 if( !suggestions_popup ) {
385 suggestions_popup = new BC_TextBoxSuggestions(this, x, y);
386 get_parent()->add_subwindow(suggestions_popup);
387 suggestions_popup->set_is_suggestions(1);
390 suggestions_popup->update(this->suggestions, 0, 0, 1);
392 suggestions_popup->activate(0);
395 // Show the highlighted text
396 if( suggestions->size() == 1 ) {
397 highlight_letter1 = wtext_update();
398 int len = text_update(wtext,wlen, text,tsize);
399 char *current_suggestion = suggestions->get(0);
400 int col = len - suggestion_column;
401 if( col < 0 ) col = 0;
402 char *cur = current_suggestion + col;
404 highlight_letter2 = wtext_update();
405 //printf("BC_TextBox::set_suggestions %d %d\n", __LINE__, suggestion_column);
413 if( !suggestions || !this->suggestions->size() )
417 void BC_TextBox::wset_selection(int char1, int char2, int ibeam)
419 highlight_letter1 = char1;
420 highlight_letter2 = char2;
421 ibeam_letter = ibeam;
425 // count utf8 chars in text which occur before cp
426 int BC_TextBox::wcpos(const char *text, const char *cp)
429 const unsigned char *bp = (const unsigned char *)text;
430 const unsigned char *ep = (const unsigned char *)cp;
431 while( bp < ep && *bp != 0 ) {
434 if( ch < 0x80 ) continue;
436 int n = i<0? 0 : i<32? 1 : i<48? 2 : i<56? 3 : i<60? 4 : 5;
437 for( i=n; bp < ep && --i>=0 && (*bp&0xc0) == 0x80; ++bp );
442 void BC_TextBox::set_selection(int char1, int char2, int ibeam)
444 const char *cp = get_text();
445 wset_selection(wcpos(cp, cp+char1), wcpos(cp, cp+char2), wcpos(cp, cp+ibeam));
448 int BC_TextBox::update(const char *text)
450 //printf("BC_TextBox::update 1 %d %s %s\n", tstrcmp(text), text, this->text);
451 // Don't update if contents are the same
452 int bg_color = has_border || !highlighted ? back_color : high_color;
453 if( bg_color == background_color && !tstrcmp(text)) return 0;
455 int wtext_len = wtext_update();
456 if(highlight_letter1 > wtext_len) highlight_letter1 = wtext_len;
457 if(highlight_letter2 > wtext_len) highlight_letter2 = wtext_len;
458 if(ibeam_letter > wtext_len) ibeam_letter = wtext_len;
463 int BC_TextBox::update(const wchr_t *wtext)
465 int wtext_len = wstrlen(wtext);
467 wstrncpy(this->wtext, wtext, wsize);
468 this->wlen = wtext_len;
469 if(highlight_letter1 > wtext_len) highlight_letter1 = wtext_len;
470 if(highlight_letter2 > wtext_len) highlight_letter2 = wtext_len;
471 if(ibeam_letter > wtext_len) ibeam_letter = wtext_len;
476 int BC_TextBox::update(int64_t value)
478 char string[BCTEXTLEN];
479 sprintf(string, "%jd", value);
484 int BC_TextBox::update(float value)
486 char string[BCTEXTLEN];
487 sprintf(string, "%0.*f", precision, value);
492 void BC_TextBox::disable()
501 void BC_TextBox::enable()
511 int BC_TextBox::get_enabled() { return enabled; }
512 int BC_TextBox::get_text_x() { return text_x; }
513 int BC_TextBox::get_text_y() { return text_y; }
514 void BC_TextBox::set_text_x(int v) { text_x = v; }
515 void BC_TextBox::set_text_y(int v) { text_y = v; }
516 int BC_TextBox::get_back_color() { return back_color; }
517 void BC_TextBox::set_back_color(int v) { back_color = v; }
519 int BC_TextBox::pixels_to_rows(BC_WindowBase *window, int font, int pixels)
521 return (pixels - 4) /
522 (window->get_text_ascent(font) + 1 +
523 window->get_text_descent(font) + 1);
526 int BC_TextBox::calculate_row_h(int rows,
527 BC_WindowBase *parent_window,
532 (parent_window->get_text_ascent(font) + 1 +
533 parent_window->get_text_descent(font) + 1) +
534 (has_border ? 4 : 0);
537 const char* BC_TextBox::get_text()
539 int wtext_len = wtext_update();
540 text_update(wtext,wtext_len, text,tsize);
544 const wchr_t* BC_TextBox::get_wtext()
550 void BC_TextBox::set_text(char *text, int isz)
552 if( size < 0 && isz > 0 ) {
562 int BC_TextBox::get_text_rows()
564 int wtext_len = wtext_update();
566 for(int i = 0; i < wtext_len; i++) {
567 if(wtext[i] == '\n') result++;
573 int BC_TextBox::get_row_h(int rows)
575 return rows * text_height + top_margin + bottom_margin;
578 int BC_TextBox::reposition_window(int x, int y, int w, int rows)
581 if(w < 0) w = get_w();
584 new_h = get_row_h(rows);
593 // printf("BC_TextBox::reposition_window 1 %d %d %d %d %d %d %d %d\n",
594 // x, get_x(), y, get_y(), w, get_w(), new_h, get_h());
595 BC_WindowBase::reposition_window(x, y, w, new_h);
601 void BC_TextBox::draw_border()
603 BC_Resources *resources = get_resources();
605 set_color(background_color);
606 draw_box(0, 0, left_margin, get_h());
607 draw_box(get_w() - right_margin, 0, right_margin, get_h());
612 draw_3d_border(0, 0, w, h,
613 resources->text_border1,
614 resources->text_border2_hi,
615 resources->text_border3_hi,
616 resources->text_border4);
618 draw_3d_border(0, 0, w, h,
619 resources->text_border1,
620 resources->text_border2,
621 resources->text_border3,
622 resources->text_border4);
626 void BC_TextBox::draw_cursor()
628 // set_color(background_color);
636 draw_box(ibeam_x + text_x,
645 void BC_TextBox::draw(int flush)
648 int row_begin, row_end;
649 int highlight_x1, highlight_x2;
651 BC_Resources *resources = get_resources();
653 //printf("BC_TextBox::draw %d %s\n", __LINE__, text);
655 background_color = has_border || !highlighted ? back_color : high_color;
656 set_color(background_color);
657 draw_box(0, 0, w, h);
659 int wtext_len = wtext_update();
661 // Draw text with selection
664 for(i=0, k=text_y; i < wtext_len && k < get_h(); k += text_height) {
667 wchr_t *wtext_row = &wtext[i];
668 for( ; i<wtext_len && wtext[i]!='\n'; ++i );
669 if( (row_end=i) < wtext_len ) ++i;
671 if(k > top_margin-text_height && k < get_h()-bottom_margin) {
672 // Draw highlighted region of row
673 if( highlight_letter2 > highlight_letter1 &&
674 highlight_letter2 > row_begin &&
675 highlight_letter1 <= row_end ) {
676 int color = active && enabled && get_has_focus() ?
677 resources->text_highlight :
679 resources->text_selected_highlight :
680 resources->text_inactive_highlight;
681 if( unicode_active >= 0 )
684 if(highlight_letter1 >= row_begin &&
685 highlight_letter1 <= row_end)
686 highlight_x1 = get_x_position(highlight_letter1, row_begin);
690 if(highlight_letter2 > row_begin &&
691 highlight_letter2 <= row_end)
692 highlight_x2 = get_x_position(highlight_letter2, row_begin);
694 highlight_x2 = get_w();
696 draw_box(highlight_x1 + text_x, k,
697 highlight_x2 - highlight_x1, text_height);
700 // Draw text over highlight
701 int len = row_end - row_begin;
703 set_color(enabled ? resources->text_default : DMGREY);
704 draw_single_text(1, font, text_x, k + text_ascent, wtext_row, len);
707 // Get ibeam location
708 if(ibeam_letter >= row_begin && ibeam_letter <= row_end) {
710 ibeam_y = k - text_y;
711 ibeam_x = get_x_position(ibeam_letter, row_begin);
716 //printf("BC_TextBox::draw 3 %d\n", ibeam_y);
718 // ibeam_x = ibeam_y = !wtext_len ? 0 : -1;
719 ibeam_x = 0; ibeam_y = k - text_y;
722 //printf("BC_TextBox::draw 4 %d\n", ibeam_y);
732 int BC_TextBox::focus_in_event()
738 int BC_TextBox::focus_out_event()
744 int BC_TextBox::cursor_enter_event()
746 if( top_level->event_win == win && enabled &&
747 !(top_level->get_resources()->textbox_focus_policy & CLICK_ACTIVATE) )
750 top_level->deactivate();
763 int BC_TextBox::cursor_leave_event()
772 if( !suggestions_popup && !get_button_down() &&
773 !(top_level->get_resources()->textbox_focus_policy & CLICK_DEACTIVATE) )
778 int BC_TextBox::button_press_event()
782 if(!enabled) return 0;
783 // if(get_buttonpress() != WHEEL_UP &&
784 // get_buttonpress() != WHEEL_DOWN &&
785 // get_buttonpress() != LEFT_BUTTON &&
786 // get_buttonpress() != MIDDLE_BUTTON) return 0;
788 if(debug) printf("BC_TextBox::button_press_event %d\n", __LINE__);
790 int cursor_letter = 0;
791 int wtext_len = wtext_update();
792 int update_scroll = 0;
795 if(top_level->event_win == win)
800 top_level->deactivate();
805 if(get_buttonpress() == WHEEL_UP)
807 text_y += text_height;
808 text_y = MIN(text_y, top_margin);
812 if(get_buttonpress() == WHEEL_DOWN)
814 int min_y = -(get_text_rows() *
818 text_y -= text_height;
819 text_y = MAX(text_y, min_y);
820 text_y = MIN(text_y, top_margin);
824 if(get_buttonpress() == RIGHT_BUTTON)
826 menu->activate_menu();
831 cursor_letter = get_cursor_letter(top_level->cursor_x, top_level->cursor_y);
833 //printf("BC_TextBox::button_press_event %d %d\n", __LINE__, cursor_letter);
836 if(get_triple_click())
838 //printf("BC_TextBox::button_press_event %d\n", __LINE__);
840 select_line(highlight_letter1, highlight_letter2, cursor_letter);
841 highlight_letter3 = highlight_letter1;
842 highlight_letter4 = highlight_letter2;
843 ibeam_letter = highlight_letter2;
844 copy_selection(PRIMARY_SELECTION);
847 if(get_double_click())
850 select_word(highlight_letter1, highlight_letter2, cursor_letter);
851 highlight_letter3 = highlight_letter1;
852 highlight_letter4 = highlight_letter2;
853 ibeam_letter = highlight_letter2;
854 copy_selection(PRIMARY_SELECTION);
857 if(get_buttonpress() == MIDDLE_BUTTON)
859 highlight_letter3 = highlight_letter4 =
860 ibeam_letter = highlight_letter1 =
861 highlight_letter2 = cursor_letter;
862 paste_selection(PRIMARY_SELECTION);
867 highlight_letter3 = highlight_letter4 =
868 ibeam_letter = highlight_letter1 =
869 highlight_letter2 = cursor_letter;
873 // Handle scrolling by highlighting text
874 if(text_selected || word_selected || line_selected)
876 set_repeat(top_level->get_resources()->scroll_repeat);
879 if(ibeam_letter < 0) ibeam_letter = 0;
880 if(ibeam_letter > wtext_len) ibeam_letter = wtext_len;
884 if(update_scroll && yscroll)
886 yscroll->update_length(get_text_rows(),
888 yscroll->get_handlelength(),
896 if( suggestions_popup && (!yscroll || !yscroll->is_event_win())) {
897 if( suggestions_popup->button_press_event() )
898 return suggestions_popup->handle_event();
900 else if( (top_level->get_resources()->textbox_focus_policy & CLICK_DEACTIVATE) )
907 int BC_TextBox::button_release_event()
912 if(text_selected || word_selected || line_selected)
918 // Stop scrolling by highlighting text
919 unset_repeat(top_level->get_resources()->scroll_repeat);
925 int BC_TextBox::cursor_motion_event()
927 int cursor_letter, letter1, letter2;
930 if(text_selected || word_selected || line_selected)
932 cursor_letter = get_cursor_letter(top_level->cursor_x,
933 top_level->cursor_y);
935 //printf("BC_TextBox::cursor_motion_event %d cursor_letter=%d\n", __LINE__, cursor_letter);
939 select_line(letter1, letter2, cursor_letter);
944 select_word(letter1, letter2, cursor_letter);
949 letter1 = letter2 = cursor_letter;
952 if(letter1 <= highlight_letter3)
954 highlight_letter1 = letter1;
955 highlight_letter2 = highlight_letter4;
956 ibeam_letter = letter1;
959 if(letter2 >= highlight_letter4)
961 highlight_letter2 = letter2;
962 highlight_letter1 = highlight_letter3;
963 ibeam_letter = letter2;
966 copy_selection(PRIMARY_SELECTION);
979 int BC_TextBox::activate()
983 top_level->set_active_subwindow(this);
984 top_level->set_repeat(top_level->get_resources()->blink_rate);
990 int BC_TextBox::deactivate()
994 text_selected = word_selected = line_selected = 0;
995 top_level->set_active_subwindow(0);
996 top_level->unset_repeat(top_level->get_resources()->blink_rate);
1002 int BC_TextBox::repeat_event(int64_t duration)
1005 int cursor_y = get_cursor_y();
1006 //int cursor_x = get_cursor_x();
1008 if(duration == top_level->get_resources()->tooltip_delay &&
1009 tooltip_text && tooltip_text[0] != 0 && highlighted)
1015 if(duration == top_level->get_resources()->blink_rate &&
1019 // don't flash if keypress
1020 if(skip_cursor->get_difference() < 500)
1022 // printf("BC_TextBox::repeat_event 1 %lld %lld\n",
1023 // skip_cursor->get_difference(),
1029 if(!(text_selected || word_selected || line_selected))
1038 if(duration == top_level->get_resources()->scroll_repeat &&
1039 (text_selected || word_selected || line_selected))
1042 if(get_cursor_y() < top_margin)
1044 difference = get_cursor_y() - top_margin ;
1047 if(get_cursor_y() > get_h() - bottom_margin)
1049 difference = get_cursor_y() -
1050 (get_h() - bottom_margin);
1052 if(difference != 0) {
1053 int min_y = -(get_text_rows() * text_height -
1054 get_h() + bottom_margin);
1056 text_y -= difference;
1057 // printf("BC_TextBox::repeat_event %d %d %d\n",
1061 text_y = MAX(min_y, text_y);
1062 text_y = MIN(text_y, top_margin);
1069 if(get_cursor_x() < left_margin)
1071 int difference = left_margin - get_cursor_x();
1073 text_x += difference;
1074 text_x = MIN(text_x, left_margin);
1078 else if(get_cursor_x() > get_w() - right_margin)
1080 int difference = get_cursor_x() - (get_w() - right_margin);
1081 int new_text_x = text_x - difference;
1083 // Get width of current row
1086 int wtext_len = wtext_update();
1089 for(int i = 0, k = text_y; i < wtext_len; k += text_height)
1092 while(wtext[i] != '\n' && i < wtext_len) {
1096 if(wtext[i] == '\n') i++;
1098 if(cursor_y >= k && cursor_y < k + text_height) {
1099 row_width = get_text_width(font,
1101 row_end - row_begin);
1107 min_x = -row_width + get_w() - left_margin - BCCURSORW;
1108 new_text_x = MAX(new_text_x, min_x);
1109 new_text_x = MIN(new_text_x, left_margin);
1111 if(new_text_x < text_x) text_x = new_text_x;
1120 void BC_TextBox::default_keypress(int &dispatch_event, int &result)
1122 int key = top_level->get_keypress(), len;
1123 wchr_t *wkeys = top_level->get_wkeystring(&len);
1125 case KPENTER: key = '\n'; goto kpchr;
1126 case KPMINUS: key = '-'; goto kpchr;
1127 case KPPLUS: key = '+'; goto kpchr;
1128 case KPDEL: key = '.'; goto kpchr;
1129 case RETURN: key = '\n'; goto kpchr;
1130 case KPINS: key = '0'; goto kpchr;
1131 case KP1: case KP2: case KP3: case KP4: case KP5:
1132 case KP6: case KP7: case KP8: case KP9:
1133 key = key - KP1 + '1';
1135 wkeys[0] = key; wkeys[1] = 0; len = 1;
1138 if( key < 32 || key > 255 ) return;
1140 insert_text(wkeys, len);
1147 int BC_TextBox::keypress_event()
1149 // Result == 2 contents changed
1150 // Result == 1 trapped keypress
1151 // Result == 0 nothing
1153 int dispatch_event = 0;
1156 if (context_help_check_and_show()) return 1;
1158 if(!active || !enabled) return 0;
1160 int wtext_len = wtext_update();
1161 last_keypress = get_keypress();
1163 if( unicode_active >= 0 ) {
1166 switch( last_keypress ) {
1167 //unicode active acitons
1169 for( int i=highlight_letter1+1; i<highlight_letter2; ++i ) {
1170 int ch = nib(wtext[i]);
1171 if( ch < 0 ) return 1;
1172 wch = (wch<<4) + ch;
1176 unicode_active = -1;
1182 unicode_active = -1;
1187 if(ibeam_letter > 0) {
1188 delete_selection(ibeam_letter - 1, ibeam_letter, wtext_len);
1189 highlight_letter2 = --ibeam_letter;
1190 if( highlight_letter1 >= highlight_letter2 )
1191 unicode_active = -1;
1196 case KPINS: last_keypress = KP1-'1'+'0'; // fall thru
1197 case KP1: case KP2: case KP3: case KP4: case KP5:
1198 case KP6: case KP7: case KP8: case KP9:
1199 last_keypress = last_keypress-KP1 + '1';
1200 case '0': case '1': case '2': case '3': case '4':
1201 case '5': case '6': case '7': case '8': case '9':
1202 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
1203 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': {
1204 int n = nib(last_keypress);
1205 wch = n < 10 ? '0'+n : 'A'+n-10;
1219 insert_text(&wch, wlen);
1221 if( unicode_active >= 0 )
1222 highlight_letter2 = ibeam_letter;
1224 highlight_letter1 = highlight_letter2 = 0;
1230 //printf("BC_TextBox::keypress_event %d %x\n", __LINE__, last_keypress)
1231 switch(last_keypress) {
1233 // Deactivate the suggestions
1234 if( suggestions_popup ) {
1239 top_level->deactivate();
1246 highlight_letter1 = highlight_letter2 = 0;
1247 ibeam_letter = wtext_update();
1248 top_level->deactivate();
1253 default_keypress(dispatch_event, result);
1258 // Handle like a default keypress
1260 top_level->cycle_textboxes(1);
1265 top_level->cycle_textboxes(-1);
1270 if(ibeam_letter > 0) {
1271 int old_ibeam_letter = ibeam_letter;
1279 while(ibeam_letter > 0 && isalnum(wtext[ibeam_letter - 1]))
1284 if(top_level->shift_down()) {
1285 // Initialize highlighting
1286 if(highlight_letter1 == highlight_letter2) {
1287 highlight_letter1 = ibeam_letter;
1288 highlight_letter2 = old_ibeam_letter;
1290 else if(highlight_letter1 == old_ibeam_letter) {
1291 // Extend left highlight
1292 highlight_letter1 = ibeam_letter;
1294 else if(highlight_letter2 == old_ibeam_letter) {
1295 // Shrink right highlight
1296 highlight_letter2 = ibeam_letter;
1300 highlight_letter1 = highlight_letter2 = ibeam_letter;
1305 if(keypress_draw) draw(1);
1311 if(ibeam_letter < wtext_len) {
1312 int old_ibeam_letter = ibeam_letter;
1319 while(ibeam_letter < wtext_len && isalnum(wtext[ibeam_letter++]));
1325 if(top_level->shift_down()) {
1326 // Initialize highlighting
1327 if(highlight_letter1 == highlight_letter2) {
1328 highlight_letter1 = old_ibeam_letter;
1329 highlight_letter2 = ibeam_letter;
1331 else if(highlight_letter1 == old_ibeam_letter) {
1332 // Shrink left highlight
1333 highlight_letter1 = ibeam_letter;
1335 else if(highlight_letter2 == old_ibeam_letter) {
1336 // Expand right highlight
1337 highlight_letter2 = ibeam_letter;
1341 highlight_letter1 = highlight_letter2 = ibeam_letter;
1345 if(keypress_draw) draw(1);
1351 if( suggestions && suggestions_popup ) {
1352 // Pass to suggestions popup
1353 //printf("BC_TextBox::keypress_event %d\n", __LINE__);
1354 suggestions_popup->activate(1);
1355 suggestions_popup->keypress_event();
1358 else if(ibeam_letter > 0) {
1359 //printf("BC_TextBox::keypress_event 1 %d %d %d\n", ibeam_x, ibeam_y, ibeam_letter);
1360 int new_letter = get_cursor_letter2(ibeam_x + text_x,
1361 ibeam_y + text_y - text_height);
1362 //printf("BC_TextBox::keypress_event 2 %d %d %d\n", ibeam_x, ibeam_y, new_letter);
1365 if(top_level->shift_down()) {
1366 // Initialize highlighting
1367 if(highlight_letter1 == highlight_letter2) {
1368 highlight_letter1 = new_letter;
1369 highlight_letter2 = ibeam_letter;
1371 else if(highlight_letter1 == ibeam_letter) {
1372 // Expand left highlight
1373 highlight_letter1 = new_letter;
1375 else if(highlight_letter2 == ibeam_letter) {
1376 // Shrink right highlight
1377 highlight_letter2 = new_letter;
1381 highlight_letter1 = highlight_letter2 = new_letter;
1383 if(highlight_letter1 > highlight_letter2) {
1384 int temp = highlight_letter1;
1385 highlight_letter1 = highlight_letter2;
1386 highlight_letter2 = temp;
1388 ibeam_letter = new_letter;
1391 if(keypress_draw) draw(1);
1397 if(ibeam_letter > 0) {
1398 int new_letter = get_cursor_letter2(ibeam_x + text_x,
1399 ibeam_y + text_y - get_h());
1402 if(top_level->shift_down()) {
1403 // Initialize highlighting
1404 if(highlight_letter1 == highlight_letter2) {
1405 highlight_letter1 = new_letter;
1406 highlight_letter2 = ibeam_letter;
1408 else if(highlight_letter1 == ibeam_letter) {
1409 // Expand left highlight
1410 highlight_letter1 = new_letter;
1412 else if(highlight_letter2 == ibeam_letter) {
1413 // Shrink right highlight
1414 highlight_letter2 = new_letter;
1418 highlight_letter1 = highlight_letter2 = new_letter;
1420 if(highlight_letter1 > highlight_letter2) {
1421 int temp = highlight_letter1;
1422 highlight_letter1 = highlight_letter2;
1423 highlight_letter2 = temp;
1425 ibeam_letter = new_letter;
1428 if(keypress_draw) draw(1);
1434 // printf("BC_TextBox::keypress_event %d %p %p\n",
1437 // suggestions_popup);
1438 if( suggestions && suggestions_popup ) {
1439 // Pass to suggestions popup
1440 suggestions_popup->activate(1);
1441 suggestions_popup->keypress_event();
1445 // if(ibeam_letter > 0)
1448 int new_letter = get_cursor_letter2(ibeam_x + text_x,
1449 ibeam_y + text_y + text_height);
1450 //printf("BC_TextBox::keypress_event 10 %d\n", new_letter);
1452 if(top_level->shift_down()) {
1453 // Initialize highlighting
1454 if(highlight_letter1 == highlight_letter2) {
1455 highlight_letter1 = new_letter;
1456 highlight_letter2 = ibeam_letter;
1458 else if(highlight_letter1 == ibeam_letter) {
1459 // Shrink left highlight
1460 highlight_letter1 = new_letter;
1462 else if(highlight_letter2 == ibeam_letter) {
1463 // Expand right highlight
1464 highlight_letter2 = new_letter;
1468 highlight_letter1 = highlight_letter2 = new_letter;
1470 if(highlight_letter1 > highlight_letter2) {
1471 int temp = highlight_letter1;
1472 highlight_letter1 = highlight_letter2;
1473 highlight_letter2 = temp;
1475 ibeam_letter = new_letter;
1478 if(keypress_draw) draw(1);
1480 //printf("BC_TextBox::keypress_event 20 %d\n", ibeam_letter);
1487 int new_letter = get_cursor_letter2(ibeam_x + text_x,
1488 ibeam_y + text_y + get_h());
1489 //printf("BC_TextBox::keypress_event 10 %d\n", new_letter);
1491 if(top_level->shift_down()) {
1492 // Initialize highlighting
1493 if(highlight_letter1 == highlight_letter2) {
1494 highlight_letter1 = new_letter;
1495 highlight_letter2 = ibeam_letter;
1497 else if(highlight_letter1 == ibeam_letter) {
1498 // Shrink left highlight
1499 highlight_letter1 = new_letter;
1501 else if(highlight_letter2 == ibeam_letter) {
1502 // Expand right highlight
1503 highlight_letter2 = new_letter;
1507 highlight_letter1 = highlight_letter2 = new_letter;
1509 if(highlight_letter1 > highlight_letter2) {
1510 int temp = highlight_letter1;
1511 highlight_letter1 = highlight_letter2;
1512 highlight_letter2 = temp;
1514 ibeam_letter = new_letter;
1517 if(keypress_draw) draw(1);
1519 //printf("BC_TextBox::keypress_event 20 %d\n", ibeam_letter);
1526 int old_ibeam_letter = ibeam_letter;
1528 while(ibeam_letter < wtext_len && wtext[ibeam_letter] != '\n')
1531 if(top_level->shift_down()) {
1533 if(highlight_letter1 == highlight_letter2) {
1534 highlight_letter2 = ibeam_letter;
1535 highlight_letter1 = old_ibeam_letter;
1537 else if(highlight_letter1 == old_ibeam_letter) {
1539 highlight_letter1 = highlight_letter2;
1540 highlight_letter2 = ibeam_letter;
1542 else if(highlight_letter2 == old_ibeam_letter) {
1544 highlight_letter2 = ibeam_letter;
1548 highlight_letter1 = highlight_letter2 = ibeam_letter;
1551 if(keypress_draw) draw(1);
1558 int old_ibeam_letter = ibeam_letter;
1560 while(ibeam_letter > 0 && wtext[ibeam_letter - 1] != '\n')
1563 if(top_level->shift_down())
1566 if(highlight_letter1 == highlight_letter2)
1568 highlight_letter2 = old_ibeam_letter;
1569 highlight_letter1 = ibeam_letter;
1573 if(highlight_letter1 == old_ibeam_letter)
1575 highlight_letter1 = ibeam_letter;
1579 if(highlight_letter2 == old_ibeam_letter)
1581 highlight_letter2 = highlight_letter1;
1582 highlight_letter1 = ibeam_letter;
1586 highlight_letter1 = highlight_letter2 = ibeam_letter;
1589 if(keypress_draw) draw(1);
1596 if(highlight_letter1 == highlight_letter2) {
1597 if(ibeam_letter > 0) {
1598 delete_selection(ibeam_letter - 1, ibeam_letter, wtext_len);
1603 delete_selection(highlight_letter1, highlight_letter2, wtext_len);
1604 highlight_letter2 = ibeam_letter = highlight_letter1;
1608 if(keypress_draw) draw(1);
1614 //printf("BC_TextBox::keypress_event %d\n", __LINE__);
1615 if(highlight_letter1 == highlight_letter2) {
1616 if(ibeam_letter < wtext_len) {
1617 delete_selection(ibeam_letter, ibeam_letter + 1, wtext_len);
1621 delete_selection(highlight_letter1, highlight_letter2, wtext_len);
1622 highlight_letter2 = ibeam_letter = highlight_letter1;
1626 if(keypress_draw) draw(1);
1633 switch( last_keypress ) {
1634 case 'c': case 'C': {
1637 case 'v': case 'V': {
1641 case 'x': case 'X': {
1645 case 'u': case 'U': {
1646 if( shift_down() ) {
1647 unicode_active = ibeam_letter;
1649 insert_text(&wkey, 1);
1651 highlight_letter1 = unicode_active;
1652 highlight_letter2 = ibeam_letter;
1661 default_keypress(dispatch_event, result);
1666 if(result) skip_cursor->update();
1667 if(dispatch_event && handle_event())
1674 int BC_TextBox::cut(int do_update)
1676 if( highlight_letter1 != highlight_letter2 ) {
1677 int wtext_len = wtext_update();
1678 copy_selection(SECONDARY_SELECTION);
1679 delete_selection(highlight_letter1, highlight_letter2, wtext_len);
1680 highlight_letter2 = ibeam_letter = highlight_letter1;
1688 skip_cursor->update();
1694 int BC_TextBox::copy(int do_update)
1697 if( highlight_letter1 != highlight_letter2 ) {
1698 copy_selection(SECONDARY_SELECTION);
1701 skip_cursor->update();
1707 int BC_TextBox::paste(int do_update)
1709 paste_selection(SECONDARY_SELECTION);
1714 skip_cursor->update();
1721 int BC_TextBox::uses_text()
1727 void BC_TextBox::delete_selection(int letter1, int letter2, int wtext_len)
1730 for(i=letter1, j=letter2; j<wtext_len; i++, j++) {
1731 wtext[i] = wtext[j];
1739 int BC_TextBox::wdemand(int len)
1741 if( wtext && wsize >= len ) return 0;
1742 int nsize = len + wlen/2 + BCTEXTLEN;
1743 wchr_t *ntext = new wchr_t[nsize+1];
1745 memcpy(ntext, wtext, wsize*sizeof(wtext[0]));
1746 delete [] wtext; wtext = ntext; wsize = nsize;
1750 int BC_TextBox::tdemand(int len)
1752 if( text && tsize >= len ) return 0;
1753 int tlen = !text ? 0 : strlen(text);
1754 int nsize = len + tlen/2 + BCTEXTLEN;
1755 char *ntext = new char[nsize+1];
1757 memcpy(ntext, text, tsize*sizeof(text[0]));
1758 delete [] text; text = ntext; tsize = nsize;
1762 void BC_TextBox::insert_text(const wchr_t *wcp, int len)
1764 if( len < 0 ) len = wstrlen(wcp);
1765 int wtext_len = wtext_update();
1766 wdemand(wtext_len + len + 1);
1767 if( unicode_active < 0 && highlight_letter1 < highlight_letter2 ) {
1768 delete_selection(highlight_letter1, highlight_letter2, wtext_len);
1769 highlight_letter2 = ibeam_letter = highlight_letter1;
1770 wtext_len = wtext_update();
1774 for( i=wtext_len, j=wtext_len+len; --i>=ibeam_letter; )
1775 if( --j < wsize ) wtext[j] = wtext[i];
1776 for( i=ibeam_letter,j=0; j<len; ++i, ++j )
1777 if( i < wsize ) wtext[i] = wcp[j];
1779 if( (wlen+=len) > wsize ) wlen = wsize;
1780 if( (ibeam_letter+=len) > wsize ) ibeam_letter = wsize;
1781 wtext[wlen] = 0; // wtext allocated wsize+1
1785 int BC_TextBox::is_separator(const char *txt, int i)
1787 if( i != 0 || separators[0] != '+' ) return !isalnum(txt[i]);
1788 return txt[0] != '+' && txt[0] != '-' && !isalnum(txt[0]);
1791 // used for time entry
1792 void BC_TextBox::do_separators(int ibeam_left)
1796 // Remove separators from text
1797 int wtext_len = wtext_update();
1798 for(int i = 0; i < wtext_len; ) {
1799 if( !iswalnum(wtext[i]) ) {
1800 for(int j = i; j < wtext_len - 1; j++)
1801 wtext[j] = wtext[j + 1];
1802 if(!ibeam_left && i < ibeam_letter) ibeam_letter--;
1808 wtext[wtext_len] = 0;
1814 // Insert separators into text
1815 int separator_len = strlen(separators);
1816 for(int i = 0; i < separator_len; i++) {
1818 // Insert a separator
1819 if( is_separator(separators,i) ) {
1820 for(int j = wtext_len; j >= i; j--) {
1821 wtext[j + 1] = wtext[j];
1823 if(!ibeam_left && i < ibeam_letter) ibeam_letter++;
1825 wtext[i] = separators[i];
1829 wtext[i] = separators[i];
1834 wtext[separator_len] = 0;
1835 wlen = separator_len;
1839 int BC_TextBox::get_x_position(int i, int start)
1841 return get_text_width(font, &wtext[start], i - start);
1844 void BC_TextBox::get_ibeam_position(int &x, int &y)
1846 int i, row_begin, row_end;
1847 int wtext_len = wtext_update();
1850 for( i=0; i<wtext_len; ) {
1852 for(; i<wtext_len && wtext[i]!='\n'; i++);
1855 if( ibeam_letter >= row_begin && ibeam_letter <= row_end ) {
1856 x = get_x_position(ibeam_letter, row_begin);
1857 //printf("BC_TextBox::get_ibeam_position %d %d %d %d %d\n", ibeam_letter, row_begin, row_end, x, y);
1861 if( i < wtext_len && wtext[i] == '\n' ) {
1866 //printf("BC_TextBox::get_ibeam_position 10 %d %d\n", x, y);
1872 void BC_TextBox::set_text_row(int row)
1874 text_x = left_margin;
1875 text_y = -(row * text_height) + top_margin;
1879 int BC_TextBox::get_text_row()
1881 return -(text_y - top_margin) / text_height;
1884 void BC_TextBox::find_ibeam(int dispatch_event)
1887 int old_x = text_x, old_y = text_y;
1889 get_ibeam_position(x, y);
1891 if(left_margin + text_x + x >= get_w() - right_margin - BCCURSORW)
1893 text_x = -(x - (get_w() - get_w() / 4)) + left_margin;
1894 if(text_x > left_margin) text_x = left_margin;
1897 if(left_margin + text_x + x < left_margin)
1899 text_x = -(x - (get_w() / 4)) + left_margin;
1900 if(text_x > left_margin) text_x = left_margin;
1903 int text_row = y / text_height;
1904 if( text_row < rows ) text_y = top_margin;
1906 int pix_rows = get_h() - bottom_margin - (y + text_y);
1907 if( pix_rows < text_height )
1908 text_y -= text_height * ((2*text_height-1-pix_rows) / text_height);
1910 pix_rows = y + text_y - top_margin;
1911 if( pix_rows < 0 ) {
1912 text_y += text_height * ((text_height-1-pix_rows) / text_height);
1913 if( text_y > top_margin ) text_y = top_margin;
1916 if(dispatch_event && (old_x != text_x || old_y != text_y)) motion_event();
1920 int BC_TextBox::get_cursor_letter(int cursor_x, int cursor_y)
1922 int i, j, k, row_begin, row_end, result = 0, done = 0;
1923 int column1, column2;
1924 int got_visible_row = 0;
1926 // Select complete row if cursor above the window
1927 //printf("BC_TextBox::get_cursor_letter %d %d\n", __LINE__, text_y);
1928 if(cursor_y < text_y - text_height)
1934 int wtext_len = wtext_update();
1936 for(i=0, k=text_y; i<wtext_len && k<get_h() && !done; k+=text_height) {
1937 // Simulate drawing of 1 row
1939 for(j = 0; wtext[i]!='\n' && i<wtext_len; i++);
1943 int first_visible_row = 0;
1944 int last_visible_row = 0;
1945 if( k+text_height > top_margin && !got_visible_row) {
1946 first_visible_row = 1;
1947 got_visible_row = 1;
1950 if( (k+text_height >= get_h() - bottom_margin ||
1951 (row_end >= wtext_len && k < get_h() - bottom_margin &&
1952 k + text_height > 0)) )
1953 last_visible_row = 1;
1955 // Cursor is inside vertical range of row
1956 if((cursor_y >= top_margin &&
1957 cursor_y < get_h() - bottom_margin &&
1958 cursor_y >= k && cursor_y < k + text_height) ||
1959 // Cursor is above 1st row
1960 (cursor_y < k + text_height && first_visible_row) ||
1961 // Cursor is below last row
1962 (cursor_y >= k && last_visible_row))
1964 column1 = column2 = 0;
1965 for(j = row_begin; j<wsize && j<=row_end && !done; j++) {
1966 column2 = get_text_width(font, &wtext[row_begin], j-row_begin) + text_x;
1967 if((column2 + column1) / 2 >= cursor_x) {
1970 // printf("BC_TextBox::get_cursor_letter %d %d %d %d\n",
1971 // __LINE__, result, first_visible_row, last_visible_row);
1982 if(wtext[i] == '\n') i++;
1984 // Select complete row if last visible & cursor is below window
1985 if(last_visible_row && cursor_y > k + text_height * 2)
1988 if(i >= wtext_len && !done) {
1994 // printf("BC_TextBox::get_cursor_letter %d cursor_y=%d k=%d h=%d %d %d\n",
1995 // __LINE__, cursor_y, k, get_h(), first_visible_row, last_visible_row);
1996 if(result < 0) result = 0;
1997 if(result > wtext_len) {
1998 //printf("BC_TextBox::get_cursor_letter %d\n", __LINE__);
2006 int BC_TextBox::get_cursor_letter2(int cursor_x, int cursor_y)
2008 int i, j, k, row_begin, row_end, result = 0, done = 0;
2009 int column1, column2;
2010 int wtext_len = wtext_update();
2012 if(cursor_y < text_y) {
2017 for(i = 0, k = text_y; i < wtext_len && !done; k += text_height) {
2019 for(; wtext[i] != '\n' && i < wtext_len; i++);
2022 if(cursor_y >= k && cursor_y < k + text_height) {
2023 column1 = column2 = 0;
2024 for(j = 0; j <= row_end - row_begin && !done; j++) {
2025 column2 = get_text_width(font, &wtext[row_begin], j) + text_x;
2026 if((column2 + column1) / 2 >= cursor_x) {
2027 result = row_begin + j - 1;
2038 if(wtext[i] == '\n') i++;
2040 if(i >= wtext_len && !done) {
2044 if(result < 0) result = 0;
2045 if(result > wtext_len) result = wtext_len;
2050 void BC_TextBox::select_word(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 && iswalnum(wtext[i]); --i ) letter1 = i;
2060 for( int i=letter2; i<wtext_len && iswalnum(wtext[i]); ) letter2 = ++i;
2061 if( letter2 < wtext_len && wtext[letter2] == ' ' ) ++letter2;
2065 void BC_TextBox::select_line(int &letter1, int &letter2, int ibeam_letter)
2067 int wtext_len = wtext_update();
2068 letter1 = letter2 = ibeam_letter;
2069 if( letter1 < 0 ) letter1 = 0;
2070 if( letter2 < 0 ) letter2 = 0;
2071 if( letter1 > wtext_len ) letter1 = wtext_len;
2072 if( letter2 > wtext_len ) letter2 = wtext_len;
2073 if( !wtext_len ) return;
2074 for( int i=letter1; i>=0 && wtext[i]!='\n'; --i ) letter1 = i;
2075 for( int i=letter2; i<wtext_len && wtext[i]!='\n'; ) letter2 = ++i;
2078 void BC_TextBox::copy_selection(int clipboard_num)
2080 int wtext_len = wtext_update();
2081 if(!wtext_len) return;
2083 if(highlight_letter1 >= wtext_len || highlight_letter2 > wtext_len ||
2084 highlight_letter1 < 0 || highlight_letter2 < 0 ||
2085 highlight_letter2 - highlight_letter1 <= 0) return;
2086 int clip_len = highlight_letter2 - highlight_letter1;
2087 //printf(" BC_TextBox::copy_selection %d %d %d\n",highlight_letter1, highlight_letter2, clip_len);
2088 char ctext[4*clip_len+4];
2089 clip_len = text_update(&wtext[highlight_letter1],clip_len, ctext,4*clip_len+4);
2090 to_clipboard(ctext, clip_len, clipboard_num);
2091 selection_active = 1;
2094 int BC_TextBox::selection_clear_event()
2096 if( !is_event_win() ) return 0;
2097 selection_active = 0;
2102 void BC_TextBox::paste_selection(int clipboard_num)
2104 int len = clipboard_len(clipboard_num);
2107 char cstring[len]; wchr_t wstring[len];
2108 from_clipboard(cstring, len, clipboard_num); --len;
2109 //printf("BC_TextBox::paste_selection %d '%*.*s'\n",len,len,len,cstring);
2110 len = BC_Resources::encode(BC_Resources::encoding, BC_Resources::wide_encoding,
2111 cstring,len, (char *)wstring,(len+1)*sizeof(wchr_t)) / sizeof(wchr_t);
2112 insert_text(wstring, len);
2117 void BC_TextBox::set_keypress_draw(int value)
2119 keypress_draw = value;
2122 int BC_TextBox::get_last_keypress()
2124 return last_keypress;
2127 int BC_TextBox::get_ibeam_letter()
2129 return ibeam_letter;
2132 void BC_TextBox::set_ibeam_letter(int number, int redraw)
2134 this->ibeam_letter = number;
2141 void BC_TextBox::set_separators(const char *separators)
2143 this->separators = (char*)separators;
2146 int BC_TextBox::get_rows()
2157 BC_TextBoxSuggestions::BC_TextBoxSuggestions(BC_TextBox *text_box, int x, int y)
2158 : BC_ListBox(x, y, text_box->get_w(), 200, LISTBOX_TEXT,
2159 text_box->suggestions, 0, 0, 1, 0, 1)
2161 this->text_box = text_box;
2163 set_justify(LISTBOX_LEFT);
2166 BC_TextBoxSuggestions::~BC_TextBoxSuggestions()
2170 int BC_TextBoxSuggestions::handle_event()
2172 char *current_suggestion = 0;
2173 BC_ListBoxItem *item = get_selection(0, 0);
2174 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2175 if(item && (current_suggestion=item->get_text()) != 0)
2177 int col = text_box->suggestion_column;
2178 int len = BCTEXTLEN-1 - col;
2179 char *cp = &text_box->text[col];
2180 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2181 strncpy(cp, current_suggestion, len);
2182 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2183 if( (col=strlen(current_suggestion)) >= len )
2185 text_box->dirty = 1;
2189 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2190 text_box->highlight_letter1 =
2191 text_box->highlight_letter2 =
2192 text_box->ibeam_letter = text_box->tstrlen();
2193 text_box->wtext_update();
2195 text_box->handle_event();
2196 //printf("BC_TextBoxSuggestions::handle_event %d\n", __LINE__);
2201 BC_ScrollTextBox::BC_ScrollTextBox(BC_WindowBase *parent_window,
2202 int x, int y, int w, int rows,
2203 const char *default_text, int default_size)
2205 this->parent_window = parent_window;
2210 xscroll = 0; yscroll = 0;
2211 this->default_text = default_text;
2212 this->default_wtext = 0;
2213 this->default_size = default_size;
2216 BC_ScrollTextBox::BC_ScrollTextBox(BC_WindowBase *parent_window,
2217 int x, int y, int w, int rows,
2218 const wchr_t *default_wtext, int default_size)
2220 this->parent_window = parent_window;
2225 xscroll = 0; yscroll = 0;
2226 this->default_text = 0;
2227 this->default_wtext = default_wtext;
2228 this->default_size = default_size;
2231 BC_ScrollTextBox::~BC_ScrollTextBox()
2241 void BC_ScrollTextBox::create_objects()
2243 // Must be created first
2244 parent_window->add_subwindow(text = default_wtext ?
2245 new BC_ScrollTextBoxText(this, default_wtext) :
2246 new BC_ScrollTextBoxText(this, default_text));
2250 void BC_ScrollTextBox::set_text(char *text, int isz)
2252 this->text->set_text(text, isz);
2253 update_scrollbars();
2256 int BC_ScrollTextBox::set_text_row(int n)
2258 text->set_text_row(n);
2259 update_scrollbars();
2263 void BC_ScrollTextBox::update(const char *text)
2265 this->text->update(text);
2266 update_scrollbars();
2269 void BC_ScrollTextBox::update(const wchr_t *wtext)
2271 this->text->update(wtext);
2272 update_scrollbars();
2275 void BC_ScrollTextBox::reposition_window(int x, int y, int w, int rows)
2281 update_scrollbars();
2284 int BC_ScrollTextBox::button_press_event()
2286 return text->BC_TextBox::button_press_event();
2288 int BC_ScrollTextBox::button_release_event()
2290 return text->BC_TextBox::button_release_event();
2293 int BC_ScrollTextBox::get_h() { return text->get_h(); }
2294 const char *BC_ScrollTextBox::get_text() { return text->get_text(); }
2295 const wchr_t *BC_ScrollTextBox::get_wtext() { return text->get_wtext(); }
2297 int BC_ScrollTextBox::get_buttonpress()
2299 return text->BC_TextBox::get_buttonpress();
2301 void BC_ScrollTextBox::wset_selection(int char1, int char2, int ibeam)
2303 text->wset_selection(char1, char2, ibeam);
2305 void BC_ScrollTextBox::set_selection(int char1, int char2, int ibeam)
2307 text->set_selection(char1, char2, ibeam);
2309 int BC_ScrollTextBox::get_ibeam_letter()
2311 return text->get_ibeam_letter();
2313 int BC_ScrollTextBox::get_x_pos()
2315 return text->left_margin - text->get_text_x();
2317 void BC_ScrollTextBox::set_x_pos(int x)
2319 text->set_text_x(text->left_margin - x);
2323 BC_ScrollTextBoxText::BC_ScrollTextBoxText(BC_ScrollTextBox *gui, const char *text)
2324 : BC_TextBox(gui->x, gui->y,
2325 gui->w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
2326 gui->rows, gui->default_size, (char*)text, 1, MEDIUMFONT)
2331 BC_ScrollTextBoxText::BC_ScrollTextBoxText(BC_ScrollTextBox *gui, const wchr_t *wtext)
2332 : BC_TextBox(gui->x, gui->y,
2333 gui->w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
2334 gui->rows, gui->default_size, (wchr_t*)wtext, 1, MEDIUMFONT)
2339 BC_ScrollTextBoxText::~BC_ScrollTextBoxText()
2348 void BC_ScrollTextBox::update_scrollbars()
2350 int view_w = w, view_rows = rows;
2351 int view_h = BC_TextBox::calculate_row_h(view_rows, parent_window);
2352 int text_rows = text->get_text_rows();
2353 int text_width = parent_window->get_text_width(text->font, text->get_wtext());
2354 BC_Resources *resources = parent_window->get_resources();
2355 int need_xscroll = 0, need_yscroll = 0;
2357 // Create scrollbars as needed
2361 if( !need_xscroll && (text->get_text_x() != text->left_margin ||
2362 text_width >= view_w - text->left_margin - text->right_margin) ) {
2363 resize = need_xscroll = 1;
2364 view_h -= resources->hscroll_data[SCROLL_HANDLE_UP]->get_h();
2365 view_rows = BC_TextBox::pixels_to_rows(parent_window, text->font, view_h);
2367 if( !need_yscroll && (text->get_text_y() != text->top_margin ||
2368 text_rows > view_rows) ) {
2369 resize = need_yscroll = 1;
2370 view_w -= resources->vscroll_data[SCROLL_HANDLE_UP]->get_w();
2374 if( !need_xscroll && xscroll ) {
2376 delete xscroll; xscroll = 0;
2378 if( !need_yscroll && yscroll ) {
2380 delete yscroll; yscroll = 0;
2383 if( view_rows != text->get_rows() || view_w != text->get_w() ||
2384 x != text->get_x() || y != text->get_y() ) {
2385 text->reposition_window(x, y, view_w, view_rows);
2387 if( need_xscroll && !xscroll ) {
2388 xscroll = new BC_ScrollTextBoxXScroll(this);
2389 parent_window->add_subwindow(xscroll);
2390 text->xscroll = xscroll;
2391 xscroll->bound_to = text;
2392 xscroll->show_window();
2394 if( need_yscroll && !yscroll ) {
2395 yscroll = new BC_ScrollTextBoxYScroll(this);
2396 parent_window->add_subwindow(yscroll);
2397 text->yscroll = yscroll;
2398 yscroll->bound_to = text;
2399 yscroll->show_window();
2402 xscroll->reposition_window(x, y + text->get_h(), view_w);
2403 int xpos = get_x_pos();
2404 if( xpos != xscroll->get_value() )
2405 xscroll->update_value(xpos);
2406 if( text_width != xscroll->get_length() ||
2407 view_w != xscroll->get_handlelength() )
2408 xscroll->update_length(text_width, xpos, view_w, 0);
2411 yscroll->reposition_window(x + w - yscroll->get_span(), y, text->get_h());
2412 int text_row = text->get_text_row();
2413 if( text_row != yscroll->get_value() )
2414 yscroll->update_value(text_row);
2415 if( text_rows != yscroll->get_length() ||
2416 view_rows != yscroll->get_handlelength() )
2417 yscroll->update_length(text_rows, text_row, view_rows, 0);
2421 int BC_ScrollTextBoxText::handle_event()
2423 gui->update_scrollbars();
2424 return gui->handle_event();
2427 int BC_ScrollTextBoxText::motion_event()
2429 gui->update_scrollbars();
2433 BC_ScrollTextBoxXScroll::BC_ScrollTextBoxXScroll(BC_ScrollTextBox *gui)
2434 : BC_ScrollBar(gui->x, gui->y + gui->text->get_h(), SCROLL_HORIZ + SCROLL_STRETCH,
2435 gui->text->get_w(), gui->text->get_text_width(MEDIUMFONT, gui->get_wtext()),
2441 BC_ScrollTextBoxXScroll::~BC_ScrollTextBoxXScroll()
2445 int BC_ScrollTextBoxXScroll::handle_event()
2447 gui->set_x_pos(get_position());
2451 BC_ScrollTextBoxYScroll::BC_ScrollTextBoxYScroll(BC_ScrollTextBox *gui)
2452 : BC_ScrollBar(gui->x + gui->text->get_w(), gui->y, SCROLL_VERT,
2453 gui->text->get_h(), gui->text->get_text_rows(), 0, gui->rows)
2458 BC_ScrollTextBoxYScroll::~BC_ScrollTextBoxYScroll()
2462 int BC_ScrollTextBoxYScroll::handle_event()
2464 gui->text->set_text_row(get_position());
2470 BC_PopupTextBoxText::BC_PopupTextBoxText(BC_PopupTextBox *popup, int x, int y, const char *text)
2471 : BC_TextBox(x, y, popup->text_w, 1, text, BCTEXTLEN)
2473 this->popup = popup;
2476 BC_PopupTextBoxText::BC_PopupTextBoxText(BC_PopupTextBox *popup, int x, int y, const wchr_t *wtext)
2477 : BC_TextBox(x, y, popup->text_w, 1, wtext, BCTEXTLEN)
2479 this->popup = popup;
2482 BC_PopupTextBoxText::~BC_PopupTextBoxText()
2492 int BC_PopupTextBoxText::handle_event()
2494 popup->list_item = -1;
2495 popup->handle_event();
2499 BC_PopupTextBoxList::BC_PopupTextBoxList(BC_PopupTextBox *popup, int x, int y)
2501 popup->text_w + BC_WindowBase::get_resources()->listbox_button[0]->get_w(),
2502 popup->list_h, popup->list_format, popup->list_items, 0, 0, 1, 0, 1)
2504 this->popup = popup;
2506 int BC_PopupTextBoxList::handle_event()
2508 int k = get_selection_number(0, 0);
2509 popup->list_item = k;
2510 if( k >= 0 && k < popup->list_items->size() ) {
2511 popup->textbox->update(popup->list_items->get(k)->get_text());
2512 popup->textbox->set_text_row(0);
2513 popup->handle_event();
2521 BC_PopupTextBox::BC_PopupTextBox(BC_WindowBase *parent_window,
2522 ArrayList<BC_ListBoxItem*> *list_items,
2523 const char *default_text, int x, int y,
2524 int text_w, int list_h, int list_format)
2528 this->list_h = list_h;
2529 this->list_format = list_format;
2530 this->default_text = (char*)default_text;
2531 this->default_wtext = 0;
2532 this->text_w = text_w;
2533 this->parent_window = parent_window;
2534 this->list_items = list_items;
2537 BC_PopupTextBox::~BC_PopupTextBox()
2547 int BC_PopupTextBox::create_objects()
2549 int x = this->x, y = this->y;
2550 parent_window->add_subwindow(textbox = default_wtext ?
2551 new BC_PopupTextBoxText(this, x, y, default_wtext) :
2552 new BC_PopupTextBoxText(this, x, y, default_text));
2553 x += textbox->get_w();
2554 parent_window->add_subwindow(listbox = new BC_PopupTextBoxList(this, x, y));
2558 void BC_PopupTextBox::update(const char *text)
2560 textbox->update(text);
2561 textbox->set_text_row(0);
2564 void BC_PopupTextBox::update_list(ArrayList<BC_ListBoxItem*> *data)
2567 listbox->update(data, 0, 0, 1);
2570 int BC_PopupTextBox::handle_event()
2575 const char *BC_PopupTextBox::get_text() { return textbox->get_text(); }
2576 const wchr_t *BC_PopupTextBox::get_wtext() { return textbox->get_wtext(); }
2577 int BC_PopupTextBox::get_number() { return list_item; }
2578 void BC_PopupTextBox::set_number(int v) { list_item = v; }
2579 int BC_PopupTextBox::get_x() { return x; }
2580 int BC_PopupTextBox::get_y() { return y; }
2581 int BC_PopupTextBox::get_w() { return textbox->get_w() + listbox->get_w(); }
2582 int BC_PopupTextBox::get_h() { return textbox->get_h(); }
2583 int BC_PopupTextBox::get_show_query() { return listbox->get_show_query(); }
2584 void BC_PopupTextBox::set_show_query(int v) { listbox->set_show_query(v); }
2585 int BC_PopupTextBox::get_back_color() { return textbox->get_back_color(); }
2586 void BC_PopupTextBox::set_back_color(int v) { textbox->set_back_color(v); }
2588 void BC_PopupTextBox::set_tooltip(const char *text)
2590 listbox->set_tooltip(text);
2593 void BC_PopupTextBox::reposition_window(int x, int y)
2598 textbox->reposition_window(x1,
2601 textbox->get_rows());
2602 x1 += textbox->get_w();
2603 listbox->reposition_window(x1, y1, -1, -1, 0);
2604 // if(flush) parent_window->flush();
2608 BC_TumbleTextBoxText::BC_TumbleTextBoxText(BC_TumbleTextBox *popup,
2609 int64_t default_value, int x, int y)
2610 : BC_TextBox(x, y, popup->text_w, 1, default_value)
2612 this->popup = popup;
2615 BC_TumbleTextBoxText::BC_TumbleTextBoxText(BC_TumbleTextBox *popup,
2616 float default_value, int x, int y, int precision)
2617 : BC_TextBox(x, y, popup->text_w, 1, default_value, 1, MEDIUMFONT, precision)
2619 this->popup = popup;
2622 BC_TumbleTextBoxText::~BC_TumbleTextBoxText()
2634 int BC_TumbleTextBoxText::handle_event()
2636 popup->handle_event();
2640 int BC_TumbleTextBoxText::button_press_event()
2642 if( get_enabled() && is_event_win() ) {
2643 if( get_buttonpress() < 4 ) return BC_TextBox::button_press_event();
2644 if( get_buttonpress() == 4 ) popup->tumbler->handle_up_event();
2645 else if( get_buttonpress() == 5 ) popup->tumbler->handle_down_event();
2653 BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window,
2654 int64_t default_value, int64_t min, int64_t max,
2655 int x, int y, int text_w)
2662 this->default_value = default_value;
2663 this->text_w = text_w;
2664 this->parent_window = parent_window;
2670 BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window,
2671 int default_value, int min, int max,
2672 int x, int y, int text_w)
2679 this->default_value = default_value;
2680 this->text_w = text_w;
2681 this->parent_window = parent_window;
2687 BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window,
2688 float default_value_f, float min_f, float max_f,
2689 int x, int y, int text_w, int precision)
2694 this->min_f = min_f;
2695 this->max_f = max_f;
2696 this->default_value_f = default_value_f;
2697 this->text_w = text_w;
2698 this->precision = precision;
2699 this->parent_window = parent_window;
2704 BC_TumbleTextBox::~BC_TumbleTextBox()
2706 // Recursive delete. Normally ~BC_TumbleTextBox is never called but textbox
2707 // is deleted anyway by the windowbase so textbox deletes this.
2708 if(tumbler) delete tumbler;
2710 // Don't delete text here if we were called by ~BC_TumbleTextBoxText
2719 void BC_TumbleTextBox::reset()
2726 void BC_TumbleTextBox::set_precision(int precision)
2728 this->precision = precision;
2731 void BC_TumbleTextBox::set_increment(float value)
2733 this->increment = value;
2734 if(tumbler) tumbler->set_increment(value);
2737 void BC_TumbleTextBox::set_log_floatincrement(int value)
2739 this->log_floatincrement = value;
2740 if(tumbler) tumbler->set_log_floatincrement(value);
2743 int BC_TumbleTextBox::create_objects()
2745 int x = this->x, y = this->y;
2747 textbox = use_float ?
2748 new BC_TumbleTextBoxText(this, default_value_f, x, y, precision) :
2749 new BC_TumbleTextBoxText(this, default_value, x, y);
2751 parent_window->add_subwindow(textbox);
2752 x += textbox->get_w();
2754 tumbler = use_float ?
2755 (BC_Tumbler *)new BC_FTextTumbler(this, min_f, max_f, x, y) :
2756 (BC_Tumbler *)new BC_ITextTumbler(this, min, max, x, y);
2757 parent_window->add_subwindow(tumbler);
2758 tumbler->set_increment(increment);
2762 int BC_TumbleTextBox::handle_up_event()
2765 ((BC_FTumbler *)tumbler)->BC_FTumbler::handle_up_event() :
2766 ((BC_ITumbler *)tumbler)->BC_ITumbler::handle_up_event() ;
2769 int BC_TumbleTextBox::handle_down_event()
2772 ((BC_FTumbler *)tumbler)->BC_FTumbler::handle_down_event() :
2773 ((BC_ITumbler *)tumbler)->BC_ITumbler::handle_down_event() ;
2776 const char* BC_TumbleTextBox::get_text()
2778 return textbox->get_text();
2781 const wchr_t* BC_TumbleTextBox::get_wtext()
2783 return textbox->get_wtext();
2786 BC_TextBox* BC_TumbleTextBox::get_textbox()
2791 int BC_TumbleTextBox::update(const char *value)
2793 textbox->update(value);
2794 textbox->set_text_row(0);
2798 int BC_TumbleTextBox::update(int64_t value)
2800 textbox->update(value);
2801 textbox->set_text_row(0);
2805 int BC_TumbleTextBox::update(float value)
2807 textbox->update(value);
2808 textbox->set_text_row(0);
2813 int BC_TumbleTextBox::get_x()
2818 int BC_TumbleTextBox::get_y()
2823 int BC_TumbleTextBox::get_w()
2825 return textbox->get_w() + tumbler->get_w();
2828 int BC_TumbleTextBox::get_h()
2830 return textbox->get_h();
2833 void BC_TumbleTextBox::disable(int hide_text)
2835 if( hide_text && !textbox->is_hidden() )
2836 textbox->hide_window(0);
2837 if( !tumbler->is_hidden() )
2838 tumbler->hide_window(0);
2839 if( !get_enabled() ) return;
2840 return textbox->disable();
2843 void BC_TumbleTextBox::enable()
2845 if( textbox->is_hidden() )
2846 textbox->show_window(0);
2847 if( tumbler->is_hidden() )
2848 tumbler->show_window(0);
2849 if( get_enabled() ) return;
2850 return textbox->enable();
2853 int BC_TumbleTextBox::get_enabled()
2855 return textbox->get_enabled();
2858 int BC_TumbleTextBox::handle_event()
2863 void BC_TumbleTextBox::reposition_window(int x, int y)
2868 textbox->reposition_window(x, y, text_w, 1);
2869 tumbler->reposition_window(x + textbox->get_w(), y);
2870 // if(flush) parent_window->flush();
2874 void BC_TumbleTextBox::set_boundaries(int64_t min, int64_t max)
2876 tumbler->set_boundaries(min, max);
2879 void BC_TumbleTextBox::set_boundaries(float min, float max)
2881 tumbler->set_boundaries(min, max);
2886 BC_TextMenu::BC_TextMenu(BC_TextBox *textbox)
2887 : BC_PopupMenu(0, 0, 0, "", 0)
2889 this->textbox = textbox;
2892 BC_TextMenu::~BC_TextMenu()
2896 void BC_TextMenu::create_objects()
2898 add_item(new BC_TextMenuCut(this));
2899 add_item(new BC_TextMenuCopy(this));
2900 add_item(new BC_TextMenuPaste(this));
2904 BC_TextMenuCut::BC_TextMenuCut(BC_TextMenu *menu)
2905 : BC_MenuItem(_("Cut"))
2910 int BC_TextMenuCut::handle_event()
2912 menu->textbox->cut(1);
2918 BC_TextMenuCopy::BC_TextMenuCopy(BC_TextMenu *menu)
2919 : BC_MenuItem(_("Copy"))
2924 int BC_TextMenuCopy::handle_event()
2926 menu->textbox->copy(1);
2931 BC_TextMenuPaste::BC_TextMenuPaste(BC_TextMenu *menu)
2932 : BC_MenuItem(_("Paste"))
2937 int BC_TextMenuPaste::handle_event()
2939 menu->textbox->paste(1);
2944 void BC_TumbleTextBox::set_tooltip(const char *text)
2946 textbox->set_tooltip(text);