Skip to content

Commit ede8e20

Browse files
committedJun 10, 2022
feat: implemented first rudimentary GUI
1 parent 68524df commit ede8e20

File tree

6 files changed

+1408
-18
lines changed

6 files changed

+1408
-18
lines changed
 

‎CHANGELOG.md

+11
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,26 @@ All notable changes to this project will be documented in this file.
44

55
## [unreleased]
66

7+
### Bug Fixes
8+
9+
- Excluding masterpiece and giftbox sets if include-promos is not enabled
10+
711
### Documentation
812

913
- Added changelog
14+
- Updated changelog
15+
- Updated changelog
1016

1117
### Features
1218

1319
- Added card prices to output
1420
- Added no-promos flag
1521
- Added unit tests for most functions and made api more testable
22+
- Implemented first rudimentary GUI
23+
24+
### Refactor
25+
26+
- Added anyhow crate for easier error handling
1627

1728
## [0.2.0-alpha] - 2022-05-23
1829

‎Cargo.lock

+1,055-17
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[workspace]
22
members = [
33
"scrollrack-core",
4-
"scrollrack-cli"
4+
"scrollrack-cli",
5+
"scrollrack-gui"
56
]
67

‎scrollrack-gui/Cargo.toml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "scrollrack-gui"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
scrollrack-core = { path = "../scrollrack-core" }
8+
druid = "0.7.0"

‎scrollrack-gui/src/main.rs

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// On Windows platform, don't show a console when opening the app.
2+
#![windows_subsystem = "windows"]
3+
4+
use std::sync::Arc;
5+
6+
use druid::widget::{Button, Flex, TextBox};
7+
use druid::{commands, Data, Lens};
8+
use druid::{
9+
AppDelegate, AppLauncher, DelegateCtx, Env, FileDialogOptions, FileSpec, Handled, Target,
10+
Widget, WidgetExt, WindowDesc,
11+
};
12+
use scrollrack_core::output;
13+
use scrollrack_core::parse;
14+
use scrollrack_core::query_stuff;
15+
16+
struct Delegate;
17+
18+
#[derive(Clone, Data, Lens)]
19+
struct AppData {
20+
input_str: Arc<String>,
21+
output_str: Arc<String>,
22+
}
23+
24+
fn build_app() -> impl Widget<AppData> {
25+
let txt = FileSpec::new("Text file", &["txt"]);
26+
let other = FileSpec::new("Deck file", &["dck", "deck"]);
27+
// The options can also be generated at runtime,
28+
// so to show that off we create a String for the default save name.
29+
let default_save_name = String::from("MyFile.txt");
30+
let save_dialog_options = FileDialogOptions::new()
31+
.allowed_types(vec![txt, other])
32+
.default_type(txt)
33+
.default_name(default_save_name)
34+
.name_label("Target")
35+
.title("Output file name")
36+
.button_text("Export");
37+
let open_dialog_options = save_dialog_options
38+
.clone()
39+
.default_name("MySavedFile.txt")
40+
.name_label("Source")
41+
.title("Input file name")
42+
.button_text("Import");
43+
44+
let save = Button::new("Save as...").on_click(move |ctx, _, _| {
45+
ctx.submit_command(druid::commands::SHOW_SAVE_PANEL.with(save_dialog_options.clone()))
46+
});
47+
let open = Button::new("Import...").on_click(move |ctx, _, _| {
48+
ctx.submit_command(druid::commands::SHOW_OPEN_PANEL.with(open_dialog_options.clone()))
49+
});
50+
51+
let sort = Button::new("Sort").on_click(move |_ctx, data: &mut AppData, _| {
52+
let card_infos = parse::parse_card_infos(data.input_str.lines());
53+
let cards_by_set = query_stuff::CardQuery::with_options(false, false).query(card_infos);
54+
let out_string = output::output_string::<output::SortByName>(cards_by_set);
55+
data.output_str = out_string.into();
56+
});
57+
58+
Flex::column()
59+
.with_flex_child(
60+
Flex::row()
61+
.main_axis_alignment(druid::widget::MainAxisAlignment::SpaceEvenly)
62+
.must_fill_main_axis(true)
63+
.with_flex_child(
64+
TextBox::multiline()
65+
.lens(AppData::input_str)
66+
.expand_height()
67+
.expand_width(),
68+
0.5,
69+
)
70+
.with_default_spacer()
71+
.with_flex_child(
72+
TextBox::multiline()
73+
.lens(AppData::output_str)
74+
.expand_height()
75+
.expand_width(),
76+
0.5,
77+
),
78+
0.9,
79+
)
80+
.with_default_spacer()
81+
.with_flex_child(
82+
Flex::row()
83+
.with_child(open)
84+
.with_default_spacer()
85+
.with_child(sort)
86+
.with_default_spacer()
87+
.with_child(save),
88+
0.1,
89+
)
90+
.padding(8.0)
91+
92+
// This method asks druid to draw colored rectangles around our widgets,
93+
// so we can visually inspect their layout rectangles.
94+
// col.debug_paint_layout()
95+
}
96+
97+
pub fn main() {
98+
let window = WindowDesc::new(build_app).title("Scrollrack GUI");
99+
100+
AppLauncher::with_window(window)
101+
.delegate(Delegate)
102+
.launch(AppData {
103+
input_str: "".to_string().into(),
104+
output_str: "".to_string().into(),
105+
})
106+
.expect("launch failed");
107+
}
108+
109+
impl AppDelegate<AppData> for Delegate {
110+
fn event(
111+
&mut self,
112+
_ctx: &mut DelegateCtx,
113+
_window_id: druid::WindowId,
114+
event: druid::Event,
115+
_data: &mut AppData,
116+
_env: &Env,
117+
) -> Option<druid::Event> {
118+
Some(event)
119+
}
120+
121+
fn command(
122+
&mut self,
123+
_ctx: &mut DelegateCtx,
124+
_target: Target,
125+
cmd: &druid::Command,
126+
data: &mut AppData,
127+
_env: &Env,
128+
) -> Handled {
129+
if let Some(file_info) = cmd.get(commands::SAVE_FILE_AS) {
130+
if let Err(e) = std::fs::write(file_info.path(), &data.output_str[..]) {
131+
println!("Error writing file: {}", e);
132+
}
133+
return Handled::Yes;
134+
}
135+
if let Some(file_info) = cmd.get(commands::OPEN_FILE) {
136+
match std::fs::read_to_string(file_info.path()) {
137+
Ok(s) => {
138+
data.input_str = s.into();
139+
}
140+
Err(e) => {
141+
println!("Error opening file: {}", e);
142+
}
143+
}
144+
return Handled::Yes;
145+
}
146+
Handled::No
147+
}
148+
149+
fn window_added(
150+
&mut self,
151+
_id: druid::WindowId,
152+
_data: &mut AppData,
153+
_env: &Env,
154+
_ctx: &mut DelegateCtx,
155+
) {
156+
}
157+
158+
fn window_removed(
159+
&mut self,
160+
_id: druid::WindowId,
161+
_data: &mut AppData,
162+
_env: &Env,
163+
_ctx: &mut DelegateCtx,
164+
) {
165+
}
166+
}

