📄 spinbutton.c
字号:
else { xm_string = spin_p->items[spin_p->position]; if ((text = GetTextString(xm_string))) { XtSetArg(arg, XmNvalue, text); XtSetValues(spin_p->text, &arg, 1); XtFree(text); } } }}/* * Set the maximum size of the label, depending on the * characteristics of the list of items. Not very efficient * if switching from numeric to non-numeric. */static voidSetMaximumLabelSize(spin_p)DtSpinButtonPart *spin_p;{ XmString xm_string; XmFontList font_list; char string[NUMERIC_LENGTH]; Dimension width, height; Dimension longest = 0; Dimension highest = 0; Arg args[5]; int i; /* Get font info from the widget */ XtSetArg(args[0], XmNfontList, &font_list); XtGetValues(spin_p->label, args, 1); if (spin_p->child_type == XmNUMERIC) { /* Find out maximum size of the widget from min/max */ sprintf(string, spin_p->float_format, spin_p->min); xm_string = XmStringCreateSimple(string); XmStringExtent(font_list, xm_string, &longest, &highest); XmStringFree(xm_string); sprintf(string, spin_p->float_format, spin_p->max); xm_string = XmStringCreateSimple(string); XmStringExtent(font_list, xm_string, &width, &height); XmStringFree(xm_string); longest = (width > longest) ? width : longest; highest = (height > highest) ? height : highest; } else if (spin_p->items) { /* * Loop through all the items to find the biggest dimensions */ for (i = 0; i < spin_p->item_count; i++) { XmStringExtent(font_list, spin_p->items[i], &width, &height); longest = (width > longest) ? width : longest; highest = (height > highest) ? height : highest; } } else XmStringExtent(font_list, InitLabel, &longest, &highest); spin_p->label_max_length = longest + (LABEL_PADDING * 2); spin_p->label_max_height = highest; XtResizeWidget(spin_p->label, spin_p->label_max_length, highest, spin_p->label->core.border_width);}/* * Put the current list item into the label. */static voidSetLabelData(spin)DtSpinButtonWidget spin;{ DtSpinButtonPart *spin_p = (DtSpinButtonPart*)&(spin->spin_button); XmString xm_string; char string[NUMERIC_LENGTH]; int index = spin_p->position; Arg arg; if (spin_p->child_type == XmNUMERIC) { sprintf(string, spin_p->float_format, (float)spin_p->current); xm_string = XmStringCreateSimple(string); XtSetArg(arg, XmNlabelString, xm_string); XtSetValues(spin_p->label, &arg, 1); } else { /* * If the item is not empty, get the current item from the list, else * use InitLabel. */ xm_string = (spin_p->items) ? spin_p->items[index] : InitLabel; XtSetArg(arg, XmNlabelString, xm_string); XtSetValues(spin_p->label, &arg, 1); }}/* * Timout dispatch routine. This calls the appropriate callback function * to simulate up or down arrow activation. */static voidtimer_dispatch(client_data, id)XtPointer client_data;XtIntervalId *id;{ DtSpinButtonWidget spin_w = (DtSpinButtonWidget)client_data; DtSpinButtonPart *spin_p = (DtSpinButtonPart*)&(spin_w->spin_button); timer = 0; spin_p->init_cb = FALSE; if (spin_p->which_arrow == XmARROW_UP) { if (spin_p->grabbed) { XtRemoveGrab(spin_p->up_arrow); spin_p->grabbed = FALSE; } up_cb(NULL, client_data, NULL); } else { if (spin_p->grabbed) { XtRemoveGrab(spin_p->down_arrow); spin_p->grabbed = FALSE; } down_cb(NULL, client_data, NULL); }}static voidTextFieldActivate(spin_p)DtSpinButtonPart *spin_p;{ XmTextFieldWidget w = (XmTextFieldWidget)(spin_p->text); XmAnyCallbackStruct cb; char string[NUMERIC_LENGTH]; char *data = NULL; char *text = NULL; Arg arg; Boolean free_me = TRUE; XtSetArg(arg, XmNvalue, &data); XtGetValues((Widget)w, &arg, 1); if (spin_p->child_type == XmNUMERIC) { sprintf(string, spin_p->float_format, (float)spin_p->current); text = string; free_me = FALSE; } else if (spin_p->items) text = GetTextString(spin_p->items[spin_p->position]); if (text && data && (strcmp(text, data) == 0)) { if (free_me) XtFree(text); return; } /* Only send callback if both are not NULL */ else if (!((text == NULL) && (data == NULL))) { cb.reason = XmCR_ACTIVATE; cb.event = NULL; XtCallCallbackList((Widget)w, w->text.activate_callback, (XtPointer)&cb); if (text && free_me) XtFree(text); }}/* * This function calls the appropriate callback for the spin-button. * It gathers the correct arguments and fills in the callback structure. */static BooleanSendCallback(spin, event, value_changed, position, current, crossed)DtSpinButtonWidget spin;XEvent *event;Boolean value_changed;int position;float current; /* Used for numeric */Boolean crossed;{ DtSpinButtonPart *spin_p = (DtSpinButtonPart*)&(spin->spin_button); DtSpinButtonCallbackStruct cb; XmString xm_string = NULL; char string[NUMERIC_LENGTH]; if (spin_p->child_type == XmNUMERIC) { sprintf(string, spin_p->float_format, (float)current); xm_string = XmStringCreateSimple(string); } else { xm_string = (spin_p->items) ? spin_p->items[position] : InitLabel; xm_string = XmStringCopy(xm_string); } if (event) cb.reason = XmCR_OK; else if (spin_p->which_arrow == XmARROW_UP) cb.reason = XmCR_SPIN_UP; else cb.reason = XmCR_SPIN_DOWN; cb.doit = TRUE; cb.event = event; cb.widget = (Widget)spin; cb.position = position; cb.value = xm_string; cb.crossed_boundary = crossed; if (value_changed) { XtCallCallbackList((Widget)spin, spin_p->value_changed_callback, (XtPointer)&cb); cb.doit = TRUE; } else { XtCallCallbackList((Widget)spin, spin_p->modify_verify_callback, (XtPointer)&cb); } XmStringFree(xm_string); return(cb.doit);}/* * This function gets called by the up/down arm callback functions. * We set up the timer and send the modify-verify and value-changed * callbacks. * There are potential problems if the user does some weird stuff * in the callbacks. I have added protection against the case where * a user does a grab (with XtAddGrab/XtPopup/etc.) in the callbacks. * Grabbing in the callback would cause us to lose the button-release * (disarm), which would make the timer go on forever. A grab is * done after the callbacks just to make sure we will receive the * button-release. The button-release will call disarm_cb() which will * un-grab and disable the timer. I have also added a leave callback * which helps to protect against these kinds of problems. * If the callback goes into another event-loop (which I hope would * never happen), we would spin continuously (since our XtAddGrab never * get called), until the user left the window (which would call * grab_leave_cb). The grabbed flag gets set if we do the grab, so that * we know if we can remove the grab. Our XtAddGrab() might not get called * if the callback enters another event-loop. * * The event sent in the callback will be NULL during continuous spinning. */static voidFinishUpDown(spin, arrow_call_data, new_position, new_current, crossed)DtSpinButtonWidget spin;XtPointer arrow_call_data;int new_position;float new_current;Boolean crossed;{ DtSpinButtonPart *spin_p = (DtSpinButtonPart*)&(spin->spin_button); XmArrowButtonCallbackStruct *arrow_data; XEvent *last_event = NULL; int repeat_delay = spin_p->repeat_delay; if (spin_p->init_cb) repeat_delay = spin_p->initial_delay; timer = XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)spin), repeat_delay, timer_dispatch, (XtPointer)spin); /* Try to get Xevent */ if ((arrow_data = (XmArrowButtonCallbackStruct*)arrow_call_data)) last_event = arrow_data->event; /* * Send modify_verify callback. If user says no, then * clear the timer and reset the state before returning. */ if (SendCallback(spin, last_event, FALSE, new_position, new_current, crossed) == FALSE) { XtRemoveTimeOut(timer); timer = (XtIntervalId)NULL; spin->spin_button.init_cb = TRUE; return; } /* User said yes, so set widget values */ spin_p->position = new_position; spin_p->current = new_current; if (spin_p->editable) SetTextFieldData(spin); else SetLabelData(spin); /* send value_changed callback */ (void)SendCallback(spin, last_event, TRUE, spin_p->position, spin_p->current, crossed); /* See notes at top of function on XtAddGrab usage */ spin_p->grabbed = TRUE; if (spin_p->which_arrow == XmARROW_UP) XtAddGrab(spin_p->up_arrow, FALSE, FALSE); else XtAddGrab(spin_p->down_arrow, FALSE, FALSE);}/* * Show the next value in the SpinButton. If numeric, just add the * increment value. If using string-table, get the next one in the * table. This function takes care of wrap around. Set the arrow * type. This is needed for the timer_dispatch function. up_cb * gets called the first time the button is pressed, and each time the * timer goes off. * All widget internals are expected to be correct here; they * get verified when set by the user. */static voidup_cb(w, client_data, call_data)Widget w;XtPointer client_data;XtPointer call_data;{ DtSpinButtonWidget spin = (DtSpinButtonWidget)client_data; DtSpinButtonPart *spin_p = (DtSpinButtonPart*)&(spin->spin_button); Boolean crossed_boundary = FALSE; int new_position = spin_p->position; float new_current = spin_p->current; if (spin_p->editable) TextFieldActivate(spin_p); /* * If non-numeric and no items then ignore the user activate event. */ if ((spin_p->child_type == XmSTRING) && (spin_p->items == NULL)) return; if (spin_p->child_type == XmNUMERIC) { if ((new_current + spin_p->increment) > spin_p->max) { if (spin_p->wrap) { new_position = spin_p->minimum; new_current = spin_p->min; crossed_boundary = TRUE; } else XBell(XtDisplayOfObject((Widget)spin), 0); } else { new_position += spin_p->numeric_increment; new_current += spin_p->increment; } } else if (spin_p->items) { if (new_position == (spin_p->item_count - 1)) { if (spin_p->wrap) { new_position = 0; crossed_boundary = TRUE; } else XBell(XtDisplayOfObject((Widget)spin), 0); } else new_position++; } spin_p->which_arrow = XmARROW_UP; FinishUpDown(spin, call_data, new_position, new_current, crossed_boundary);}/* * Show the previous value in the SpinButton. If numeric, just decrement * the increment value. If using string-table, get the previous one in the * table. This function takes care of wrap around. Set the arrow * type. This is needed for the timer_dispatch function. down_cb * gets called the first time the button is pressed, and each time the * timer goes off. * All widget internals are expected to be correct here; they * get verified when set by the user. */static voiddown_cb(w, client_data, call_data)Widget w;XtPointer client_data;XtPointer call_data;{ DtSpinButtonWidget spin = (DtSpinButtonWidget)client_data; DtSpinButtonPart *spin_p = (DtSpinButtonPart*)&(spin->spin_button); Boolean crossed_boundary = FALSE; int new_position = spin_p->position; f
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -