Last active
December 1, 2019 15:28
-
-
Save SuborbitalPigeon/5467071 to your computer and use it in GitHub Desktop.
Simpson's rule using GTK+ via gjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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