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

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

imlib: refactor a few image methods so that they use vec2i.

File size: 10.6 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 "pmenu.h"
20
21void pmenu::move(int new_x, int new_y)
22{
23  wm->move_window(bar,new_x,new_y);
24}
25
26pmenu::pmenu(int X, int Y, pmenu_item *first, image *screen)
27{
28  top=first;
29  active=NULL;
30
31  int cx1, cy1, cx2, cy2;
32  screen->GetClip(cx1, cy1, cx2, cy2);
33  if (cx1<X) cx1=X;
34  int w = cx2 - cx1 - Jwindow::left_border() - Jwindow::right_border();
35  int h = Jwindow::top_border() + Jwindow::bottom_border();
36
37  bar=wm->new_window(X, Y, w, 0, NULL);
38  bar->freeze();  // can't drag this window
39  bar->m_surf->WidgetBar(vec2i(0, 0), vec2i(w - 1, h - 1),
40                         wm->bright_color(), wm->medium_color(),
41                         wm->dark_color());
42
43  int total=0,tx,tw;
44  pmenu_item *p=top;
45  for (; p; p=p->next) total++;
46
47  tw=w/(total+1);
48  tx=tw/2;
49
50  for (p=top; p; p=p->next,tx+=tw)
51    p->draw_self(bar,itemx(p),1,itemw(p),1,p==active);
52/*  }
53  else
54  {
55    for (p=top; p; p=p->next,tx+=tw)
56      p->draw(bar,itemx(p),1,itemw(p),1,p==active);
57  }*/
58
59}
60
61pmenu_item::pmenu_item(int ID, char const *Name, char const *on_off_flag, int Hotkey, pmenu_item *Next)
62{
63  xp=-1;
64  id=ID;
65  hotkey=Hotkey;
66  on_off=on_off_flag;
67  if (Name)
68    n = strdup(Name);
69  else n=NULL;
70  next=Next;
71  sub=NULL;
72}
73
74pmenu_item::pmenu_item(char const *Name, psub_menu *Sub, pmenu_item *Next, int xpos)
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");
81  n = strdup(Name);
82  sub=Sub;
83}
84
85pmenu_item *pmenu_item::find_id(int search_id)
86{
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
110psub_menu::~psub_menu()
111{
112  if (win)
113    wm->close_window(win);
114
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{
125  for (pmenu_item *f=first; f; f=f->next)
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{
135  for (pmenu_item *f=first; f; f=f->next)
136  {
137    pmenu_item *ret=f->find_key(key);
138    if (ret) return ret;
139  }
140  return NULL;
141}
142
143
144void psub_menu::hide(Jwindow *parent, int x, int y)
145{
146  int w,h;
147  calc_size(w,h);
148  int cx1, cy1, cx2, cy2;
149  main_screen->GetClip(cx1, cy1, cx2, cy2);
150  // FIXME: is this correct? it looks like it used to be incorrect
151  // before the GetClip refactoring...
152  if (w+x>cx2-1)
153    x=cx2-1-w;
154
155  if (win)
156  {
157    if (active!=-1)
158    {
159      int w,h;
160      calc_size(w,h);
161      item_num(active)->draw(win,x+3,y+3+active*(wm->font()->height()+1),w-6,0,0);
162    }
163    wm->close_window(win);
164    win=NULL;
165  }
166}
167
168void psub_menu::calc_size(int &w, int &h)
169{
170  int tw=wm->font()->width(),th=wm->font()->height();
171  w=h=0;
172  for (pmenu_item *p=first; p; p=p->next)
173  {
174    if (p->name())
175    {
176      int l=strlen(p->name())*tw+8;
177      if (p->on_off) l+=tw*4;
178      if (l>w) w=l;
179    }
180    h++;
181  }
182  h=h*(th+1)+8;
183}
184
185void psub_menu::draw(Jwindow *parent, int x, int y)
186{
187  if (win) wm->close_window(win);
188
189  int w,h,i=0;
190  calc_size(w,h);
191  int cx1, cy1, cx2, cy2;
192  main_screen->GetClip(cx1, cy1, cx2, cy2);
193  if (parent->x+w+x>=cx2)
194    x=cx2-1-w-parent->x;
195  if (h+y+parent->y>=cy2)
196  {
197    if (parent->y+parent->h+wm->font()->height()>=cy2)
198      y=-h;
199    else y=y-h+wm->font()->height()+5;
200  }
201
202
203  win=wm->new_window(parent->x+x,parent->y+y,
204             w - Jwindow::left_border() - Jwindow::right_border(),
205             h - Jwindow::top_border() - Jwindow::bottom_border(),
206                     NULL);
207  win->freeze();
208  win->m_surf->WidgetBar(vec2i(0, 0), vec2i(w - 1, h - 1),
209                         wm->bright_color(), wm->medium_color(),
210                         wm->dark_color());
211
212  int has_flags=0;
213  pmenu_item *p=first;
214  for (; p; p=p->next) if (p->on_off) has_flags=1;
215  x=has_flags ? 3+wm->font()->width() : 3;
216  y=3;
217
218  for (p=first; p; p=p->next,i++,y+=wm->font()->height()+1)
219    p->draw(win,x,y,w-6,0,i==active);
220
221}
222
223void pmenu_item::draw_self(Jwindow *parent, int x, int y, int w, int top, int active)
224{
225  int bx=x;
226  if (on_off) bx=x-wm->font()->width();
227
228  if (!n)
229  {
230    int h=wm->font()->height();
231    parent->m_surf->WidgetBar(vec2i(x, y + h / 2 - 1),
232                              vec2i(x + w - 1, y + h / 2), wm->dark_color(),
233                              wm->medium_color(), wm->bright_color());
234  } else
235  {
236    if (active)
237    {
238      if (xp!=-1)
239        parent->m_surf->xor_bar(bx,y,x+w-1,y+wm->font()->height()+1,wm->dark_color());
240      else
241      {
242    parent->m_surf->Bar(vec2i(bx, y),
243                        vec2i(x + w - 1, y + wm->font()->height() + 1),
244                        wm->dark_color());
245    wm->font()->put_string(parent->m_surf,x+1,y+1,n,wm->medium_color());
246    if (on_off && *on_off) wm->font()->put_string(parent->m_surf,bx+1,y+1,"*",wm->medium_color());
247      }
248    } else
249    {
250      if (xp!=-1)
251        parent->m_surf->xor_bar(bx,y,x+w-1,y+wm->font()->height()+1,wm->dark_color());
252      else
253      {
254    parent->m_surf->Bar(vec2i(bx, y),
255                        vec2i(x + w - 1, y + wm->font()->height() + 1),
256                        wm->medium_color());
257    wm->font()->put_string(parent->m_surf,x+1,y+1,n,wm->bright_color());
258    if (on_off && *on_off) wm->font()->put_string(parent->m_surf,bx+1,y+1,"*",wm->bright_color());
259      }
260    }
261  }
262}
263
264void pmenu_item::draw(Jwindow *parent, int x, int y, int w, int top,
265              int active)
266{
267  if (n)
268  {
269    if (active)
270    {
271      draw_self(parent,x,y,w,top,active);
272      if (sub)
273      {
274    if (top)
275          sub->draw(parent,x,y+wm->font()->height()+2);
276    else
277      sub->draw(parent,x+w,y);
278      }
279    }
280    else
281    {
282      if (sub)
283      {
284    if (top)
285          sub->hide(parent,x,y+wm->font()->height()+2);
286    else
287      sub->hide(parent,x+w,y);
288      }
289      draw_self(parent,x,y,w,top,active);
290
291    }
292
293  } else draw_self(parent,x,y,w,top,active);
294}
295
296int pmenu::itemx(pmenu_item *p)
297{
298  if (p->xp!=-1) return p->xp;
299  int w=bar->m_surf->Size().x;
300
301
302  int total=0,tw,i=0,x=0;
303  for (pmenu_item *pp=top; pp; pp=pp->next,i++)
304  { if (pp==p) x=i;
305    total++;
306  }
307
308
309  tw=w/(total+1);
310  return tw/2+x*tw;
311}
312
313
314void pmenu::draw(image *screen, int top_only)
315{
316
317}
318
319
320int psub_menu::handle_event(Jwindow *parent, int x, int y, Event &ev)
321{
322  int w,h;
323  calc_size(w,h);
324  int cx1, cy1, cx2, cy2;
325  main_screen->GetClip(cx1, cy1, cx2, cy2);
326
327  x=win->x;
328  y=win->y;
329
330  int has_flags=0,dx=3;
331  for (pmenu_item *p=first; p; p=p->next) if (p->on_off) has_flags=1;
332  if (has_flags) dx+=wm->font()->width();
333
334  int th=wm->font()->height();
335  if (ev.mouse_move.x>=x && ev.mouse_move.y>=y && ev.mouse_move.x<x+w && ev.mouse_move.y<y+h)
336  {
337    int new_active=(ev.mouse_move.y-y-3)/(th+1);
338    if (item_num(new_active)==NULL) new_active=-1;
339
340    if (new_active!=active)
341    {
342      if (active!=-1)
343        item_num(active)->draw(win,dx,3+active*(th+1),w-6,0,0);
344      active=new_active;
345      if (active!=-1)
346        item_num(active)->draw(win,dx,3+active*(th+1),w-6,0,1);
347    }
348    if (ev.type==EV_MOUSE_BUTTON)
349    {
350      if (active!=-1)
351        return item_num(active)->handle_event(win,dx,3+active*(th+1),w-6,0,ev);
352      else return 0;
353    } else return 1;
354  } else if (active!=-1)
355    return item_num(active)->handle_event(win,win->x+dx,win->y+3+active*(th+1),w-6,0,ev);
356  else return 0;
357
358
359}
360
361int pmenu_item::handle_event(Jwindow *parent, int x, int y, int w, int top,
362                 Event &ev)
363{
364  x+=parent->x;
365  y+=parent->y;
366  if (ev.mouse_move.x>=x && ev.mouse_move.y>=y && ev.mouse_move.x<x+w &&
367      ev.mouse_move.y<y+wm->font()->height()+2)
368  {
369    if (sub) return 1;
370    else
371    {
372      if (ev.type==EV_MOUSE_BUTTON &&n)
373        wm->Push(new Event(id,(char *)this));
374      return 1;
375    }
376  } else if (sub)
377  {
378    if (top)
379      return sub->handle_event(parent,x,y+wm->font()->height()+2,ev);
380    else return sub->handle_event(parent,x+w,y,ev);
381  } else return 0;
382}
383
384pmenu_item *pmenu::inarea(int mx, int my, image *screen)
385{
386  int cx1, cy1, cx2, cy2;
387  screen->GetClip(cx1, cy1, cx2, cy2);
388  mx-=bar->x;
389  my-=bar->y;
390  if (mx<0 || my<0 || mx>=bar->m_surf->Size().x || my>=bar->m_surf->Size().y) return NULL;
391  else
392  {
393    for (pmenu_item *p=top; p; p=p->next)
394    {
395      if (!p->next) return p;
396      else if (itemx(p->next)>mx) return p;
397    }
398    return NULL;
399  }
400}
401
402int psub_menu::own_event(Event &ev)
403{
404  if (win && ev.window==win) return 1; else
405    for (pmenu_item *p=first; p; p=p->next)
406      if (p->own_event(ev))
407        return 1;
408  return 0;
409}
410
411int pmenu_item::own_event(Event &ev)
412{
413  if (sub)
414    return sub->own_event(ev);
415  else return 0;
416}
417
418pmenu_item::~pmenu_item()
419{ if (n) free(n); if (sub) delete sub;
420}
421
422int pmenu::handle_event(Event &ev, image *screen)
423{
424  if (!active && ev.window!=bar) return 0;
425/*
426    int yes=0;
427    if (ev.window==bar) yes=1;    // event in top bar?
428    else
429    {
430      for (pmenu_item *p=top; p && !yes; p=p->next)  // event in submenu?
431      if (p->own_event(ev)) yes=1;
432    }
433    if (!yes) return 0;        // event is not for us...
434  }*/
435
436  switch (ev.type)
437  {
438    case EV_KEY :
439    {
440      for (pmenu_item *p=top; p; p=p->next)
441      {
442    pmenu_item *r=p->find_key(ev.key);
443    if (r)
444    {
445      wm->Push(new Event(r->id,(char *)r));
446      return 1;
447    }
448      }
449      return 0;
450    } break;
451    case EV_MOUSE_MOVE :
452    {
453      pmenu_item *new_selection=inarea(ev.mouse_move.x,ev.mouse_move.y,screen);
454      if (!new_selection && active &&
455      active->handle_event(bar,itemx(active),1,itemw(active),1,ev))
456    return 1;
457      else if (active!=new_selection)
458      {
459    if (active)
460      active->draw(bar,itemx(active),1,itemw(active),1,0);
461    active=new_selection;
462    if (active)
463      active->draw(bar,itemx(active),1,itemw(active),1,1);
464      }
465      if (active) return 1;
466      else return 0;
467    } break;
468    case EV_MOUSE_BUTTON :
469    {
470      if (active)
471      {
472        if (active->handle_event(bar,itemx(active),1,itemw(active),1,ev))
473    {
474      active->draw(bar,itemx(active),1,itemw(active),1,0);
475      active=NULL;
476      return 1;
477    } else return 0;
478      }
479      else return 0;
480    } break;
481  }
482  return 0;
483}
484
485
Note: See TracBrowser for help on using the repository browser.