]> git.draconx.ca Git - rrace.git/blobdiff - src/xcounter.h
Reimplement xcounter based on pre-rendered pixmpas.
[rrace.git] / src / xcounter.h
index 6109b0594a9a9636db2510fb3c53f0f0f734f7a1..e08b8a8a6333fb9b1bc9d9302abfb6182328c0b1 100644 (file)
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+#ifndef XCOUNTER_H_
+#define XCOUNTER_H_
+
 /*
- * 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).
+ * A set of functions to implement a simple decimal counter display supporting
+ * rapid updates.  This is intended to avoid two specific practical problems
+ * with the Motif text widgets:
  *
- * This is intended to avoid two specific practical problems with these widgets:
+ *  (1) Updating the text involves expensive(?) XmString operations, and
+ *  (2) Updating the text causes the label to be cleared and redrawn.
  *
- *  (1) Any update to the text involves dynamic allocation of XmStrings
- *  (2) Updating the text causes the entire label to be redrawn.
+ * Point #2 in particular results in very annoying flicker.
  *
- * Point #2 can lead to annoying flicker on static portions of the label when
- * updates are occurring continuously.
+ * These functions are intended for dealing with strings that consist of
+ * "static" text interspersed with digits.  For example, a string such as:
  *
- * 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."
+ *    "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 call to xcounter_init, a string like this is provided as the template.
+ * The "static" elements are all the maximal nondigit substrings, which in this
+ * instance are "The time is ", ":" (twice) and ".".  These static elements
+ * are pre-rendered to an X pixmap along with all possible decimal digits.
  *
- * 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:
+ * A subsequent call to xcounter_update will change the displayed string by
+ * combining the pre-rendered images in various ways.  This takes a strings in
+ * the same format the original template to modify the digit sequences.
  *
- *   - 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.
+ * This solves the practical problems by significantly simplifying the actual
+ * X drawing process (just a single operation to update any particular pixel).
+ * This avoids the flicker inherent to a clear+redraw, and a simple change
+ * tracking scheme is employed to avoid redundant drawing for a smoother
+ * update.
  *
- *   - 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.
+ * To simplify the implementation, some arbitrary limits are baked in:
  *
- * The xcounter_redraw function can then be used to redraw only the portions of
- * the string that have changed since the last redraw.
+ *   - maximum number of static elements in a template:            10
+ *   - maximum number of digits plus static elements in an update: 23
+ *
+ * Which should be more than enough to handle the RRace displays.
  */
 
-#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.
+ * Create xcounter based on template.
  *
- * Note that the provided template string will be modified by this function,
- * but restored to its original value before returning.
+ * The provided template must be writeable as it is internally modified by
+ * this function.  However, it is restored to its original value upon return.
  */
 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.
+ * Generally, the string should be in the same format as the original
+ * template, with only the digits changing between calls.  However, there
+ * are two allowed exceptions:
+ *
+ *   - It does not matter what exact text is placed in the static portions
+ *     between digits, provided they are nonempty.  These are used only to
+ *     separate groups of digits.  The pre-rendered text from the original
+ *     template is always used.
+ *
+ *   - The updated string need not include all the elements of the original
+ *     template.  Omitted elements from the update string are not drawn.
  */
-void xcounter_update(Widget w, struct xcounter *xc, const char *str);
+void xcounter_update(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);
+void xcounter_expose(struct xcounter *xc, XExposeEvent *e);
 
 /*
- * Resize and expose callbacks that can be registered on a drawing area widget.
+ * Resize and expose callbacks that can be registered on an XmDrawingArea.
  */
 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)
+/*
+ * Clear the margins of the counter after resizing the widget.
+ *
+ * Since the pre-rendered text never changes, this is all that is needed:
+ * existing portions of the window do not need to be redrawn (except when
+ * shrinking the margins over previously-drawn text), and newly-revealed
+ * areas will get expose events to trigger redraw.
+ */
+static inline void xcounter_resize(struct xcounter *xc)
+{
+       xcounter_resize_cb(0, xc, 0);
+}
+
+static inline struct xcounter *xcounter_simple_init(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);
+       return xc;
 }
 
 #endif