Merge remote-tracking branch 'upstream/main' into Aristo3

This commit is contained in:
daboe01
2026-05-19 18:53:15 +02:00
5 changed files with 106 additions and 17 deletions
+78 -6
View File
@@ -395,6 +395,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
CPInteger _editingColumn;
SEL _doubleAction;
id _doubleClickTarget @accessors(property=doubleClickTarget);
id _doubleClickArgument @accessors(property=doubleClickArgument);
CPInteger _clickedRow;
CPInteger _clickedColumn;
unsigned _columnAutoResizingStyle;
@@ -3709,13 +3711,73 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
[removeIndexes addIndex:columnIdx];
}
var rowIndexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self numberOfRows])];
[self _unloadDataViewsInRows:rowIndexes columns:removeIndexes];
if ([removeIndexes count] > 0)
{
var rowIndexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self numberOfRows])];
[self _unloadDataViewsInRows:rowIndexes columns:removeIndexes];
[_tableColumns removeObjectsAtIndexes:removeIndexes];
[_tableColumns removeObjectsAtIndexes:removeIndexes];
_dirtyTableColumnRangeIndex = 0;
[self _recalculateTableColumnRanges];
_dirtyTableColumnRangeIndex = 0;
[self _recalculateTableColumnRanges];
// Shift cached index sets downwards to account for the removed columns
var shiftIndexSet = function(indexSet)
{
var newSet = [CPIndexSet indexSet];
[indexSet enumerateIndexesUsingBlock:function(idx, stop)
{
if (![removeIndexes containsIndex:idx])
{
var shift = 0,
remIdx = [removeIndexes firstIndex];
while (remIdx !== CPNotFound && remIdx < idx)
{
shift++;
remIdx = [removeIndexes indexGreaterThanIndex:remIdx];
}
[newSet addIndex:idx - shift];
}
}];
return newSet;
};
_exposedColumns = shiftIndexSet(_exposedColumns);
_selectedColumnIndexes = shiftIndexSet(_selectedColumnIndexes);
// Shift individual index variables
var shiftIndex = function(idx)
{
if (idx === CPNotFound || idx === -1)
return idx;
if ([removeIndexes containsIndex:idx])
return CPNotFound;
var shift = 0,
remIdx = [removeIndexes firstIndex];
while (remIdx !== CPNotFound && remIdx < idx)
{
shift++;
remIdx = [removeIndexes indexGreaterThanIndex:remIdx];
}
return idx - shift;
};
_editingColumn = shiftIndex(_editingColumn);
_draggedColumnIndex = shiftIndex(_draggedColumnIndex);
if (_draggedColumnIndex === CPNotFound)
_draggedColumnIndex = -1;
_clickedColumn = shiftIndex(_clickedColumn);
if (_clickedColumn === CPNotFound)
_clickedColumn = -1;
}
[_differedColumnDataToRemove removeAllObjects];
_needsDifferedTableColumnRemove = NO;
@@ -4733,7 +4795,12 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
//double click actions
if ([[CPApp currentEvent] clickCount] === 2 && _doubleAction)
[self sendAction:_doubleAction to:_target];
{
var target = _doubleClickTarget || _target,
argument = [self infoForBinding:@"doubleClickArgument"] ? _doubleClickArgument : self;
[CPApp sendAction:_doubleAction to:target from:argument];
}
}
/*
@@ -6148,6 +6215,11 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
{
if (aBinding == @"content")
_contentBindingExplicitlySet = YES;
else if (aBinding == @"doubleClickTarget")
{
if ([options objectForKey:CPSelectorNameBindingOption])
[self setDoubleAction:CPSelectorFromString([options objectForKey:CPSelectorNameBindingOption])];
}
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
}
+2
View File
@@ -286,6 +286,8 @@ _oncontextmenuhandler = function () { return false; };
if (removeRange.length)
_removeInvalidLineFragmentsRange = CPMakeRangeCopy(removeRange);
else
_removeInvalidLineFragmentsRange = nil;
// We erased all lines
if (!startIndex)
+11
View File
@@ -365,6 +365,17 @@ var CPSystemTypesetterFactory,
wrapWidth = rangeWidth;
wrapRange._height = _lineHeight;
wrapRange._base = _lineBase;
// Optimization: Start measuring from the next character to avoid O(n^2)
// string width calculation within a line since spaces do not carry ligatures or kerning.
// Only reset the measuring range if the next character is NOT another space.
// This prevents compounded subpixel rounding errors with contiguous spaces.
if (theString.charCodeAt(glyphIndex + 1) !== 32)
{
currentAnchor = rangeWidth;
measuringRange = CPMakeRange(glyphIndex + 1, 0);
}
break;
case 10:
+1 -7
View File
@@ -3,18 +3,12 @@
# Cappuccino: Build Desktop-Class Web Applications
Cappuccino is an open-source framework that supports building powerful, desktop-class applications running in any modern web browser. Instead of direct manipulation of HTML, CSS, and the DOM, applications are built using Objective-J, a superset of JavaScript modeled on Objective-C.
Cappuccino faithfully implements the proven design patterns of NeXTSTEP/Apple's Cocoa frameworks, enabling the creation of incredibly complex and reliable applications with a fraction of the code.
> **✨ Project Status: Active Development & Node.js Transition**
> Cappuccino has been under continuous development since 2008 and is actively maintained. A major transition to a modern, **Node.js-based toolchain** has recently been finalized. The current release is a production-ready Release Candidate, with a formal release scheduled for 2026. It is stable, fast, and ready for new projects.
---
## Why Use Cappuccino?
Cappuccino is not intended for building simple websites. It is for building **applications**—especially complex, data-rich, line-of-business tools where productivity and user experience are paramount.
Cappuccino is an open-source framework that supports building powerful, desktop-class applications running in any modern web browser. Cappuccino is not intended for building simple websites. It is for building **applications**—especially complex, data-rich, line-of-business tools where productivity and user experience are paramount. Instead of direct manipulation of HTML, CSS, and the DOM, applications are built using Objective-J, a superset of JavaScript modeled on Objective-C. This gives you a lot of benefits:
* **💻 True Desktop Behavior, Out-of-the-Box:** Applications built with Cappuccino behave like native desktop software by default. This includes a rich palette of UI controls, **full keyboard navigation and focus management**, and **multi-level undo/redo support** — as you can see in this [Showcase application](https://ansb.uniklinik-freiburg.de/ThemeKitchenSinkA3). Also take a look at the [Cookbook tutorial](https://cappuccino-cookbook.5apps.com/).
* **🚀 Incredible Productivity:** Less code is needed. High-level abstractions and a powerful object-oriented model mean development is focused on application logic, not browser quirks.
+14 -4
View File
@@ -164,10 +164,20 @@ tableTestDragType = @"CPTableViewTestDragType";
- (void)removeColumn:(id)sender
{
// if ([[tableView tableColumns] containsObject:randomColumn])
[tableView removeTableColumn:randomColumn];
//else
// [tableView addTableColumn:randomColumn];
var columns = [tableView tableColumns];
// Check if we still have columns left to remove
if (columns && [columns count] > 0)
{
var columnToRemove = [columns lastObject];
[tableView removeTableColumn:columnToRemove];
CPLog.debug(@"Removed column with identifier: " + [columnToRemove identifier]);
}
else
{
CPLog.debug(@"No more columns to remove!");
}
}
- (void)addColumn:(id)sender