source: golgotha/src/i4/window/window.cc @ 80

Last change on this file since 80 was 80, checked in by Sam Hocevar, 11 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: 33.3 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#include "window/window.hh"
10#include "area/rectlist.hh"
11#include "device/kernel.hh"
12#include "error/error.hh"
13#include "window/win_evt.hh"
14#include "image/image.hh"
15#include "window/cursor.hh"
16#include "time/profile.hh"
17
18i4_profile_class pf_child_draw_prepare("window::child_prepare"),
19  pf_parent_draw_prepare("window::parent_prepare");
20
21#include <stdlib.h>
22
23i4_parent_window_class *i4_window_class::root_window()
24{
25  if (parent)
26    return parent->root_window();
27  else return 0;
28}
29
30i4_parent_window_class *i4_parent_window_class::root_window()
31{
32  if (parent)
33    return parent->root_window();
34  else return this;
35}
36
37i4_bool i4_window_class::isa_parent(i4_window_class *who)
38{
39  if (who==0)
40    return i4_F;
41  else if (who==parent)
42    return i4_T;
43  else if (parent)
44    return parent->isa_parent(who);
45  else return i4_F;
46}
47
48void i4_window_class::receive_event(i4_event *ev)
49{
50  if (ev->type()==i4_event::MOUSE_MOVE)
51  {
52    CAST_PTR(move, i4_mouse_move_event_class, ev);
53    mouse_x=move->x;
54    mouse_y=move->y;
55  }
56
57  if (cursor && parent)  // if we have a cursor we need to load when we get a mouse focus
58  {
59    if (ev->type()==i4_event::WINDOW_MESSAGE)
60    {
61      CAST_PTR(wev,i4_window_message_class,ev);
62      if (wev->sub_type==i4_window_message_class::GOT_MOUSE_FOCUS)
63      {
64        CAST_PTR(mev, i4_window_got_mouse_focus_class, ev);
65
66        mouse_x=mev->x;
67        mouse_y=mev->y;
68
69        i4_window_change_cursor_class c(this,cursor);
70        i4_kernel.send_event(parent,&c);
71      } else if (wev->sub_type==i4_window_message_class::LOST_MOUSE_FOCUS)
72      {
73        i4_window_change_cursor_class c(this,0);   // unload the cursor
74        i4_kernel.send_event(parent,&c);
75      }
76    }     
77  }
78}
79
80void i4_window_class::set_cursor(i4_cursor_class *Cursor)
81{
82  if (cursor)
83    delete cursor;
84 
85  if (Cursor)
86    cursor=Cursor->copy();
87  else
88    cursor=0;
89
90  if (parent)
91  {
92    i4_window_change_cursor_class c(this,cursor,i4_F);
93    i4_kernel.send_event(parent,&c);
94  }
95}
96
97i4_window_class::~i4_window_class()
98
99  if (cursor)
100    delete cursor;
101 
102  if (parent)
103    parent->remove_child(this);
104}
105
106
107void i4_window_class::resize(w16 new_width, w16 new_height)
108{
109  if (parent)
110  {
111    i4_window_notify_resize_class resize(this,new_width,new_height);
112    i4_kernel.send_event(parent,&resize);
113  }
114  private_resize(new_width,new_height);
115}
116
117void i4_parent_window_class::resize(w16 new_width, w16 new_height)
118{
119  i4_window_class::resize(new_width, new_height);
120
121  i4_window_notify_resize_class resize(this,new_width,new_height);
122
123  for (win_iter c=children.begin(); c!=children.end(); ++c)   
124    send_event_to_child(&*c,&resize);
125}
126
127
128void i4_window_class::private_resize(w16 new_width, w16 new_height)
129{
130  i4_rect_list_class parent_dirty;
131  if (width() && height())
132    parent_dirty.add_area(0,0,width()-1, height()-1);
133
134  w=new_width;
135  h=new_height;
136  parent_dirty.remove_area(0,0,width()-1,height()-1);
137
138  if (width() && height())
139    note_undrawn(0,0,width()-1,height()-1);
140
141   
142  if (parent)
143  {
144    for (i4_rect_list_class::area_iter a=parent_dirty.list.begin();
145         a!=parent_dirty.list.end(); ++a)
146    {
147      parent->note_undrawn(a->x1 + x() - parent->x(),
148                           a->y1 + y() - parent->y(),
149                           a->x2 + x() - parent->x(),
150                           a->y2 + y() - parent->y());
151                           
152    }
153  }
154
155  request_redraw();
156}
157
158
159void i4_window_class::reparent(i4_image_class *draw_area, i4_parent_window_class *Parent)
160{
161  parent=Parent;
162  if (parent)
163  {
164    mouse_x=parent->last_mouse_x()+parent->x()-x();
165    mouse_y=parent->last_mouse_y()+parent->y()-y();
166  }
167  else
168  {
169    mouse_x=-10000;
170    mouse_y=-10000;
171  }
172
173  if (local_image)
174    local_image=0;
175
176  global_image=draw_area;
177  if (global_image)
178  {
179    local_image=global_image;
180   
181    if (width() & height())
182      note_undrawn(0,0,width()-1,height()-1);
183
184    request_redraw();
185  }
186}
187
188void i4_window_class::private_move(i4_coord x_offset, i4_coord y_offset)
189{
190  global_x+=x_offset;
191  global_y+=y_offset;
192
193  if (width() && height())
194    note_undrawn(0,0,width()-1,height()-1);
195
196
197  request_redraw();
198}
199
200void i4_window_class::move(i4_coord x_offset, i4_coord y_offset,  i4_bool draw_under)
201{
202  private_move(x_offset,y_offset);
203  if (parent)
204  {
205    i4_window_notify_move_class move(this,x_offset,y_offset,draw_under);
206    i4_kernel.send_event(parent,&move);
207  }
208}
209
210void i4_window_class::draw(i4_draw_context_class &context)
211{
212  redraw_flag=i4_F;
213}
214
215void i4_window_class::request_redraw(i4_bool for_a_child)
216{
217  redraw_flag=i4_T;
218   
219  if (parent)
220  {
221    if (transparent() && width() && height())
222    {
223      int x1=x()-parent->x(), y1=y()-parent->y();
224      int x2=x1+width()-1, y2=y1+height()-1;
225
226      parent->note_undrawn(x1,y1,x2,y2, i4_F);
227    }
228
229    parent->request_redraw(i4_T);
230  }
231}
232
233void i4_window_class::note_undrawn(i4_coord x1, i4_coord y1, i4_coord x2, i4_coord y2,
234                                   i4_bool propogate_to_children)
235{
236  request_redraw(i4_F);
237}
238
239
240
241void i4_parent_window_class::parent_draw(i4_draw_context_class &context)
242{
243  redraw_flag=i4_F;
244}
245
246// draw should redraw supplied area of self
247void i4_parent_window_class::draw(i4_draw_context_class &context)
248
249
250  if (!undrawn_area.empty() || redraw_flag)
251  {   
252    pf_parent_draw_prepare.start();
253
254    redraw_flag=i4_F;
255    // copy the clip list, which should already be in our coordinates
256    i4_rect_list_class child_clip(&context.clip,0,0); 
257   
258    // remove the area of other children above us   
259    win_iter d=children.begin();
260    for (;d!=children.end();++d)
261    {
262      if (!d->transparent())
263        child_clip.remove_area(d->x()-x(),
264                               d->y()-y(),
265                               d->x()+d->width()-1-x(),
266                               d->y()+d->height()-1-y());
267    }
268
269    child_clip.swap(&context.clip);
270
271    pf_parent_draw_prepare.stop();
272
273    parent_draw(context);
274
275    pf_parent_draw_prepare.start();
276    undrawn_area.delete_list();
277
278    child_clip.swap(&context.clip);
279    pf_parent_draw_prepare.stop();
280
281  }
282
283  if (child_need_redraw)
284  {
285    child_need_redraw=i4_F;
286    win_iter c=children.begin();
287    for (;c!=children.end();++c)   
288    {
289      if (c->need_redraw())
290      {
291        pf_child_draw_prepare.start();
292
293        i4_coord x1=c->x()-x(),
294          y1=c->y()-y(),
295          x2=c->x()+c->width()-1-x(),
296          y2=c->y()+c->height()-1-y();
297
298        // copy the clip list, and move it to local coordinates
299        i4_rect_list_class child_clip(&context.clip,
300                                      -(c->x()-x()),
301                                      -(c->y()-y()));
302
303        // intersect the clip with what our area is supposed to be
304        child_clip.intersect_area(0,0,
305                                  c->width()-1,
306                                  c->height()-1);   
307
308        // save the old context xoff and yoff
309        sw16 old_xoff=context.xoff,old_yoff=context.yoff;   
310         
311        // move the context offset to the child's x,y
312        context.xoff+=(c->x()-x());                         
313        context.yoff+=(c->y()-y());
314
315          // remove the area of other children above us
316        i4_window_class *d=c->next;
317        for (;d;d=d->next)
318          child_clip.remove_area(d->x()-c->x(),
319                                 d->y()-c->y(),
320                                 d->x()+d->width()-1-c->x(),
321                                 d->y()+d->height()-1-c->y());
322
323        c->call_stack_counter++;  // make sure window doesn't get deleted during it's draw
324
325        // the child is covered completely by other windows
326        // tell it this in case it depends on draw()
327        if (child_clip.empty())
328          c->forget_redraw();   
329        else
330        {
331          child_clip.swap(&context.clip);
332         
333          child_rerequested_redraw = i4_F;
334         
335          pf_child_draw_prepare.stop();
336
337          c->draw(context);         // the child is ready to draw
338
339          pf_child_draw_prepare.start();
340          if (!child_rerequested_redraw)         
341            c->i4_window_class::forget_redraw();
342
343          child_clip.swap(&context.clip);   // restore the old clip list
344        }
345       
346        context.xoff=old_xoff;    // restore the context's x & y offsets
347        context.yoff=old_yoff;
348
349        c->call_stack_counter--;
350        pf_child_draw_prepare.stop();
351
352      }     
353    }
354  }
355
356}
357   
358#if ( __linux || __sgi)
359//extern void db_show();
360#else
361//void db_show() { ; }
362#endif
363
364void i4_window_class::show_context(i4_draw_context_class &context)
365{
366  i4_draw_context_class nc(0,0,local_image->width(),local_image->height());
367  local_image->clear(0xffff,nc);
368  i4_rect_list_class::area_iter c=context.clip.list.begin();
369  for (; c!=context.clip.list.end(); ++c)
370    local_image->rectangle(c->x1,c->y1,c->x2,c->y2,0,nc);
371
372  //  db_show();
373}
374
375
376i4_window_class::i4_window_class(w16 w, w16 h) : w(w),h(h)
377{
378  mouse_x=-10000;
379  mouse_y=-10000;
380
381  global_x=0;
382  global_y=0;
383  local_image=0;
384  global_image=0;
385  parent=0;
386  cursor=0;
387}
388
389
390i4_parent_window_class::i4_parent_window_class(w16 w, w16 h) : i4_window_class(w,h)
391{
392  have_mouse_focus=i4_F;
393  mouse_focus_grabbed=i4_F;
394  key_focus=children.end();
395  mouse_focus=children.end();
396  drag_drop_focus=children.end();
397}
398
399i4_parent_window_class::win_iter i4_parent_window_class::find_window(i4_coord global_mouse_x,
400                                                                     i4_coord global_mouse_y)
401{
402  win_iter c=children.begin(),
403    find=children.end();
404
405  for (;c!=children.end();++c)
406  {
407    if (global_mouse_x>=c->x() && 
408        global_mouse_y>=c->y() &&
409        global_mouse_x<c->x()+c->width() &&
410        global_mouse_y<c->y()+c->height())
411      find=c;
412  }
413  return find;
414}
415
416void i4_parent_window_class::drag_drop_move(i4_event *ev)
417{
418  CAST_PTR(move, i4_window_drag_drop_move_class, ev);
419  i4_coord real_mx=move->x+x(),
420    real_my=move->y+y();
421
422  win_iter find=find_window(real_mx, real_my);
423  if (find != drag_drop_focus)
424  {
425    if (drag_drop_focus != children.end())
426    {
427      i4_window_lost_drag_drop_focus_class lost(this);
428      send_event_to_child(&*drag_drop_focus, &lost);
429    }
430
431    drag_drop_focus = find;
432    if (find != children.end())
433    {
434      i4_window_class *prev_from=move->from_window;
435      move->from_window=this;
436
437      send_event_to_child(&*find, move);
438
439      move->from_window=prev_from;
440    }
441  }
442
443  if (drag_drop_focus != children.end())
444    send_event_to_child(&*drag_drop_focus,ev);
445}
446
447
448i4_bool i4_parent_window_class::find_new_mouse_focus()
449{
450  if (!mouse_focus_grabbed)  // see if we need to change the mouse focus
451  {
452    win_iter new_mouse_focus=find_window(mouse_x + x(), mouse_y + y());
453
454    if (new_mouse_focus!=mouse_focus)
455    {
456      change_mouse_focus(&*new_mouse_focus);
457      return i4_T;
458    }
459
460    else return i4_F;
461  }
462  else return i4_F;
463}
464
465void i4_parent_window_class::mouse_move(i4_event *ev)
466{
467  CAST_PTR(move, i4_mouse_move_event_class, ev);
468  mouse_x=move->x;
469  mouse_y=move->y;
470
471  find_new_mouse_focus();
472
473  if (mouse_focus!=children.end())
474    send_event_to_child(&*mouse_focus,ev);
475}
476
477void i4_parent_window_class::send_event_to_child(i4_window_class *w, i4_event *ev)
478{
479  sw32 xo=(sw32)x()-(sw32)w->x(), yo=(sw32)y()-(sw32)w->y();
480
481  ev->move(xo, yo);
482  i4_kernel.send_event(w, ev);
483  ev->move(-xo, -yo);
484}
485
486// passes events to mouse_focus or key_focus depending on the event type
487void i4_parent_window_class::receive_event(i4_event *ev)
488{
489  switch (ev->type())
490  {
491    case i4_event::IDLE_MESSAGE :     // pass idle message to current mouse focus
492    {
493      if (mouse_focus!=children.end())
494        send_event_to_child(&*mouse_focus,ev);
495    } break;
496
497    case i4_event::MOUSE_MOVE :
498    {
499      mouse_move(ev);
500    } break;
501
502    case i4_event::MOUSE_BUTTON_DOWN :
503    {
504      if (mouse_focus!=children.end())
505        send_event_to_child(&*mouse_focus,ev);
506    } break;
507
508    case i4_event::MOUSE_BUTTON_UP :
509    {
510      if (mouse_focus!=children.end())
511        send_event_to_child(&*mouse_focus,ev);
512    } break;
513
514    case i4_event::KEY_PRESS :
515    case i4_event::KEY_RELEASE :
516    {
517      if (key_focus!=children.end())
518        send_event_to_child(&*key_focus,ev);
519      else if (mouse_focus!=children.end())
520        send_event_to_child(&*mouse_focus,ev);
521    } break;
522
523
524    case i4_event::WINDOW_MESSAGE :
525    {
526      CAST_PTR(mess,i4_window_message_class,ev);
527      switch (mess->sub_type)
528      {
529        case i4_window_message_class::GOT_DROP :
530        {
531          if (drag_drop_focus != children.end())
532          {
533            send_event_to_child(&*drag_drop_focus, ev);
534            drag_drop_focus=children.end();
535          }
536          else
537          {
538            CAST_PTR(dev, i4_window_got_drop_class, ev);
539
540            i4_parent_window_class::win_iter w=find_window(dev->drag_info.x+x(),
541                                                           dev->drag_info.y+y());
542            if (w!=children.end())
543              send_event_to_child(&*w, ev);
544          }
545        } break;
546
547        case i4_window_message_class::REQUEST_DRAG_DROP_START :
548        case i4_window_message_class::REQUEST_DRAG_DROP_END :
549        {
550          if (parent)
551            parent->receive_event(ev);
552        } break;
553        case i4_window_message_class::DRAG_DROP_MOVE :
554        {
555          drag_drop_move(ev);
556        } break;
557
558        case i4_window_message_class::CHANGE_CURSOR :
559        {
560          CAST_PTR(cc,i4_window_change_cursor_class,ev);
561          if (parent && (!cc->only_if_active || cc->from()==&*mouse_focus))
562          {
563            i4_window_change_cursor_class scope(this,cc->cursor,cc->only_if_active);
564            parent->receive_event(&scope);
565          }
566
567        } break;
568        case i4_window_message_class::REQUEST_KEY_GRAB :
569        {
570          CAST_PTR(grab,i4_window_request_key_grab_class,ev);
571          grab->return_result=i4_T;
572
573          if (parent)
574          {
575            i4_window_request_key_grab_class ask_parent(this);
576            i4_kernel.send_event(parent,&ask_parent);
577            if (ask_parent.return_result==i4_F)
578              grab->return_result=i4_F;
579          }
580
581          if (grab->return_result)
582          {
583            win_iter c=children.begin();
584            for (;c!=children.end() && c!=mess->from();++c);
585            if (c!=children.end())
586            {
587              if (c != key_focus)
588                change_key_focus(&*c);
589            }
590            else
591              i4_warning("got key grab from unknown child");
592          }
593        } break;
594        case i4_window_message_class::REQUEST_DELETE :
595        {
596          remove_child(mess->from());
597          delete mess->from();
598        } break;
599       
600        case i4_window_message_class::REQUEST_NEXT_KEY_FOCUS : next_key_focus(); break;
601        case i4_window_message_class::REQUEST_LEFT_KEY_FOCUS : left_key_focus(); break;
602        case i4_window_message_class::REQUEST_RIGHT_KEY_FOCUS : right_key_focus(); break;
603        case i4_window_message_class::REQUEST_UP_KEY_FOCUS : up_key_focus(); break;
604        case i4_window_message_class::REQUEST_DOWN_KEY_FOCUS : down_key_focus(); break;
605        case i4_window_message_class::REQUEST_MOUSE_GRAB :
606        {
607          CAST_PTR(grab,i4_window_request_mouse_grab_class,ev);
608
609          grab->return_result=i4_T;    // defulat return is false
610
611          if (!mouse_focus_grabbed)  // see if we need to change the mouse focus         
612          {
613            if (parent)
614            {
615              i4_window_request_mouse_grab_class ask_parent(this);
616              i4_kernel.send_event(parent,&ask_parent);
617              if (ask_parent.return_result==i4_F)
618                grab->return_result=i4_F;
619              else grab->return_result=i4_T;
620            }
621
622            if (grab->return_result)
623            {
624              mouse_focus_grabbed=i4_T;
625 
626              if (&(*mouse_focus) != grab->from())
627                change_mouse_focus(grab->from());
628            }
629
630          } else
631            grab->return_result=i4_F;
632        } break;
633
634        case i4_window_message_class::REQUEST_MOUSE_UNGRAB :
635        {
636          if (mouse_focus_grabbed)
637          {
638            mouse_focus_grabbed=i4_F;
639            if (parent)
640              i4_kernel.send_event(parent,ev);   
641
642            find_new_mouse_focus();
643          }
644          else i4_warning("mouse not grabbed");
645
646        } break;
647
648
649        case i4_window_message_class::NOTIFY_RESIZE :
650        {
651          CAST_PTR(resize,i4_window_notify_resize_class,ev);
652          i4_window_class *cf=resize->from();
653
654          if (cf!=parent)    // if this is from our parent, ignore it
655          {
656            i4_rect_list_class dirty;
657            if (cf->width() && cf->height())
658              dirty.add_area   (cf->x(),cf->y(),cf->x()+cf->width()-1,cf->y()+cf->height()-1);
659
660            if (resize->new_width && resize->new_height)
661              dirty.remove_area(cf->x(),cf->y(),
662                                cf->x()+resize->new_width-1,
663                                cf->y()+resize->new_height-1);
664
665            if (width() && height())
666              dirty.intersect_area(x(),y(),x()+width()-1,y()+height()-1);
667
668            if (resize->draw_covered)
669            {
670              // check to see if any child were under this window
671              // will need to be redraw because of this
672              win_iter c=children.begin();
673              for (;c!=children.end() && c!=cf;++c)
674              {                 
675                if (c->width() && c->height() &&
676                    !dirty.clipped_away(c->x(),c->y(),c->x()+c->width()-1,c->y()+height()-1))
677                {
678                  i4_rect_list_class::area_iter a=dirty.list.begin();
679                  for (;a!=dirty.list.end();++a)
680                  {
681                    if (c->width() && c->height())
682                    {
683                      i4_coord x1=a->x1-c->x(),y1=a->y1-c->y(),x2=a->x2-c->x(),y2=a->y2-c->y();
684
685                      if (x1<0) x1=0;
686                      if (y1<0) y1=0;
687                      if (x2>=c->width()) x2=c->width()-1;
688                      if (y2>=c->height()) y2=c->height()-1;
689                      if (x1<=x2 && y1<=y2)
690                        c->note_undrawn(x1,y1,x2,y2);
691                    }
692                  }
693                }
694              }
695
696              // add this dirty area to the parent's undrawn_area list,
697              // so the parent knows what part of itself it needs to redraw
698              i4_rect_list_class::area_iter a=dirty.list.begin();
699              for (;a!=dirty.list.end();++a)
700                undrawn_area.add_area(a->x1-x(),    // make sure we add in parent-local coordinates
701                                      a->y1-y(),
702                                      a->x2-x(),
703                                      a->y2-y());
704            }
705          }
706          else
707            request_redraw(i4_F);
708        } break;
709
710        case i4_window_message_class::NOTIFY_MOVE :
711        {
712          CAST_PTR(move_event,i4_window_notify_move_class,ev);
713          i4_window_class *child=move_event->from();
714          i4_coord old_x=child->x()-move_event->x_offset,old_y=child->y()-move_event->y_offset;
715
716          i4_coord new_x=child->x(),new_y=child->y();
717
718          if (move_event->draw_covered)
719          {
720            i4_rect_list_class dirty;
721
722            if (child->width() && child->height())
723              dirty.add_area(old_x,old_y,old_x+child->width()-1,old_y+child->height()-1);
724
725            if (width() && height())
726              dirty.intersect_area(x(),y(),x()+width()-1,y()+height()-1);
727
728            if (child->width() && child->height())
729              dirty.remove_area(new_x,new_y,new_x+child->width()-1,new_y+child->height()-1);
730           
731
732      // check to see if any child were under this window will need to be redraw because of this
733            win_iter c=children.begin();
734            for (;c!=children.end() && c!=child;++c)
735            {
736              if (c->width() && c->height() &&
737                  !dirty.clipped_away(c->x(),c->y(),c->x()+c->width()-1,c->y()+height()-1))
738              {
739                i4_rect_list_class::area_iter a=dirty.list.begin();
740                for (;a!=dirty.list.end();++a)
741                {
742                  if (c->width() && c->height())
743                  {
744                    i4_coord x1=a->x1-c->x(),y1=a->y1-c->y(),x2=a->x2-c->x(),y2=a->y2-c->y();
745
746                    if (x1<0) x1=0;
747                    if (y1<0) y1=0;
748                    if (x2>=c->width()) x2=c->width()-1;
749                    if (y2>=c->height()) y2=c->height()-1;
750                    if (x1<=x2 && y1<=y2)
751                      c->note_undrawn(x1,y1,x2,y2);
752                  }
753                }
754              }
755            }
756
757            // add this dirty area to the parent's dirty_area list,
758            // so the parent knows what part of itself it needs to redraw
759            i4_rect_list_class::area_iter a=dirty.list.begin();
760            for (;a!=dirty.list.end();++a)
761              undrawn_area.add_area(a->x1-x(),   // add in local coordinates
762                                    a->y1-y(),
763                                    a->x2-x(),
764                                    a->y2-y());
765          }
766
767        } break;
768
769        case i4_window_message_class::GOT_MOUSE_FOCUS :
770        {
771          have_mouse_focus=i4_T;
772
773          CAST_PTR(mev, i4_window_got_mouse_focus_class, ev);
774          mouse_x=mev->x;
775          mouse_y=mev->y;
776
777          i4_window_change_cursor_class c(this,cursor);
778          i4_kernel.send_event(parent,&c);
779
780          find_new_mouse_focus();
781        } break;
782
783
784        case i4_window_message_class::LOST_DROP_FOCUS :
785        {
786          if (drag_drop_focus!=children.end())
787          {
788            send_event_to_child(&*drag_drop_focus,ev);
789            drag_drop_focus=children.end();
790          }
791          i4_window_class::receive_event(ev);
792        } break;
793
794        case i4_window_message_class::LOST_MOUSE_FOCUS :
795        {
796          if (mouse_focus!=children.end())
797          {
798            send_event_to_child(&*mouse_focus,ev);
799            mouse_focus=children.end();
800          }
801          i4_window_class::receive_event(ev);
802          have_mouse_focus=i4_F;
803
804        } break;
805        case i4_window_message_class::LOST_KEYBOARD_FOCUS :
806        {
807          change_key_focus(0);
808        } break;
809        default :
810          i4_window_class::receive_event(ev);
811         
812      }
813    } break;
814    default :
815      i4_window_class::receive_event(ev);
816         
817  }
818}
819
820void i4_parent_window_class::change_key_focus(i4_window_class *new_focus)
821{
822  if (key_focus!=children.end())
823  {
824    i4_window_message_class lost(i4_window_message_class::LOST_KEYBOARD_FOCUS,this);
825    send_event_to_child(&*key_focus,&lost);   
826  }
827
828  key_focus=new_focus;
829
830  if (new_focus)
831  {
832    i4_window_message_class got(i4_window_message_class::GOT_KEYBOARD_FOCUS,this);
833    send_event_to_child(&*key_focus,&got); 
834  }
835}
836
837
838void i4_parent_window_class::change_mouse_focus(i4_window_class *new_focus)
839{
840  if (mouse_focus!=children.end())
841  {
842    i4_window_lost_mouse_focus_class lost(this, new_focus);
843    send_event_to_child(&*mouse_focus,&lost);   
844  }
845
846
847  mouse_focus=new_focus;
848
849  if (mouse_focus!=children.end())
850  {
851    i4_window_got_mouse_focus_class got(this, mouse_x, mouse_y);
852    send_event_to_child(&*mouse_focus,&got); 
853  }
854}
855
856
857void i4_parent_window_class::next_key_focus()
858{
859  if (key_focus!=children.end())
860    change_key_focus(key_focus->next);
861}
862
863
864void i4_parent_window_class::left_key_focus()
865{
866  if (key_focus!=children.end())
867  {
868    win_iter c=children.begin(),closest=children.end();
869    w32 closest_distance=0xffffffff;
870    i4_coord cx1=key_focus->x()+key_focus->width()/2,
871      cy1=key_focus->y()+key_focus->height()/2;
872
873
874    for (;c!=children.end();++c)
875    {
876      if (c->x()<key_focus->x())
877      {
878        i4_coord cx2=c->x()+c->width()/2,cy2=c->y()+c->height()/2;
879
880        w32 dist=(cx2-cx1)*(cx2-cx1)+(cy2-cy1)*(cy2-cy1);
881        if (dist<closest_distance)
882        {
883          closest_distance=dist;
884          closest=c;
885        }
886      }
887    }
888
889    if (closest!=children.end())
890      change_key_focus(&*closest);
891  }
892}
893
894
895void i4_parent_window_class::right_key_focus()
896{
897  if (key_focus!=children.end())
898  {
899    win_iter c=children.begin(),closest=children.end();
900    w32 closest_distance=0xffffffff;
901    i4_coord cx1=key_focus->x()+key_focus->width()/2,
902      cy1=key_focus->y()+key_focus->height()/2;
903
904
905    for (;c!=children.end();++c)
906    {
907      if (c->x()>cx1)
908      {
909        i4_coord cx2=c->x()+c->width()/2,
910          cy2=c->y()+c->height()/2;       
911        w32 dist=(cx2-cx1)*(cx2-cx1)+(cy2-cy1)*(cy2-cy1);
912        if (dist<closest_distance)
913        {
914          closest_distance=dist;
915          closest=c;
916        }
917      }
918    }
919
920    if (closest!=children.end())
921      change_key_focus(&*closest);
922  }
923}
924
925
926void i4_parent_window_class::up_key_focus()
927{
928  if (key_focus!=children.end())
929  {
930    win_iter c=children.begin(),closest=children.end();
931    w32 closest_distance=0xffffffff;
932    i4_coord cx1=key_focus->x()+key_focus->width()/2,
933      cy1=key_focus->y()+key_focus->height()/2;
934
935
936    for (;c!=children.end();++c)
937    {
938      if (c->y()<key_focus->y())
939      {
940        i4_coord cx2=c->x()+c->width()/2,
941          cy2=c->y()+c->height()/2;       
942        w32 dist=(cx2-cx1)*(cx2-cx1)+(cy2-cy1)*(cy2-cy1);
943        if (dist<closest_distance)
944        {
945          closest_distance=dist;
946          closest=c;
947        }
948      }
949    }
950
951    if (closest!=children.end())
952      change_key_focus(&*closest);
953  }
954}
955
956
957void i4_parent_window_class::down_key_focus()
958{
959  if (key_focus!=children.end())
960  {
961    win_iter c=children.begin(),closest=children.end();
962    w32 closest_distance=0xffffffff;
963    i4_coord cx1=key_focus->x()+key_focus->width()/2,
964      cy1=key_focus->y()+key_focus->height()/2;
965
966    for (;c!=children.end();++c)
967    {
968      if (c->y()>key_focus->y())
969      {
970        i4_coord cx2=c->x()+c->width()/2,
971          cy2=c->y()+c->height()/2;       
972        w32 dist=(cx2-cx1)*(cx2-cx1)+(cy2-cy1)*(cy2-cy1);
973        if (dist<closest_distance)
974        {
975          closest_distance=dist;
976          closest=c;
977        }
978      }
979    }
980
981    if (closest!=children.end())
982      change_key_focus(&*closest);
983  }
984}
985
986void i4_parent_window_class::reparent(i4_image_class *draw_area, i4_parent_window_class *_parent)
987{
988  // reparent children first, in case the have a mouse grab and need to tell our
989  // original parent to ungrab
990  for (win_iter c=children.begin();c!=children.end();++c)
991    c->reparent(draw_area,this);
992
993  i4_window_class::reparent(draw_area,_parent);
994
995  if (have_mouse_focus)
996    find_new_mouse_focus();
997}
998
999void i4_parent_window_class::add_child(i4_coord x_, i4_coord y_, i4_window_class *child)
1000{
1001  children.insert_end(*child);
1002  child->reparent(global_image,this);
1003  child->private_move(x()+x_-child->x(),y()+y_-child->y());
1004
1005  if (have_mouse_focus)
1006    find_new_mouse_focus();
1007}
1008
1009void i4_parent_window_class::add_child_front(i4_coord x_, i4_coord y_, i4_window_class *child)
1010{
1011  children.insert(*child);
1012  child->reparent(global_image,this);
1013  child->private_move(x()+x_-child->x(),y()+y_-child->y());
1014
1015  if (have_mouse_focus)
1016    find_new_mouse_focus();
1017}
1018
1019
1020void i4_parent_window_class::forget_redraw()
1021{
1022  undrawn_area.delete_list(); 
1023  for (win_iter c=children.begin();c!=children.end();++c)
1024    c->forget_redraw();
1025}
1026
1027void i4_parent_window_class::transfer_children(i4_parent_window_class *other_parent,
1028                                               i4_coord x_offset, i4_coord y_offset)
1029{
1030  while (children.begin() != children.end())
1031  {
1032    i4_window_class *c=&*children.begin();
1033    i4_coord xn=c->x()-x();
1034    i4_coord yn=c->y()-y();
1035
1036    remove_child(c);
1037    other_parent->add_child(xn+x_offset,
1038                            yn+y_offset,c);
1039  }
1040
1041  if (have_mouse_focus)
1042    find_new_mouse_focus();
1043
1044  if (other_parent->has_mouse_focus())
1045    other_parent->find_new_mouse_focus();
1046}
1047
1048void i4_parent_window_class::remove_child(i4_window_class *child)
1049{
1050  if (&*key_focus==child)
1051    change_key_focus(0);
1052
1053  if (&*mouse_focus==child)
1054  {
1055    if (mouse_focus_grabbed)
1056    {
1057      if (parent)
1058      {
1059        i4_window_request_mouse_ungrab_class ungrab(this);
1060        i4_kernel.send_event(parent, &ungrab);
1061      }
1062
1063      mouse_focus_grabbed=i4_F;
1064    }
1065  }
1066
1067  if (child==&*children.begin())
1068    children.erase();
1069  else
1070  {
1071    win_iter f=children.begin(),last=children.end();
1072    for (;f!=children.end() && f!=&*child;)
1073    {
1074      last=f;
1075      ++f;
1076    }
1077    if (f!=children.end())
1078      children.erase_after(last);
1079    else
1080      i4_error("child not found");
1081  }
1082
1083  if (child->width() && child->height())
1084  {
1085    note_undrawn(child->x()-x(),
1086                 child->y()-y(),
1087                 child->x()+child->width()-1-x(),
1088                 child->y()+child->height()-1-y());
1089  }
1090
1091  if (&*mouse_focus==child)
1092  {
1093    i4_window_lost_mouse_focus_class lost(this, 0);
1094    send_event_to_child(child, &lost);   
1095    mouse_focus=children.end();
1096  }
1097
1098
1099  child->reparent(0,0);  // tell the child it doesn't have a parent or a draw_area anymore
1100
1101  if (have_mouse_focus)
1102    find_new_mouse_focus();
1103
1104}
1105
1106void i4_parent_window_class::request_redraw(i4_bool for_a_child)
1107{
1108  if (for_a_child)
1109  {
1110    child_need_redraw=i4_T;
1111    child_rerequested_redraw=i4_T;
1112  }
1113  else
1114    redraw_flag=i4_T;
1115  if (parent)
1116    parent->request_redraw(i4_T);
1117}
1118
1119void i4_parent_window_class::note_undrawn(i4_coord x1, i4_coord y1,
1120                                          i4_coord x2, i4_coord y2,
1121                                          i4_bool propogate_to_children)
1122{
1123
1124  undrawn_area.add_area(x1,y1,x2,y2);
1125  request_redraw();
1126   
1127  win_iter c=children.begin();
1128
1129
1130  x1+=x();  y1+=y();     // transform to global coordinates
1131  x2+=x();  y2+=y();
1132 
1133  if (propogate_to_children)
1134  {
1135    for (;c!=children.end();++c)
1136    {
1137      if (c->width() && c->height())
1138      {
1139        if (!(c->x()>x2 ||
1140              c->y()>y2 ||
1141              c->x()+c->width()-1  < x1 ||
1142              c->y()+c->height()-1 < y1))
1143        {     
1144          i4_coord ax1=x1-c->x(),
1145            ay1=y1-c->y(),
1146            ax2=x2-c->x(),
1147            ay2=y2-c->y();
1148          if (ax1<0) ax1=0;
1149          if (ay1<0) ay1=0;
1150          if (ax2>=c->width()) ax2=c->width()-1;
1151          if (ay2>=c->height()) ay2=c->height()-1;
1152          if (ax1<=ax2 && ay1<=ay2)
1153            c->note_undrawn(ax1,ay1,ax2,ay2);
1154        }
1155      }
1156    }
1157  }
1158}
1159
1160
1161
1162void i4_parent_window_class::private_move(i4_coord x_offset, i4_coord y_offset)
1163{
1164  i4_window_class::private_move(x_offset,y_offset);
1165  win_iter c=children.begin();
1166  for (;c!=children.end();++c)
1167  {
1168    c->private_move(x_offset,y_offset); 
1169  }
1170  // use private move so child doesn't tell us it moved (we know!)
1171}
1172
1173
1174void i4_parent_window_class::redraw_area(i4_coord x1, i4_coord y1, i4_coord x2, i4_coord y2)
1175{
1176  if (!(x2<0 || y2<0 || x1>=width() || y1>=height()))
1177    undrawn_area.add_area(x1,y1,x2,y2);
1178}
1179
1180// arranges child windows from left to right then down
1181void i4_parent_window_class::arrange_right_down() 
1182{
1183  i4_coord x1=x(),y1=y(),mh=0;
1184  win_iter c=children.begin();
1185  for (;c!=children.end();++c)
1186  {
1187
1188    if (c->width()+x1>x()+width())
1189    {
1190      y1+=mh;
1191      x1=x();
1192      mh=0;
1193    }
1194
1195    c->move(x1-c->x(),y1-c->y());
1196
1197    if (c->height()>mh)
1198      mh=c->height();
1199
1200    x1+=c->width();
1201
1202
1203  }
1204}
1205
1206void i4_parent_window_class::resize_to_fit_children()
1207{
1208  i4_coord x2=0,y2=0;
1209  win_iter c=children.begin();
1210  for (;c!=children.end();++c)
1211  {
1212    if (c->x()-x()+c->width()>x2)   
1213      x2=c->x()-x()+c->width();
1214    if (c->y()-y()+c->height()>y2)
1215      y2=c->y()-y()+c->height();
1216  }
1217
1218  resize(x2,y2);
1219}
1220
1221void i4_parent_window_class::arrange_down_right()                                 // arranges child windows from top to bottom then right
1222{
1223  i4_coord x1=x(),y1=y(),mw=0;
1224  win_iter c=children.begin();
1225  for (;c!=children.end();++c)
1226  {
1227    if (c->height()+y1>=height())
1228    {
1229      x1+=mw;
1230      y1=y();
1231      mw=0;
1232    }
1233
1234    c->move(x1-c->x(),y1-c->y());
1235    y1+=c->height();
1236
1237    if (c->width()>mw)
1238      mw=c->width();
1239
1240
1241  }
1242}
1243
1244
1245i4_parent_window_class::~i4_parent_window_class()
1246{
1247  while (children.begin() != children.end())
1248  {
1249    win_iter c=children.begin();
1250    children.erase();
1251    c->reparent(0,0);
1252   
1253    i4_kernel.delete_handler(&*c);
1254  } 
1255}
1256
1257i4_window_class *i4_parent_window_class::get_nth_window(w32 win_num)
1258{
1259  win_iter i=children.begin();
1260  while (win_num && i!=children.end())
1261  {
1262    ++i;
1263    win_num--;
1264  }
1265  if (i==children.end())
1266    return 0;
1267  else return &*i;
1268}
1269
1270
1271#ifndef I4_RETAIL
1272void i4_window_class::debug_show()
1273{
1274  i4_warning("%s",name());
1275  if (parent)
1276    parent->debug_show();
1277}
1278#endif
1279
1280i4_bool i4_parent_window_class::isa_child(i4_window_class *w)
1281{
1282  win_iter c=children.begin();
1283  for (;c!=children.end();++c)
1284    if (&*c==w)
1285      return i4_T;
1286
1287  return i4_F;
1288}
Note: See TracBrowser for help on using the repository browser.