r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / guicast / bctextbox.C
blob66b461f474cec9fa6608d75d2c2a6ab0b4fb9acd
1 #include "bcclipboard.h"
2 #include "bclistboxitem.h"
3 #include "bcresources.h"
4 #include "bctextbox.h"
5 #include "colors.h"
6 #include <ctype.h>
7 #include "cursors.h"
8 #include "keys.h"
9 #include "vframe.h"
11 #include <string.h>
13 BC_TextBox::BC_TextBox(int x, int y, int w, int rows, char *text, int has_border, int font)
14  : BC_SubWindow(x, y, w, 0, -1)
16         reset_parameters(rows, has_border, font);
17         strcpy(this->text, text);
20 BC_TextBox::BC_TextBox(int x, int y, int w, int rows, int64_t text, int has_border, int font)
21  : BC_SubWindow(x, y, w, 0, -1)
23         reset_parameters(rows, has_border, font);
24         sprintf(this->text, "%lld", text);
27 BC_TextBox::BC_TextBox(int x, int y, int w, int rows, float text, int has_border, int font)
28  : BC_SubWindow(x, y, w, 0, -1)
30         reset_parameters(rows, has_border, font);
31         sprintf(this->text, "%0.4f", text);
34 BC_TextBox::BC_TextBox(int x, int y, int w, int rows, int text, int has_border, int font)
35  : BC_SubWindow(x, y, w, 0, -1)
37         reset_parameters(rows, has_border, font);
38         sprintf(this->text, "%d", text);
41 BC_TextBox::~BC_TextBox()
45 int BC_TextBox::reset_parameters(int rows, int has_border, int font)
47         this->rows = rows;
48         this->has_border = has_border;
49         this->font = font;
50         text_start = 0;
51         text_end = 0;
52         highlight_letter1 = highlight_letter2 = 0;
53         highlight_letter3 = highlight_letter4 = 0;
54         ibeam_letter = 0;
55         active = 0;
56         text_selected = word_selected = 0;
57         text_x = 0;
58         enabled = 1;
59         highlighted = 0;
60         precision = 4;
61         return 0;
64 int BC_TextBox::initialize()
66 // Get dimensions
67         text_ascent = get_text_ascent(font) + 1;
68         text_descent = get_text_descent(font) + 1;
69         text_height = text_ascent + text_descent;
70         ibeam_letter = strlen(text);
71         if(has_border)
72         { 
73                 left_margin = right_margin = 4;
74                 top_margin = bottom_margin = 2;
75         }
76         else 
77         { 
78                 left_margin = right_margin = 2;
79                 top_margin = bottom_margin = 0;
80         }
81         h = get_row_h(rows);
82         text_x = left_margin;
83         text_y = top_margin;
84         find_ibeam(0);
86 // Create the subwindow
87         BC_SubWindow::initialize();
89         if(has_border)
90         {
91                 back_color = WHITE;
92                 high_color = LTYELLOW;
93         }
94         else 
95         {
96                 high_color = LTGREY;
97                 back_color = bg_color;
98         }
100         draw();
101         set_cursor(IBEAM_CURSOR);
102         return 0;
105 void BC_TextBox::set_precision(int precision)
107         this->precision = precision;
110 int BC_TextBox::update(char *text)
112 //printf("BC_TextBox::update 1 %d %s %s\n", strcmp(text, this->text), text, this->text);
113         int text_len = strlen(text);
114 // Don't update if contents are the same
115         if(!strcmp(text, this->text)) return 0;
117         strcpy(this->text, text);
118         if(highlight_letter1 > text_len) highlight_letter1 = text_len;
119         if(highlight_letter2 > text_len) highlight_letter2 = text_len;
120         ibeam_letter = text_len;
121         draw();
122         return 0;
125 int BC_TextBox::update(int64_t value)
127         char string[BCTEXTLEN];
128         sprintf(string, "%lld", value);
131         update(string);
132         return 0;
135 int BC_TextBox::update(float value)
137         char string[BCTEXTLEN];
138         sprintf(string, "%f", value);
139         char *ptr = strchr(string, '.');
141 //printf("BC_TextBox::update 1 %d\n", precision);
142         if(ptr) ptr[precision + 1] = 0;
144         update(string);
145         return 0;
148 void BC_TextBox::disable()
150         if(enabled)
151         {
152                 enabled = 0;
153                 if(active) top_level->deactivate();
154                 draw();
155         }
158 void BC_TextBox::enable()
160         if(!enabled)
161         {
162                 enabled = 1;
163                 draw();
164         }
167 int BC_TextBox::pixels_to_rows(BC_WindowBase *window, int font, int pixels)
169         return (pixels - 4) / 
170                 (window->get_text_ascent(font) + 1 + 
171                         window->get_text_descent(font) + 1);
174 int BC_TextBox::calculate_row_h(int rows, 
175         BC_WindowBase *parent_window, 
176         int has_border, 
177         int font)
179         return rows * 
180                 (parent_window->get_text_ascent(font) + 1 + 
181                 parent_window->get_text_descent(font) + 1) +
182                 (has_border ? 4 : 0);
185 char* BC_TextBox::get_text()
187         return text;
190 int BC_TextBox::get_text_rows()
192         int text_len = strlen(text);
193         int result = 1;
194         for(int i = 0; i < text_len; i++)
195         {
196                 if(text[i] == 0xa) result++;
197         }
198         return result;
202 int BC_TextBox::get_row_h(int rows)
204         return rows * text_height + top_margin + bottom_margin;
207 int BC_TextBox::reposition_window(int x, int y, int w, int rows)
209         int new_h = get_h();
210         if(rows != -1)
211         {
212                 new_h = get_row_h(rows);
213                 this->rows = rows;
214         }
215         BC_WindowBase::reposition_window(x, y, w, new_h);
216         draw();
217         return 0;
220 void BC_TextBox::draw_border()
222 // Clear margins
223         set_color(background_color);
224         draw_box(0, 0, left_margin, get_h());
225         draw_box(get_w() - right_margin, 0, right_margin, get_h());
227         if(has_border)
228         {
229                 if(highlighted)
230                         draw_3d_border(0, 0, w, h,
231                                 top_level->get_resources()->button_shadow, 
232                                 RED, 
233                                 LTPINK,
234                                 top_level->get_resources()->button_light);
235                 else
236                         draw_3d_border(0, 0, w, h, 
237                                 top_level->get_resources()->button_shadow, 
238                                 BLACK, 
239                                 top_level->get_resources()->button_up,
240                                 top_level->get_resources()->button_light);
241         }
244 void BC_TextBox::draw_cursor()
246         set_color(background_color);
247         set_inverse();
248         draw_box(ibeam_x, ibeam_y, BCCURSORW, text_height);
249         set_opaque();
253 void BC_TextBox::draw()
255         int i, j, k, text_len;
256         int row_begin, row_end;
257         int highlight_x1, highlight_x2;
258         int need_ibeam = 1;
260 // Background
261         if(has_border)
262         {
263                 background_color = WHITE;
264         }
265         else
266         {
267                 if(highlighted)
268                 {
269                         background_color = high_color;
270                 }
271                 else
272                 {
273                         background_color = back_color;
274                 }
275         }
277         set_color(background_color);
278         draw_box(0, 0, w, h);
280 // Draw text with selection
281         set_font(font);
282         text_len = strlen(text);
283 //printf("BC_TextBox::draw 0 %s %d %d %d %d\n", text, text_y, text_len, get_w(), text_height);
285         for(i = 0, k = text_y; i < text_len && k < get_h(); k += text_height)
286         {
287 // Draw row of text
288                 if(text[i] == '\n') i++;
289                 row_begin = i;
290                 for(j = 0; text[i] != '\n' && i < text_len; j++, i++)
291                 {
292                         text_row[j] = text[i];
293                 }
294                 row_end = i;
295                 text_row[j] = 0;
297 //printf("BC_TextBox::draw 1 %d %d %c\n", row_begin, row_end, text_row[j - 1]);
299                 if(k > -text_height + top_margin && k < get_h() - bottom_margin)
300                 {
301 // Draw highlighted region of row
302                         if(highlight_letter2 > highlight_letter1 &&
303                                 highlight_letter2 > row_begin && highlight_letter1 < row_end)
304                         {
305                                 if(active && enabled)
306                                         set_color(top_level->get_resources()->text_highlight);
307                                 else
308                                         set_color(MEGREY);
310                                 if(highlight_letter1 >= row_begin && highlight_letter1 < row_end)
311                                         highlight_x1 = get_text_width(font, text_row, highlight_letter1 - row_begin);
312                                 else
313                                         highlight_x1 = 0;
315                                 if(highlight_letter2 > row_begin && highlight_letter2 <= row_end)
316                                         highlight_x2 = get_text_width(font, text_row, highlight_letter2 - row_begin);
317                                 else
318                                         highlight_x2 = get_w();
320                                 draw_box(highlight_x1 + text_x, 
321                                         k, 
322                                         highlight_x2 - highlight_x1, 
323                                         text_height);
324                         }
326 // Draw text over highlight
327                         if(enabled)
328                                 set_color(BLACK);
329                         else
330                                 set_color(MEGREY);
332                         draw_text(text_x, k + text_ascent, text_row);
333 // Get ibeam location
334                         if(ibeam_letter >= row_begin && ibeam_letter <= row_end)
335                         {
336 //printf("BC_TextBox::draw 2 %d %d %d\n", row_begin, row_end, ibeam_letter);
337                                 need_ibeam = 0;
338                                 ibeam_y = k;
339                                 ibeam_x = text_x + get_text_width(font, text_row, ibeam_letter - row_begin);
340                         }
341                 }
342         }
344 //printf("BC_TextBox::draw 3 %d\n", ibeam_y);
345         if(need_ibeam)
346         {
347                 ibeam_x = text_x;
348                 ibeam_y = text_y;
349         }
351 //printf("BC_TextBox::draw 4 %d\n", ibeam_y);
352 // Draw solid cursor
353         if(!active)
354         {
355                 draw_cursor();
356         }
358 // Border
359         draw_border();
360         flash();
363 int BC_TextBox::cursor_enter_event()
365         if(top_level->event_win == win)
366         {
367                 if(!highlighted)
368                 {
369                         highlighted = 1;
370                         draw_border();
371                         flash();
372                 }
373         }
374         return 0;
377 int BC_TextBox::cursor_leave_event()
379         if(highlighted)
380         {
381                 highlighted = 0;
382                 draw_border();
383                 flash();
384         }
385         return 0;
388 int BC_TextBox::button_press_event()
390         if(get_buttonpress() > 2) return 0;
392         int cursor_letter = 0;
393         int text_len = strlen(text);
395         if(!enabled) return 0;
397         if(top_level->event_win == win)
398         {
399                 if(!active)
400                 {
401                         top_level->deactivate();
402                         activate();
403                 }
405                 cursor_letter = get_cursor_letter(top_level->cursor_x, top_level->cursor_y);
406                 if(get_double_click())
407                 {
408                         word_selected = 1;
409                         select_word(highlight_letter1, highlight_letter2, cursor_letter);
410                         highlight_letter3 = highlight_letter1;
411                         highlight_letter4 = highlight_letter2;
412                         ibeam_letter = highlight_letter2;
413                         copy_selection(PRIMARY_SELECTION);
414                 }
415                 else
416                 if(get_buttonpress() == 2)
417                 {
418                         highlight_letter3 = highlight_letter4 = 
419                                 ibeam_letter = highlight_letter1 = 
420                                 highlight_letter2 = cursor_letter;
421                         paste_selection(PRIMARY_SELECTION);
422                 }
423                 else
424                 {
425                         text_selected = 1;
426                         highlight_letter3 = highlight_letter4 = 
427                                 ibeam_letter = highlight_letter1 = 
428                                 highlight_letter2 = cursor_letter;
429                 }
430                 
431                 if(ibeam_letter < 0) ibeam_letter = 0;
432                 if(ibeam_letter > text_len) ibeam_letter = text_len;
433                 draw();
434                 return 1;
435         }
436         else
437         if(active)
438         {
439                 top_level->deactivate();
440         }
442         return 0;
445 int BC_TextBox::button_release_event()
447         if(active)
448         {
449                 if(text_selected || word_selected)
450                 {
451                         text_selected = 0;
452                         word_selected = 0;
453                 }
454         }
455         return 0;
458 int BC_TextBox::cursor_motion_event()
460         int cursor_letter, text_len = strlen(text), letter1, letter2;
461         if(active)
462         {
463                 if(text_selected || word_selected)
464                 {
465                         cursor_letter = get_cursor_letter(top_level->cursor_x, top_level->cursor_y);
466                         if(word_selected)
467                         {
468                                 select_word(letter1, letter2, cursor_letter);
469                         }
470                         else
471                         if(text_selected)
472                         {
473                                 letter1 = letter2 = cursor_letter;
474                         }
476                         if(letter1 <= highlight_letter3)
477                         {
478                                 highlight_letter1 = letter1;
479                                 highlight_letter2 = highlight_letter4;
480                                 ibeam_letter = letter1;
481                         }
482                         else
483                         if(letter2 >= highlight_letter4)
484                         {
485                                 highlight_letter2 = letter2;
486                                 highlight_letter1 = highlight_letter3;
487                                 ibeam_letter = letter2;
488                         }
489                         
490                         copy_selection(PRIMARY_SELECTION);
491                         find_ibeam(1);
492                         draw();
493                         return 1;
494                 }
495         }
496         return 0;
499 int BC_TextBox::activate()
501         top_level->active_subwindow = this;
502         active = 1;
503         draw();
504         top_level->set_repeat(top_level->get_resources()->blink_rate);
505         return 0;
508 int BC_TextBox::deactivate()
510         active = 0;
511         top_level->unset_repeat(top_level->get_resources()->blink_rate);
512         draw();
513         return 0;
516 int BC_TextBox::repeat_event(int64_t duration)
518         if(duration == top_level->get_resources()->blink_rate && 
519                 active)
520         {
521                 draw_cursor();
522                 flash();
523                 return 1;
524         }
525         return 0;
528 void BC_TextBox::default_keypress(int &dispatch_event, int &result)
530     if((top_level->get_keypress() == RETURN) ||
531 //              (top_level->get_keypress() > 30 && top_level->get_keypress() < 127))
532                 (top_level->get_keypress() > 30 && top_level->get_keypress() <= 255))
533         {
534 // Substitute UNIX linefeed
535                 if(top_level->get_keypress() == RETURN) 
536                         temp_string[0] = 0xa;
537                 else
538                         temp_string[0] = top_level->get_keypress();
539                 temp_string[1] = 0;
540                 insert_text(temp_string);
541                 find_ibeam(1);
542                 draw();
543                 dispatch_event = 1;
544                 result = 1;
545         }
548 int BC_TextBox::keypress_event()
550 // Result == 2 contents changed
551 // Result == 1 trapped keypress
552 // Result == 0 nothing
553         int result = 0;
554         int text_len;
555         int dispatch_event = 0;
557         if(!active || !enabled) return 0;
559         text_len = strlen(text);
560         switch(top_level->get_keypress())
561         {
562                 case ESC:
563                         top_level->deactivate();
564                         result = 0;
565                         break;
567                 case RETURN:
568                         if(rows == 1)
569                         {
570                                 top_level->deactivate();
571                                 dispatch_event = 1;
572                                 result = 0;
573                         }
574                         else
575                         {
576                                 default_keypress(dispatch_event, result);
577                         }
578                         break;
579 // Handle like a default keypress
581                 case TAB:
582                         top_level->cycle_textboxes(1);
583                         result = 1;
584                         break;
586                 case LEFTTAB:
587                         top_level->cycle_textboxes(-1);
588                         result = 1;
589                         break;
591                 case LEFT:
592                         if(ibeam_letter > 0)
593                         {
594 // Extend selection
595                                 if(top_level->shift_down())
596                                 {
597 // Initialize highlighting
598                                         if(highlight_letter1 == highlight_letter2)
599                                         {
600                                                 highlight_letter1 = ibeam_letter - 1;
601                                                 highlight_letter2 = ibeam_letter;
602                                         }
603                                         else
604 // Extend left highlight
605                                         if(highlight_letter1 == ibeam_letter)
606                                         {
607                                                 highlight_letter1--;
608                                         }
609                                         else
610 // Shrink right highlight
611                                         if(highlight_letter2 == ibeam_letter)
612                                         {
613                                                 highlight_letter2--;
614                                         }
615                                 }
616                                 else
617                                         highlight_letter1 = highlight_letter2;
619                                 ibeam_letter--;
621                                 find_ibeam(1);
622                                 draw();
623                         }
624                         result = 1;
625                         break;
627                 case RIGHT:
628                         if(ibeam_letter < text_len)
629                         {
630 // Extend selection
631                                 if(top_level->shift_down())
632                                 {
633 // Initialize highlighting
634                                         if(highlight_letter1 == highlight_letter2)
635                                         {
636                                                 highlight_letter1 = ibeam_letter;
637                                                 highlight_letter2 = ibeam_letter + 1;
638                                         }
639                                         else
640 // Shrink left highlight
641                                         if(highlight_letter1 == ibeam_letter)
642                                         {
643                                                 highlight_letter1++;
644                                         }
645                                         else
646 // Expand right highlight
647                                         if(highlight_letter2 == ibeam_letter)
648                                         {
649                                                 highlight_letter2++;
650                                         }
651                                 }
652                                 else
653                                         highlight_letter1 = highlight_letter2;
655                                 ibeam_letter++;
657                                 find_ibeam(1);
658                                 draw();
659                         }
660                         result = 1;
661                         break;
663                 case UP:
664                         if(ibeam_letter > 0)
665                         {
666 // Extend selection
667                                 int new_letter = get_cursor_letter(ibeam_x, ibeam_y - text_height);
668 //printf("BC_TextBox::keypress_event %d\n", new_letter);
670                                 if(top_level->shift_down())
671                                 {
672 // Initialize highlighting
673                                         if(highlight_letter1 == highlight_letter2)
674                                         {
675                                                 highlight_letter1 = new_letter;
676                                                 highlight_letter2 = ibeam_letter;
677                                         }
678                                         else
679 // Expand left highlight
680                                         if(highlight_letter1 == ibeam_letter)
681                                         {
682                                                 highlight_letter1 = new_letter;
683                                         }
684                                         else
685 // Shrink right highlight
686                                         if(highlight_letter2 == ibeam_letter)
687                                         {
688                                                 highlight_letter2 = new_letter;
689                                         }
690                                 }
691                                 else
692                                         highlight_letter1 = highlight_letter2 = new_letter;
694                                 if(highlight_letter1 > highlight_letter2)
695                                 {
696                                         int temp = highlight_letter1;
697                                         highlight_letter1 = highlight_letter2;
698                                         highlight_letter2 = temp;
699                                 }
700                                 ibeam_letter = new_letter;
702                                 find_ibeam(1);
703                                 draw();
704                         }
705                         result = 1;
706                         break;
708                 case DOWN:
709 //                      if(ibeam_letter > 0)
710                         {
711 // Extend selection
712                                 int new_letter = get_cursor_letter(ibeam_x, ibeam_y + text_height);
713 //printf("BC_TextBox::keypress_event %d\n", new_letter);
715                                 if(top_level->shift_down())
716                                 {
717 // Initialize highlighting
718                                         if(highlight_letter1 == highlight_letter2)
719                                         {
720                                                 highlight_letter1 = new_letter;
721                                                 highlight_letter2 = ibeam_letter;
722                                         }
723                                         else
724 // Shrink left highlight
725                                         if(highlight_letter1 == ibeam_letter)
726                                         {
727                                                 highlight_letter1 = new_letter;
728                                         }
729                                         else
730 // Expand right highlight
731                                         if(highlight_letter2 == ibeam_letter)
732                                         {
733                                                 highlight_letter2 = new_letter;
734                                         }
735                                 }
736                                 else
737                                         highlight_letter1 = highlight_letter2 = new_letter;
739                                 if(highlight_letter1 > highlight_letter2)
740                                 {
741                                         int temp = highlight_letter1;
742                                         highlight_letter1 = highlight_letter2;
743                                         highlight_letter2 = temp;
744                                 }
745                                 ibeam_letter = new_letter;
747                                 find_ibeam(1);
748                                 draw();
749                         }
750                         result = 1;
751                         break;
752                 
753                 case END:
754                         if(top_level->shift_down())
755                         {
756                                 if(highlight_letter1 == highlight_letter2)
757                                 {
758                                         highlight_letter2 = text_len;
759                                         highlight_letter1 = ibeam_letter;
760                                 }
761                                 else
762                                 if(highlight_letter1 == ibeam_letter)
763                                 {
764                                         highlight_letter1 = highlight_letter2;
765                                         highlight_letter2 = text_len;
766                                 }
767                                 else
768                                 if(highlight_letter2 == ibeam_letter)
769                                 {
770                                         highlight_letter2 = text_len;
771                                 }
772                         }
773                         else
774                                 highlight_letter1 = highlight_letter2;
776                         ibeam_letter = text_len;
777                         find_ibeam(1);
778                         draw();
779                         result = 1;
780                         break;
781                 
782                 case HOME:
783                         if(top_level->shift_down())
784                         {
785                                 if(highlight_letter1 == highlight_letter2)
786                                 {
787                                         highlight_letter2 = ibeam_letter;
788                                         highlight_letter1 = 0;
789                                 }
790                                 else
791                                 if(highlight_letter1 == ibeam_letter)
792                                 {
793                                         highlight_letter1 = 0;
794                                 }
795                                 else
796                                 if(highlight_letter2 == ibeam_letter)
797                                 {
798                                         highlight_letter2 = highlight_letter1;
799                                         highlight_letter1 = 0;
800                                 }
801                         }
802                         else
803                                 highlight_letter1 = highlight_letter2;
805                         ibeam_letter = 0;
806                         find_ibeam(1);
807                         draw();
808                         result = 1;
809                         break;
811         case BACKSPACE:
812                         if(highlight_letter1 == highlight_letter2)
813                         {
814                                 if(ibeam_letter > 0)
815                                 {
816                                         delete_selection(ibeam_letter - 1, ibeam_letter, text_len);
817                                         ibeam_letter--;
818                                 }
819                         }
820                         else
821                         {
822                                 delete_selection(highlight_letter1, highlight_letter2, text_len);
823                                 highlight_letter2 = ibeam_letter = highlight_letter1;
824                         }
826                         find_ibeam(1);
827                         draw();
828                         dispatch_event = 1;
829                         result = 1;
830                 break;
832                 case DELETE:
833                         if(highlight_letter1 == highlight_letter2)
834                         {
835                                 if(ibeam_letter < text_len)
836                                 {
837                                         delete_selection(ibeam_letter, ibeam_letter + 1, text_len);
838                                 }
839                         }
840                         else
841                         {
842                                 delete_selection(highlight_letter1, highlight_letter2, text_len);
843                                 highlight_letter2 = ibeam_letter = highlight_letter1;
844                         }
845                         
846                         find_ibeam(1);
847                         draw();
848                         dispatch_event = 1;
849                         result = 1;
850                         break;
854                 default:
855                         if(ctrl_down())
856                         {
857                                 if(get_keypress() == 'c' || get_keypress() == 'C')
858                                 {
859                                         if(highlight_letter1 != highlight_letter2)
860                                         {
861                                                 copy_selection(SECONDARY_SELECTION);
862                                                 result = 1;
863                                         }
864                                 }
865                                 else
866                                 if(get_keypress() == 'v' || get_keypress() == 'V')
867                                 {
868                                         paste_selection(SECONDARY_SELECTION);
869                                         find_ibeam(1);
870                                         draw();
871                                         dispatch_event = 1;
872                                         result = 1;
873                                 }
874                                 else
875                                 if(get_keypress() == 'x' || get_keypress() == 'X')
876                                 {
877                                         if(highlight_letter1 != highlight_letter2)
878                                         {
879                                                 copy_selection(SECONDARY_SELECTION);
880                                                 delete_selection(highlight_letter1, highlight_letter2, text_len);
881                                                 highlight_letter2 = ibeam_letter = highlight_letter1;
882                                         }
884                                         find_ibeam(1);
885                                         draw();
886                                         dispatch_event = 1;
887                                         result = 1;
888                                 }
889                                 
890                                 break;
891                         }
893                         default_keypress(dispatch_event, result);
894                         break;
895         }
897         if(dispatch_event) handle_event();
898         return result;
903 int BC_TextBox::uses_text()
905         return 1;
908 void BC_TextBox::delete_selection(int letter1, int letter2, int text_len)
910         int i, j;
911         
912         for(i = letter1, j = letter2; j < text_len; i++, j++)
913         {
914                 text[i] = text[j];
915         }
916         text[i] = 0;
919 void BC_TextBox::insert_text(char *string)
921         int i, j, text_len, string_len;
923         string_len = strlen(string);
924         text_len = strlen(text);
925         if(highlight_letter1 < highlight_letter2)
926         {
927                 delete_selection(highlight_letter1, highlight_letter2, text_len);
928                 highlight_letter2 = ibeam_letter = highlight_letter1;
929         }
931         text_len = strlen(text);
933         for(i = text_len, j = text_len + string_len; i >= ibeam_letter; i--, j--)
934                 text[j] = text[i];
936         for(i = ibeam_letter, j = 0; j < string_len; j++, i++)
937                 text[i] = string[j];
939         ibeam_letter += string_len;
942 void BC_TextBox::get_ibeam_position(int &x, int &y)
944         int i, j, k, row_begin, row_end, text_len;
946         text_len = strlen(text);
947         for(i = 0, k = 0; i < text_len; k += text_height)
948         {
949                 row_begin = i;
950                 for(j = 0; text[i] != '\n' && i < text_len; j++, i++)
951                 {
952                         text_row[j] = text[i];
953                 }
955                 row_end = i;
956                 text_row[j] = 0;
958                 if(ibeam_letter >= row_begin && ibeam_letter <= row_end)
959                 {
960                         x = get_text_width(font, text_row, ibeam_letter - row_begin);
961                         y = k;
962                         return;
963                 }
964                 if(text[i] == '\n') i++;
965         }
967         x = 0;
968         y = 0;
969         return;
972 void BC_TextBox::set_text_row(int row)
974         text_y = -(row * text_height) + top_margin;
975         draw();
978 int BC_TextBox::get_text_row()
980         return -(text_y - top_margin) / text_height;
983 void BC_TextBox::find_ibeam(int dispatch_event)
985         int x, y;
986         int old_x = text_x, old_y = text_y;
988         get_ibeam_position(x, y);
989         if(left_margin + text_x + x >= get_w() - right_margin - BCCURSORW)
990         {
991                 text_x = -(x - (get_w() - get_w() / 4)) + left_margin;
992                 if(text_x > left_margin) text_x = left_margin;
993         }
994         else
995         if(left_margin + text_x + x < left_margin)
996         {
997                 text_x = -(x - (get_w() / 4)) + left_margin;
998                 if(text_x > left_margin) text_x = left_margin;
999         }
1001         if((y >= get_h() - text_height - bottom_margin) || 
1002                 (y < top_margin))
1003         {
1004                 text_y = -(y - (get_h() / 2)) + top_margin;
1005                 if(text_y > top_margin) text_y = top_margin;
1006         }
1008         if(dispatch_event && (old_x != text_x || old_y != text_y)) motion_event();
1011 int BC_TextBox::get_cursor_letter(int cursor_x, int cursor_y)
1013         int i, j, k, l, row_begin, row_end, text_len, result = 0, done = 0;
1014         text_len = strlen(text);
1016         if(cursor_y < 0) 
1017         {
1018                 result = 0;
1019                 done = 1;
1020         }
1022         for(i = 0, k = text_y; i < text_len && !done; k += text_height)
1023         {
1024                 row_begin = i;
1025                 for(j = 0; text[i] != '\n' && i < text_len; j++, i++)
1026                 {
1027                         text_row[j] = text[i];
1028                 }
1029                 row_end = i;
1030                 text_row[j] = 0;
1032                 if(cursor_y >= k && cursor_y < k + text_height)
1033                 {
1034                         for(j = 0; j <= row_end - row_begin && !done; j++)
1035                         {
1036                                 l = get_text_width(font, text_row, j) + text_x;
1037                                 if(l > cursor_x)
1038                                 {
1039                                         result = row_begin + j - 1;
1040                                         done = 1;
1041                                 }
1042                         }
1043                         if(!done)
1044                         {
1045                                 result = row_end;
1046                                 done = 1;
1047                         }
1048                 }
1049                 if(text[i] == '\n') i++;
1050                 
1051                 if(i >= text_len && !done)
1052                 {
1053                         result = text_len;
1054                 }
1055         }
1056         if(result < 0) result = 0;
1057         if(result > text_len) result = text_len;
1058         return result;
1061 void BC_TextBox::select_word(int &letter1, int &letter2, int ibeam_letter)
1063         int text_len = strlen(text);
1064         letter1 = letter2 = ibeam_letter;
1065         do
1066         {
1067                 if(isalnum(text[letter1])) letter1--;
1068         }while(letter1 > 0 && isalnum(text[letter1]));
1069         if(!isalnum(text[letter1])) letter1++;
1071         do
1072         {
1073                 if(isalnum(text[letter2])) letter2++;
1074         }while(letter2 < text_len && isalnum(text[letter2]));
1075         if(letter2 < text_len && text[letter2] == ' ') letter2++;
1077         if(letter1 < 0) letter1 = 0;
1078         if(letter2 < 0) letter2 = 0;
1079         if(letter1 > text_len) letter1 = text_len;
1080         if(letter2 > text_len) letter2 = text_len;
1083 void BC_TextBox::copy_selection(int clipboard_num)
1085         int text_len = strlen(text);
1087         if(highlight_letter1 >= text_len ||
1088                 highlight_letter2 > text_len ||
1089                 highlight_letter1 < 0 ||
1090                 highlight_letter2 < 0 ||
1091                 highlight_letter2 - highlight_letter1 <= 0) return;
1093         get_clipboard()->to_clipboard(&text[highlight_letter1], 
1094                 highlight_letter2 - highlight_letter1, 
1095                 clipboard_num);
1098 void BC_TextBox::paste_selection(int clipboard_num)
1100         int len = get_clipboard()->clipboard_len(clipboard_num);
1101         if(len)
1102         {
1103                 char *string = new char[len + 1];
1104                 get_clipboard()->from_clipboard(string, len, clipboard_num);
1105                 insert_text(string);
1106         }
1115 BC_ScrollTextBox::BC_ScrollTextBox(BC_WindowBase *parent_window, 
1116         int x, 
1117         int y, 
1118         int w,
1119         int rows,
1120         char *default_text)
1122         this->parent_window = parent_window;
1123         this->x = x;
1124         this->y = y;
1125         this->w = w;
1126         this->rows = rows;
1127         this->default_text = default_text;
1130 BC_ScrollTextBox::~BC_ScrollTextBox()
1132         delete yscroll;
1133         if(text)
1134         {
1135                 text->gui = 0;
1136                 delete text;
1137         }
1140 void BC_ScrollTextBox::create_objects()
1142 // Must be created first
1143         parent_window->add_subwindow(text = new BC_ScrollTextBoxText(this));
1144         parent_window->add_subwindow(yscroll = new BC_ScrollTextBoxYScroll(this));
1147 int BC_ScrollTextBox::handle_event()
1149         return 1;
1152 int BC_ScrollTextBox::get_x()
1154         return x;
1157 int BC_ScrollTextBox::get_y()
1159         return y;
1162 int BC_ScrollTextBox::get_w()
1164         return w;
1167 int BC_ScrollTextBox::get_rows()
1169         return rows;
1173 char* BC_ScrollTextBox::get_text()
1175         return text->get_text();
1178 void BC_ScrollTextBox::update(char *text)
1180         this->text->update(text);
1181         yscroll->update_length(this->text->get_text_rows(),
1182                 this->text->get_text_row(),
1183                 yscroll->get_handlelength());
1186 void BC_ScrollTextBox::reposition_window(int x, int y, int w, int rows)
1188         this->x = x;
1189         this->y = y;
1190         this->w = w;
1191         this->rows = rows;
1192         text->reposition_window(x, 
1193                 y, 
1194                 w - yscroll->get_span(), 
1195                 rows);
1196         yscroll->reposition_window(x + w - yscroll->get_span(), 
1197                 y, 
1198                 BC_TextBox::calculate_row_h(rows, 
1199                         parent_window));
1200         yscroll->update_length(text->get_text_rows(),
1201                 text->get_text_row(),
1202                 rows);
1213 BC_ScrollTextBoxText::BC_ScrollTextBoxText(BC_ScrollTextBox *gui)
1214  : BC_TextBox(gui->x, 
1215         gui->y, 
1216         gui->w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(), 
1217         gui->rows,
1218         gui->default_text)
1220         this->gui = gui;
1223 BC_ScrollTextBoxText::~BC_ScrollTextBoxText()
1225         if(gui)
1226         {
1227                 gui->text = 0;
1228                 delete gui;
1229         }
1232 int BC_ScrollTextBoxText::handle_event()
1234         gui->yscroll->update_length(get_text_rows(),
1235                 get_text_row(),
1236                 gui->yscroll->get_handlelength());
1237         return gui->handle_event();
1240 int BC_ScrollTextBoxText::motion_event()
1242         gui->yscroll->update_length(get_text_rows(),
1243                 get_text_row(),
1244                 gui->yscroll->get_handlelength());
1245         return 1;
1249 BC_ScrollTextBoxYScroll::BC_ScrollTextBoxYScroll(BC_ScrollTextBox *gui)
1250  : BC_ScrollBar(gui->x + 
1251                         gui->w - 
1252                         get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(), 
1253                 gui->y, 
1254                 SCROLL_VERT, 
1255                 BC_TextBox::calculate_row_h(gui->rows, 
1256                         gui->parent_window), 
1257                 gui->text->get_text_rows(), 
1258                 0, 
1259                 gui->rows)
1261         this->gui = gui;
1264 BC_ScrollTextBoxYScroll::~BC_ScrollTextBoxYScroll()
1268 int BC_ScrollTextBoxYScroll::handle_event()
1270         gui->text->set_text_row(get_position());
1271         return 1;
1283 BC_PopupTextBoxText::BC_PopupTextBoxText(BC_PopupTextBox *popup, int x, int y)
1284  : BC_TextBox(x, y, popup->text_w, 1, popup->default_text)
1286         this->popup = popup;
1289 BC_PopupTextBoxText::~BC_PopupTextBoxText()
1291         if(popup)
1292         {
1293                 popup->textbox = 0;
1294                 delete popup;
1295                 popup = 0;
1296         }
1300 int BC_PopupTextBoxText::handle_event()
1302         popup->handle_event();
1303         return 1;
1306 BC_PopupTextBoxList::BC_PopupTextBoxList(BC_PopupTextBox *popup, int x, int y)
1307  : BC_ListBox(x,
1308         y,
1309         popup->text_w + BC_WindowBase::get_resources()->listbox_button[0]->get_w(),
1310         popup->list_h,
1311         LISTBOX_TEXT,
1312         popup->list_items,
1313         0,
1314         0,
1315         1,
1316         0,
1317         1)
1319         this->popup = popup;
1321 int BC_PopupTextBoxList::handle_event()
1323         popup->textbox->update(get_selection(0, 0)->get_text());
1324         popup->handle_event();
1325         return 1;
1331 BC_PopupTextBox::BC_PopupTextBox(BC_WindowBase *parent_window, 
1332                 ArrayList<BC_ListBoxItem*> *list_items,
1333                 char *default_text,
1334                 int x, 
1335                 int y, 
1336                 int text_w,
1337                 int list_h)
1339         this->x = x;
1340         this->y = y;
1341         this->list_h = list_h;
1342         this->default_text = default_text;
1343         this->text_w = text_w;
1344         this->parent_window = parent_window;
1345         this->list_items = list_items;
1348 BC_PopupTextBox::~BC_PopupTextBox()
1350         delete listbox;
1351         if(textbox) 
1352         {
1353                 textbox->popup = 0;
1354                 delete textbox;
1355         }
1358 int BC_PopupTextBox::create_objects()
1360         int x = this->x, y = this->y;
1361         parent_window->add_subwindow(textbox = new BC_PopupTextBoxText(this, x, y));
1362         x += textbox->get_w();
1363         parent_window->add_subwindow(listbox = new BC_PopupTextBoxList(this, x, y));
1364         return 0;
1367 void BC_PopupTextBox::update(char *text)
1369         textbox->update(text);
1372 void BC_PopupTextBox::update_list(ArrayList<BC_ListBoxItem*> *data)
1374         listbox->update(data, 
1375                 0, 
1376                 0,
1377                 1);
1381 char* BC_PopupTextBox::get_text()
1383         return textbox->get_text();
1386 int BC_PopupTextBox::get_number()
1388         return listbox->get_selection_number(0, 0);
1391 int BC_PopupTextBox::get_x()
1393         return x;
1396 int BC_PopupTextBox::get_y()
1398         return y;
1401 int BC_PopupTextBox::get_w()
1403         return textbox->get_w() + listbox->get_w();
1406 int BC_PopupTextBox::get_h()
1408         return textbox->get_h();
1411 int BC_PopupTextBox::handle_event()
1413         return 1;
1416 void BC_PopupTextBox::reposition_window(int x, int y)
1418         this->x = x;
1419         this->y = y;
1420         int x1 = x, y1 = y;
1421         textbox->reposition_window(x1, y1);
1422         x1 += textbox->get_w();
1423         listbox->reposition_window(x1, y1);
1439 BC_TumbleTextBoxText::BC_TumbleTextBoxText(BC_TumbleTextBox *popup, 
1440         int64_t default_value,
1441         int64_t min,
1442         int64_t max,
1443         int x, 
1444         int y)
1445  : BC_TextBox(x, 
1446         y, 
1447         popup->text_w, 
1448         1, 
1449         default_value)
1451         this->popup = popup;
1454 BC_TumbleTextBoxText::BC_TumbleTextBoxText(BC_TumbleTextBox *popup, 
1455         float default_value,
1456         float min,
1457         float max,
1458         int x, 
1459         int y)
1460  : BC_TextBox(x, 
1461         y, 
1462         popup->text_w, 
1463         1, 
1464         default_value)
1466         this->popup = popup;
1469 BC_TumbleTextBoxText::~BC_TumbleTextBoxText()
1471         if(popup)
1472         {
1473                 popup->textbox = 0;
1474                 delete popup;
1475                 popup = 0;
1476         }
1481 int BC_TumbleTextBoxText::handle_event()
1483         popup->handle_event();
1484         return 1;
1492 BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window, 
1493                 int64_t default_value,
1494                 int64_t min,
1495                 int64_t max,
1496                 int x, 
1497                 int y, 
1498                 int text_w)
1500         reset();
1501         this->x = x;
1502         this->y = y;
1503         this->min = min;
1504         this->max = max;
1505         this->default_value = default_value;
1506         this->text_w = text_w;
1507         this->parent_window = parent_window;
1508         use_float = 0;
1509         precision = 4;
1512 BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window, 
1513                 int default_value,
1514                 int min,
1515                 int max,
1516                 int x, 
1517                 int y, 
1518                 int text_w)
1520         reset();
1521         this->x = x;
1522         this->y = y;
1523         this->min = min;
1524         this->max = max;
1525         this->default_value = default_value;
1526         this->text_w = text_w;
1527         this->parent_window = parent_window;
1528         use_float = 0;
1529         precision = 4;
1532 BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window, 
1533                 float default_value_f,
1534                 float min_f,
1535                 float max_f,
1536                 int x, 
1537                 int y, 
1538                 int text_w)
1540         reset();
1541         this->x = x;
1542         this->y = y;
1543         this->min_f = min_f;
1544         this->max_f = max_f;
1545         this->default_value_f = default_value_f;
1546         this->text_w = text_w;
1547         this->parent_window = parent_window;
1548         use_float = 1;
1549         precision = 4;
1552 BC_TumbleTextBox::~BC_TumbleTextBox()
1554 // Recursive delete.  Normally ~BC_TumbleTextBox is never called but textbox
1555 // is deleted anyway by the windowbase so textbox deletes this.
1556         if(tumbler) delete tumbler;
1557         tumbler = 0;
1558 // Don't delete text here if we were called by ~BC_TumbleTextBoxText
1559         if(textbox)
1560         {
1561                 textbox->popup = 0;
1562                 delete textbox;
1563         }
1564         textbox = 0;
1567 void BC_TumbleTextBox::reset()
1569         textbox = 0;
1570         tumbler = 0;
1571         increment = 1.0;
1574 void BC_TumbleTextBox::set_precision(int precision)
1576         this->precision = precision;
1579 void BC_TumbleTextBox::set_increment(float value)
1581         this->increment = value;
1582         if(tumbler) tumbler->set_increment(value);
1585 int BC_TumbleTextBox::create_objects()
1587         int x = this->x, y = this->y;
1589         if(use_float)
1590         {
1591                 parent_window->add_subwindow(textbox = new BC_TumbleTextBoxText(this, 
1592                         default_value_f,
1593                         min_f, 
1594                         max_f, 
1595                         x, 
1596                         y));
1597                 textbox->set_precision(precision);
1598         }
1599         else
1600                 parent_window->add_subwindow(textbox = new BC_TumbleTextBoxText(this, 
1601                         default_value,
1602                         min, 
1603                         max, 
1604                         x, 
1605                         y));
1607         x += textbox->get_w();
1609         if(use_float)
1610                 parent_window->add_subwindow(tumbler = new BC_FTumbler(textbox, 
1611                         min_f,
1612                         max_f,
1613                         x, 
1614                         y));
1615         else
1616                 parent_window->add_subwindow(tumbler = new BC_ITumbler(textbox, 
1617                         min, 
1618                         max, 
1619                         x, 
1620                         y));
1622         tumbler->set_increment(precision);
1623         return 0;
1626 char* BC_TumbleTextBox::get_text()
1628         return textbox->get_text();
1631 int BC_TumbleTextBox::update(char *value)
1633         textbox->update(value);
1634         return 0;
1637 int BC_TumbleTextBox::update(int64_t value)
1639         textbox->update(value);
1640         return 0;
1643 int BC_TumbleTextBox::update(float value)
1645         textbox->update(value);
1646         return 0;
1650 int BC_TumbleTextBox::get_x()
1652         return x;
1655 int BC_TumbleTextBox::get_y()
1657         return y;
1660 int BC_TumbleTextBox::get_w()
1662         return textbox->get_w() + tumbler->get_w();
1665 int BC_TumbleTextBox::get_h()
1667         return textbox->get_h();
1670 int BC_TumbleTextBox::handle_event()
1672         return 1;
1675 void BC_TumbleTextBox::reposition_window(int x, int y)
1677         this->x = x;
1678         this->y = y;
1679         
1680         textbox->reposition_window(x, 
1681                 y, 
1682                 text_w, 
1683                 1);
1684         tumbler->reposition_window(x + textbox->get_w(),
1685                 y);
1689 void BC_TumbleTextBox::set_boundaries(int64_t min, int64_t max)
1691         tumbler->set_boundaries(min, max);
1694 void BC_TumbleTextBox::set_boundaries(float min, float max)
1696         tumbler->set_boundaries(min, max);