The HP-67 emulator, a command-line interface begins

Now that the internals for interactive mode are mainly done, it’s time to put a front-end on it, so that we can have something to test on.

I’m not an interface person, I write computational engines, and have little experience interacting with the user of the program.  If a reader could recommend a good GUI from among those on cliki.net that I should use for the graphical interface, that would be helpful.

In the mean time, I’m starting a text-based interface, using NCurses.  The library I’ll be using is cl-charms, as it’s based on the more modern CFFI system for calling external libraries.

The CLI behaves differently from a GUI that replicates the behaviour of the calculator.  For instance, you’re not likely to input numbers one digit at a time, you can simply type the entire number into the prompt.  Also, some keys are unnecessary in this context.  For instance, the specific gosub keys for labels A, B, C, D, E, and their lower-case equivalents.  From the CLI you would just enter the label on the line, so having those keys there only clutters the display.

In the CLI, we will want all of the keys to have natural positions in the table, but only display those keys which have meaning in the current mode.  This means that keys that only have effect in programming mode shouldn’t be displayed in interactive mode.  We’ll leave those spaces blank, to avoid confusion with key names moving around based on the mode.

One minor annoyance, cl-charms doesn’t run within a SLIME context, so we’ll have to test outside of SLIME.

Here is the beginning of the CLI function.  This just displays the keys, waits 4 seconds, then exits:
curses-cli.lisp

(defun main()
  (charms:with-curses ()
    (charms:disable-echoing)
    (charms:disable-extra-keys charms:*standard-window*)
    (charms:enable-non-blocking-mode charms:*standard-window*)
    (charms:enable-raw-input :interpret-control-characters t)

    (multiple-value-bind (n-cols n-rows)
        (charms:window-dimensions charms:*standard-window*)

      (let* ((stack (get-new-stack-object 4))
             (mode (get-new-mode-object))
             (all-keys (get-key-abbrevs mode
                                        :sort-fcn #'comp<
                                        :veto-list *excluded-keys*))
             (maxlen (apply 'max
                            (mapcar 'length all-keys)))
             (keys-per-row (floor (/ n-cols (1+ maxlen)))))

        (do (exit-requested)
            (exit-requested)

          (charms:clear-window charms:*standard-window*)

          (let ((active-keys (get-key-abbrevs mode
                                              :sort-fcn #'comp<
                                              :veto-list *excluded-keys*
                                              :limit-to-mode t))
                (i 0))

            (dolist (candidate all-keys)
              (when (member candidate active-keys
                            :test 'string=)
                (multiple-value-bind (r c)
                    (floor i keys-per-row)
                  (charms:move-cursor charms:*standard-window*
                                      (* c (1+ maxlen))
                                      r))
                (charms:write-string-at-cursor charms:*standard-window*
                                               candidate))
              (incf i))

            (charms:refresh-window charms:*standard-window*)

            (sleep 4)

            (setf exit-requested t)

            ))))))

This code is checked into the git repository under the tag v2014-11-22.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

反垃圾邮件 / Anti-spam question * Time limit is exhausted. Please reload CAPTCHA.