source: abuse/trunk/src/imlib/scroller.cpp @ 129

Last change on this file since 129 was 129, checked in by Sam Hocevar, 15 years ago
  • Get rid of jmalloc and replace it with standard malloc. Modern operating systems certainly perform a lot better than this custom implementation, and we have superior tools (eg. valgrind) to debug and profile memory usage without interfering with the code itself.
File size: 15.0 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *
5 *  This software was released into the Public Domain. As with most public
6 *  domain software, no warranty is made or implied by Crack dot Com or
7 *  Jonathan Clark.
8 */
9
10#include "config.h"
11
12#include "scroller.hpp"
13#define HS_ICON_W 10
14#define HS_ICON_H 8
15
16
17uint8_t hs_left_arrow[10*8]={
18    0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
19    0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
20    1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
21    1, 1, 1, 1, 2, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2,
22    0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
23    2, 0, 0, 0, 0};
24
25
26uint8_t hs_right_arrow[10*8]={
27    0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
28    0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
29    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1,
30    1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 0,
31    0, 0, 0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 2,
32    1, 1, 0, 0, 0};
33
34
35uint8_t vs_up_arrow[8*10]={
36    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0,
37    0, 0, 0, 1, 1, 1, 1, 2, 0, 0, 1, 2, 1, 1, 2,
38    1, 2, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 1, 1,
39    2, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 1,
40    1, 2, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0,
41    0, 2, 2, 0, 0};
42
43
44uint8_t vs_down_arrow[8*10]={
45    0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 1, 1, 2, 0,
46    0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 1, 1, 2,
47    0, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 1, 1,
48    2, 0, 0, 0, 1, 2, 1, 1, 2, 1, 2, 0, 0, 1, 1,
49    1, 1, 2, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0,
50    0, 0, 0, 0, 0};
51
52void show_icon(image *screen, int x, int y, int icw, int ich, uint8_t *buf)
53{
54  short cx1,cy1,cx2,cy2;
55  screen->get_clip(cx1,cy1,cx2,cy2);
56  uint8_t remap[3];
57  remap[0]=wm->medium_color();
58  remap[1]=wm->bright_color();
59  remap[2]=wm->dark_color();
60
61  screen->lock();
62  for (int yc=ich;yc;yc--,y++)
63  {
64    if (y>=cy1 && y<=cy2)
65    {
66      uint8_t *sl=screen->scan_line(y)+x;
67      for (int xc=icw,xo=x;xc;xc--,xo++,sl++,buf++)
68      {
69    if (xo>=cx1 && xo<=cx2)
70      *sl=remap[*buf];
71      }
72    }
73  }
74  screen->add_dirty(x,y,x+icw-1,y+ich-1);
75  screen->unlock();
76}
77
78scroller::scroller(int X, int Y, int ID, int L, int H, int Vert, int Total_items, ifield *Next)
79{  x=X; y=Y; id=ID; next=Next;  l=L; h=H;  sx=0;  t=Total_items;  drag=-1; vert=Vert;
80}
81
82
83void scroller::area(int &x1, int &y1, int &x2, int &y2)
84{
85  area_config();
86  x1=x-1; y1=y-1;
87  if (vert)
88  { x2=x+l+bw();  y2=y+h; }
89  else
90  { x2=x+l;  y2=y+h+bh(); }
91}
92
93void scroller::dragger_area(int &x1, int &y1, int &x2, int &y2)
94{
95  if (vert)
96  { x1=x+l; y1=y+bh(); x2=x+l+bw()-1; y2=y+h-bh()-1; }
97  else { x1=x+bw(); y1=y+h; x2=x+l-bw(); y2=y+h+bh()-1; }
98}
99
100int scroller::bh() { if (vert) return 15; else return 13; }
101int scroller::bw() { if (vert) return 12; else return 14; }
102
103uint8_t *scroller::b1()
104{
105  if (vert) return vs_up_arrow;
106  else return hs_left_arrow;
107}
108
109uint8_t *scroller::b2()
110{
111  if (vert) return vs_down_arrow;
112  else return hs_right_arrow;
113}
114
115
116void scroller::draw_first(image *screen)
117{
118  if (sx>=t) sx=t-1;
119  draw(0,screen);
120  screen->widget_bar(b1x(),b1y(),b1x()+bw()-1,b1y()+bh()-1,
121            wm->bright_color(),wm->medium_color(),wm->dark_color());
122  screen->widget_bar(b2x(),b2y(),b2x()+bw()-1,b2y()+bh()-1,
123            wm->bright_color(),wm->medium_color(),wm->dark_color());
124  show_icon(screen,b1x()+2,b1y()+2,bw()-4,bh()-4,b1());
125  show_icon(screen,b2x()+2,b2y()+2,bw()-4,bh()-4,b2());
126
127  int x1,y1,x2,y2;
128  dragger_area(x1,y1,x2,y2);
129  screen->bar(x1,y1,x2,y2,wm->black());
130  screen->bar(x1+1,y1+1,x2-1,y2-1,wm->medium_color());
131  draw_widget(screen,0);
132  scroll_event(sx,screen);
133}
134
135void scroller::wig_area(int &x1, int &y1, int &x2, int &y2)
136{
137  int sx1,sy1,sx2,sy2;
138  dragger_area(sx1,sy1,sx2,sy2);
139  if (vert)
140  {
141    x1=x+l+1;
142    if (t<2)
143      y1=y+bh()+1;
144    else
145      y1=y+bh()+1+sx*(sy2-sy1+1-bh())/(t-1);
146  } else
147  {
148    if (t<2) x1=x+bw()+1;
149    else x1=x+bw()+1+sx*(sx2-sx1+1-bw())/(t-1);
150    y1=y+h+1;
151  }
152  x2=x1+bw()-3;
153  y2=y1+bh()-3;
154
155}
156
157
158void scroller::draw_widget(image *screen, int erase)
159{
160  int x1,y1,x2,y2;
161  wig_area(x1,y1,x2,y2);
162  if (erase)
163    screen->bar(x1,y1,x2,y2,wm->medium_color());
164  else
165    screen->widget_bar(x1,y1,x2,y2,
166              wm->bright_color(),wm->medium_color(),wm->dark_color());
167}
168
169void scroller::draw(int active, image *screen)
170{
171  int x1,y1,x2,y2;
172  area(x1,y1,x2,y2);
173  screen->rectangle(x1,y1,x2,y2,active ? wm->bright_color() : wm->dark_color());
174}
175
176
177void scroller::handle_event(event &ev, image *screen, InputManager *inm)
178{
179  int mx=ev.mouse_move.x,my=ev.mouse_move.y;
180  switch (ev.type)
181  {
182    case EV_MOUSE_BUTTON :
183    {
184      if (ev.mouse_button && drag==-1)
185      {   
186    if (mx>=b1x() && mx<b1x()+bw() && my>=b1y()-2 && my<b1y()+bh())
187    {
188      if (sx>0)
189      {
190        draw_widget(screen,1);
191        sx--;
192        draw_widget(screen,0);
193        scroll_event(sx,screen);
194      }
195    } else if (mx>=b2x() && mx<b2x()+bw() && my>=b2y() && my<=b2y()+bh())
196    {
197      if (sx<t-1)
198      {
199        draw_widget(screen,1);
200        sx++;
201        draw_widget(screen,0);
202        scroll_event(sx,screen);
203      }   
204    }
205    else
206    {
207      int dx1,dy1,dx2,dy2;
208      dragger_area(dx1,dy1,dx2,dy2);
209      if (mx>=dx1 && mx<=dx2 && my>=dy1 && my<=dy2)
210      {
211        int x1,y1,x2,y2;
212        wig_area(x1,y1,x2,y2);
213        if (mx>=x1 && mx<=x2 && my>=y1 && my<=y2)
214        {
215          drag=sx;
216          inm->grab_focus(this);
217        }   
218        else if (t>1)
219        {
220          int nx=mouse_to_drag(mx,my);
221          if (nx!=sx && nx>=0 && nx<t)
222          {
223        draw_widget(screen,1);
224        sx=nx;
225        draw_widget(screen,0);
226        scroll_event(sx,screen);       
227          }       
228        }
229      } else handle_inside_event(ev,screen,inm);
230    }
231      } else if (!ev.mouse_button && drag!=-1)
232      {
233    inm->release_focus();
234    drag=-1;
235      }
236    } break;
237
238    case EV_MOUSE_MOVE :
239    {
240      if (drag!=-1)
241      {
242    int nx=mouse_to_drag(mx,my);
243    if (nx<0) nx=0; else if (nx>=t) nx=t-1;
244    if (nx!=sx)
245    {
246      draw_widget(screen,1);
247      sx=nx;
248      draw_widget(screen,0);
249      scroll_event(sx,screen);
250    }
251      } else if ( activate_on_mouse_move())
252      {
253    int x1,y1,x2,y2;
254    wig_area(x1,y1,x2,y2);
255    if (mx>=x && mx<=x+l-1 && my>=y && my<=y+h-1)
256      handle_inside_event(ev,screen,inm);
257      }
258
259    } break;
260    case EV_KEY :
261    {
262      switch (ev.key)
263      {
264    case JK_LEFT :
265    { handle_left(screen,inm); } break;
266    case JK_RIGHT :
267    { handle_right(screen,inm); } break;
268    case JK_UP :
269    { handle_up(screen,inm); } break;
270    case JK_DOWN :
271    { handle_down(screen,inm); } break;
272
273    default :
274      handle_inside_event(ev,screen,inm);
275      }
276    } break;
277  }
278}
279
280
281void scroller::handle_right(image *screen, InputManager *inm)
282{
283  if (!vert && sx<t-1)
284  {
285    draw_widget(screen,1);
286    sx++;
287    draw_widget(screen,0);
288    scroll_event(sx,screen);   
289  }
290}
291
292void scroller::handle_left(image *screen, InputManager *inm)
293{
294  if (!vert && sx>1)
295  {
296    draw_widget(screen,1);
297    sx--;
298    draw_widget(screen,0);
299    scroll_event(sx,screen);   
300  }
301}
302
303void scroller::handle_up(image *screen, InputManager *inm)
304{
305  if (vert && sx>1)
306  {
307    draw_widget(screen,1);
308    sx--;
309    draw_widget(screen,0);
310    scroll_event(sx,screen);   
311  }
312}
313
314void scroller::handle_down(image *screen, InputManager *inm)
315{
316  if (vert && sx<t-1)
317  {
318    draw_widget(screen,1);
319    sx++;
320    draw_widget(screen,0);
321    scroll_event(sx,screen);   
322  }
323}
324
325void scroller::set_x (int x, image *screen)
326{
327  if (x<0) x=0;
328  if (x>=t) x=t-1;
329  if (x!=sx)
330  {
331    draw_widget(screen,1);
332    sx=x;
333    draw_widget(screen,0);
334    scroll_event(sx,screen);   
335  }
336}
337
338int scroller::mouse_to_drag(int mx,int my)
339{
340  int x1,y1,x2,y2;
341  dragger_area(x1,y1,x2,y2);
342
343  if (vert)
344  {
345    int h=(y2-y1+1-bh());
346    if (h)
347      return (my-y-bh()-bh()/2)*(t-1)/h;
348    else return 0;
349  }
350  else
351  {
352    int w=(x2-x1+1-bw());
353    if (w)
354      return (mx-x-bw()-bw()/2)*(t-1)/w;
355    else return 0;
356  }
357}
358
359
360void scroller::scroll_event(int newx, image *screen)
361{
362  screen->bar(x,y,x+l-1,y+h-1,wm->black());
363  int xa,ya,xo=0,yo;
364  if (vert) { xa=0; ya=30; yo=x+5; yo=y+5; } else { xa=30; ya=0; xo=x+5; yo=y+5; }
365  for (int i=newx,c=0;c<30 && i<100;i++,c++)
366  {
367    char st[10];
368    sprintf(st,"%d",i);
369    wm->font()->put_string(screen,xo,yo,st,wm->bright_color());
370    xo+=xa; yo+=ya;
371  }
372}
373
374void pick_list::area_config()
375{
376  l=wid*wm->font()->width();
377  h=th*(wm->font()->height()+1);
378}
379
380int lis_sort(void const *a, void const *b)
381{
382  pick_list_item *a1=(pick_list_item *)a;
383  pick_list_item *a2=(pick_list_item *)b;
384  return strcmp(a1->name,a2->name);
385}
386
387pick_list::pick_list(int X, int Y, int ID, int height,
388        char **List, int num_entries, int start_yoffset, ifield *Next, image *texture)
389     : scroller(X,Y,ID,2,2,1,0,Next)
390{
391  th=height;
392  tex=texture;
393  t=num_entries;
394  wid=0;
395  key_hist_total=0;
396  lis=(pick_list_item *)malloc(sizeof(pick_list_item)*num_entries);
397  int i=0;
398  for (;i<num_entries;i++)
399  {
400    lis[i].name=List[i];
401    lis[i].number=i;
402  }
403  qsort((void *)lis,num_entries,sizeof(pick_list_item),lis_sort);
404
405  for (i=0;i<t;i++)
406    if ((int)strlen(List[i])>wid)
407      wid=strlen(List[i]);
408  cur_sel=sx=start_yoffset;
409}
410
411void pick_list::handle_inside_event(event &ev, image *screen, InputManager *inm)
412{
413  if (ev.type==EV_MOUSE_MOVE && activate_on_mouse_move())
414  {
415    int sel=last_sel+(ev.mouse_move.y-y)/(wm->font()->height()+1);
416    if (sel!=cur_sel && sel<t && sel>=0)
417    {
418      cur_sel=sel;
419      scroll_event(last_sel,screen);
420    }
421  }
422  else if (ev.type==EV_MOUSE_BUTTON)
423  {
424    int sel=last_sel+(ev.mouse_move.y-y)/(wm->font()->height()+1);
425    if (sel<t && sel>=0)
426    {
427      if (sel==cur_sel)
428      wm->push_event(new event(id,(char *)this));
429      else
430      {
431    cur_sel=sel;
432    scroll_event(last_sel,screen);
433      }
434    }
435  } else if (ev.type==EV_KEY && ev.key==JK_ENTER)
436    wm->push_event(new event(id,(char *)this));
437  else if (ev.type==EV_KEY)
438  {
439    int found=-1;
440    if (key_hist_total<20)
441      key_hist[(int)(key_hist_total++)]=ev.key;
442
443    for (int i=0;i<t && found==-1;i++)
444    {
445      if ((int)strlen(lis[i].name)>=key_hist_total && memcmp(lis[i].name,key_hist,key_hist_total)==0)
446    found=i;
447    }
448    if (found!=-1)
449    {
450      sx=found;
451      cur_sel=found;
452      scroll_event(sx,screen);
453    } else key_hist_total=0;
454  }
455}
456
457void pick_list::handle_up(image *screen, InputManager *inm)
458{
459  if (cur_sel>0)
460    cur_sel--;
461  else return ;
462  if (cur_sel<sx)
463  {
464    draw_widget(screen,1);
465    sx=cur_sel;
466    draw_widget(screen,0);
467  }
468  scroll_event(sx,screen);   
469}
470
471void pick_list::handle_down(image *screen, InputManager *inm)
472{
473  if (cur_sel<t-1)
474    cur_sel++;
475  else return ;
476  if (cur_sel>sx+th-1)
477  {
478    draw_widget(screen,1);
479    sx=cur_sel-th+1;
480    draw_widget(screen,0);
481  }
482  scroll_event(sx,screen);   
483}
484
485void pick_list::scroll_event(int newx, image *screen)
486{
487  last_sel=newx;
488  if (tex)
489  {
490    short cx1,cy1,cx2,cy2;
491    screen->get_clip(cx1,cy1,cx2,cy2);
492    screen->set_clip(x,y,x+l-1,y+h-1);
493    int tw=(l+tex->width()-1)/tex->width();
494    int th=(h+tex->height()-1)/tex->height();
495    int dy=y;
496    for (int j=0;j<th;j++,dy+=tex->height())
497      for (int i=0,dx=x;i<tw;i++,dx+=tex->width())
498        tex->put_image(screen,dx,dy);
499
500    screen->set_clip(cx1,cy1,cx2,cy2);
501  } else screen->bar(x,y,x+l-1,y+h-1,wm->black());
502
503  int dy=y;
504  for (int i=0;i<th;i++,dy+=wm->font()->height()+1)
505  {
506    if (i+newx==cur_sel)
507      screen->bar(x,dy,x+wid*wm->font()->width()-1,dy+wm->font()->height(),wm->dark_color());
508    if (i+newx<t)
509      wm->font()->put_string(screen,x,dy,lis[i+newx].name,wm->bright_color());
510  }
511}
512
513
514
515
516spicker::spicker(int X, int Y, int ID, int Rows, int Cols, int Vert, int MultiSelect,
517           ifield *Next)
518     : scroller(X,Y,ID,2,2,Vert,0,Next)
519{
520  l=-1;
521  last_click=-1;
522  r=Rows;
523  c=Cols;
524  m=MultiSelect;
525  select=NULL;
526}
527
528void spicker::set_select(int x, int on)
529{
530  if (m)
531  {
532    if (on)
533      select[x/8]|=1<<(x&7);
534    else
535      select[x/8]&=(0xff-(1<<(x&7)));
536  } else cur_sel=x;
537}
538
539int spicker::get_select(int x)
540{
541  if (m)
542    return select[x/8]&(1<<(x&7));
543  else return (x==cur_sel);
544}
545
546int spicker::first_selected()
547{
548  if (m)
549  {
550    for (int i=0;i<t;i++)
551      if (get_select(i)) return i;
552    return -1;
553  } else return cur_sel;
554}
555
556void spicker::reconfigure()
557{
558  if (select)
559    free(select);
560  select=NULL;
561
562
563  t=total();
564  if (sx>t)
565    sx=t-1;
566  if (m)
567  {
568    select=(uint8_t *)malloc((t+7)/8);
569    memset(select,0,(t+7)/8);
570  } else cur_sel=0;
571}
572
573void spicker::draw_background(image *screen)
574{
575  screen->bar(x,y,x+l-1,y+h-1,wm->dark_color());
576}
577
578
579void spicker::area_config()
580{
581  if (vert)
582    l=item_width()+4;
583  else
584    l=item_width()*c+4;
585
586  if (vert)
587    h=item_height()*r+4;
588  else
589    h=item_height()+4;
590
591}
592
593void spicker::set_x(int x, image *screen)
594{
595  cur_sel=x;
596  sx=x;
597  scroll_event(x,screen);
598}
599
600
601void spicker::scroll_event(int newx, image *screen)
602{
603  last_sel=newx;
604  int xa,ya,xo,yo;
605  xo=x+2;
606  yo=y+2;
607  if (vert) { xa=0; ya=item_height(); }
608  else { xa=item_width(); ya=0; }
609  draw_background(screen);
610
611  for (int i=newx;i<newx+vis();i++)
612  {
613    if (i<t)
614    {
615      if (m)
616        draw_item(screen,xo,yo,i,get_select(i));
617      else
618        draw_item(screen,xo,yo,i,i==cur_sel);
619    }
620    xo+=xa; yo+=ya;
621  }
622}
623
624
625void spicker::handle_inside_event(event &ev, image *screen, InputManager *inm)
626{
627  switch (ev.type)
628  {
629    case EV_MOUSE_MOVE :
630    {
631      if (activate_on_mouse_move())
632      {
633    int me;
634    if (vert)
635      me=last_sel+(ev.mouse_move.y-y)/item_height();
636    else
637      me=last_sel+(ev.mouse_move.x-x)/item_width();
638    if (me<t && me>=0)
639    {
640      if (cur_sel!=me)
641      {
642        cur_sel=me;
643        scroll_event(last_sel,screen);
644        note_new_current(screen,inm,me);
645      }
646    }
647      }
648    } break;
649    case EV_MOUSE_BUTTON :
650    {
651      int me;
652      if (vert)
653    me=last_sel+(ev.mouse_move.y-y)/item_height();
654      else
655    me=last_sel+(ev.mouse_move.x-x)/item_width();
656      if (me<t && me>=0)
657      {
658    if (m)
659    {   
660      if (ev.mouse_button)
661      {
662        if (ok_to_select(me))
663        {
664          set_select(me,!get_select(me));
665          scroll_event(last_sel,screen);
666          inm->grab_focus(this);
667        }
668      } else last_click=-1;
669
670    } else if (ok_to_select(me))
671    {
672      if (cur_sel==me)   
673        note_selection(screen,inm,me);
674      else
675      {
676        cur_sel=me;
677        scroll_event(last_sel,screen);
678        note_new_current(screen,inm,me);
679      }
680    }
681      }
682    } break;
683  }
684}
685
686
687
688void spicker::handle_up(image *screen, InputManager *inm)
689{
690  if (vert && cur_sel>0)
691  {
692    cur_sel--;
693
694    if (cur_sel<sx)
695    {
696      draw_widget(screen,1);
697      last_sel=sx=cur_sel;
698      draw_widget(screen,0);
699    }
700    scroll_event(last_sel,screen);
701    note_new_current(screen,inm,cur_sel);
702  }
703}
704
705void spicker::handle_down(image *screen, InputManager *inm)
706{
707  if (vert && cur_sel<t-1)
708    cur_sel++;
709  else return ;
710  if (cur_sel>sx+r-1)
711  {
712    draw_widget(screen,1);
713    last_sel=sx=cur_sel-r+1;
714    draw_widget(screen,0);
715  }
716  scroll_event(sx,screen);
717  note_new_current(screen,inm,cur_sel);
718}
719
720void spicker::handle_left(image *screen, InputManager *inm)
721{
722}
723
724void spicker::handle_right(image *screen, InputManager *inm)
725{
726}
727
728
729
730
Note: See TracBrowser for help on using the repository browser.