mirror of
https://gitlab.com/erkanisik/yali-rs.git
synced 2026-07-31 03:09:00 +00:00
feat: dropdown full-width click, gradient bg, pointing-hand cursor
This commit is contained in:
+24
-10
@@ -114,21 +114,35 @@ pub fn language_selector_ui(ui: &mut eframe::egui::Ui, state: &mut crate::instal
|
|||||||
let item_height = 28.0;
|
let item_height = 28.0;
|
||||||
|
|
||||||
// Eleman kutularını sarmalayarak tam genişlikte tıklanabilir yapıyoruz
|
// Eleman kutularını sarmalayarak tam genişlikte tıklanabilir yapıyoruz
|
||||||
ui.add_sized([available_width, item_height], |ui: &mut egui::Ui| {
|
let (rect, item_resp) = ui.allocate_exact_size(
|
||||||
|
egui::vec2(available_width, item_height),
|
||||||
|
egui::Sense::click(),
|
||||||
|
);
|
||||||
|
{
|
||||||
|
use egui::epaint::Mesh;
|
||||||
|
let top = egui::Color32::from_rgb(249, 249, 249);
|
||||||
|
let bot = egui::Color32::from_rgb(233, 233, 233);
|
||||||
|
let mut mesh = Mesh::default();
|
||||||
|
let idx = mesh.vertices.len() as u32;
|
||||||
|
mesh.vertices.push(egui::epaint::Vertex { pos: egui::pos2(rect.left(), rect.top()), uv: egui::pos2(0.0, 0.0), color: top });
|
||||||
|
mesh.vertices.push(egui::epaint::Vertex { pos: egui::pos2(rect.right(), rect.top()), uv: egui::pos2(0.0, 0.0), color: top });
|
||||||
|
mesh.vertices.push(egui::epaint::Vertex { pos: egui::pos2(rect.right(), rect.bottom()), uv: egui::pos2(0.0, 0.0), color: bot });
|
||||||
|
mesh.vertices.push(egui::epaint::Vertex { pos: egui::pos2(rect.left(), rect.bottom()), uv: egui::pos2(0.0, 0.0), color: bot });
|
||||||
|
mesh.indices.extend_from_slice(&[idx, idx + 1, idx + 2, idx + 2, idx + 3, idx]);
|
||||||
|
ui.painter().add(egui::Shape::mesh(mesh));
|
||||||
|
}
|
||||||
|
ui.put(rect, |ui: &mut egui::Ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add_space(6.0); // İç sol boşluk
|
ui.add_space(6.0);
|
||||||
ui.add(eframe::egui::Image::new(image_source.clone()).max_width(18.0));
|
ui.add(eframe::egui::Image::new(image_source.clone()).max_width(18.0));
|
||||||
ui.add_space(4.0);
|
ui.add_space(4.0);
|
||||||
|
ui.label(*label);
|
||||||
let mut current_lang = state.language.clone();
|
|
||||||
let resp = ui.selectable_value(&mut current_lang, code.to_string(), *label);
|
|
||||||
|
|
||||||
if resp.clicked() {
|
|
||||||
state.language = code.to_string();
|
|
||||||
}
|
|
||||||
resp
|
|
||||||
}).response
|
}).response
|
||||||
});
|
});
|
||||||
|
if item_resp.clicked() {
|
||||||
|
state.language = code.to_string();
|
||||||
|
}
|
||||||
|
item_resp.on_hover_cursor(egui::CursorIcon::PointingHand);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+8
-9
@@ -471,18 +471,18 @@ impl InstallerStep for WelcomeStep {
|
|||||||
// Rescue mode butonu
|
// Rescue mode butonu
|
||||||
ui.add_space(10.0);
|
ui.add_space(10.0);
|
||||||
|
|
||||||
ui.allocate_ui(
|
egui::Frame::none()
|
||||||
egui::vec2(ui.available_width(), 30.0), // Genişlik tam, Yükseklik sadece 24px
|
.rounding(egui::Rounding::same(6.0))
|
||||||
|ui| {
|
.inner_margin(egui::Margin::symmetric(8.0, 4.0))
|
||||||
// Şimdi dikeyde ortalayarak soldan sağa diziyoruz
|
.show(ui, |ui| {
|
||||||
ui.with_layout(egui::Layout::left_to_right(egui::Align::Center), |ui| {
|
ui.horizontal(|ui| {
|
||||||
let rescue_available = detect_existing_linux();
|
let rescue_available = detect_existing_linux();
|
||||||
if rescue_available {
|
if rescue_available {
|
||||||
if theme::secondary_button(ui, &t!("rescue_button")).clicked() {
|
if theme::light_gray_btn(ui, &t!("rescue_button")).clicked() {
|
||||||
state.rescue_mode = true;
|
state.rescue_mode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if theme::secondary_button(ui, &t!("recheck")).clicked() {
|
if theme::light_gray_btn(ui, &t!("recheck")).clicked() {
|
||||||
self.checked = false;
|
self.checked = false;
|
||||||
self.on_enter(state);
|
self.on_enter(state);
|
||||||
}
|
}
|
||||||
@@ -494,8 +494,7 @@ impl InstallerStep for WelcomeStep {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
use eframe::egui::{self, Color32, FontId, Rounding, Stroke, Vec2};
|
||||||
|
|
||||||
|
fn lerp_color(a: Color32, b: Color32, t: f32) -> Color32 {
|
||||||
|
Color32::from_rgba_premultiplied(
|
||||||
|
(a.r() as f32 + (b.r() as f32 - a.r() as f32) * t) as u8,
|
||||||
|
(a.g() as f32 + (b.g() as f32 - a.g() as f32) * t) as u8,
|
||||||
|
(a.b() as f32 + (b.b() as f32 - a.b() as f32) * t) as u8,
|
||||||
|
(a.a() as f32 + (b.a() as f32 - a.a() as f32) * t) as u8,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gradient_button(ui: &mut egui::Ui, text: &str, top_color: Color32, bottom_color: Color32, text_color: Color32, hover_top: Color32, hover_bottom: Color32, border_color: Color32) -> egui::Response {
|
||||||
|
let rounding = Rounding::same(6.0);
|
||||||
|
let min_size = Vec2::new(100.0, 32.0);
|
||||||
|
let padding = Vec2::new(12.0, 6.0);
|
||||||
|
|
||||||
|
let font_id = ui.style().text_styles.get(&egui::TextStyle::Button)
|
||||||
|
.cloned().unwrap_or(FontId::proportional(14.0));
|
||||||
|
let galley = ui.painter().layout_no_wrap(
|
||||||
|
text.to_string(),
|
||||||
|
font_id,
|
||||||
|
text_color,
|
||||||
|
);
|
||||||
|
|
||||||
|
let size = Vec2::new(
|
||||||
|
min_size.x.max(galley.size().x + 2.0 * padding.x),
|
||||||
|
min_size.y.max(galley.size().y + 2.0 * padding.y),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (rect, response) = ui.allocate_exact_size(size, egui::Sense::click());
|
||||||
|
|
||||||
|
let n_strips = 16;
|
||||||
|
for i in 0..n_strips {
|
||||||
|
let t = i as f32 / n_strips as f32;
|
||||||
|
let t2 = (i + 1) as f32 / n_strips as f32;
|
||||||
|
let c = lerp_color(top_color, bottom_color, (t + t2) * 0.5);
|
||||||
|
let y0 = rect.top() + rect.height() * t;
|
||||||
|
let y1 = rect.top() + rect.height() * t2;
|
||||||
|
let strip_rect = egui::Rect::from_min_max(
|
||||||
|
egui::pos2(rect.left(), y0),
|
||||||
|
egui::pos2(rect.right(), y1),
|
||||||
|
);
|
||||||
|
ui.painter().rect(strip_rect, Rounding::ZERO, c, Stroke::NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.hovered() {
|
||||||
|
for i in 0..n_strips {
|
||||||
|
let t = i as f32 / n_strips as f32;
|
||||||
|
let t2 = (i + 1) as f32 / n_strips as f32;
|
||||||
|
let c = lerp_color(hover_top, hover_bottom, (t + t2) * 0.5);
|
||||||
|
let y0 = rect.top() + rect.height() * t;
|
||||||
|
let y1 = rect.top() + rect.height() * t2;
|
||||||
|
let strip_rect = egui::Rect::from_min_max(
|
||||||
|
egui::pos2(rect.left(), y0),
|
||||||
|
egui::pos2(rect.right(), y1),
|
||||||
|
);
|
||||||
|
ui.painter().rect(strip_rect, Rounding::ZERO, c, Stroke::NONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.painter().rect(rect, rounding, Color32::TRANSPARENT, Stroke::new(1.0, border_color));
|
||||||
|
|
||||||
|
ui.painter().galley(
|
||||||
|
egui::pos2(rect.center().x - galley.size().x / 2.0, rect.center().y - galley.size().y / 2.0),
|
||||||
|
galley,
|
||||||
|
text_color,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(cursor) = ui.visuals().interact_cursor {
|
||||||
|
if response.hovered() {
|
||||||
|
ui.ctx().set_cursor_icon(cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn primary_button(ui: &mut egui::Ui, text: &str) -> egui::Response {
|
||||||
|
gradient_button(ui, text,
|
||||||
|
Color32::from_rgb(50, 130, 255),
|
||||||
|
Color32::from_rgb(13, 110, 253),
|
||||||
|
Color32::WHITE,
|
||||||
|
Color32::from_rgb(70, 150, 255),
|
||||||
|
Color32::from_rgb(30, 130, 255),
|
||||||
|
Color32::from_rgb(13, 110, 253))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn secondary_button(ui: &mut egui::Ui, text: &str) -> egui::Response {
|
||||||
|
gradient_button(ui, text,
|
||||||
|
Color32::from_rgb(130, 140, 150),
|
||||||
|
Color32::from_rgb(100, 110, 120),
|
||||||
|
Color32::from_rgb(158, 158, 175),
|
||||||
|
Color32::from_rgb(150, 160, 170),
|
||||||
|
Color32::from_rgb(120, 130, 140),
|
||||||
|
Color32::from_rgb(100, 110, 120))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn danger_button(ui: &mut egui::Ui, text: &str) -> egui::Response {
|
||||||
|
gradient_button(ui, text,
|
||||||
|
Color32::from_rgb(240, 83, 99),
|
||||||
|
Color32::from_rgb(200, 40, 60),
|
||||||
|
Color32::WHITE,
|
||||||
|
Color32::from_rgb(255, 100, 120),
|
||||||
|
Color32::from_rgb(220, 60, 80),
|
||||||
|
Color32::from_rgb(200, 40, 60))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn white_grd_btn(ui: &mut egui::Ui, text: &str) -> egui::Response {
|
||||||
|
gradient_button(ui, text,
|
||||||
|
Color32::from_rgb(255, 255, 255),
|
||||||
|
Color32::from_rgb(246, 246, 246),
|
||||||
|
Color32::from_rgb(102, 102, 102),
|
||||||
|
Color32::from_rgb(246, 246, 246),
|
||||||
|
Color32::from_rgb(255, 255, 255),
|
||||||
|
Color32::from_rgb(177, 177, 177))
|
||||||
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn btn_dark_blue(ui: &mut egui::Ui, text: &str) -> egui::Response {
|
||||||
|
gradient_button(ui, text,
|
||||||
|
Color32::from_rgb(99, 184, 238),
|
||||||
|
Color32::from_rgb(70, 140, 207),
|
||||||
|
Color32::WHITE,
|
||||||
|
Color32::from_rgb(70, 140, 207),
|
||||||
|
Color32::from_rgb(99, 184, 238),
|
||||||
|
Color32::from_rgb(56, 102, 163))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn light_gray_btn(ui: &mut egui::Ui, text: &str) -> egui::Response {
|
||||||
|
gradient_button(ui, text,
|
||||||
|
Color32::from_rgb(249, 249, 249), // üst: #f9f9f9
|
||||||
|
Color32::from_rgb(233, 233, 233), // alt: #e9e9e9
|
||||||
|
Color32::from_rgb(102, 102, 102), // metin: #666666
|
||||||
|
Color32::from_rgb(233, 233, 233), // hover üst (ters)
|
||||||
|
Color32::from_rgb(249, 249, 249), // hover alt (ters)
|
||||||
|
Color32::from_rgb(227, 195, 227)) // border: #e3c7e3
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
pub mod theme;
|
pub mod theme;
|
||||||
|
pub mod buttons;
|
||||||
pub mod slideshow;
|
pub mod slideshow;
|
||||||
pub mod error_screen;
|
pub mod error_screen;
|
||||||
|
|
||||||
|
|||||||
+5
-85
@@ -15,6 +15,8 @@ use std::sync::atomic::{AtomicU32, Ordering};
|
|||||||
static BG_DARK: AtomicU32 = AtomicU32::new(0x121214);
|
static BG_DARK: AtomicU32 = AtomicU32::new(0x121214);
|
||||||
static BG_PANEL: AtomicU32 = AtomicU32::new(0x1A1A1E);
|
static BG_PANEL: AtomicU32 = AtomicU32::new(0x1A1A1E);
|
||||||
static BG_WIDGET: AtomicU32 = AtomicU32::new(0x242428);
|
static BG_WIDGET: AtomicU32 = AtomicU32::new(0x242428);
|
||||||
|
|
||||||
|
|
||||||
static BORDER: AtomicU32 = AtomicU32::new(0x323238);
|
static BORDER: AtomicU32 = AtomicU32::new(0x323238);
|
||||||
static TEXT: AtomicU32 = AtomicU32::new(0xF3F3F5);
|
static TEXT: AtomicU32 = AtomicU32::new(0xF3F3F5);
|
||||||
static TEXT_DIM: AtomicU32 = AtomicU32::new(0x9E9EAF);
|
static TEXT_DIM: AtomicU32 = AtomicU32::new(0x9E9EAF);
|
||||||
@@ -284,96 +286,14 @@ fn build_style() -> egui::Style {
|
|||||||
]
|
]
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
|
style.visuals.interact_cursor = Some(egui::CursorIcon::PointingHand);
|
||||||
|
|
||||||
style
|
style
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Yardımcı widget'lar ─────────────────────────────────────────
|
// ─── Yardımcı widget'lar ─────────────────────────────────────────
|
||||||
|
|
||||||
fn lerp_color(a: Color32, b: Color32, t: f32) -> Color32 {
|
pub use super::buttons::*;
|
||||||
Color32::from_rgba_premultiplied(
|
|
||||||
(a.r() as f32 + (b.r() as f32 - a.r() as f32) * t) as u8,
|
|
||||||
(a.g() as f32 + (b.g() as f32 - a.g() as f32) * t) as u8,
|
|
||||||
(a.b() as f32 + (b.b() as f32 - a.b() as f32) * t) as u8,
|
|
||||||
(a.a() as f32 + (b.a() as f32 - a.a() as f32) * t) as u8,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gradient_button(ui: &mut egui::Ui, text: &str, top_color: Color32, bottom_color: Color32, text_color: Color32) -> egui::Response {
|
|
||||||
let rounding = Rounding::same(6.0);
|
|
||||||
let min_size = Vec2::new(100.0, 32.0);
|
|
||||||
let padding = Vec2::new(12.0, 6.0);
|
|
||||||
|
|
||||||
let font_id = ui.style().text_styles.get(&egui::TextStyle::Button)
|
|
||||||
.cloned().unwrap_or(FontId::proportional(14.0));
|
|
||||||
let galley = ui.painter().layout_no_wrap(
|
|
||||||
text.to_string(),
|
|
||||||
font_id,
|
|
||||||
text_color,
|
|
||||||
);
|
|
||||||
|
|
||||||
let size = Vec2::new(
|
|
||||||
min_size.x.max(galley.size().x + 2.0 * padding.x),
|
|
||||||
min_size.y.max(galley.size().y + 2.0 * padding.y),
|
|
||||||
);
|
|
||||||
|
|
||||||
let (rect, response) = ui.allocate_exact_size(size, egui::Sense::click());
|
|
||||||
|
|
||||||
// Gradient arka plan (16 yatay şerit)
|
|
||||||
let n_strips = 16;
|
|
||||||
for i in 0..n_strips {
|
|
||||||
let t = i as f32 / n_strips as f32;
|
|
||||||
let t2 = (i + 1) as f32 / n_strips as f32;
|
|
||||||
let c = lerp_color(top_color, bottom_color, (t + t2) * 0.5);
|
|
||||||
let y0 = rect.top() + rect.height() * t;
|
|
||||||
let y1 = rect.top() + rect.height() * t2;
|
|
||||||
let strip_rect = egui::Rect::from_min_max(
|
|
||||||
egui::pos2(rect.left(), y0),
|
|
||||||
egui::pos2(rect.right(), y1),
|
|
||||||
);
|
|
||||||
ui.painter().rect(strip_rect, Rounding::ZERO, c, Stroke::NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Yuvarlak köşe efekti için border
|
|
||||||
ui.painter().rect(rect, rounding, Color32::TRANSPARENT, Stroke::new(1.0, bottom_color));
|
|
||||||
|
|
||||||
// Hover efekti
|
|
||||||
if response.hovered() {
|
|
||||||
ui.painter().rect(rect, rounding, Color32::WHITE.linear_multiply(0.10), Stroke::NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Metin
|
|
||||||
ui.painter().galley(
|
|
||||||
egui::pos2(rect.center().x - galley.size().x / 2.0, rect.center().y - galley.size().y / 2.0),
|
|
||||||
galley,
|
|
||||||
text_color,
|
|
||||||
);
|
|
||||||
|
|
||||||
response
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ana eylem butonu (mavi gradient).
|
|
||||||
pub fn primary_button(ui: &mut egui::Ui, text: &str) -> egui::Response {
|
|
||||||
gradient_button(ui, text,
|
|
||||||
Color32::from_rgb(50, 130, 255), // üst: açık mavi
|
|
||||||
Color32::from_rgb(13, 110, 253), // alt: koyu mavi
|
|
||||||
Color32::WHITE)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// İkincil buton (gri gradient).
|
|
||||||
pub fn secondary_button(ui: &mut egui::Ui, text: &str) -> egui::Response {
|
|
||||||
gradient_button(ui, text,
|
|
||||||
Color32::from_rgb(130, 140, 150), // üst: açık gri
|
|
||||||
Color32::from_rgb(100, 110, 120), // alt: koyu gri
|
|
||||||
c_text_dim())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// İptal/Danger butonu (kırmızı gradient).
|
|
||||||
pub fn danger_button(ui: &mut egui::Ui, text: &str) -> egui::Response {
|
|
||||||
gradient_button(ui, text,
|
|
||||||
Color32::from_rgb(240, 83, 99), // üst: açık kırmızı
|
|
||||||
Color32::from_rgb(200, 40, 60), // alt: koyu kırmızı
|
|
||||||
Color32::WHITE)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Bölüm başlığı — büyük, açık renkli, alt çizgisiz.
|
/// Bölüm başlığı — büyük, açık renkli, alt çizgisiz.
|
||||||
pub fn section_heading(ui: &mut egui::Ui, text: &str) {
|
pub fn section_heading(ui: &mut egui::Ui, text: &str) {
|
||||||
|
|||||||
Reference in New Issue
Block a user