From 2f5593390ed63148dbb9a8569e28281a0fce1290 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Wed, 3 Sep 2025 15:54:40 +0300 Subject: [PATCH 1/8] new: CPSplitViewController and CPSplitViewItem --- AppKit/CPSplitViewController.j | 192 +++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 AppKit/CPSplitViewController.j diff --git a/AppKit/CPSplitViewController.j b/AppKit/CPSplitViewController.j new file mode 100644 index 000000000..70e47692f --- /dev/null +++ b/AppKit/CPSplitViewController.j @@ -0,0 +1,192 @@ +/* + * CPSplitViewController.j + * + * Created by Google Gemini. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +@import +@import +@import "CPSplitViewItem.j" + +var CPSplitViewControllerAutomaticDimension = -1.0; + +@implementation CPSplitViewController : CPViewController +{ + CPSplitView _splitView; + CPMutableArray _splitViewItems; + CPNumber _minimumThicknessForInlineSidebars; +} + +- (id)init +{ + if (self = [super init]) + { + _splitViewItems = [CPMutableArray array]; + _minimumThicknessForInlineSidebars = 20.0; + } + return self; +} + +- (void)loadView +{ + _splitView = [[CPSplitView alloc] initWithFrame:CGRectMake(0,0,400,400)]; + [self setView:_splitView]; + [_splitView setDelegate:self]; +} + +#pragma mark - Accessors + +- (CPSplitView)splitView +{ + return _splitView; +} + +- (CPArray)splitViewItems +{ + return _splitViewItems; +} + +#pragma mark - Managing Split View Items + +- (void)addSplitViewItem:(CPSplitViewItem)splitViewItem +{ + [self insertSplitViewItem:splitViewItem atIndex:[_splitViewItems count]]; +} + +- (void)insertSplitViewItem:(CPSplitViewItem)splitViewItem atIndex:(CPInteger)index +{ + [splitViewItem _setSplitViewController:self]; + [_splitViewItems insertObject:splitViewItem atIndex:index]; + [self addChildViewController:[splitViewItem viewController]]; + + if ([self isViewLoaded]) + [[self splitView] insertArrangedSubview:[[splitViewItem viewController] view] atIndex:index]; +} + +- (void)removeSplitViewItem:(CPSplitViewItem)splitViewItem +{ + [[splitViewItem viewController] removeFromParentViewController]; + [splitViewItem _setSplitViewController:nil]; + [_splitViewItems removeObject:splitViewItem]; +} + +- (CPSplitViewItem)splitViewItemForViewController:(CPViewController)viewController +{ + for (var i = 0; i < [_splitViewItems count]; i++) + { + var item = [_splitViewItems objectAtIndex:i]; + if ([item viewController] === viewController) + return item; + } + return nil; +} + +#pragma mark - View Lifecycle + +- (void)viewDidLoad +{ + [super viewDidLoad]; + for (var i = 0; i < [_splitViewItems count]; i++) + { + var viewController = [[_splitViewItems objectAtIndex:i] viewController]; + [[self splitView] addArrangedSubview:[viewController view]]; + } +} + +#pragma mark - Managing Sidebars and Inspectors + +- (void)toggleSidebar:(id)sender +{ + if ([_splitViewItems count] > 0) + { + var sidebarItem = [_splitViewItems objectAtIndex:0]; + [sidebarItem setCollapsed:![sidebarItem isCollapsed]]; + } +} + +- (void)toggleInspector:(id)sender +{ + if ([_splitViewItems count] > 1) + { + var inspectorItem = [_splitViewItems lastObject]; + [inspectorItem setCollapsed:![inspectorItem isCollapsed]]; + } +} + +- (CPNumber)minimumThicknessForInlineSidebars +{ + return _minimumThicknessForInlineSidebars; +} + +@end + +@implementation CPSplitViewItem : CPObject +{ + CPViewController _viewController; + BOOL _isCollapsed; + CPSplitViewController _splitViewController; +} + +#pragma mark - Initialization + ++ (instancetype)splitViewItemWithViewController:(CPViewController)viewController +{ + return [[self alloc] initWithViewController:viewController]; +} + +- (id)initWithViewController:(CPViewController)viewController +{ + if (self = [super init]) + { + _viewController = viewController; + _isCollapsed = NO; + } + return self; +} + +#pragma mark - Accessors + +- (CPViewController)viewController +{ + return _viewController; +} + +- (BOOL)isCollapsed +{ + return _isCollapsed; +} + +- (void)setCollapsed:(BOOL)shouldCollapse +{ + if (_isCollapsed === shouldCollapse) + return; + + _isCollapsed = shouldCollapse; + [[_viewController view] setHidden:shouldCollapse]; +} + +- (CPSplitViewController)splitViewController +{ + return _splitViewController; +} + +- (void)_setSplitViewController:(CPSplitViewController)splitViewController +{ + _splitViewController = splitViewController; +} + +@end From de96e0c22cfc4c079d39a248af8fe5af8080e4c3 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Wed, 3 Sep 2025 15:57:42 +0300 Subject: [PATCH 2/8] fixed: missing import --- AppKit/CPSplitViewController.j | 1 - 1 file changed, 1 deletion(-) diff --git a/AppKit/CPSplitViewController.j b/AppKit/CPSplitViewController.j index 70e47692f..c004d1810 100644 --- a/AppKit/CPSplitViewController.j +++ b/AppKit/CPSplitViewController.j @@ -20,7 +20,6 @@ @import @import -@import "CPSplitViewItem.j" var CPSplitViewControllerAutomaticDimension = -1.0; From 44de0334b7b94a5213bcc6701e71ba5a9208d603 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Thu, 4 Sep 2025 11:49:59 +0300 Subject: [PATCH 3/8] improved: documentation --- AppKit/CPSplitViewController.j | 226 +++++++++++++++++++++++++-------- 1 file changed, 173 insertions(+), 53 deletions(-) diff --git a/AppKit/CPSplitViewController.j b/AppKit/CPSplitViewController.j index c004d1810..255504509 100644 --- a/AppKit/CPSplitViewController.j +++ b/AppKit/CPSplitViewController.j @@ -1,7 +1,8 @@ /* * CPSplitViewController.j * - * Created by Google Gemini. + * Created by Daniel Boehringer on September 2, 2025. + * Copyright (c) 2025 [Copyright Holder]. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,13 +24,31 @@ var CPSplitViewControllerAutomaticDimension = -1.0; +/** + * A container view controller that manages two or more child view + * controllers in a split view interface. + * + * This class provides a controller-level abstraction for CPSplitView, + * managing the addition, removal, and arrangement of view controllers + * through CPSplitViewItem instances. + * + * This implementation was synthesized with the assistance of an LLM, + * directed by the author. + */ @implementation CPSplitViewController : CPViewController { + /** @private The underlying split view that arranges the child views. */ CPSplitView _splitView; + + /** @private An array of CPSplitViewItem objects managed by this controller. */ CPMutableArray _splitViewItems; + + /** @private The minimum thickness for sidebars to be displayed inline. */ CPNumber _minimumThicknessForInlineSidebars; } +// MARK: - Initialization + - (id)init { if (self = [super init]) @@ -40,6 +59,8 @@ var CPSplitViewControllerAutomaticDimension = -1.0; return self; } +// MARK: - View Lifecycle + - (void)loadView { _splitView = [[CPSplitView alloc] initWithFrame:CGRectMake(0,0,400,400)]; @@ -47,55 +68,6 @@ var CPSplitViewControllerAutomaticDimension = -1.0; [_splitView setDelegate:self]; } -#pragma mark - Accessors - -- (CPSplitView)splitView -{ - return _splitView; -} - -- (CPArray)splitViewItems -{ - return _splitViewItems; -} - -#pragma mark - Managing Split View Items - -- (void)addSplitViewItem:(CPSplitViewItem)splitViewItem -{ - [self insertSplitViewItem:splitViewItem atIndex:[_splitViewItems count]]; -} - -- (void)insertSplitViewItem:(CPSplitViewItem)splitViewItem atIndex:(CPInteger)index -{ - [splitViewItem _setSplitViewController:self]; - [_splitViewItems insertObject:splitViewItem atIndex:index]; - [self addChildViewController:[splitViewItem viewController]]; - - if ([self isViewLoaded]) - [[self splitView] insertArrangedSubview:[[splitViewItem viewController] view] atIndex:index]; -} - -- (void)removeSplitViewItem:(CPSplitViewItem)splitViewItem -{ - [[splitViewItem viewController] removeFromParentViewController]; - [splitViewItem _setSplitViewController:nil]; - [_splitViewItems removeObject:splitViewItem]; -} - -- (CPSplitViewItem)splitViewItemForViewController:(CPViewController)viewController -{ - for (var i = 0; i < [_splitViewItems count]; i++) - { - var item = [_splitViewItems objectAtIndex:i]; - if ([item viewController] === viewController) - return item; - } - return nil; -} - -#pragma mark - View Lifecycle - - (void)viewDidLoad { [super viewDidLoad]; @@ -106,8 +78,92 @@ var CPSplitViewControllerAutomaticDimension = -1.0; } } -#pragma mark - Managing Sidebars and Inspectors +// MARK: - Accessors +/** + * Returns the CPSplitView instance managed by the controller. + * + * @returns {CPSplitView} The split view. + */ +- (CPSplitView)splitView +{ + return _splitView; +} + +/** + * Returns the array of split view items. + * + * @returns {CPArray} The array of CPSplitViewItem objects. + */ +- (CPArray)splitViewItems +{ + return _splitViewItems; +} + +// MARK: - Managing Split View Items + +/** + * Adds a split view item to the end of the split view. + * + * @param {CPSplitViewItem} splitViewItem The split view item to add. + */ +- (void)addSplitViewItem:(CPSplitViewItem)splitViewItem +{ + [self insertSplitViewItem:splitViewItem atIndex:[_splitViewItems count]]; +} + +/** + * Inserts a split view item at a specific index. + * + * @param {CPSplitViewItem} splitViewItem The split view item to insert. + * @param {CPInteger} index The zero-based index at which to insert the item. + */ +- (void)insertSplitViewItem:(CPSplitViewItem)splitViewItem atIndex:(CPInteger)index +{ + [splitViewItem _setSplitViewController:self]; + [_splitViewItems insertObject:splitViewItem atIndex:index]; + [self addChildViewController:[splitViewItem viewController]]; + + if ([self isViewLoaded]) + [[self splitView] insertArrangedSubview:[[splitViewItem viewController] view] atIndex:index]; +} + +/** + * Removes the specified split view item. + * + * @param {CPSplitViewItem} splitViewItem The split view item to remove. + */ +- (void)removeSplitViewItem:(CPSplitViewItem)splitViewItem +{ + [[splitViewItem viewController] removeFromParentViewController]; + [splitViewItem _setSplitViewController:nil]; + [_splitViewItems removeObject:splitViewItem]; +} + +/** + * Retrieves the split view item associated with a given view controller. + * + * @param {CPViewController} viewController The view controller to find. + * @returns {CPSplitViewItem | null} The corresponding split view item, or nil if not found. + */ +- (CPSplitViewItem)splitViewItemForViewController:(CPViewController)viewController +{ + for (var i = 0; i < [_splitViewItems count]; i++) + { + var item = [_splitViewItems objectAtIndex:i]; + if ([item viewController] === viewController) + return item; + } + return nil; +} + +// MARK: - Managing Sidebars and Inspectors + +/** + * Toggles the collapsed state of the first split view item, typically a sidebar. + * + * @param {id} sender The object that initiated the action. + */ - (void)toggleSidebar:(id)sender { if ([_splitViewItems count] > 0) @@ -117,6 +173,11 @@ var CPSplitViewControllerAutomaticDimension = -1.0; } } +/** + * Toggles the collapsed state of the last split view item, typically an inspector. + * + * @param {id} sender The object that initiated the action. + */ - (void)toggleInspector:(id)sender { if ([_splitViewItems count] > 1) @@ -126,6 +187,11 @@ var CPSplitViewControllerAutomaticDimension = -1.0; } } +/** + * Returns the minimum thickness for sidebars to be displayed inline. + * + * @returns {CPNumber} The minimum thickness. + */ - (CPNumber)minimumThicknessForInlineSidebars { return _minimumThicknessForInlineSidebars; @@ -133,20 +199,46 @@ var CPSplitViewControllerAutomaticDimension = -1.0; @end +/** + * An object that manages a view controller within a CPSplitViewController. + * + * A CPSplitViewItem acts as a wrapper around a CPViewController, + * maintaining properties like its collapsed state within the parent + * split view controller. + */ @implementation CPSplitViewItem : CPObject { + /** @private The view controller managed by this item. */ CPViewController _viewController; + + /** @private A boolean indicating whether the item is collapsed. */ BOOL _isCollapsed; + + /** @private A weak reference to the owning split view controller. */ CPSplitViewController _splitViewController; } -#pragma mark - Initialization +// MARK: - Class Methods +/** + * Creates and returns a new split view item with the specified view controller. + * + * @param {CPViewController} viewController The view controller for the new item. + * @returns {instancetype} A new CPSplitViewItem instance. + */ + (instancetype)splitViewItemWithViewController:(CPViewController)viewController { return [[self alloc] initWithViewController:viewController]; } +// MARK: - Initialization + +/** + * Initializes a new split view item with the specified view controller. + * + * @param {CPViewController} viewController The view controller for the new item. + * @returns {id} The initialized CPSplitViewItem instance. + */ - (id)initWithViewController:(CPViewController)viewController { if (self = [super init]) @@ -157,18 +249,34 @@ var CPSplitViewControllerAutomaticDimension = -1.0; return self; } -#pragma mark - Accessors +// MARK: - Accessors +/** + * Returns the view controller associated with the item. + * + * @returns {CPViewController} The associated view controller. + */ - (CPViewController)viewController { return _viewController; } +/** + * Returns a boolean value indicating whether the item is collapsed. + * + * @returns {BOOL} YES if the item is collapsed, otherwise NO. + */ - (BOOL)isCollapsed { return _isCollapsed; } +/** + * Sets the collapsed state of the item. + * When collapsed, the view controller's view is hidden. + * + * @param {BOOL} shouldCollapse YES to collapse the item, NO to expand it. + */ - (void)setCollapsed:(BOOL)shouldCollapse { if (_isCollapsed === shouldCollapse) @@ -178,11 +286,23 @@ var CPSplitViewControllerAutomaticDimension = -1.0; [[_viewController view] setHidden:shouldCollapse]; } +/** + * Returns the split view controller that owns this item. + * + * @returns {CPSplitViewController | null} The parent split view controller. + */ - (CPSplitViewController)splitViewController { return _splitViewController; } +/** + * @private + * Sets the owning split view controller. This method is for internal use by + * CPSplitViewController. + * + * @param {CPSplitViewController} splitViewController The parent controller. + */ - (void)_setSplitViewController:(CPSplitViewController)splitViewController { _splitViewController = splitViewController; From dc23fe49aff6a6184623a71479f46e9ba6c0a0d0 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Thu, 4 Sep 2025 11:54:06 +0300 Subject: [PATCH 4/8] new: unit tests --- Tests/AppKit/CPSplitViewControllerTests.j | 186 ++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 Tests/AppKit/CPSplitViewControllerTests.j diff --git a/Tests/AppKit/CPSplitViewControllerTests.j b/Tests/AppKit/CPSplitViewControllerTests.j new file mode 100644 index 000000000..464dfae36 --- /dev/null +++ b/Tests/AppKit/CPSplitViewControllerTests.j @@ -0,0 +1,186 @@ +@import +@import + +// MARK: - Test Implementation + +@implementation CPSplitViewControllerTest : OJTestCase +{ + // Instance variables can be declared here if needed for tests. +} + +// MARK: - Initialization Tests + +- (void)testInit +{ + var splitViewController = [[CPSplitViewController alloc] init]; + + [self assertNotNil:splitViewController message:@"CPSplitViewController should initialize."]; + [self assertNotNil:[splitViewController splitViewItems] message:@"splitViewItems should be an empty array on init."]; + [self assert:[[splitViewController splitViewItems] count] equals:0 message:@"splitViewItems should have 0 items on init."]; +} + +- (void)testViewLoading +{ + var splitViewController = [[CPSplitViewController alloc] init]; + + // Accessing the view property triggers loadView + var view = [splitViewController view]; + + [self assertNotNil:view message:@"The controller's view should be created."]; + [self assertTrue:[view isKindOfClass:[CPSplitView class]] message:@"The controller's view should be a CPSplitView."]; + [self assert:[splitViewController splitView] equals:view message:@"The splitView accessor should return the controller's view."]; +} + +- (void)testSplitViewItemInit +{ + var childVC = [[CPViewController alloc] init]; + var item = [CPSplitViewItem splitViewItemWithViewController:childVC]; + + [self assertNotNil:item message:@"CPSplitViewItem should be created."]; + [self assert:[item viewController] equals:childVC message:@"The item should hold the correct view controller."]; + [self assertFalse:[item isCollapsed] message:@"A new item should not be collapsed."]; +} + +// MARK: - Item Management Tests + +- (void)testAddSplitViewItem +{ + var splitViewController = [[CPSplitViewController alloc] init]; + [splitViewController view]; // Ensure view is loaded + + var childVC1 = [[CPViewController alloc] init]; + var item1 = [CPSplitViewItem splitViewItemWithViewController:childVC1]; + + [splitViewController addSplitViewItem:item1]; + + [self assert:[[splitViewController splitViewItems] count] equals:1 message:@"Should have 1 split view item."]; + [self assert:[splitViewController splitViewItemForViewController:childVC1] equals:item1 message:@"Should be able to retrieve item by its view controller."]; + [self assert:[item1 splitViewController] equals:splitViewController message:@"Item should have a reference to its parent controller."]; + [self assert:[[[splitViewController splitView] arrangedSubviews] count] equals:1 message:@"The splitView should have one arranged subview."]; + [self assert:[[[childVC1 view] superview] equals:[splitViewController splitView]] message:@"Child's view should be a subview of the splitView."]; +} + +- (void)testInsertSplitViewItem +{ + var splitViewController = [[CPSplitViewController alloc] init]; + [splitViewController view]; + + var childVC1 = [[CPViewController alloc] init]; + var childVC2 = [[CPViewController alloc] init]; + var item1 = [CPSplitViewItem splitViewItemWithViewController:childVC1]; + var item2 = [CPSplitViewItem splitViewItemWithViewController:childVC2]; + + [splitViewController addSplitViewItem:item1]; + [splitViewController insertSplitViewItem:item2 atIndex:0]; + + [self assert:[[splitViewController splitViewItems] count] equals:2 message:@"Should have 2 split view items."]; + [self assert:[[splitViewController splitViewItems] objectAtIndex:0] equals:item2 message:@"Item2 should be at index 0."]; + + var arrangedSubviews = [[splitViewController splitView] arrangedSubviews]; + [self assert:[arrangedSubviews objectAtIndex:0] equals:[childVC2 view] message:@"The view of item2 should be the first arranged subview."]; +} + +- (void)testRemoveSplitViewItem +{ + var splitViewController = [[CPSplitViewController alloc] init]; + [splitViewController view]; + + var childVC1 = [[CPViewController alloc] init]; + var item1 = [CPSplitViewItem splitViewItemWithViewController:childVC1]; + + [splitViewController addSplitViewItem:item1]; + [self assert:[[splitViewController splitViewItems] count] equals:1 message:@"Pre-condition: Should have 1 item."]; + + [splitViewController removeSplitViewItem:item1]; + + [self assert:[[splitViewController splitViewItems] count] equals:0 message:@"Should have 0 split view items after removal."]; + [self assertNil:[item1 splitViewController] message:@"Item's reference to parent should be nil after removal."]; + [self assert:[[[splitViewController splitView] arrangedSubviews] count] equals:0 message:@"The splitView should have no arranged subviews after removal."]; + [self assertNil:[[childVC1 view] superview] message:@"Child's view should be removed from the splitView."]; +} + +- (void)testAddingItemsBeforeViewLoads +{ + var splitViewController = [[CPSplitViewController alloc] init]; + + var childVC1 = [[CPViewController alloc] init]; + var childVC2 = [[CPViewController alloc] init]; + var item1 = [CPSplitViewItem splitViewItemWithViewController:childVC1]; + var item2 = [CPSplitViewItem splitViewItemWithViewController:childVC2]; + + [splitViewController addSplitViewItem:item1]; + [splitViewController addSplitViewItem:item2]; + + [self assert:[[[splitViewController childViewControllers] objectAtIndex:0] equals:childVC1] message:@"Child view controllers should be added immediately."]; + + // View is not loaded yet, so it should have no arranged subviews + [self assertNil:[splitViewController _splitView] message:@"SplitView should not exist yet."]; + + // Trigger viewDidLoad + [splitViewController view]; + + // Now check if the views were added + var arrangedSubviews = [[splitViewController splitView] arrangedSubviews]; + [self assert:[arrangedSubviews count] equals:2 message:@"SplitView should have 2 subviews after loading."]; + [self assert:[arrangedSubviews objectAtIndex:0] equals:[childVC1 view]]; + [self assert:[arrangedSubviews objectAtIndex:1] equals:[childVC2 view]]; +} + + +// MARK: - Toggling and State Tests + +- (void)testToggleSidebar +{ + var splitViewController = [[CPSplitViewController alloc] init]; + var childVC1 = [[CPViewController alloc] init]; + var item1 = [CPSplitViewItem splitViewItemWithViewController:childVC1]; + [splitViewController addSplitViewItem:item1]; + + [splitViewController toggleSidebar:self]; + [self assertTrue:[item1 isCollapsed] message:@"Sidebar item should be collapsed."]; + [self assertTrue:[[childVC1 view] isHidden] message:@"Sidebar view should be hidden."]; + + [splitViewController toggleSidebar:self]; + [self assertFalse:[item1 isCollapsed] message:@"Sidebar item should be expanded again."]; + [self assertFalse:[[childVC1 view] isHidden] message:@"Sidebar view should be visible again."]; +} + +- (void)testToggleInspector +{ + var splitViewController = [[CPSplitViewController alloc] init]; + var childVC1 = [[CPViewController alloc] init]; + var childVC2 = [[CPViewController alloc] init]; + var item1 = [CPSplitViewItem splitViewItemWithViewController:childVC1]; + var item2 = [CPSplitViewItem splitViewItemWithViewController:childVC2]; + [splitViewController addSplitViewItem:item1]; + [splitViewController addSplitViewItem:item2]; + + [splitViewController toggleInspector:self]; + [self assertTrue:[item2 isCollapsed] message:@"Inspector item should be collapsed."]; + [self assertTrue:[[childVC2 view] isHidden] message:@"Inspector view should be hidden."]; + + [splitViewController toggleInspector:self]; + [self assertFalse:[item2 isCollapsed] message:@"Inspector item should be expanded again."]; + [self assertFalse:[[childVC2 view] isHidden] message:@"Inspector view should be visible again."]; +} + +- (void)testSetCollapsed +{ + var childVC = [[CPViewController alloc] init]; + var item = [CPSplitViewItem splitViewItemWithViewController:childVC]; + var childView = [childVC view]; + + [item setCollapsed:YES]; + [self assertTrue:[item isCollapsed] message:@"Item's collapsed property should be YES."]; + [self assertTrue:[childView isHidden] message:@"The item's view should be hidden."]; + + [item setCollapsed:NO]; + [self assertFalse:[item isCollapsed] message:@"Item's collapsed property should be NO."]; + [self assertFalse:[childView isHidden] message:@"The item's view should be visible."]; + + // Test idempotency + [item setCollapsed:NO]; + [self assertFalse:[item isCollapsed] message:@"Setting the same value should have no effect."]; +} + +@end \ No newline at end of file From f1f0703619bfc6b8558372fba9220680e26ce3a7 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Thu, 4 Sep 2025 12:11:03 +0300 Subject: [PATCH 5/8] fixed: imports --- AppKit/CPSplitViewController.j | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AppKit/CPSplitViewController.j b/AppKit/CPSplitViewController.j index 255504509..4c486b0cb 100644 --- a/AppKit/CPSplitViewController.j +++ b/AppKit/CPSplitViewController.j @@ -19,8 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import -@import +@import "CPViewController" +@import "CPSplitView.j" var CPSplitViewControllerAutomaticDimension = -1.0; From 205b645de84d9c395d53409792f824505ca6a5b4 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Thu, 4 Sep 2025 12:14:06 +0300 Subject: [PATCH 6/8] fixed: import statement for CPViewController --- AppKit/CPSplitViewController.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPSplitViewController.j b/AppKit/CPSplitViewController.j index 4c486b0cb..66dcef38f 100644 --- a/AppKit/CPSplitViewController.j +++ b/AppKit/CPSplitViewController.j @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import "CPViewController" +@import "CPViewController.j" @import "CPSplitView.j" var CPSplitViewControllerAutomaticDimension = -1.0; From a3cb43bad822557a67ba5eff91ccd3f10a4a6f9a Mon Sep 17 00:00:00 2001 From: daboe01 Date: Sat, 6 Sep 2025 08:58:59 +0200 Subject: [PATCH 7/8] fixed: missing api issues --- AppKit/CPSplitViewController.j | 78 ++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 4 deletions(-) diff --git a/AppKit/CPSplitViewController.j b/AppKit/CPSplitViewController.j index 66dcef38f..bacf9195d 100644 --- a/AppKit/CPSplitViewController.j +++ b/AppKit/CPSplitViewController.j @@ -2,7 +2,7 @@ * CPSplitViewController.j * * Created by Daniel Boehringer on September 2, 2025. - * Copyright (c) 2025 [Copyright Holder]. All rights reserved. + * Copyright (c) 2025 Daniel Boehringer. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -63,9 +63,12 @@ var CPSplitViewControllerAutomaticDimension = -1.0; - (void)loadView { - _splitView = [[CPSplitView alloc] initWithFrame:CGRectMake(0,0,400,400)]; + if (!_splitView) + { + _splitView = [[CPSplitView alloc] initWithFrame:CGRectMake(0,0,400,400)]; + [_splitView setDelegate:self]; + } [self setView:_splitView]; - [_splitView setDelegate:self]; } - (void)viewDidLoad @@ -90,6 +93,22 @@ var CPSplitViewControllerAutomaticDimension = -1.0; return _splitView; } +/** + * Sets a custom split view for the controller. + * + * @param {CPSplitView} splitView The custom split view to use. + */ +- (void)setSplitView:(CPSplitView)splitView +{ + if (_splitView !== splitView) + { + _splitView = splitView; + [_splitView setDelegate:self]; + if ([self isViewLoaded]) + [self setView:_splitView]; + } +} + /** * Returns the array of split view items. * @@ -100,6 +119,26 @@ var CPSplitViewControllerAutomaticDimension = -1.0; return _splitViewItems; } +/** + * Sets the array of split view items, replacing any existing items. + * + * @param {CPArray} splitViewItems An array of CPSplitViewItem objects. + */ +- (void)setSplitViewItems:(CPArray)splitViewItems +{ + // Remove all existing items + while ([_splitViewItems count] > 0) + { + [self removeSplitViewItem:[_splitViewItems lastObject]]; + } + + // Add new items + for (var i = 0; i < [splitViewItems count]; i++) + { + [self addSplitViewItem:[splitViewItems objectAtIndex:i]]; + } +} + // MARK: - Managing Split View Items /** @@ -135,7 +174,11 @@ var CPSplitViewControllerAutomaticDimension = -1.0; */ - (void)removeSplitViewItem:(CPSplitViewItem)splitViewItem { - [[splitViewItem viewController] removeFromParentViewController]; + var viewController = [splitViewItem viewController]; + if ([self isViewLoaded]) + [[viewController view] removeFromSuperview]; + + [viewController removeFromParentViewController]; [splitViewItem _setSplitViewController:nil]; [_splitViewItems removeObject:splitViewItem]; } @@ -197,6 +240,33 @@ var CPSplitViewControllerAutomaticDimension = -1.0; return _minimumThicknessForInlineSidebars; } +// MARK: - CPSplitViewDelegate Methods + +// Note: A more complete implementation would forward these delegate methods +// to a separate delegate property on the CPSplitViewController itself. +// For now, these are stubbed to demonstrate where they would be handled. + +- (BOOL)splitView:(CPSplitView)splitView canCollapseSubview:(CPView)subview +{ + // Default behavior: allow all subviews to be collapsed. + return YES; +} + +- (CGFloat)splitView:(CPSplitView)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(CPInteger)dividerIndex +{ + return proposedMinimumPosition; +} + +- (CGFloat)splitView:(CPSplitView)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(CPInteger)dividerIndex +{ + return proposedMaximumPosition; +} + +- (void)splitViewDidResizeSubviews:(CPNotification)notification +{ + // Can be used to respond to user-initiated resizing. +} + @end /** From 812f69f4a7f5dbabd9a6f776009e496025de1cc0 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Wed, 24 Sep 2025 14:20:37 +0200 Subject: [PATCH 8/8] fixed: missing splitView:effectiveRect:forDrawnRect:ofDividerAtIndex: --- AppKit/CPSplitViewController.j | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AppKit/CPSplitViewController.j b/AppKit/CPSplitViewController.j index bacf9195d..fe23f53df 100644 --- a/AppKit/CPSplitViewController.j +++ b/AppKit/CPSplitViewController.j @@ -262,6 +262,13 @@ var CPSplitViewControllerAutomaticDimension = -1.0; return proposedMaximumPosition; } +- (CGRect)splitView:(CPSplitView)splitView effectiveRect:(CGRect)proposedEffectiveRect forDrawnRect:(CGRect)drawnRect ofDividerAtIndex:(CPInteger)dividerIndex +{ + // Default behavior: return the proposed rectangle. + // This can be overridden to provide a larger or custom hit area for the divider. + return proposedEffectiveRect; +} + - (void)splitViewDidResizeSubviews:(CPNotification)notification { // Can be used to respond to user-initiated resizing.