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

Last change on this file since 513 was 513, checked in by Sam Hocevar, 11 years ago

imlib: some more vec2i transition for simplicity.

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