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

Last change on this file was 682, checked in by Sam Hocevar, 12 years ago

core: rename vec2i to ivec2 and update matrix.h from Lol Engine.

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