/* Written by Dan Heller and Paula Ferguson. * Copyright 1994, O'Reilly & Associates, Inc. * Permission to use, copy, and modify this program without * restriction is hereby granted, as long as this copyright * notice appears in each copy of the program source code. * This program is freely distributable without licensing fees and * is provided without guarantee or warrantee expressed or implied. * This program is -not- in the public domain. */ /* arrow_timer.c -- demonstrate continuous callbacks using * ArrowButton widgets. Display up and down ArrowButtons and * attach arm and disarm callbacks to them to start and stop timer * that is called repeatedly while the button is down. A label * that has a value changes either positively or negatively * by single increments while the button is depressed. */ #include <Xm/ArrowBG.h> #include <Xm/Form.h> #include <Xm/RowColumn.h> #include <Xm/LabelG.h> XtAppContext app; Widget label; XtIntervalId arrow_timer_id; typedef struct value_range { int value, min_, max_; } ValueRange; main(argc, argv) int argc; char *argv[]; { Widget w, toplevel, rowcol; void start_stop(); ValueRange range; XtSetLanguageProc (NULL, NULL, NULL); toplevel = XtVaAppInitialize (&app, "Demos", NULL, 0, &argc, argv, NULL, NULL); rowcol = XtVaCreateWidget ("rowcol", xmRowColumnWidgetClass, toplevel, XmNorientation, XmHORIZONTAL, NULL); w = XtVaCreateManagedWidget ("arrow_up", xmArrowButtonGadgetClass, rowcol, XmNarrowDirection, XmARROW_UP, NULL); /*XtAddCallback (w, XmNarmCallback, start_stop, 1); XtAddCallback (w, XmNdisarmCallback, start_stop, 1);*/ XtAddCallback (w, XmNarmCallback, start_stop, (XtPointer)1); XtAddCallback (w, XmNdisarmCallback, start_stop, (XtPointer)1); w = XtVaCreateManagedWidget ("arrow_dn", xmArrowButtonGadgetClass, rowcol, XmNarrowDirection, XmARROW_DOWN, NULL); /*XtAddCallback (w, XmNarmCallback, start_stop, -1); XtAddCallback (w, XmNdisarmCallback, start_stop, -1);*/ XtAddCallback (w, XmNarmCallback, start_stop, (XtPointer)-1); XtAddCallback (w, XmNdisarmCallback, start_stop, (XtPointer)-1); range.value = 0; range.min_ = -50; range.max_ = 50; label = XtVaCreateManagedWidget ("label", xmLabelGadgetClass, rowcol, XtVaTypedArg, XmNlabelString, XmRString, "0 ", 3, XmNuserData, &range, NULL); XtManageChild (rowcol); XtRealizeWidget (toplevel); XtAppMainLoop (app); } /* start_stop is used to start or stop the incremental changes to * the label's value. When the button goes down, the reason is * XmCR_ARM and the timer starts. XmCR_DISARM disables the timer. */ void start_stop(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { int incr = (int) client_data; XmArrowButtonCallbackStruct *cbs = (XmArrowButtonCallbackStruct *) call_data; void change_value(); if (cbs->reason == XmCR_ARM) change_value (incr, 1 ); else if (cbs->reason == XmCR_DISARM) XtRemoveTimeOut (arrow_timer_id); } /* change_value is called each time the timer expires. This function * is also used to initiate the timer. The "id" represents that timer * ID returned from the last call to XtAppAddTimeOut(). If id == 1, * the function was called from start_stop(), not a timeout. If the value * has reached its max_imum or min_imum, don't restart timer, just return. * If id == 1, this is the first timeout so make it be longer to allow * the user to release the button and avoid getting into the "speedy" * part of the timeouts. */ void change_value(client_data, id) XtPointer client_data; XtIntervalId* id; { ValueRange *range; char buf[8]; int incr = (int) client_data; XtVaGetValues (label, XmNuserData, &range, NULL); if (range->value + incr > range->max_ || range->value + incr < range->min_) return; range->value += incr; sprintf (buf, "%d", range->value); XtVaSetValues (label, XtVaTypedArg, XmNlabelString, XmRString, buf, strlen(buf), NULL); arrow_timer_id = XtAppAddTimeOut (app, (int)id==1? 500 : 100, change_value, (XtPointer)incr); }