Commit 2d9f6126 authored by Meade's avatar Meade

Added version 6.0.0. Changed from switches to dropdowns for units. Added...

Added version 6.0.0. Changed from switches to dropdowns for units. Added Imperial (British) units. In Total IBU, changed Boil Time to per hop. Under the bonnet, complete rewrite/cleanup. Test all the THIIIINGS!!!
parent cd0e6ce7
## New In 5.3.1
* Fixed the percentage display for Real Attenuation.
## New In 5.3.0
* Added unit tests for verifying maths. To check, run `cargo test`
## New In 5.2.0
* Created traits and implementations for common functions.
* Removed the arch PKGBUILD. It's on the AUR.
## New In 5.1.0
* Made things more rusty, changed two images from svg to png, and code cleanup.
## New In 5.0.0
* MASSIVE overhaul!!! Hence the jump from Version 3.0.0 to 5.0.0.
* Huge code cleanup: removed tons of unneeded borrows and things of that nature.
* Created a complete theme with CSS and images.
* Switched from a GtkWindow to a GtkApplicationWindow, which allows us to have proper domain naming.
* Added finished beer colour output:
* To calculate what the finished beer will look like, the flow goes like this:
* Individual grains go through singleMCU, those are added up and passed into beerSRM, and that gives us a total SRM value.
* We then convert that SRM value to L\*ab, from L\*ab to XYZ, and finally to RGBA.
* That gives us the colour you would expect to see.
* Also, because of the diameter of a glass, larger vessels will make beer appear darker. So, we accounted for that with standard glassware and averaged lighting data.
* We now have a dropdown menu where you can pick your glassware and it will show you the appropriate colour in that glass.
* Switched from an entry/button setup to a dynamic one: everything is calculated on the fly.
* Refactored our ABV functions. It's now based off of one source, which is very accurate.
* Changed from using 32 bit floating point to 64 bit.
## New In 3.0.0
* Added the grain calculator to the beer tab.
* Reworked the maths in the RealABV calculator, because it was completely inaccurate.
* Reworked the graphical layout as well.
## New In 2.0.0
* Added the IBU calculator to the beer tab.
\ No newline at end of file
This diff is collapsed.
[package]
name = "BrewStillery"
version = "5.3.1"
version = "6.0.0"
authors = ["Meade <thedarkula2049@gmail.com>", "Emily <marleybrush5@gmail.com>"]
description = "BrewStillery is a brewer's, vintner's, and distiller's calculator. It has a multitude of great functions, such as calculating ABV, determining carbonation, and total sparge water needed."
# documentation to come
......@@ -16,6 +16,10 @@ exclude = ["Arch/*"]
[badges]
maintenance = { status = "actively-developed" }
[dependencies.gtk]
version = "0.3.0"
features = ["v3_22"]
[dependencies]
gdk = "0.7.0"
gio = "0.3.0"
......@@ -24,14 +28,9 @@ gio = "0.3.0"
[features]
default = []
[dependencies.gtk]
version = "0.3.0"
features = ["v3_22"]
[profile.dev]
codegen-units = 16
[profile.release]
opt-level = 3
codegen-units = 16
codegen-units = 1
lto = true
\ No newline at end of file
......@@ -4,35 +4,16 @@ It has a multitude of great functions, such as calculating ABV, determining carb
Written in Rust, using GTK3
## New In 5.3.1
* Fixed the percentage display for Real Attenuation.
## New In 5.3.0
* Added unit tests for verifying maths. To check, run `cargo test`
## New In 5.2.0
* Created traits and implementations for common functions.
* Removed the arch PKGBUILD. It's on the AUR.
## New In 5.1.0
* Made things more rusty, changed two images from svg to png, and code cleanup.
## New In 5.0.0
* MASSIVE overhaul!!! Hence the jump from Version 3.0.0 to 5.0.0.
* Huge code cleanup: removed tons of unneeded borrows and things of that nature.
* Created a complete theme with CSS and images.
* Switched from a GtkWindow to a GtkApplicationWindow, which allows us to have proper domain naming.
* Added finished beer colour output:
* To calculate what the finished beer will look like, the flow goes like this:
* Individual grains go through singleMCU, those are added up and passed into beerSRM, and that gives us a total SRM value.
* We then convert that SRM value to L\*ab, from L\*ab to XYZ, and finally to RGBA.
* That gives us the colour you would expect to see.
* Also, because of the diameter of a glass, larger vessels will make beer appear darker. So, we accounted for that with standard glassware and averaged lighting data.
* We now have a dropdown menu where you can pick your glassware and it will show you the appropriate colour in that glass.
* Switched from an entry/button setup to a dynamic one: everything is calculated on the fly.
* Refactored our ABV functions. It's now based off of one source, which is very accurate.
* Changed from using 32 bit floating point to 64 bit.
## New In 6.0.0
* Changed from switches to dropdowns for units.
* Added Imperial (British) units.
* In Total IBU, changed Boil Time to per hop.
* Under the bonnet, complete rewrite/cleanup.
* Broke apart large functions.
* Wrote tests for all of the Maths, Formatting, Implementations, and Common Functions.
## Full Changelog
* [Available Here](CHANGELOG.md)
## Screenshots:
![General Tab Screenshot](media/screenshots/BrewStilleryGeneralTab.png)
......@@ -45,15 +26,19 @@ Written in Rust, using GTK3
![Beer Tab Bottom Screenshot](media/screenshots/BrewStilleryBeerTabBottom.png)
![Beer Tab Bottom Screenshot](media/screenshots/BrewStilleryBeerTabBottomFilledIn.png)
![Champagne Tab Screenshot](media/screenshots/BrewStilleryChampagneTab.png)
![Champagne Tab Screenshot](media/screenshots/BrewStilleryChampagneTabFilledIn.png)
![About Tab Screenshot](media/screenshots/BrewStilleryAboutTab.png)
## To Do:
* Add Documentation To The Info Tab
* Add Sugars And Fruits To ABV From Grain
* Add Water Minerals Calculator
* Add Documentation To The Info Tab
* Add Export To Gourmet Option
......
......@@ -3,56 +3,72 @@ use gtk::prelude::*;
use functions::commonFunctions::*;
pub fn champagneCarbonationPrep(champagneCarbonationBuilderClone: &gtk::Builder) {
let champagneCarbonationInput: gtk::Entry = champagneCarbonationBuilderClone.get_object("champagneCarbonationInput").unwrap();
let champagneCarbonationInputBuffer = champagneCarbonationInput.get_text().expect("No input");
let champagneVolume = champagneCarbonationInputBuffer.validInput();
let champagneCarbonationVolume: gtk::Entry = champagneCarbonationBuilderClone.get_object("champagneCarbonationVolume").expect("champagneCarbonationPrep(), champagneCarbonationVolume");
let champagneCarbonationVolumeBuffer = champagneCarbonationVolume.get_text().expect("champagneCarbonationPrep(), champagneCarbonationVolumeBuffer");
let champagneVolume = champagneCarbonationVolumeBuffer.validInput();
let champagneCarbonationOutput: gtk::Entry = champagneCarbonationBuilderClone.get_object("champagneCarbonationOutput").unwrap();
let champagneCarbonationSugar: gtk::Entry = champagneCarbonationBuilderClone.get_object("champagneCarbonationSugar").expect("champagneCarbonationPrep(), champagneCarbonationSugar");
let champagneCarbonationSwitch: gtk::Switch = champagneCarbonationBuilderClone.get_object("champagneCarbonationSwitch").unwrap();
let imperialOrMetric = champagneCarbonationSwitch.switchMatch();
let champagneCarbonationUnits: gtk::ComboBoxText = champagneCarbonationBuilderClone.get_object("champagneCarbonationUnits").expect("champagneCarbonationPrep(), champagneCarbonationUnits");
let champagneCarbonationUnitsBuffer = champagneCarbonationUnits.get_active_id().expect("champagneCarbonationPrep(), champagneCarbonationUnitsBuffer");
let imperialOrMetric = champagneCarbonationUnitsBuffer.unitMatch();
if champagneVolume == 0.0 {
champagneCarbonationOutput.set_text("Enter a number");
champagneCarbonationSugar.set_text("Enter a number");
} else if champagneVolume <= 0.0 {
champagneCarbonationOutput.set_text("Enter a positive number");
champagneCarbonationSugar.set_text("Enter a positive number");
} else {
let totalSugar = champagneCarbonationMaths(champagneVolume, &imperialOrMetric);
let totalSugar = champagneCarbonationMaths(champagneVolume, imperialOrMetric);
champagneOutput(totalSugar, imperialOrMetric, champagneCarbonationBuilderClone)
}
}
pub fn champagneCarbonationMaths(champagneVolume: f64, imperialOrMetric: &imperialOrMetric) -> f64 {
pub fn champagneCarbonationMaths(champagneVolume: f64, imperialOrMetric: imperialOrMetric) -> f64 {
let mut totalSugar = 0.0;
if imperialOrMetric == &imperialOrMetric::imperial {
totalSugar = champagneVolume * 0.2;
} else if imperialOrMetric == &imperialOrMetric::metric {
totalSugar = (champagneVolume * 23.986897025) / 1000.0;
if imperialOrMetric == imperialOrMetric::imperialGB {
totalSugar = champagneVolume.gallonsGBToGallonsUS().volumeToSugarChampagne();
} else if imperialOrMetric == imperialOrMetric::imperialUS {
totalSugar = champagneVolume.volumeToSugarChampagne();
} else if imperialOrMetric == imperialOrMetric::metric {
totalSugar = champagneVolume.litresToGallonsUS().volumeToSugarChampagne().poundsToKilos();
}
totalSugar
}
fn champagneOutput(totalSugar: f64, imperialOrMetric: imperialOrMetric, champagneCarbonationBuilderClone: &gtk::Builder) {
let champagneCarbonationOutput: gtk::Entry = champagneCarbonationBuilderClone.get_object("champagneCarbonationOutput").unwrap();
pub fn champagneCarbonationFormatting(totalSugar: f64, imperialOrMetric: imperialOrMetric) -> String {
let mut sugar = String::from("");
if imperialOrMetric == imperialOrMetric::imperial {
if totalSugar == 1.0 {
let sugar = format!("{:.0} pound", totalSugar);
champagneCarbonationOutput.set_text(&sugar);
if imperialOrMetric == imperialOrMetric::imperialGB || imperialOrMetric == imperialOrMetric::imperialUS {
if totalSugar < 0.995 {
sugar = format!("{:.2} oz", totalSugar.remainingOunces());
} else if totalSugar >= 0.995 && totalSugar < 1.005 {
sugar = format!("{:.0} lb", totalSugar);
} else if totalSugar.trunc() == 1.0 && totalSugar.remainingOunces() < 15.995 {
sugar = format!("{:.0} lb {:.2} oz", totalSugar.trunc(), totalSugar.remainingOunces());
} else if totalSugar.fract() == 0.0 || totalSugar.remainingOunces() < 0.005 || totalSugar.remainingOunces() >= 15.995 {
sugar = format!("{:.0} lbs", totalSugar);
} else {
let sugar = format!("{:.2} pounds", totalSugar);
champagneCarbonationOutput.set_text(&sugar);
sugar = format!("{:.0} lbs {:.2} oz", totalSugar.trunc(), totalSugar.remainingOunces());
}
} else if imperialOrMetric == imperialOrMetric::metric {
if totalSugar == 1.0 {
let sugar = format!("{:.0} kilo", totalSugar);
champagneCarbonationOutput.set_text(&sugar);
} else {
let sugar = format!("{:.2} kilos", totalSugar);
champagneCarbonationOutput.set_text(&sugar);
}
if totalSugar >= 0.995 && totalSugar < 1.005 {
sugar = format!("{:.0} kilo", totalSugar);
} else if totalSugar.fract() >= 0.995 || totalSugar.fract() < 0.005 {
sugar = format!("{:.0} kilos", totalSugar);
} else {
sugar = format!("{:.2} kilos", totalSugar);
}
}
sugar
}
fn champagneOutput(totalSugar: f64, imperialOrMetric: imperialOrMetric, champagneCarbonationBuilderClone: &gtk::Builder) {
let champagneCarbonationSugar: gtk::Entry = champagneCarbonationBuilderClone.get_object("champagneCarbonationSugar").expect("champagneCarbonationPrep(), champagneCarbonationSugar");
let sugar = champagneCarbonationFormatting(totalSugar, imperialOrMetric);
champagneCarbonationSugar.set_text(&sugar);
}
\ No newline at end of file
use gtk;
use gtk::prelude::*;
use std::f64::consts::E;
use gtk;
use gdk::RGBA;
pub const finalGravityIdeal: f64 = 1.01627;
pub const FINAL_GRAVITY_IDEAL: f64 = 1.01627;
// when finalGravity is unknown, this constant is ideal. it is the average of all BJCP styles
pub const finalBrixIdeal: f64 = 4.1480675;
pub const FINAL_BRIX_IDEAL: f64 = 4.1480675;
// when finalBrix is unknown, this constant is ideal. it is the average of all BJCP styles
#[derive(PartialEq)]
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum imperialOrMetric {
imperial,
imperialGB,
imperialUS,
metric,
}
#[derive(Clone, Debug)]
pub struct colourOverlay {
pub overlay: gtk::Overlay,
pub colourOutput: gtk::ColorButton,
pub dimplePint: gtk::Image,
pub nonickPint: gtk::Image,
pub tulipPint: gtk::Image,
pub pilsner: gtk::Image,
pub mafs: gtk::Image,
pub dimpleHalfPint: gtk::Image,
pub nonickHalfPint: gtk::Image,
pub tulipHalfPint: gtk::Image,
}
pub trait allOverlays {
fn new(&self) -> colourOverlay;
}
impl allOverlays for gtk::Builder {
fn new(&self) -> colourOverlay {
let allOverlays = colourOverlay {
overlay: self.get_object("grainABVColourOverlay").expect("commonFunctions, allOverlays"),
colourOutput: gtk::ColorButton::new(),
dimplePint: gtk::Image::new_from_file("/usr/share/BrewStillery/glassware/Dimple.png"),
nonickPint: gtk::Image::new_from_file("/usr/share/BrewStillery/glassware/Nonick.png"),
tulipPint: gtk::Image::new_from_file("/usr/share/BrewStillery/glassware/Tulip.png"),
pilsner: gtk::Image::new_from_file("/usr/share/BrewStillery/glassware/Pilsner.png"),
mafs: gtk::Image::new_from_file("/usr/share/BrewStillery/glassware/Mafs.png"),
dimpleHalfPint: gtk::Image::new_from_file("/usr/share/BrewStillery/glassware/DimpleHalf.png"),
nonickHalfPint: gtk::Image::new_from_file("/usr/share/BrewStillery/glassware/NonickHalf.png"),
tulipHalfPint: gtk::Image::new_from_file("/usr/share/BrewStillery/glassware/TulipHalf.png"),
};
allOverlays
}
}
pub trait inputMatching {
fn validInput(&self) -> f64;
fn grainInfo(&self) -> (f64, f64);
fn grainGravity(&self) -> f64;
fn grainLovibond(&self) -> f64;
fn glassSize(&self) -> f64;
fn unitMatch(&self) -> imperialOrMetric;
}
impl inputMatching for str {
......@@ -29,24 +69,43 @@ impl inputMatching for str {
}
}
fn grainInfo(&self) -> (f64, f64) {
fn grainGravity(&self) -> f64 {
match self {
"2-Row" => 1.037,
"6-Row" => 1.035,
"Black" => 1.025,
"Caramel 60" => 1.034,
"Caramel 80" => 1.034,
"Caramel 120" => 1.033,
"Chocolate" => 1.034,
"Corn" => 1.037,
"Dextrine" => 1.033,
"Oat" => 1.034,
"Rice" => 1.032,
"Rye" => 1.036,
"Wheat" => 1.036,
_ => 1.0,
// Gravity set to water as a catch
}
}
fn grainLovibond(&self) -> f64 {
match self {
// First value is Gravity, second value is Lovibond
"2-Row" => (1.037, 1.8),
"6-Row" => (1.035, 1.8),
"Black" => (1.025, 500.0),
"Caramel 60" => (1.034, 60.0),
"Caramel 80" => (1.034, 80.0),
"Caramel 120" => (1.033, 120.0),
"Chocolate" => (1.034, 350.0),
"Corn" => (1.037, 1.3),
"Dextrine" => (1.033, 1.5),
"Oat" => (1.034, 1.0),
"Rice" => (1.032, 1.0),
"Rye" => (1.036, 2.0),
"Wheat" => (1.036, 1.6),
_ => (1.0, 0.0),
// Gravity set to water, and color to nothing as a catch
"2-Row" => 1.8,
"6-Row" => 1.8,
"Black" => 500.0,
"Caramel 60" => 60.0,
"Caramel 80" => 80.0,
"Caramel 120" => 120.0,
"Chocolate" => 350.0,
"Corn" => 1.3,
"Dextrine" => 1.5,
"Oat" => 1.0,
"Rice" => 1.0,
"Rye" => 2.0,
"Wheat" => 1.6,
_ => 0.0,
// Color to nothing as a catch
}
}
......@@ -62,20 +121,17 @@ impl inputMatching for str {
"Nonick Half Pint" => 7.0,
"Tulip Half Pint" => 7.2,
_ => 9.8,
// Size to Dimple Pint as a catch
}
}
}
pub trait imperialOrMetricMatch {
fn switchMatch(&self) -> imperialOrMetric;
}
impl imperialOrMetricMatch for gtk::Switch {
fn switchMatch(&self) -> imperialOrMetric {
let state = self.get_active();
match state {
false => imperialOrMetric::imperial,
true => imperialOrMetric::metric,
fn unitMatch(&self) -> imperialOrMetric {
match self {
"imperialGB" => imperialOrMetric::imperialGB,
"imperialUS" => imperialOrMetric::imperialUS,
"metric" => imperialOrMetric::metric,
_ => imperialOrMetric::imperialGB,
// Unit set to imperialGB as a catch
}
}
}
......@@ -85,9 +141,20 @@ pub trait singleInput {
fn gravityToBrix(&self) -> f64;
fn gravityToPlato(&self) -> f64;
fn gramsToOunces(&self) -> f64;
fn poundsToOunces(&self) -> f64;
fn ouncesToPounds(&self) -> f64;
fn kilosToPounds(&self) -> f64;
fn litresToGallons(&self) -> f64;
fn gallonsToLitres(&self) -> f64;
fn poundsToKilos(&self) -> f64;
fn gramsToKilograms(&self) -> f64;
fn litresToGallonsGB(&self) -> f64;
fn litresToGallonsUS(&self) -> f64;
fn gallonsGBToLitres(&self) -> f64;
fn gallonsUSToLitres(&self) -> f64;
fn gallonsGBToGallonsUS(&self) -> f64;
fn gallonsUSToGallonsGB(&self) -> f64;
fn sugarToHoney(&self) -> f64;
fn volumeToSugarChampagne(&self) -> f64;
fn remainingOunces(&self) -> f64;
}
impl singleInput for f64 {
......@@ -104,23 +171,69 @@ impl singleInput for f64 {
}
fn gramsToOunces(&self) -> f64 {
0.03527396_f64 * self
0.035273962 * self
}
fn poundsToOunces(&self) -> f64 {
self * 16.0
}
fn ouncesToPounds(&self) -> f64 {
self / 16.0
}
fn kilosToPounds(&self) -> f64 {
2.204623_f64 * self
2.204622622 * self
}
fn litresToGallons(&self) -> f64 {
0.2641729_f64 * self
fn poundsToKilos(&self) -> f64 {
0.45359237 * self
}
fn gallonsToLitres(&self) -> f64 {
3.7854_f64 * self
fn gramsToKilograms(&self) -> f64 {
self / 1000.0
}
fn litresToGallonsGB(&self) -> f64 {
0.219969248 * self
}
fn litresToGallonsUS(&self) -> f64 {
0.264172052 * self
}
fn gallonsGBToLitres(&self) -> f64 {
4.54609 * self
}
fn gallonsUSToLitres(&self) -> f64 {
3.785411784 * self
}
fn gallonsGBToGallonsUS(&self) -> f64 {
1.200950 * self
}
fn gallonsUSToGallonsGB(&self) -> f64 {
0.8326742 * self
}
fn sugarToHoney(&self) -> f64 {
// 82 grams of sugar equals 100 grams of honey
1.219512195 * self
}
fn volumeToSugarChampagne(&self) -> f64 {
// 1 pound of sugar carbonates 5 US gallons at 6 atmospheres of pressure, which is standard champagne carbonation
0.2 * self
}
fn remainingOunces(&self) -> f64 {
self.fract() * 16.0
}
}
pub fn realIBU(brix: f64, wortVolume: f64, boilTime: f64, alphaAcid: f64, hopAmount: f64) -> f64 {
pub fn realIBU(brix: f64, wortVolume: f64, alphaAcid: f64, hopAmount: f64, boilTime: f64) -> f64 {
(1.65 * 0.000125_f64.powf(brix.brixToGravity() - 1.0)) * ((1.0 - E.powf(-0.04 * boilTime)) / 4.15) * (( (alphaAcid / 100.0) * hopAmount * 7490.0 ) / wortVolume)
}
......@@ -140,14 +253,14 @@ pub fn realABV(startingBrix: f64, finalBrix: f64) -> (f64, f64) {
(abv, attenuation)
}
pub fn grainToGravity(volumeInGallons: f64, weightInPounds: f64, grainGravity: f64) -> f64 {
let extractPotential = grainGravity % 1.0 * 1000.0;
pub fn grainToGravity(volumeInGallonsUS: f64, weightInPounds: f64, grainGravity: f64) -> f64 {
let extractPotential = grainGravity.fract() * 1000.0;
let extractionEfficiency = 0.57;
// sane default here of 57%
let mut originalGravity = 1.0;
// set to the gravity of water
let specificGravityPoints = (weightInPounds * extractPotential * extractionEfficiency) / volumeInGallons;
let specificGravityPoints = (weightInPounds * extractPotential * extractionEfficiency) / volumeInGallonsUS;
if specificGravityPoints != 0.0 {
originalGravity = specificGravityPoints / 1000.0 + 1.0;
......@@ -155,4 +268,16 @@ pub fn grainToGravity(volumeInGallons: f64, weightInPounds: f64, grainGravity: f
} else {
originalGravity
}
}
// when const fn hits stable, we can create a constant called RGBA_ZERO that uses zeroRGBA()
pub fn zeroRGBA() -> RGBA {
let zeroRGBA = RGBA {
red: 255.0,
green: 255.0,
blue: 255.0,
alpha: 1.0,
};
zeroRGBA
}
\ No newline at end of file
This diff is collapsed.
......@@ -2,26 +2,32 @@ use gtk;
use gtk::prelude::*;
use functions::commonFunctions::*;
pub fn guestimatePrep(guestimatorBuilderClone: &gtk::Builder) {
let guestimatorInput: gtk::Entry = guestimatorBuilderClone.get_object("guestimatorInput").unwrap();
let guestimatorInput = guestimatorInput.get_text().expect("No input");
let startingBrix = guestimatorInput.validInput();
let guestimatorOutput: gtk::Entry = guestimatorBuilderClone.get_object("guestimatorOutput").unwrap();
pub fn guestimateABVPrep(guestimatorBuilder: &gtk::Builder) {
let guestimatorStartingBrix: gtk::Entry = guestimatorBuilder.get_object("guestimatorStartingBrix").expect("guestimateABVPrep(), guestimatorStartingBrix");
let guestimatorStartingBrixBuffer = guestimatorStartingBrix.get_text().expect("guestimateABVPrep(), guestimatorStartingBrixBuffer");
let startingBrix = guestimatorStartingBrixBuffer.validInput();
let guestimatorTemporaryOutput: gtk::Entry = guestimatorBuilder.get_object("guestimatorABV").expect("guestimateABVPrep(), guestimatorTemporaryOutput");
if startingBrix == 0.0 {
guestimatorOutput.set_text("Enter a number");
guestimatorTemporaryOutput.set_text("Enter a number");
} else if startingBrix < 2.57 {
guestimatorOutput.set_text("Enter a Brix greater than 2.57");
guestimatorTemporaryOutput.set_text("Enter a Brix greater than 2.57");
} else if startingBrix > 49.48 {
guestimatorOutput.set_text("Enter a Brix less than 49.48");
guestimatorTemporaryOutput.set_text("Enter a Brix less than 49.48");
} else {
guestiMaths(startingBrix, guestimatorBuilderClone);
guestimateABVOutput(startingBrix, guestimatorBuilder);
}
}
fn guestiMaths(startingBrix: f64, guestimatorBuilderClone: &gtk::Builder) {
let guestimatorOutput: gtk::Entry = guestimatorBuilderClone.get_object("guestimatorOutput").unwrap();
pub fn guestimateABVFormatting(startingBrix: f64) -> String {
let finalABV = format!("{:.2}%", realABV(startingBrix, FINAL_BRIX_IDEAL).0);
finalABV
}
fn guestimateABVOutput(startingBrix: f64, guestimatorBuilder: &gtk::Builder) {
let guestimatorABV: gtk::Entry = guestimatorBuilder.get_object("guestimatorABV").expect("guestimateABVOutput(), guestimatorABV");
let finalABV = guestimateABVFormatting(startingBrix);
let abv = format!("{:.2}%", realABV(startingBrix, finalBrixIdeal).0);
guestimatorOutput.set_text(&abv);
guestimatorABV.set_text(&finalABV);
}
\ No newline at end of file
This diff is collapsed.
......@@ -2,52 +2,121 @@ use gtk;
use gtk::prelude::*;
use functions::commonFunctions::*;
pub fn gyleCarbonationPrep(gyleBuilderClone: &gtk::Builder) {
let gyleBrixInput: gtk::Entry = gyleBuilderClone.get_object("gyleBrixInput").unwrap();
let gyleBrixInputBuffer = gyleBrixInput.get_text().expect("No input");
let startingBrix = gyleBrixInputBuffer.validInput();
#[derive(Debug)]
pub struct gyleData {
pub startingGravity: f64,
pub desiredCO2Level: f64,
pub finalVolume: f64,
pub gyleVolumeFloat: f64,
pub imperialOrMetric: imperialOrMetric,
}
let gyleCO2Input: gtk::Entry = gyleBuilderClone.get_object("gyleCO2Input").unwrap();
let gyleCO2InputBuffer = gyleCO2Input.get_text().expect("No input");
let desiredCO2Level = gyleCO2InputBuffer.validInput();
pub fn gyleCarbonationPrep(gyleBuilder: &gtk::Builder) {
let gyleStartingBrix: gtk::Entry = gyleBuilder.get_object("gyleStartingBrix").expect("gyleCarbonationPrep(), gyleStartingBrix");
let gyleStartingBrixBuffer = gyleStartingBrix.get_text().expect("gyleCarbonationPrep(), gyleStartingBrixBuffer");
let startingBrix = gyleStartingBrixBuffer.validInput();
let gyleWortVolumeInput: gtk::Entry = gyleBuilderClone.get_object("gyleWortVolumeInput").unwrap();
let gyleWortVolumeInputBuffer = gyleWortVolumeInput.get_text().expect("No input");
let finalVolume = gyleWortVolumeInputBuffer.validInput();
let gyleDesiredCO2: gtk::Entry = gyleBuilder.get_object("gyleDesiredCO2").expect("gyleCarbonationPrep(), gyleDesiredCO2");
let gyleDesiredCO2Buffer = gyleDesiredCO2.get_text().expect("gyleCarbonationPrep(), gyleDesiredCO2Buffer");
let desiredCO2LevelTemp = gyleDesiredCO2Buffer.validInput();
let gyleOutput: &gtk::Entry = &gyleBuilderClone.get_object("gyleOutput").unwrap();
let gyleWortVolume: gtk::Entry = gyleBuilder.get_object("gyleWortVolume").expect("gyleCarbonationPrep(), gyleWortVolume");
let gyleWortVolumeBuffer = gyleWortVolume.get_text().expect("gyleCarbonationPrep(), gyleWortVolumeBuffer");
let finalVolumeTemp = gyleWortVolumeBuffer.validInput();
let gyleCarbonationSwitch: gtk::Switch = gyleBuilderClone.get_object("gyleCarbonationSwitch").unwrap();
let gyleTemporaryOutput: &gtk::Entry = &gyleBuilder.get_object("gyleCarbonationOutput").expect("gyleCarbonationPrep(), gyleTemporaryOutput");
let imperialOrMetric = gyleCarbonationSwitch.switchMatch();
let gyleCarbonationUnits: gtk::ComboBoxText = gyleBuilder.get_object("gyleCarbonationUnits").expect("gyleCarbonationPrep(), gyleCarbonationUnits");
let gyleCarbonationUnitsBuffer = gyleCarbonationUnits.get_active_id().expect("gyleCarbonationPrep(), gyleCarbonationUnitsBuffer");
let imperialOrMetric = gyleCarbonationUnitsBuffer.unitMatch();
if startingBrix < 2.57 {
gyleOutput.set_text("Enter a Starting Brix greater than 2.57");
gyleTemporaryOutput.set_text("Enter a Starting Brix greater than 2.57");
} else if startingBrix > 49.48 {
gyleOutput.set_text("Enter a Starting Brix less than 49.48");
} else if startingBrix == 0.0 || desiredCO2Level == 0.0 || finalVolume == 0.0 {
gyleOutput.set_text("Enter all 3 inputs");
} else if startingBrix <= 0.0 || desiredCO2Level <= 0.0 || finalVolume <= 0.0 {
gyleOutput.set_text("Enter a positive number");
gyleTemporaryOutput.set_text("Enter a Starting Brix less than 49.48");
} else if startingBrix == 0.0 || desiredCO2LevelTemp == 0.0 || finalVolumeTemp == 0.0 {
gyleTemporaryOutput.set_text("Enter all 3 inputs");
} else if startingBrix <= 0.0 || desiredCO2LevelTemp <= 0.0 || finalVolumeTemp <= 0.0 {
gyleTemporaryOutput.set_text("Enter a positive number");
} else {
gyleMaths(startingBrix, desiredCO2Level, finalVolume, imperialOrMetric, gyleBuilderClone);
let allInputs = gyleData {