Skip to content

Commit

Permalink
Add application: Calculator
Browse files Browse the repository at this point in the history
  • Loading branch information
baskerville committed Jan 18, 2019
1 parent 4583074 commit 35d7989
Show file tree
Hide file tree
Showing 22 changed files with 1,244 additions and 127 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/archives
/resources
/libs
/bin
/Settings.toml
/user.css
/hyphenation-patterns
Expand Down
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ case "$method" in
echo "Downloading ${archive}."
release_url=$(wget -q -O - "$info_url" | grep -Eo "https[^\"]+files[^\"]+${archive}")
wget -q "$release_url"
unzip "$archive" 'libs/*' 'hyphenation-patterns/*'
unzip "$archive" 'libs/*' 'bin/*' 'hyphenation-patterns/*'
rm "$archive"
cd libs

Expand Down
1 change: 1 addition & 0 deletions dist.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ cp libs/libmupdf.so dist/libs
cp libs/libmupdfwrapper.so dist/libs

cp -R hyphenation-patterns dist
cp -R bin dist
cp -R scripts dist
cp -R icons dist
cp -R fonts dist
Expand Down
2 changes: 1 addition & 1 deletion doc/TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
- Pocket articles.
- Complex/fuzzy search queries?
- Input field completions bar.
- Applications: Terminal, Calculator, Browser.
- Applications: Terminal, Browser.
130 changes: 66 additions & 64 deletions src/app.rs

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion src/apps/mod.rs

This file was deleted.

83 changes: 45 additions & 38 deletions src/emulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ mod frontlight;
mod lightsensor;
mod symbolic_path;
mod trash;
mod apps;
mod app;

use std::mem;
Expand All @@ -40,13 +39,15 @@ use sdl2::rect::Rect as SdlRect;
use crate::framebuffer::{Framebuffer, UpdateMode};
use crate::input::{DeviceEvent, FingerStatus};
use crate::view::{View, Event, ViewId, EntryId, AppId, EntryKind};
use crate::view::{render, render_no_wait, render_no_wait_region, handle_event, fill_crack};
use crate::view::{render, render_no_wait, render_no_wait_region, handle_event, expose};
use crate::view::home::Home;
use crate::view::reader::Reader;
use crate::view::notification::Notification;
use crate::view::frontlight::FrontlightWindow;
use crate::view::keyboard::Keyboard;
use crate::view::menu::{Menu, MenuKind};
use crate::view::sketch::Sketch;
use crate::view::calculator::Calculator;
use crate::view::common::{locate, locate_by_id, transfer_notifications, overlapping_rectangle};
use crate::helpers::{load_json, save_json, load_toml, save_toml};
use crate::metadata::{Metadata, METADATA_FILENAME};
Expand All @@ -57,7 +58,6 @@ use crate::device::CURRENT_DEVICE;
use crate::battery::{Battery, FakeBattery};
use crate::frontlight::{Frontlight, LightLevels};
use crate::lightsensor::LightSensor;
use crate::apps::sketch::Sketch;
use crate::font::Fonts;
use crate::app::Context;

Expand All @@ -66,7 +66,7 @@ const DEFAULT_ROTATION: i8 = 1;

const CLOCK_REFRESH_INTERVAL: Duration = Duration::from_secs(60);

