blob: c1f53b2cc173ad54d389aa6b3dcb64ae20e8b0f8 [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
#include "base/logging.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/themes/theme_service.h"
#import "chrome/browser/ui/cocoa/nsview_additions.h"
#import "chrome/browser/ui/cocoa/themed_window.h"
#include "grit/theme_resources.h"
#import "ui/base/cocoa/nsgraphics_context_additions.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/font.h"
#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
@implementation StyledTextFieldCell
- (CGFloat)topTextFrameOffset {
return 0.0;
}
- (CGFloat)bottomTextFrameOffset {
return 0.0;
}
- (CGFloat)cornerRadius {
return 0.0;
}
- (rect_path_utils::RoundedCornerFlags)roundedCornerFlags {
return rect_path_utils::RoundedCornerAll;
}
- (BOOL)shouldDrawBezel {
return NO;
}
- (NSRect)textFrameForFrameInternal:(NSRect)cellFrame {
CGFloat topOffset = [self topTextFrameOffset];
NSRect textFrame = cellFrame;
textFrame.origin.y += topOffset;
textFrame.size.height -= topOffset + [self bottomTextFrameOffset];
return textFrame;
}
// Returns the same value as textCursorFrameForFrame, but does not call it
// directly to avoid potential infinite loops.
- (NSRect)textFrameForFrame:(NSRect)cellFrame {
return [self textFrameForFrameInternal:cellFrame];
}
// Returns the same value as textFrameForFrame, but does not call it directly to
// avoid potential infinite loops.
- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame {
return [self textFrameForFrameInternal:cellFrame];
}
// Override to show the I-beam cursor only in the area given by
// |textCursorFrameForFrame:|.
- (void)resetCursorRect:(NSRect)cellFrame inView:(NSView *)controlView {
[super resetCursorRect:[self textCursorFrameForFrame:cellFrame]
inView:controlView];
}
// For NSTextFieldCell this is the area within the borders. For our
// purposes, we count the info decorations as being part of the
// border.
- (NSRect)drawingRectForBounds:(NSRect)theRect {
return [super drawingRectForBounds:[self textFrameForFrame:theRect]];
}
// TODO(shess): This code is manually drawing the cell's border area,
// but otherwise the cell assumes -setBordered:YES for purposes of
// calculating things like the editing area. This is probably
// incorrect. I know that this affects -drawingRectForBounds:.
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
const CGFloat lineWidth = [controlView cr_lineWidth];
const CGFloat halfLineWidth = lineWidth / 2.0;
DCHECK([controlView isFlipped]);
rect_path_utils::RoundedCornerFlags roundedCornerFlags =
[self roundedCornerFlags];
// TODO(shess): This inset is also reflected by |kFieldVisualInset|
// in omnibox_popup_view_mac.mm.
const NSRect frame = NSInsetRect(cellFrame, 0, lineWidth);
const CGFloat radius = [self cornerRadius];
// Paint button background image if there is one (otherwise the border won't
// look right).
ThemeService* themeProvider =
static_cast<ThemeService*>([[controlView window] themeProvider]);
if (themeProvider) {
NSColor* backgroundImageColor = nil;
if (themeProvider->HasCustomImage(IDR_THEME_BUTTON_BACKGROUND)) {
backgroundImageColor =
themeProvider->GetNSImageColorNamed(IDR_THEME_BUTTON_BACKGROUND);
}
if (backgroundImageColor) {
// Set the phase to match window.
NSRect trueRect = [controlView convertRect:cellFrame toView:nil];
NSPoint midPoint = NSMakePoint(NSMinX(trueRect), NSMaxY(trueRect));
[[NSGraphicsContext currentContext] cr_setPatternPhase:midPoint
forView:controlView];
// NOTE(shess): This seems like it should be using a 0.0 inset,
// but AFAICT using a halfLineWidth inset is important in mixing the
// toolbar background and the omnibox background.
rect_path_utils::FillRectWithInset(roundedCornerFlags, frame,
halfLineWidth, halfLineWidth, radius,
backgroundImageColor);
}
// Draw the outer stroke (over the background).
BOOL active = [[controlView window] isMainWindow];
NSColor* strokeColor = themeProvider->GetNSColor(
active ? ThemeProperties::COLOR_TOOLBAR_BUTTON_STROKE :
ThemeProperties::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE);
rect_path_utils::FrameRectWithInset(roundedCornerFlags, frame, 0.0, 0.0,
radius, lineWidth, strokeColor);
}
// Fill interior with background color.
rect_path_utils::FillRectWithInset(roundedCornerFlags, frame, lineWidth,
lineWidth, radius,
[self backgroundColor]);
// Draw the shadow. For the rounded-rect case, the shadow needs to
// slightly turn in at the corners. |shadowFrame| is at the same
// midline as the inner border line on the top and left, but at the
// outer border line on the bottom and right. The clipping change
// will clip the bottom and right edges (and corner).
{
gfx::ScopedNSGraphicsContextSaveGState state;
[rect_path_utils::RectPathWithInset(roundedCornerFlags, frame, lineWidth,
lineWidth, radius) addClip];
const NSRect shadowFrame =
NSOffsetRect(frame, halfLineWidth, halfLineWidth);
NSColor* shadowShade = [NSColor colorWithCalibratedWhite:0.0
alpha:0.05 / lineWidth];
rect_path_utils::FrameRectWithInset(roundedCornerFlags, shadowFrame,
halfLineWidth, halfLineWidth,
radius - halfLineWidth, lineWidth,
shadowShade);
}
// Draw optional bezel below bottom stroke.
if ([self shouldDrawBezel] && themeProvider &&
themeProvider->UsingDefaultTheme()) {
NSColor* bezelColor = themeProvider->GetNSColor(
ThemeProperties::COLOR_TOOLBAR_BEZEL);
[[bezelColor colorWithAlphaComponent:0.5 / lineWidth] set];
NSRect bezelRect = NSMakeRect(cellFrame.origin.x,
NSMaxY(cellFrame) - lineWidth,
NSWidth(cellFrame),
lineWidth);
bezelRect = NSInsetRect(bezelRect, radius - halfLineWidth, 0.0);
NSRectFillUsingOperation(bezelRect, NSCompositeSourceOver);
}
// Draw the interior before the focus ring, to make sure nothing overlaps it.
[self drawInteriorWithFrame:cellFrame inView:controlView];
// Draw the focus ring if needed.
if ([self showsFirstResponder]) {
NSColor* color = [[NSColor keyboardFocusIndicatorColor]
colorWithAlphaComponent:0.5 / lineWidth];
rect_path_utils::FrameRectWithInset(roundedCornerFlags, frame, 0.0, 0.0,
radius, lineWidth * 2, color);
}
}
@end