‎scrollrack-gui/src/main.rs.1

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// On Windows platform, don't show a console when opening the app.
2+
#![windows_subsystem = "windows"]
3+
4+
use std::sync::Arc;
5+
6+
use druid::widget::{Button, Flex, TextBox};
7+
use druid::{commands, Data, Lens, LocalizedString, WindowId};
8+
use druid::{
9+
AppDelegate, AppLauncher, DelegateCtx, Env, FileDialogOptions, FileSpec, Handled, Target,
10+
Widget, WidgetExt, WindowDesc,
11+
};
12+
use scrollrack_core::output;
13+
use scrollrack_core::parse;
14+
use scrollrack_core::query_stuff;
15+
16+
struct Delegate;
17+
18+
#[derive(Clone, Data, Lens)]
19+
struct AppData {
20+
input_str: Arc<String>,
21+
output_str: Arc<String>,
22+
}
23+
24+
fn build_app() -> impl Widget<AppData> {
25+
let txt = FileSpec::new("Text file", &["txt"]);
26+
let other = FileSpec::new("Deck file", &["dck", "deck"]);
27+
// The options can also be generated at runtime,
28+
// so to show that off we create a String for the default save name.
29+
let default_save_name = String::from("MyFile.txt");
30+
let save_dialog_options = FileDialogOptions::new()
31+
.allowed_types(vec![txt, other])
32+
.default_type(txt)
33+
.default_name(default_save_name)
34+
.name_label("Target")
35+
.title("Choose a target for this lovely file")
36+
.button_text("Export");
37+
let open_dialog_options = save_dialog_options
38+
.clone()
39+
.default_name("MySavedFile.txt")
40+
.name_label("Source")
41+
.title("Where did you put that file?")
42+
.button_text("Import");
43+
44+
let save = Button::new("Save").on_click(move |ctx, _, _| {
45+
ctx.submit_command(druid::commands::SHOW_SAVE_PANEL.with(save_dialog_options.clone()))
46+
});
47+
let open = Button::new("Open").on_click(move |ctx, _, _| {
48+
ctx.submit_command(druid::commands::SHOW_OPEN_PANEL.with(open_dialog_options.clone()))
49+
});
50+
51+
let sort = Button::new("Sort").on_click(move |_ctx, data: &mut AppData, _| {
52+
let card_infos = parse::parse_card_infos(data.input_str.lines());
53+
let cards_by_set = query_stuff::CardQuery::with_options(false, false).query(card_infos);
54+
let out_string = output::output_string::<output::SortByName>(cards_by_set);
55+
data.output_str = out_string.into();
56+
});
57+
58+
Flex::column()
59+
.with_flex_child(
60+
Flex::row()
61+
.main_axis_alignment(druid::widget::MainAxisAlignment::SpaceEvenly)
62+
.must_fill_main_axis(true)
63+
.with_flex_child(
64+
TextBox::multiline()
65+
.lens(AppData::input_str)
66+
.expand_height()
67+
.expand_width(),
68+
0.5,
69+
)
70+
.with_default_spacer()
71+
.with_flex_child(
72+
TextBox::multiline()
73+
.lens(AppData::output_str)
74+
.expand_height()
75+
.expand_width(),
76+
0.5,
77+
),
78+
0.9,
79+
)
80+
.with_default_spacer()
81+
.with_flex_child(
82+
Flex::row()
83+
.with_child(open)
84+
.with_default_spacer()
85+
.with_child(sort)
86+
.with_default_spacer()
87+
.with_child(save),
88+
0.1,
89+
)
90+
.padding(8.0)
91+
92+
// This method asks druid to draw colored rectangles around our widgets,
93+
// so we can visually inspect their layout rectangles.
94+
// col.debug_paint_layout()
95+
}
96+
97+
pub fn main() {
98+
let window = WindowDesc::new(build_app).title("Very flexible");
99+
100+
AppLauncher::with_window(window)
101+
.delegate(Delegate)
102+
.launch(AppData {
103+
input_str: "".to_string().into(),
104+
output_str: "".to_string().into(),
105+
})
106+
.expect("launch failed");
107+
}
108+
109+
impl AppDelegate<AppData> for Delegate {
110+
fn command(
111+
&mut self,
112+
_ctx: &mut DelegateCtx,
113+
_target: Target,
114+
cmd: &druid::Command,
115+
data: &mut AppData,
116+
_env: &Env,
117+
) -> Handled {
118+
if let Some(file_info) = cmd.get(commands::SAVE_FILE_AS) {
119+
if let Err(e) = std::fs::write(file_info.path(), &data.output_str[..]) {
120+
println!("Error writing file: {}", e);
121+
}
122+
return Handled::Yes;
123+
}
124+
if let Some(file_info) = cmd.get(commands::OPEN_FILE) {
125+
match std::fs::read_to_string(file_info.path()) {
126+
Ok(s) => {
127+
data.input_str = s.into();
128+
}
129+
Err(e) => {
130+
println!("Error opening file: {}", e);
131+
}
132+
}
133+
return Handled::Yes;
134+
}
135+
Handled::No
136+
}
137+
138+
fn event(
139+
&mut self,
140+
ctx: &mut DelegateCtx,
141+
window_id: druid::WindowId,
142+
event: druid::Event,
143+
data: &mut AppData,
144+
env: &Env,
145+
) -> Option<druid::Event> {
146+
Some(event)
147+
}
148+
149+
fn window_added(
150+
&mut self,
151+
id: druid::WindowId,
152+
data: &mut AppData,
153+
env: &Env,
154+
ctx: &mut DelegateCtx,
155+
) {
156+
}
157+
158+
fn window_removed(
159+
&mut self,
160+
id: druid::WindowId,
161+
data: &mut AppData,
162+
env: &Env,
163+
ctx: &mut DelegateCtx,
164+
) {
165+
}
166+
}

0 commit comments

Comments
 (0)
Please sign in to comment.