summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@bitwiz.me.uk>2019-05-28 22:53:11 +0200
committerThomas White <taw@bitwiz.me.uk>2019-05-28 22:53:11 +0200
commit1e32c49b4d08b1d517ccda7380c3909986d9d7cd (patch)
treeffde0e1e71926d8dfd3a147c5b9ef9d75cdb2678
parentec0a7bac9d80b4ac094e361535f1ce4a5f5c6487 (diff)
Command line and rendering stuff
-rw-r--r--meson.build1
-rw-r--r--src/command.c185
-rw-r--r--src/command.h28
-rw-r--r--src/nanolight.c207
-rw-r--r--src/nanolight.h8
5 files changed, 417 insertions, 12 deletions
diff --git a/meson.build b/meson.build
index d939dac..96aea93 100644
--- a/meson.build
+++ b/meson.build
@@ -24,6 +24,7 @@ mdep = cc.find_library('m', required : false)
# Main program
executable('nanolight',
['src/nanolight.c',
+ 'src/command.c',
],
dependencies : [gtk_dep, mdep],
install : true)
diff --git a/src/command.c b/src/command.c
new file mode 100644
index 0000000..7ae36ae
--- /dev/null
+++ b/src/command.c
@@ -0,0 +1,185 @@
+/*
+ * command.c
+ *
+ * Copyright © 2019 Thomas White <taw@bitwiz.me.uk>
+ *
+ * This file is part of NanoLight.
+ *
+ * NanoLight 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <libintl.h>
+#define _(x) gettext(x)
+
+#include "nanolight.h"
+
+enum token_type
+{
+ TK_FIXTURE,
+ TK_AT,
+ TK_DOT,
+ TK_TO,
+ TK_LEVEL,
+ TK_ATTRIBUTE,
+};
+
+
+struct token
+{
+ enum token_type type;
+ int fixture_index;
+ int val;
+};
+
+
+static int stop_char(char c)
+{
+ if ( c == '@' ) return 1;
+ if ( c == ' ' ) return 1;
+ if ( c == '\0' ) return 1;
+ if ( c == '.' ) return 1;
+ if ( c == '-' ) return 1;
+ return 0;
+}
+
+
+static int find_tokens(const char *cmd, struct token *tokens, struct nanolight *nl)
+{
+ int i;
+ int n = 0;
+ int pos = 0;
+ do {
+ int start;
+ char *word;
+ unsigned long val;
+ char *endptr;
+ int done = 0;
+
+ while ( isspace(cmd[pos]) ) pos++;
+ start = pos;
+
+ /* Is it an AT? */
+ if ( cmd[pos] == '@' ) {
+ tokens[n++].type = TK_AT;
+ pos++;
+ continue;
+ }
+
+ /* Is it a dot? */
+ if ( cmd[pos] == '.' ) {
+ tokens[n++].type = TK_DOT;
+ pos++;
+ continue;
+ }
+
+ /* Is it a dash? */
+ if ( cmd[pos] == '-' ) {
+ tokens[n++].type = TK_TO;
+ pos++;
+ continue;
+ }
+
+ while ( !stop_char(cmd[pos]) ) pos++;
+ word = strndup(cmd+start, pos-start);
+
+ /* Is is a fixture name? */
+ for ( i=0; i<nl->n_fixtures; i++ ) {
+ if ( strcasecmp(nl->fixtures[i].label, word) == 0 ) {
+ tokens[n].fixture_index = i;
+ tokens[n++].type = TK_FIXTURE;
+ done = 1;
+ break;
+ }
+ }
+
+ /* Is is an attribute name? */
+ for ( i=0; i<nl->n_fixtures; i++ ) {
+ if ( strcasecmp(nl->fixtures[i].label, word) == 0 ) {
+ tokens[n].fixture_index = i;
+ tokens[n++].type = TK_FIXTURE;
+ done = 1;
+ break;
+ }
+ }
+
+ /* Is it a number? */
+ val = strtoul(word, &endptr, 10);
+ if ( (word[0] != '\0') && (endptr[0] == '\0') ) {
+ tokens[n].val = val;
+ tokens[n++].type = TK_LEVEL;
+ done = 1;
+ }
+
+ free(word);
+
+ if ( !done ) return 0;
+
+ } while ( cmd[pos] != '\0' );
+ return n;
+}
+
+
+static void show_tokens(struct token *tokens, int n, struct nanolight *nl)
+{
+ int i;
+
+ for ( i=0; i<n; i++ ) {
+ switch ( tokens[i].type ) {
+
+ case TK_FIXTURE:
+ printf(" [fixture:%s]", nl->fixtures[tokens[i].fixture_index].label);
+ break;
+
+ case TK_AT:
+ printf(" [@]");
+ break;
+
+ case TK_DOT:
+ printf(" [.]");
+ break;
+
+ case TK_TO:
+ printf(" [-]");
+ break;
+
+ case TK_LEVEL:
+ printf(" [value:%i]", tokens[i].val);
+ break;
+
+ }
+ }
+
+ printf("\n");
+}
+
+
+int command_run(const char *cmd, struct nanolight *nl)
+{
+ struct token tokens[1024];
+ int n;
+
+ n = find_tokens(cmd, tokens, nl);
+ if ( n == 0 ) return 1;
+
+ show_tokens(tokens, n, nl);
+
+ return 0;
+}
+
diff --git a/src/command.h b/src/command.h
new file mode 100644
index 0000000..2d540d4
--- /dev/null
+++ b/src/command.h
@@ -0,0 +1,28 @@
+/*
+ * command.h
+ *
+ * Copyright © 2019 Thomas White <taw@bitwiz.me.uk>
+ *
+ * This file is part of NanoLight.
+ *
+ * NanoLight 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef COMMAND_H
+#define COMMAND_H
+
+extern int command_run(const char *cmd, struct nanolight *nl);
+
+#endif /* COMMAND_H */
diff --git a/src/nanolight.c b/src/nanolight.c
index 4c657df..6cb06e6 100644
--- a/src/nanolight.c
+++ b/src/nanolight.c
@@ -33,6 +33,7 @@
#define _(x) gettext(x)
#include "nanolight.h"
+#include "command.h"
static void show_help(const char *s)
{
@@ -43,12 +44,28 @@ static void show_help(const char *s)
#define OVERALL_BORDER (20.0)
#define OVERALL_SPLIT (0.5)
+#define FIXTURE_BORDER (5.0)
+
+static double get_attr_val(struct fixture *fix, enum attr_class acls)
+{
+ int i;
+ for ( i=0; i<fix->cls->n_attrs; i++ ) {
+ if ( fix->cls->attrs[i].cls == acls ) {
+ int max = 255;
+ if ( fix->cls->attrs[i].props & ATTR_16BIT ) max = 65535;
+ return (double)fix->attr_vals[i] / max;
+ }
+ }
+ return 0.0;
+}
+
static void draw_fixture(cairo_t *cr, PangoContext *pc, PangoFontDescription *fontdesc,
- struct nanolight *nl, struct fixture *fx)
+ struct nanolight *nl, struct fixture *fix)
{
PangoLayout *layout;
- const double w = nl->fixture_width;
+ const double w = 40.0;
+ char tmp[32];
cairo_rectangle(cr, 0.5, 0.5, w, 3.0/2.0*w);
cairo_set_source_rgb(cr, 0.3, 0.3, 0.3);
@@ -57,13 +74,28 @@ static void draw_fixture(cairo_t *cr, PangoContext *pc, PangoFontDescription *fo
cairo_set_line_width(cr, 1.0);
cairo_stroke(cr);
+ /* Label */
layout = pango_layout_new(pc);
- pango_layout_set_text(layout, fx->label, -1);
- pango_layout_set_width(layout, w*PANGO_SCALE);
+ pango_layout_set_text(layout, fix->label, -1);
+ pango_layout_set_width(layout, (w*PANGO_SCALE)-4.0);
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
pango_layout_set_font_description(layout, fontdesc);
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+ cairo_move_to(cr, 0.0, 2.0);
pango_cairo_show_layout(cr, layout);
+ g_object_unref(layout);
+
+ /* Intensity */
+ snprintf(tmp, 32, "%.0f %%", get_attr_val(fix, ATT_INTENSITY)*100.0);
+ layout = pango_layout_new(pc);
+ pango_layout_set_text(layout, tmp, -1);
+ pango_layout_set_width(layout, (w*PANGO_SCALE)-4.0);
+ pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
+ pango_layout_set_font_description(layout, fontdesc);
+ cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+ cairo_move_to(cr, 0.0, 15.0);
+ pango_cairo_show_layout(cr, layout);
+ g_object_unref(layout);
}
@@ -73,11 +105,12 @@ static gboolean draw_sig(GtkWidget *widget, cairo_t *cr, struct nanolight *nl)
int i;
PangoContext *pc;
PangoFontDescription *fontdesc;
+ PangoLayout *layout;
+ double x, y;
w = gtk_widget_get_allocated_width(widget);
h = gtk_widget_get_allocated_height(widget);
pc = gtk_widget_get_pango_context(widget);
- fontdesc = pango_font_description_from_string("Comfortaa Bold 14");
/* Overall background */
cairo_set_source_rgb(cr, 0.0, 0.0, 0.2);
@@ -93,11 +126,153 @@ static gboolean draw_sig(GtkWidget *widget, cairo_t *cr, struct nanolight *nl)
/* Fixtures */
cairo_translate(cr, OVERALL_BORDER, OVERALL_BORDER);
+ x = FIXTURE_BORDER;
+ y = FIXTURE_BORDER;
+ fontdesc = pango_font_description_from_string("Comfortaa Bold 8");
for ( i=0; i<nl->n_fixtures; i++ ) {
+ cairo_save(cr);
+ cairo_translate(cr, x, y);
+ cairo_scale(cr, nl->fixture_width/40.0, nl->fixture_width/40.0);
draw_fixture(cr, pc, fontdesc, nl, &nl->fixtures[i]);
+ cairo_restore(cr);
+ x += nl->fixture_width + FIXTURE_BORDER*2;
+ if ( x + nl->fixture_width + FIXTURE_BORDER*2 > w*OVERALL_SPLIT ) {
+ x = FIXTURE_BORDER;
+ y += nl->fixture_width*3.0/2.0 + FIXTURE_BORDER*2;
+ }
}
/* Command line */
+ layout = pango_layout_new(pc);
+ fontdesc = pango_font_description_from_string("Comfortaa Bold 16");
+ pango_layout_set_text(layout, nl->cmdline, -1);
+ pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
+ pango_layout_set_font_description(layout, fontdesc);
+ cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+ cairo_move_to(cr, 0.0, h - OVERALL_BORDER*2 - 20.0);
+ pango_cairo_show_layout(cr, layout);
+ g_object_unref(layout);
+
+ return FALSE;
+}
+
+
+static struct fixture *create_fixture(struct nanolight *nl, struct fixture_class *cls,
+ const char *label, int base_addr)
+{
+ struct fixture *fix;
+
+ if ( nl->n_fixtures == nl->max_fixtures ) {
+ struct fixture *fixtures_new;
+ fixtures_new = realloc(nl->fixtures, (64+nl->max_fixtures)*sizeof(struct fixture));
+ if ( fixtures_new == NULL ) return NULL;
+ nl->fixtures = fixtures_new;
+ nl->max_fixtures += 64;
+ }
+
+ fix = &nl->fixtures[nl->n_fixtures++];
+ fix->label = strdup(label);
+ fix->base_addr = base_addr;
+ fix->cls = cls;
+ fix->attr_vals = calloc(cls->n_attrs, sizeof(int));
+ if ( fix->attr_vals == NULL ) {
+ nl->n_fixtures--;
+ return NULL;
+ }
+ return fix;
+}
+
+
+static void redraw(struct nanolight *nl)
+{
+ gint w, h;
+ w = gtk_widget_get_allocated_width(GTK_WIDGET(nl->da));
+ h = gtk_widget_get_allocated_height(GTK_WIDGET(nl->da));
+ gtk_widget_queue_draw_area(GTK_WIDGET(nl->da), 0, 0, w, h);
+}
+
+
+static void execute_command(struct nanolight *nl)
+{
+ if ( command_run(nl->cmdline, nl) == 0 ) {
+ nl->cmdline[0] = '\0';
+ }
+ redraw(nl);
+}
+
+
+static gboolean im_commit_sig(GtkIMContext *im, gchar *str, struct nanolight *nl)
+{
+ size_t cmd_len = strlen(nl->cmdline);
+ if ( cmd_len+strlen(str) > 1023 ) return FALSE;
+ strcat(nl->cmdline, str);
+ redraw(nl);
+ return FALSE;
+}
+
+
+static void delete_char(char *str)
+{
+ char *last;
+ if ( str[0] == '\0' ) return;
+ last = g_utf8_find_prev_char(str, str+strlen(str));
+ last[0] = '\0';
+}
+
+
+static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event, struct nanolight *nl)
+{
+ gboolean r;
+ int claim = 0;
+
+ /* Throw the event to the IM context and let it sort things out */
+ r = gtk_im_context_filter_keypress(GTK_IM_CONTEXT(nl->im_context), event);
+ if ( r ) return FALSE; /* IM ate it */
+
+ switch ( event->keyval ) {
+
+ case GDK_KEY_Left :
+ claim = 1;
+ break;
+
+ case GDK_KEY_Right :
+ claim = 1;
+ break;
+
+ case GDK_KEY_Return :
+ execute_command(nl);
+ claim = 1;
+ break;
+
+ case GDK_KEY_Escape :
+ nl->cmdline[0] = '\0';
+ redraw(nl);
+ claim = 1;
+ break;
+
+ case GDK_KEY_BackSpace :
+ delete_char(nl->cmdline);
+ claim = 1;
+ redraw(nl);
+ break;
+
+ }
+
+ if ( claim ) return TRUE;
+ return FALSE;
+}
+
+
+static gint realise_sig(GtkWidget *da, struct nanolight *nl)
+{
+ GdkWindow *win = gtk_widget_get_window(da);
+
+ /* Keyboard and input method stuff */
+ nl->im_context = gtk_im_multicontext_new();
+ gtk_im_context_set_client_window(GTK_IM_CONTEXT(nl->im_context), win);
+ gdk_window_set_accept_focus(win, TRUE);
+ g_signal_connect(G_OBJECT(nl->im_context), "commit", G_CALLBACK(im_commit_sig), nl);
+ g_signal_connect(G_OBJECT(da), "key-press-event", G_CALLBACK(key_press_sig), nl);
return FALSE;
}
@@ -106,7 +281,6 @@ static gboolean draw_sig(GtkWidget *widget, cairo_t *cr, struct nanolight *nl)
int main(int argc, char *argv[])
{
struct nanolight nl;
- struct fixture fix;
struct fixture_class cls;
struct attribute attrs[3];
int c;
@@ -163,21 +337,30 @@ int main(int argc, char *argv[])
cls.attrs[2].props = ATTR_16BIT;
cls.attrs[2].addr_offset = 2;
- nl.n_fixtures = 1;
- nl.fixtures = &fix;
- fix.label = "mh1";
- fix.cls = &cls;
-
nl.fixture_width = 80.0;
+ nl.fixtures = NULL;
+ nl.n_fixtures = 0;
+ nl.max_fixtures = 0;
+ nl.cmdline[0] = '\0';
+
+ create_fixture(&nl, &cls, "mh1", 1);
+ create_fixture(&nl, &cls, "mh2", 52);
+ create_fixture(&nl, &cls, "mh3", 103);
+ create_fixture(&nl, &cls, "mh4", 154)->attr_vals[0]=255;
mainwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_fullscreen(GTK_WINDOW(mainwindow));
+ //gtk_window_fullscreen(GTK_WINDOW(mainwindow));
g_signal_connect_swapped(G_OBJECT(mainwindow), "destroy", gtk_main_quit, NULL);
da = gtk_drawing_area_new();
+ nl.da = da;
gtk_container_add(GTK_CONTAINER(mainwindow), GTK_WIDGET(da));
+ gtk_widget_set_can_focus(GTK_WIDGET(da), TRUE);
+ gtk_widget_add_events(da, GDK_POINTER_MOTION_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
g_signal_connect(G_OBJECT(da), "draw", G_CALLBACK(draw_sig), &nl);
+ g_signal_connect(G_OBJECT(da), "realize", G_CALLBACK(realise_sig), &nl);
+ gtk_widget_grab_focus(GTK_WIDGET(da));
gtk_widget_show_all(mainwindow);
gtk_main();
diff --git a/src/nanolight.h b/src/nanolight.h
index 5235666..29cdbfc 100644
--- a/src/nanolight.h
+++ b/src/nanolight.h
@@ -23,6 +23,8 @@
#ifndef NANOLIGHT_H
#define NANOLIGHT_H
+#include <gtk/gtk.h>
+
/* Attribute flags */
#define ATTR_NONE (0)
#define ATTR_16BIT (1)
@@ -57,15 +59,21 @@ struct fixture
char *label;
int base_addr;
struct fixture_class *cls;
+ int *attr_vals;
};
struct nanolight
{
int n_fixtures;
+ int max_fixtures;
struct fixture *fixtures;
+ GtkIMContext *im_context;
+ GtkWidget *da;
+
double fixture_width;
+ char cmdline[1024];
};