mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-07 13:35:14 +02:00
feat(bar): binary clock and no-second time formats
This commit is contained in:
+263
-13
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::bar::Alignment;
|
||||||
use crate::config::LabelPrefix;
|
use crate::config::LabelPrefix;
|
||||||
use crate::render::RenderConfig;
|
use crate::render::RenderConfig;
|
||||||
use crate::selected_frame::SelectableFrame;
|
use crate::selected_frame::SelectableFrame;
|
||||||
@@ -6,8 +7,12 @@ use eframe::egui::text::LayoutJob;
|
|||||||
use eframe::egui::Align;
|
use eframe::egui::Align;
|
||||||
use eframe::egui::Context;
|
use eframe::egui::Context;
|
||||||
use eframe::egui::Label;
|
use eframe::egui::Label;
|
||||||
|
use eframe::egui::Rounding;
|
||||||
|
use eframe::egui::Sense;
|
||||||
|
use eframe::egui::Stroke;
|
||||||
use eframe::egui::TextFormat;
|
use eframe::egui::TextFormat;
|
||||||
use eframe::egui::Ui;
|
use eframe::egui::Ui;
|
||||||
|
use eframe::egui::Vec2;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
@@ -36,8 +41,16 @@ impl From<TimeConfig> for Time {
|
|||||||
pub enum TimeFormat {
|
pub enum TimeFormat {
|
||||||
/// Twelve-hour format (with seconds)
|
/// Twelve-hour format (with seconds)
|
||||||
TwelveHour,
|
TwelveHour,
|
||||||
|
/// Twelve-hour format (without seconds)
|
||||||
|
TwelveHourWithoutSeconds,
|
||||||
/// Twenty-four-hour format (with seconds)
|
/// Twenty-four-hour format (with seconds)
|
||||||
TwentyFourHour,
|
TwentyFourHour,
|
||||||
|
/// Twenty-four-hour format (without seconds)
|
||||||
|
TwentyFourHourWithoutSeconds,
|
||||||
|
/// Twenty-four-hour format displayed as a binary clock with circles (with seconds) (https://en.wikipedia.org/wiki/Binary_clock)
|
||||||
|
BinaryCircle,
|
||||||
|
/// Twenty-four-hour format displayed as a binary clock with rectangles (with seconds) (https://en.wikipedia.org/wiki/Binary_clock)
|
||||||
|
BinaryRectangle,
|
||||||
/// Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)
|
/// Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)
|
||||||
Custom(String),
|
Custom(String),
|
||||||
}
|
}
|
||||||
@@ -45,8 +58,12 @@ pub enum TimeFormat {
|
|||||||
impl TimeFormat {
|
impl TimeFormat {
|
||||||
pub fn toggle(&mut self) {
|
pub fn toggle(&mut self) {
|
||||||
match self {
|
match self {
|
||||||
TimeFormat::TwelveHour => *self = TimeFormat::TwentyFourHour,
|
TimeFormat::TwelveHour => *self = TimeFormat::TwelveHourWithoutSeconds,
|
||||||
TimeFormat::TwentyFourHour => *self = TimeFormat::TwelveHour,
|
TimeFormat::TwelveHourWithoutSeconds => *self = TimeFormat::TwentyFourHour,
|
||||||
|
TimeFormat::TwentyFourHour => *self = TimeFormat::TwentyFourHourWithoutSeconds,
|
||||||
|
TimeFormat::TwentyFourHourWithoutSeconds => *self = TimeFormat::BinaryCircle,
|
||||||
|
TimeFormat::BinaryCircle => *self = TimeFormat::BinaryRectangle,
|
||||||
|
TimeFormat::BinaryRectangle => *self = TimeFormat::TwelveHour,
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -54,7 +71,11 @@ impl TimeFormat {
|
|||||||
fn fmt_string(&self) -> String {
|
fn fmt_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
TimeFormat::TwelveHour => String::from("%l:%M:%S %p"),
|
TimeFormat::TwelveHour => String::from("%l:%M:%S %p"),
|
||||||
|
TimeFormat::TwelveHourWithoutSeconds => String::from("%l:%M %p"),
|
||||||
TimeFormat::TwentyFourHour => String::from("%T"),
|
TimeFormat::TwentyFourHour => String::from("%T"),
|
||||||
|
TimeFormat::TwentyFourHourWithoutSeconds => String::from("%H:%M"),
|
||||||
|
TimeFormat::BinaryCircle => String::from("c%T"),
|
||||||
|
TimeFormat::BinaryRectangle => String::from("r%T"),
|
||||||
TimeFormat::Custom(format) => format.to_string(),
|
TimeFormat::Custom(format) => format.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,6 +93,169 @@ impl Time {
|
|||||||
chrono::Local::now()
|
chrono::Local::now()
|
||||||
.format(&self.format.fmt_string())
|
.format(&self.format.fmt_string())
|
||||||
.to_string()
|
.to_string()
|
||||||
|
.trim()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint_binary_circle(
|
||||||
|
&mut self,
|
||||||
|
size: f32,
|
||||||
|
number: u32,
|
||||||
|
max_power: usize,
|
||||||
|
ctx: &Context,
|
||||||
|
ui: &mut Ui,
|
||||||
|
) {
|
||||||
|
let full_height = size;
|
||||||
|
let height = full_height / 4.0;
|
||||||
|
let width = height;
|
||||||
|
|
||||||
|
let (response, painter) =
|
||||||
|
ui.allocate_painter(Vec2::new(width, full_height), Sense::hover());
|
||||||
|
let color = ctx.style().visuals.text_color();
|
||||||
|
|
||||||
|
let c = response.rect.center();
|
||||||
|
let r = height / 2.0 - 0.5;
|
||||||
|
|
||||||
|
if number == 1 || number == 3 || number == 5 || number == 7 || number == 9 {
|
||||||
|
painter.circle_filled(c + Vec2::new(0.0, height * 1.50), r, color);
|
||||||
|
} else {
|
||||||
|
painter.circle_filled(c + Vec2::new(0.0, height * 1.50), r / 2.5, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if number == 2 || number == 3 || number == 6 || number == 7 {
|
||||||
|
painter.circle_filled(c + Vec2::new(0.0, height * 0.50), r, color);
|
||||||
|
} else {
|
||||||
|
painter.circle_filled(c + Vec2::new(0.0, height * 0.50), r / 2.5, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if number == 4 || number == 5 || number == 6 || number == 7 {
|
||||||
|
painter.circle_filled(c + Vec2::new(0.0, -height * 0.50), r, color);
|
||||||
|
} else if max_power > 2 {
|
||||||
|
painter.circle_filled(c + Vec2::new(0.0, -height * 0.50), r / 2.5, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if number == 8 || number == 9 {
|
||||||
|
painter.circle_filled(c + Vec2::new(0.0, -height * 1.50), r, color);
|
||||||
|
} else if max_power > 3 {
|
||||||
|
painter.circle_filled(c + Vec2::new(0.0, -height * 1.50), r / 2.5, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint_binary_rect(
|
||||||
|
&mut self,
|
||||||
|
size: f32,
|
||||||
|
number: u32,
|
||||||
|
max_power: usize,
|
||||||
|
ctx: &Context,
|
||||||
|
ui: &mut Ui,
|
||||||
|
) {
|
||||||
|
let full_height = size;
|
||||||
|
let height = full_height / 4.0;
|
||||||
|
let width = height * 1.5;
|
||||||
|
|
||||||
|
let (response, painter) =
|
||||||
|
ui.allocate_painter(Vec2::new(width, full_height), Sense::hover());
|
||||||
|
let color = ctx.style().visuals.text_color();
|
||||||
|
let stroke = Stroke::new(1.0, color);
|
||||||
|
|
||||||
|
let round_all = Rounding::same(response.rect.width() * 0.1);
|
||||||
|
let round_top = Rounding {
|
||||||
|
nw: round_all.nw,
|
||||||
|
ne: round_all.ne,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let round_none = Rounding::ZERO;
|
||||||
|
let round_bottom = Rounding {
|
||||||
|
sw: round_all.nw,
|
||||||
|
se: round_all.ne,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
if max_power == 2 {
|
||||||
|
let mut rect = response.rect.shrink(stroke.width);
|
||||||
|
rect.set_height(rect.height() - height * 2.0);
|
||||||
|
rect = rect.translate(Vec2::new(0.0, height * 2.0));
|
||||||
|
painter.rect_stroke(rect, round_all, stroke);
|
||||||
|
} else if max_power == 3 {
|
||||||
|
let mut rect = response.rect.shrink(stroke.width);
|
||||||
|
rect.set_height(rect.height() - height);
|
||||||
|
rect = rect.translate(Vec2::new(0.0, height));
|
||||||
|
painter.rect_stroke(rect, round_all, stroke);
|
||||||
|
} else {
|
||||||
|
painter.rect_stroke(response.rect.shrink(stroke.width), round_all, stroke);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rect_bin = response.rect;
|
||||||
|
rect_bin.set_width(width);
|
||||||
|
|
||||||
|
if number == 1 || number == 5 || number == 9 {
|
||||||
|
rect_bin.set_height(height);
|
||||||
|
painter.rect_filled(
|
||||||
|
rect_bin.translate(Vec2::new(0.0, height * 3.0)),
|
||||||
|
round_bottom,
|
||||||
|
color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if number == 2 {
|
||||||
|
rect_bin.set_height(height);
|
||||||
|
painter.rect_filled(
|
||||||
|
rect_bin.translate(Vec2::new(0.0, height * 2.0)),
|
||||||
|
if max_power == 2 {
|
||||||
|
round_top
|
||||||
|
} else {
|
||||||
|
round_none
|
||||||
|
},
|
||||||
|
color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if number == 3 {
|
||||||
|
rect_bin.set_height(height * 2.0);
|
||||||
|
painter.rect_filled(
|
||||||
|
rect_bin.translate(Vec2::new(0.0, height * 2.0)),
|
||||||
|
round_bottom,
|
||||||
|
color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if number == 4 || number == 5 {
|
||||||
|
rect_bin.set_height(height);
|
||||||
|
painter.rect_filled(
|
||||||
|
rect_bin.translate(Vec2::new(0.0, height * 1.0)),
|
||||||
|
if max_power == 3 {
|
||||||
|
round_top
|
||||||
|
} else {
|
||||||
|
round_none
|
||||||
|
},
|
||||||
|
color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if number == 6 {
|
||||||
|
rect_bin.set_height(height * 2.0);
|
||||||
|
painter.rect_filled(
|
||||||
|
rect_bin.translate(Vec2::new(0.0, height * 1.0)),
|
||||||
|
if max_power == 3 {
|
||||||
|
round_top
|
||||||
|
} else {
|
||||||
|
round_none
|
||||||
|
},
|
||||||
|
color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if number == 7 {
|
||||||
|
rect_bin.set_height(height * 3.0);
|
||||||
|
painter.rect_filled(
|
||||||
|
rect_bin.translate(Vec2::new(0.0, height)),
|
||||||
|
if max_power == 3 {
|
||||||
|
round_all
|
||||||
|
} else {
|
||||||
|
round_bottom
|
||||||
|
},
|
||||||
|
color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if number == 8 || number == 9 {
|
||||||
|
rect_bin.set_height(height);
|
||||||
|
painter.rect_filled(rect_bin.translate(Vec2::new(0.0, 0.0)), round_top, color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,6 +264,9 @@ impl BarWidget for Time {
|
|||||||
if self.enable {
|
if self.enable {
|
||||||
let mut output = self.output();
|
let mut output = self.output();
|
||||||
if !output.is_empty() {
|
if !output.is_empty() {
|
||||||
|
let use_binary_circle = output.starts_with('c');
|
||||||
|
let use_binary_rectangle = output.starts_with('r');
|
||||||
|
|
||||||
let mut layout_job = LayoutJob::simple(
|
let mut layout_job = LayoutJob::simple(
|
||||||
match self.label_prefix {
|
match self.label_prefix {
|
||||||
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
||||||
@@ -96,20 +283,83 @@ impl BarWidget for Time {
|
|||||||
output.insert_str(0, "TIME: ");
|
output.insert_str(0, "TIME: ");
|
||||||
}
|
}
|
||||||
|
|
||||||
layout_job.append(
|
if !use_binary_circle && !use_binary_rectangle {
|
||||||
&output,
|
layout_job.append(
|
||||||
10.0,
|
&output,
|
||||||
TextFormat {
|
10.0,
|
||||||
font_id: config.text_font_id.clone(),
|
TextFormat {
|
||||||
color: ctx.style().visuals.text_color(),
|
font_id: config.text_font_id.clone(),
|
||||||
valign: Align::Center,
|
color: ctx.style().visuals.text_color(),
|
||||||
..Default::default()
|
valign: Align::Center,
|
||||||
},
|
..Default::default()
|
||||||
);
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let font_id = config.icon_font_id.clone();
|
||||||
|
let is_reversed = matches!(config.alignment, Some(Alignment::Right));
|
||||||
|
|
||||||
config.apply_on_widget(false, ui, |ui| {
|
config.apply_on_widget(false, ui, |ui| {
|
||||||
if SelectableFrame::new(false)
|
if SelectableFrame::new(false)
|
||||||
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
.show(ui, |ui| {
|
||||||
|
if !is_reversed {
|
||||||
|
ui.add(Label::new(layout_job.clone()).selectable(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
if use_binary_circle || use_binary_rectangle {
|
||||||
|
let ordered_output = if is_reversed {
|
||||||
|
output.chars().rev().collect()
|
||||||
|
} else {
|
||||||
|
output
|
||||||
|
};
|
||||||
|
|
||||||
|
for (section_index, section) in
|
||||||
|
ordered_output.split(':').enumerate()
|
||||||
|
{
|
||||||
|
ui.scope(|ui| {
|
||||||
|
ui.spacing_mut().item_spacing = Vec2::splat(2.0);
|
||||||
|
for (number_index, number_char) in
|
||||||
|
section.chars().enumerate()
|
||||||
|
{
|
||||||
|
if let Some(number) = number_char.to_digit(10) {
|
||||||
|
// the hour is the second char in the first section (in reverse, it's in the last section)
|
||||||
|
let max_power = match (
|
||||||
|
is_reversed,
|
||||||
|
section_index,
|
||||||
|
number_index,
|
||||||
|
) {
|
||||||
|
(true, 2, 1) | (false, 0, 1) => 2,
|
||||||
|
(true, _, 1) | (false, _, 0) => 3,
|
||||||
|
_ => 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
if use_binary_circle {
|
||||||
|
self.paint_binary_circle(
|
||||||
|
font_id.size,
|
||||||
|
number,
|
||||||
|
max_power,
|
||||||
|
ctx,
|
||||||
|
ui,
|
||||||
|
);
|
||||||
|
} else if use_binary_rectangle {
|
||||||
|
self.paint_binary_rect(
|
||||||
|
font_id.size,
|
||||||
|
number,
|
||||||
|
max_power,
|
||||||
|
ctx,
|
||||||
|
ui,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_reversed {
|
||||||
|
ui.add(Label::new(layout_job.clone()).selectable(false));
|
||||||
|
}
|
||||||
|
})
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
self.format.toggle()
|
self.format.toggle()
|
||||||
|
|||||||
@@ -723,6 +723,13 @@
|
|||||||
"TwelveHour"
|
"TwelveHour"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Twelve-hour format (without seconds)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"TwelveHourWithoutSeconds"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Twenty-four-hour format (with seconds)",
|
"description": "Twenty-four-hour format (with seconds)",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -730,6 +737,27 @@
|
|||||||
"TwentyFourHour"
|
"TwentyFourHour"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Twenty-four-hour format (without seconds)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"TwentyFourHourWithoutSeconds"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Twenty-four-hour format displayed as a binary clock with circles (with seconds) (https://en.wikipedia.org/wiki/Binary_clock)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"BinaryCircle"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Twenty-four-hour format displayed as a binary clock with rectangles (with seconds) (https://en.wikipedia.org/wiki/Binary_clock)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"BinaryRectangle"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)",
|
"description": "Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -1905,6 +1933,13 @@
|
|||||||
"TwelveHour"
|
"TwelveHour"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Twelve-hour format (without seconds)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"TwelveHourWithoutSeconds"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Twenty-four-hour format (with seconds)",
|
"description": "Twenty-four-hour format (with seconds)",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -1912,6 +1947,27 @@
|
|||||||
"TwentyFourHour"
|
"TwentyFourHour"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Twenty-four-hour format (without seconds)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"TwentyFourHourWithoutSeconds"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Twenty-four-hour format displayed as a binary clock with circles (with seconds) (https://en.wikipedia.org/wiki/Binary_clock)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"BinaryCircle"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Twenty-four-hour format displayed as a binary clock with rectangles (with seconds) (https://en.wikipedia.org/wiki/Binary_clock)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"BinaryRectangle"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)",
|
"description": "Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -2840,6 +2896,13 @@
|
|||||||
"TwelveHour"
|
"TwelveHour"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Twelve-hour format (without seconds)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"TwelveHourWithoutSeconds"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Twenty-four-hour format (with seconds)",
|
"description": "Twenty-four-hour format (with seconds)",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -2847,6 +2910,27 @@
|
|||||||
"TwentyFourHour"
|
"TwentyFourHour"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Twenty-four-hour format (without seconds)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"TwentyFourHourWithoutSeconds"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Twenty-four-hour format displayed as a binary clock with circles (with seconds) (https://en.wikipedia.org/wiki/Binary_clock)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"BinaryCircle"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Twenty-four-hour format displayed as a binary clock with rectangles (with seconds) (https://en.wikipedia.org/wiki/Binary_clock)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"BinaryRectangle"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)",
|
"description": "Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|||||||
Reference in New Issue
Block a user