Skip to content

Commit 09c43a9

Browse files
committed
Handle colours via GObject properties and draw them using snapshot
1 parent bfe98e8 commit 09c43a9

9 files changed

Lines changed: 226 additions & 186 deletions

File tree

kcshot-data/src/colour.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ use std::borrow::Cow;
22

33
use gtk4::{
44
gdk::RGBA,
5-
glib::{self, prelude::*},
5+
glib::{self, ValueDelegate, prelude::*},
66
};
77

8-
#[derive(Clone, Copy, Debug)]
8+
#[derive(Clone, Copy, Debug, ValueDelegate)]
9+
#[value_delegate(from = u32)]
910
pub struct Colour {
1011
pub red: u8,
1112
pub green: u8,
@@ -84,6 +85,35 @@ impl From<Colour> for glib::Variant {
8485
}
8586
}
8687

88+
impl From<Colour> for RGBA {
89+
fn from(value: Colour) -> Self {
90+
RGBA::new(
91+
value.red as f32 / 255.0,
92+
value.green as f32 / 255.0,
93+
value.blue as f32 / 255.0,
94+
value.alpha as f32 / 255.0,
95+
)
96+
}
97+
}
98+
99+
impl From<u32> for Colour {
100+
fn from(value: u32) -> Self {
101+
Colour::deserialise_from_u32(value)
102+
}
103+
}
104+
105+
impl From<Colour> for u32 {
106+
fn from(value: Colour) -> Self {
107+
value.serialise_to_u32()
108+
}
109+
}
110+
111+
impl From<&Colour> for u32 {
112+
fn from(value: &Colour) -> Self {
113+
value.serialise_to_u32()
114+
}
115+
}
116+
87117
#[derive(Debug, Copy, Clone)]
88118
pub struct Hsv {
89119
pub h: f32,

src/editor.rs

Lines changed: 2 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use gtk4::{gio, glib, prelude::*, subclass::prelude::ObjectSubclassIsExt};
2-
use kcshot_data::{colour::Colour, settings::Settings};
2+
use kcshot_data::colour::Colour;
33

44
use self::operations::Tool;
55
use crate::kcshot::KCShot;
66

7+
pub mod colourbutton;
78
mod colourchooser;
89
mod colourchooserdialog;
910
mod colourwheel;
@@ -27,14 +28,6 @@ impl EditorWindow {
2728
.property("editing-starts-with-cropping", editing_starts_with_cropping)
2829
.build();
2930

30-
let settings = Settings::open();
31-
32-
let restored_primary_colour = settings.last_used_primary_colour();
33-
let restored_secondary_colour = settings.last_used_secondary_colour();
34-
35-
editor.set_primary_colour(restored_primary_colour);
36-
editor.set_secondary_colour(restored_secondary_colour);
37-
3831
editor
3932
}
4033

@@ -65,53 +58,6 @@ impl EditorWindow {
6558
});
6659
}
6760

