Skip to content

Commit

Permalink
Add support for frontlight presets
Browse files Browse the repository at this point in the history
  • Loading branch information
baskerville committed Apr 23, 2018
1 parent f1d3410 commit df9b017
Show file tree
Hide file tree
Showing 25 changed files with 790 additions and 146 deletions.
2 changes: 1 addition & 1 deletion doc/MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Gestures by region:
- Hold: next bookmark.
- *BL* (Bottom Left Corner):
- Tap: table of contents in normal mode, previous page in search mode.
- Hold: toggle frontlight.
- Hold: guess the frontlight if there's more than two frontlight presets defined, toggle the frontlight otherwise.
- *BR* (Bottom Right Corner):
- Tap: go to page in normal mode, next page in search mode.
- Hold: invert colors.
Expand Down
60 changes: 43 additions & 17 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ use std::time::{Instant, Duration};
use fnv::FnvHashMap;
use chrono::Local;
use framebuffer::{Framebuffer, KoboFramebuffer, UpdateMode};
use view::{View, Event, EntryId, ViewId};
use view::{View, Event, EntryId, EntryKind, ViewId};
use view::{render, render_no_wait, handle_event, fill_crack};
use view::common::{locate, locate_by_id, overlapping_rectangle};
use view::frontlight::FrontlightWindow;
use view::menu::{Menu, MenuKind};
use input::{DeviceEvent, ButtonCode, ButtonStatus};
use input::{raw_events, device_events, usb_events};
use gesture::{GestureEvent, gesture_events, BUTTON_HOLD_DELAY};
use helpers::{load_json, save_json};
use metadata::{Metadata, METADATA_FILENAME, import};
use settings::{Settings, SETTINGS_PATH};
use frontlight::{Frontlight, NaturalFrontlight, StandardFrontlight};
use lightsensor::{LightSensor, KoboLightSensor};
use battery::{Battery, KoboBattery};
use view::home::Home;
use view::reader::Reader;
Expand All @@ -41,6 +43,7 @@ pub struct Context {
pub fonts: Fonts,
pub frontlight: Box<Frontlight>,
pub battery: Box<Battery>,
pub lightsensor: Box<LightSensor>,
pub notification_index: u8,
pub resumed_at: Instant,
pub inverted: bool,
Expand All @@ -51,11 +54,13 @@ pub struct Context {
}

impl Context {
pub fn new(settings: Settings, metadata: Metadata, filename: PathBuf,
fonts: Fonts, frontlight: Box<Frontlight>, battery: Box<Battery>) -> Context {
Context { settings, metadata, filename, fonts, frontlight, battery,
notification_index: 0, resumed_at: Instant::now(),
inverted: false, monochrome: false, suspended: false,
pub fn new(settings: Settings, metadata: Metadata,
filename: PathBuf, fonts: Fonts, battery: Box<Battery>,
frontlight: Box<Frontlight>, lightsensor: Box<LightSensor>) -> Context {
Context { settings, metadata, filename, fonts, battery,
frontlight, lightsensor, notification_index: 0,
resumed_at: Instant::now(), inverted: false,
monochrome: false, suspended: false,
plugged: false, mounted: false }
}
}
Expand Down Expand Up @@ -131,24 +136,31 @@ pub fn run() -> Result<()> {

let levels = settings.frontlight_levels;
let mut frontlight = if CURRENT_DEVICE.has_natural_light() {
Box::new(NaturalFrontlight::new(levels.intensity(), levels.warmth())
Box::new(NaturalFrontlight::new(levels.intensity, levels.warmth)
.chain_err(|| "Can't create natural frontlight.")?) as Box<Frontlight>
} else {
Box::new(StandardFrontlight::new(levels.intensity())
Box::new(StandardFrontlight::new(levels.intensity)
.chain_err(|| "Can't create standard frontlight.")?) as Box<Frontlight>
};

if settings.frontlight {
frontlight.set_intensity(levels.intensity());
frontlight.set_warmth(levels.warmth());
frontlight.set_intensity(levels.intensity);
frontlight.set_warmth(levels.warmth);
} else {
frontlight.set_warmth(0.0);
frontlight.set_intensity(0.0);
}

let battery = Box::new(KoboBattery::new().chain_err(|| "Can't create battery.")?) as Box<Battery>;

let mut context = Context::new(settings, metadata, PathBuf::from(METADATA_FILENAME), fonts, frontlight, battery);
let lightsensor = if CURRENT_DEVICE.has_lightsensor() {
Box::new(KoboLightSensor::new().chain_err(|| "Can't create light sensor.")?) as Box<LightSensor>
} else {
Box::new(0u16) as Box<LightSensor>
};

let mut context = Context::new(settings, metadata, PathBuf::from(METADATA_FILENAME),
fonts, battery, frontlight, lightsensor);
let mut history: Vec<Box<View>> = Vec::new();
let mut view: Box<View> = Box::new(Home::new(fb_rect, &tx, &mut context)?);

Expand Down Expand Up @@ -220,8 +232,8 @@ pub fn run() -> Result<()> {
}
if context.settings.frontlight {
let levels = context.settings.frontlight_levels;
context.frontlight.set_intensity(levels.intensity());
context.frontlight.set_warmth(levels.warmth());
context.frontlight.set_intensity(levels.intensity);
context.frontlight.set_warmth(levels.warmth);
}
if let Some(index) = locate::<Intermission>(view.as_ref()) {
let rect = *view.child(index).rect();
Expand Down Expand Up @@ -296,8 +308,8 @@ pub fn run() -> Result<()> {
}
if context.settings.frontlight {
let levels = context.settings.frontlight_levels;
context.frontlight.set_intensity(levels.intensity());
context.frontlight.set_warmth(levels.warmth());
context.frontlight.set_intensity(levels.intensity);
context.frontlight.set_warmth(levels.warmth);
}
tx.send(Event::ClockTick).unwrap();
tx.send(Event::BatteryTick).unwrap();
Expand Down Expand Up @@ -348,8 +360,8 @@ pub fn run() -> Result<()> {
context.settings.frontlight = !context.settings.frontlight;
if context.settings.frontlight {
let levels = context.settings.frontlight_levels;
context.frontlight.set_intensity(levels.intensity());
context.frontlight.set_warmth(levels.warmth());
context.frontlight.set_intensity(levels.intensity);
context.frontlight.set_warmth(levels.warmth);
} else {
context.settings.frontlight_levels = context.frontlight.levels();
context.frontlight.set_warmth(0.0);
Expand Down Expand Up @@ -394,6 +406,20 @@ pub fn run() -> Result<()> {
view.handle_event(&Event::Reseed, &tx, &mut bus, &mut context);
}
},
Event::TogglePresetMenu(rect, index) => {
if let Some(index) = locate_by_id(view.as_ref(), ViewId::PresetMenu) {
let rect = *view.child(index).rect();
view.children_mut().remove(index);
tx.send(Event::Expose(rect)).unwrap();
} else {
let preset_menu = Menu::new(rect, ViewId::PresetMenu, MenuKind::Contextual,
vec![EntryKind::Command("Remove".to_string(),
EntryId::RemovePreset(index))],
&mut context.fonts);
tx.send(Event::Render(*preset_menu.rect(), UpdateMode::Gui)).unwrap();
view.children_mut().push(Box::new(preset_menu) as Box<View>);
}
},
Event::Show(ViewId::Frontlight) => {
if !context.settings.frontlight {
continue;
Expand Down
7 changes: 7 additions & 0 deletions src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ impl Device {
_ => false,
}
}

pub fn has_lightsensor(&self) -> bool {
match self.model {
Model::AuraONE => true,
_ => false,
}
}
}

lazy_static! {
Expand Down
41 changes: 37 additions & 4 deletions src/emulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ mod document;
mod metadata;
mod settings;
mod frontlight;
mod lightsensor;
mod symbolic_path;
mod trash;
mod app;
Expand Down Expand Up @@ -73,21 +74,24 @@ use sdl2::rect::Point as SdlPoint;
use sdl2::rect::Rect as SdlRect;
use framebuffer::{Framebuffer, UpdateMode};
use input::{DeviceEvent, FingerStatus};
use view::{View, Event, ViewId, EntryId, render, render_no_wait, handle_event, fill_crack};
use view::{View, Event, ViewId, EntryId, EntryKind};
use view::{render, render_no_wait, handle_event, fill_crack};
use view::home::Home;
use view::reader::Reader;
use view::notification::Notification;
use view::frontlight::FrontlightWindow;
use view::keyboard::Keyboard;
use view::menu::{Menu, MenuKind};
use view::common::{locate, locate_by_id, overlapping_rectangle};
use geom::Rectangle;
use gesture::gesture_events;
use device::CURRENT_DEVICE;
use helpers::{load_json, save_json};
use metadata::{Metadata, METADATA_FILENAME};
use settings::{Settings, SETTINGS_PATH};
use frontlight::{Frontlight, FakeFrontlight};
use battery::{Battery, FakeBattery};
use frontlight::{Frontlight, LightLevels};
use lightsensor::LightSensor;
use font::Fonts;
use app::Context;
use errors::*;
Expand All @@ -100,10 +104,12 @@ pub fn build_context() -> Result<Context> {
let settings = load_json::<Settings, _>(SETTINGS_PATH)?;
let path = settings.library_path.join(METADATA_FILENAME);
let metadata = load_json::<Metadata, _>(path)?;
let frontlight = Box::new(FakeFrontlight::new()) as Box<Frontlight>;
let battery = Box::new(FakeBattery::new()) as Box<Battery>;
let frontlight = Box::new(LightLevels::default()) as Box<Frontlight>;
let lightsensor = Box::new(0u16) as Box<LightSensor>;
let fonts = Fonts::load()?;
Ok(Context::new(settings, metadata, PathBuf::from(METADATA_FILENAME), fonts, frontlight, battery))
Ok(Context::new(settings, metadata, PathBuf::from(METADATA_FILENAME),
fonts, battery, frontlight, lightsensor))
}

#[inline]
Expand Down Expand Up @@ -230,6 +236,15 @@ pub fn run() -> Result<()> {

let mut updating = FnvHashMap::default();

if context.settings.frontlight {
let levels = context.settings.frontlight_levels;
context.frontlight.set_intensity(levels.intensity);
context.frontlight.set_warmth(levels.warmth);
} else {
context.frontlight.set_warmth(0.0);
context.frontlight.set_intensity(0.0);
}

println!("{} is running on a Kobo {}.", APP_NAME,
CURRENT_DEVICE.model);
println!("The framebuffer resolution is {} by {}.", fb_rect.width(),
Expand Down Expand Up @@ -328,6 +343,20 @@ pub fn run() -> Result<()> {
view.handle_event(&Event::Reseed, &tx, &mut bus, &mut context);
}
},
Event::TogglePresetMenu(rect, index) => {
if let Some(index) = locate_by_id(view.as_ref(), ViewId::PresetMenu) {
let rect = *view.child(index).rect();
view.children_mut().remove(index);
tx.send(Event::Expose(rect)).unwrap();
} else {
let preset_menu = Menu::new(rect, ViewId::PresetMenu, MenuKind::Contextual,
vec![EntryKind::Command("Remove".to_string(),
EntryId::RemovePreset(index))],
&mut context.fonts);
tx.send(Event::Render(*preset_menu.rect(), UpdateMode::Gui)).unwrap();
view.children_mut().push(Box::new(preset_menu) as Box<View>);
}
},
Event::Show(ViewId::Frontlight) => {
if !context.settings.frontlight {
continue;
Expand Down Expand Up @@ -387,6 +416,10 @@ pub fn run() -> Result<()> {
}
}

if context.settings.frontlight {
context.settings.frontlight_levels = context.frontlight.levels();
}

let path = context.settings.library_path.join(&context.filename);
save_json(&context.metadata, path).chain_err(|| "Can't save metadata.")?;

Expand Down
2 changes: 1 addition & 1 deletion src/framebuffer/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl Framebuffer for ImageFramebuffer {
return;
}
let addr = (y * self.width + x) as usize;
let blended_color = lerp(self.data[addr], color, alpha);
let blended_color = lerp(self.data[addr] as f32, color as f32, alpha) as u8;
self.data[addr] = blended_color;
}

Expand Down
2 changes: 1 addition & 1 deletion src/framebuffer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ pub trait Framebuffer {
if dist < mid_radius {
let delta_dist = small_radius as f32 - dist;
alpha = surface_area(delta_dist, angle);
color = lerp(color, border_color, alpha);
color = lerp(color as f32, border_color as f32, alpha) as u8;
alpha = 1.0;
} else {
let delta_dist = dist - radius as f32;
Expand Down
37 changes: 0 additions & 37 deletions src/frontlight/fake.rs

This file was deleted.

46 changes: 29 additions & 17 deletions src/frontlight/mod.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,50 @@
mod standard;
mod natural;
mod fake;

pub use self::standard::StandardFrontlight;
pub use self::natural::NaturalFrontlight;
pub use self::fake::FakeFrontlight;
use geom::lerp;

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum LightLevels {
Standard(f32),
Natural(f32, f32),
pub struct LightLevels {
pub intensity: f32,
pub warmth: f32,
}

impl LightLevels {
pub fn intensity(&self) -> f32 {
match *self {
LightLevels::Standard(v) => v,
LightLevels::Natural(v, _) => v,
impl Default for LightLevels {
fn default() -> Self {
LightLevels {
intensity: 0.0,
warmth: 0.0,
}
}
}

pub fn warmth(&self) -> f32 {
match *self {
LightLevels::Standard(_) => 0.0,
LightLevels::Natural(_, v) => v,
impl LightLevels {
pub fn interpolate(&self, other: &Self, t: f32) -> Self {
LightLevels {
intensity: lerp(self.intensity, other.intensity, t),
warmth: lerp(self.warmth, other.warmth, t),
}
}
}

pub trait Frontlight {
fn set_intensity(&mut self, value: f32);
fn set_warmth(&mut self, value: f32);
fn intensity(&self) -> f32;
fn warmth(&self) -> f32;
fn levels(&self) -> LightLevels;
}

impl Frontlight for LightLevels {
fn set_intensity(&mut self, value: f32) {
self.intensity = value;
}

fn set_warmth(&mut self, value: f32) {
self.warmth = value;
}

fn levels(&self) -> LightLevels {
*self
}
}
Loading

0 comments on commit df9b017

Please sign in to comment.