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

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

style: remove trailing spaces, fix copyright statements.

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