/* * 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 "KWQSlider.h" #import "KWQButton.h" #import "KWQExceptions.h" #import "KWQKHTMLPart.h" #import "KWQView.h" #import "WebCoreBridge.h" #import "render_form.h" using khtml::RenderWidget; using khtml::RenderLayer; @interface KWQSlider : NSSlider <KWQWidgetHolder> { 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 { QWidget::beforeMouseDown(self); [super mouseDown:event]; QWidget::afterMouseDown(self); if (slider) { slider->sendConsumedMouseUp(); } if (slider) { slider->clicked(); } } - (IBAction)slide:(NSSlider*)sender { if (slider) { slider->sliderValueChanged(); } } - (QWidget *)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 (!KWQKHTMLPart::currentEventIsMouseDownInWidget(slider)) { RenderWidget *widget = const_cast<RenderWidget *> (static_cast<const RenderWidget *>(slider->eventFilterObject())); RenderLayer *layer = widget->enclosingLayer(); if (layer) layer->scrollRectToVisible(widget->absoluteBoundingBoxRect()); } if (slider) { QFocusEvent event(QEvent::FocusIn); if (slider->eventFilterObject()) const_cast<QObject *>(slider->eventFilterObject())->eventFilter(slider, &event); } } return become; } - (BOOL)resignFirstResponder { BOOL resign = [super resignFirstResponder]; if (resign && slider) { QFocusEvent event(QEvent::FocusOut); if (slider->eventFilterObject()) const_cast<QObject *>(slider->eventFilterObject())->eventFilter(slider, &event); } 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 = KWQKHTMLPart::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 = KWQKHTMLPart::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 && !KWQKHTMLPart::partForWidget(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_sliderValueChanged(this, SIGNAL(sliderValueChanged())), m_clicked(this, SIGNAL(clicked())), m_minVal(0.0), m_maxVal(100.0), m_val(50.0) { KWQ_BLOCK_EXCEPTIONS; KWQSlider* slider = [[KWQSlider alloc] initWithQSlider:this]; [[slider cell] setControlSize:NSSmallControlSize]; setView(slider); [slider release]; KWQ_UNBLOCK_EXCEPTIONS; } QSlider::~QSlider() { KWQSlider* slider = (KWQSlider*)getView(); [slider detachQSlider]; } void QSlider::setFont(const QFont &f) { KWQ_BLOCK_EXCEPTIONS; QWidget::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]]]; KWQ_UNBLOCK_EXCEPTIONS; } QWidget::FocusPolicy QSlider::focusPolicy() const { KWQ_BLOCK_EXCEPTIONS; WebCoreBridge *bridge = KWQKHTMLPart::bridgeForWidget(this); if (!bridge || ![bridge part] || ![bridge part]->tabsToAllControls()) { return NoFocus; } KWQ_UNBLOCK_EXCEPTIONS; return QWidget::focusPolicy(); } QSize QSlider::sizeHint() const { return QSize(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]; } void QSlider::setMaxValue(double v) { if (v == m_maxVal) return; KWQSlider* slider = (KWQSlider*)getView(); [slider setMaxValue: 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; m_sliderValueChanged.call(); } } 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()); KWQ_BLOCK_EXCEPTIONS; return w[[[slider cell] controlSize]]; KWQ_UNBLOCK_EXCEPTIONS; return w[NSSmallControlSize]; } void QSlider::clicked() { m_clicked.call(); }