Skip to content

Instantly share code, notes, and snippets.

@SuborbitalPigeon
Last active December 1, 2019 15:28
Show Gist options
  • Save SuborbitalPigeon/5467071 to your computer and use it in GitHub Desktop.
Save SuborbitalPigeon/5467071 to your computer and use it in GitHub Desktop.
Simpson's rule using GTK+ via gjs
#!/usr/bin/gjs
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const GtkSource = imports.gi.GtkSource;
const Pango = imports.gi.Pango;
var Simpson = GObject.registerClass(
class Simpson extends Gtk.Application
{
_init()
{
super._init({ application_id: "eu.bcowan.Simpson" });
}
vfunc_activate()
{
this._window.show_all();
}
vfunc_startup()
{
super.vfunc_startup();
this._window = new Gtk.ApplicationWindow({ application: this,
window_position: Gtk.WindowPosition.CENTER });
// Grid
let grid = new Gtk.Grid({ column_spacing: 24,
orientation: Gtk.Orientation.VERTICAL,
row_spacing: 6 });
this._window.add(grid);
let headerBar = new Gtk.HeaderBar({ has_subtitle : false,
show_close_button: true,
title: "Simpson's rule" });
this._window.set_titlebar(headerBar);
// Labels
let fnLabel = this._makeLabel("Function");
grid.add(fnLabel);
let limitLabel = this._makeLabel("Limits");
grid.add(limitLabel);
let stripsLabel = this._makeLabel("Strips");
grid.add(stripsLabel);
// SourceView
let lm = GtkSource.LanguageManager.get_default();
let language = lm.get_language("js");
this._buffer = new GtkSource.Buffer({ language: language });
this._buffer.set_text("return Math.exp(Math.cos(x));", -1);
let sourceView = new GtkSource.View({ buffer: this._buffer,
height_request: 100,
tooltip_markup: "This has to be a JavaScript function in <i>x</i>",
width_request: 400 });
let fd = new Pango.FontDescription();
fd.set_family("Monospace");
sourceView.override_font(fd);
grid.attach_next_to(sourceView, fnLabel, Gtk.PositionType.RIGHT, 1, 1);
// Button grid
let buttonGrid = new Gtk.Grid({ column_homogeneous: true,
hexpand: true,
orientation: Gtk.Orientation.HORIZONTAL });
grid.attach_next_to(buttonGrid, limitLabel, Gtk.PositionType.RIGHT, 1, 1);
// Lower limit
this._lowerAdj = new Gtk.Adjustment({ lower: -100,
step_increment: 1,
upper: 100,
value: 1 });
let lowerLimit = new Gtk.SpinButton({ adjustment: this._lowerAdj,
tooltip_text: "Lower limit" });
buttonGrid.add(lowerLimit);
// Upper limit
this._upperAdj = new Gtk.Adjustment({ lower: -100,
step_increment: 1,
upper: 100,
value: 6 });
let upperLimit = new Gtk.SpinButton({ adjustment: this._upperAdj,
tooltip_text: "Upper limit" });
buttonGrid.add(upperLimit);
this._stripsAdj = new Gtk.Adjustment({ lower: 2,
step_increment: 2,
upper: 100,
value: 20 });
let strips = new Gtk.SpinButton({ adjustment: this._stripsAdj,
tooltip_text: "This must be an even number" });
grid.attach_next_to(strips, stripsLabel, Gtk.PositionType.RIGHT, 1, 1);
// Execute button
let button = new Gtk.Button({ label: "_Execute",
use_underline: true });
let ctx = button.get_style_context();
ctx.add_class("suggested-action");
button.connect("clicked", this._executeClicked.bind(this));
headerBar.pack_end(button);
}
_makeLabel(label)
{
let l = new Gtk.Label({ halign: Gtk.Align.END,
label: label });
l.get_style_context().add_class("dim-label");
return l;
}
_executeClicked(btn)
{
let js = this._buffer.text;
let lower = this._lowerAdj.value;
let upper = this._upperAdj.value;
let strips = this._stripsAdj.value;
// Swap bounds if required
if (lower > upper)
{
let temp = lower;
lower = upper;
upper = temp;
}
try
{
let fn = Function("x", js);
let val = this._simpson(fn, lower, upper, strips);
let text = `The integral from ${lower} to ${upper} using Simpson's rule with ${strips} is ${val}`;
this._showDialogue(Gtk.MessageType.INFO, "Result", text);
}
catch(e)
{
this._showDialogue(Gtk.MessageType.ERROR, e.name, e.message);
}
}
_showDialogue(messageType, title, text)
{
let dialogue = new Gtk.MessageDialog({ buttons: Gtk.ButtonsType.CLOSE,
message_type: messageType,
modal: true,
secondary_text: text,
text: title,
transient_for: this._window });
// TODO: deprecated
dialogue.run();
dialogue.destroy();
}
_simpson(fn, a, b, n)
{
if ((n % 2) !== 0)
throw new RangeError("Number of strips must be even");
let h = (b - a) / n;
// Ends
let s = fn(a) + fn(b);
// Odds
for (let i = 1; i <= n; i += 2)
s += 4 * fn(a + i * h);
// Evens
for (let i = 2; i < n; i +=2)
s += 2 * fn(a + i * h);
return s * h / 3;
}
});
let app = new Simpson();
app.run(ARGV);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment