/*************************************************************************** * ktouchkey.cpp * * ------------- * * Copyright (C) 2000 by Håvard Frøiland, 2004 by Andreas Nicolai * * ghorwin@users.sourceforge.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "ktouchkey.h" #include "ktouchkey.moc" #include #include #include #include #include "ktouchcolorscheme.h" #include "ktouchkeyboard.h" #include "prefs.h" const double PEN_WIDTH = 1.0; // ************************** // ***** Public functions *** // ************************** KTouchKey::KTouchKey(QObject * parent) : QObject(parent), m_state(NormalState), m_colorIndex(-1), m_type(Normal), m_x(0), m_y(0), m_w(0), m_h(0), m_fingerKeyIndex(-1), m_fingerKey(NULL) { m_keyChar[0] = QChar(); m_keyChar[1] = QChar(); m_keyChar[2] = QChar(); m_keyChar[3] = QChar(); setPos(m_x, m_y); setZValue(0); } // ----------------------------------------------------------------------------- KTouchKey::KTouchKey(QObject * parent, keytype_t type, int x, int y, int w, int h, QChar ch) : QObject(parent), m_state(NormalState), m_colorIndex(-1), m_type(type), m_x(x), m_y(y), m_w(w), m_h(h), m_fingerKeyIndex(-1), m_fingerKey(NULL) { m_keyChar[0] = ch; m_keyChar[1] = QChar(); m_keyChar[2] = QChar(); m_keyChar[3] = QChar(); setPos(m_x, m_y); } // ---------------------------------------------------------------------------- KTouchKey::KTouchKey(QObject * parent, int x, int y, int w, int h, const QString &text) : QObject(parent), m_state(NormalState), m_colorIndex(-1), m_x(x), m_y(y), m_w(w), m_h(h), m_fingerKeyIndex(-1), m_fingerKey(NULL) { m_type = Other; m_keyChar[0] = QChar(); m_keyText = text; setPos(m_x, m_y); } // ---------------------------------------------------------------------------- // Reads the key data from the DomElement bool KTouchKey::read(const QDomElement &e) { if (e.hasAttribute("Type")) { QString typetext = e.attribute("Type"); m_type = keyType(typetext); if (m_type == Other) { if (e.hasAttribute("KeyText")) m_keyText = e.attribute("KeyText"); } } QDomElement charElement = e.firstChildElement("Char"); while (!charElement.isNull()) { position_t pos = TopLeft; if (charElement.hasAttribute("Position")) { QString position = charElement.attribute("Position"); if (position == "TopLeft") pos = TopLeft; else if (position == "TopRight") pos = TopRight; else if (position == "BottomLeft") pos = BottomLeft; else if (position == "BottomRight") pos = BottomRight; } if (charElement.hasAttribute("Unicode")) m_keyChar[pos] = QChar(charElement.attribute("Unicode").toInt()); else m_keyChar[pos] = QChar(); // do we have a character? QDomNode chNode = charElement.firstChild(); if (!chNode.isNull()) { QString chstr = chNode.nodeValue(); if (chstr.count() > 0) { QChar ch = chstr[0]; if (m_keyChar[pos]!=QChar() && m_keyChar[pos]!=ch.unicode()) { kDebug() << "Character '" << ch << "' is defined with different unicode, the given unicode " "value is used and the display character. is discarted. If you want to use the display " "character, delete the unicode property." << endl; } if (m_keyChar[pos]==QChar()) m_keyChar[pos] = ch.unicode(); } } charElement = charElement.nextSiblingElement("Char"); } if (e.hasAttribute("Width")) m_w = e.attribute("Width").toInt(); if (e.hasAttribute("Height")) m_h = e.attribute("Height").toInt(); if (e.hasAttribute("X")) m_x = e.attribute("X").toInt(); if (e.hasAttribute("Y")) m_y = e.attribute("Y").toInt(); if (e.hasAttribute("FingerKeyIndex")) m_fingerKeyIndex = e.attribute("FingerKeyIndex").toInt(); else m_fingerKeyIndex = -1; setPos(m_x, m_y); //kDebug() << "Key = " << m_keyChar[TopLeft] << " " << m_x << " " << m_y << " " << m_w << " " << m_h; return true; } // ---------------------------------------------------------------------------- // Writes the key data into the DomElement void KTouchKey::write(QDomDocument& doc, QDomElement& root, const QList& keys) const { QDomElement element = doc.createElement("Key"); element.setAttribute("Type", keyTypeString(m_type)); if (m_type == Other) element.setAttribute("KeyText", m_keyText); // write the characters for (int i=0; i<4; ++i) { if (m_keyChar[i] != QChar()) { QDomElement char_element = doc.createElement("Char"); char_element.setAttribute("Unicode", m_keyChar[i].unicode()); QString position; switch (i) { case 0 : position = "TopLeft"; break; case 1 : position = "TopRight"; break; case 2 : position = "BottomLeft"; break; case 3 : position = "BottomRight"; break; } char_element.setAttribute("Unicode", m_keyChar[i].unicode()); char_element.setAttribute("Position", position); QDomText t = doc.createTextNode(QString(m_keyChar[i])); char_element.appendChild(t); element.appendChild(char_element); } } element.setAttribute("X", m_x); element.setAttribute("Y", m_y); element.setAttribute("Width", m_w); element.setAttribute("Height", m_h); if (m_fingerKey != NULL) { int index = keys.indexOf(m_fingerKey); if (index != -1) element.setAttribute("FingerKeyIndex", index); } root.appendChild(element); } // ---------------------------------------------------------------------------- void KTouchKey::setState(state_t state) { m_state = state; update(); } // ---------------------------------------------------------------------------- QRectF KTouchKey::boundingRect() const { return QRectF(- PEN_WIDTH/2.0, - PEN_WIDTH/2.0, m_w + PEN_WIDTH, m_h + PEN_WIDTH); } // ---------------------------------------------------------------------------- void KTouchKey::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); Q_UNUSED(widget); // get the colorscheme from the configuration const KTouchColorScheme& colorScheme = KTouchColorScheme::m_colorSchemes[Prefs::currentColorScheme()]; // first draw the background switch (m_state) { case NormalState : case DisabledState : { switch (m_type) { case Normal : case Finger : { //Q_ASSERT(m_colorIndex < 8); QLinearGradient grad(QPointF(0,0), QPointF(0.3*m_h,1.3*m_h)); //kDebug() << m_keyChar[0] << " m_colorIndex = " << m_colorIndex; QColor c; if (m_colorIndex<8) { c = colorScheme.m_background[m_colorIndex]; grad.setColorAt(0,c); qreal h, s, v, a; c.getHsvF(&h, &s, &v, &a); c.setHsvF(h, s, v*0.8, a); grad.setColorAt(1,c); painter->setBrush( QBrush(grad) ); } else { c = widget->palette().color(QPalette::Background); painter->setBrush( c ); } QPen p(colorScheme.m_frame); p.setWidth(0); // only one pixel! painter->setPen( p ); painter->drawRect(0, 0, m_w, m_h); // Finger keys get a special decoration if (m_type == Finger) { QRadialGradient radgrad(QPointF(m_w/2, m_h/2), qMin(m_w, m_h)*0.48, QPointF(m_w/2*0.9, m_h/2*0.9) ); radgrad.setColorAt(0, c); radgrad.setColorAt(0.9, QColor(255,255,255,196)); radgrad.setColorAt(1, QColor(0,0,0,48)); painter->setBrush( QBrush(radgrad) ); painter->drawRect(0, 0, m_w, m_h); } } break; default : { QLinearGradient grad(QPointF(0,0), QPointF(0,m_h)); QColor c = colorScheme.m_cBackground; grad.setColorAt(0,c); qreal h, s, v, a; c.getHsvF(&h, &s, &v, &a); c.setHsvF(h, s, v*0.7, a); grad.setColorAt(1,c); painter->setBrush( QBrush(grad) ); QPen p(colorScheme.m_frame); p.setWidth(0); // only one pixel! painter->setPen( p ); painter->drawRect(0, 0, m_w, m_h); } } // switch if (m_state == DisabledState) { // overlay the key with a semitransparent, grey color to indicate that they have to be learned yet painter->setBrush( QBrush( QColor(40,40,40,196)) ); QPen p(colorScheme.m_frame); p.setWidth(0); // only one pixel! p.setStyle( Qt::NoPen ); painter->setPen( p ); painter->drawRect(0, 0, m_w+1, m_h+1); } } break; // NormalState case HighlightedState : { switch (m_type) { case Normal : case Finger : { //Q_ASSERT(m_colorIndex < 8); QLinearGradient grad(QPointF(0,0), QPointF(0.3*m_h,1.3*m_h)); QColor c = colorScheme.m_backgroundH; grad.setColorAt(0,c); qreal h, s, v, a; c.getHsvF(&h, &s, &v, &a); c.setHsvF(h, s, v*0.8, a); grad.setColorAt(1,c); painter->setBrush( QBrush(grad) ); QPen p(colorScheme.m_frame); p.setWidth(0); // only one pixel! painter->setPen( p ); painter->drawRect(0, 0, m_w, m_h); } break; default : { QLinearGradient grad(QPointF(0,0), QPointF(0,m_h)); QColor c = colorScheme.m_cBackgroundH; grad.setColorAt(0,c); qreal h, s, v, a; c.getHsvF(&h, &s, &v, &a); c.setHsvF(h, s, v*0.7, a); grad.setColorAt(1,c); painter->setBrush( QBrush(grad) ); QPen p(colorScheme.m_frame); p.setWidth(0); // only one pixel! painter->setPen( p ); painter->drawRect(0, 0, m_w, m_h); } } // switch } break; // HighlightedState case FingerKeyState : { QLinearGradient grad(QPointF(0,0), QPointF(0.3*m_h,1.3*m_h)); QColor c; if (m_colorIndex<8) { c = colorScheme.m_background[m_colorIndex]; grad.setColorAt(0,c); qreal h, s, v, a; c.getHsvF(&h, &s, &v, &a); c.setHsvF(h, s, v*0.8, a); grad.setColorAt(1,c); painter->setBrush( QBrush(grad) ); } else { c = widget->palette().color(QPalette::Background); painter->setBrush( c ); } QPen p(colorScheme.m_frame); p.setWidth(0); // only one pixel! painter->setPen( p ); painter->drawRect(0, 0, m_w, m_h); } break; // FingerKeyState } // draw text/decoration KTouchKeyboard * kb = dynamic_cast(parent()); QFont f = kb->font(); // painter->setRenderHint(QPainter::Antialiasing); QPen p; switch (m_state) { case HighlightedState : { switch (m_type) { case Normal : case Finger : { p.setColor(colorScheme.m_textH); } break; default : { p.setColor(colorScheme.m_cTextH); } } } break; default : { switch (m_type) { case Normal : case Finger : { p.setColor(colorScheme.m_text); } break; default : { p.setColor(colorScheme.m_cText); } } } } p.setWidthF(3); p.setJoinStyle(Qt::RoundJoin); painter->setPen( p ); qreal h = qMin(m_w, m_h); qreal ch = h*0.5; // the height for the special chars switch (m_type) { case Normal : case Finger : { // only one topleft character? if (m_keyChar[KTouchKey::TopLeft] != QChar() && m_keyChar[KTouchKey::BottomLeft] == QChar()) { // print the character a little bit bigger f.setPixelSize( int(qMax(0.01, m_h*0.4) + 0.5) ); painter->setFont( f ); painter->drawText(QRectF(m_h*0.1, m_h*0.1, m_h*0.6, m_h*0.6), Qt::AlignCenter | Qt::AlignVCenter, m_keyChar[0]); // if we also have a bottom right character, print it small if (m_keyChar[KTouchKey::BottomRight] != QChar()) { f.setPixelSize( int(qMax(0.01, m_h*0.3) + 0.5) ); painter->setFont( f ); painter->drawText(QRectF(m_h*0.2, m_h*0.05, m_w - m_h*0.3, m_h*0.95), Qt::AlignRight | Qt::AlignBottom, m_keyChar[KTouchKey::BottomRight]); } } else { f.setPixelSize( int(qMax(0.01, m_h*0.3) + 0.5) ); painter->setFont( f ); // print each character in one corner if (m_keyChar[KTouchKey::TopLeft] != QChar()) { painter->drawText(QRectF(m_h*0.2, m_h*0.05, m_w - m_h*0.4, m_h*0.92), Qt::AlignLeft | Qt::AlignTop, m_keyChar[KTouchKey::TopLeft]); } if (m_keyChar[KTouchKey::TopRight] != QChar()) { painter->drawText(QRectF(m_h*0.2, m_h*0.05, m_w - m_h*0.3, m_h*0.92), Qt::AlignRight | Qt::AlignTop, m_keyChar[KTouchKey::TopRight]); } if (m_keyChar[KTouchKey::BottomLeft] != QChar()) { painter->drawText(QRectF(m_h*0.2, m_h*0.05, m_w - m_h*0.4, m_h*0.92), Qt::AlignLeft | Qt::AlignBottom, m_keyChar[KTouchKey::BottomLeft]); } if (m_keyChar[KTouchKey::BottomRight] != QChar()) { painter->drawText(QRectF(m_h*0.2, m_h*0.05, m_w - m_h*0.3, m_h*0.92), Qt::AlignRight | Qt::AlignBottom, m_keyChar[KTouchKey::BottomRight]); } } } break; case Enter : { qreal xleft = 0+h/2-ch/2; qreal xright = 0 + qMin(m_w-h/2+ch/2,h); qreal y = 0+m_h/2; QPainterPath path; path.moveTo(xright, y-ch/2); path.lineTo(xright, y); path.lineTo(xleft+ch/3, y); path.lineTo(xleft+ch/3, y-static_cast(ch*0.15)); path.lineTo(xleft, y); path.lineTo(xleft+ch/3, y+static_cast(ch*0.15)); path.lineTo(xleft+ch/3, y); painter->drawPath(path); } break; case Backspace : { qreal xleft = 0+h/2-ch/2; qreal xright = 0 + qMin(m_w-h/2+ch/2,h); qreal y = 0+m_h/2; QPainterPath path; path.moveTo(xright, y); path.lineTo(xleft+ch/3, y); path.lineTo(xleft+ch/3, y-static_cast(ch*0.15)); path.lineTo(xleft, y); path.lineTo(xleft+ch/3, y+static_cast(ch*0.15)); path.lineTo(xleft+ch/3, y); painter->drawPath(path); } break; case Shift : { qreal x = 0+h/2; qreal y = 0+m_h/2; QPainterPath path; path.moveTo(x-ch/2, y); path.lineTo(x-ch/4, y); path.lineTo(x-ch/4, y+ch/2); path.lineTo(x+ch/4, y+ch/2); path.lineTo(x+ch/4, y); path.lineTo(x+ch/2, y); path.lineTo(x, y-ch/2); path.lineTo(x-ch/2, y); painter->drawPath(path); } break; case CapsLock : { qreal x = 0+h/2; qreal y = 0+m_h/2; QPainterPath path; path.moveTo(x-ch/2, y); path.lineTo(x-ch/4, y); path.lineTo( x-ch/4, y-ch/2); path.lineTo(x+ch/4, y-ch/2); path.lineTo(x+ch/4, y); path.lineTo(x+ch/2, y); path.lineTo(x, y+ch/2); path.lineTo(x-ch/2, y); painter->drawPath(path); } break; case Tab : { qreal xleft = 0+h/2-ch/2; qreal xright = 0 + qMin(m_w-h/2+ch/2,h); qreal y = 0+m_h/2; painter->drawLine(QLineF(xleft, y, xleft, y-ch/2)); QPainterPath pathLeft; { QPainterPath path; path.moveTo(xright, y-ch/4); path.lineTo(xleft+ch/3, y-ch/4); path.lineTo(xleft+ch/3, y-ch*0.15-ch/4); path.lineTo(xleft, y-ch/4); path.lineTo(xleft+ch/3, y+ch*0.15-ch/4); path.lineTo(xleft+ch/3, y-ch/4); painter->drawPath(path); } { painter->drawLine(QLineF(xright+2, y, xright+2, y+ch/2)); QPainterPath path; path.moveTo(xleft, y+ch/4); path.lineTo(xright-ch/3, y+ch/4); path.lineTo(xright-ch/3, y+ch*0.15+ch/4); path.lineTo(xright, y+ch/4); path.lineTo(xright-ch/3, y-ch*0.15+ch/4); path.lineTo(xright-ch/3, y+ch/4); painter->drawPath(path); } } break; case Space : ; break; // nothing on space key case Other : f.setPixelSize( int(qMax(0.01, m_h*0.4) + 0.5) ); painter->setFont( f ); painter->drawText(QRectF(m_h*0.15, m_h*0.15, m_w - m_h*0.3, m_h*0.7), Qt::AlignCenter | Qt::AlignVCenter, m_keyText); break; } // painter->setRenderHint(QPainter::Antialiasing, false); } // ----------------------------------------------------------------------------- // ************************** // ***** Static functions *** // ************************** QString KTouchKey::keyTypeString(KTouchKey::keytype_t t) { switch (t) { case Normal : return "NORMAL"; case Finger : return "FINGER"; case Enter : return "ENTER"; case Backspace : return "BACKSPACE"; case Shift : return "SHIFT"; case CapsLock : return "CAPSLOCK"; case Tab : return "TAB"; case Space : return "SPACE"; default : return "OTHER"; } } // ----------------------------------------------------------------------------- KTouchKey::keytype_t KTouchKey::keyType(const QString& str) { if (str=="NORMAL") return Normal; else if (str=="FINGER") return Finger; else if (str=="ENTER") return Enter; else if (str=="BACKSPACE") return Backspace; else if (str=="SHIFT") return Shift; else if (str=="CAPSLOCK") return CapsLock; else if (str=="TAB") return Tab; else if (str=="SPACE") return Space; else return Other; } // ----------------------------------------------------------------------------- // ***************************** // ***** Protected functions *** // ***************************** void KTouchKey::mousePressEvent(QGraphicsSceneMouseEvent * event) { if (event->button() | Qt::LeftButton) { emit clicked(this); // are we allowed to click/activate the key? KTouchKeyboard * kb = dynamic_cast(parent()); if (kb != NULL && kb->allowKeyClicks()) { QPointF scene_pos = event->scenePos(); m_dragXOffset = scene_pos.x() - m_x; m_dragYOffset = scene_pos.y() - m_y; setZValue(1); // let the event pass through so that the graphics view can handle the selection part } else { event->accept(); } } else { event->accept(); } } // ----------------------------------------------------------------------------- void KTouchKey::mouseMoveEvent(QGraphicsSceneMouseEvent * event) { if (event->button() | Qt::LeftButton) { // are we allowed to click/activate/move the key? KTouchKeyboard * kb = dynamic_cast(parent()); if (kb != NULL && kb->allowKeyClicks()) { QPointF scene_pos = event->scenePos(); m_x = int( (scene_pos.x() - m_dragXOffset + 5)/10 )*10; m_y = int( (scene_pos.y() - m_dragYOffset + 5)/10 )*10; setPos(m_x, m_y); emit positionChanged(this); // let the event pass through so that the graphics view can handle the movement part } else { // this is the default behavior when the keyboard is used during the lecture event->accept(); } } else { event->accept(); } } // ----------------------------------------------------------------------------- void KTouchKey::mouseReleaseEvent(QGraphicsSceneMouseEvent *) { setZValue(0); } // -----------------------------------------------------------------------------