| 347 |
347 |
|
THEME.read().border
|
| 348 |
348 |
|
}
|
| 349 |
349 |
|
|
|
350 |
+ |
/// This app's resolved theme, as the palette `makeover-egui` renders against.
|
|
351 |
+ |
///
|
|
352 |
+ |
/// The whole makeover-to-renderer adapter, and deliberately a snapshot rather
|
|
353 |
+ |
/// than a handle: it is six `Copy` colors read under one lock, so a caller
|
|
354 |
+ |
/// painting several regions in a frame is not taking the lock per edge.
|
|
355 |
+ |
///
|
|
356 |
+ |
/// `well` is `None` because `ThemeColors` has no `surface_well`: that intent is
|
|
357 |
+ |
/// derived by makeover 2.3.0, which is bumped in-tree and unpublished, and this
|
|
358 |
+ |
/// app is on 2.2.0. The renderer supplies `surface-page` in its place, which is
|
|
359 |
+ |
/// exactly what [`super::widgets::inset_well`] filled by hand before, so the
|
|
360 |
+ |
/// fallback is a transcription of current behaviour rather than a new choice.
|
|
361 |
+ |
pub fn palette() -> makeover_egui::Palette {
|
|
362 |
+ |
let t = THEME.read();
|
|
363 |
+ |
makeover_egui::Palette {
|
|
364 |
+ |
page: t.surface_page,
|
|
365 |
+ |
raised: t.surface_raised,
|
|
366 |
+ |
overlay: t.surface_overlay,
|
|
367 |
+ |
well: None,
|
|
368 |
+ |
bevel_light: t.bevel_light,
|
|
369 |
+ |
bevel_dark: t.bevel_dark,
|
|
370 |
+ |
}
|
|
371 |
+ |
}
|
|
372 |
+ |
|
| 350 |
373 |
|
/// The lit edge of a bevel: top and left on a raised surface.
|
| 351 |
374 |
|
pub fn bevel_light() -> Color32 {
|
| 352 |
375 |
|
THEME.read().bevel_light
|
| 378 |
401 |
|
/// `Visuals.widgets.*.bg_stroke` is a single stroke with no per-side control,
|
| 379 |
402 |
|
/// so no amount of theme tuning produces a two-tone frame.
|
| 380 |
403 |
|
pub mod bevel {
|
| 381 |
|
- |
use super::{bevel_dark, bevel_light, stroke};
|
|
404 |
+ |
use super::{palette, stroke};
|
| 382 |
405 |
|
|
| 383 |
406 |
|
/// Which way the light falls.
|
| 384 |
|
- |
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
| 385 |
|
- |
pub enum Bevel {
|
| 386 |
|
- |
/// Lit from the top left: light top and left, dark bottom and right.
|
| 387 |
|
- |
Raised,
|
| 388 |
|
- |
/// The same frame inverted, which is also the pressed state of
|
| 389 |
|
- |
/// anything that draws itself `Raised`.
|
| 390 |
|
- |
Inset,
|
| 391 |
|
- |
}
|
| 392 |
|
- |
|
| 393 |
|
- |
/// The (top-left, bottom-right) edge colors for a bevel.
|
| 394 |
407 |
|
///
|
| 395 |
|
- |
/// Split out from [`paint`] because the inversion is the load-bearing part
|
| 396 |
|
- |
/// and a `Painter` needs a live render context to build.
|
| 397 |
|
- |
fn edges(kind: Bevel) -> (egui::Color32, egui::Color32) {
|
| 398 |
|
- |
match kind {
|
| 399 |
|
- |
Bevel::Raised => (bevel_light(), bevel_dark()),
|
| 400 |
|
- |
Bevel::Inset => (bevel_dark(), bevel_light()),
|
| 401 |
|
- |
}
|
| 402 |
|
- |
}
|
|
408 |
+ |
/// Re-exported rather than defined: this used to be a local enum with the
|
|
409 |
+ |
/// same two variants and the same inversion rule. `makeover-layout` owns
|
|
410 |
+ |
/// the vocabulary now, so the terminal and webview renderers invert a
|
|
411 |
+ |
/// bevel the same way this one does instead of each restating it.
|
|
412 |
+ |
pub use makeover_layout::Bevel;
|
| 403 |
413 |
|
|
| 404 |
414 |
|
/// Paint a 1px two-tone frame just inside `rect`.
|
| 405 |
415 |
|
///
|
| 406 |
|
- |
/// Fill first, bevel after: this paints two polylines and nothing else, so
|
| 407 |
|
- |
/// it composes onto whatever is already there rather than clearing it.
|
| 408 |
|
- |
/// That is what lets it go over an `egui::TextEdit` after `ui.add`, where
|
| 409 |
|
- |
/// the widget's own fill has already landed.
|
|
416 |
+ |
/// Now a thin call into `makeover-egui`, which holds the polyline geometry
|
|
417 |
+ |
/// and the half-stroke inset. What stays here is the choice of stroke
|
|
418 |
+ |
/// width, which is a value and so belongs to the app until
|
|
419 |
+ |
/// `makeover-geometry` carries border widths.
|
| 410 |
420 |
|
pub fn paint(painter: &egui::Painter, rect: egui::Rect, kind: Bevel) {
|
| 411 |
|
- |
let (light, dark) = edges(kind);
|
| 412 |
|
- |
|
| 413 |
|
- |
// Inset by half a stroke so the 1px line lands inside `rect` rather
|
| 414 |
|
- |
// than straddling its edge, which on a fractional-scale display is the
|
| 415 |
|
- |
// difference between one crisp pixel and two dim ones.
|
| 416 |
|
- |
let r = rect.shrink(stroke::DEFAULT / 2.0);
|
| 417 |
|
- |
|
| 418 |
|
- |
// Two 3-point polylines meeting at the opposite corners. A polyline
|
| 419 |
|
- |
// rather than three segments so the corner joins are mitered by egui
|
| 420 |
|
- |
// instead of leaving a notch.
|
| 421 |
|
- |
painter.add(egui::Shape::line(
|
| 422 |
|
- |
vec![r.left_bottom(), r.left_top(), r.right_top()],
|
| 423 |
|
- |
egui::Stroke::new(stroke::DEFAULT, light),
|
| 424 |
|
- |
));
|
| 425 |
|
- |
painter.add(egui::Shape::line(
|
| 426 |
|
- |
vec![r.right_top(), r.right_bottom(), r.left_bottom()],
|
| 427 |
|
- |
egui::Stroke::new(stroke::DEFAULT, dark),
|
| 428 |
|
- |
));
|
|
421 |
+ |
makeover_egui::paint_bevel(painter, rect, kind, &palette(), stroke::DEFAULT);
|
| 429 |
422 |
|
}
|
| 430 |
423 |
|
|
| 431 |
424 |
|
#[cfg(test)]
|
| 432 |
425 |
|
mod tests {
|
| 433 |
426 |
|
use super::*;
|
| 434 |
427 |
|
|
|
428 |
+ |
// The inversion itself is now asserted in `makeover-layout`, where the
|
|
429 |
+ |
// rule lives. What is worth testing here is the adapter: that this
|
|
430 |
+ |
// app's palette maps the description's edge intents onto the theme
|
|
431 |
+ |
// colors it actually resolved, and does not quietly swap them.
|
| 435 |
432 |
|
#[test]
|
| 436 |
|
- |
fn inset_is_raised_with_the_light_moved() {
|
| 437 |
|
- |
// The whole idiom in one assertion: the pressed state of a raised
|
| 438 |
|
- |
// control is the same frame with its two edges swapped, which is
|
| 439 |
|
- |
// why a bevel is cheap to invert and expensive to fake.
|
| 440 |
|
- |
let (rl, rd) = edges(Bevel::Raised);
|
| 441 |
|
- |
let (il, id) = edges(Bevel::Inset);
|
| 442 |
|
- |
assert_eq!((rl, rd), (id, il));
|
|
433 |
+ |
fn a_raised_edge_is_lit_from_the_top_left() {
|
|
434 |
+ |
let p = palette();
|
|
435 |
+ |
let (top_left, bottom_right) = Bevel::Raised.edges();
|
|
436 |
+ |
assert_eq!(p.edge(top_left), crate::ui::theme::bevel_light());
|
|
437 |
+ |
assert_eq!(p.edge(bottom_right), crate::ui::theme::bevel_dark());
|
| 443 |
438 |
|
}
|
| 444 |
439 |
|
|
| 445 |
440 |
|
#[test]
|
| 446 |
|
- |
fn a_raised_edge_is_lit_from_the_top_left() {
|
| 447 |
|
- |
let (top_left, bottom_right) = edges(Bevel::Raised);
|
| 448 |
|
- |
assert_eq!(top_left, bevel_light());
|
| 449 |
|
- |
assert_eq!(bottom_right, bevel_dark());
|
|
441 |
+ |
fn pressing_swaps_which_theme_color_each_side_takes() {
|
|
442 |
+ |
let p = palette();
|
|
443 |
+ |
let (tl, _) = Bevel::Raised.edges();
|
|
444 |
+ |
let (ptl, _) = Bevel::Raised.pressed().edges();
|
|
445 |
+ |
assert_eq!(p.edge(tl), crate::ui::theme::bevel_light());
|
|
446 |
+ |
assert_eq!(p.edge(ptl), crate::ui::theme::bevel_dark());
|
| 450 |
447 |
|
}
|
| 451 |
448 |
|
}
|
| 452 |
449 |
|
}
|