Fixed `FallbackConfig`.
This commit is contained in:
parent
2101834526
commit
b8ce11cfca
|
@ -1,8 +1,3 @@
|
|||
* Test emoji, looks like webrender supports then.
|
||||
- We need more than one "fallback" font?
|
||||
- Right now we use "Segoe UI Symbol" in Windows.
|
||||
- We need to fallback to "Segoe UI Emoji" instead, or have both?
|
||||
|
||||
# TextInput
|
||||
|
||||
* Implement cursor position.
|
||||
|
@ -29,17 +24,26 @@
|
|||
- Input replaces selection.
|
||||
- Char input, paste, IME
|
||||
- Impl cut & copy.
|
||||
|
||||
* Implement custom node access to text.
|
||||
- Clone text var in `ResolvedText`?
|
||||
- Getter property `get_transformed_text`, to get the text after whitespace transforms?
|
||||
|
||||
* Implement IME.
|
||||
- See https://github.com/rust-windowing/winit/issues/1497
|
||||
|
||||
# Clipboard
|
||||
|
||||
* Implement image copy&paste in image example.
|
||||
|
||||
# Config
|
||||
# Emoji Rendering
|
||||
|
||||
* `FallbackConfig` always inserts a copy on the write config, should stay bound to fallback.
|
||||
- We want the "config/fallback" to be used like the "workspace/user" settings of VSCode.
|
||||
- When the fallback changes and it is not overridden the config var should update.
|
||||
- When it is set, the config file only should update.
|
||||
- Like a `CowVar`.
|
||||
- But we still have the embedded ultimate fallback.
|
||||
* Tech is called CPAL/COLR.
|
||||
- Layered glyphs of different colors.
|
||||
* Looks like webrender expects the glyphs to be pre-processed?
|
||||
* Newer versions of harfbuzz have function to get the colors.
|
||||
|
||||
* We need more than one "fallback" font?
|
||||
- Right now we use "Segoe UI Symbol" in Windows.
|
||||
- We need to fallback to "Segoe UI Emoji" instead, or have both?
|
||||
- See what browsers do, maybe we need a "front" font, that is added on top of other fonts?
|
|
@ -25,103 +25,40 @@ impl<S: Config, F: Config> AnyConfig for FallbackConfig<S, F> {
|
|||
}
|
||||
|
||||
fn get_raw(&mut self, key: ConfigKey, default: RawConfigValue, shared: bool) -> BoxedVar<RawConfigValue> {
|
||||
let over = self.config.get_raw(key.clone(), default.clone(), shared);
|
||||
let cfg_var = self.config.get_raw(key.clone(), default.clone(), shared);
|
||||
if self.config.contains_key(&key) {
|
||||
return over;
|
||||
// no need for fallback
|
||||
return cfg_var;
|
||||
}
|
||||
|
||||
let fallback = self.fallback.get_raw(key, default, shared);
|
||||
let result = var(fallback.get());
|
||||
let fall_var = self.fallback.get_raw(key, default, shared);
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum State {
|
||||
Fallback,
|
||||
FallbackUpdated,
|
||||
Over,
|
||||
OverUpdated,
|
||||
}
|
||||
let state = Arc::new(atomic::Atomic::new(State::Fallback));
|
||||
let res_var = var(fall_var.get());
|
||||
|
||||
// hook fallback, signal `result` that an update is flowing from the fallback.
|
||||
let wk_result = result.downgrade();
|
||||
fallback
|
||||
.hook(Box::new(clmv!(state, |value| {
|
||||
match state.load(atomic::Ordering::Relaxed) {
|
||||
State::Over | State::OverUpdated => {
|
||||
// result -> over
|
||||
return false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let fall_to_res = fall_var.bind(&res_var);
|
||||
|
||||
// fallback -> result
|
||||
if let Some(result) = wk_result.upgrade() {
|
||||
state.store(State::FallbackUpdated, atomic::Ordering::Relaxed);
|
||||
result.set(value.as_any().downcast_ref::<RawConfigValue>().unwrap().clone());
|
||||
true
|
||||
} else {
|
||||
// weak-ref to avoid circular ref.
|
||||
false
|
||||
}
|
||||
})))
|
||||
.perm();
|
||||
|
||||
// hook over, signals `result` that an update is flowing from the override.
|
||||
let wk_result = result.downgrade();
|
||||
over.hook(Box::new(clmv!(state, |value| {
|
||||
match state.load(atomic::Ordering::Relaxed) {
|
||||
State::OverUpdated => {
|
||||
// result -> over
|
||||
state.store(State::Over, atomic::Ordering::Relaxed);
|
||||
}
|
||||
_ => {
|
||||
// over -> result
|
||||
let value = value.as_any().downcast_ref::<RawConfigValue>().unwrap();
|
||||
state.store(State::OverUpdated, atomic::Ordering::Relaxed);
|
||||
if let Some(result) = wk_result.upgrade() {
|
||||
result.set(value.clone());
|
||||
let fall_var = Mutex::new(Some((fall_var, fall_to_res)));
|
||||
res_var
|
||||
.hook(Box::new(move |v| {
|
||||
let mut fall_var = fall_var.lock();
|
||||
if let Some((fv, _)) = &*fall_var {
|
||||
if fv.last_update() != VARS.update_id() {
|
||||
// update from assign, disconnect from fallback.
|
||||
*fall_var = None;
|
||||
let _ = cfg_var.set(v.as_any().downcast_ref::<RawConfigValue>().unwrap().clone());
|
||||
} else {
|
||||
// weak-ref to avoid circular ref.
|
||||
return false;
|
||||
// update from fallback
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
let _ = cfg_var.set_ne(v.as_any().downcast_ref::<RawConfigValue>().unwrap().clone());
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
})))
|
||||
.perm();
|
||||
|
||||
// hook result, on first callback not caused by `fallback` drops it and changes to `over`.
|
||||
let fallback = Mutex::new(Some(fallback));
|
||||
result
|
||||
.hook(Box::new(move |value| {
|
||||
match state.load(atomic::Ordering::Relaxed) {
|
||||
State::Fallback => {
|
||||
// result -> over(first)
|
||||
state.store(State::Over, atomic::Ordering::Relaxed);
|
||||
*fallback.lock() = None;
|
||||
let value = value.as_any().downcast_ref::<RawConfigValue>().unwrap().clone();
|
||||
let _ = over.set_ne(value);
|
||||
}
|
||||
State::FallbackUpdated => {
|
||||
// fallback -> result
|
||||
state.store(State::Fallback, atomic::Ordering::Relaxed);
|
||||
}
|
||||
State::Over => {
|
||||
// result -> over
|
||||
let value = value.as_any().downcast_ref::<RawConfigValue>().unwrap().clone();
|
||||
let _ = over.set_ne(value);
|
||||
}
|
||||
State::OverUpdated => {
|
||||
// over -> result
|
||||
state.store(State::Over, atomic::Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
true
|
||||
}))
|
||||
.perm();
|
||||
|
||||
result.boxed()
|
||||
res_var.boxed()
|
||||
}
|
||||
|
||||
fn contains_key(&self, key: &ConfigKey) -> bool {
|
||||
|
@ -132,100 +69,38 @@ impl<S: Config, F: Config> Config for FallbackConfig<S, F> {
|
|||
fn get<T: ConfigValue>(&mut self, key: impl Into<ConfigKey>, default: impl FnOnce() -> T) -> BoxedVar<T> {
|
||||
let key = key.into();
|
||||
let default = default();
|
||||
let fallback = self.fallback.get(key.clone(), || default.clone());
|
||||
let over = var(None::<T>); // TODO, actually provided by self.source
|
||||
if over.with(|s| s.is_some()) {
|
||||
return self.config.get(key, move || default);
|
||||
|
||||
let cfg_var = self.config.get(key.clone(), || default.clone());
|
||||
if self.config.contains_key(&key) {
|
||||
// no need for fallback
|
||||
return cfg_var;
|
||||
}
|
||||
let result = var(fallback.get());
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum State {
|
||||
Fallback,
|
||||
FallbackUpdated,
|
||||
Over,
|
||||
OverUpdated,
|
||||
}
|
||||
let state = Arc::new(atomic::Atomic::new(State::Fallback));
|
||||
let fall_var = self.fallback.get(key, || default);
|
||||
|
||||
// hook fallback, signal `result` that an update is flowing from the fallback.
|
||||
let wk_result = result.downgrade();
|
||||
fallback
|
||||
.hook(Box::new(clmv!(state, |value| {
|
||||
match state.load(atomic::Ordering::Relaxed) {
|
||||
State::Over | State::OverUpdated => {
|
||||
// result -> over
|
||||
return false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let res_var = var(fall_var.get());
|
||||
|
||||
// fallback -> result
|
||||
if let Some(result) = wk_result.upgrade() {
|
||||
state.store(State::FallbackUpdated, atomic::Ordering::Relaxed);
|
||||
result.set(value.as_any().downcast_ref::<T>().unwrap().clone());
|
||||
true
|
||||
} else {
|
||||
// weak-ref to avoid circular ref.
|
||||
false
|
||||
}
|
||||
})))
|
||||
.perm();
|
||||
let fall_to_res = fall_var.bind(&res_var);
|
||||
|
||||
// hook over, signals `result` that an update is flowing from the override.
|
||||
let wk_result = result.downgrade();
|
||||
over.hook(Box::new(clmv!(state, |value| {
|
||||
match state.load(atomic::Ordering::Relaxed) {
|
||||
State::OverUpdated => {
|
||||
// result -> over
|
||||
state.store(State::Over, atomic::Ordering::Relaxed);
|
||||
}
|
||||
_ => {
|
||||
// over -> result
|
||||
if let Some(value) = value.as_any().downcast_ref::<Option<T>>().unwrap() {
|
||||
state.store(State::OverUpdated, atomic::Ordering::Relaxed);
|
||||
if let Some(result) = wk_result.upgrade() {
|
||||
result.set(value.clone());
|
||||
} else {
|
||||
// weak-ref to avoid circular ref.
|
||||
return false;
|
||||
}
|
||||
let fall_var = Mutex::new(Some((fall_var, fall_to_res)));
|
||||
res_var
|
||||
.hook(Box::new(move |v| {
|
||||
let mut fall_var = fall_var.lock();
|
||||
if let Some((fv, _)) = &*fall_var {
|
||||
if fv.last_update() != VARS.update_id() {
|
||||
// update from assign, disconnect from fallback.
|
||||
*fall_var = None;
|
||||
} else {
|
||||
// update from fallback
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
})))
|
||||
.perm();
|
||||
|
||||
// hook result, on first callback not caused by `fallback` drops it and changes to `over`.
|
||||
let fallback = Mutex::new(Some(fallback));
|
||||
result
|
||||
.hook(Box::new(move |value| {
|
||||
match state.load(atomic::Ordering::Relaxed) {
|
||||
State::Fallback => {
|
||||
// result -> over(first)
|
||||
state.store(State::Over, atomic::Ordering::Relaxed);
|
||||
*fallback.lock() = None;
|
||||
over.set(Some(value.as_any().downcast_ref::<T>().unwrap().clone()));
|
||||
}
|
||||
State::FallbackUpdated => {
|
||||
// fallback -> result
|
||||
state.store(State::Fallback, atomic::Ordering::Relaxed);
|
||||
}
|
||||
State::Over => {
|
||||
// result -> over
|
||||
over.set(Some(value.as_any().downcast_ref::<T>().unwrap().clone()));
|
||||
}
|
||||
State::OverUpdated => {
|
||||
// over -> result
|
||||
state.store(State::Over, atomic::Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
let _ = cfg_var.set(v.as_any().downcast_ref::<T>().unwrap().clone());
|
||||
true
|
||||
}))
|
||||
.perm();
|
||||
|
||||
result.boxed()
|
||||
res_var.boxed()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue