Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ A fast, ncview‑inspired visualization tool for structured and unstructured geo
- **Multiple formats**: Supports netCDF, zarr, GRIB, and MITgcm binary (MDS)
- **Unified data handling**: Treats all data as collections of points with lon/lat coordinates
- **Fast visualization**: KDTree-based nearest-neighbor interpolation to regular grid
- **X11/Xaw interface**: Works over SSH with X forwarding
- **X11/Xaw interface**: Works over SSH with X forwarding, dark/light theme
- **Terminal quick-look mode**: Separate `uterm` binary with raw terminal interaction (no X is needed)
- **Animation support**: Step through time dimensions
- **Multiple colormaps**: viridis, hot, grayscale, plus the full cmocean set
Expand Down Expand Up @@ -256,6 +256,7 @@ Options:
--box W,E,S,N Regional box (e.g. --box -10,30,35,70 for Europe)
--polar <pole> Polar LAEA projection (north or south)
--cutoff <deg> Cutoff latitude for polar view (default: 60)
--light Use light theme (default: dark)
--yac Use YAC interpolation with default method (avg_arith)
--yac-method <method> Use YAC interpolation with specific method;
click the method button in the GUI to cycle methods at runtime
Expand Down
13 changes: 10 additions & 3 deletions src/interface/range_popup.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#include <string.h>
#include <math.h>

#define MINMAX_TEXT_WIDTH 120
#define MINMAX_TEXT_WIDTH 160

