[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    I was kinda bored
From:       Rolf Eike Beer <kde () opensource ! sf-tec ! de>
Date:       2010-10-06 22:13:39
Message-ID: 201010070013.49574.kde () opensource ! sf-tec ! de
[Download RAW message or body]

[Attachment #2 (multipart/mixed)]


I was hacking for something like 3 or 4 hours and came up with this 
implementation of the "new" HTML5 <input type="number"> field. I have no idea 
if that is the right way to do it, I must also confess that most of the code 
is copy&paste from the normal input fields. The only real testing I did was 
using http://diveintohtml5.org/examples/input-type-number-min-max-step.html 
which seems to work as expected.

If someone with any insight in KHTML could take a look if this is anything 
close to a sane implementation I would be happy to see something like this 
going into KHTML for KDE 4.6. If it covers only half of the cases it still 
makes the users life easier than the pure text field ;)

Eike

["html5-number.patch" (text/x-patch)]

Index: misc/htmlnames.h
===================================================================
--- misc/htmlnames.h	(Revision 1183252)
+++ misc/htmlnames.h	(Arbeitskopie)
@@ -620,6 +620,7 @@
 #define ID_CLOSE_TAG 16384
 #define ATTR_LAST_ATTR 254
 #define ATTR_LAST_CI_ATTR 210
+#define ATTR_STEP ((DOM::xmlNamespace << 16) | 556)
 
 #define caseSensitiveAttr(id) (((localNamePart(id)) > ATTR_LAST_CI_ATTR || (id) == \
ATTR_ABBR || (id) == ATTR_CITE || (id) == ATTR_CODE || (id) == ATTR_LABEL || (id) == \
ATTR_OBJECT || (id) == ATTR_TITLE))  
Index: misc/htmlnames.cpp
===================================================================
--- misc/htmlnames.cpp	(Revision 1183252)
+++ misc/htmlnames.cpp	(Arbeitskopie)
@@ -518,6 +518,7 @@
     s_idTable->addStaticMapping(localNamePart(ATTR_STDDEVIATION), "stdDeviation");
     s_idTable->addStaticMapping(localNamePart(ATTR_STEMH), "stemh");
     s_idTable->addStaticMapping(localNamePart(ATTR_STEMV), "stemv");
+    s_idTable->addStaticMapping(localNamePart(ATTR_STEP), "step");
     s_idTable->addStaticMapping(localNamePart(ATTR_STITCHTILES), "stitchTiles");
     s_idTable->addStaticMapping(localNamePart(ATTR_STOP_COLOR), "stop-color");
     s_idTable->addStaticMapping(localNamePart(ATTR_STOP_OPACITY), "stop-opacity");
Index: html/html_formimpl.cpp
===================================================================
--- html/html_formimpl.cpp	(Revision 1183252)
+++ html/html_formimpl.cpp	(Arbeitskopie)
@@ -66,8 +66,8 @@
 #include <ksslkeygen.h>
 
 #include <assert.h>
+#include <float.h>
 
-
 using namespace DOM;
 using namespace khtml;
 using namespace WTF;
@@ -1289,6 +1289,10 @@
     m_inited = false;
     m_unsubmittedFormChange = false;
 
+    m_numberMin = FLT_MIN;
+    m_numberMax = FLT_MAX;
+    m_numberStep = 1.0;
+
     xPos = 0;
     yPos = 0;
 
@@ -1337,6 +1341,8 @@
         newType = BUTTON;
     else if ( strcasecmp( t, "khtml_isindex" ) == 0 )
         newType = ISINDEX;
+    else if ( strcasecmp( t, "number" ) == 0 )
+        newType = NUMBER;
     else
         newType = TEXT;
 
@@ -1375,6 +1381,7 @@
     case HIDDEN: return "hidden";
     case IMAGE: return "image";
     case BUTTON: return "button";
+    case NUMBER: return "number";
     default: return "";
     }
 }
@@ -1503,6 +1510,34 @@
         setHTMLEventListener(EventImpl::CHANGE_EVENT,
             document()->createHTMLEventListener(attr->value().string(), "onchange", \
this));  break;
+    case ATTR_MIN:
+    {
+        bool ok;
+        float tmp = attr->value().toFloat(&ok);
+        if (ok)
+            m_numberMin = tmp;
+        break;
+    }
+    case ATTR_MAX:
+    {
+        bool ok;
+        float tmp = attr->value().toFloat(&ok);
+        if (ok)
+            m_numberMax = tmp;
+        break;
+    }
+    case ATTR_STEP:
+    {
+        bool ok;
+        float tmp = attr->value().toFloat(&ok);
+        // W3C HTML5 says: "The step scale factor is 1. The default step is 1
+        // (allowing only integers, unless the min attribute has a non-integer \
value)." +        if ((int)m_numberMin == m_numberMin)
+            ok = ((int)tmp == tmp);
+        if (ok)
+            m_numberStep = tmp;
+        break;
+    }
     default:
         HTMLGenericFormElementImpl::parseAttribute(attr);
     }
