Skip to content

Instantly share code, notes, and snippets.

@toshimasa-nanaki
Last active December 23, 2018 02:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save toshimasa-nanaki/f8cc1224d50cc1dfc1e7319593a1d331 to your computer and use it in GitHub Desktop.
Save toshimasa-nanaki/f8cc1224d50cc1dfc1e7319593a1d331 to your computer and use it in GitHub Desktop.
Rust 電卓アプリ 計算できるようにした
//クレートとしてconrodを読み込む
#[macro_use] extern crate conrod;
fn main() {
//featureモジュールのmain関数呼び出し
feature::main();
}
/// モジュール
mod feature {
use conrod::backend::glium::glium::{self, Surface};
use conrod::{self, widget, widget_ids, Labelable, Positionable, Sizeable, Widget};
struct ButtonInfo {
widget_id2: conrod::widget::Id,
label: String,
value: char,
}
//publicなmain関数
pub fn main() {
//画面の横縦サイズ宣言
const WIDTH: u32 = 400;
const HEIGHT: u32 = 600;
//ループイベントオブジェクトを生成
let mut events_loop = glium::glutin::EventsLoop::new();
//gliumを使ってディスプレイ用のオブジェクトを作る
let window = glium::glutin::WindowBuilder::new()
.with_title("Calculator")
.with_dimensions((WIDTH, HEIGHT).into());
let context = glium::glutin::ContextBuilder::new()
.with_vsync(true)
.with_multisampling(4);
let display = glium::Display::new(window, context, &events_loop).unwrap();
// UIの組み立て
let mut ui = conrod::UiBuilder::new([WIDTH as f64, HEIGHT as f64]).build();
// ウィジェットIDの生成
widget_ids!(struct Ids { text, button1, button2, button3, button4, button5, button6, button7, button8, button9, button0, button_point, button_eq, button_plus, button_minus, button_multi, button_divide, textbox });
let ids = Ids::new(ui.widget_id_generator());
let button_map = vec![
vec![
ButtonInfo {
widget_id2: ids.button7,
label: "7".to_string(),
value: '7',
},
ButtonInfo {
widget_id2: ids.button8,
label: "8".to_string(),
value: '8',
},
ButtonInfo {
widget_id2: ids.button9,
label: "9".to_string(),
value: '9',
},
ButtonInfo {
widget_id2: ids.button_divide,
label: "÷".to_string(),
value: '/',
},
],
vec![
ButtonInfo {
widget_id2: ids.button4,
label: "4".to_string(),
value: '4',
},
ButtonInfo {
widget_id2: ids.button5,
label: "5".to_string(),
value: '5',
},
ButtonInfo {
widget_id2: ids.button6,
label: "6".to_string(),
value: '6',
},
ButtonInfo {
widget_id2: ids.button_multi,
label: "×".to_string(),
value: '*',
},
],
vec![
ButtonInfo {
widget_id2: ids.button1,
label: "1".to_string(),
value: '1',
},
ButtonInfo {
widget_id2: ids.button2,
label: "2".to_string(),
value: '2',
},
ButtonInfo {
widget_id2: ids.button3,
label: "3".to_string(),
value: '3',
},
ButtonInfo {
widget_id2: ids.button_minus,
label: "ー".to_string(),
value: '-',
},
],
vec![
ButtonInfo {
widget_id2: ids.button0,
label: "0".to_string(),
value: '0',
},
ButtonInfo {
widget_id2: ids.button_point,
label: ".".to_string(),
value: '.',
},
ButtonInfo {
widget_id2: ids.button_eq,
label: "=".to_string(),
value: '=',
},
ButtonInfo {
widget_id2: ids.button_plus,
label: "+".to_string(),
value: '+',
},
],
];
// フォントファイルの読み込み
const FONT_PATH: &'static str =
concat!(env!("CARGO_MANIFEST_DIR"), "/assets/fonts/ipag.ttf");
ui.fonts.insert_from_file(FONT_PATH).unwrap();
// gliumで描くためのオブジェクト
let mut renderer = conrod::backend::glium::Renderer::new(&display).unwrap();
// ウィジェットと画像をマッピングさせたマップ(今は使わない)
let image_map = conrod::image::Map::<glium::texture::Texture2d>::new();
let mut events = Vec::new();
// 表示用の数式文字列
let mut eq_display_string: String = "0".to_string();
// 内部処理用の数式文字列
let mut eq_string: String = "0".to_string();
//無限ループ(イベントを待つ人)
'render: loop {
events.clear();
// 最新のフレームからイベントをすべて取得する
events_loop.poll_events(|event| {
events.push(event);
});
// イベントが取得できるまで待つ。
if events.is_empty() {
events_loop.run_forever(|event| {
events.push(event);
glium::glutin::ControlFlow::Break
});
}
// 取得したイベントを処理する
for event in events.drain(..) {
//表示されたWindow上でクローズボタンが押された場合などの処理。
match event.clone() {
glium::glutin::Event::WindowEvent { event, .. } => match event {
glium::glutin::WindowEvent::CloseRequested
| glium::glutin::WindowEvent::KeyboardInput {
input:
glium::glutin::KeyboardInput {
virtual_keycode: Some(glium::glutin::VirtualKeyCode::Escape),
..
},
..
} => break 'render,
_ => (),
},
_ => (),
};
// winitイベントをconrodイベントに変換する。
let input = match conrod::backend::winit::convert_event(event, &display) {
None => continue,
Some(input) => input,
};
// UIでハンドリング(これでButtonをクリックしたときのイベントとかを検知できる)
ui.handle_event(input);
// ウィジェットをUIにセットする
let ui = &mut ui.set_widgets();
//計算表示
widget::TextBox::new(&eq_display_string)
.w_h(400.0, 40.0)
.top_left_of(ui.window)
.set(ids.textbox, ui);
let mut h = 1.0;
let mut w = 1.0;
for button_row in &button_map {
w = 1.0;
for button in button_row {
if widget::Button::new()
.w_h(40.0, 40.0)
.x_y(w * 70.0 - ui.win_w / 2.0, ui.win_h / 2.0 - h * 70.0)
.label(&button.label)
.label_font_size(16)
.set(button.widget_id2, ui)
.was_clicked()
{
match button.value {
'=' => {
println!("EQ is {}", eq_string);
let ans = calculate(eq_string.split_whitespace().collect());
eq_display_string = ans.to_string();
eq_string = ans.to_string();
}
'+' | '-' | '*' | '/' => {
eq_display_string.push_str(&button.label);
eq_string.push_str(&" ".to_string());
eq_string.push_str(&button.value.to_string());
eq_string.push_str(&" ".to_string());
}
_ => {
if eq_display_string == "0" && button.value != '.' {
//0のみで、入力文字が小数点でない場合は置き換える。
eq_display_string = eq_display_string.replace("0", &button.label);
eq_string = eq_string.replace("0", &button.value.to_string());
}else{
eq_display_string.push_str(&button.label);
eq_string.push_str(&button.value.to_string());
}
}
}
}
w = w + 1.0;
}
h = h + 1.0;
}
}
// uiが変わった場合に再描画する
if let Some(primitives) = ui.draw_if_changed() {
renderer.fill(&display, primitives, &image_map);
let mut target = display.draw();
target.clear_color(0.0, 0.0, 0.0, 1.0); //背景色
renderer.draw(&display, &mut target, &image_map).unwrap();
target.finish().unwrap();
}
}
}
/// 引数で受け取った演算式の結果を返す関数
fn calculate(eq_string: Vec<&str>) -> f64 {
let mut nums: Vec<f64> = vec![]; //数式の数字
let mut op: Vec<String> = vec![]; //数式の演算子
let mut answer: f64 = 0.0;
for p in eq_string {
match p.parse::<f64>() {
Ok(num) => {
nums.push(num);
}
Err(_) => {
if op.len() == 0 {
//要素がない場合は追加するだけ
op.push(p.to_string());
} else {
if op.last() == Some(&"*".to_string()) {
//最後の要素が*だった場合
let ans = nums.pop().unwrap() * nums.pop().unwrap();
nums.push(ans);
op.pop();
op.push(p.to_string());
} else if op.last() == Some(&"/".to_string()) {
//最後の要素が/だった場合
let num1 = nums.pop().unwrap();
let num2 = nums.pop().unwrap();
let ans = num2 / num1;
nums.push(ans);
op.pop();
op.push(p.to_string());
} else {
op.push(p.to_string());
}
}
}
}
}
//残った計算を実施する
while op.len() != 0 {
let operator = op.pop();
if operator == Some("+".to_string()) {
answer = nums.pop().unwrap() + nums.pop().unwrap();
} else if operator == Some("-".to_string()) {
let num1 = nums.pop().unwrap();
let num2 = nums.pop().unwrap();
answer = num2 - num1;
} else if operator == Some("*".to_string()) {
answer = nums.pop().unwrap() * nums.pop().unwrap();
} else {
let num1 = nums.pop().unwrap();
let num2 = nums.pop().unwrap();
answer = num2 / num1;
}
nums.push(answer);
}
answer
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment