blob: 6f7a6efd8b5adde7f0b71b9fa84db8ef84c70fb4 [file] [log] [blame]
/*
* Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "config.h"
#import "KWQSlider.h"
#import "BlockExceptions.h"
#import "KWQLineEdit.h"
#import "FrameMac.h"
#import "WebCoreFrameBridge.h"
#import "WebCoreWidgetHolder.h"
#import "render_form.h"
using namespace WebCore;
@interface KWQSlider : NSSlider <WebCoreWidgetHolder>
{
QSlider* slider;
BOOL inNextValidKeyView;
}
- (id)initWithQSlider:(QSlider*)s;
- (void)detachQSlider;
@end
@implementation KWQSlider
- (id)initWithQSlider:(QSlider*)s
{
self = [self init];
slider = s;
[self setTarget:self];
[self setAction:@selector(slide:)];
[self setContinuous:YES]; // Our sliders are always continuous by default.
[self setMinValue:0.0];
[self setMaxValue:100.0];
[self setDoubleValue:50.0];
return self;
}
- (void)detachQSlider
{
[self setTarget:nil];
slider = 0;
}
- (void)mouseDown:(NSEvent *)event
{
Widget::beforeMouseDown(self);
[super mouseDown:event];
Widget::afterMouseDown(self);
if (slider)
slider->sendConsumedMouseUp();
if (slider && slider->client())
slider->client()->clicked(slider);
}
- (IBAction)slide:(NSSlider*)sender
{
if (slider)
slider->sliderValueChanged();
}
- (Widget *)widget
{
return slider;
}
// FIXME: All the firstResponder and keyView code here is replicated in KWQButton and
// other KWQ classes. We should find a way to share this code.
- (BOOL)becomeFirstResponder
{
BOOL become = [super becomeFirstResponder];
if (become && slider) {
if (slider && slider->client() && !FrameMac::currentEventIsMouseDownInWidget(slider))
slider->client()->scrollToVisible(slider);
if (slider && slider->client())
slider->client()->focusIn(slider);
}
return become;
}
- (BOOL)resignFirstResponder
{
BOOL resign = [super resignFirstResponder];
if (resign && slider && slider->client()) {
slider->client()->focusOut(slider);
if (slider)
[FrameMac::bridgeForWidget(slider) formControlIsResigningFirstResponder:self];
}
return resign;
}
-(NSView *)nextKeyView
{
NSView *view = nil;
if (slider && inNextValidKeyView) {
// resign so we send a blur before setting focus on
// the next widget, otherwise the blur for this
// widget will remove focus from the widget after
// we tab to it
[self resignFirstResponder];
if (slider) {
view = FrameMac::nextKeyViewForWidget(slider, KWQSelectingNext);
} else {
view = [super nextKeyView];
}
} else {
view = [super nextKeyView];
}
return view;
}
-(NSView *)previousKeyView
{
NSView *view = nil;
if (slider && inNextValidKeyView) {
// resign so we send a blur before setting focus on
// the next widget, otherwise the blur for this
// widget will remove focus from the widget after
// we tab to it
[self resignFirstResponder];
if (slider) {
view = FrameMac::nextKeyViewForWidget(slider, KWQSelectingPrevious);
} else {
view = [super previousKeyView];
}
} else {
view = [super previousKeyView];
}
return view;
}
- (BOOL)canBecomeKeyView
{
// Simplified method from NSView; overridden to replace NSView's way of checking
// for full keyboard access with ours.
if (slider && !FrameMac::frameForWidget(slider)->tabsToAllControls()) {
return NO;
}
return ([self window] != nil) && ![self isHiddenOrHasHiddenAncestor] && [self acceptsFirstResponder];
}
-(NSView *)nextValidKeyView
{
inNextValidKeyView = YES;
NSView *view = [super nextValidKeyView];
inNextValidKeyView = NO;
return view;
}
-(NSView *)previousValidKeyView
{
inNextValidKeyView = YES;
NSView *view = [super previousValidKeyView];
inNextValidKeyView = NO;
return view;
}
@end
enum {
dimWidth,
dimHeight
};
QSlider::QSlider()
: m_minVal(0.0), m_maxVal(100.0), m_val(50.0)
{
BEGIN_BLOCK_OBJC_EXCEPTIONS;
KWQSlider* slider = [[KWQSlider alloc] initWithQSlider:this];
[[slider cell] setControlSize:NSSmallControlSize];
setView(slider);
[slider release];
END_BLOCK_OBJC_EXCEPTIONS;
}
QSlider::~QSlider()
{
KWQSlider* slider = (KWQSlider*)getView();
[slider detachQSlider];
}
void QSlider::setFont(const Font& f)
{
BEGIN_BLOCK_OBJC_EXCEPTIONS;
Widget::setFont(f);
const NSControlSize size = KWQNSControlSizeForFont(f);
NSControl * const slider = static_cast<NSControl *>(getView());
[[slider cell] setControlSize:size];
[slider setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:size]]];
END_BLOCK_OBJC_EXCEPTIONS;
}
Widget::FocusPolicy QSlider::focusPolicy() const
{
BEGIN_BLOCK_OBJC_EXCEPTIONS;
WebCoreFrameBridge *bridge = FrameMac::bridgeForWidget(this);
if (!bridge || ![bridge impl] || ![bridge impl]->tabsToAllControls()) {
return NoFocus;
}
END_BLOCK_OBJC_EXCEPTIONS;
return Widget::focusPolicy();
}
IntSize QSlider::sizeHint() const
{
return IntSize(dimensions()[dimWidth], dimensions()[dimHeight]);
}
void QSlider::setValue(double v)
{
double val = kMax(m_minVal, kMin(v, m_maxVal));
KWQSlider* slider = (KWQSlider*)getView();
[slider setDoubleValue: val];
m_val = val;
}
void QSlider::setMinValue(double v)
{
if (v == m_minVal) return;
KWQSlider* slider = (KWQSlider*)getView();
[slider setMinValue: v];
m_minVal = v;
}
void QSlider::setMaxValue(double v)
{
if (v == m_maxVal) return;
KWQSlider* slider = (KWQSlider*)getView();
[slider setMaxValue: v];
m_maxVal = v;
}
double QSlider::value() const
{
return m_val;
}
double QSlider::minValue() const
{
return m_minVal;
}
double QSlider::maxValue() const
{
return m_maxVal;
}
void QSlider::sliderValueChanged()
{
KWQSlider* slider = (KWQSlider*)getView();
double v = [slider doubleValue];
if (m_val != v) {
m_val = v;
if (client())
client()->valueChanged(this);
}
}
const int* QSlider::dimensions() const
{
// We empirically determined these dimensions.
// It would be better to get this info from AppKit somehow.
static const int w[3][2] = {
{ 129, 21 },
{ 129, 15 },
{ 129, 12 },
};
NSControl * const slider = static_cast<NSControl *>(getView());
BEGIN_BLOCK_OBJC_EXCEPTIONS;
return w[[[slider cell] controlSize]];
END_BLOCK_OBJC_EXCEPTIONS;
return w[NSSmallControlSize];
}