@@ -1576,6 +1611,7 @@
         case FILE:         m_render =  new (document()->renderArena()) \
                RenderFileButton(this);    break;
         case BUTTON:  m_render = new (document()->renderArena()) \
RenderPushButton(this);  case HIDDEN:   break;
+        case NUMBER:  m_render = new (document()->renderArena()) \
RenderNumberEdit(this); break;  }
     }
 
@@ -1716,6 +1752,7 @@
         case HIDDEN:
         case TEXT:
         case PASSWORD:
+        case NUMBER:
             // always successful
             encoding += fixUpfromUnicode(codec, value().string());
             return true;
@@ -1832,6 +1869,7 @@
             case SEARCH:
         #endif
             case TEXT:
+            case NUMBER:
                 break;
         }
     }
Index: html/html_formimpl.h
===================================================================
--- html/html_formimpl.h	(Revision 1183252)
+++ html/html_formimpl.h	(Arbeitskopie)
@@ -41,6 +41,7 @@
     class RenderLineEdit;
     class RenderRadioButton;
     class RenderFileButton;
+    class RenderNumberEdit;
 
     typedef QList<QByteArray> encodingList;
 }
@@ -252,6 +253,7 @@
     friend class khtml::RenderLineEdit;
     friend class khtml::RenderRadioButton;
     friend class khtml::RenderFileButton;
+    friend class khtml::RenderNumberEdit;
 
 public:
     // do not change the order!
@@ -266,7 +268,8 @@
         FILE,
         HIDDEN,
         IMAGE,
-        BUTTON
+        BUTTON,
+        NUMBER
     };
 
     HTMLInputElementImpl(DocumentImpl *doc, HTMLFormElementImpl *f = 0);
@@ -289,6 +292,9 @@
     int size() const { return m_size; }
     DOMString type() const;
     void setType(const DOMString& t);
+    float minValue() const { return m_numberMin; }
+    float maxValue() const { return m_numberMax; }
+    float step() const { return m_numberStep; }
 
     DOMString value() const;
     void setValue(DOMString val);
@@ -351,6 +357,9 @@
     bool m_autocomplete : 1;
     bool m_inited : 1;
     bool m_unsubmittedFormChange : 1;
+    float m_numberMin;
+    float m_numberMax;
+    float m_numberStep;
 };
 
 // -------------------------------------------------------------------------
Index: rendering/render_form.h
===================================================================
--- rendering/render_form.h	(Revision 1183252)
+++ rendering/render_form.h	(Arbeitskopie)
@@ -39,6 +39,7 @@
 #include <QtGui/QCheckBox>
 #include <QtGui/QRadioButton>
 #include <QtGui/QPushButton>
+#include <QtGui/QDoubleSpinBox>
 #include <klistwidget.h>
 #include <kcombobox.h>
 #include "dom/dom_misc.h"
@@ -327,6 +328,58 @@
 
 // -------------------------------------------------------------------------
 
+class RenderNumberEdit : public RenderFormElement
+{
+    Q_OBJECT
+public:
+    RenderNumberEdit(DOM::HTMLInputElementImpl *element);
+    virtual ~RenderNumberEdit();
+
+    virtual void calcMinMaxWidth();
+
+    virtual const char *renderName() const { return "RenderNumberEdit"; }
+    virtual void updateFromElement();
+    virtual void setStyle(RenderStyle *style);
+    virtual short baselinePosition( bool ) const;
+    virtual void handleFocusOut();
+
+    void select();
+
+    QDoubleSpinBox *widget() const { return static_cast<QDoubleSpinBox*>(m_widget); \
} +    DOM::HTMLInputElementImpl* element() const
+    { return static_cast<DOM::HTMLInputElementImpl*>(RenderObject::element()); }
+
+public Q_SLOTS:
+    void slotReturnPressed();
+    void slotValueChanged(double d);
+protected:
+
+private:
+    virtual bool isEditable() const { return true; }
+    virtual bool canHaveBorder() const { return true; }
+};
+
+// -------------------------------------------------------------------------
+
+class NumberEditWidget : public QDoubleSpinBox, public KHTMLWidget
+{
+    Q_OBJECT
+public:
+    NumberEditWidget(DOM::HTMLInputElementImpl* input,
+                   KHTMLView* view, QWidget* parent);
+    ~NumberEditWidget();
+    void setFocus();
+
+protected:
+    virtual void paintEvent( QPaintEvent *pe );
+
+private:
+    DOM::HTMLInputElementImpl* m_input;
+    KHTMLView* m_view;
+};
+
+// -------------------------------------------------------------------------
+
 class RenderFieldset : public RenderBlock
 {
 public:
Index: rendering/render_form.cpp
===================================================================
--- rendering/render_form.cpp	(Revision 1183252)
+++ rendering/render_form.cpp	(Arbeitskopie)
@@ -766,6 +766,22 @@
         setText( s );
 }
 
