ryanmcgrath / cacao

Rust bindings for AppKit (macOS) and UIKit (iOS/tvOS). Experimental, but working!
MIT License
1.79k stars 65 forks source link

Add trait to get layout anchors for a view #108

Open Isaac-Leonard opened 9 months ago

Isaac-Leonard commented 9 months ago

Add trait to get layout anchors for a view, implement it on common components and add some functions that make use of it to simplify creating layout constraints

Isaac-Leonard commented 9 months ago

I've put all the implementations and functions that make use of it all in one file for now, I think they'd probably be better off in each components file but this is probably easier to see what I'm intending for now. I'm wondering too if there might be a way to add a default for each method that gets the view id and creates the anchors from that like how they are constructed initially each component.

ryanmcgrath commented 9 months ago

So I think this is a gray area for me... it's definitely getting outside of what AppKit/UIKit offer by default, but cacao's taken the opinionated position before so I could be convinced to support this.

I would say a few changes come to mind tho:

pub struct ColumnLayout {
    pub spacing: usize // psuedocode, do whatever type here
}

pub fn column<I, C>(parent: &Layout, layout: ColumnLayout, children: I)
where
    I:  IntoIterator<Item = &C>,
    C: Layout,
{
    // Manage adding views, setting spacing, etc
}

This feels more declarative in nature to me, e.g I could then write:

impl MyGenericView {
    pub fn build(&self) {
        column(&self.view_handle, ColumnLayout {
            spacing: 8
        }, [
            &self.child_view_1,
            &self.child_view_2,
            // etc
        ]);
    }
}

The above is all pseudocode and not tested but hopefully showcases the idea.

fill_safe_area I'm less enthused about and might want that in a contrib or helpers module, but I'll muse on that one for a bit.

Isaac-Leonard commented 9 months ago

I'd like to move it into the Layout trait but currently the Layout trait is not object safe and so doesn't work well as a dyn generic parameter. HasLayout is intended to be used as a dyn parameter so you can pass a list of random components to top_to_bottom / columns and other similar functions. I might make another PR soon to make Layout object safe but it will require some pretty large api changes with new traits but most actual functions should remain the exact same.

On 12 Sep 2023, at 03:17, Ryan McGrath @.***> wrote:



So I think this is a gray area for me... it's definitely getting outside of what AppKit/UIKit offer by default, but cacao's taken the opinionated position before so I could be convinced to support this.

I would say a few changes come to mind tho:

pub struct ColumnLayout { pub spacing: usize // psuedocode, do whatever type here }

pub fn column<I, C>(parent: &Layout, layout: ColumnLayout, children: I) where I: IntoIterator, C: Layout, { // Manage adding views, setting spacing, etc }

This feels more declarative in nature to me, e.g I could then write:

impl MyGenericView { pub fn build(&self) { column(&self.view_handle, ColumnLayout { spacing: 8 }, [ &self.child_view_1, &self.child_view_2, // etc ]); } }

The above is all pseudocode and not tested but hopefully showcases the idea.

fill_safe_area I'm less enthused about and might want that in a contrib or helpers module, but I'll muse on that one for a bit.

— Reply to this email directly, view it on GitHubhttps://github.com/ryanmcgrath/cacao/pull/108#issuecomment-1714285401, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AFMGHTZEVCHGRLX4NRBY5ULXZ5BRLANCNFSM6AAAAAA4R5Q52A. You are receiving this because you authored the thread.Message ID: @.***>

ryanmcgrath commented 9 months ago

Hmm, interesting.

FYI this might be a thing you'll need to rebase since we merged the objc2 PR recently. Apologies for the hassle but it should overall be better for the library going forward. :(

Isaac-Leonard commented 9 months ago

Hey, not sure if its just me but I can't seem to get a bunch of warnings and errors when running cargo +nightly clippy and warnings with cargo check and build: Here's the start of the clippy output: warning: error reading Clippy's configuration file: deprecated field cyclomatic-complexity-threshold. Please use cognitive-complexity-threshold instead --> /Users/isaac/Programming/rust/cacao-fork/clippy.toml:1:1 | 1 | cyclomatic-complexity-threshold = 30 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: cacao (build script) generated 1 warning Compiling cacao v0.4.0-beta2 (/Users/isaac/Programming/rust/cacao-fork) warning: unnecessary parentheses around match arm expression --> src/appkit/app/enums.rs:122:49 122 PresentationOption::AutoHideDock => (1 << 0), ^ ^
= note: `#[warn(unused_parens)]` on by default
help: remove these parentheses 122 - PresentationOption::AutoHideDock => (1 << 0), 122 + PresentationOption::AutoHideDock => 1 << 0,

Am I doing something wrong o might there be an issue with my set up?

ryanmcgrath commented 9 months ago

Offhand I dunno - but if that's deprecated the replacement does the same thing, we can certainly just swap the key out.

Isaac-Leonard commented 9 months ago

There's 51 warnings with cargo check and over 100 with clippy though, is just an issue on my system or is it with the repo? I'm happy to go through and fix them if the latter

Isaac-Leonard commented 9 months ago

Okay, so I think I've implemented everything now that's needed to use Layout as a dye trait. I had to create a new trait for the set_frame method as I didn't really know how that could work without generics, I updated the frame example with the change. I had to change how ObjcAccess works too as the get_from_backing_obj method couldn't work without the generic return type. Instead I've made a new method that just returns the reference to the inner Id that callers can then just dereference and do what they were doing before. I'm not sure if I've be putting Shared or Owned for the ownership generic of Id though, for now I've just got Owned. I've also not had any experience with objective C so I'm not sure if I'm creating layout anchors correctly,. I'm creating them the same way its done in the constructor for view but not sure if this creates non-allowed duplicates or anything. I believe all of these changes may allow me to implement a more reactive framework on top of cacao too now.

ryanmcgrath commented 9 months ago

Hmm… I’ll try to find time to take a look at this over the weekend. This wound up being more invasive than I thought (which isn’t your fault, I think I sent you down that path) so want to regroup and figure out the best option. It may end up being your original take, not sure yet.

And yeah ownership of the ObjC object is something I want to try and hide from this all, since it can get thorny quickly - it’s what led me to the handler approach originally.

Def appreciate the efforts tho and we’ll figure out the best way to do this!

On Fri, Sep 15, 2023 at 20:51, Isaac-Leonard @.***(mailto:On Fri, Sep 15, 2023 at 20:51, Isaac-Leonard < wrote:

Okay, so I think I've implemented everything now that's needed to use Layout as a dye trait. I had to create a new trait for the set_frame method as I didn't really know how that could work without generics, I updated the frame example with the change. I had to change how ObjcAccess works too as the get_from_backing_obj method couldn't work without the generic return type. Instead I've made a new method that just returns the reference to the inner Id that callers can then just dereference and do what they were doing before. I'm not sure if I've be putting Shared or Owned for the ownership generic of Id though, for now I've just got Owned. I've also not had any experience with objective C so I'm not sure if I'm creating layout anchors correctly,. I'm creating them the same way its done in the constructor for view but not sure if this creates non-allowed duplicates or anything. I believe all of these changes may allow me to implement a more reactive framework on top of cacao too now.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

Isaac-Leonard commented 9 months ago

No no, stuff I've been working on in my own project was also leading down this route, either way I was probably going to fork and do something similar.

Isaac-Leonard commented 9 months ago

I've started working on a framework of sorts based on the changes I've made: https://github.com/Isaac-Leonard/cacao_framework Currently have a simple counter button working though you need to pass the click id through to it from the top of the app. I'm going to try make this work with more native components, write a macro to simplify specifying options and let it render nested components