source: abuse/trunk/src/imlib/jwindow.cpp @ 521

Last change on this file since 521 was 518, checked in by Sam Hocevar, 12 years ago

imlib: refactor dirty_rect clipping coordiantes so that the upper
bound is no longer inclusive. It will make things easier in the future.

File size: 17.9 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5 *
6 *  This software was released into the Public Domain. As with most public
7 *  domain software, no warranty is made or implied by Crack dot Com or
8 *  Jonathan Clark.
9 */
10
11#include "config.h"
12
13#include <string.h>
14
15#include "common.h"
16
17#include "video.h"
18#include "image.h"
19#include "input.h"
20#include "event.h"
21#include "filter.h"
22#include "event.h"
23#include "jwindow.h"
24
25static int jw_left = 3, jw_right = 3, jw_top = 2, jw_bottom = 3;
26
27int frame_top() { return jw_top; }
28int frame_bottom() { return jw_bottom; }
29int frame_left() { return jw_left; }
30int frame_right() { return jw_right; }
31
32//
33//  Sets the size of the border around each window
34//
35void set_frame_size(int x)
36{
37    if(x < 1)
38        x = 1;
39    jw_left = x;
40    jw_right = x;
41    jw_top = 2;
42    jw_bottom = x;
43}
44
45 // true if a window lies in this area
46int WindowManager::window_in_area(int x1, int y1, int x2, int y2)
47{
48  for (Jwindow *f=first; f; f=f->next)
49    if (f->x<=x2 && f->y<=y2 && f->x+f->l-1>=x1 && f->y+f->h-1>=y1)
50      return 1;
51  return 0;
52}
53
54void WindowManager::grab_focus(Jwindow *j)
55{ grab=j; }
56
57void WindowManager::release_focus()
58{ grab=NULL; }
59
60
61void WindowManager::close_window(Jwindow *j)
62{
63    delete j;
64}
65
66void WindowManager::hide_windows()
67{
68    for (Jwindow *p = first; p; p = p->next)
69    {
70        if (!p->is_hidden())
71        {
72            p->hide();
73            screen->AddDirty(p->x, p->y, p->x + p->l, p->y + p->h);
74        }
75    }
76}
77
78void WindowManager::show_windows()
79{
80  Jwindow *p;
81  for (p=first; p; p=p->next)
82    if (p->is_hidden())
83      show_window(p);
84}
85
86void WindowManager::hide_window(Jwindow *j)
87{
88    if (j == first)
89        first = first->next;
90    else
91    {
92        Jwindow *k;
93        for (k = first; k->next != j; k = k->next)
94            k->screen->AddDirty(j->x - k->x, j->y - k->y,
95                                j->x + j->l - k->x, j->y + j->h - k->y);
96        k->screen->AddDirty(j->x - k->x, j->y - k->y,
97                            j->x + j->l - k->x, j->y + j->h - k->y);
98        k->next = j->next;
99    }
100    screen->AddDirty(j->x, j->y, j->x + j->l, j->y + j->h);
101    j->hide();
102}
103
104void WindowManager::show_window(Jwindow *j)
105{
106    if (j->is_hidden())
107    {
108        j->show();
109        j->screen->AddDirty(0, 0, j->l, j->h);
110    }
111}
112
113void WindowManager::get_event(event &ev)
114{
115  Jwindow *j;
116  eh->get_event(ev);
117  if (ev.type==EV_KEY)
118    key_state[ev.key]=1;
119  else if (ev.type==EV_KEYRELEASE)
120    key_state[ev.key]=0;
121
122  if (state==inputing)
123  {
124    for (ev.window=NULL,j=first; j; j=j->next)
125      if (!j->is_hidden() && ev.mouse_move.x>=j->x && ev.mouse_move.y>=j->y &&
126          ev.mouse_move.x<j->x+j->l && ev.mouse_move.y<j->y+j->h)
127        ev.window=j;
128
129    if (!ev.window && grab) ev.window=grab;
130
131    if (ev.window)
132    {
133      int closew=0,movew=0;
134
135      if ((ev.type==EV_MOUSE_BUTTON && ev.mouse_button==1 && ev.window &&
136       ev.mouse_move.x>=ev.window->x && ev.mouse_move.y>=ev.window->y &&
137       ev.mouse_move.x<ev.window->x+ev.window->l && ev.mouse_move.y<ev.window->y+ev.window->y1()))
138      {
139    if (ev.mouse_move.x-ev.window->x<11) closew=1;
140    else if (ev.window->is_moveable()) movew=1;
141      } else if (grab)
142        ev.window=grab;
143
144      if (ev.type==EV_KEY && ev.key==JK_ESC)
145        closew=1;
146
147
148
149      if (closew)
150        ev.type=EV_CLOSE_WINDOW;
151      else if (movew)
152      {
153    int red=0;
154    if (ev.window==first)       // see if we need to raise the window
155    {
156      first=first->next;
157      if (first)
158        red=1;
159    }
160    else
161    {
162      Jwindow *last=first;
163      for (; last->next!=ev.window; last=last->next);
164      if (ev.window->next)
165        red=1;
166      last->next=ev.window->next;
167    }
168    if (!first)
169      first=ev.window;
170    else
171    {
172      Jwindow *last=first;
173      for (; last->next; last=last->next);
174      last->next=ev.window;
175    }
176    ev.window->next=NULL;
177    if (red)
178    {
179      Jwindow *j=ev.window;
180/*      screen->AddDirty(j->x,j->y,j->x+j->l,j->y+j->h);
181      for (p=first; p!=j; p=p->next)
182        p->screen->AddDirty(j->x-p->x,j->y-p->y,j->x+j->l-p->x,j->y+j->h-p->y); */
183      j->screen->AddDirty(0, 0, j->l, j->h);
184      flush_screen();
185    }
186
187        state=dragging;
188        drag_window=ev.window;
189        drag_mousex=ev.window->x-ev.mouse_move.x;
190        drag_mousey=ev.window->y-ev.mouse_move.y;
191        ev.type=EV_SPURIOUS;
192      } else if (ev.window)
193        ev.window->inm->handle_event(ev,ev.window);
194    }
195  } else if (state==dragging)
196  {
197    ev.window=drag_window;
198    if (ev.type==EV_MOUSE_BUTTON && ev.mouse_button==0)  // user released the mouse
199    {
200      state=inputing;
201      ev.type=EV_SPURIOUS;
202    } else if (ev.type==EV_MOUSE_MOVE)
203    {
204       move_window(drag_window,ev.mouse_move.x+drag_mousex,ev.mouse_move.y+drag_mousey);
205       flush_screen();
206       ev.type=EV_DRAG_WINDOW;
207       ev.window_position.x=ev.mouse_move.x+drag_mousex;
208       ev.window_position.y=ev.mouse_move.y+drag_mousey;
209    }
210  }
211  if (ev.type == EV_REDRAW)
212  {
213    for (j=first; j; j=j->next)
214       j->screen->AddDirty(ev.redraw.x1 - j->x, ev.redraw.y1 - j->y,
215                           ev.redraw.x2 + 1 - j->x, ev.redraw.y2 + 1 - j->y);
216    screen->AddDirty(ev.redraw.x1, ev.redraw.y1, ev.redraw.x2 + 1, ev.redraw.y2 + 1);
217    flush_screen();
218    ev.type=EV_SPURIOUS;   // we took care of this one by ourselves.
219  }
220}
221
222void Jwindow::resize(int L, int H)
223{
224  screen->SetSize(vec2i(L,H));
225  l=L; h=H;
226}
227
228void WindowManager::resize_window(Jwindow *j, int l, int h)
229{
230  Jwindow *p;
231  screen->AddDirty(j->x, j->y, j->x + j->l, j->y + j->h);
232  for (p=first; p!=j; p=p->next)
233    p->screen->AddDirty(j->x - p->x, j->y - p->y, j->x + j->l - p->x, j->y + j->h - p->y);
234  j->resize(l,h);
235  if (!frame_suppress)
236  j->redraw();
237}
238
239void WindowManager::move_window(Jwindow *j, int x, int y)
240{
241    screen->AddDirty(j->x, j->y, j->x + j->l, j->y + j->h);
242    for(Jwindow *p = first; p != j; p = p->next)
243        p->screen->AddDirty(j->x - p->x, j->y - p->y,
244                            j->x + j->l - p->x, j->y + j->h - p->y);
245    j->x = x;
246    j->y = y;
247    j->screen->AddDirty(0, 0, j->l, j->h);
248}
249
250WindowManager::WindowManager(image *Screen, palette *Pal, int Hi,
251                             int Med, int Low, JCFont *Font)
252{
253    wm = this;
254    screen = Screen;
255    hi = Hi; low = Low; med = Med; first = NULL; pal = Pal; grab = NULL;
256    bk = pal->find_closest(0, 0, 0);
257    state = inputing; fnt = Font;  wframe_fnt = Font;
258    memset(key_state, 0, sizeof(key_state));
259    eh = new event_handler(screen, pal);
260    frame_suppress = 0;
261}
262
263WindowManager::~WindowManager()
264{
265    delete eh;
266    while(first)
267        close_window(first);
268    wm = NULL;
269}
270
271void WindowManager::add_window(Jwindow *win)
272{
273    if(!first)
274        first = win;
275    else
276    {
277        Jwindow *tmp = first;
278        while(tmp->next)
279            tmp = tmp->next;
280        tmp->next = win;
281        win->next = NULL;
282    }
283}
284
285void WindowManager::remove_window(Jwindow *win)
286{
287    if(grab == win)
288        grab = NULL;
289
290    // close the window we were dragging
291    if(state == dragging && win == drag_window)
292        state = inputing;
293
294    if(first == win)
295        first = first->next;
296    else
297    {
298        Jwindow * search;
299        for(search = first; search->next != win; search = search->next)
300            search->screen->AddDirty(win->x - search->x,
301                                     win->y - search->y,
302                                     win->x + win->l - search->x,
303                                     win->y + win->h - search->y);
304        search->screen->AddDirty(win->x - search->x, win->y - search->y,
305                                 win->x + win->l - search->x,
306                                 win->y + win->h - search->y);
307        search->next = win->next;
308    }
309
310    screen->AddDirty(win->x, win->y, win->x + win->l, win->y + win->h);
311}
312
313Jwindow * WindowManager::new_window(int x, int y, int l, int h,
314                                     ifield * fields, char const *name)
315{
316    if(x > screen->Size().x - 4)
317        x = screen->Size().x - 25;
318    if(y > screen->Size().y - 4)
319        y = screen->Size().y - 10;
320
321    Jwindow * j = new Jwindow (x, y, l, h, fields, name);
322    j->show();
323
324    return j;
325}
326
327void WindowManager::flush_screen()
328{
329    Jwindow *p, *q;
330
331    int mx = 0, my = 0;
332    image *mouse_pic = NULL, *mouse_save = NULL;
333
334    if(has_mouse())
335    {
336        mouse_pic = eh->mouse_sprite()->visual;
337        mouse_save = eh->mouse_sprite()->save;
338        mx = eh->mouse->drawx();
339        my = eh->mouse->drawy();
340
341        screen->put_part(mouse_save, 0, 0, mx, my,
342                         mx + mouse_pic->Size().x - 1,
343                         my + mouse_pic->Size().y - 1);
344        mouse_pic->put_image(screen, mx, my, 1);
345    }
346
347    for(p = first; p; p = p->next)
348        if(!p->is_hidden())
349            screen->delete_dirty(p->x, p->y, p->x + p->l, p->y + p->h);
350    update_dirty(screen);
351
352    if(has_mouse())
353        mouse_save->put_image(screen, mx, my);
354
355    for(p = first; p; p = p->next)
356    {
357        if(p->is_hidden())
358            continue;
359
360        if(has_mouse())
361        {
362            p->screen->put_part(mouse_save, 0, 0, mx - p->x, my - p->y,
363                                mx - p->x + mouse_pic->Size().x - 1,
364                                my - p->y + mouse_pic->Size().y - 1);
365            if(has_mouse())
366                mouse_pic->put_image(p->screen, mx - p->x, my - p->y, 1);
367        }
368
369//          screen->delete_dirty(p->x, p->y, p->x+p->l, p->y+p->h);
370        for(q = p->next; q; q = q->next)
371            if(!q->is_hidden())
372                p->screen->delete_dirty(q->x - p->x, q->y - p->y,
373                                        q->x + q->l - p->x, q->y + q->h - p->y);
374        update_dirty(p->screen, p->x, p->y);
375        if(has_mouse())
376            mouse_save->put_image(p->screen, mx - p->x, my - p->y, 0);
377    }
378}
379
380Jwindow::Jwindow(char const *name)
381{
382    _x1 = left_border();
383    _y1 = jw_top + 5;
384    _x2 = _y2 = 0;
385
386    _hidden = true;
387    _moveable = true;
388    // property.flags = JWINDOW_NOAUTOHIDE_FLAG;
389
390    inm = new InputManager(this, NULL);
391    reconfigure();
392
393    screen = NULL;
394    next = NULL;
395
396    _name = NULL;
397    if(name)
398        _name = strdup(name);
399    wm->add_window(this);
400}
401
402Jwindow::Jwindow(int X, int Y, int L, int H, ifield *f, char const *name)
403{
404    l = 0;
405    h = 0;
406    _hidden = false;
407    _moveable = true;
408
409    _x1 = left_border();
410    _y1 = name ? top_border() : jw_top + 5;
411
412    screen = NULL;
413    inm = new InputManager(screen, f);
414    reconfigure(); /* FIXME: TODO */
415
416    l = L >= 0 ? L + left_border() : l - L;
417    h = H >= 0 ? H + top_border() : h - H;
418    y = Y >= 0 ? Y : yres - h + Y - top_border() - bottom_border() - 1;
419    x = X >= 0 ? X : xres - l + X - left_border() - right_border() - 1;
420
421    backg = wm->medium_color();
422
423    _x2 = l - 1;
424    _y2 = h - 1;
425    l += right_border();
426    h += bottom_border();
427
428    if(L == -1)
429        if(l < 15 + left_border() + right_border())
430            l = 15 + left_border() + right_border();
431    if(H == -1)
432        if(h < top_border() + bottom_border())
433            h = top_border() + bottom_border();
434    screen = new image(vec2i(l, h), NULL, 2);
435    screen->clear(backg);
436    // Keep this from getting destroyed when image list is cleared
437    image_list.unlink(screen);
438    inm->screen = screen;
439
440    next = NULL;
441
442    _name = NULL;
443    if(name)
444        _name = strdup(name);
445
446    wm->add_window(this);
447    if(!wm->frame_suppress)
448        redraw();
449}
450
451Jwindow::~Jwindow()
452{
453    wm->remove_window(this);
454    local_close();
455    if(screen)
456        delete screen;
457    delete inm;
458    if(_name)
459        free(_name);
460}
461
462void Jwindow::reconfigure()
463{
464    int x1, y1, x2, y2;
465    ifield *i;
466    l = 2;
467    h = 2;
468    for(i = inm->first; i; i = i->next)
469    {
470        i->set_owner(this);
471        i->area(x1, y1, x2, y2);
472        if ((int)y2 > (int)h)
473            h = y2;
474        if ((int)x2 > (int)l)
475            l = x2;
476    }
477}
478
479void Jwindow::local_close()
480{
481    ;
482}
483
484void Jwindow::redraw()
485{
486    int hi = wm->bright_color ();
487    int med = wm->medium_color ();
488    int low = wm->dark_color ();
489    JCFont * fnt = wm->frame_font ();
490
491    if(_name)
492    {
493        if (right_border() >= 1)
494        {
495            screen->widget_bar (0, 0, l - 1, h - 1, hi, med, low);
496            if (right_border() >= 3)
497                screen->widget_bar (right_border() - 1, top_border() - 1,
498                                l - left_border(), h - bottom_border(), low,
499                                med, hi);
500
501          else
502            screen->line (left_border() - 1, top_border() - 1,
503                           right_border() - 1, top_border() - 1, low);
504        }
505      screen->rectangle (2, 2, top_border() - 2, top_border() - 3,
506                           wm->black ());
507      screen->widget_bar (3, 3, top_border() - 3, top_border() - 4, hi, med, low);     // draws the 'close' button
508    }
509
510  else
511    {
512      if (right_border() >= 1)
513        {
514          screen->widget_bar (0, 0, l - 1, h - 1, hi, med, low);
515          if (right_border() >= 3)
516            screen->widget_bar (right_border() - 1, jw_top + 4,
517                                l - left_border(), h - bottom_border(), low,
518                                med, hi);
519
520          else
521            screen->line (left_border() - 1, jw_top + 4, right_border() - 1,
522                           jw_top + 4, low);
523        }
524      screen->rectangle (1, 1, 4, 4, wm->black ());
525      screen->widget_bar (2, 2, 3, 3, hi, med, low);   // draws the 'close' button
526    }
527  if (_name && _name[0])
528    {
529      screen->bar (top_border(), 1,
530                    top_border() + fnt->width() * strlen (_name) + 1,
531                    top_border() - 2, med);
532      fnt->put_string (screen, top_border() + 1, 1, _name, low);
533    }
534  screen->bar (x1 (), y1 (), x2 (), y2 (), backg);  // clear 'client' region
535  inm->redraw ();
536}
537
538int Jwindow::left_border()
539{
540    return frame_left();
541}
542
543int Jwindow::right_border()
544{
545    return frame_right();
546}
547
548int Jwindow::top_border()
549{
550    return wm->font()->height() + frame_top();
551}
552
553int Jwindow::bottom_border()
554{
555    return frame_bottom();
556}
557
558
559ifield *InputManager::unlink(int id)     // unlinks ID from fields list and return the pointer to it
560{
561  for (ifield *i=first,*last=NULL; i; i=i->next)
562  {
563    if (i->id==id)
564    {
565      if (i==first)
566    first=first->next;
567      else
568        last->next=i->next;
569      if (active==i)
570        active=first;
571      return i;
572    }
573    ifield *x=i->unlink(id);
574    if (x) return x;
575    last=i;
576  }
577  return NULL;   // no such id
578}
579
580InputManager::~InputManager()
581{ ifield *i;
582  while (first)
583  { i=first;
584    first=first->next;
585    delete i;
586  }
587}
588
589void InputManager::clear_current()
590{
591    if(owner)
592        screen = owner->screen;
593    if(active)
594        active->draw(0, screen);
595    active = NULL;
596}
597
598void InputManager::handle_event(event &ev, Jwindow *j)
599{
600  ifield *i,*in_area=NULL;
601  int x1,y1,x2,y2;
602
603  if(owner)
604      screen = owner->screen;
605
606  if (j)
607  {
608    ev.mouse_move.x-=j->x;
609    ev.mouse_move.y-=j->y;
610    cur=j;
611  }
612
613  if (!grab)
614  {
615    if ((ev.type==EV_MOUSE_BUTTON && ev.mouse_button==1) || ev.type==EV_MOUSE_MOVE)
616    {
617      for (i=first; i; i=i->next)
618      {
619    i->area(x1,y1,x2,y2);
620    if (ev.mouse_move.x>=x1 && ev.mouse_move.y>=y1 &&
621        ev.mouse_move.x<=x2 && ev.mouse_move.y<=y2)
622        in_area=i;
623      }
624      if (in_area!=active && (no_selections_allowed || (in_area && in_area->selectable())))
625      {
626    if (active)
627          active->draw(0,screen);
628
629    active=in_area;
630
631    if (active)
632      active->draw(1,screen);
633      }
634    }
635    if (ev.type==EV_KEY && ev.key==JK_TAB && active)
636    {
637      active->draw(0,screen);
638      do
639      {
640    active=active->next;
641    if (!active) active=first;
642      } while (active && !active->selectable());
643      active->draw(1,screen);
644    }
645  } else active=grab;
646
647  if (active)
648  {
649    if (ev.type!=EV_MOUSE_MOVE && ev.type!=EV_MOUSE_BUTTON)
650      active->handle_event(ev,screen,this);
651    else
652    {
653      active->area(x1,y1,x2,y2);
654      if (grab || (ev.mouse_move.x>=x1 && ev.mouse_move.y>=y1 &&
655          ev.mouse_move.x<=x2 && ev.mouse_move.y<=y2))
656      {
657    if (j)
658      active->handle_event(ev,screen,j->inm);
659    else active->handle_event(ev,screen,this);
660      }
661    }
662  }
663
664  if (j)
665  {
666    ev.mouse_move.x+=j->x;
667    ev.mouse_move.y+=j->y;
668  }
669}
670
671void InputManager::allow_no_selections()
672{
673  no_selections_allowed=1;
674}
675
676void InputManager::redraw()
677{
678    ifield *i;
679    if(owner)
680        screen = owner->screen;
681    for(i = first; i; i = i->next)
682        i->draw_first(screen);
683    if(active)
684        active->draw(1, screen);
685}
686
687InputManager::InputManager(image *Screen, ifield *First)
688{
689    no_selections_allowed = 0;
690    cur = NULL;
691    grab = NULL;
692    owner = NULL;
693    screen = Screen;
694    active = first = First;
695    while(active && !active->selectable())
696        active = active->next;
697    if(screen)
698        redraw();
699}
700
701InputManager::InputManager(Jwindow *Owner, ifield *First)
702{
703    no_selections_allowed = 0;
704    cur = NULL;
705    grab = NULL;
706    owner = Owner;
707    screen = NULL;
708    active = first = First;
709    while(active && !active->selectable())
710        active = active->next;
711}
712
713void InputManager::grab_focus(ifield *i)
714{ grab=i;
715  if (cur)
716    wm->grab_focus(cur);
717}
718
719void InputManager::release_focus()
720{ grab=NULL;
721  if (cur)
722    wm->release_focus();
723}
724
725void InputManager::remap(filter *f)
726{
727  for (ifield *i=first; i; i=i->next)
728   i->remap(f);
729  redraw();
730}
731
732void InputManager::add(ifield *i)
733{ ifield *f=first;
734  if (i->selectable())
735  {
736    if (!f)
737      first=i;
738    else
739    {
740      while (f->next) f=f->next;
741      f->next=i;
742    }
743  }
744}
745
746ifield *InputManager::get(int id)
747{
748  ifield *f;
749  for (f=first; f; f=f->next)
750  {
751    ifield *ret=f->find(id);
752    if (ret) return ret;
753  }
754  return NULL;
755}
756
757ifield::ifield()
758{
759    owner = NULL;
760    x = 0;
761    y = 0;
762    next = NULL;
763    id = 0;
764}
765
766ifield::~ifield()
767{
768    ;
769}
770
771/* re-position the control with respect to the "client" area of the window */
772void ifield::set_owner(Jwindow * newowner)
773{
774    if(owner)
775        move(x - owner->x1(), y - owner->y1());
776    owner = newowner;
777    if(owner)
778        move(x + owner->x1(), y + owner->y1());
779}
780
Note: See TracBrowser for help on using the repository browser.