+NumberEditWidget::NumberEditWidget(DOM::HTMLInputElementImpl* input, KHTMLView* \
view, QWidget* parent) +    : QDoubleSpinBox(parent), m_input(input), m_view(view)
+{
+    m_kwp->setIsRedirected( true );
+    setMouseTracking(true);
+}
+
+NumberEditWidget::~NumberEditWidget()
+{
+}
+
+void NumberEditWidget::setFocus()
+{
+    QDoubleSpinBox::setFocus();
+}
+
 namespace khtml {
 
 /**
@@ -1008,6 +1024,15 @@
     setDragEnabled(true);
 }
 
+void NumberEditWidget::paintEvent( QPaintEvent *pe )
+{
+    if (!hasFrame()) {
+        QPainter p(this);
+        p.fillRect(pe->rect(), palette().brush(QPalette::Base));
+        p.end();
+    }
+    QDoubleSpinBox::paintEvent( pe );
+}
 
 // -----------------------------------------------------------------------------
 
@@ -1210,6 +1235,100 @@
     w->setSelection(start, end - start);
 }
 
+// -----------------------------------------------------------------------------
+
+RenderNumberEdit::RenderNumberEdit(HTMLInputElementImpl *element)
+    : RenderFormElement(element)
+{
+    NumberEditWidget *edit = new NumberEditWidget(element, view(), \
view()->widget()); +    connect(edit,SIGNAL(returnPressed()), this, \
SLOT(slotReturnPressed())); +    \
connect(edit,SIGNAL(valueChanged(double)),this,SLOT(slotValueChanged(double))); +
+    edit->setRange( element->minValue(), element->maxValue() );
+    edit->setSingleStep( element->step() );
+
+    // we need only to check the minimum value here
+    // if the minimum is an int, step is only allowed to be int, too
+    if ( (int)element->minValue() == element->minValue() )
+        edit->setDecimals(0);
+
+    setQWidget(edit);
+}
+
+RenderNumberEdit::~RenderNumberEdit()
+{
+}
+
+short RenderNumberEdit::baselinePosition( bool f ) const
+{
+    bool hasFrame = static_cast<NumberEditWidget*>(widget())->hasFrame();
+    int bTop = hasFrame ? 0 : borderTop();
+    int bBottom = hasFrame ? 0 : borderBottom();
+    int ret = (height()-RenderWidget::paddingTop()-RenderWidget::paddingBottom()-bTop-bBottom+1)/2;
 +    ret += marginTop() + RenderWidget::paddingTop() + bTop;
+    ret += ((fontMetrics( f ).ascent())/2)-2;
+    return ret;
+}
+
+void RenderNumberEdit::setStyle(RenderStyle* _style)
+{
+    RenderFormElement::setStyle( _style );
+
+    widget()->setAlignment(textAlignment());
+}
+
+void RenderNumberEdit::slotReturnPressed()
+{
+}
+
+void RenderNumberEdit::handleFocusOut()
+{
+}
+
+void RenderNumberEdit::calcMinMaxWidth()
+{
+    KHTMLAssert( !minMaxKnown() );
+
+    const QFontMetrics &fm = style()->fontMetrics();
+    QSize s;
+
+    int size = element()->size();
+
+    int h = fm.lineSpacing();
+    int w = fm.width( 'x' ) * (size > 0 ? size+1 : 17); // "some"
+
+    QStyleOptionFrame opt;
+    opt.initFrom(widget());
+    if (static_cast<NumberEditWidget*>(widget())->hasFrame())
+        opt.lineWidth = widget()->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, \
&opt, widget()); +
+    s = QSize(w, qMax(h, 14));
+    s = widget()->style()->sizeFromContents(QStyle::CT_LineEdit, &opt, s, widget());
+    s = s.expandedTo(QApplication::globalStrut());
+
+    setIntrinsicWidth( s.width() );
+    setIntrinsicHeight( s.height() );
+
+    RenderFormElement::calcMinMaxWidth();
+}
+
+void RenderNumberEdit::updateFromElement()
+{
+    if (element()->value().toInt() != widget()->value()) {
+        widget()->setValue(element()->value().toInt());
+    }
+    widget()->setReadOnly(element()->readOnly());
+
+    RenderFormElement::updateFromElement();
+}
+
+void RenderNumberEdit::slotValueChanged(double d)
+{
+    // don't use setValue here!
+    element()->m_value = QString::number(d);
+    element()->m_unsubmittedFormChange = true;
+}
+
 // ---------------------------------------------------------------------------
 
 RenderFieldset::RenderFieldset(HTMLGenericFormElementImpl *element)


["signature.asc" (application/pgp-signature)]

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic