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

Last change on this file since 579 was 579, checked in by Sam Hocevar, 8 years ago

imlib: refactor the Filter and ColorFilter? classes.

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