diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index 698c939c3..cb8cb6c95 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -326,7 +326,7 @@ var _CPButtonClassName = nil, if (self) { - _imagePosition = CPNoImage; + _imagePosition = CPImageLeft; _imageScaling = CPScaleNone; _controlSize = CPRegularControlSize; @@ -761,19 +761,20 @@ var _CPButtonClassName = nil, if (!_imageAndTextView) { _imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:[self bounds]]; - + [self addSubview:_imageAndTextView]; [self tile]; } + [_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment]; [_imageAndTextView setFont:[self font]]; [_imageAndTextView setTextColor:[self textColor]]; [_imageAndTextView setAlignment:[self alignment]]; [_imageAndTextView setImagePosition:_imagePosition]; [_imageAndTextView setImageScaling:_imageScaling]; - [_imageAndTextView setTitle:isHighlighted && _alternateTitle ? _alternateTitle : _title]; + [_imageAndTextView setText:isHighlighted && _alternateTitle ? _alternateTitle : _title]; [_imageAndTextView setImage:isHighlighted && _alternateImage ? _alternateImage : _image]; } diff --git a/AppKit/CPMenuItem.j b/AppKit/CPMenuItem.j index 4acf4aeb3..9ac71b5a0 100644 --- a/AppKit/CPMenuItem.j +++ b/AppKit/CPMenuItem.j @@ -844,7 +844,8 @@ var CPMenuItemTitleKey = @"CPMenuItemTitleKey", var LEFT_MARGIN = 3.0, RIGHT_MARGIN = 16.0, STATE_COLUMN_WIDTH = 14.0, - INDENTATION_WIDTH = 17.0; + INDENTATION_WIDTH = 17.0, + VERTICAL_MARGIN = 4.0; var _CPMenuItemSelectionColor = nil, @@ -1018,20 +1019,25 @@ var _CPMenuItemSelectionColor = nil, font = _font; [_imageAndTextView setFont:font]; + [_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment]; [_imageAndTextView setImage:[_menuItem image]]; - [_imageAndTextView setTitle:[_menuItem title]]; + [_imageAndTextView setText:[_menuItem title]]; [_imageAndTextView setTextColor:[self textColor]]; - [_imageAndTextView setFrameOrigin:CGPointMake(x, 0.0)]; + [_imageAndTextView setFrameOrigin:CGPointMake(x, VERTICAL_MARGIN)]; [_imageAndTextView sizeToFit]; var frame = [_imageAndTextView frame]; + frame.size.height += 2 * VERTICAL_MARGIN; + x += CGRectGetWidth(frame); // Submenu Arrow if ([_menuItem hasSubmenu]) { + x += 3.0; + if (!_submenuView) { _submenuView = [[_CPMenuItemArrowView alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)]; @@ -1048,7 +1054,7 @@ var _CPMenuItemSelectionColor = nil, else [_submenuView setHidden:YES]; - _minSize = CGSizeMake(x + (_belongsToMenuBar ? 0.0 : RIGHT_MARGIN), CGRectGetHeight(frame)); + _minSize = CGSizeMake(x + (_belongsToMenuBar ? 0.0 : RIGHT_MARGIN) + 3.0, CGRectGetHeight(frame)); [self setFrameSize:_minSize]; } diff --git a/AppKit/CPStringDrawing.j b/AppKit/CPStringDrawing.j index 78028180b..868ccb651 100644 --- a/AppKit/CPStringDrawing.j +++ b/AppKit/CPStringDrawing.j @@ -23,7 +23,8 @@ @import -var CPStringReferenceElement = nil; +var CPStringReferenceElement = nil, + CPStringDefaultFont = nil; @implementation CPString (CPStringDrawing) @@ -36,6 +37,11 @@ var CPStringReferenceElement = nil; } - (CGSize)sizeWithFont:(CPFont)aFont +{ + return [self sizeWithFont:aFont inWidth:NULL]; +} + +- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth { if (!CPStringReferenceElement) { @@ -56,11 +62,44 @@ var CPStringReferenceElement = nil; document.getElementsByTagName("body")[0].appendChild(CPStringReferenceElement); } + + if (!aFont) + { + if (!CPStringDefaultFont) + CPStringDefaultFont = [CPFont systemFontOfSize:12.0]; + + aFont = CPStringDefaultFont; + } + + var style = CPStringReferenceElement.style; - CPStringReferenceElement.style.font = [aFont ? aFont : [CPFont systemFontOfSize:12.0] cssString]; + if (aWidth === NULL) + { + style.width = ""; + style.whiteSpace = "pre"; + } + + else + { + style.width = ROUND(aWidth) + "px"; + + if (document.attachEvent) + style.wordWrap = "break-word"; + + else + { + style.whiteSpace = "-o-pre-wrap"; + style.whiteSpace = "-pre-wrap"; + style.whiteSpace = "-moz-pre-wrap"; + style.whiteSpace = "pre-wrap"; + } + } + + style.font = [aFont cssString]; if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature)) CPStringReferenceElement.innerText = self; + else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature)) CPStringReferenceElement.textContent = self; diff --git a/AppKit/_CPImageAndTextView.j b/AppKit/_CPImageAndTextView.j index 9a4628685..2d8318a0d 100644 --- a/AppKit/_CPImageAndTextView.j +++ b/AppKit/_CPImageAndTextView.j @@ -33,25 +33,44 @@ #include "Platform/Platform.h" #include "Platform/DOM/CPDOMDisplayServer.h" -var _CPImageAndTextViewTextChangedFlag = 1 << 0, - _CPImageAndTextViewImageChangedFlag = 1 << 1; + +CPTopVerticalTextAlignment = 1, +CPCenterVerticalTextAlignment = 2, +CPBottomVerticalTextAlignment = 3; + +var _CPimageAndTextViewFrameSizeChangedFlag = 1 << 0, + _CPImageAndTextViewImageChangedFlag = 1 << 1, + _CPImageAndTextViewTextChangedFlag = 1 << 2, + _CPImageAndTextViewAlignmentChangedFlag = 1 << 3, + _CPImageAndTextViewVerticalAlignmentChangedFlag = 1 << 4, + _CPImageAndTextViewLineBreakModeChangedFlag = 1 << 5, + _CPImageAndTextViewTextColorChangedFlag = 1 << 6, + _CPImageAndTextViewFontChangedFlag = 1 << 7, + _CPImageAndTextViewImagePositionChangedFlag = 1 << 8, + _CPImageAndTextViewImageScalingChangedFlag = 1 << 9; + +var HORIZONTAL_MARGIN = 3.0, + VERTICAL_MARGIN = 5.0; /* @ignore */ @implementation _CPImageAndTextView : CPView { - CPTextAlignment _alignment; - CPColor _textColor; - CPFont _font; + CPTextAlignment _alignment; + CPVerticalTextAlignment _verticalAlignment; - CPCellImagePosition _imagePosition; - CPImageScaling _imageScaling; + CPLineBreakMode _lineBreakMode; + CPColor _textColor; + CPFont _font; - CPImage _image; - CPString _text; + CPCellImagePosition _imagePosition; + CPImageScaling _imageScaling; - CGRect _textSize; + CPImage _image; + CPString _text; + + CGRect _textSize; - unsigned _flags; + unsigned _flags; #if PLATFORM(DOM) DOMElement _DOMImageElement; @@ -65,7 +84,11 @@ var _CPImageAndTextViewTextChangedFlag = 1 << 0, if (self) { + _lineBreakMode = CPLineBreakByClipping; + _textColor = nil; + [self setAlignment:CPCenterTextAlignment]; + [self setVerticalAlignment:CPTopVerticalTextAlignment]; [self setFont:[CPFont systemFontOfSize:12.0]]; [self setImagePosition:CPNoImage]; [self setImageScaling:CPScaleNone]; @@ -107,12 +130,45 @@ var _CPImageAndTextViewTextChangedFlag = 1 << 0, return _alignment; } +- (void)setVerticalAlignment:(CPVerticalTextAlignment)anAlignment +{ + if (_verticalAlignment === anAlignment) + return; + + _verticalAlignment = anAlignment; + _flags |= _CPImageAndTextViewVerticalAlignmentChangedFlag; + + [self setNeedsDisplay:YES]; +} + +- (unsigned)verticalAlignment +{ + return _verticalAlignment; +} + +- (void)setLineBreakMode:(CPLineBreakMode)aLineBreakMode +{ + if (_lineBreakMode === aLineBreakMode) + return; + + _lineBreakMode = aLineBreakMode; + _flags |= _CPImageAndTextViewLineBreakModeChangedFlag; + + [self setNeedsDisplay:YES]; +} + +- (CPLineBreakMode)lineBreakMode +{ + return _lineBreakMode; +} + - (void)setImagePosition:(CPCellImagePosition)anImagePosition { if (_imagePosition == anImagePosition) return; _imagePosition = anImagePosition; + _flags |= _CPImageAndTextViewImagePositionChangedFlag; [self setNeedsDisplay:YES]; } @@ -128,6 +184,7 @@ var _CPImageAndTextViewTextChangedFlag = 1 << 0, return; _imageScaling = anImageScaling; + _flags |= _CPImageAndTextViewImageScalingChangedFlag; [self setNeedsDisplay:YES]; } @@ -139,7 +196,7 @@ var _CPImageAndTextViewTextChangedFlag = 1 << 0, - (void)setTextColor:(CPColor)aTextColor { - if (_textColor == aTextColor) + if (_textColor === aTextColor) return; _textColor = aTextColor; @@ -160,11 +217,7 @@ var _CPImageAndTextViewTextChangedFlag = 1 << 0, return; _font = aFont; - -#if PLATFORM(DOM) - _DOMElement.style.font = [_font ? _font : [CPFont systemFontOfSize:12.0] cssString]; -#endif - + _flags |= _CPImageAndTextViewFontChangedFlag; _textSize = NULL; [self setNeedsDisplay:YES]; @@ -191,12 +244,12 @@ var _CPImageAndTextViewTextChangedFlag = 1 << 0, return _image; } -- (void)setTitle:(CPString)aTitle +- (void)setText:(CPString)text { - if (_text === aTitle) + if (_text === text) return; - _text = aTitle; + _text = text; _flags |= _CPImageAndTextViewTextChangedFlag; _textSize = NULL; @@ -212,31 +265,46 @@ var _CPImageAndTextViewTextChangedFlag = 1 << 0, - (void)drawRect:(CGRect)aRect { #if PLATFORM(DOM) - var needsDOMTextElement = _imagePosition !== CPImageOnly && ([_text length] > 0); + var needsDOMTextElement = _imagePosition !== CPImageOnly && ([_text length] > 0), + hasDOMTextElement = !!_DOMTextElement; // Create or destroy the DOM Text Element as necessary - if (needsDOMTextElement !== !!_DOMTextElement) - if (_DOMTextElement) + if (needsDOMTextElement !== hasDOMTextElement) + if (hasDOMTextElement) { _DOMElement.removeChild(_DOMTextElement); + _DOMTextElement = NULL; + + hasDOMTextElement = NO; } else - { + { _DOMTextElement = document.createElement("div"); -// _DOMTextElement.style.background = "red"; - _DOMTextElement.style.position = "absolute"; - _DOMTextElement.style.whiteSpace = "pre"; - _DOMTextElement.style.cursor = "default"; - _DOMTextElement.style.zIndex = 100; - _DOMTextElement.style.overflow = "hidden"; + + var textStyle = _DOMTextElement.style; + + textStyle.position = "absolute"; + textStyle.whiteSpace = "pre"; + textStyle.cursor = "default"; + textStyle.zIndex = 100; + textStyle.overflow = "hidden"; _DOMElement.appendChild(_DOMTextElement); + + hasDOMTextElement = YES; + + // We have to set all these values now. + _flags |= _CPImageAndTextViewTextChangedFlag | _CPImageAndTextViewFontChangedFlag | _CPImageAndTextViewLineBreakModeChangedFlag; } - if (_DOMTextElement) - { + if (hasDOMTextElement) + { + if (!textStyle) + var textStyle = _DOMTextElement.style; + + // Update the text contents if necessary. if (_flags & _CPImageAndTextViewTextChangedFlag) if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature)) _DOMTextElement.innerText = _text; @@ -244,48 +312,103 @@ var _CPImageAndTextViewTextChangedFlag = 1 << 0, else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature)) _DOMTextElement.textContent = _text; - if (!_textSize) - _textSize = [_text sizeWithFont:_font]; + if (_flags & _CPImageAndTextViewFontChangedFlag) + textStyle.font = [_font ? _font : [CPFont systemFontOfSize:12.0] cssString]; + + // Update the line break mode if necessary. + if (_flags & _CPImageAndTextViewLineBreakModeChangedFlag) + { + switch (_lineBreakMode) + { + case CPLineBreakByClipping: textStyle.overflow = "hidden"; + textStyle.textOverflow = "clip"; + textStyle.whiteSpace = "pre"; + + if (document.attachEvent) + textStyle.wordWrap = "normal"; + + break; + + case CPLineBreakByTruncatingHead: + case CPLineBreakByTruncatingMiddle: // Don't have support for these (yet?), so just degrade to truncating tail. + + case CPLineBreakByTruncatingTail: textStyle.textOverflow = "ellipsis"; + textStyle.whiteSpace = "nowrap"; + textStyle.overflow = "hidden"; + + if (document.attachEvent) + textStyle.wordWrap = "normal"; + + break; + + case CPLineBreakByCharWrapping: + case CPLineBreakByWordWrapping: if (document.attachEvent) + { + textStyle.whiteSpace = "pre"; + textStyle.wordWrap = "break-word"; + } + + else + { + textStyle.whiteSpace = "-o-pre-wrap"; + textStyle.whiteSpace = "-pre-wrap"; + textStyle.whiteSpace = "-moz-pre-wrap"; + textStyle.whiteSpace = "pre-wrap"; + } + + textStyle.overflow = "hidden"; + textStyle.textOverflow = "clip"; + + break; + } + } } - var needsDOMImageElement = _image !== nil; + var needsDOMImageElement = _image !== nil && _imagePosition !== CPNoImage, + hasDOMImageElement = !!_DOMImageElement; // Create or destroy DOM Image element - if (needsDOMImageElement !== !!_DOMImageElement) - if (_DOMImageElement) + if (needsDOMImageElement !== hasDOMImageElement) + if (hasDOMImageElement) { _DOMElement.removeChild(_DOMImageElement); _DOMImageElement = NULL; + + hasDOMImageElement = NO; } else { _DOMImageElement = document.createElement("img"); + + var imageStyle = _DOMImageElement.style; - _DOMImageElement.style.top = "0px"; - _DOMImageElement.style.left = "0px"; - _DOMImageElement.style.position = "absolute"; - _DOMImageElement.style.zIndex = 100; + imageStyle.top = "0px"; + imageStyle.left = "0px"; + imageStyle.position = "absolute"; + imageStyle.zIndex = 100; _DOMElement.appendChild(_DOMImageElement); - } - - if (_DOMImageElement && (_flags & _CPImageAndTextViewImageChangedFlag)) - _DOMImageElement.src = [_image filename]; + + hasDOMImageElement = YES; + } #endif - _flags = 0; - var size = [self bounds].size, - centerX = size.width / 2.0, - centerY = size.height / 2.0, - titleHeight = _DOMTextElement ? _textSize.height : 0.0, - titleRect = _CGRectMake(0.0, centerY - titleHeight / 2.0, size.width, titleHeight); + textRect = _CGRectMake(0.0, 0.0, size.width, size.height); - if ((_imagePosition !== CPNoImage) && _image) + if (hasDOMImageElement) { - var imageSize = [_image size], + if (!imageStyle) + var imageStyle = _DOMImageElement.style; + + if (_flags & _CPImageAndTextViewImageChangedFlag) + _DOMImageElement.src = [_image filename]; + + var centerX = size.width / 2.0, + centerY = size.height / 2.0, + imageSize = [_image size], imageWidth = imageSize.width, imageHeight = imageSize.height; @@ -305,71 +428,110 @@ var _CPImageAndTextViewTextChangedFlag = 1 << 0, #if PLATFORM(DOM) _DOMImageElement.width = imageWidth; _DOMImageElement.height = imageHeight; - _DOMImageElement.style.width = imageWidth + "px"; - _DOMImageElement.style.height = imageHeight + "px"; + imageStyle.width = imageWidth + "px"; + imageStyle.height = imageHeight + "px"; #endif if (_imagePosition === CPImageBelow) { #if PLATFORM(DOM) - _DOMImageElement.style.left = FLOOR(centerX - imageWidth / 2.0) + "px"; - _DOMImageElement.style.top = FLOOR(size.height - imageHeight) + "px"; + imageStyle.left = FLOOR(centerX - imageWidth / 2.0) + "px"; + imageStyle.top = FLOOR(size.height - imageHeight) + "px"; #endif - titleRect.origin.y = (size.height - imageHeight - titleHeight) / 2.0; + textRect.size.height = size.height - imageHeight - VERTICAL_MARGIN; } else if (_imagePosition === CPImageAbove) { #if PLATFORM(DOM) CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, FLOOR(centerX - imageWidth / 2.0), 0); #endif - - titleRect.origin.y = imageHeight + (size.height - imageHeight - titleHeight) / 2.0; + + textRect.origin.y += imageHeight + VERTICAL_MARGIN; + textRect.size.height = size.height - imageHeight - VERTICAL_MARGIN; } else if (_imagePosition === CPImageLeft) { #if PLATFORM(DOM) - _DOMImageElement.style.top = FLOOR(centerY - imageHeight / 2.0) + "px"; - _DOMImageElement.style.left = "0px"; + imageStyle.top = FLOOR(centerY - imageHeight / 2.0) + "px"; + imageStyle.left = "0px"; #endif - titleRect.origin.x += imageWidth; - titleRect.size.width -= imageWidth; + textRect.origin.x = imageWidth + HORIZONTAL_MARGIN; + textRect.size.width -= imageWidth + HORIZONTAL_MARGIN; } else if (_imagePosition === CPImageRight) { #if PLATFORM(DOM) - _DOMImageElement.style.top = FLOOR(centerY - imageHeight / 2.0) + "px"; - _DOMImageElement.style.left = FLOOR(size.width - imageWidth) + "px"; + imageStyle.top = FLOOR(centerY - imageHeight / 2.0) + "px"; + imageStyle.left = FLOOR(size.width - imageWidth) + "px"; #endif - titleRect.size.width -= imageWidth; + textRect.size.width -= imageWidth + HORIZONTAL_MARGIN; } - else if(_imagePosition === CPImageOnly) + else if (_imagePosition === CPImageOnly) { #if PLATFORM(DOM) - _DOMImageElement.style.top = FLOOR(centerY - imageHeight / 2.0) + "px"; - _DOMImageElement.style.left = FLOOR(centerX - imageWidth / 2.0) + "px"; + imageStyle.top = FLOOR(centerY - imageHeight / 2.0) + "px"; + imageStyle.left = FLOOR(centerX - imageWidth / 2.0) + "px"; #endif } } #if PLATFORM(DOM) - if (_DOMTextElement) + if (hasDOMTextElement) { - _DOMTextElement.style.top = FLOOR(_CGRectGetMinY(titleRect)) + "px"; - _DOMTextElement.style.left = FLOOR(_CGRectGetMinX(titleRect)) + "px"; - _DOMTextElement.style.width = FLOOR(_CGRectGetWidth(titleRect)) + "px"; - _DOMTextElement.style.height = FLOOR(_CGRectGetHeight(titleRect)) + "px"; + var textRectX = FLOOR(_CGRectGetMinX(textRect)), + textRectY = FLOOR(_CGRectGetMinY(textRect)), + textRectWidth = FLOOR(_CGRectGetWidth(textRect)), + textRectHeight = FLOOR(_CGRectGetHeight(textRect)); + + textStyle.left = textRectX + "px"; + textStyle.width = textRectWidth + "px"; + + switch (_verticalAlignment) + { + case CPTopVerticalTextAlignment: textStyle.top = "0px"; + textStyle.height = textRectHeight + "px"; + + break; + + case CPCenterVerticalTextAlignment: if (0 && _lineBreakMode !== CPLineBreakByCharWrapping && _lineBreakMode !== CPLineBreakByWordWrapping) + { + textStyle.lineHeight = textRectHeight + "px"; + textStyle.height = textRectHeight + "px"; + } + + else + { + if (!_textSize) + _textSize = [_text sizeWithFont:_font inWidth:textRectWidth]; + + textStyle.top = (textRectY + (textRectHeight - _textSize.height) / 2.0) + "px"; + textStyle.height = _textSize.height + "px"; + } + + break; + + case CPBottomVerticalTextAlignment: if (!_textSize) + _textSize = [_text sizeWithFont:_font inWidth:textRectWidth]; + + textStyle.top = (textRectY + textRectHeight - _textSize.height) + "px"; + textStyle.height = _textSize.height + "px"; + + break; + } } #endif + + _flags = 0; } - (void)sizeToFit { var size = CGSizeMakeZero(); - if (_imagePosition != CPNoImage && _image) + if ((_imagePosition !== CPNoImage) && _image) { var imageSize = [_image size]; @@ -377,20 +539,20 @@ var _CPImageAndTextViewTextChangedFlag = 1 << 0, size.height += imageSize.height; } - if (_imagePosition != CPImageOnly && [_text length] > 0) + if ((_imagePosition !== CPImageOnly) && [_text length] > 0) { if (!_textSize) - _textSize = [_text sizeWithFont:_font]; + _textSize = [_text sizeWithFont:_font ? _font : [CPFont systemFontOfSize:12.0]]; if (_imagePosition == CPImageLeft || _imagePosition == CPImageRight) { - size.width += _textSize.width; + size.width += _textSize.width + HORIZONTAL_MARGIN; size.height = MAX(size.height, _textSize.height); } else if (_imagePosition == CPImageAbove || _imagePosition == CPImageBelow) { size.width = MAX(size.width, _textSize.width); - size.height += _textSize.height; + size.height += _textSize.height + VERTICAL_MARGIN; } else // if (_imagePosition == CPImageOverlaps) {