Post

Replies

Boosts

Views

Activity

Reply to Problem with alignment guides
To utilize an alignment guide it appears that the parent container must indicate the alignment type listed in the guide. Other wise the alignment guide is not called. So I removed all of the alignments and alignment guides. Then stepped down thru the views starting with the outermost. At the outmost view and each subview I set the alignment to leading. As a result, if I set the alignment guide to be HorizontalAlignment.leading, the associated closure is run and the guide is applied. I should note that I had to insert a V Stack directly inside the Natigation Stack to get things to work, and of course set its alignment to leading. I have not yet determined how to replace the spacers with vertical alignment guides but will work on that next. Below is a view of the resutling output and the associated code. The code for sections "Group 2" and "Group 3" are essentially identical to that for "Group 1", so I did not include them. In addition, the Navigation Destination did not change so it was also not included. struct ContentView: View { var body: some View { NavigationStack { VStack (alignment: HorizontalAlignment.leading) { Text("Group1") .font(Font.custom("Arial", size: 16)) .alignmentGuide(HorizontalAlignment.leading, computeValue: { viewDimensions in return viewDimensions[HorizontalAlignment.leading] - 42 }) ZStack (alignment: Alignment(horizontal: .leading, vertical: .center)) { RoundedRectangle(cornerRadius: 10) .fill(.white) .alignmentGuide(HorizontalAlignment.leading, computeValue: { viewDimensions in return viewDimensions[HorizontalAlignment.leading] - 30 }) VStack (alignment: HorizontalAlignment.leading) { NavigationLink(value: "vooTable") { Text("Data Table") .alignmentGuide(HorizontalAlignment.leading, computeValue: { viewDimensions in return viewDimensions[HorizontalAlignment.leading] - 55 }) } .font(Font.custom("Arial", size: 14)) .buttonStyle(.link) .underline() .focusable(false) } // end vstack } // end zStack .frame(width: 200, height: 60, alignment: .leading) Spacer() .frame(width: 200, height: 25, alignment: .leading) } // end navigation destination } // end v stack } // end navigtion stack .frame(width: 750, height: 550, alignment: Alignment(horizontal: .leading, vertical: .center)) }
Topic: Programming Languages SubTopic: Swift Tags:
Sep ’23
Reply to Chart - Last (right most) x axis label not being displayed
After some additional research, it turns out that there are several preset styles for the Axis Marks. The aligned style is what I needed. I added that preset to the Axis Marks contained in .chartXAxis section of code. Problem solved. Below is a pic of the updated x axis labels and the updated code for .chartXAxis. .chartXAxis { AxisMarks(preset: .aligned, values: xAxisValues) { value in if let date = value.as(Date.self) { AxisValueLabel(horizontalSpacing: -14, verticalSpacing: 10) { VStack(alignment: .leading) { Text(ChartMonthFormatter.string(from: date)) .font(.custom("Arial", size: 14)) Text(ChartYearFormatter.string(from: date)) .font(.custom("Arial", size: 14)) } // end v stack } // end axis label } // end if statement AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1)) .foregroundStyle(Color.black) AxisTick(centered: true, length: 0, stroke: .none) } } // end chart x axis .chartXScale(domain: [xAxisValues[0], xAxisValues[12]])
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Sep ’23
Reply to Set Content View size/position upon retuning from navigation stack destination view
I updated the HostingWindowFinder*** struct (where *** is replaced with Home, Table or Chart). With this code the home view (content view) is correctly positioned and the right size. When I select a destination view (chart or table) it appears as if the origin of the home view does not change and that the window size increases to just fit the table or the chart. When I return to the Content View it goes back to the original size/position. When I step through the code, the setPosition function for the chart view for example is executed but it does not appear that the setFrame call is doing anything. I am clearly misunderstanding something. Probably something very obvious. Below is the updated HostingWindowFinderHome code. private struct HostingWindowFinderHome: NSViewRepresentable { var callback: (NSWindow) -> () func makeNSView(context: Self.Context) -> NSView { let view = BridgingViewHome() view.callback = callback return view } func updateNSView(_ nsView: NSView, context: Context) {} } private class BridgingViewHome: NSView { var callback: ((NSWindow) -> ())? override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) if let window = window { callback?(window) } } }
Topic: Programming Languages SubTopic: Swift Tags:
Sep ’23
Reply to Set Content View size/position upon retuning from navigation stack destination view
After some additional testing, discovered that I just have to associate the code with the home view (ContentView). With this in place the home view initially displays centered and the correct size. When I go to a destination view (both are larger) the view stays centered and its size adjusts correctly. But when I return to the home view. the size/position of the view does not change. To get the home view to be the correct width and height initially I set the default size in the initial call to ContentView (see code below). So it makes sense to me that I all I need to do upon returning to the home view is reset the default size. Unfortunately I have not yet figured out how to do that. If. someone has any ideas I am all ears. If I figure it out, I will post the solution. @main struct TableViewTestApp: App { var body: some Scene { WindowGroup { ContentView() .hostingWindowPosition( vertical: .center, horizontal: .center, screen: .main ) } .defaultSize(width: 450, height: 700) } } extension NSWindow { struct Position { static let defaultPadding: CGFloat = 16 var vertical: Vertical var horizontal: Horizontal var padding = Self.defaultPadding } } extension NSWindow.Position { enum Horizontal { case left, center, right } enum Vertical { case top, center, bottom } } extension View { func hostingWindowPosition( vertical: NSWindow.Position.Vertical, horizontal: NSWindow.Position.Horizontal, padding: CGFloat = NSWindow.Position.defaultPadding, screen: NSScreen? = nil ) -> some View { modifier( WindowPositionModifier( position: NSWindow.Position( vertical: vertical, horizontal: horizontal, padding: padding ), screen: screen ) ) } } private struct WindowPositionModifier: ViewModifier { let position: NSWindow.Position let screen: NSScreen? func body(content: Content) -> some View { content.background( HostingWindowFinder { $0.setPosition(position, in: screen) } ) } } private struct HostingWindowFinder: NSViewRepresentable { var callback: (NSWindow) -> () func makeNSView(context: Self.Context) -> NSView { let view = BridgingView() view.callback = callback return view } func updateNSView(_ nsView: NSView, context: Context) {} } private class BridgingView: NSView { var callback: ((NSWindow) -> ())? override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) if let window = window { callback?(window) } } } extension NSWindow { func setPosition(_ position: Position, in screen: NSScreen?) { guard let visibleFrame = (screen ?? self.screen)?.visibleFrame else { return } let origin = position.value(forWindow: frame, inScreen: visibleFrame) setFrameOrigin(origin) } } extension NSWindow.Position { func value(forWindow windowRect: CGRect, inScreen screenRect: CGRect) -> CGPoint { let xPosition = horizontal.valueFor( screenRange: screenRect.minX..<screenRect.maxX, width: windowRect.width, padding: padding ) let yPosition = vertical.valueFor( screenRange: screenRect.minY..<screenRect.maxY, height: windowRect.height, padding: padding ) return CGPoint(x: xPosition, y: yPosition) } } extension NSWindow.Position.Horizontal { func valueFor( screenRange: Range<CGFloat>, width: CGFloat, padding: CGFloat) -> CGFloat { switch self { case .left: return screenRange.lowerBound + padding case .center: return (screenRange.upperBound + screenRange.lowerBound - width) / 2 case .right: return screenRange.upperBound - width - padding } } } extension NSWindow.Position.Vertical { func valueFor( screenRange: Range<CGFloat>, height: CGFloat, padding: CGFloat) -> CGFloat { switch self { case .top: return screenRange.upperBound - height - padding case .center: return (screenRange.upperBound + screenRange.lowerBound - height) / 2 case .bottom: return screenRange.lowerBound + padding } } }
Topic: Programming Languages SubTopic: Swift Tags:
Sep ’23
Reply to Set Content View size/position upon retuning from navigation stack destination view
I finally figured out what to do. I created 3 WindowGroups in @main. One for the home view, one for the table view and one for the chart view. I then simplified the position logic as well as added logic to account for each view (they are all of the different size). I manually determined the origin and size of all three windows and assign the appropriate values in an NSRect which is used in the setFrame function of NSWindow. The position logic is assigned to each WindowGroup in @main. All works. Below is the updated code. // @main code struct WindowGroupsApp: App { var body: some Scene { WindowGroup ("Home") { ContentView() .hostingWindowPosition(window: "Home") } WindowGroup ("Table", id: "table", for: String.self) { $fundName in TableView(fundName: fundName!) .hostingWindowPosition(window: "Table") } WindowGroup ("Chart", id: "chart", for: String.self) { $fundName in ChartView(fundName: fundName!) .hostingWindowPosition(window: "Chart") } } } // position logic extension View { func hostingWindowPosition(window: String) -> some View { modifier( WindowPositionModifier(window: window) ) } } private struct WindowPositionModifier: ViewModifier { let window: String func body(content: Content) -> some View { content.background( HostingWindowFinder { $0?.setPosition(window: window) } ) } } struct HostingWindowFinder: NSViewRepresentable { // the system calls the methods at appropriate times var callback: (NSWindow?) -> () func makeNSView(context: Self.Context) -> NSView { let view = NSView() DispatchQueue.main.async { self.callback(view.window) } return view } func updateNSView(_ nsView: NSView, context: Context) { DispatchQueue.main.async { self.callback(nsView.window) } } } extension NSWindow { func setPosition(window: String) { var nsRectangle: NSRect = NSRect(x: 100, y: 100, width: 100, height: 100) switch window { case "Home": nsRectangle = NSRect(x: 1055.0, y: 370.0, width: 450, height: 700) case "Table": nsRectangle = NSRect(x: 1055.0, y: 320.0, width: 450, height: 800) // 390 case "Chart": nsRectangle = NSRect(x: 680.0, y: 245.0, width: 1200, height: 950) default: print("problem in window logic set position") } setFrame(nsRectangle, display: true) } } // content view struct ContentView: View { @Environment (\.openWindow) private var openWindow var body: some View { VStack(alignment: .leading) { ZStack (alignment: .leading) { RoundedRectangle(cornerRadius: 10.0) .fill(Color.white) .frame(width: 200, height: 80) .padding(.leading, 20) VStack(alignment: .leading, spacing: 10) { Button { openWindow(id: "table", value: "Table1") } label: { Text("Table") .font(Font.custom("Arial", size: 14.0)) .foregroundColor(Color.blue) .background(Color.clear) .padding(.leading, 35) } .focusable(false) .buttonStyle(.link) Button { openWindow(id: "chart", value: "Chart1") } label: { Text("Chart - 1 Year") .font(Font.custom("Arial", size: 14.0)) .foregroundColor(Color.blue) .background(Color.clear) .padding(.leading, 35) } .focusable(false) .buttonStyle(.link) Button { openWindow(id: "chart", value: "Chart5") } label: { Text("Chart - 5 Years") .font(Font.custom("Arial", size: 14.0)) .foregroundColor(Color.blue) .background(Color.clear) .padding(.leading, 35) } .focusable(false) .buttonStyle(.link) } // end v stack } // end zstack } // end v stack .frame(width: 450, height: 600, alignment: .topLeading) } // end some view }
Topic: Programming Languages SubTopic: Swift Tags:
Oct ’23
Reply to Is it possible to call openWindow() in a navigationDestination in a NavigationStack?
After doing more research it appears that this is not possible. So I converted the navigation stack to a series of buttons. It works. Below is an example button and my App struct. Button { openWindow(id: "summary") } label: { Text("Summary") .font(Font.custom("Arial", size: 14.0)) .foregroundColor(Color.blue) .background(Color.clear) .padding(.leading, 35) } .focusable(false) .buttonStyle(.link) @main struct WindowGroupsApp: App { var body: some Scene { WindowGroup ("Home") { ContentView() .hostingWindowPosition(window: "Home") } Window("Summary", id: "summary") { SummaryView() .hostingWindowPosition(window: "Summary") } WindowGroup ("Table", id: "table", for: String.self) { $fundName in NavigationDestinationView(fundName: fundName!, numYears: 1) .hostingWindowPosition(window: "Table") } WindowGroup ("Chart", id: "chart1", for: String.self) { $fundName in CustomChartView(fundName: fundName!, numYears: 1) .hostingWindowPosition(window: "Chart") } WindowGroup ("Chart", id: "chart5", for: String.self) { $fundName in CustomChartView(fundName: fundName!, numYears: 5) .hostingWindowPosition(window: "Chart") } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Oct ’23