pub fn build_context(fb: &Framebuffer) -> Result<Context, Error> {
pub fn build_context(fb: Box<dyn Framebuffer>) -> Result<Context, Error> {
let settings = load_toml::<Settings, _>(SETTINGS_PATH)?;
let path = settings.library_path.join(METADATA_FILENAME);
let metadata = load_json::<Metadata, _>(path)?;
Expand Down Expand Up @@ -135,10 +135,10 @@ impl Framebuffer for WindowCanvas {

fn update(&mut self, _rect: &Rectangle, _mode: UpdateMode) -> Result<u32, Error> {
self.present();
Ok(1)
Ok(Local::now().timestamp_subsec_millis())
}

fn wait(&self, _: u32) -> Result<i32, Error> {
fn wait(&self, _tok: u32) -> Result<i32, Error> {
Ok(1)
}

Expand Down Expand Up @@ -198,7 +198,7 @@ pub fn run() -> Result<(), Error> {
let mut fb = window.into_canvas().software().build().unwrap();
fb.set_blend_mode(BlendMode::Blend);

let mut context = build_context(&fb)?;
let mut context = build_context(Box::new(fb))?;

let (tx, rx) = mpsc::channel();
let (ty, ry) = mpsc::channel();
Expand All @@ -220,7 +220,7 @@ pub fn run() -> Result<(), Error> {
});

let mut history: Vec<Box<dyn View>> = Vec::new();
let mut view: Box<dyn View> = Box::new(Home::new(fb.rect(), &tx, &mut context)?);
let mut view: Box<dyn View> = Box::new(Home::new(context.fb.rect(), &tx, &mut context)?);

let mut updating = FnvHashMap::default();

Expand All @@ -235,16 +235,22 @@ pub fn run() -> Result<(), Error> {

println!("{} is running on a Kobo {}.", APP_NAME,
CURRENT_DEVICE.model);
println!("The framebuffer resolution is {} by {}.", fb.rect().width(),
fb.rect().height());
println!("The framebuffer resolution is {} by {}.", context.fb.rect().width(),
context.fb.rect().height());

let mut bus = VecDeque::with_capacity(4);

'outer: loop {
if let Some(sdl_evt) = sdl_context.event_pump().unwrap().wait_event_timeout(20) {
match sdl_evt {
SdlEvent::Quit { .. } |
SdlEvent::KeyDown { keycode: Some(Keycode::Escape), .. } => break,
SdlEvent::KeyDown { keycode: Some(Keycode::Escape), .. } => {
view.handle_event(&Event::Back, &tx, &mut VecDeque::new(), &mut context);
while let Some(mut view) = history.pop() {
view.handle_event(&Event::Back, &tx, &mut VecDeque::new(), &mut context);
}
break;
},
SdlEvent::KeyDown { scancode: Some(scancode), .. } => {
if let Some(kb_idx) = locate::<Keyboard>(view.as_ref()) {
let index = match scancode {
Expand Down Expand Up @@ -294,41 +300,41 @@ pub fn run() -> Result<(), Error> {
while let Ok(evt) = rx.recv_timeout(Duration::from_millis(20)) {
match evt {
Event::Render(mut rect, mode) => {
render(view.as_ref(), &mut rect, &mut fb, &mut context.fonts, &mut updating);
if let Ok(tok) = fb.update(&rect, mode) {
render(view.as_ref(), &mut rect, context.fb.as_mut(), &mut context.fonts, &mut updating);
if let Ok(tok) = context.fb.update(&rect, mode) {
updating.insert(tok, rect);
}
},
Event::RenderNoWait(mut rect, mode) => {
render_no_wait(view.as_ref(), &mut rect, &mut fb, &mut context.fonts, &mut updating);
if let Ok(tok) = fb.update(&rect, mode) {
render_no_wait(view.as_ref(), &mut rect, context.fb.as_mut(), &mut context.fonts, &mut updating);
if let Ok(tok) = context.fb.update(&rect, mode) {
updating.insert(tok, rect);
}
},
Event::RenderNoWaitRegion(mut rect, mode) => {
render_no_wait_region(view.as_ref(), &mut rect, &mut fb, &mut context.fonts, &mut updating);
if let Ok(tok) = fb.update(&rect, mode) {
render_no_wait_region(view.as_ref(), &mut rect, context.fb.as_mut(), &mut context.fonts, &mut updating);
if let Ok(tok) = context.fb.update(&rect, mode) {
updating.insert(tok, rect);
}
},
Event::Expose(mut rect, mode) => {
fill_crack(view.as_ref(), &mut rect, &mut fb, &mut context.fonts, &mut updating);
if let Ok(tok) = fb.update(&rect, mode) {
expose(view.as_ref(), &mut rect, context.fb.as_mut(), &mut context.fonts, &mut updating);
if let Ok(tok) = context.fb.update(&rect, mode) {
updating.insert(tok, rect);
}
},
Event::Open(info) => {
let rotation = context.display.rotation;
if let Some(n) = info.reader.as_ref().and_then(|r| r.rotation) {
if n != rotation {
if let Ok(dims) = fb.set_rotation(n) {
if let Ok(dims) = context.fb.set_rotation(n) {
context.display.rotation = n;
context.display.dims = dims;
}
}
}
let info2 = info.clone();
if let Some(r) = Reader::new(fb.rect(), *info, &tx, &mut context) {
if let Some(r) = Reader::new(context.fb.rect(), *info, &tx, &mut context) {
let mut next_view = Box::new(r) as Box<dyn View>;
transfer_notifications(view.as_mut(), next_view.as_mut(), &mut context);
history.push(view as Box<dyn View>);
Expand All @@ -338,31 +344,32 @@ pub fn run() -> Result<(), Error> {
}
},
Event::OpenToc(ref toc, current_page, next_page) => {
let r = Reader::from_toc(fb.rect(), toc, current_page, next_page, &tx, &mut context);
let r = Reader::from_toc(context.fb.rect(), toc, current_page, next_page, &tx, &mut context);
let mut next_view = Box::new(r) as Box<dyn View>;
transfer_notifications(view.as_mut(), next_view.as_mut(), &mut context);
history.push(view as Box<dyn View>);
view = next_view;
},
Event::Select(EntryId::Launch(app_id)) => {
view.children_mut().retain(|child| !child.is::<Menu>());
match app_id {
let mut next_view: Box<View> = match app_id {
AppId::Sketch => {
let v = Sketch::new(fb.rect(), &tx, &mut context);
let mut next_view = Box::new(v) as Box<View>;
transfer_notifications(view.as_mut(), next_view.as_mut(), &mut context);
history.push(view as Box<View>);
view = next_view;
Box::new(Sketch::new(context.fb.rect(), &tx, &mut context))
},
_ => (),
}
AppId::Calculator => {
Box::new(Calculator::new(context.fb.rect(), &tx, &mut context)?)
},
};
transfer_notifications(view.as_mut(), next_view.as_mut(), &mut context);
history.push(view as Box<View>);
view = next_view;
},
Event::Back => {
if let Some(v) = history.pop() {
view = v;
if view.is::<Home>() {
if context.display.rotation % 2 != 1 {
if let Ok(dims) = fb.set_rotation(DEFAULT_ROTATION) {
if let Ok(dims) = context.fb.set_rotation(DEFAULT_ROTATION) {
context.display.rotation = DEFAULT_ROTATION;
context.display.dims = dims;
}
Expand Down Expand Up @@ -408,8 +415,8 @@ pub fn run() -> Result<(), Error> {
}
},
Event::Select(EntryId::Rotate(n)) if n != context.display.rotation => {
updating.retain(|tok, _| fb.wait(*tok).is_err());
if let Ok(dims) = fb.set_rotation(n) {
updating.retain(|tok, _| context.fb.wait(*tok).is_err());
if let Ok(dims) = context.fb.set_rotation(n) {
context.display.rotation = n;
let fb_rect = Rectangle::from(dims);
if context.display.dims != dims {
Expand All @@ -419,18 +426,18 @@ pub fn run() -> Result<(), Error> {
}
},
Event::Select(EntryId::ToggleInverted) => {
fb.toggle_inverted();
context.fb.toggle_inverted();
context.inverted = !context.inverted;
tx.send(Event::Render(fb.rect(), UpdateMode::Gui)).unwrap();
tx.send(Event::Render(context.fb.rect(), UpdateMode::Gui)).unwrap();
},
Event::Select(EntryId::ToggleMonochrome) => {
fb.toggle_monochrome();
context.fb.toggle_monochrome();
context.monochrome = !context.monochrome;
tx.send(Event::Render(fb.rect(), UpdateMode::Gui)).unwrap();
tx.send(Event::Render(context.fb.rect(), UpdateMode::Gui)).unwrap();
},
Event::Select(EntryId::TakeScreenshot) => {
let name = Local::now().format("screenshot-%Y%m%d_%H%M%S.png");
let msg = match fb.save(&name.to_string()) {
let msg = match context.fb.save(&name.to_string()) {
Err(e) => format!("Couldn't take screenshot: {}).", e),
Ok(_) => format!("Saved {}.", name),
};
Expand Down
27 changes: 21 additions & 6 deletions src/font/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,16 +155,17 @@ impl FontFamily {
}

pub struct Fonts {
sans_serif: FontFamily,
serif: FontFamily,
keyboard: Font,
display: Font,
pub sans_serif: FontFamily,
pub serif: FontFamily,
pub monospace: FontFamily,
pub keyboard: Font,
pub display: Font,
}

impl Fonts {
pub fn load() -> Result<Fonts, Error> {
let opener = FontOpener::new()?;
Ok(Fonts {
let mut fonts = Fonts {
sans_serif: FontFamily {
regular: opener.open("fonts/NotoSans-Regular.ttf")?,
italic: opener.open("fonts/NotoSans-Italic.ttf")?,
Expand All @@ -177,9 +178,18 @@ impl Fonts {
bold: opener.open("fonts/NotoSerif-Bold.ttf")?,
bold_italic: opener.open("fonts/NotoSerif-BoldItalic.ttf")?,
},
monospace: FontFamily {
regular: opener.open("fonts/SourceCodeVariable-Roman.otf")?,
italic: opener.open("fonts/SourceCodeVariable-Italic.otf")?,
bold: opener.open("fonts/SourceCodeVariable-Roman.otf")?,
bold_italic: opener.open("fonts/SourceCodeVariable-Italic.otf")?,
},
keyboard: opener.open("fonts/VarelaRound-Regular.ttf")?,
display: opener.open("fonts/Cormorant-Regular.ttf")?,
})
};
fonts.monospace.bold.set_variations(&["wght=600"]);
fonts.monospace.bold_italic.set_variations(&["wght=600"]);
Ok(fonts)
}
}

Expand All @@ -195,6 +205,7 @@ bitflags! {
pub enum Family {
SansSerif,
Serif,
Monospace,
Keyboard,
Display,
}
Expand Down Expand Up @@ -227,6 +238,10 @@ pub fn font_from_style<'a>(fonts: &'a mut Fonts, style: &Style, dpi: u16) -> &'a
let family = &mut fonts.serif;
font_from_variant(family, style.variant)
},
Family::Monospace => {
let family = &mut fonts.monospace;
font_from_variant(family, style.variant)
},
Family::Keyboard => &mut fonts.keyboard,
Family::Display => &mut fonts.display,
};
Expand Down
1 change: 0 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ mod settings;
mod trash;
mod view;
mod font;
mod apps;
mod app;

use std::process;
Expand Down
20 changes: 20 additions & 0 deletions src/settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub struct Settings {
pub reader: ReaderSettings,
pub import: ImportSettings,
pub sketch: SketchSettings,
pub calculator: CalculatorSettings,
pub battery: BatterySettings,
pub frontlight_levels: LightLevels,
}
Expand All @@ -57,6 +58,14 @@ pub struct SketchSettings {
pub pen: Pen,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, rename_all = "kebab-case")]
pub struct CalculatorSettings {
pub font_size: f32,
pub margin_width: i32,
pub history_size: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, rename_all = "kebab-case")]
pub struct Pen {
Expand Down Expand Up @@ -89,6 +98,16 @@ impl Default for SketchSettings {
}
}

impl Default for CalculatorSettings {
fn default() -> Self {
CalculatorSettings {
font_size: 8.0,
margin_width: 2,
history_size: 4096,
}
}
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum SecondColumn {
Expand Down Expand Up @@ -193,6 +212,7 @@ impl Default for Settings {
reader: ReaderSettings::default(),
import: ImportSettings::default(),
sketch: SketchSettings::default(),
calculator: CalculatorSettings::default(),
battery: BatterySettings::default(),
frontlight_levels: LightLevels::default(),
frontlight_presets: Vec::new(),
Expand Down
Loading

0 comments on commit 35d7989

Please sign in to comment.