fixed: basic ruler view support

This commit is contained in:
daboe01
2026-05-29 10:46:10 +02:00
parent 1d93cf2b1a
commit c94ed00f41
6 changed files with 742 additions and 1133 deletions
+13 -4
View File
@@ -29,6 +29,7 @@
@import "CPClipView.j"
@import "CPScroller.j"
@import "CPView.j"
@import "CPRulerView.j"
@class CPTableView
@class CPRulerView
@@ -824,7 +825,7 @@ Notifies the delegate when the scroll view has finished scrolling.
if (_hasHorizontalRuler && !_horizontalRuler)
{
_horizontalRuler = [[CPRulerView alloc] initWithScrollView:self orientation:CPHorizontalRuler];
_horizontalRuler = [[CPRulerView alloc] initWithScrollView:self orientation:CPRulerOrientationHorizontal];
}
[self tile];
@@ -844,7 +845,7 @@ Notifies the delegate when the scroll view has finished scrolling.
if (_hasVerticalRuler && !_verticalRuler)
{
_verticalRuler = [[CPRulerView alloc] initWithScrollView:self orientation:CPVerticalRuler];
_verticalRuler = [[CPRulerView alloc] initWithScrollView:self orientation:CPRulerOrientationVertical];
}
[self tile];
@@ -1428,7 +1429,11 @@ Notifies the delegate when the scroll view has finished scrolling.
CGRectGetWidth(contentFrame),
horizRulerThickness
)];
[_horizontalRuler setNeedsDisplay:YES];
if ([_horizontalRuler respondsToSelector:@selector(updateRuler)])
[_horizontalRuler updateRuler];
else
[_horizontalRuler setNeedsDisplay:YES];
}
if (showVerticalRuler)
@@ -1439,7 +1444,11 @@ Notifies the delegate when the scroll view has finished scrolling.
vertRulerThickness,
CGRectGetHeight(contentFrame)
)];
[_verticalRuler setNeedsDisplay:YES];
if ([_verticalRuler respondsToSelector:@selector(updateRuler)])
[_verticalRuler updateRuler];
else
[_verticalRuler setNeedsDisplay:YES];
}
--_recursionCount;
+91 -81
View File
@@ -217,24 +217,112 @@ var _sharedDefaultParagraphStyle = nil;
@end
// MARK: - CPMutableParagraphStyle Implementation
// MARK: - CPMutableParagraphStyle Implementation
@implementation CPMutableParagraphStyle : CPParagraphStyle
{
}
- (id)initWithParagraphStyle:(CPParagraphStyle)other
{
if (self = [super initWithParagraphStyle:other])
{
// Ensure our tab stops array is mutable in the mutable subclass
_tabStops = [[other tabStops] mutableCopy];
}
return self;
}
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_tabStops = [_tabStops mutableCopy];
}
return self;
}
- (void)setLineSpacing:(float)aLineSpacing
{
_lineSpacing = aLineSpacing;
}
- (void)setParagraphSpacing:(float)aParagraphSpacing
{
_paragraphSpacing = aParagraphSpacing;
}
- (void)setAlignment:(CPTextAlignment)anAlignment
{
_alignment = anAlignment;
}
- (void)setHeadIndent:(float)aHeadIndent
{
_headIndent = aHeadIndent;
}
- (void)setTailIndent:(float)aTailIndent
{
_tailIndent = aTailIndent;
}
- (void)setFirstLineHeadIndent:(float)aFirstLineHeadIndent
{
_firstLineHeadIndent = aFirstLineHeadIndent;
}
- (void)setMinimumLineHeight:(float)aMinimumLineHeight
{
_minimumLineHeight = aMinimumLineHeight;
}
- (void)setMaximumLineHeight:(float)aMaximumLineHeight
{
_maximumLineHeight = aMaximumLineHeight;
}
- (void)setLineBreakMode:(CPLineBreakMode)aLineBreakMode
{
_lineBreakMode = aLineBreakMode;
}
- (void)setBaseWritingDirection:(CPWritingDirection)aBaseWritingDirection
{
_baseWritingDirection = aBaseWritingDirection;
}
- (void)setLineHeightMultiple:(float)aLineHeightMultiple
{
_lineHeightMultiple = aLineHeightMultiple;
}
- (void)setParagraphSpacingBefore:(float)aParagraphSpacingBefore
{
_paragraphSpacingBefore = aParagraphSpacingBefore;
}
- (void)setDefaultTabInterval:(float)aDefaultTabInterval
{
_defaultTabInterval = aDefaultTabInterval;
}
- (void)addTabStop:(CPTextTab)aTabStop
{
// Copy on write logic would go here if we shared structure,
// but here we just mutate the array.
[_tabStops addObject:aTabStop];
}
- (void)removeTabStop:(CPTextTab)aTabStop
{
[_tabStops removeObject:aTabStop];
}
- (void)setTabStops:(CPArray)newTabStops
{
if (_tabStops === newTabStops) return;
_tabStops = [newTabStops copy];
_tabStops = [newTabStops mutableCopy];
}
- (id)copyWithZone:(CPZone)aZone
@@ -244,81 +332,3 @@ var _sharedDefaultParagraphStyle = nil;
}
@end
// MARK: - CPCoding
var CPParagraphStyleLineSpacingKey = @"CPParagraphStyleLineSpacingKey",
CPParagraphStyleParagraphSpacingKey = @"CPParagraphStyleParagraphSpacingKey",
CPParagraphStyleAlignmentKey = @"CPParagraphStyleAlignmentKey",
CPParagraphStyleHeadIndentKey = @"CPParagraphStyleHeadIndentKey",
CPParagraphStyleTailIndentKey = @"CPParagraphStyleTailIndentKey",
CPParagraphStyleFirstLineHeadIndentKey = @"CPParagraphStyleFirstLineHeadIndentKey",
CPParagraphStyleMinimumLineHeightKey = @"CPParagraphStyleMinimumLineHeightKey",
CPParagraphStyleMaximumLineHeightKey = @"CPParagraphStyleMaximumLineHeightKey",
CPParagraphStyleLineBreakModeKey = @"CPParagraphStyleLineBreakModeKey",
CPParagraphStyleTabStopsKey = @"CPParagraphStyleTabStopsKey",
CPParagraphStyleBaseWritingDirectionKey = @"CPParagraphStyleBaseWritingDirectionKey",
CPParagraphStyleLineHeightMultipleKey = @"CPParagraphStyleLineHeightMultipleKey",
CPParagraphStyleParagraphSpacingBeforeKey = @"CPParagraphStyleParagraphSpacingBeforeKey",
CPParagraphStyleDefaultTabIntervalKey = @"CPParagraphStyleDefaultTabIntervalKey";
@implementation CPParagraphStyle (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super init])
{
_lineSpacing = [aCoder decodeFloatForKey:CPParagraphStyleLineSpacingKey];
_paragraphSpacing = [aCoder decodeFloatForKey:CPParagraphStyleParagraphSpacingKey];
_alignment = [aCoder decodeIntForKey:CPParagraphStyleAlignmentKey];
_headIndent = [aCoder decodeFloatForKey:CPParagraphStyleHeadIndentKey];
_tailIndent = [aCoder decodeFloatForKey:CPParagraphStyleTailIndentKey];
_firstLineHeadIndent = [aCoder decodeFloatForKey:CPParagraphStyleFirstLineHeadIndentKey];
_minimumLineHeight = [aCoder decodeFloatForKey:CPParagraphStyleMinimumLineHeightKey];
_maximumLineHeight = [aCoder decodeFloatForKey:CPParagraphStyleMaximumLineHeightKey];
_lineBreakMode = [aCoder decodeIntForKey:CPParagraphStyleLineBreakModeKey];
_tabStops = [aCoder decodeObjectForKey:CPParagraphStyleTabStopsKey];
// Handle potential missing keys for backward compatibility or new properties
if ([aCoder containsValueForKey:CPParagraphStyleBaseWritingDirectionKey])
_baseWritingDirection = [aCoder decodeIntForKey:CPParagraphStyleBaseWritingDirectionKey];
else
_baseWritingDirection = CPWritingDirectionNatural;
if ([aCoder containsValueForKey:CPParagraphStyleLineHeightMultipleKey])
_lineHeightMultiple = [aCoder decodeFloatForKey:CPParagraphStyleLineHeightMultipleKey];
if ([aCoder containsValueForKey:CPParagraphStyleParagraphSpacingBeforeKey])
_paragraphSpacingBefore = [aCoder decodeFloatForKey:CPParagraphStyleParagraphSpacingBeforeKey];
if ([aCoder containsValueForKey:CPParagraphStyleDefaultTabIntervalKey])
_defaultTabInterval = [aCoder decodeFloatForKey:CPParagraphStyleDefaultTabIntervalKey];
else
_defaultTabInterval = kDefaultTabInterval;
if (!_tabStops) _tabStops = [];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeFloat:_lineSpacing forKey:CPParagraphStyleLineSpacingKey];
[aCoder encodeFloat:_paragraphSpacing forKey:CPParagraphStyleParagraphSpacingKey];
[aCoder encodeInt:_alignment forKey:CPParagraphStyleAlignmentKey];
[aCoder encodeFloat:_headIndent forKey:CPParagraphStyleHeadIndentKey];
[aCoder encodeFloat:_tailIndent forKey:CPParagraphStyleTailIndentKey];
[aCoder encodeFloat:_firstLineHeadIndent forKey:CPParagraphStyleFirstLineHeadIndentKey];
[aCoder encodeFloat:_minimumLineHeight forKey:CPParagraphStyleMinimumLineHeightKey];
[aCoder encodeFloat:_maximumLineHeight forKey:CPParagraphStyleMaximumLineHeightKey];
[aCoder encodeInt:_lineBreakMode forKey:CPParagraphStyleLineBreakModeKey];
[aCoder encodeObject:_tabStops forKey:CPParagraphStyleTabStopsKey];
[aCoder encodeInt:_baseWritingDirection forKey:CPParagraphStyleBaseWritingDirectionKey];
[aCoder encodeFloat:_lineHeightMultiple forKey:CPParagraphStyleLineHeightMultipleKey];
[aCoder encodeFloat:_paragraphSpacingBefore forKey:CPParagraphStyleParagraphSpacingBeforeKey];
[aCoder encodeFloat:_defaultTabInterval forKey:CPParagraphStyleDefaultTabIntervalKey];
}
@end
File diff suppressed because it is too large Load Diff
+234 -1
View File
@@ -542,12 +542,15 @@ var kDelegateRespondsTo_textShouldBeginEditing
- (void)_becomeFirstResponder
{
[self updateInsertionPointStateAndRestartTimer:YES];
// SYNCHRONIZE ACTIVE PARAGRAPH MARKERS ON EDITOR FOCUS
[self updateRuler];
[[CPFontManager sharedFontManager] setSelectedFont:[self font] isMultiple:NO];
[self setNeedsDisplay:YES];
[[CPRunLoop currentRunLoop] performSelector:@selector(focusForTextView:) target:[_CPNativeInputManager class] argument:self order:0 modes:[CPDefaultRunLoopMode]];
}
- (BOOL)becomeFirstResponder
{
[super becomeFirstResponder];
@@ -1783,6 +1786,9 @@ Sets the selection to a range of characters in response to user action.
[self _enrichEssentialTypingAttributes:_typingAttributes];
}
// SYNCHRONIZE ACTIVE PARAGRAPH MARKERS ON TYPING ATTRIBUTES CHANGE
[self updateRuler];
[[CPNotificationCenter defaultCenter] postNotificationName:CPTextViewDidChangeTypingAttributesNotification object:self];
// We always clear the saved selection range from the last mouse down event here.
@@ -2406,6 +2412,233 @@ Sets the selection to a range of characters in response to user action.
@end
@implementation CPTextView (CPRulerSupport)
- (void)updateRuler
{
var scrollView = [self enclosingScrollView];
if (!scrollView || ![scrollView hasHorizontalRuler] || ![scrollView rulersVisible])
return;
var ruler = [scrollView horizontalRulerView];
if (!ruler)
return;
var selectedRange = [self selectedRange],
paragraphStyle = [CPParagraphStyle defaultParagraphStyle],
currentAttributes = _typingAttributes;
var textLength = [_textStorage length];
if (textLength > 0)
{
var charIndex = selectedRange.location;
// Safety bounds checks for cursor placements
if (charIndex >= textLength)
charIndex = textLength - 1;
if (charIndex < 0)
charIndex = 0;
currentAttributes = [_textStorage attributesAtIndex:charIndex effectiveRange:nil];
}
if ([currentAttributes objectForKey:CPParagraphStyleAttributeName])
paragraphStyle = [currentAttributes objectForKey:CPParagraphStyleAttributeName];
var markers = [],
tabStops = [paragraphStyle tabStops],
count = [tabStops count];
// A. Load existing tab stop markers onto the ruler
for (var i = 0; i < count; i++)
{
var tab = [tabStops objectAtIndex:i],
marker = [[CPRulerMarker alloc] initWithRulerView:ruler
markerLocation:[tab location]
imageValue:[tab location]
representedObject:tab];
[markers addObject:marker];
}
// B. Add Indentation Handles (First line indent & Head indent)
var firstLineMarker = [[CPRulerMarker alloc] initWithRulerView:ruler
markerLocation:[paragraphStyle firstLineHeadIndent]
imageValue:[paragraphStyle firstLineHeadIndent]
representedObject:@"CPFirstLineIndent"];
[firstLineMarker._label setStringValue:@"▼"]; // downward arrow styling
[markers addObject:firstLineMarker];
var headMarker = [[CPRulerMarker alloc] initWithRulerView:ruler
markerLocation:[paragraphStyle headIndent]
imageValue:[paragraphStyle headIndent]
representedObject:@"CPHeadIndent"];
[headMarker._label setStringValue:@"▼"];
[markers addObject:headMarker];
[ruler setMarkers:markers];
}
// Local comparison function helper for tab sorting
var compareTabStops = function(obj1, obj2, context) {
if ([obj1 location] < [obj2 location]) return CPOrderedAscending;
if ([obj1 location] > [obj2 location]) return CPOrderedDescending;
return CPOrderedSame;
};
- (void)rulerView:(CPRulerView)rulerView didAddMarker:(CPRulerMarker)marker
{
if (![self _didBeginEditing] || ![self shouldChangeTextInRange:_selectionRange replacementString:nil])
return;
var selectedRange = [self selectedRange],
paragraphStyle = [CPParagraphStyle defaultParagraphStyle],
currentAttributes = _typingAttributes;
if (selectedRange.length > 0)
currentAttributes = [_textStorage attributesAtIndex:selectedRange.location effectiveRange:nil];
if ([currentAttributes objectForKey:CPParagraphStyleAttributeName])
paragraphStyle = [currentAttributes objectForKey:CPParagraphStyleAttributeName];
var mutableStyle = [paragraphStyle mutableCopy];
// Create a new Left-aligned tab stop where the user clicked
var newTab = [[CPTextTab alloc] initWithType:CPLeftTextAlignment location:[marker imageValue]],
tabs = [[mutableStyle tabStops] mutableCopy];
[tabs addObject:newTab];
// Sort tabs by location ascending
[tabs sortUsingFunction:compareTabStops context:nil];
[mutableStyle setTabStops:tabs];
[marker setRepresentedObject:newTab];
if (selectedRange.length > 0)
{
[_textStorage addAttribute:CPParagraphStyleAttributeName value:mutableStyle range:CPMakeRangeCopy(selectedRange)];
[_layoutManager textStorage:_textStorage
edited:0
range:CPMakeRangeCopy(selectedRange)
changeInLength:0
invalidatedRange:CPMakeRangeCopy(selectedRange)];
}
else
{
[_typingAttributes setObject:mutableStyle forKey:CPParagraphStyleAttributeName];
[[CPNotificationCenter defaultCenter] postNotificationName:CPTextViewDidChangeTypingAttributesNotification object:self];
}
}
- (void)rulerView:(CPRulerView)rulerView didMoveMarker:(CPRulerMarker)marker
{
if (![self _didBeginEditing] || ![self shouldChangeTextInRange:_selectionRange replacementString:nil])
return;
var selectedRange = [self selectedRange],
paragraphStyle = [CPParagraphStyle defaultParagraphStyle],
currentAttributes = _typingAttributes;
if (selectedRange.length > 0)
currentAttributes = [_textStorage attributesAtIndex:selectedRange.location effectiveRange:nil];
if ([currentAttributes objectForKey:CPParagraphStyleAttributeName])
paragraphStyle = [currentAttributes objectForKey:CPParagraphStyleAttributeName];
var mutableStyle = [paragraphStyle mutableCopy],
oldTab = [marker representedObject];
if (!oldTab)
return;
// A. Handle standard tab stops
if ([oldTab isKindOfClass:[CPTextTab class]])
{
var newTab = [[CPTextTab alloc] initWithType:[oldTab alignment] location:[marker imageValue]],
tabs = [[mutableStyle tabStops] mutableCopy];
[tabs removeObject:oldTab];
[tabs addObject:newTab];
// Sort tabs by location ascending
[tabs sortUsingFunction:compareTabStops context:nil];
[mutableStyle setTabStops:tabs];
[marker setRepresentedObject:newTab];
}
// B. Handle Indentation Marker drags (First Line, Left, and Right indents)
else if ([oldTab isKindOfClass:[CPString class]])
{
if (oldTab === @"CPFirstLineIndent")
[mutableStyle setFirstLineHeadIndent:[marker imageValue]];
else if (oldTab === @"CPHeadIndent")
[mutableStyle setHeadIndent:[marker imageValue]];
else if (oldTab === @"CPTailIndent")
[mutableStyle setTailIndent:[marker imageValue]];
}
if (selectedRange.length > 0)
{
[_textStorage addAttribute:CPParagraphStyleAttributeName value:mutableStyle range:CPMakeRangeCopy(selectedRange)];
[_layoutManager textStorage:_textStorage
edited:0
range:CPMakeRangeCopy(selectedRange)
changeInLength:0
invalidatedRange:CPMakeRangeCopy(selectedRange)];
}
else
{
[_typingAttributes setObject:mutableStyle forKey:CPParagraphStyleAttributeName];
[[CPNotificationCenter defaultCenter] postNotificationName:CPTextViewDidChangeTypingAttributesNotification object:self];
}
}
- (void)rulerView:(CPRulerView)rulerView didRemoveMarker:(CPRulerMarker)marker
{
if (![self _didBeginEditing] || ![self shouldChangeTextInRange:_selectionRange replacementString:nil])
return;
var selectedRange = [self selectedRange],
paragraphStyle = [CPParagraphStyle defaultParagraphStyle],
currentAttributes = _typingAttributes;
if (selectedRange.length > 0)
currentAttributes = [_textStorage attributesAtIndex:selectedRange.location effectiveRange:nil];
if ([currentAttributes objectForKey:CPParagraphStyleAttributeName])
paragraphStyle = [currentAttributes objectForKey:CPParagraphStyleAttributeName];
var mutableStyle = [paragraphStyle mutableCopy],
oldTab = [marker representedObject];
if (!oldTab)
return;
var tabs = [[mutableStyle tabStops] mutableCopy];
[tabs removeObject:oldTab];
[mutableStyle setTabStops:tabs];
if (selectedRange.length > 0)
{
[_textStorage addAttribute:CPParagraphStyleAttributeName value:mutableStyle range:CPMakeRangeCopy(selectedRange)];
[_layoutManager textStorage:_textStorage
edited:0
range:CPMakeRangeCopy(selectedRange)
changeInLength:0
invalidatedRange:CPMakeRangeCopy(selectedRange)];
}
else
{
[_typingAttributes setObject:mutableStyle forKey:CPParagraphStyleAttributeName];
[[CPNotificationCenter defaultCenter] postNotificationName:CPTextViewDidChangeTypingAttributesNotification object:self];
}
}
@end
@implementation CPTextView (CPTextViewDelegate)
+54 -8
View File
@@ -135,29 +135,34 @@ var CPSystemTypesetterFactory,
return [_layoutManager textContainers];
}
// Retrieves correct CPTextTab stop accounting for CPArray properties
- (CPTextTab)textTabForWidth:(double)aWidth writingDirection:(CPWritingDirection)direction
{
var tabStops = [_currentParagraph tabStops];
if (!tabStops)
tabStops = [CPParagraphStyle _defaultTabStops];
tabStops = [[CPParagraphStyle defaultParagraphStyle] tabStops];
var l = tabStops.length;
var l = [tabStops count];
if (l === 0)
return nil;
if (aWidth > tabStops[l - 1]._location)
var lastTab = [tabStops lastObject];
if (aWidth > [lastTab location])
return nil;
for (var i = l - 1; i >= 0; i--)
{
if (aWidth > tabStops[i]._location)
var tab = [tabStops objectAtIndex:i];
if (aWidth > [tab location])
{
if (i + 1 < l)
return tabStops[i + 1];
return [tabStops objectAtIndex:i + 1];
}
}
if (i === -1)
return tabStops[0];
return [tabStops objectAtIndex:0];
return nil;
}
@@ -356,9 +361,50 @@ var CPSystemTypesetterFactory,
isTabStop = YES;
if (nextTab)
rangeWidth = nextTab._location - lineOrigin.x;
{
// Look-ahead to measure the width of the incoming text segment for alignment
var nextSegmentWidth = 0.0,
tempIndex = glyphIndex + 1,
segmentString = "";
while (tempIndex < numberOfGlyphs)
{
var nextCharCode = theString.charCodeAt(tempIndex);
if (nextCharCode === 9 || nextCharCode === 10 || nextCharCode === 13)
break;
segmentString += theString.charAt(tempIndex);
tempIndex++;
}
if (segmentString.length > 0)
nextSegmentWidth = [segmentString sizeWithFont:currentFont inWidth:NULL].width;
var tabLocation = [nextTab location],
tabAlignment = [nextTab alignment];
// Mathematically offset the tab character's right boundary
if (tabAlignment === CPCenterTextAlignment)
{
rangeWidth = (tabLocation - nextSegmentWidth / 2.0) - lineOrigin.x;
}
else if (tabAlignment === CPRightTextAlignment)
{
rangeWidth = (tabLocation - nextSegmentWidth) - lineOrigin.x;
}
else // Left align tab stop
{
rangeWidth = tabLocation - lineOrigin.x;
}
// Enforce a minimum safety spacer width to avoid character overlapping
var minRangeWidth = prevRangeWidth + 5.0;
if (rangeWidth < minRangeWidth)
rangeWidth = minRangeWidth;
}
else
rangeWidth += 28; //FIXME
{
rangeWidth += 28.0; // standard fallback spacer
}
} // fallthrough intentional
case 32: // ' '
wrapRange = CPMakeRangeCopy(lineRange);
+56 -36
View File
@@ -75,6 +75,21 @@
[_textView alignJustified:self];
}
- (void)insertAttachment:(id)sender
{
// Insert modern spinner image attachment
var tempImageView = [[CPImageView alloc] initWithFrame:CGRectMake(0, 0, 32, 32)];
[tempImageView setImage:[[CPImage alloc] initWithContentsOfFile:@"Resources/spinner.gif" size:CGSizeMake(32, 32)]];
[_textView insertText:[CPTextStorage attributedStringWithAttachment:tempImageView]];
[_textView insertText:@" "];
// Insert an interactive button attachment
var tempButton = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 80, 28)];
[tempButton setTitle:@"Click Me"];
[_textView insertText:[CPTextStorage attributedStringWithAttachment:tempButton]];
[_textView insertText:@" "];
}
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask],
@@ -112,7 +127,7 @@
[rulerButton setTarget:self];
[rulerButton setAction:@selector(toggleRuler:)];
[toolbarView addSubview:rulerButton];
currentX += 140;
currentX += 130;
// RTF Roundtrip Trigger
var rtfButton = [[CPButton alloc] initWithFrame:CGRectMake(currentX, 15, 150, 30)];
@@ -120,7 +135,15 @@
[rtfButton setTarget:self];
[rtfButton setAction:@selector(makeRTF:)];
[toolbarView addSubview:rtfButton];
currentX += 165;
currentX += 160;
// Insert Attachment Trigger
var attachButton = [[CPButton alloc] initWithFrame:CGRectMake(currentX, 15, 140, 30)];
[attachButton setTitle:@"Insert Attachment"];
[attachButton setTarget:self];
[attachButton setAction:@selector(insertAttachment:)];
[toolbarView addSubview:attachButton];
currentX += 150;
// Text Alignment Group
var labelAlign = [[CPTextField alloc] initWithFrame:CGRectMake(currentX, 22, 45, 20)];
@@ -129,34 +152,34 @@
[toolbarView addSubview:labelAlign];
currentX += 45;
var alignLeftBtn = [[CPButton alloc] initWithFrame:CGRectMake(currentX, 15, 30, 30)];
[alignLeftBtn setTitle:@"⃔"]; // Left-align symbol
var alignLeftBtn = [[CPButton alloc] initWithFrame:CGRectMake(currentX, 15, 50, 30)];
[alignLeftBtn setTitle:@"Left"];
[alignLeftBtn setTarget:self];
[alignLeftBtn setAction:@selector(alignLeft:)];
[toolbarView addSubview:alignLeftBtn];
currentX += 32;
currentX += 55;
var alignCenterBtn = [[CPButton alloc] initWithFrame:CGRectMake(currentX, 15, 30, 30)];
[alignCenterBtn setTitle:@"↔"]; // Center-align symbol
var alignCenterBtn = [[CPButton alloc] initWithFrame:CGRectMake(currentX, 15, 60, 30)];
[alignCenterBtn setTitle:@"Center"];
[alignCenterBtn setTarget:self];
[alignCenterBtn setAction:@selector(alignCenter:)];
[toolbarView addSubview:alignCenterBtn];
currentX += 32;
currentX += 65;
var alignRightBtn = [[CPButton alloc] initWithFrame:CGRectMake(currentX, 15, 30, 30)];
[alignRightBtn setTitle:@"⃕"]; // Right-align symbol
var alignRightBtn = [[CPButton alloc] initWithFrame:CGRectMake(currentX, 15, 55, 30)];
[alignRightBtn setTitle:@"Right"];
[alignRightBtn setTarget:self];
[alignRightBtn setAction:@selector(alignRight:)];
[toolbarView addSubview:alignRightBtn];
currentX += 32;
currentX += 60;
var alignJustifyBtn = [[CPButton alloc] initWithFrame:CGRectMake(currentX, 15, 30, 30)];
[alignJustifyBtn setTitle:@"≡"]; // Justify-align symbol
var alignJustifyBtn = [[CPButton alloc] initWithFrame:CGRectMake(currentX, 15, 65, 30)];
[alignJustifyBtn setTitle:@"Justify"];
[alignJustifyBtn setTarget:self];
[alignJustifyBtn setAction:@selector(alignJustified:)];
[toolbarView addSubview:alignJustifyBtn];
// Default return key target test (as defined in original source)
// Default return key target test
var returnButton = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth([contentView bounds]) - 270, 15, 250, 30)];
[returnButton setAutoresizingMask:CPViewMinXMargin];
[returnButton setTitle:@"Key Return Target"];
@@ -244,44 +267,41 @@
[mainMenu setSubmenu:formatMenu forItem:item];
// 4. Load Rich Sample Text content
[_textView insertText:@"123"];
var tempImageView = [[CPImageView alloc] initWithFrame:CGRectMake(0, 0, 32, 32)];
[tempImageView setImage:[[CPImage alloc] initWithContentsOfFile:@"Resources/spinner.gif" size:CGSizeMake(32, 32)]];
[_textView insertText:@"123 456 "];
[_textView insertText:[CPTextStorage attributedStringWithAttachment:tempImageView]];
[_textView insertText:@" 456 "];
var tempButton = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 64, 28)];
[_textView insertText:[CPTextStorage attributedStringWithAttachment:tempButton]];
// Centered paragraph text block
var centeredParagraph = [CPParagraphStyle new];
// Elegant Slate-Blue & Soft Light Blue paragraph
var centeredParagraph = [CPMutableParagraphStyle new];
[centeredParagraph setAlignment:CPCenterTextAlignment];
[_textView insertText:@"\n"];
var elegantForeground = [CPColor colorWithRed:0.18 green:0.24 blue:0.35 alpha:1.0]; // Slate Blue
var elegantBackground = [CPColor colorWithRed:0.92 green:0.95 blue:0.98 alpha:1.0]; // Soft Sky Blue tint
[_textView insertText:[[CPAttributedString alloc] initWithString:@"Fusce\n"
attributes:[CPDictionary dictionaryWithObjects:[centeredParagraph, [CPFont boldFontWithName:@"Arial" size:18], [CPColor redColor], [CPColor yellowColor]]
attributes:[CPDictionary dictionaryWithObjects:[centeredParagraph, [CPFont boldFontWithName:@"Arial" size:18], elegantForeground, elegantBackground]
forKeys:[CPParagraphStyleAttributeName, CPFontAttributeName, CPForegroundColorAttributeName, CPBackgroundColorAttributeName]]]];
// Highlighted Heading
// Highlighted Heading - Pine & Sage Green tones
[_textView insertText:@"\n"];
var showcaseForeground = [CPColor colorWithRed:0.15 green:0.25 blue:0.15 alpha:1.0]; // Forest Green
var showcaseBackground = [CPColor colorWithRed:0.94 green:0.97 blue:0.92 alpha:1.0]; // Light Sage Green
[_textView insertText:[[CPAttributedString alloc] initWithString:@"Interactive Ruler Showcase\n"
attributes:[CPDictionary dictionaryWithObjects:[[CPFont boldFontWithName:@"Arial" size:22], [CPColor yellowColor]]
forKeys:[CPFontAttributeName, CPBackgroundColorAttributeName]]]];
attributes:[CPDictionary dictionaryWithObjects:[[CPFont boldFontWithName:@"Arial" size:22], showcaseForeground, showcaseBackground]
forKeys:[CPFontAttributeName, CPForegroundColorAttributeName, CPBackgroundColorAttributeName]]]];
// DEMONSTRATION OF CPRULERVIEW TAB MARKERS
// Creating left, center, and right tabs to showcase the ruler markers dynamically
var tabParagraph = [[CPParagraphStyle defaultParagraphStyle] mutableCopy];
var tab1 = [[CPTextTab alloc] initWithType:CPLeftTabStopType location:100.0];
var tab2 = [[CPTextTab alloc] initWithType:CPCenterTabStopType location:220.0];
var tab3 = [[CPTextTab alloc] initWithType:CPRightTabStopType location:340.0];
var tab1 = [[CPTextTab alloc] initWithType:CPLeftTextAlignment location:100.0];
var tab2 = [[CPTextTab alloc] initWithType:CPCenterTextAlignment location:220.0];
var tab3 = [[CPTextTab alloc] initWithType:CPRightTextAlignment location:340.0];
[tabParagraph setTabStops:[tab1, tab2, tab3]];
[_textView insertText:@"\n"];
[_textView insertText:[[CPAttributedString alloc] initWithString:@"Tab1\tTab2\tTab3\nLeftAlign\tCenterAlign\tRightAlign\n"
attributes:[CPDictionary dictionaryWithObject:tabParagraph forKey:CPParagraphStyleAttributeName]]];
[_textView insertText:[[CPAttributedString alloc] initWithString:@"\tTab1\tTab2\tTab3\n\tLeftAlign\tCenterAlign\tRightAlign\n"
attributes:[CPDictionary dictionaryWithObject:tabParagraph forKey:CPParagraphStyleAttributeName]]];
// DEMONSTRATION OF INDENTATION MARKERS
// Creating custom margin and indentation settings
var indentParagraph = [[CPParagraphStyle defaultParagraphStyle] mutableCopy];
[indentParagraph setFirstLineHeadIndent:30.0];
[indentParagraph setHeadIndent:50.0];