68-
/// Returns the primary colour of the editor
69-
///
70-
/// The primary colour is the one used for filling in shapes
71-
#[track_caller]
72-
fn primary_colour(&self) -> Colour {
73-
self.imp()
74-
.with_image("get primary_colour", |image| {
75-
image.operation_stack.primary_colour
76-
})
77-
.unwrap()
78-
}
79-
80-
fn set_primary_colour(&self, colour: Colour) {
81-
self.imp().with_image_mut("set_primary_colour", |image| {
82-
image.operation_stack.primary_colour = colour;
83-
});
84-
85-
let settings = Settings::open();
86-
if let Err(why) = settings.try_set_last_used_primary_colour(colour) {
87-
tracing::warn!("Failed to update `last-used-primary-colour` setting value: {why}");
88-
}
89-
}
90-
91-
/// Returns the secondary colour of the editor
92-
///
93-
/// The secondary colour is used for lines, the text colour in case of bubbles and as the
94-
/// default colour for text and the pencil
95-
#[track_caller]
96-
fn secondary_colour(&self) -> Colour {
97-
self.imp()
98-
.with_image("get secondary_colour", |image| {
99-
image.operation_stack.secondary_colour
100-
})
101-
.unwrap()
102-
}
103-
104-
fn set_secondary_colour(&self, colour: Colour) {
105-
self.imp().with_image_mut("set_secondary_colour", |image| {
106-
image.operation_stack.secondary_colour = colour;
107-
});
108-
109-
let settings = Settings::open();
110-
if let Err(why) = settings.try_set_last_used_secondary_colour(colour) {
111-
tracing::warn!("Failed to update `last-used-secondary-colour` setting value: {why}");
112-
}
113-
}
114-
11561
fn set_line_width(&self, line_width: f64) {
11662
self.imp().with_image_mut("set_line_width", |image| {
11763
image.operation_stack.line_width = line_width;

src/editor/colourbutton.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
use gtk4::glib;
2+
3+
glib::wrapper! {
4+
pub struct ColourButton(ObjectSubclass<underlying::ColourButton>)
5+
@extends gtk4::Widget, gtk4::Button,
6+
@implements gtk4::Accessible, gtk4::Buildable, gtk4::ConstraintTarget, gtk4::Actionable;
7+
}
8+
9+
mod underlying {
10+
use std::cell::Cell;
11+
12+
use gtk4::{
13+
gdk::RGBA,
14+
glib::{self, Properties},
15+
graphene::Rect,
16+
prelude::*,
17+
subclass::prelude::*,
18+
};
19+
use kcshot_data::colour::Colour;
20+
21+
use crate::ext::DisposeExt;
22+
23+
#[derive(Debug, Properties)]
24+
#[properties(wrapper_type = super::ColourButton)]
25+
pub struct ColourButton {
26+
#[property(get, set)]
27+
colour: Cell<Colour>,
28+
}
29+
30+
impl Default for ColourButton {
31+
fn default() -> Self {
32+
Self {
33+
colour: Cell::new(Colour {
34+
red: 0,
35+
green: 0,
36+
blue: 0,
37+
alpha: 0,
38+
}),
39+
}
40+
}
41+
}
42+
43+
#[glib::object_subclass]
44+
impl ObjectSubclass for ColourButton {
45+
const NAME: &'static str = "KCShotColourButton";
46+
type Type = super::ColourButton;
47+
type ParentType = gtk4::Button;
48+
}
49+
50+
#[glib::derived_properties]
51+
impl ObjectImpl for ColourButton {
52+
fn constructed(&self) {
53+
self.obj().set_halign(gtk4::Align::Center);
54+
self.obj().set_valign(gtk4::Align::Center);
55+
}
56+
57+
fn dispose(&self) {
58+
self.obj().dispose_children();
59+
}
60+
}
61+
62+
impl WidgetImpl for ColourButton {
63+
fn snapshot(&self, snapshot: &gtk4::Snapshot) {
64+
let colour = self.colour.get();
65+
66+
let w = self.obj().width() as f32;
67+
let h = self.obj().height() as f32;
68+
69+
if colour.alpha != 0 {
70+
snapshot.append_color(&colour.into(), &Rect::new(0.0, 0.0, w, h));
71+
} else {
72+
let black = RGBA::new(0.0, 0.0, 0.0, 1.0);
73+
let magenta = RGBA::new(1.0, 0.0, 0.8, 1.0);
74+
snapshot.append_color(&black, &Rect::new(0.0, 0.0, w / 2.0, h / 2.0));
75+
snapshot.append_color(&magenta, &Rect::new(w / 2.0, 0.0, w / 2.0, h / 2.0));
76+
snapshot.append_color(&magenta, &Rect::new(0.0, h / 2.0, w / 2.0, h / 2.0));
77+
snapshot.append_color(&black, &Rect::new(w / 2.0, h / 2.0, w / 2.0, h / 2.0));
78+
}
79+
}
80+
}
81+
82+
impl ButtonImpl for ColourButton {}
83+
}

src/editor/colourchooserdialog.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ glib::wrapper! {
1111
}
1212

1313
impl ColourChooserDialog {
14-
pub fn new(editor: &EditorWindow) -> Self {
15-
glib::Object::builder().property("editor", editor).build()
14+
pub fn new(editor: &EditorWindow, initial_colour: Colour) -> Self {
15+
glib::Object::builder()
16+
.property("editor", editor)
17+
.property("initial-colour", initial_colour)
18+
.build()
1619
}
1720

1821
pub async fn colour(&self) -> Colour {
@@ -22,7 +25,7 @@ impl ColourChooserDialog {
2225
}
2326

2427
mod underlying {
25-
use std::cell::RefCell;
28+
use std::{cell::RefCell, marker::PhantomData};
2629

2730
use gtk4::{
2831
CompositeTemplate,
@@ -44,6 +47,8 @@ mod underlying {
4447
pub struct ColourChooserDialog {
4548
#[property(get, set)]
4649
editor: WeakRef<EditorWindow>,
50+
#[property(name = "initial-colour", set = Self::set_initial_colour, construct_only)]
51+
colour: PhantomData<Colour>,
4752

4853
#[template_child]
4954
colour_chooser: TemplateChild<ColourChooserWidget>,
@@ -58,6 +63,7 @@ mod underlying {
5863

5964
Self {
6065
editor: Default::default(),
66+
colour: PhantomData,
6167
colour_chooser: Default::default(),
6268
colour_rx: RefCell::new(Some(colour_rx)),
6369
colour_tx: RefCell::new(Some(colour_tx)),
@@ -93,6 +99,12 @@ mod underlying {
9399
impl WidgetImpl for ColourChooserDialog {}
94100
impl WindowImpl for ColourChooserDialog {}
95101

102+
impl ColourChooserDialog {
103+
fn set_initial_colour(&self, colour: Colour) {
104+
self.colour_chooser.set_colour(colour);
105+
}
106+
}
107+
96108
#[gtk4::template_callbacks]
97109
impl ColourChooserDialog {
98110
#[template_callback]

src/editor/operations/stack.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ impl OperationStack {
5151
windows: Vec<Window>,
5252
screen_dimensions: Rectangle,
5353
editing_started_with_cropping: bool,
54+
primary_colour: Colour,
55+
secondary_colour: Colour,
5456
) -> Self {
5557
Self {
5658
operations: vec![],
@@ -62,18 +64,8 @@ impl OperationStack {
6264
},
6365
current_operation: None,
6466
autoincrement_bubble_number: 1,
65-
primary_colour: Colour {
66-
red: 127,
67-
green: 0,
68-
blue: 127,
69-
alpha: 255,
70-
},
71-
secondary_colour: Colour {
72-
red: 0,
73-
green: 127,
74-
blue: 127,
75-
alpha: 255,
76-
},
67+
primary_colour,
68+
secondary_colour,
7769
windows,
7870
current_window: None,
7971
is_in_crop_drag: false,

src/editor/textdialog/text_input.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ mod underlying {
160160
async fn on_colour_button_clicked(&self, _: &gtk4::Button) {
161161
let editor = self.obj().editor().unwrap();
162162

163-
let dialog = ColourChooserDialog::new(&editor);
163+
let dialog = ColourChooserDialog::new(&editor, editor.secondary_colour());
164164
dialog.set_transient_for(self.parent_dialog.upgrade().as_ref());
165165
dialog.show();
166166
editor.set_secondary_colour(dialog.colour().await);

src/editor/toolbar.blp

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Gtk 4.0;
22

3-
template $KCShotToolbarWidget : Gtk.Widget {
3+
template $KCShotToolbarWidget: Gtk.Widget {
44
$KCShotToolButton group_source {
55
editor: bind template.editor;
66
}
@@ -79,30 +79,18 @@ template $KCShotToolbarWidget : Gtk.Widget {
7979
editor: bind template.editor;
8080
}
8181

82-
Gtk.Button primary {
82+
$KCShotColourButton primary {
8383
clicked => $on_primary_colour_clicked() swapped;
84-
8584
visible: false;
8685
tooltip-text: "Set primary colour";
87-
88-
Gtk.DrawingArea primary_button_drawing_area {
89-
accessible-role: img;
90-
width-request: 20;
91-
height-request: 20;
92-
}
86+
colour: bind (template.editor as <$KCShotEditorWindow>).primary-colour;
9387
}
9488

95-
Gtk.Button secondary {
89+
$KCShotColourButton secondary {
9690
clicked => $on_secondary_colour_clicked() swapped;
97-
9891
visible: false;
9992
tooltip-text: "Set secondary colour";
100-
101-
Gtk.DrawingArea secondary_button_drawing_area {
102-
accessible-role: img;
103-
width-request: 20;
104-
height-request: 20;
105-
}
93+
colour: bind (template.editor as <$KCShotEditorWindow>).secondary-colour;
10694
}
10795

10896
Gtk.SpinButton line_width_spinner {
@@ -116,6 +104,7 @@ template $KCShotToolbarWidget : Gtk.Widget {
116104
page-increment: 1.0;
117105
page-size: 1.0;
118106
};
107+
119108
climb-rate: 0.5;
120109
digits: 1;
121110
numeric: true;

0 commit comments

Comments
 (0)