X-Git-Url: http://git.draconx.ca/gitweb/rrace.git/blobdiff_plain/aebcc2d9a4090d8136f750463b1cfbb73916d717..4ba1a1949117408cf81132b4f168a4e7f0a79ac3:/src/xcounter.h diff --git a/src/xcounter.h b/src/xcounter.h new file mode 100644 index 0000000..6109b05 --- /dev/null +++ b/src/xcounter.h @@ -0,0 +1,105 @@ +/* + * Helpers for implementing a rapid-update counter display in Motif. + * Copyright © 2022 Nick Bowler + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * A set of functions to implement a simple counter display with better support + * for rapid updates than regular XmLabel (and other Motif text display widgets). + * + * This is intended to avoid two specific practical problems with these widgets: + * + * (1) Any update to the text involves dynamic allocation of XmStrings + * (2) Updating the text causes the entire label to be redrawn. + * + * Point #2 can lead to annoying flicker on static portions of the label when + * updates are occurring continuously. + * + * These functions are intended for displaying strings that consist of non- + * changing static text with digits interspersed. Specifically, strings such + * as "The time is 12:30:57." + * + * Passing this string as the template argument to xcounter_init will pre- + * allocate an XmString values for each of the four maximal nondigit + * substrings. These nondigit parts cannot be changed. + * + * On a subsequent call to xcounter_update, a different string may be passed. + * The digits in this string are used to construct a sequence of XmString + * values that includes the precomputed static portions interspersed with + * digits. This new string is expected to be in the same format as the + * template although there are two possible exceptions: + * + * - The nondigit substrings do not need to match the template; they are + * used only to separate different groups of digits and otherwise have + * no effect on the output. + * + * - If the new string may be a prefix of the template, only that portion + * will be output. However it is still not possible to alter the static + * portions: they are either present in their entirety or omitted. + * + * The xcounter_redraw function can then be used to redraw only the portions of + * the string that have changed since the last redraw. + */ + +#ifndef XCOUNTER_H_ +#define XCOUNTER_H_ + +/* + * Create xcounter based on template, which should be representative of + * the number of digits expected to preallocate a typical number of digits. + * + * Note that the provided template string will be modified by this function, + * but restored to its original value before returning. + */ +struct xcounter *xcounter_init(Widget w, char *template); + +/* + * Update xcounter segments according to str. + * + * The nondigit sequences are assumed to match those from the original + * template. + */ +void xcounter_update(Widget w, struct xcounter *xc, const char *str); + +/* + * Redraw the counter in response to an expose event. + */ +void xcounter_expose(Widget w, struct xcounter *xc, XExposeEvent *e); + +/* + * Resize and expose callbacks that can be registered on a drawing area widget. + */ +void xcounter_resize_cb(Widget w, void *data, void *cb_data); +void xcounter_expose_cb(Widget w, void *data, void *cb_data); + +static inline void xcounter_simple_setup(Widget w, char *template) +{ + struct xcounter *xc = xcounter_init(w, template); + + XtVaSetValues(w, XmNuserData, (void *)xc, (char *)NULL); + XtAddCallback(w, XmNresizeCallback, xcounter_resize_cb, xc); + XtAddCallback(w, XmNexposeCallback, xcounter_expose_cb, xc); +} + +static inline void xcounter_simple_update(Widget w, const char *str) +{ + void *xc; + + XtVaGetValues(w, XmNuserData, &xc, (char *)NULL); + xcounter_update(w, xc, str); +} + +#endif