Last active
December 23, 2018 02:51
-
-
Save toshimasa-nanaki/f8cc1224d50cc1dfc1e7319593a1d331 to your computer and use it in GitHub Desktop.
Rust 電卓アプリ 計算できるようにした
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
//クレートとして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