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

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

style: remove trailing spaces, fix copyright statements.

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