/* X11 handles (passed during init) */
static Display *popup_display = NULL;
Expand Down Expand Up @@ -115,7 +115,7 @@ void range_popup_init(Widget parent, Display *dpy, XtAppContext app_ctx) {
range_min_label = XtVaCreateManagedWidget(
"range_min_label", labelWidgetClass, range_form,
XtNlabel, "Minimum:",
XtNwidth, 80,
XtNwidth, 90,
XtNborderWidth, 0,
NULL);

Expand All @@ -130,7 +130,7 @@ void range_popup_init(Widget parent, Display *dpy, XtAppContext app_ctx) {
range_max_label = XtVaCreateManagedWidget(
"range_max_label", labelWidgetClass, range_form,
XtNlabel, "Maximum:",
XtNwidth, 80,
XtNwidth, 90,
XtNborderWidth, 0,
XtNfromVert, range_min_label,
NULL);
Expand All @@ -147,13 +147,15 @@ void range_popup_init(Widget parent, Display *dpy, XtAppContext app_ctx) {
range_symmetric_btn = XtVaCreateManagedWidget(
"Symmetric about Zero", commandWidgetClass, range_form,
XtNfromVert, range_max_label,
XtNvertDistance, 8,
NULL);
XtAddCallback(range_symmetric_btn, XtNcallback, symmetric_callback, NULL);

/* Row 4: Reset to Global Values + label showing values */
range_reset_btn = XtVaCreateManagedWidget(
"Reset to Global Values", commandWidgetClass, range_form,
XtNfromVert, range_symmetric_btn,
XtNvertDistance, 8,
NULL);
XtAddCallback(range_reset_btn, XtNcallback, reset_global_callback, NULL);

Expand All @@ -170,13 +172,18 @@ void range_popup_init(Widget parent, Display *dpy, XtAppContext app_ctx) {
range_ok_btn = XtVaCreateManagedWidget(
"OK", commandWidgetClass, range_form,
XtNfromVert, range_reset_btn,
XtNvertDistance, 12,
XtNwidth, 80,
NULL);
XtAddCallback(range_ok_btn, XtNcallback, ok_callback, NULL);

range_cancel_btn = XtVaCreateManagedWidget(
"Cancel", commandWidgetClass, range_form,
XtNfromHoriz, range_ok_btn,
XtNfromVert, range_reset_btn,
XtNvertDistance, 12,
XtNhorizDistance, 8,
XtNwidth, 80,
NULL);
XtAddCallback(range_cancel_btn, XtNcallback, cancel_callback, NULL);
}
Expand Down
81 changes: 65 additions & 16 deletions src/interface/timeseries_popup.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

#include "timeseries_popup.h"
#include "x_interface.h"
#include <X11/Xlib.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
Expand Down Expand Up @@ -38,6 +39,9 @@ static GC ts_gc = None;
/* Colors */
static unsigned long color_blue = 0;
static unsigned long color_gray = 0;
static unsigned long color_bg = 0;
static unsigned long color_axis = 0;
static unsigned long color_label = 0;
static int colors_allocated = 0;

/* Cached data (deep copy) */
Expand Down Expand Up @@ -177,25 +181,68 @@ static void allocate_colors(void) {
int screen = DefaultScreen(ts_display);
Colormap cmap = DefaultColormap(ts_display, screen);
XColor xc;
int is_light = x_is_light_theme();

/* Blue for data line */
xc.red = 0x3333; xc.green = 0x6666; xc.blue = 0xFFFF;
if (is_light) {
xc.red = 0x2222; xc.green = 0x5555; xc.blue = 0xCCCC;
} else {
xc.red = 0x5555; xc.green = 0x9999; xc.blue = 0xFFFF;
}
xc.flags = DoRed | DoGreen | DoBlue;
if (XAllocColor(ts_display, cmap, &xc)) {
if (XAllocColor(ts_display, cmap, &xc))
color_blue = xc.pixel;
else
color_blue = is_light ? BlackPixel(ts_display, screen) : WhitePixel(ts_display, screen);

/* Grid lines */
if (is_light) {
xc.red = 0xCCCC; xc.green = 0xCCCC; xc.blue = 0xCCCC;
} else {
color_blue = BlackPixel(ts_display, screen);
xc.red = 0x4444; xc.green = 0x4444; xc.blue = 0x4444;
}

/* Light gray for grid */
xc.red = 0xCCCC; xc.green = 0xCCCC; xc.blue = 0xCCCC;
xc.flags = DoRed | DoGreen | DoBlue;
if (XAllocColor(ts_display, cmap, &xc)) {
if (XAllocColor(ts_display, cmap, &xc))
color_gray = xc.pixel;
else
color_gray = is_light ? WhitePixel(ts_display, screen) : BlackPixel(ts_display, screen);

/* Background */
if (is_light) {
color_bg = WhitePixel(ts_display, screen);
} else {
color_gray = WhitePixel(ts_display, screen);
xc.red = 0x1E1E; xc.green = 0x1E1E; xc.blue = 0x1E1E;
xc.flags = DoRed | DoGreen | DoBlue;
if (XAllocColor(ts_display, cmap, &xc))
color_bg = xc.pixel;
else
color_bg = BlackPixel(ts_display, screen);
}

/* Axis color */
if (is_light) {
xc.red = 0x4444; xc.green = 0x4444; xc.blue = 0x4444;
} else {
xc.red = 0x8888; xc.green = 0x8888; xc.blue = 0x8888;
}
xc.flags = DoRed | DoGreen | DoBlue;
if (XAllocColor(ts_display, cmap, &xc))
color_axis = xc.pixel;
else
color_axis = is_light ? BlackPixel(ts_display, screen) : WhitePixel(ts_display, screen);

/* Label color */
if (is_light) {
xc.red = 0x2222; xc.green = 0x2222; xc.blue = 0x2222;
} else {
xc.red = 0xCCCC; xc.green = 0xCCCC; xc.blue = 0xCCCC;
}
xc.flags = DoRed | DoGreen | DoBlue;
if (XAllocColor(ts_display, cmap, &xc))
color_label = xc.pixel;
else
color_label = is_light ? BlackPixel(ts_display, screen) : WhitePixel(ts_display, screen);

colors_allocated = 1;
}

Expand All @@ -206,9 +253,6 @@ static void draw_plot(Widget w) {
if (!XtIsRealized(w)) return;

Window win = XtWindow(w);
int screen = DefaultScreen(ts_display);
unsigned long black = BlackPixel(ts_display, screen);
unsigned long white = WhitePixel(ts_display, screen);

allocate_colors();

Expand All @@ -220,8 +264,8 @@ static void draw_plot(Widget w) {
int plot_w = plot_x1 - plot_x0;
int plot_h = plot_y1 - plot_y0;

/* White background */
XSetForeground(ts_display, ts_gc, white);
/* Dark background */
XSetForeground(ts_display, ts_gc, color_bg);
XFillRectangle(ts_display, win, ts_gc, 0, 0, PLOT_WIDTH, PLOT_HEIGHT);

/* Compute data range for Y axis (valid values only) */
Expand Down Expand Up @@ -287,11 +331,12 @@ static void draw_plot(Widget w) {
}
}

/* Draw axes (black) */
XSetForeground(ts_display, ts_gc, black);
/* Draw axes (gray) */
XSetForeground(ts_display, ts_gc, color_axis);
XDrawRectangle(ts_display, win, ts_gc, plot_x0, plot_y0, plot_w, plot_h);

/* Y-axis tick labels */
XSetForeground(ts_display, ts_gc, color_label);
XFontStruct *font = XQueryFont(ts_display, XGContextFromGC(ts_gc));
int font_ascent = font ? font->ascent : 10;

Expand All @@ -302,9 +347,11 @@ static void draw_plot(Widget w) {
if (py < plot_y0 || py > plot_y1) continue;

/* Tick mark */
XSetForeground(ts_display, ts_gc, color_axis);
XDrawLine(ts_display, win, ts_gc, plot_x0 - TICK_LEN, py, plot_x0, py);

/* Label */
XSetForeground(ts_display, ts_gc, color_label);
char buf[32];
snprintf(buf, sizeof(buf), "%.4g", val);
int tw = font ? XTextWidth(font, buf, (int)strlen(buf)) : 40;
Expand All @@ -321,9 +368,11 @@ static void draw_plot(Widget w) {
if (px < plot_x0 || px > plot_x1) continue;

/* Tick mark */
XSetForeground(ts_display, ts_gc, color_axis);
XDrawLine(ts_display, win, ts_gc, px, plot_y1, px, plot_y1 + TICK_LEN);

/* Label */
XSetForeground(ts_display, ts_gc, color_label);
char buf[32];
if (use_cf_time) {
if (!ts_format_time(buf, sizeof(buf), val, ts_cache.x_label))
Expand Down Expand Up @@ -405,7 +454,7 @@ static void draw_plot(Widget w) {

/* Reset line width */
XSetLineAttributes(ts_display, ts_gc, 0, LineSolid, CapButt, JoinMiter);
XSetForeground(ts_display, ts_gc, black);
XSetForeground(ts_display, ts_gc, color_label);

if (font) {
XFreeFontInfo(NULL, font, 1);
Expand Down
Loading