initial display of the table

This commit is contained in:
daboe01
2026-06-14 21:06:51 +02:00
parent 5897d76c04
commit 1cad83aba8
4 changed files with 297 additions and 133 deletions
+112 -67
View File
@@ -292,7 +292,6 @@ _oncontextmenuhandler = function () { return false; };
// We erased all lines
if (!startIndex)
[self setExtraLineFragmentRect:CGRectMake(0, 0) usedRect:CGRectMake(0, 0) textContainer:nil];
// document.title=startIndex;
[_typesetter layoutGlyphsInLayoutManager:self startingAtGlyphIndex:startIndex maxNumberOfLineFragments:-1 nextGlyphIndex:nil];
@@ -532,20 +531,26 @@ _oncontextmenuhandler = function () { return false; };
var frames = [fragment glyphFrames],
len = fragment._range.length;
for (var j = 0; j < len; j++)
if (frames)
{
if (CGRectContainsPoint(frames[j], point))
{
if (partialFraction)
partialFraction[0] = (point.x - frames[j].origin.x) / frames[j].size.width;
var maxLen = MIN(len, frames.length);
return fragment._range.location + j;
for (var j = 0; j < maxLen; j++)
{
var frame = frames[j];
if (frame && CGRectContainsPoint(frame, point))
{
if (partialFraction)
partialFraction[0] = (point.x - frame.origin.x) / frame.size.width;
return fragment._range.location + j;
}
}
}
}
}
// Not found, maybe a point left to the last character was clicked -> search again with broader constraints
if ([[_textStorage string] length])
{
for (var i = 0; i < c; i++)
@@ -554,30 +559,33 @@ _oncontextmenuhandler = function () { return false; };
if (fragment._textContainer === container)
{
// Within the horizontal territory of the current (not-empty) line?
if (fragment._range.length > 0 && point.y > fragment._fragmentRect.origin.y &&
point.y <= fragment._fragmentRect.origin.y + fragment._fragmentRect.size.height)
if (fragment._range.length > 0 && point.y > fragment._fragmentRect.origin.y &&
point.y <= fragment._fragmentRect.origin.y + fragment._fragmentRect.size.height)
{
if (i < c - 1 && _lineFragments[i + 1]._fragmentRect.origin.y === fragment._fragmentRect.origin.y)
continue;
var nlLoc = CPMaxRange(fragment._range),
frames = [fragment glyphFrames];
if (frames && frames.length > 0)
{
// Skip tabs and move on the last fragment in this line
if (i < c - 1 && _lineFragments[i + 1]._fragmentRect.origin.y === fragment._fragmentRect.origin.y)
continue;
var lastFrame = frames[frames.length - 1],
firstFrame = frames[0];
var nlLoc = CPMaxRange(fragment._range),
lastFrame = [fragment glyphFrames][fragment._range.length - 1],
firstFrame = [fragment glyphFrames][0];
if (lastFrame && firstFrame)
{
if (_isNewlineCharacter([[_textStorage string] characterAtIndex:nlLoc > 0 ? nlLoc - 1 : 0]))
nlLoc--;
// stay on the line the newline character belongs to
if (_isNewlineCharacter([[_textStorage string] characterAtIndex:nlLoc > 0 ? nlLoc - 1 : 0]))
nlLoc--;
// Clicked right to the last character
if (point.x > CGRectGetMaxX(lastFrame))
return nlLoc;
// Clicked left to the last character
else if (point.x <= CGRectGetMinX(firstFrame))
return fragment._range.location;
else
return nlLoc;
if (point.x > CGRectGetMaxX(lastFrame))
return nlLoc;
else if (point.x <= CGRectGetMinX(firstFrame))
return fragment._range.location;
else
return nlLoc;
}
}
}
}
}
@@ -707,7 +715,11 @@ _oncontextmenuhandler = function () { return false; };
var index = location - lineFragment._range.location;
return lineFragment._glyphsOffsets[index];
if (index < 0 || !lineFragment._glyphsOffsets || index >= lineFragment._glyphsOffsets.length)
return 0.0;
var offset = lineFragment._glyphsOffsets[index];
return (offset === undefined) ? 0.0 : offset;
}
- (double)_descentAtLocation:(unsigned)location
@@ -719,7 +731,11 @@ _oncontextmenuhandler = function () { return false; };
var index = location - lineFragment._range.location;
return lineFragment._glyphsFrames[index]._descent;
if (index < 0 || !lineFragment._glyphsFrames || index >= lineFragment._glyphsFrames.length)
return 0.0;
var frame = lineFragment._glyphsFrames[index];
return (frame && frame._descent !== undefined) ? frame._descent : 0.0;
}
- (void)setLineFragmentRect:(CGRect)fragmentRect forGlyphRange:(CPRange)glyphRange usedRect:(CGRect)usedRect
@@ -843,11 +859,16 @@ _oncontextmenuhandler = function () { return false; };
{
if (_lineFragments.length > 0 && index >= [self numberOfGlyphs] - 1)
{
var lineFragment= _lineFragments[_lineFragments.length - 1],
var lineFragment = _lineFragments[_lineFragments.length - 1],
glyphFrames = [lineFragment glyphFrames];
if (glyphFrames.length > 0)
return CGPointCreateCopy(glyphFrames[glyphFrames.length - 1].origin);
if (glyphFrames && glyphFrames.length > 0)
{
var frame = glyphFrames[glyphFrames.length - 1];
if (frame)
return CGPointCreateCopy(frame.origin);
}
}
var lineFragment = _objectWithLocationInRange(_lineFragments, index);
@@ -858,8 +879,17 @@ _oncontextmenuhandler = function () { return false; };
return CGPointCreateCopy(lineFragment._location);
var glyphFrames = [lineFragment glyphFrames];
var relativeIndex = index - lineFragment._range.location;
return CGPointCreateCopy(glyphFrames[index - lineFragment._range.location].origin);
if (glyphFrames && relativeIndex >= 0 && relativeIndex < glyphFrames.length)
{
var frame = glyphFrames[relativeIndex];
if (frame)
return CGPointCreateCopy(frame.origin);
}
return CGPointCreateCopy(lineFragment._location);
}
return CGPointMakeZero();
@@ -905,7 +935,6 @@ _oncontextmenuhandler = function () { return false; };
inTextContainer:(CPTextContainer)container
rectCount:(CGRectPointer)rectCount
{
var rectArray = [],
lineFragments = _objectsInRange(_lineFragments, selectedCharRange);
@@ -924,21 +953,29 @@ _oncontextmenuhandler = function () { return false; };
rect = nil,
len = fragment._range.length;
for (var j = 0; j < len; j++)
if (frames)
{
if (CPLocationInRange(fragment._range.location + j, selectedCharRange))
for (var j = 0; j < len; j++)
{
var correctedRect = CGRectCreateCopy(frames[j]);
correctedRect.size.height -= frames[j]._descent;
correctedRect.origin.y -= frames[j]._descent;
if (j < frames.length && CPLocationInRange(fragment._range.location + j, selectedCharRange))
{
var frame = frames[j];
if (!rect)
rect = CGRectCreateCopy(correctedRect);
else
rect = CGRectUnion(rect, correctedRect);
if (frame)
{
var correctedRect = CGRectCreateCopy(frame);
correctedRect.size.height -= frame._descent;
correctedRect.origin.y -= frame._descent;
if (_isNewlineCharacter([[_textStorage string] characterAtIndex:MAX(0, CPMaxRange(selectedCharRange) - 1)]))
rect.size.width = containerSize.width - rect.origin.x;
if (!rect)
rect = CGRectCreateCopy(correctedRect);
else
rect = CGRectUnion(rect, correctedRect);
if (_isNewlineCharacter([[_textStorage string] characterAtIndex:MAX(0, CPMaxRange(selectedCharRange) - 1)]))
rect.size.width = containerSize.width - rect.origin.x;
}
}
}
}
@@ -949,7 +986,7 @@ _oncontextmenuhandler = function () { return false; };
var len = rectArray.length;
for (var i = 0; i < len - 1; i++) // extend the width of all but the last one
for (var i = 0; i < len - 1; i++)
{
if (FLOOR(CGRectGetMaxY(rectArray[i])) == FLOOR(CGRectGetMaxY(rectArray[i + 1])))
continue;
@@ -1182,13 +1219,9 @@ var _objectsInRange = function(aList, aRange)
{
if (![attributes objectForKey:_CPAttachmentInvisible])
{
var view = [attributes objectForKey:_CPAttachmentView],
viewCopy = [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:view]],
elem = viewCopy._DOMElement,
run = {_range:CPMakeRangeCopy(effectiveRange), color:nil, font:nil, elem:elem, string:nil, view:viewCopy};
var view = [attributes objectForKey:_CPAttachmentView];
var run = {_range:CPMakeRangeCopy(effectiveRange), color:nil, font:nil, elem:nil, string:nil, view:view}; }
_runs.push(run);
}
}
else
{
@@ -1269,13 +1302,11 @@ var _objectsInRange = function(aList, aRange)
for (var i = 0; i < l; i++)
{
if (_runs[i].view && _runs[i].DOMactive)
[_runs[i].view removeFromSuperview];
if (_runs[i].elem && _runs[i].DOMactive)
{
if (_runs[i].view)
[_runs[i].view removeFromSuperview];
else
_textContainer._textView._DOMElement.removeChild(_runs[i].elem);
}
_textContainer._textView._DOMElement.removeChild(_runs[i].elem);
_runs[i].elem = nil;
_runs[i].DOMactive = NO;
@@ -1288,6 +1319,9 @@ var _objectsInRange = function(aList, aRange)
c = runs.length,
orig = CGPointMake(_fragmentRect.origin.x, _fragmentRect.origin.y);
if (_runs.length === 0)
return;
for (var i = 0; i < c; i++)
{
var run = runs[i];
@@ -1302,13 +1336,21 @@ var _objectsInRange = function(aList, aRange)
continue;
var loc = run._range.location - _runs[0]._range.location;
// Safety bounds check to protect against uninitialized/empty glyph frames or offsets
if (loc < 0 || loc >= _glyphsFrames.length || !_glyphsFrames[loc] || !_glyphsOffsets || loc >= _glyphsOffsets.length)
continue;
orig.x = _glyphsFrames[loc].origin.x + aPoint.x;
orig.y = _glyphsFrames[loc].origin.y + aPoint.y + _glyphsOffsets[loc];
if(run.elem)
if(run.elem || run.view)
{
run.elem.style.left = (orig.x) + "px";
run.elem.style.top = (orig.y) + "px";
if (run.elem)
{
run.elem.style.left = (orig.x) + "px";
run.elem.style.top = (orig.y) + "px";
}
if (run.view)
[run.view setFrameOrigin:orig];
@@ -1316,8 +1358,9 @@ var _objectsInRange = function(aList, aRange)
if (!run.DOMactive)
{
if (run.view)
[self._textContainer._textView addSubview:run.view];
else
[_textContainer._textView addSubview:run.view];
if (run.elem)
_textContainer._textView._DOMElement.appendChild(run.elem);
}
@@ -1373,12 +1416,14 @@ var _objectsInRange = function(aList, aRange)
{
_runs[i]._range.location += rangeOffset;
if (verticalOffset && _runs[i].elem)
if (verticalOffset)
{
if (_runs[i].view)
_runs[i].view._frame.origin.y += verticalOffset;
_runs[i].elem.top = (_runs[i].elem.top + verticalOffset) + 'px';
if (_runs[i].elem)
_runs[i].elem.top = (_runs[i].elem.top + verticalOffset) + 'px';
_runs[i].DOMpatched = YES;
}
}
+21 -3
View File
@@ -401,6 +401,7 @@ var kDelegateRespondsTo_textShouldBeginEditing
- (void)superviewFrameChanged:(CPNotification)aNotification
{
_exposedRect = nil;
[self sizeToFit];
}
- (void)viewWillMoveToSuperview:(CPView)aView
@@ -1397,7 +1398,10 @@ Sets the selection to a range of characters in response to user action.
- (void)moveLeftAndModifySelection:(id)sender
{
if ([self isSelectable])
{
[self _extendSelectionIntoDirection:-1 granularity:CPSelectByCharacter];
[self scrollRangeToVisible:_selectionRange];
}
}
- (void)moveBackward:(id)sender
@@ -1419,7 +1423,10 @@ Sets the selection to a range of characters in response to user action.
- (void)moveLeft:(id)sender
{
if ([self isSelectable])
{
[self _establishSelection:CPMakeRange(_selectionRange.location - (_selectionRange.length ? 0 : 1), 0) byExtending:NO];
[self scrollRangeToVisible:_selectionRange];
}
}
- (void)moveToEndOfParagraph:(id)sender
@@ -2134,9 +2141,15 @@ Sets the selection to a range of characters in response to user action.
if (CPEmptyRange(aRange))
{
if (aRange.location >= [_layoutManager numberOfCharacters])
rect = [_layoutManager extraLineFragmentRect];
{
rect = CGRectCreateCopy([_layoutManager extraLineFragmentRect]);
rect.size.width = 1.0;
}
else
rect = [_layoutManager lineFragmentRectForGlyphAtIndex:aRange.location effectiveRange:nil];
{
rect = CGRectCreateCopy([_layoutManager boundingRectForGlyphRange:CPMakeRange(aRange.location, 1) inTextContainer:_textContainer]);
rect.size.width = 1.0;
}
}
else
{
@@ -2851,11 +2864,16 @@ var CPTextViewAllowsUndoKey = @"CPTextViewAllowsUndoKey",
_typingAttributes = [[_textStorage attributesAtIndex:0 effectiveRange:nil] copy];
if (!_typingAttributes)
_typingAttributes = [CPMutableDictionary dictionary];
if (![_typingAttributes valueForKey:CPForegroundColorAttributeName])
[_typingAttributes setObject:[CPColor blackColor] forKey:CPForegroundColorAttributeName];
_textColor = [_typingAttributes valueForKey:CPForegroundColorAttributeName];
[self setFont:[_typingAttributes valueForKey:CPFontAttributeName]];
var decodedFont = [_typingAttributes valueForKey:CPFontAttributeName] || [CPFont systemFontOfSize:12.0];
[self setFont:decodedFont];
[self setString:[_textStorage string]];
+131 -62
View File
@@ -16,8 +16,7 @@
* 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 "CPView.j"
@import "CPTextView.j"
@@ -28,6 +27,7 @@
{
CPArray _headers;
CPArray _rows;
BOOL _isResizing;
}
- (id)initWithHeaders:(CPArray)headers rows:(CPArray)rows
@@ -42,30 +42,41 @@
{
_headers = headers;
_rows = rows;
_isResizing = NO;
var numCols = [headers count];
[self _rebuildTableWithWidth:totalWidth];
}
if (numCols == 0 && [rows count] > 0)
numCols = [[rows objectAtIndex:0] count];
return self;
}
// Apply borders on the outer left and top container edges
if (self._DOMElement) {
self._DOMElement.style.borderTop = "1px solid #e0e0e0";
self._DOMElement.style.borderLeft = "1px solid #e0e0e0";
- (void)_rebuildTableWithWidth:(float)totalWidth
{
var numCols = _headers ? [_headers count] : 0;
if (numCols == 0 && _rows && [_rows count] > 0)
numCols = [[_rows objectAtIndex:0] count];
// Apply borders on the outer left and top container edges
if (self._DOMElement) {
self._DOMElement.style.borderTop = "1px solid #e0e0e0";
self._DOMElement.style.borderLeft = "1px solid #e0e0e0";
self._DOMElement.style.boxSizing = "border-box";
}
// Initialize header cells
if (_headers && [_headers count] > 0) {
for (var c = 0; c < numCols; c++) {
var headerText = [_headers objectAtIndex:c];
var cellView = [self createCellWithText:headerText frame:CGRectMakeZero() isHeader:YES];
[self addSubview:cellView];
}
// Initialize header cells
if ([headers count] > 0) {
for (var c = 0; c < numCols; c++) {
var headerText = [headers objectAtIndex:c];
var cellView = [self createCellWithText:headerText frame:CGRectMakeZero() isHeader:YES];
[self addSubview:cellView];
}
}
// Initialize body rows
for (var r = 0; r < [rows count]; r++) {
var rowData = [rows objectAtIndex:r];
}
// Initialize body rows
if (_rows) {
for (var r = 0; r < [_rows count]; r++) {
var rowData = [_rows objectAtIndex:r];
for (var c = 0; c < numCols; c++) {
var cellText = @"";
@@ -76,10 +87,53 @@
[self addSubview:cellView];
}
}
[self resizeToWidth:totalWidth];
}
return self;
[self resizeToWidth:totalWidth];
// Trigger a parent layout manager re-layout once the table is fully reconstructed and sized.
var textView = [self superview];
if (textView && [textView isKindOfClass:[CPTextView class]])
{
var layoutManager = [textView layoutManager];
if (layoutManager)
{
var charRange = [self _findCharacterRangeInLayoutManager:layoutManager];
if (charRange && charRange.location !== CPNotFound)
{
[layoutManager invalidateLayoutForCharacterRange:charRange isSoft:NO actualCharacterRange:nil];
[layoutManager invalidateDisplayForGlyphRange:charRange];
[layoutManager _validateLayoutAndGlyphs];
[textView sizeToFit];
}
}
}
}
- (CPRange)_findCharacterRangeInLayoutManager:(CPLayoutManager)layoutManager
{
var lineFragments = layoutManager._lineFragments;
if (lineFragments)
{
var l = lineFragments.length;
for (var i = 0; i < l; i++)
{
var fragment = lineFragments[i];
var runs = fragment._runs;
if (runs)
{
var rc = runs.length;
for (var j = 0; j < rc; j++)
{
if (runs[j].view === self)
{
return runs[j]._range;
}
}
}
}
}
return CPMakeRange(CPNotFound, 0);
}
- (CPArray)headers
@@ -94,6 +148,7 @@
- (CPView)viewForWidth:(float)width
{
// Always call resize to ensure cell views are constructed, but do not guard here
[self resizeToWidth:width];
return self;
}
@@ -110,7 +165,9 @@
var borderView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, initialWidth, initialHeight)];
[borderView setBackgroundColor:[CPColor clearColor]];
[borderView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
if (borderView._DOMElement) {
if (borderView._DOMElement)
{
borderView._DOMElement.style.borderBottom = "1px solid #e0e0e0";
borderView._DOMElement.style.borderRight = "1px solid #e0e0e0";
borderView._DOMElement.style.boxSizing = "border-box";
@@ -119,29 +176,18 @@
var textContainer = [[CPTextContainer alloc] initWithContainerSize:CGSizeMake(initialWidth - 8, 1e7)];
var textView = [[CPTextView alloc] initWithFrame:CGRectMake(4, 2, initialWidth - 8, initialHeight - 4) textContainer:textContainer];
[textView setEditable:NO];
[textView setEditable:YES];
[textView setSelectable:YES];
[textView setBackgroundColor:[CPColor clearColor]];
[textView setVerticallyResizable:YES];
[textView setHorizontallyResizable:NO];
[[textView textContainer] setWidthTracksTextView:YES];
// Construct cell text using standard fonts
// Configure cell text style using standard CPTextView APIs
var cellFont = isHeader ? [CPFont boldSystemFontOfSize:11.0] : [CPFont systemFontOfSize:11.0];
var parsedText = [[CPAttributedString alloc] initWithString:text attributes:@{
CPFontAttributeName: cellFont,
CPForegroundColorAttributeName: [CPColor blackColor]
}];
var storage = [textView textStorage];
if (storage && [storage respondsToSelector:@selector(setAttributedString:)]) {
[storage setAttributedString:parsedText];
} else {
[textView setEditable:YES];
[textView setString:@""];
[textView insertText:parsedText];
[textView setEditable:NO];
}
[textView setFont:cellFont];
[textView setTextColor:[CPColor blackColor]];
[textView setString:text];
[cellContainer addSubview:textView];
return cellContainer;
@@ -161,11 +207,19 @@
- (void)resizeToWidth:(float)newWidth
{
var numCols = [_headers count];
if (numCols == 0 && [_rows count] > 0) {
if (_isResizing)
return;
_isResizing = YES;
var numCols = _headers ? [_headers count] : 0;
if (numCols == 0 && _rows && [_rows count] > 0) {
numCols = [[_rows objectAtIndex:0] count];
}
if (numCols == 0) return;
if (numCols == 0) {
_isResizing = NO;
return;
}
var subviews = [self subviews];
var colNaturalWidths = [];
@@ -206,18 +260,22 @@
}
};
for (var c = 0; c < [_headers count]; c++) {
measureCell([_headers objectAtIndex:c], YES, c);
if (_headers) {
for (var c = 0; c < [_headers count]; c++) {
measureCell([_headers objectAtIndex:c], YES, c);
}
}
for (var r = 0; r < [_rows count]; r++) {
var rowData = [_rows objectAtIndex:r];
for (var c = 0; c < numCols; c++) {
var cellText = @"";
if (c < [rowData count]) {
cellText = [rowData objectAtIndex:c];
if (_rows) {
for (var r = 0; r < [_rows count]; r++) {
var rowData = [_rows objectAtIndex:r];
for (var c = 0; c < numCols; c++) {
var cellText = @"";
if (c < [rowData count]) {
cellText = [rowData objectAtIndex:c];
}
measureCell(cellText, NO, c);
}
measureCell(cellText, NO, c);
}
}
@@ -279,8 +337,9 @@
var targetWidth = Math.max(10.0, colWidths[c] - 8);
[[textView textContainer] setContainerSize:CGSizeMake(targetWidth, 1e7)];
var usedRect = [[textView layoutManager] usedRectForTextContainer:[textView textContainer]];
var wrappedHeight = CGRectGetHeight(usedRect) + 12.0;
var layoutManager = [textView layoutManager];
var usedRect = layoutManager ? [layoutManager usedRectForTextContainer:[textView textContainer]] : nil;
var wrappedHeight = (usedRect ? CGRectGetHeight(usedRect) : 0.0) + 12.0;
if (wrappedHeight > maxCellHeight) {
maxCellHeight = wrappedHeight;
}
@@ -314,19 +373,29 @@
return maxCellHeight;
};
if ([_headers count] > 0) {
if (_headers && [_headers count] > 0) {
var headerHeight = layoutRow(cellIndex);
cellIndex += numCols;
currentY += headerHeight;
}
for (var r = 0; r < [_rows count]; r++) {
var rowHeight = layoutRow(cellIndex);
cellIndex += numCols;
currentY += rowHeight;
if (_rows) {
for (var r = 0; r < [_rows count]; r++) {
var rowHeight = layoutRow(cellIndex);
cellIndex += numCols;
currentY += rowHeight;
}
}
[self setFrameSize:CGSizeMake(newWidth, currentY)];
// GUARD FRAME SIZE MUTATIONS: Only execute setFrameSize if dimensions actually change.
// This stops infinite layout passes while ensuring subviews are laid out.
var currentSize = [self frame].size;
if (ABS(currentSize.width - newWidth) > 0.1 || ABS(currentSize.height - currentY) > 0.1)
{
[self setFrameSize:CGSizeMake(newWidth, currentY)];
}
_isResizing = NO;
}
@end
+33 -1
View File
@@ -14,6 +14,8 @@
@import <AppKit/CPTextField.j>
@import <AppKit/CPScrollView.j>
@import <AppKit/CPParagraphStyle.j>
@import <AppKit/CPTextStorage.j>
@import <AppKit/_CPTableTextAttachment.j>
@implementation AppController : CPObject
{
@@ -90,6 +92,25 @@
[_textView insertText:@" "];
}
- (void)insertTable:(id)sender
{
var headers = [@"Item Description", @"Quantity", @"Unit Price"];
var rows = [
[@"Cappuccino Web Framework Lic.", @"2", @"$199.00"],
[@"Objective-J Development Support", @"5", @"$150.00"],
[@"Cloud Compilation VM Server", @"1", @"$49.00"]
];
var tableAttachment = [[_CPTableTextAttachment alloc] initWithHeaders:headers rows:rows width:500.0];
// Insert single-character atomic text attachment
var tableAttrStr = [CPTextStorage attributedStringWithAttachment:tableAttachment];
[_textView insertText:@"\ntable (own line)\n"];
[_textView insertText:tableAttrStr];
[_textView insertText:@"\nend table"];
}
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask],
@@ -145,6 +166,14 @@
[toolbarView addSubview:attachButton];
currentX += 150;
// Add Table Trigger
var tableButton = [[CPButton alloc] initWithFrame:CGRectMake(currentX, 15, 100, 30)];
[tableButton setTitle:@"Add Table"];
[tableButton setTarget:self];
[tableButton setAction:@selector(insertTable:)];
[toolbarView addSubview:tableButton];
currentX += 110;
// Text Alignment Group
var labelAlign = [[CPTextField alloc] initWithFrame:CGRectMake(currentX, 22, 45, 20)];
[labelAlign setStringValue:@"Align:"];
@@ -210,9 +239,10 @@
[leftLabel setAutoresizingMask:CPViewWidthSizable];
[leftContainer addSubview:leftLabel];
_textView = [[CPTextView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth([leftContainer bounds]) - 30, CGRectGetHeight([leftContainer bounds]) - 70)];
_textView = [[CPTextView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth([leftContainer bounds]) - 30, 0)];
[_textView setRichText:YES];
[_textView setBackgroundColor:[CPColor whiteColor]];
[[_textView textContainer] setWidthTracksTextView:YES];
_scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(15, 40, CGRectGetWidth([leftContainer bounds]) - 30, CGRectGetHeight([leftContainer bounds]) - 65)];
[_scrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
@@ -321,6 +351,8 @@
[_textView insertText:[[CPAttributedString alloc] initWithString:@"This paragraph has a first-line indent of 30pt, a head indent of 50pt, and a tail indent of -30pt. Check the horizontal ruler above to see how the indent markers align with this paragraph, and adjust them directly!\n"
attributes:[CPDictionary dictionaryWithObject:indentParagraph forKey:CPParagraphStyleAttributeName]]];
[_textView insertText:@"\n"];
[theWindow orderFront:self];
[CPMenu setMenuBarVisible:YES];
}