3 * provides handling for clever buttons and things.
5 * v. 1.00 (23 July 1993)
7 * © 1993-1998 Straylight
10 /*----- Licensing note ----------------------------------------------------*
12 * This file is part of Straylight's Steel library.
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)
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.
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.
36 #include "colourtran.h"
45 /* --- Information from the caller --- */
55 /* --- Other information about the arrow --- */
63 * A structure that says everything necessary about a slider
77 buttons_sliderHandler proc;
84 static BOOL buttons__testMouse=TRUE;
87 * void buttons_arrowClick
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.
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
114 void buttons_arrowClick
124 int value=dbox_getNumeric(d,f);
126 if (buttons__testMouse && dbox_wasAdjustClick())
127 increment=-increment;
132 value=wrap ? min : max;
134 value=wrap ? max : min;
136 dbox_setNumeric(d,f,value);
140 * void buttons__simpleArrows(dbox d,dbox_field f,int diff,void *handle)
143 * Handles a simple arrow click event on an arrow button
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
152 static void buttons__simpleArrows(dbox d,dbox_field f,int diff,void *handle)
154 buttons_simpleArrow *sa=handle;
156 buttons_arrowClick(d,f,sa->min,sa->max,diff,sa->wrap);
160 * void buttons__arrowAlarm(int at,void *handle)
163 * Handles an alarm for the arrow handlers: we use alarms to handle the
164 * auto-repeat on the arrows more easily.
167 * int at == when this alarm was meant to happen
168 * void *handle == information about the arrow handling
171 static void buttons__arrowAlarm(int at,void *handle)
173 buttons__arrowstr *a=handle;
176 /* --- Call the user function, and get a call-back --- *
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.
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);
188 * BOOL buttons__arrowUnknowns(wimp_eventstr *e,void *handle)
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
196 static BOOL buttons__arrowUnknowns(wimp_eventstr *e,void *handle)
199 buttons__arrowstr *a=handle;
205 win_remove_unknown_event_processor(buttons__arrowUnknowns,a);
213 * void buttons_arrow(dbox d,
217 * buttons_arrowProc p,
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.
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
240 void buttons_arrow(dbox d,
248 buttons__arrowstr ar;
254 /* --- Handle adjust-clicks in time-honoured fashion --- */
256 if (dbox_wasAdjustClick())
259 /* --- Start a drag to constrain the mouse --- */
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));
268 /* --- Read auto-repeat information --- */
271 os_byte(196,&delay,&read_osbyte);
274 os_byte(197,&rate,&read_osbyte);
276 /* --- Fill in the structure --- */
282 ar.p=p ? p : buttons__simpleArrows;
288 /* --- Perform an initial `click' --- */
290 dbox_selecticon(d,f,TRUE);
291 buttons__testMouse=FALSE;
292 ar.p(wd,wf,diff,handle);
294 /* --- Set the alarm up to do the next one --- */
296 alarm_set(alarm_timenow()+delay,buttons__arrowAlarm,&ar);
297 win_add_unknown_event_processor(buttons__arrowUnknowns,&ar);
299 /* --- Wait until the user stops clicking --- */
304 /* --- Tidy everything away again --- */
306 dbox_selecticon(d,f,FALSE);
307 buttons__testMouse=TRUE;
308 alarm_removeall(&ar);
312 * BOOL buttons_insertChar(dbox d,int chcode,char min,char max)
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).
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.
328 * Whether it inserted the character or not.
331 BOOL buttons_insertChar(dbox d,int chcode,char min,char max)
342 if (chcode<min || chcode>max)
344 wimpt_noerr(wimp_get_caret_pos(&c));
346 dbox_getfield(d,c.i,field,254);
348 for (i=len;i>=c.index;i--)
350 field[c.index]=chcode;
352 dbox_setfield(d,c.i,field);
353 wimpt_noerr(wimp_set_caret_pos(&c));
358 * void buttons__rect(int x1,int y1,int x2,int y2,int colour)
361 * Gagdy veneer for bbc_rectanglefill
364 * int x1 == left side
366 * int x2 == right side
368 * int colour == the colour to use
371 static void buttons__rect(int x1,int y1,int x2,int y2,int colour)
374 wimpt_noerr(wimp_setcolour(colour));
378 wimpt_noerr(bbc_rectanglefill(x1,y1,w,h));
382 * void buttons__doRdrSlider
392 * Redraws a slider with the specified length.
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
402 static void buttons__doRdrSlider
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;
424 icn->box.x0+ox , icn->box.y0+oy ,
425 icn->box.x1+ox , slideLen+icn->box.y0+oy ,
430 icn->box.x0+ox , icn->box.y0+oy+slideLen ,
431 icn->box.x1+ox , icn->box.y1+oy ,
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));
442 icn->box.x0+ox , icn->box.y0+oy ,
443 slideLen+icn->box.x0+ox , icn->box.y1+oy ,
448 icn->box.x0+ox+slideLen , icn->box.y0+oy ,
449 icn->box.x1+ox , icn->box.y1+oy ,
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));
459 * void buttons_redrawSlider
470 * Draws a slider in the specified icon
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
481 void buttons_redrawSlider
491 wimp_w w=dbox_syshandle(d);
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)
503 buttons__doRdrSlider(w,&icn,slideLen,colour,isVertical);
507 * void buttons_updateSlider
518 * Redraws a slider in the specified icon
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
529 void buttons_updateSlider
539 wimp_w w=dbox_syshandle(d);
543 wimpt_noerr(wimp_get_icon_info(w,i,&icn));
549 wimpt_noerr(wimp_update_wind(&r,&more));
552 buttons_redrawSlider(d,i,max,val,colour,isVertical);
553 wimpt_noerr(wimp_get_rectangle(&r,&more));
558 * void buttons__doSlide(void *handle)
561 * This is the routine wot keeps everything going during the drag.
564 * void *handle == pointer to the buttons__sliderstr running the show
567 static void buttons__doSlide(void *handle)
571 buttons__sliderstr *s=(buttons__sliderstr *)handle;
573 wimp_w w=dbox_syshandle(s->d);
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;
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;
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();
603 wimpt_noerr(wimp_update_wind(&r,&more));
604 icn.box.x1-=wimpt_dx();
605 icn.box.y1-=wimpt_dy();
608 buttons__doRdrSlider(w,&icn,len,s->colour,s->isVertical);
609 wimpt_noerr(wimp_get_rectangle(&r,&more));
612 (s->proc)(s->d,s->i,nVal,s->handle);
617 * BOOL buttons__ukEvents(wimp_eventstr *e,void *handle)
620 * This routine just grabs the drag event and closes off the drag if it's
624 * wimp_eventstr *e == a pointer to the event
625 * void *handle == pointer to the current slider
628 * Whether it handled the event or not.
631 static BOOL buttons__ukEvents(wimp_eventstr *e,void *handle)
634 buttons__sliderstr *s=(buttons__sliderstr *)handle;
639 win_remove_idle_claimer(buttons__doSlide,handle);
641 win_remove_unknown_event_processor(buttons__ukEvents,handle);
649 * void buttons_slideSlider
657 * buttons_sliderHandler proc,
662 * This routine just neatly handles the slider totally. Just pass it the
663 * parameters it needs, and let it get on with it.
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
677 void buttons_slideSlider
685 buttons_sliderHandler proc,
689 wimp_w w=dbox_syshandle(d);
693 buttons__sliderstr *s;
696 s=(buttons__sliderstr *)mem_alloc(sizeof(buttons__sliderstr));
699 werr(FALSE,msgs_lookup("buttonsNM:Not enough memory for slider."));
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;
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;
723 wimpt_noerr(wimp_get_point_info(&m));
725 drag.type=wimp_USER_HIDDEN;
729 drag.parent.y0=icn.box.y0+oy;
731 drag.parent.y1=icn.box.y1+oy;
735 drag.parent.x0=icn.box.x0+ox;
737 drag.parent.x1=icn.box.x1+ox;
740 wimpt_noerr(wimp_drag_box(&drag));
741 win_add_unknown_event_processor(buttons__ukEvents,s);
742 win_addIdleClaimer(buttons__doSlide,2,s);
746 * void buttons_redrawColourButton(dbox d,wimp_i i,buttons_colourstr *c)
749 * Redraws a true-colour button.
753 * wimp_i i == icon number
754 * buttons_colourstr == the colour we're intersted in
757 void buttons_redrawColourButton(dbox d,wimp_i i,wimp_paletteword c)
759 wimp_w w=dbox_syshandle(d);
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 */
771 colourtran_setGCOL(c,0,0,&dummy);
773 ox+icn.box.x0 , oy+icn.box.y0 ,
774 icn.box.x1-icn.box.x0-1 , icn.box.y1-icn.box.y0-1
779 * buttons_updateColourButton(dbox d,wimp_i i,wimp_paletteword c)
782 * This routine redraws a colour button.
786 * wimp_i == the icon number
787 * wimp_paletteword c == the colour number
790 void buttons_updateColourButton(dbox d,wimp_i i,wimp_paletteword c)
792 wimp_w w=dbox_syshandle(d);
796 wimpt_noerr(wimp_get_icon_info(w,i,&icn));
802 wimpt_noerr(wimp_update_wind(&r,&more));
805 buttons_redrawColourButton(d,i,c);
806 wimpt_noerr(wimp_get_rectangle(&r,&more));