]> git.draconx.ca Git - rrace.git/blobdiff - src/xcounter.h
Add timer display.
[rrace.git] / src / xcounter.h
diff --git a/src/xcounter.h b/src/xcounter.h
new file mode 100644 (file)
index 0000000..6109b05
--- /dev/null
@@ -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 <https://www.gnu.org/licenses/>.
+ */
+
+/*
+ * 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