Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ImageButton widget variant #195

Merged
merged 4 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions examples/image-button/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "cosmic-image-button"
version = "0.1.0"
edition = "2021"

[dependencies]
tracing = "0.1.37"
tracing-subscriber = "0.3.17"

[dependencies.libcosmic]
path = "../../"
default-features = false
features = ["debug", "wayland", "tokio"]
105 changes: 105 additions & 0 deletions examples/image-button/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright 2023 System76 <[email protected]>
// SPDX-License-Identifier: MPL-2.0

//! Application API example

use cosmic::app::{Command, Core, Settings};
use cosmic::{executor, iced, ApplicationExt, Element};

/// Runs application with these settings
#[rustfmt::skip]
fn main() -> Result<(), Box<dyn std::error::Error>> {
cosmic::app::run::<App>(Settings::default(), ())?;

Ok(())
}

/// Messages that are used specifically by our [`App`].
#[derive(Clone, Debug)]
pub enum Message {
Clicked,
}

/// The [`App`] stores application-specific state.
pub struct App {
core: Core,
}

/// Implement [`cosmic::Application`] to integrate with COSMIC.
impl cosmic::Application for App {
/// Default async executor to use with the app.
type Executor = executor::Default;

/// Argument received [`cosmic::Application::new`].
type Flags = ();

/// Message type specific to our [`App`].
type Message = Message;

/// The unique application ID to supply to the window manager.
const APP_ID: &'static str = "org.cosmic.AppDemo";

fn core(&self) -> &Core {
&self.core
}

fn core_mut(&mut self) -> &mut Core {
&mut self.core
}

/// Creates the application, and optionally emits command on initialize.
fn init(core: Core, _input: Self::Flags) -> (Self, Command<Self::Message>) {
let mut app = App { core };

let command = app.update_title();

(app, command)
}

/// Handle application events here.
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
if let Message::Clicked = message {
eprintln!("clicked");
}

Command::none()
}

/// Creates a view after each update.
fn view(&self) -> Element<Self::Message> {
let content = cosmic::widget::column()
.spacing(12)
.push(
cosmic::widget::button::image("/usr/share/backgrounds/pop/kait-herzog-8242.jpg")
.width(600.0)
.selected(true)
.on_press(Message::Clicked),
)
.push(
cosmic::widget::button::image(
"/usr/share/backgrounds/pop/kate-hazen-unleash-your-robot-blue.png",
)
.width(600.0)
.selected(true)
.on_press(Message::Clicked),
);

let centered = cosmic::widget::container(content)
.width(iced::Length::Fill)
.height(iced::Length::Shrink)
.align_x(iced::alignment::Horizontal::Center)
.align_y(iced::alignment::Vertical::Center);

Element::from(centered)
}
}

impl App
where
Self: cosmic::Application,
{
fn update_title(&mut self) -> Command<Message> {
self.set_header_title(String::from("Image Button Demo"));
self.set_window_title(String::from("Image Button Demo"))
}
}
17 changes: 17 additions & 0 deletions src/theme/style/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub enum Button {
Link,
Icon,
IconVertical,
Image,
#[default]
Standard,
Suggested,
Expand Down Expand Up @@ -80,6 +81,22 @@ pub fn appearance(
}
}

Button::Image => {
appearance.background = Some(Background::Color(cosmic.bg_color().into()));
appearance.text_color = Some(cosmic.accent.base.into());
appearance.icon_color = Some(cosmic.accent.base.into());

corner_radii = &cosmic.corner_radii.radius_s;
appearance.border_radius = (*corner_radii).into();

if focused {
appearance.border_width = 3.0;
appearance.border_color = cosmic.accent.base.into();
}

return appearance;
}

Button::Link => {
appearance.background = None;
appearance.icon_color = Some(cosmic.accent.base.into());
Expand Down
72 changes: 72 additions & 0 deletions src/widget/button/image.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2023 System76 <[email protected]>
// SPDX-License-Identifier: MPL-2.0

use super::{Builder, Style};
use crate::{
widget::{self, image::Handle},
Element,
};
use apply::Apply;
use iced_core::{font::Weight, widget::Id, Length, Padding};
use std::borrow::Cow;

pub type Button<'a, Message> = Builder<'a, Message, Image<'a, Handle>>;

pub fn image<'a, Message>(handle: impl Into<Handle> + 'a) -> Button<'a, Message> {
Button::new(Image {
image: widget::image(handle).border_radius([9.0; 4]),
selected: false,
})
}

pub struct Image<'a, Handle> {
image: widget::Image<'a, Handle>,
selected: bool,
}

impl<'a, Message> Button<'a, Message> {
pub fn new(variant: Image<'a, Handle>) -> Self {
Self {
id: Id::unique(),
label: Cow::Borrowed(""),
tooltip: Cow::Borrowed(""),
on_press: None,
width: Length::Shrink,
height: Length::Shrink,
padding: Padding::from(0),
spacing: 0,
icon_size: 16,
line_height: 20,
font_size: 14,
font_weight: Weight::Normal,
style: Style::Image,
variant,
}
}

pub fn selected(mut self, selected: bool) -> Self {
self.variant.selected = selected;
self
}
}

impl<'a, Message> From<Button<'a, Message>> for Element<'a, Message>
where
Handle: Clone + std::hash::Hash,
Message: Clone + 'static,
{
fn from(builder: Button<'a, Message>) -> Element<'a, Message> {
builder
.variant
.image
.width(builder.width)
.height(builder.height)
.apply(widget::button)
.selected(builder.variant.selected)
.id(builder.id)
.padding(0)
.on_press_maybe(builder.on_press)
.style(builder.style)
.into()
}
}
6 changes: 5 additions & 1 deletion src/widget/button/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ mod icon;
pub use icon::icon;
pub use icon::Button as IconButton;

mod image;
pub use image::image;
pub use image::Button as ImageButton;

mod style;
pub use style::{Appearance, StyleSheet};

Expand Down Expand Up @@ -81,7 +85,7 @@ pub struct Builder<'a, Message, Variant> {
/// Sets the preferred font weight.
font_weight: Weight,

// The preferred style of the button.
/// The preferred style of the button.
style: Style,

#[setters(skip)]
Expand Down
3 changes: 0 additions & 3 deletions src/widget/button/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ use apply::Apply;
use iced_core::{font::Weight, text::LineHeight, widget::Id, Alignment, Length, Padding};
use std::borrow::Cow;

/// A [`Button`] with the highest level of attention.
///
/// There should only be one primary button used per page.
pub type Button<'a, Message> = Builder<'a, Message, Text>;

pub fn destructive<'a, Message>(label: impl Into<Cow<'a, str>>) -> Button<'a, Message> {
Expand Down
Loading
Loading