source: abuse/trunk/src/imlib/pmenu.cpp @ 682

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

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

File size: 10.6 KB
RevLine 
[56]1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
[494]4 *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
[56]5 *
6 *  This software was released into the Public Domain. As with most public
[555]7 *  domain software, no warranty is made or implied by Crack dot Com, by
8 *  Jonathan Clark, or by Sam Hocevar.
[56]9 */
10
[555]11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
[56]14
[131]15#include <string.h>
16
[512]17#include "common.h"
18
[481]19#include "pmenu.h"
[2]20
21void pmenu::move(int new_x, int new_y)
22{
23  wm->move_window(bar,new_x,new_y);
24}
25
[106]26pmenu::pmenu(int X, int Y, pmenu_item *first, image *screen)
[124]27{
28  top=first;
29  active=NULL;
[2]30
[682]31  ivec2 caa, cbb;
[665]32  screen->GetClip(caa, cbb);
33  if (caa.x<X) caa.x=X;
34  int w = cbb.x - caa.x - Jwindow::left_border() - Jwindow::right_border();
[120]35  int h = Jwindow::top_border() + Jwindow::bottom_border();
[2]36
[682]37  bar = wm->CreateWindow(ivec2(X, Y), ivec2(w, 0), NULL);
[109]38  bar->freeze();  // can't drag this window
[682]39  bar->m_surf->WidgetBar(ivec2(0, 0), ivec2(w - 1, h - 1),
[655]40                         wm->bright_color(), wm->medium_color(),
41                         wm->dark_color());
[2]42
43  int total=0,tx,tw;
44  pmenu_item *p=top;
[494]45  for (; p; p=p->next) total++;
[2]46
47  tw=w/(total+1);
48  tx=tw/2;
49
[494]50  for (p=top; p; p=p->next,tx+=tw)
[124]51    p->draw_self(bar,itemx(p),1,itemw(p),1,p==active);
[2]52/*  }
53  else
54  {
[494]55    for (p=top; p; p=p->next,tx+=tw)
[106]56      p->draw(bar,itemx(p),1,itemw(p),1,p==active);
[2]57  }*/
[124]58
[2]59}
60
[39]61pmenu_item::pmenu_item(int ID, char const *Name, char const *on_off_flag, int Hotkey, pmenu_item *Next)
[124]62{
[2]63  xp=-1;
[124]64  id=ID;
[2]65  hotkey=Hotkey;
66  on_off=on_off_flag;
67  if (Name)
[131]68    n = strdup(Name);
[2]69  else n=NULL;
70  next=Next;
71  sub=NULL;
72}
73
[39]74pmenu_item::pmenu_item(char const *Name, psub_menu *Sub, pmenu_item *Next, int xpos)
[2]75{
76  xp=xpos;
77  id=0; hotkey=-1;
78  next=Next;
79  on_off=NULL;
80  CONDITION(Name,"Sub menu cannot have a NULL name");
[131]81  n = strdup(Name);
[2]82  sub=Sub;
83}
84
[124]85pmenu_item *pmenu_item::find_id(int search_id)
86{
[2]87  if (id==search_id) return this;
88  else if (sub) return sub->find_id(search_id);
89  else return NULL;
90}
91
92pmenu_item *pmenu_item::find_key(int key)
93{
94  if (key==hotkey && hotkey!=-1) return this;
95  else if (sub) return sub->find_key(key);
96  else return NULL;
97}
98
99pmenu::~pmenu()
100{
101  while (top)
102  {
103    pmenu_item *p=top;
104    top=top->next;
105    delete p;
106  }
107  if (bar) wm->close_window(bar);
108}
109
[124]110psub_menu::~psub_menu()
111{
112  if (win)
[2]113    wm->close_window(win);
[124]114
[2]115  while (first)
116  {
117    pmenu_item *tmp=first;
118    first=first->next;
119    delete tmp;
120  }
121}
122
123pmenu_item *psub_menu::find_id(int search_id)
124{
[494]125  for (pmenu_item *f=first; f; f=f->next)
[2]126  {
127    pmenu_item *ret=f->find_id(search_id);
128    if (ret) return ret;
129  }
130  return NULL;
131}
132
133pmenu_item *psub_menu::find_key(int key)
134{
[494]135  for (pmenu_item *f=first; f; f=f->next)
[2]136  {
137    pmenu_item *ret=f->find_key(key);
138    if (ret) return ret;
139  }
140  return NULL;
141}
142
143
[120]144void psub_menu::hide(Jwindow *parent, int x, int y)
[2]145{
146  int w,h;
[106]147  calc_size(w,h);
[682]148  ivec2 caa, cbb;
[665]149  main_screen->GetClip(caa, cbb);
[518]150  // FIXME: is this correct? it looks like it used to be incorrect
151  // before the GetClip refactoring...
[665]152  if (w+x>cbb.x-1)
153    x=cbb.x-1-w;
[2]154
155  if (win)
156  {
157    if (active!=-1)
158    {
159      int w,h;
[106]160      calc_size(w,h);
[668]161      item_num(active)->draw(win,x+3,y+3+active*(wm->font()->Size().y+1),w-6,0,0);
[2]162    }
163    wm->close_window(win);
164    win=NULL;
165  }
166}
167
[106]168void psub_menu::calc_size(int &w, int &h)
[2]169{
[682]170    ivec2 ts = wm->font()->Size();
[2]171  w=h=0;
[494]172  for (pmenu_item *p=first; p; p=p->next)
[2]173  {
174    if (p->name())
175    {
[668]176      int l=strlen(p->name())*ts.x+8;
177      if (p->on_off) l+=ts.x*4;
[124]178      if (l>w) w=l;
[2]179    }
180    h++;
181  }
[668]182  h=h*(ts.y+1)+8;
[2]183}
184
[120]185void psub_menu::draw(Jwindow *parent, int x, int y)
[2]186{
187  if (win) wm->close_window(win);
188
189  int w,h,i=0;
[106]190  calc_size(w,h);
[682]191  ivec2 caa, cbb;
[665]192  main_screen->GetClip(caa, cbb);
193  if (parent->m_pos.x + w + x >= cbb.x)
194    x=cbb.x-1-w-parent->m_pos.x;
195  if (h+y+parent->m_pos.y>=cbb.y)
[162]196  {
[671]197    if (parent->m_pos.y+parent->m_size.y+wm->font()->Size().y>=cbb.y)
[2]198      y=-h;
[668]199    else y=y-h+wm->font()->Size().y+5;
[162]200  }
[2]201
[124]202
[682]203  win=wm->CreateWindow(parent->m_pos + ivec2(x, y),
204             ivec2(w - Jwindow::left_border() - Jwindow::right_border(),
[671]205                   h - Jwindow::top_border() - Jwindow::bottom_border()),
206             NULL);
[109]207  win->freeze();
[682]208  win->m_surf->WidgetBar(ivec2(0, 0), ivec2(w - 1, h - 1),
[655]209                         wm->bright_color(), wm->medium_color(),
210                         wm->dark_color());
[2]211
212  int has_flags=0;
213  pmenu_item *p=first;
[494]214  for (; p; p=p->next) if (p->on_off) has_flags=1;
[668]215  x = has_flags ? 3 + wm->font()->Size().x : 3;
216  y = 3;
[124]217
[668]218  for (p=first; p; p=p->next,i++,y+=wm->font()->Size().y+1)
[106]219    p->draw(win,x,y,w-6,0,i==active);
[2]220
221}
222
[120]223void pmenu_item::draw_self(Jwindow *parent, int x, int y, int w, int top, int active)
[2]224{
225  int bx=x;
[668]226  if (on_off) bx=x-wm->font()->Size().x;
[2]227
228  if (!n)
229  {
[668]230    int h=wm->font()->Size().y;
[682]231    parent->m_surf->WidgetBar(ivec2(x, y + h / 2 - 1),
232                              ivec2(x + w - 1, y + h / 2), wm->dark_color(),
[655]233                              wm->medium_color(), wm->bright_color());
[2]234  } else
235  {
236    if (active)
237    {
238      if (xp!=-1)
[668]239        parent->m_surf->xor_bar(bx,y,x+w-1,y+wm->font()->Size().y+1,wm->dark_color());
[2]240      else
241      {
[682]242    parent->m_surf->Bar(ivec2(bx, y),
243                        ivec2(x + w - 1, y + wm->font()->Size().y + 1),
[655]244                        wm->dark_color());
[682]245    wm->font()->PutString(parent->m_surf, ivec2(x+1, y+1), n, wm->medium_color());
246    if (on_off && *on_off) wm->font()->PutString(parent->m_surf, ivec2(bx+1, y+1), "*", wm->medium_color());
[2]247      }
248    } else
249    {
250      if (xp!=-1)
[668]251        parent->m_surf->xor_bar(bx,y,x+w-1,y+wm->font()->Size().y+1,wm->dark_color());
[2]252      else
253      {
[682]254    parent->m_surf->Bar(ivec2(bx, y),
255                        ivec2(x + w - 1, y + wm->font()->Size().y + 1),
[655]256                        wm->medium_color());
[682]257    wm->font()->PutString(parent->m_surf, ivec2(x + 1, y + 1), n, wm->bright_color());
258    if (on_off && *on_off) wm->font()->PutString(parent->m_surf, ivec2(bx + 1, y + 1), "*", wm->bright_color());
[2]259      }
260    }
261  }
262}
263
[120]264void pmenu_item::draw(Jwindow *parent, int x, int y, int w, int top,
[124]265              int active)
266{
[2]267  if (n)
268  {
269    if (active)
[124]270    {
[106]271      draw_self(parent,x,y,w,top,active);
[2]272      if (sub)
273      {
[124]274    if (top)
[668]275          sub->draw(parent,x,y+wm->font()->Size().y+2);
[124]276    else
277      sub->draw(parent,x+w,y);
[2]278      }
279    }
280    else
281    {
282      if (sub)
283      {
[124]284    if (top)
[668]285          sub->hide(parent,x,y+wm->font()->Size().y+2);
[124]286    else
287      sub->hide(parent,x+w,y);
[2]288      }
[106]289      draw_self(parent,x,y,w,top,active);
[2]290
291    }
292
[106]293  } else draw_self(parent,x,y,w,top,active);
[2]294}
295
[106]296int pmenu::itemx(pmenu_item *p)
[2]297{
298  if (p->xp!=-1) return p->xp;
[644]299  int w=bar->m_surf->Size().x;
[2]300
[124]301
[4]302  int total=0,tw,i=0,x=0;
[494]303  for (pmenu_item *pp=top; pp; pp=pp->next,i++)
[2]304  { if (pp==p) x=i;
305    total++;
306  }
307
[124]308
309  tw=w/(total+1);
[2]310  return tw/2+x*tw;
311}
312
313
[106]314void pmenu::draw(image *screen, int top_only)
[2]315{
316
317}
318
319
[643]320int psub_menu::handle_event(Jwindow *parent, int x, int y, Event &ev)
[2]321{
322  int w,h;
[106]323  calc_size(w,h);
[2]324
[659]325  x=win->m_pos.x;
326  y=win->m_pos.y;
[2]327
328  int has_flags=0,dx=3;
[494]329  for (pmenu_item *p=first; p; p=p->next) if (p->on_off) has_flags=1;
[668]330  if (has_flags) dx+=wm->font()->Size().x;
[2]331
[668]332  int th=wm->font()->Size().y;
[2]333  if (ev.mouse_move.x>=x && ev.mouse_move.y>=y && ev.mouse_move.x<x+w && ev.mouse_move.y<y+h)
334  {
335    int new_active=(ev.mouse_move.y-y-3)/(th+1);
336    if (item_num(new_active)==NULL) new_active=-1;
337
338    if (new_active!=active)
339    {
340      if (active!=-1)
[106]341        item_num(active)->draw(win,dx,3+active*(th+1),w-6,0,0);
[2]342      active=new_active;
343      if (active!=-1)
[106]344        item_num(active)->draw(win,dx,3+active*(th+1),w-6,0,1);
[2]345    }
346    if (ev.type==EV_MOUSE_BUTTON)
347    {
348      if (active!=-1)
[106]349        return item_num(active)->handle_event(win,dx,3+active*(th+1),w-6,0,ev);
[2]350      else return 0;
351    } else return 1;
352  } else if (active!=-1)
[659]353    return item_num(active)->handle_event(win,win->m_pos.x+dx,win->m_pos.y+3+active*(th+1),w-6,0,ev);
[2]354  else return 0;
355
356
357}
358
[124]359int pmenu_item::handle_event(Jwindow *parent, int x, int y, int w, int top,
[643]360                 Event &ev)
[2]361{
[659]362  x+=parent->m_pos.x;
363  y+=parent->m_pos.y;
[2]364  if (ev.mouse_move.x>=x && ev.mouse_move.y>=y && ev.mouse_move.x<x+w &&
[668]365      ev.mouse_move.y<y+wm->font()->Size().y+2)
[2]366  {
367    if (sub) return 1;
[124]368    else
[2]369    {
370      if (ev.type==EV_MOUSE_BUTTON &&n)
[643]371        wm->Push(new Event(id,(char *)this));
[2]372      return 1;
[124]373    }
[2]374  } else if (sub)
[124]375  {
[2]376    if (top)
[668]377      return sub->handle_event(parent,x,y+wm->font()->Size().y+2,ev);
[106]378    else return sub->handle_event(parent,x+w,y,ev);
[2]379  } else return 0;
380}
381
[124]382pmenu_item *pmenu::inarea(int mx, int my, image *screen)
383{
[659]384  mx-=bar->m_pos.x;
385  my-=bar->m_pos.y;
[644]386  if (mx<0 || my<0 || mx>=bar->m_surf->Size().x || my>=bar->m_surf->Size().y) return NULL;
[124]387  else
[2]388  {
[494]389    for (pmenu_item *p=top; p; p=p->next)
[2]390    {
391      if (!p->next) return p;
[106]392      else if (itemx(p->next)>mx) return p;
[2]393    }
394    return NULL;
395  }
396}
397
[643]398int psub_menu::own_event(Event &ev)
[124]399{
[2]400  if (win && ev.window==win) return 1; else
[494]401    for (pmenu_item *p=first; p; p=p->next)
[124]402      if (p->own_event(ev))
403        return 1;
404  return 0;
[2]405}
406
[643]407int pmenu_item::own_event(Event &ev)
[124]408{
409  if (sub)
410    return sub->own_event(ev);
411  else return 0;
[2]412}
413
[124]414pmenu_item::~pmenu_item()
[129]415{ if (n) free(n); if (sub) delete sub;
[2]416}
417
[643]418int pmenu::handle_event(Event &ev, image *screen)
[2]419{
420  if (!active && ev.window!=bar) return 0;
[124]421/*
[2]422    int yes=0;
423    if (ev.window==bar) yes=1;    // event in top bar?
424    else
425    {
[494]426      for (pmenu_item *p=top; p && !yes; p=p->next)  // event in submenu?
[2]427      if (p->own_event(ev)) yes=1;
428    }
429    if (!yes) return 0;        // event is not for us...
430  }*/
431
432  switch (ev.type)
433  {
434    case EV_KEY :
435    {
[494]436      for (pmenu_item *p=top; p; p=p->next)
[124]437      {
438    pmenu_item *r=p->find_key(ev.key);
439    if (r)
440    {
[643]441      wm->Push(new Event(r->id,(char *)r));
[124]442      return 1;
443    }
[2]444      }
445      return 0;
446    } break;
447    case EV_MOUSE_MOVE :
448    {
[106]449      pmenu_item *new_selection=inarea(ev.mouse_move.x,ev.mouse_move.y,screen);
[124]450      if (!new_selection && active &&
451      active->handle_event(bar,itemx(active),1,itemw(active),1,ev))
452    return 1;
[2]453      else if (active!=new_selection)
454      {
[124]455    if (active)
456      active->draw(bar,itemx(active),1,itemw(active),1,0);
457    active=new_selection;
458    if (active)
459      active->draw(bar,itemx(active),1,itemw(active),1,1);
[2]460      }
461      if (active) return 1;
462      else return 0;
463    } break;
464    case EV_MOUSE_BUTTON :
465    {
[124]466      if (active)
[2]467      {
[106]468        if (active->handle_event(bar,itemx(active),1,itemw(active),1,ev))
[124]469    {
470      active->draw(bar,itemx(active),1,itemw(active),1,0);
471      active=NULL;
472      return 1;
473    } else return 0;
[2]474      }
475      else return 0;
476    } break;
477  }
478  return 0;
479}
480
481
Note: See TracBrowser for help on using the repository browser.