shithub: orca

Download patch

ref: af8178e8f65b48bf5065175e16d12ef1c3bfe962
parent: 8c20e0eb8b38aa0bdcb50d9af2e9a6839d9f143c
author: cancel <cancel@cancel.fm>
date: Sat Jan 4 23:45:03 EST 2020

Add start of PortMidi device choosing (WIP)

Does not yet let you actually pick the device, only list.

--- a/term_util.c
+++ b/term_util.c
@@ -213,6 +213,53 @@
   return qm;
 }
 
+void qmsg_printf_push(char const* title, char const* fmt, ...) {
+  int titlewidth = title ? (int)strlen(title) : 0;
+  va_list ap;
+  va_start(ap, fmt);
+  int msgbytes = vsnprintf(NULL, 0, fmt, ap);
+  va_end(ap);
+  char* buffer = malloc((Usz)msgbytes + 1);
+  if (!buffer)
+    exit(1);
+  va_start(ap, fmt);
+  vsnprintf(buffer, (Usz)msgbytes + 1, fmt, ap);
+  va_end(ap);
+  int lines = 1;
+  int curlinewidth = 0;
+  int maxlinewidth = 0;
+  for (int i = 0; i < msgbytes; i++) {
+    if (buffer[i] == '\n') {
+      buffer[i] = '\0'; // This is terrifying :)
+      lines++;
+      if (curlinewidth > maxlinewidth)
+        maxlinewidth = curlinewidth;
+      curlinewidth = 0;
+    } else {
+      curlinewidth++;
+    }
+  }
+  if (curlinewidth > maxlinewidth)
+    maxlinewidth = curlinewidth;
+  int width = titlewidth > maxlinewidth ? titlewidth + 1 : maxlinewidth + 1;
+  Qmsg* msg = qmsg_push(lines, width); // no wrapping yet, no real wcwidth, etc
+  WINDOW* msgw = qmsg_window(msg);
+  int i = 0;
+  int offset = 0;
+  for (;;) {
+    if (offset == msgbytes + 1)
+      break;
+    int numbytes = (int)strlen(buffer + offset);
+    wmove(msgw, i, 1);
+    waddstr(msgw, buffer + offset);
+    offset += numbytes + 1;
+    i++;
+  }
+  free(buffer);
+  if (title)
+    qmsg_set_title(msg, title);
+}
+
 bool qmsg_drive(Qmsg* qm, int key) {
   (void)qm;
   switch (key) {
@@ -236,6 +283,7 @@
   qm->id = id;
   return qm;
 }
+void qmenu_destroy(Qmenu* qm) { qmenu_free(qm); }
 int qmenu_id(Qmenu const* qm) { return qm->id; }
 void qmenu_set_title(Qmenu* qm, char const* title) {
   qblock_set_title(&qm->qblock, title);
--- a/term_util.h
+++ b/term_util.h
@@ -119,10 +119,18 @@
 Qmsg* qmsg_push(int height, int width);
 WINDOW* qmsg_window(Qmsg* qm);
 void qmsg_set_title(Qmsg* qm, char const* title);
+#ifdef __GNUC__
+__attribute__((format(printf, 2, 3)))
+#endif
+void qmsg_printf_push(char const* title, char const* fmt, ...);
 bool qmsg_drive(Qmsg* qm, int key);
 Qmsg* qmsg_of(Qblock* qb);
 
 Qmenu* qmenu_create(int id);
+// Useful if menu creation needs to be aborted part-way. Otherwise, no need to
+// call -- pushing the qmenu to the qnav stack transfers ownership. (Still
+// working on this design, not sure yet.)
+void qmenu_destroy(Qmenu* qm);
 int qmenu_id(Qmenu const* qm);
 void qmenu_set_title(Qmenu* qm, char const* title);
 void qmenu_add_choice(Qmenu* qm, char const* text, int id);
--- a/tui_main.c
+++ b/tui_main.c
@@ -1859,6 +1859,9 @@
   Set_grid_dims_form_id,
   Autofit_menu_id,
   Confirm_new_file_menu_id,
+#ifdef FEAT_PORTMIDI
+  Portmidi_output_device_menu_id,
+#endif
 };
 enum {
   Open_name_text_line_id = 1,
@@ -1892,6 +1895,9 @@
   Main_menu_set_grid_dims,
   Main_menu_autofit_grid,
   Main_menu_about,
+#ifdef FEAT_PORTMIDI
+  Main_menu_choose_portmidi_output,
+#endif
 };
 
 void push_main_menu(void) {
@@ -1906,6 +1912,10 @@
   qmenu_add_choice(qm, "Set Grid Size...", Main_menu_set_grid_dims);
   qmenu_add_choice(qm, "Auto-fit Grid", Main_menu_autofit_grid);
   qmenu_add_spacer(qm);
+#ifdef FEAT_PORTMIDI
+  qmenu_add_choice(qm, "PortMIDI Output", Main_menu_choose_portmidi_output);
+  qmenu_add_spacer(qm);
+#endif
   qmenu_add_choice(qm, "Controls...", Main_menu_controls);
   qmenu_add_choice(qm, "Operators...", Main_menu_opers_guide);
   qmenu_add_choice(qm, "About...", Main_menu_about);
@@ -2162,6 +2172,38 @@
   qform_push_to_nav(qf);
 }
 
+#ifdef FEAT_PORTMIDI
+void push_portmidi_output_device_menu(void) {
+  Qmenu* qm = qmenu_create(Portmidi_output_device_menu_id);
+  qmenu_set_title(qm, "PortMidi Device Selection");
+  PmError e = portmidi_init_if_necessary();
+  if (e) {
+    qmenu_destroy(qm);
+    qmsg_printf_push("PortMidi Error",
+                     "PortMidi error during initialization:\n%s",
+                     Pm_GetErrorText(e));
+    return;
+  }
+  int num = Pm_CountDevices();
+  int output_devices = 0;
+  for (int i = 0; i < num; ++i) {
+    PmDeviceInfo const* info = Pm_GetDeviceInfo(i);
+    if (!info || !info->output)
+      continue;
+    qmenu_add_choice(qm, info->name, i);
+    // printf("ID: %-4d Name: %s\n", i, info->name);
+    ++output_devices;
+  }
+  if (output_devices == 0) {
+    qmenu_destroy(qm);
+    qmsg_printf_push("No PortMidi Devices",
+                     "No PortMidi output devices found.");
+    return;
+  }
+  qmenu_push_to_nav(qm);
+}
+#endif
+
 //
 // Misc utils
 //
@@ -2849,6 +2891,11 @@
               case Main_menu_autofit_grid:
                 push_autofit_menu();
                 break;
+#ifdef FEAT_PORTMIDI
+              case Main_menu_choose_portmidi_output:
+                push_portmidi_output_device_menu();
+                break;
+#endif
               }
             } else if (qmenu_id(qm) == Autofit_menu_id) {
               Usz new_field_h, new_field_w;