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

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

Fuck the history, I'm renaming all .hpp files to .h for my own sanity.

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.h"
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.