source: golgotha/src/i4/gui/text_input.cc @ 608

Last change on this file since 608 was 80, checked in by Sam Hocevar, 15 years ago
  • Adding the Golgotha source code. Not sure what's going to be interesting in there, but since it's all public domain, there's certainly stuff to pick up.
File size: 13.5 KB
Line 
1/********************************************************************** <BR>
2  This file is part of Crack dot Com's free source code release of
3  Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
4  information about compiling & licensing issues visit this URL</a>
5  <PRE> If that doesn't help, contact Jonathan Clark at
6  golgotha_source@usa.net (Subject should have "GOLG" in it)
7***********************************************************************/
8
9
10#include "gui/text_input.hh"
11
12#include "time/timedev.hh"
13#include "device/event.hh"
14#include "window/win_evt.hh"
15#include "device/keys.hh"
16#include "device/key_man.hh"
17
18class cursor_blink_class : public i4_object_message_event_class
19{
20  public :
21  cursor_blink_class(void *object) : i4_object_message_event_class(object) {}
22  virtual i4_event  *copy() { return new cursor_blink_class(object); } 
23} ;
24
25sw32 i4_text_input_class::get_number()
26{
27  i4_str::iterator is=get_edit_string()->begin();
28  return is.read_number();
29}
30
31i4_text_input_class::i4_text_input_class(i4_graphical_style_class *style,
32                                         const i4_const_str &default_string,
33                                         w32 width,       // width in pixels of window
34                                         w32 _max_width,
35                                         i4_event_handler_class *change_notify,
36                                         i4_font_class *_font)
37  : style(style),
38    i4_window_class(0,0),
39    change_notify(change_notify)
40
41{
42  if (!_font)
43    font=style->font_hint->normal_font;
44  else
45    font=_font;
46
47  max_width=_max_width;
48  sent_change=i4_F;
49  changed=i4_F;
50  selected=i4_F;
51  cursor_on=i4_F;
52  selecting=i4_F;
53  need_cancel_blink=i4_F;
54   
55  w32 l,t,r,b;
56  style->get_in_deco_size(l,t,r,b);
57  private_resize(width+l+r, font->height(default_string)+1+t+b);
58
59  if (max_width<default_string.length())         // need a string at least as long as default
60    max_width=default_string.length();
61
62  st=new i4_str(default_string,max_width+1);
63
64  cursor_x=default_string.length();
65
66  hi_x1=0;   // nothing hilighted by default
67  hi_x2=0;
68  left_x=0;
69}
70
71
72void i4_text_input_class::draw_deco(i4_draw_context_class &context)
73{
74  style->draw_in_deco(local_image, 0,0, width()-1, height()-1, selected, context);
75}
76
77void i4_text_input_class::draw(i4_draw_context_class &context)
78{       
79  sw32 cx1,cy1,cy2;
80  w32 char_on=0;
81  w32 x;
82  i4_color fg;
83  i4_const_str::iterator c=st->begin();
84  w32 l,t,r,b;
85
86  local_image->add_dirty(0,0, width()-1, height()-1, context);
87
88  style->get_in_deco_size(l,t,r,b);
89  cx1=l;
90  cy1=t;
91  cy2=height()-1-b;
92
93
94  for (x=0; x<left_x; x++)
95  {
96    ++c;
97    char_on++;
98  }
99
100  style->deco_neutral_fill(local_image, 0,0, width()-1, height()-1, context);
101  //  local_image->clear(style->color_hint->text_background,context);
102  w32 proper_hi_x1=hi_x1>hi_x2 ? hi_x2 : hi_x1;
103  w32 proper_hi_x2=hi_x1>hi_x2 ? hi_x1 : hi_x2;
104     
105
106  for (x=0; x<width() && c!=st->end(); )
107  {
108
109    if (char_on>=proper_hi_x1 && char_on<proper_hi_x2)
110    {
111      fg=style->color_hint->selected_text_foreground;
112      local_image->bar(cx1+x,               cy1+1,
113                       cx1+x+font->width(c.get()), cy2,
114                       style->color_hint->selected_text_background,
115                       context);
116    } else
117      fg=style->color_hint->text_foreground;
118
119    font->set_color(fg);
120    if (c!=st->end())
121    {
122      font->put_character(local_image,cx1+x,cy1+1,c.get(),context);
123      if (cursor_on && cursor_x==char_on)
124        local_image->bar(cx1+x,cy1+1,
125                         cx1+x,cy2-2,style->color_hint->white,context);
126
127      x+=font->width(c.get());
128      ++c;
129    }
130    else if (cursor_on && cursor_x==char_on)
131        local_image->bar(cx1+x,cy1+1, cx1+x,cy2-2,style->color_hint->white,context);
132
133
134
135    char_on++;
136  }
137
138  if (cursor_on && cursor_x==char_on)
139    local_image->bar(cx1+x,cy1+1,
140                     cx1+x,cy2-2,style->color_hint->white,context);
141
142
143
144  draw_deco(context);
145
146}
147
148
149// this will find the character the mouse is on, this should work for non-constantly spaced
150// character strings as well
151w32 i4_text_input_class::mouse_to_cursor()
152{
153  i4_const_str::iterator c=st->begin();
154
155  w32 char_on=0;
156  w32 x,fw;
157  if (last_x<0)
158    last_x=0;
159
160  for (x=0; x<left_x && c!=st->end(); x++)
161  {
162    ++c;
163    char_on++;
164  }
165   
166  for (x=0; x<width() && c!=st->end(); )
167  {
168    fw=font->width(c.get());
169    if (last_x<=x+fw/2+1)
170      return char_on;
171
172    x+=fw;
173    char_on++;
174    ++c;
175  }
176  return char_on;
177}
178
179void i4_text_input_class::request_blink()
180{
181  if (!need_cancel_blink)
182  {
183    blink_timer=i4_time_dev.request_event(this,
184                                          new cursor_blink_class(this),
185                                          500);
186    need_cancel_blink=i4_T;
187  }
188}
189
190void i4_text_input_class::stop_blink()
191{
192  if (need_cancel_blink)
193  {
194    i4_time_dev.cancel_event(blink_timer);
195    need_cancel_blink=i4_F;
196  }
197}
198
199void i4_text_input_class::sustain_cursor()
200{
201  cursor_on=i4_T;
202  request_redraw();
203}
204
205void i4_text_input_class::del_selected()
206{
207       
208  if (hi_x1!=hi_x2)
209  {
210    i4_coord swap;
211    if (hi_x1>hi_x2)
212    {
213      swap=hi_x1;
214      hi_x1=hi_x2;
215      hi_x2=swap;
216    }
217
218    cursor_x=hi_x1;
219
220    i4_str::iterator start=st->begin(),end=st->begin();
221    while (hi_x1)
222    {
223      ++start;
224      hi_x2--;
225      hi_x1--;
226    }
227    end=start;
228    while (hi_x2)
229    {
230      ++end;
231      hi_x2--;
232    }
233    st->remove(start,end);
234  }
235  request_redraw();
236}
237
238void i4_text_input_class::move_cursor_right()
239//{{{
240{
241  if (cursor_x<st->length())
242  {
243    cursor_x++;
244
245    i4_const_str::iterator c=st->begin();
246    w32 cur_left,x;
247
248    for (x=0; x<left_x && c!=st->end(); x++)
249      ++c;
250 
251
252    for (cur_left=cursor_x-left_x; cur_left && c!=st->end(); cur_left--)
253    {
254      x+=font->width(c.get());
255      ++c;     
256    }
257    if (x>=width())
258    {
259      left_x+=4;
260    }
261    sustain_cursor();
262  }
263}
264//}}}
265
266
267void i4_text_input_class::move_cursor_left()
268{
269  if (cursor_x)
270  {
271    cursor_x--;
272    if (cursor_x<left_x)
273    {
274      if (left_x>4)
275        left_x-=4;
276      else left_x=0;
277    }
278    sustain_cursor();
279  }
280}
281
282
283void i4_text_input_class::move_cursor_end()
284//{{{
285{
286  w32 left_pos, pos;
287  i4_const_str::iterator c;
288
289  cursor_x = st->length();
290  left_x = 0;
291  pos = 0;
292  for (c=st->begin(); c!=st->end(); ++c)
293    pos += font->width(c.get());
294  left_pos = pos - width();
295
296  pos = 0;
297  for (c=st->begin(); c!=st->end() && pos<left_pos; ++c)
298  {
299    pos += font->width(c.get());
300    left_x++;
301  }
302
303  sustain_cursor();
304}
305//}}}
306
307
308void i4_text_input_class::become_active()
309{
310  i4_window_request_key_grab_class kgrab(this);
311  send_to_parent(&kgrab);
312     
313  selected=i4_T;
314  request_redraw();
315  if (!cursor_on)      // make sure cursor is not draw when we are not in focus
316    cursor_on=i4_T;
317  request_blink();
318}
319
320void i4_text_input_class::become_unactive()
321{
322  selected=i4_F;
323  request_redraw();
324
325  if (cursor_on)      // make sure cursor is not draw when we are not in focus
326    cursor_on=i4_F;
327
328  if (hi_x1!=hi_x2)
329  {
330    hi_x1=hi_x2;
331    request_redraw();
332  }
333
334  stop_blink();
335
336  if (selecting)
337  {
338    i4_window_request_mouse_ungrab_class ungrab(this);
339    send_to_parent(&ungrab);
340    selecting=i4_F;
341  }
342
343}
344 
345void i4_text_input_class::receive_event(i4_event *ev)
346{
347  switch (ev->type())
348  {
349    case i4_event::WINDOW_MESSAGE :       
350    {
351      CAST_PTR(wev,i4_window_message_class,ev);
352      switch (wev->sub_type)
353      {
354        case i4_window_message_class::GOT_DROP :
355        {
356          CAST_PTR(dev, i4_window_got_drop_class, ev);
357
358          if (dev->drag_info.drag_object_type==i4_drag_info_struct::FILENAMES)
359          {
360            if (dev->drag_info.t_filenames==1)
361            {
362              change_text(*dev->drag_info.filenames[0]);
363              if (change_notify)
364              {
365                i4_text_change_notify_event o(this, st);
366                i4_kernel.send_event(change_notify, &o);               
367                sent_change=i4_T;
368              }
369            }
370          }
371
372        } break;
373
374        case i4_window_message_class::GOT_MOUSE_FOCUS :
375        {
376          set_cursor(style->cursor_hint->text_cursor()->copy());
377        } break;
378
379        case i4_window_message_class::LOST_MOUSE_FOCUS :
380        {
381          set_cursor(0);
382        } break;
383
384
385        case i4_window_message_class::LOST_KEYBOARD_FOCUS :
386        {
387          become_unactive();
388
389          if (change_notify && changed && !sent_change)
390          {
391            i4_text_change_notify_event o(this, st);
392            i4_kernel.send_event(change_notify, &o);
393            sent_change=i4_T;
394          }
395        } break;
396         
397        default :         
398          i4_window_class::receive_event(ev);
399      }
400    } break;
401
402    case i4_event::OBJECT_MESSAGE :
403    {
404      CAST_PTR(oev,i4_object_message_event_class,ev);
405      if (oev->object==this)                              // was this an event we created?
406      {
407        need_cancel_blink=i4_F;
408        cursor_on=(i4_bool)(!cursor_on);
409        request_redraw();
410        request_blink();
411      }
412    } break;
413
414    case i4_event::MOUSE_BUTTON_DOWN :
415    {
416      CAST_PTR(bev,i4_mouse_button_down_event_class,ev);
417      if (bev->but==i4_mouse_button_down_event_class::LEFT)
418      {
419        become_active();
420
421        selecting=i4_T;
422         
423        hi_x1=mouse_to_cursor();
424        hi_x2=hi_x1;
425        cursor_x=hi_x1;
426
427        i4_window_request_mouse_grab_class grab(this);
428        send_to_parent(&grab);
429
430
431      }
432
433    } break;
434
435    case i4_event::MOUSE_BUTTON_UP :
436    {       
437      CAST_PTR(bev,i4_mouse_button_up_event_class,ev);
438      if (bev->but==i4_mouse_button_up_event_class::LEFT && selecting)
439      {
440        selecting=i4_F;
441        i4_window_request_mouse_ungrab_class ungrab(this);
442        send_to_parent(&ungrab);
443
444      }
445    } break;
446
447
448    case i4_event::MOUSE_MOVE :
449    {
450      CAST_PTR(mev,i4_mouse_move_event_class,ev);
451      last_x=mev->x;
452      last_y=mev->y;
453      if (selecting)
454      {
455        w32 old_hi_x2=hi_x2;
456        hi_x2=mouse_to_cursor();
457        if (old_hi_x2!=hi_x2)
458        {
459          request_redraw();
460          cursor_x=hi_x2;
461        }
462      }
463    } break;
464
465    case i4_event::KEY_PRESS :
466    {
467      CAST_PTR(kev,i4_key_press_event_class,ev);
468
469      switch (kev->key)
470      {
471        case I4_BACKSPACE :
472        {
473          if (hi_x1!=hi_x2)
474            del_selected();
475          else if (cursor_x)
476          {
477            cursor_x--;
478            w32 cur=cursor_x;
479            i4_str::iterator cursor1=st->begin(),cursor2=st->begin();
480            while (cur)
481            {
482              cur--;
483              ++cursor1;
484            }
485            cursor2=cursor1;
486            ++cursor2;
487            st->remove(cursor1,cursor2);
488            sustain_cursor();
489          }
490          note_change();
491       
492
493        } break;
494       
495        case I4_LEFT :
496        {
497          move_cursor_left();
498        } break;
499
500        case I4_RIGHT :
501        {
502          move_cursor_right();
503        } break;
504
505        case I4_HOME :
506        {
507          cursor_x = 0;
508          left_x = 0;
509          sustain_cursor();
510        } break;
511
512        case I4_END :
513        {
514          cursor_x = 0;
515          left_x = 0;
516          sustain_cursor();
517        } break;
518
519        case I4_ENTER :
520        {
521          if (change_notify && changed && !sent_change)
522          {
523            i4_text_change_notify_event o(this, st);
524            i4_kernel.send_event(change_notify, &o);
525            sent_change=i4_T;
526          }
527        } break;
528
529        default :
530        {
531          if (kev->key>=' ' && kev->key<='~')
532          {
533            note_change();
534       
535            if (hi_x1!=hi_x2)
536              del_selected();
537            w32 cur=cursor_x;
538            i4_str::iterator cursor=st->begin();
539            while (cur)
540            {
541              cur--;
542              ++cursor;
543            }
544
545            st->insert(cursor,kev->key);
546            move_cursor_right();
547          }
548
549        } break;
550      }
551    } break;
552
553
554    case i4_event::QUERY_MESSAGE :
555    {
556      CAST_PTR(qev,i4_query_text_input_class,ev);
557      qev->copy_of_data=new i4_str(*st,st->length()+1);
558    } break;
559
560    default :
561      i4_window_class::receive_event(ev);
562  }
563}
564
565i4_text_input_class::~i4_text_input_class()
566{
567  if (change_notify && changed && !sent_change)
568  {
569    i4_text_change_notify_event o(this, st);
570    i4_kernel.send_event(change_notify, &o);
571    sent_change=i4_T;
572  }
573
574  stop_blink();
575  delete st;
576}
577
578
579i4_window_class *i4_create_text_input(i4_graphical_style_class *style,
580                                      const i4_const_str &default_string,
581                                      w32 width,        // width in pixels of window
582                                      w32 max_width)
583{
584  i4_text_input_class *ti=new i4_text_input_class(style,
585                                                  default_string,
586                                                  width,
587                                                  max_width);
588
589
590
591  return ti;
592}
593
594void i4_text_input_class::change_text(const i4_const_str &new_st)
595{
596  delete st;
597  st=new i4_str(new_st, max_width);
598  request_redraw();
599  left_x=0;
600  cursor_x=0;
601}
602
603
604
605
Note: See TracBrowser for help on using the repository browser.