chiark / gitweb /
Initial revision
[ssr] / StraySrc / Libraries / Steel / c / buttons
1 /*
2  * Buttons
3  *  provides handling for clever buttons and things.
4  *
5  * v. 1.00 (23 July 1993)
6  *
7  * © 1993-1998 Straylight
8  */
9
10 /*----- Licensing note ----------------------------------------------------*
11  *
12  * This file is part of Straylight's Steel library.
13  *
14  * Steel is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2, or (at your option)
17  * any later version.
18  *
19  * Steel is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with Steel.  If not, write to the Free Software Foundation,
26  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 #include "wimp.h"
30 #include "wimpt.h"
31 #include "buttons.h"
32 #include "bbc.h"
33 #include "win.h"
34 #include "werr.h"
35 #include <stdio.h>
36 #include "colourtran.h"
37 #include "msgs.h"
38 #include "mem.h"
39 #include "alarm.h"
40 #include <stdlib.h>
41 #include <string.h>
42
43 typedef struct
44 {
45   /* --- Information from the caller --- */
46
47   dbox d;
48   dbox_field f;
49   dbox wd;
50   dbox_field wf;
51   int diff;
52   buttons_arrowProc p;
53   void *handle;
54
55   /* --- Other information about the arrow --- */
56
57   int rate;
58   BOOL done;
59 }
60 buttons__arrowstr;
61
62 /*
63  * A structure that says everything necessary about a slider
64  */
65
66 typedef struct
67 {
68   dbox d;
69   wimp_i i;
70   int max;
71   int *val;
72   int colour;
73   BOOL isVertical;
74   int slideMax;
75   int iwidth;
76   int o;
77   buttons_sliderHandler proc;
78   void *handle;
79   BOOL dragOver;
80   int lastLen;
81 }
82 buttons__sliderstr;
83
84 static BOOL buttons__testMouse=TRUE;
85
86 /*
87  * void buttons_arrowClick
88  * (
89  *   dbox d,
90  *   dbox_field f,
91  *   int min,
92  *   int max,
93  *   int increment,
94  *   BOOL wrap
95  * )
96  *
97  * Use
98  *  Increases (or decreases) the value in a writable box.  If the last event
99  *  was a click with the adjust button, the increment is made negative (i.e.
100  *  1 becomes -1, and -1 becomes 1), following the standard convention.  The
101  *  value will not be allowed to exceed the limits passed.  If you don't
102  *  want limits, make max and min the same.  Optionally, you can make the
103  *  field's value 'wrap around' if it goes out of range.
104  *
105  * Parameters
106  *  dbox d == the dbox handle
107  *  dbox_field f == the field number
108  *  int min == the lowest allowable value for the field
109  *  int max == the highest allowable value for the field
110  *  int increment == what to add to the value.  This may be negative.
111  *  BOOL wrap == wrap around or not
112  */
113
114 void buttons_arrowClick
115 (
116   dbox d,
117   dbox_field f,
118   int min,
119   int max,
120   int increment,
121   BOOL wrap
122 )
123 {
124   int value=dbox_getNumeric(d,f);
125
126   if (buttons__testMouse && dbox_wasAdjustClick())
127     increment=-increment;
128   value+=increment;
129   if (max>min)
130   {
131     if (value>max)
132       value=wrap ? min : max;
133     if (value<min)
134       value=wrap ? max : min;
135   }
136   dbox_setNumeric(d,f,value);
137 }
138
139 /*
140  * void buttons__simpleArrows(dbox d,dbox_field f,int diff,void *handle)
141  *
142  * Use
143  *  Handles a simple arrow click event on an arrow button
144  *
145  * Parameters
146  *  dbox d == the dbox containing the writable bitty to bump
147  *  dbox_field == the field to bump
148  *  int diff == how much to bump it by
149  *  void *handle == pointer to more information about the bump op
150  */
151
152 static void buttons__simpleArrows(dbox d,dbox_field f,int diff,void *handle)
153 {
154   buttons_simpleArrow *sa=handle;
155
156   buttons_arrowClick(d,f,sa->min,sa->max,diff,sa->wrap);
157 }
158
159 /*
160  * void buttons__arrowAlarm(int at,void *handle)
161  *
162  * Use
163  *  Handles an alarm for the arrow handlers: we use alarms to handle the
164  *  auto-repeat on the arrows more easily.
165  *
166  * Parameters
167  *  int at == when this alarm was meant to happen
168  *  void *handle == information about the arrow handling
169  */
170
171 static void buttons__arrowAlarm(int at,void *handle)
172 {
173   buttons__arrowstr *a=handle;
174   int missed;
175
176   /* --- Call the user function, and get a call-back --- *
177    *
178    * We resynch to the original time, to try to make up for any major
179    * problems, in case the repeat rate is very slow.
180    */
181
182   (a->p)(a->wd,a->wf,a->diff,a->handle);
183   missed=(alarm_timenow()-at)/a->rate;
184   alarm_set(at+(missed+1)*a->rate,buttons__arrowAlarm,a);
185 }
186
187 /*
188  * BOOL buttons__arrowUnknowns(wimp_eventstr *e,void *handle)
189  *
190  * Use
191  *  Picks up unknown events for the duration of an arrow operation.  It is
192  *  used to detect the raising of the mouse buttons by picking up the
193  *  WIMP drag event
194  */
195
196 static BOOL buttons__arrowUnknowns(wimp_eventstr *e,void *handle)
197 {
198   BOOL handled=FALSE;
199   buttons__arrowstr *a=handle;
200
201   switch (e->e)
202   {
203     case wimp_EUSERDRAG:
204       a->done=TRUE;
205       win_remove_unknown_event_processor(buttons__arrowUnknowns,a);
206       handled=TRUE;
207       break;
208   }
209   return (handled);
210 }
211
212 /*
213  * void buttons_arrow(dbox d,
214  *                    dbox_field f,
215  *                    dbox wd,
216  *                    dbox_field wf,
217  *                    buttons_arrowProc p,
218  *                    int diff,
219  *                    void *handle)
220  *
221  * Use
222  *  Handles a click on an arrow button.  It constrains the mouse pointer
223  *  so it doesn't drift away annoyingly, and presses the icon in (by
224  *  selecting it, so set up the sprites properly) while it's being clicked,
225  *  with nary a flicker in sight.  It simulates auto-repeat on the button,
226  *  so don't use real auto-repeat buttons.
227  *
228  * Parameters
229  *  dbox d,dbox_field f == the icon that was clicked
230  *  dbox wd,dbox_field wf == the (writable) icon that is passed to p
231  *  buttons_arrowProc p == a procedure to call for each `click' on the
232  *   button.  It may call buttons_arrowClick to bump the field.  If you pass
233  *   0, a default function is called which just bumps the icon.  handle must
234  *   point to a buttons_simpleArrow structure filled in correctly.
235  *  int diff == the difference to add to the icon (passed to p).  The sign
236  *   is toggled if the click was with the adjust button.
237  *  void *handle == a handle to pass to p
238  */
239
240 void buttons_arrow(dbox d,
241                    dbox_field f,
242                    dbox wd,
243                    dbox_field wf,
244                    buttons_arrowProc p,
245                    int diff,
246                    void *handle)
247 {
248   buttons__arrowstr ar;
249   wimp_mousestr m;
250   int rate=0,delay=0;
251   int read_osbyte;
252   wimp_dragstr drag;
253
254   /* --- Handle adjust-clicks in time-honoured fashion --- */
255
256   if (dbox_wasAdjustClick())
257     diff=-diff;
258
259   /* --- Start a drag to constrain the mouse --- */
260
261   wimpt_noerr(wimp_get_point_info(&m));
262   drag.window=dbox_syshandle(d);
263   drag.type=wimp_USER_HIDDEN;
264   drag.parent.x0=drag.parent.x1=m.x;
265   drag.parent.y0=drag.parent.y1=m.y;
266   wimpt_noerr(wimp_drag_box(&drag));
267
268   /* --- Read auto-repeat information --- */
269
270   read_osbyte=255;
271   os_byte(196,&delay,&read_osbyte);
272
273   read_osbyte=255;
274   os_byte(197,&rate,&read_osbyte);
275
276   /* --- Fill in the structure --- */
277
278   ar.d=d;
279   ar.f=f;
280   ar.wd=wd;
281   ar.wf=wf;
282   ar.p=p ? p : buttons__simpleArrows;
283   ar.diff=diff;
284   ar.handle=handle;
285   ar.rate=rate;
286   ar.done=FALSE;
287
288   /* --- Perform an initial `click' --- */
289
290   dbox_selecticon(d,f,TRUE);
291   buttons__testMouse=FALSE;
292   ar.p(wd,wf,diff,handle);
293
294   /* --- Set the alarm up to do the next one --- */
295
296   alarm_set(alarm_timenow()+delay,buttons__arrowAlarm,&ar);
297   win_add_unknown_event_processor(buttons__arrowUnknowns,&ar);
298
299   /* --- Wait until the user stops clicking --- */
300
301   while (!ar.done)
302     event_process();
303
304   /* --- Tidy everything away again --- */
305
306   dbox_selecticon(d,f,FALSE);
307   buttons__testMouse=TRUE;
308   alarm_removeall(&ar);
309 }
310
311 /*
312  * BOOL buttons_insertChar(dbox d,int chcode,char min,char max)
313  *
314  * Use
315  *  This function inserts the character specified into the writable field
316  *  containing the caret.  Useful if you want to handle input yourself so
317  *  you can update things (such as sliders) in deending on the input.  It
318  *  will insure that the character is within the limits given (invalid
319  *  limits will cause a default of 32-255 to be used).
320  *
321  * Parameters
322  *  dbox d == dbox handle
323  *  int chcode == the character, as returned from event_process().
324  *  char min == minimum character allowable.
325  *  char max == maximum character allowable.
326  *
327  * Returns
328  *  Whether it inserted the character or not.
329  */
330
331 BOOL buttons_insertChar(dbox d,int chcode,char min,char max)
332 {
333   wimp_caretstr c;
334   char field[255];
335   int i;
336   int len;
337   if (min>=max)
338   {
339     min=32;
340     max=255;
341   }
342   if (chcode<min || chcode>max)
343     return (FALSE);
344   wimpt_noerr(wimp_get_caret_pos(&c));
345   c.height=-1;
346   dbox_getfield(d,c.i,field,254);
347   len=strlen(field);
348   for (i=len;i>=c.index;i--)
349     field[i+1]=field[i];
350   field[c.index]=chcode;
351   c.index++;
352   dbox_setfield(d,c.i,field);
353   wimpt_noerr(wimp_set_caret_pos(&c));
354   return (TRUE);
355 }
356
357 /*
358  * void buttons__rect(int x1,int y1,int x2,int y2,int colour)
359  *
360  * Use
361  *  Gagdy veneer for bbc_rectanglefill
362  *
363  * Parameters
364  *  int x1 == left side
365  *  int y1 == bottom
366  *  int x2 == right side
367  *  int y2 == top
368  *  int colour == the colour to use
369  */
370
371 static void buttons__rect(int x1,int y1,int x2,int y2,int colour)
372 {
373   int w,h;
374   wimpt_noerr(wimp_setcolour(colour));
375   w=x2-x1;
376   h=y2-y1;
377   if (w && h)
378     wimpt_noerr(bbc_rectanglefill(x1,y1,w,h));
379 }
380
381 /*
382  * void buttons__doRdrSlider
383  * (
384  *   wimp_w w,
385  *   wimp_icon *icn,
386  *   int slideLen,
387  *   int colour,
388  *   BOOL isVertical
389  * )
390  *
391  * Use
392  *  Redraws a slider with the specified length.
393  *
394  * Parameters
395  *  wimp_w w == the window handle
396  *  wimp_icon *icn == pointer to the icon definition
397  *  int slideLen == the length to draw the slider
398  *  int colour ==  colour of the slider
399  *  BOOL isVertical == whether the slider is vertical
400  */
401
402 static void buttons__doRdrSlider
403 (
404   wimp_w w,
405   wimp_icon *icn,
406   int slideLen,
407   int colour,
408   BOOL isVertical
409 )
410 {
411   wimp_wstate state;
412   int bordCol;
413   int backg;
414   int ox,oy;
415   wimpt_noerr(wimp_get_wind_state(w,&state));
416   bordCol=(((int)icn->flags)>>24) & 15;
417   backg=(((int)icn->flags)>>28) & 15;
418   ox=state.o.box.x0-state.o.x;
419   oy=state.o.box.y1-state.o.y;
420   if (isVertical)
421   {
422     buttons__rect
423     (
424       icn->box.x0+ox , icn->box.y0+oy ,
425       icn->box.x1+ox , slideLen+icn->box.y0+oy ,
426       colour
427     );
428     buttons__rect
429     (
430       icn->box.x0+ox , icn->box.y0+oy+slideLen ,
431       icn->box.x1+ox , icn->box.y1+oy ,
432       backg
433     );
434     wimpt_noerr(wimp_setcolour(bordCol));
435     wimpt_noerr(bbc_move(ox+icn->box.x0,oy+icn->box.y0+slideLen));
436     wimpt_noerr(bbc_draw(ox+icn->box.x1,oy+icn->box.y0+slideLen));
437   }
438   else
439   {
440     buttons__rect
441     (
442       icn->box.x0+ox , icn->box.y0+oy ,
443       slideLen+icn->box.x0+ox , icn->box.y1+oy ,
444       colour
445     );
446     buttons__rect
447     (
448       icn->box.x0+ox+slideLen , icn->box.y0+oy ,
449       icn->box.x1+ox , icn->box.y1+oy ,
450       backg
451     );
452     wimpt_noerr(wimp_setcolour(bordCol));
453     wimpt_noerr(bbc_move(ox+icn->box.x0+slideLen,oy+icn->box.y0));
454     wimpt_noerr(bbc_draw(ox+icn->box.x0+slideLen,oy+icn->box.y1));
455   }
456 }
457
458 /*
459  * void buttons_redrawSlider
460  * (
461  *   dbox d,
462  *   wimp_i i,
463  *   int max,
464  *   int val,
465  *   int colour,
466  *   BOOL isVertical
467  * )
468  *
469  * Use
470  *  Draws a slider in the specified icon
471  *
472  * Parameters
473  *  dbox d == dbox handle
474  *  wimp_i icon == the icon we're dealing with
475  *  int max == the maximum value you want
476  *  int val == the current value of the slider
477  *  int colour == the WIMP colour for the slider
478  *  BOOL isVertical == TRUE if the slider is vertical
479  */
480
481 void buttons_redrawSlider
482 (
483   dbox d,
484   wimp_i i,
485   int max,
486   int val,
487   int colour,
488   BOOL isVertical
489 )
490 {
491   wimp_w w=dbox_syshandle(d);
492   wimp_icon icn;
493   int slideLen,slideMax;
494   wimpt_noerr(wimp_get_icon_info(w,i,&icn));
495   icn.box.x0+=wimpt_dx();
496   icn.box.y0+=wimpt_dy();
497   icn.box.x1-=2*wimpt_dx();
498   icn.box.y1-=2*wimpt_dy();
499   slideMax=isVertical ? icn.box.y1-icn.box.y0 : icn.box.x1-icn.box.x0;
500   slideLen=(val*slideMax)/max;
501   if (slideLen>slideMax)
502     slideLen=slideMax;
503   buttons__doRdrSlider(w,&icn,slideLen,colour,isVertical);
504 }
505
506 /*
507  * void buttons_updateSlider
508  * (
509  *   dbox d,
510  *   wimp_i i,
511  *   int max,
512  *   int val,
513  *   int colour,
514  *   BOOL isVertical
515  * )
516  *
517  * Use
518  *  Redraws a slider in the specified icon
519  *
520  * Parameters
521  *  dbox d == dbox handle
522  *  wimp_i icon == the icon we're dealing with
523  *  int max == the maximum value you want
524  *  int val == the current value of the slider
525  *  int colour == the WIMP colour for the slider
526  *  BOOL isVertical == TRUE if the slider is vertical
527  */
528
529 void buttons_updateSlider
530 (
531   dbox d,
532   wimp_i i,
533   int max,
534   int val,
535   int colour,
536   BOOL isVertical
537 )
538 {
539   wimp_w w=dbox_syshandle(d);
540   wimp_icon icn;
541   wimp_redrawstr r;
542   BOOL more;
543   wimpt_noerr(wimp_get_icon_info(w,i,&icn));
544   r.w=w;
545   r.box.x0=icn.box.x0;
546   r.box.y0=icn.box.y0;
547   r.box.x1=icn.box.x1;
548   r.box.y1=icn.box.y1;
549   wimpt_noerr(wimp_update_wind(&r,&more));
550   while (more)
551   {
552     buttons_redrawSlider(d,i,max,val,colour,isVertical);
553     wimpt_noerr(wimp_get_rectangle(&r,&more));
554   }
555 }
556
557 /*
558  * void buttons__doSlide(void *handle)
559  *
560  * Use
561  *  This is the routine wot keeps everything going during the drag.
562  *
563  * Parameters
564  *  void *handle == pointer to the buttons__sliderstr running the show
565  */
566
567 static void buttons__doSlide(void *handle)
568 {
569   wimp_mousestr m;
570   int nVal;
571   buttons__sliderstr *s=(buttons__sliderstr *)handle;
572   int dist,half;
573   wimp_w w=dbox_syshandle(s->d);
574   wimp_icon icn;
575   wimp_redrawstr r;
576   BOOL more;
577   int len;
578   wimpt_noerr(wimp_get_point_info(&m));
579   half=s->slideMax/s->max/2;
580   len=s->isVertical ? m.y-s->o : m.x-s->o;
581   dist=len+half;
582   nVal=dist*s->max/s->slideMax;
583   if ((s->slideMax)>=(s->max)*2*(s->isVertical ? wimpt_dy() : wimpt_dx()))
584     len=nVal*s->slideMax/s->max;
585   if (nVal>s->max)
586     nVal=s->max;
587   if (nVal<0)
588     nVal=0;
589   if (len!=s->lastLen)
590   {
591     *(s->val)=nVal;
592     s->lastLen=len;
593     wimpt_noerr(wimp_get_icon_info(w,s->i,&icn));
594     icn.box.x0+=wimpt_dx();
595     icn.box.y0+=wimpt_dy();
596     icn.box.x1-=wimpt_dx();
597     icn.box.y1-=wimpt_dy();
598     r.w=w;
599     r.box.x0=icn.box.x0;
600     r.box.y0=icn.box.y0;
601     r.box.x1=icn.box.x1;
602     r.box.y1=icn.box.y1;
603     wimpt_noerr(wimp_update_wind(&r,&more));
604     icn.box.x1-=wimpt_dx();
605     icn.box.y1-=wimpt_dy();
606     while (more)
607     {
608       buttons__doRdrSlider(w,&icn,len,s->colour,s->isVertical);
609       wimpt_noerr(wimp_get_rectangle(&r,&more));
610     }
611     if (s->proc)
612       (s->proc)(s->d,s->i,nVal,s->handle);
613   }
614 }
615
616 /*
617  * BOOL buttons__ukEvents(wimp_eventstr *e,void *handle)
618  *
619  * Use
620  *  This routine just grabs the drag event and closes off the drag if it's
621  *  over.
622  *
623  * Parameters
624  *  wimp_eventstr *e == a pointer to the event
625  *  void *handle == pointer to the current slider
626  *
627  * Returns
628  *  Whether it handled the event or not.
629  */
630
631 static BOOL buttons__ukEvents(wimp_eventstr *e,void *handle)
632 {
633   BOOL handled=FALSE;
634   buttons__sliderstr *s=(buttons__sliderstr *)handle;
635   switch (e->e)
636   {
637     case wimp_EUSERDRAG:
638       s->dragOver=TRUE;
639       win_remove_idle_claimer(buttons__doSlide,handle);
640       handled=TRUE;
641       win_remove_unknown_event_processor(buttons__ukEvents,handle);
642       mem_free(s);
643       break;
644   }
645   return (handled);
646 }
647
648 /*
649  * void buttons_slideSlider
650  * (
651  *   dbox d,
652  *   wimp_i i,
653  *   int max,
654  *   int *val,
655  *   int colour,
656  *   BOOL isVertical,
657  *   buttons_sliderHandler proc,
658  *   void *handle
659  * )
660  *
661  * Use
662  *  This routine just neatly handles the slider totally.  Just pass it the
663  *  parameters it needs, and let it get on with it.
664  *
665  * Parameters
666  *  dbox d == the dbox
667  *  wimp_i i == the icon number
668  *  int max == the maximum slider value
669  *  int *val == a pointer to the slider value (updated as we go along)
670  *  int colour == the colour for the slider
671  *  BOOL isVertical == whether the slider is vertical
672  *  buttons_sliderHandler proc == a slider handler, which can update, say a
673  *   a writable field as the drag takes place
674  *  void *handle == a handle to pass the routine
675  */
676
677 void buttons_slideSlider
678 (
679   dbox d,
680   wimp_i i,
681   int max,
682   int *val,
683   int colour,
684   BOOL isVertical,
685   buttons_sliderHandler proc,
686   void *handle
687 )
688 {
689   wimp_w w=dbox_syshandle(d);
690   wimp_wstate state;
691   wimp_icon icn;
692   int ox,oy;
693   buttons__sliderstr *s;
694   wimp_dragstr drag;
695   wimp_mousestr m;
696   s=(buttons__sliderstr *)mem_alloc(sizeof(buttons__sliderstr));
697   if (!s)
698   {
699     werr(FALSE,msgs_lookup("buttonsNM:Not enough memory for slider."));
700     return;
701   }
702   wimpt_noerr(wimp_get_wind_state(w,&state));
703   wimpt_noerr(wimp_get_icon_info(w,i,&icn));
704   icn.box.x0+=wimpt_dx();
705   icn.box.y0+=wimpt_dy();
706   icn.box.x1-=2*wimpt_dx();
707   icn.box.y1-=2*wimpt_dy();
708   ox=state.o.box.x0-state.o.x;
709   oy=state.o.box.y1-state.o.y;
710   s->slideMax=isVertical ? icn.box.y1-icn.box.y0 : icn.box.x1-icn.box.x0;
711   s->d=d;
712   s->i=i;
713   s->max=max;
714   s->val=val;
715   s->colour=colour;
716   s->isVertical=isVertical;
717   s->o=isVertical ? oy+icn.box.y0 : ox+icn.box.x0;
718   s->iwidth=isVertical ? icn.box.x1-icn.box.x0 : icn.box.y1-icn.box.y0;
719   s->proc=proc;
720   s->handle=handle;
721   s->dragOver=FALSE;
722   s->lastLen=-1;
723   wimpt_noerr(wimp_get_point_info(&m));
724   drag.window=0;
725   drag.type=wimp_USER_HIDDEN;
726   if (isVertical)
727   {
728     drag.parent.x0=m.x;
729     drag.parent.y0=icn.box.y0+oy;
730     drag.parent.x1=m.x;
731     drag.parent.y1=icn.box.y1+oy;
732   }
733   else
734   {
735     drag.parent.x0=icn.box.x0+ox;
736     drag.parent.y0=m.y;
737     drag.parent.x1=icn.box.x1+ox;
738     drag.parent.y1=m.y;
739   }
740   wimpt_noerr(wimp_drag_box(&drag));
741   win_add_unknown_event_processor(buttons__ukEvents,s);
742   win_addIdleClaimer(buttons__doSlide,2,s);
743 }
744
745 /*
746  * void buttons_redrawColourButton(dbox d,wimp_i i,buttons_colourstr *c)
747  *
748  * Use
749  *  Redraws a true-colour button.
750  *
751  * Parameters
752  *  dbox d == the dbox
753  *  wimp_i i == icon number
754  *  buttons_colourstr == the colour we're intersted in
755  */
756
757 void buttons_redrawColourButton(dbox d,wimp_i i,wimp_paletteword c)
758 {
759   wimp_w w=dbox_syshandle(d);
760   wimp_wstate state;
761   wimp_icon icn;
762   int ox,oy;
763   int dummy;
764   wimpt_noerr(wimp_get_wind_state(w,&state));
765   wimpt_noerr(wimp_get_icon_info(w,i,&icn));
766   ox=state.o.box.x0-state.o.x;
767   oy=state.o.box.y1-state.o.y;
768   if (wimpt_getVersion()>=300)
769     colourtran_setGCOL(c,256,0,&dummy); /* Dither if you can               */
770   else
771     colourtran_setGCOL(c,0,0,&dummy);
772   bbc_rectanglefill(
773     ox+icn.box.x0 , oy+icn.box.y0 ,
774     icn.box.x1-icn.box.x0-1 , icn.box.y1-icn.box.y0-1
775   );
776 }
777
778 /*
779  * buttons_updateColourButton(dbox d,wimp_i i,wimp_paletteword c)
780  *
781  * Use
782  *  This routine redraws a colour button.
783  *
784  * Parameters
785  *  dbox d ==  the dbox
786  *  wimp_i == the icon number
787  *  wimp_paletteword c == the colour number
788  */
789
790 void buttons_updateColourButton(dbox d,wimp_i i,wimp_paletteword c)
791 {
792   wimp_w w=dbox_syshandle(d);
793   wimp_icon icn;
794   wimp_redrawstr r;
795   BOOL more;
796   wimpt_noerr(wimp_get_icon_info(w,i,&icn));
797   r.w=w;
798   r.box.x0=icn.box.x0;
799   r.box.y0=icn.box.y0;
800   r.box.x1=icn.box.x1;
801   r.box.y1=icn.box.y1;
802   wimpt_noerr(wimp_update_wind(&r,&more));
803   while (more)
804   {
805     buttons_redrawColourButton(d,i,c);
806     wimpt_noerr(wimp_get_rectangle(&r,&more));
807   }
808 }