source: abuse/tags/pd/macabuse/imlib/scroller.c @ 528

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