summaryrefslogtreecommitdiff
path: root/inputmethods
Side-by-side diff
Diffstat (limited to 'inputmethods') (more/less context) (ignore whitespace changes)
-rw-r--r--inputmethods/.cvsignore1
-rw-r--r--inputmethods/handwriting/.cvsignore5
-rw-r--r--inputmethods/handwriting/Makefile.in281
-rw-r--r--inputmethods/handwriting/handwriting.pro33
-rw-r--r--inputmethods/handwriting/handwritingimpl.cpp113
-rw-r--r--inputmethods/handwriting/handwritingimpl.h51
-rw-r--r--inputmethods/handwriting/qimpenchar.cpp505
-rw-r--r--inputmethods/handwriting/qimpenchar.h157
-rw-r--r--inputmethods/handwriting/qimpencombining.cpp141
-rw-r--r--inputmethods/handwriting/qimpencombining.h41
-rw-r--r--inputmethods/handwriting/qimpenhelp.cpp410
-rw-r--r--inputmethods/handwriting/qimpenhelp.h85
-rw-r--r--inputmethods/handwriting/qimpeninput.cpp515
-rw-r--r--inputmethods/handwriting/qimpeninput.h94
-rw-r--r--inputmethods/handwriting/qimpenmatch.cpp365
-rw-r--r--inputmethods/handwriting/qimpenmatch.h107
-rw-r--r--inputmethods/handwriting/qimpenprefbase.ui185
-rw-r--r--inputmethods/handwriting/qimpenprofile.cpp245
-rw-r--r--inputmethods/handwriting/qimpenprofile.h70
-rw-r--r--inputmethods/handwriting/qimpensetup.cpp656
-rw-r--r--inputmethods/handwriting/qimpensetup.h124
-rw-r--r--inputmethods/handwriting/qimpenstroke.cpp646
-rw-r--r--inputmethods/handwriting/qimpenstroke.h91
-rw-r--r--inputmethods/handwriting/qimpenwidget.cpp446
-rw-r--r--inputmethods/handwriting/qimpenwidget.h88
-rw-r--r--inputmethods/handwriting/qimpenwordpick.cpp113
-rw-r--r--inputmethods/handwriting/qimpenwordpick.h49
-rw-r--r--inputmethods/handwriting/qpe-handwriting.control9
-rwxr-xr-xinputmethods/handwriting/qpe-handwriting.postinst2
-rwxr-xr-xinputmethods/handwriting/qpe-handwriting.postrm2
-rw-r--r--inputmethods/keyboard/.cvsignore3
-rw-r--r--inputmethods/keyboard/Makefile.in151
-rw-r--r--inputmethods/keyboard/keyboard.cpp794
-rw-r--r--inputmethods/keyboard/keyboard.h103
-rw-r--r--inputmethods/keyboard/keyboard.pro18
-rw-r--r--inputmethods/keyboard/keyboardimpl.cpp131
-rw-r--r--inputmethods/keyboard/keyboardimpl.h51
-rw-r--r--inputmethods/keyboard/qpe-keyboard.control9
-rwxr-xr-xinputmethods/keyboard/qpe-keyboard.postinst2
-rwxr-xr-xinputmethods/keyboard/qpe-keyboard.postrm2
-rw-r--r--inputmethods/pickboard/.cvsignore3
-rw-r--r--inputmethods/pickboard/Makefile.in147
-rw-r--r--inputmethods/pickboard/pickboard.cpp89
-rw-r--r--inputmethods/pickboard/pickboard.h43
-rw-r--r--inputmethods/pickboard/pickboard.pro12
-rw-r--r--inputmethods/pickboard/pickboardcfg.cpp731
-rw-r--r--inputmethods/pickboard/pickboardcfg.h213
-rw-r--r--inputmethods/pickboard/pickboardimpl.cpp101
-rw-r--r--inputmethods/pickboard/pickboardimpl.h51
-rw-r--r--inputmethods/pickboard/pickboardpicks.cpp418
-rw-r--r--inputmethods/pickboard/pickboardpicks.h66
-rw-r--r--inputmethods/pickboard/qpe-pickboard.control9
-rwxr-xr-xinputmethods/pickboard/qpe-pickboard.postinst2
-rwxr-xr-xinputmethods/pickboard/qpe-pickboard.postrm2
-rw-r--r--inputmethods/unikeyboard/.cvsignore3
-rw-r--r--inputmethods/unikeyboard/Makefile.in115
-rw-r--r--inputmethods/unikeyboard/qpe-unikeyboard.control9
-rwxr-xr-xinputmethods/unikeyboard/qpe-unikeyboard.postinst2
-rwxr-xr-xinputmethods/unikeyboard/qpe-unikeyboard.postrm2
-rw-r--r--inputmethods/unikeyboard/unikeyboard.cpp278
-rw-r--r--inputmethods/unikeyboard/unikeyboard.h77
-rw-r--r--inputmethods/unikeyboard/unikeyboard.pro12
-rw-r--r--inputmethods/unikeyboard/unikeyboardimpl.cpp105
-rw-r--r--inputmethods/unikeyboard/unikeyboardimpl.h49
64 files changed, 9433 insertions, 0 deletions
diff --git a/inputmethods/.cvsignore b/inputmethods/.cvsignore
new file mode 100644
index 0000000..f3c7a7c
--- a/dev/null
+++ b/inputmethods/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/inputmethods/handwriting/.cvsignore b/inputmethods/handwriting/.cvsignore
new file mode 100644
index 0000000..285856f
--- a/dev/null
+++ b/inputmethods/handwriting/.cvsignore
@@ -0,0 +1,5 @@
+moc_*
+*.moc
+Makefile
+qimpenprefbase.h
+qimpenprefbase.cpp
diff --git a/inputmethods/handwriting/Makefile.in b/inputmethods/handwriting/Makefile.in
new file mode 100644
index 0000000..aabb5aa
--- a/dev/null
+++ b/inputmethods/handwriting/Makefile.in
@@ -0,0 +1,281 @@
+#############################################################################
+
+####### Compiler, tools and options
+
+CXX = $(SYSCONF_CXX) $(QT_CXX_MT)
+CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) $(SYSCONF_CXXFLAGS_LIB)
+CC = $(SYSCONF_CC) $(QT_C_MT)
+CFLAGS = $(SYSCONF_CFLAGS) $(SYSCONF_CFLAGS_LIB)
+INCPATH = -I$(QPEDIR)/include
+LFLAGS = $(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT)
+LIBS = $(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS_QTAPP)
+MOC = $(SYSCONF_MOC)
+UIC = $(SYSCONF_UIC)
+
+####### Target
+
+DESTDIR = ../../plugins/inputmethods/
+VER_MAJ = 1
+VER_MIN = 0
+VER_PATCH = 0
+TARGET = qhandwriting
+TARGET1 = lib$(TARGET).so.$(VER_MAJ)
+
+####### Files
+
+HEADERS = qimpenchar.h \
+ qimpenprofile.h \
+ qimpencombining.h \
+ qimpenhelp.h \
+ qimpeninput.h \
+ qimpenmatch.h \
+ qimpensetup.h \
+ qimpenstroke.h \
+ qimpenwidget.h \
+ qimpenwordpick.h \
+ handwritingimpl.h
+SOURCES = qimpenchar.cpp \
+ qimpenprofile.cpp \
+ qimpencombining.cpp \
+ qimpenhelp.cpp \
+ qimpeninput.cpp \
+ qimpenmatch.cpp \
+ qimpensetup.cpp \
+ qimpenstroke.cpp \
+ qimpenwidget.cpp \
+ qimpenwordpick.cpp \
+ handwritingimpl.cpp
+OBJECTS = qimpenchar.o \
+ qimpenprofile.o \
+ qimpencombining.o \
+ qimpenhelp.o \
+ qimpeninput.o \
+ qimpenmatch.o \
+ qimpensetup.o \
+ qimpenstroke.o \
+ qimpenwidget.o \
+ qimpenwordpick.o \
+ handwritingimpl.o \
+ qimpenprefbase.o
+INTERFACES = qimpenprefbase.ui
+UICDECLS = qimpenprefbase.h
+UICIMPLS = qimpenprefbase.cpp
+SRCMOC = moc_qimpenhelp.cpp \
+ moc_qimpeninput.cpp \
+ moc_qimpenmatch.cpp \
+ moc_qimpensetup.cpp \
+ moc_qimpenwidget.cpp \
+ moc_qimpenwordpick.cpp \
+ moc_qimpenprefbase.cpp
+OBJMOC = moc_qimpenhelp.o \
+ moc_qimpeninput.o \
+ moc_qimpenmatch.o \
+ moc_qimpensetup.o \
+ moc_qimpenwidget.o \
+ moc_qimpenwordpick.o \
+ moc_qimpenprefbase.o
+
+
+####### Implicit rules
+
+.SUFFIXES: .cpp .cxx .cc .C .c
+
+.cpp.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.cxx.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.cc.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.C.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
+
+####### Build rules
+
+
+all: $(DESTDIR)$(SYSCONF_LINK_TARGET)
+
+$(DESTDIR)$(SYSCONF_LINK_TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS)
+ $(SYSCONF_LINK_LIB)
+
+moc: $(SRCMOC)
+
+tmake:
+ tmake handwriting.pro
+
+clean:
+ -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS)
+ -rm -f *~ core
+ -rm -f allmoc.cpp
+
+####### Extension Modules
+
+listpromodules:
+ @echo
+
+listallmodules:
+ @echo
+
+listaddonpromodules:
+ @echo
+
+listaddonentmodules:
+ @echo
+
+
+REQUIRES=
+
+####### Sub-libraries
+
+
+###### Combined headers
+
+
+
+####### Compile
+
+qimpenchar.o: qimpenchar.cpp \
+ qimpencombining.h \
+ qimpenchar.h \
+ qimpenstroke.h
+
+qimpenprofile.o: qimpenprofile.cpp \
+ qimpencombining.h \
+ qimpenchar.h \
+ qimpenstroke.h \
+ qimpenprofile.h
+
+qimpencombining.o: qimpencombining.cpp \
+ qimpencombining.h \
+ qimpenchar.h \
+ qimpenstroke.h
+
+qimpenhelp.o: qimpenhelp.cpp \
+ qimpenwidget.h \
+ qimpenchar.h \
+ qimpenstroke.h \
+ qimpencombining.h \
+ qimpenmatch.h \
+ qimpenhelp.h \
+ qimpenprofile.h
+
+qimpeninput.o: qimpeninput.cpp \
+ qimpenwidget.h \
+ qimpenchar.h \
+ qimpenstroke.h \
+ qimpensetup.h \
+ qimpenprofile.h \
+ qimpeninput.h \
+ qimpencombining.h \
+ qimpenwordpick.h \
+ qimpenmatch.h \
+ qimpenhelp.h
+
+qimpenmatch.o: qimpenmatch.cpp \
+ qimpenmatch.h \
+ qimpenchar.h \
+ qimpenstroke.h
+
+qimpensetup.o: qimpensetup.cpp \
+ qimpenwidget.h \
+ qimpenchar.h \
+ qimpenstroke.h \
+ qimpenprefbase.h \
+ qimpensetup.h \
+ qimpenprofile.h
+
+qimpenstroke.o: qimpenstroke.cpp \
+ qimpenstroke.h
+
+qimpenwidget.o: qimpenwidget.cpp \
+ qimpenchar.h \
+ qimpenstroke.h \
+ qimpenwidget.h
+
+qimpenwordpick.o: qimpenwordpick.cpp \
+ qimpenwordpick.h \
+ qimpenmatch.h \
+ qimpenchar.h \
+ qimpenstroke.h
+
+handwritingimpl.o: handwritingimpl.cpp \
+ qimpeninput.h \
+ qimpenprofile.h \
+ qimpenchar.h \
+ qimpenstroke.h \
+ handwritingimpl.h
+
+qimpenprefbase.h: qimpenprefbase.ui
+ $(UIC) qimpenprefbase.ui -o $(INTERFACE_DECL_PATH)/qimpenprefbase.h
+
+qimpenprefbase.cpp: qimpenprefbase.ui
+ $(UIC) qimpenprefbase.ui -i qimpenprefbase.h -o qimpenprefbase.cpp
+
+qimpenprefbase.o: qimpenprefbase.cpp \
+ qimpenprefbase.h \
+ qimpenprefbase.ui
+
+moc_qimpenhelp.o: moc_qimpenhelp.cpp \
+ qimpenhelp.h \
+ qimpenchar.h \
+ qimpenstroke.h \
+ qimpenprofile.h
+
+moc_qimpeninput.o: moc_qimpeninput.cpp \
+ qimpeninput.h \
+ qimpenprofile.h \
+ qimpenchar.h \
+ qimpenstroke.h
+
+moc_qimpenmatch.o: moc_qimpenmatch.cpp \
+ qimpenmatch.h \
+ qimpenchar.h \
+ qimpenstroke.h
+
+moc_qimpensetup.o: moc_qimpensetup.cpp \
+ qimpensetup.h \
+ qimpenprofile.h \
+ qimpenchar.h \
+ qimpenstroke.h
+
+moc_qimpenwidget.o: moc_qimpenwidget.cpp \
+ qimpenwidget.h \
+ qimpenchar.h \
+ qimpenstroke.h
+
+moc_qimpenwordpick.o: moc_qimpenwordpick.cpp \
+ qimpenwordpick.h \
+ qimpenmatch.h \
+ qimpenchar.h \
+ qimpenstroke.h
+
+moc_qimpenprefbase.o: moc_qimpenprefbase.cpp \
+ qimpenprefbase.h
+
+moc_qimpenhelp.cpp: qimpenhelp.h
+ $(MOC) qimpenhelp.h -o moc_qimpenhelp.cpp
+
+moc_qimpeninput.cpp: qimpeninput.h
+ $(MOC) qimpeninput.h -o moc_qimpeninput.cpp
+
+moc_qimpenmatch.cpp: qimpenmatch.h
+ $(MOC) qimpenmatch.h -o moc_qimpenmatch.cpp
+
+moc_qimpensetup.cpp: qimpensetup.h
+ $(MOC) qimpensetup.h -o moc_qimpensetup.cpp
+
+moc_qimpenwidget.cpp: qimpenwidget.h
+ $(MOC) qimpenwidget.h -o moc_qimpenwidget.cpp
+
+moc_qimpenwordpick.cpp: qimpenwordpick.h
+ $(MOC) qimpenwordpick.h -o moc_qimpenwordpick.cpp
+
+moc_qimpenprefbase.cpp: qimpenprefbase.h
+ $(MOC) qimpenprefbase.h -o moc_qimpenprefbase.cpp
+
+
diff --git a/inputmethods/handwriting/handwriting.pro b/inputmethods/handwriting/handwriting.pro
new file mode 100644
index 0000000..999552b
--- a/dev/null
+++ b/inputmethods/handwriting/handwriting.pro
@@ -0,0 +1,33 @@
+TEMPLATE = lib
+CONFIG += qt warn_on release
+HEADERS = qimpenchar.h \
+ qimpenprofile.h \
+ qimpencombining.h \
+ qimpenhelp.h \
+ qimpeninput.h \
+ qimpenmatch.h \
+ qimpensetup.h \
+ qimpenstroke.h \
+ qimpenwidget.h \
+ qimpenwordpick.h \
+ handwritingimpl.h
+SOURCES = qimpenchar.cpp \
+ qimpenprofile.cpp \
+ qimpencombining.cpp \
+ qimpenhelp.cpp \
+ qimpeninput.cpp \
+ qimpenmatch.cpp \
+ qimpensetup.cpp \
+ qimpenstroke.cpp \
+ qimpenwidget.cpp \
+ qimpenwordpick.cpp \
+ handwritingimpl.cpp
+INTERFACES = qimpenprefbase.ui
+TARGET = qhandwriting
+DESTDIR = ../../plugins/inputmethods
+INCLUDEPATH += $(QPEDIR)/include
+DEPENDPATH += ../$(QPEDIR)/include ../../taskbar
+LIBS += -lqpe
+VERSION = 1.0.0
+
+TRANSLATIONS += ../../i18n/de/libqhandwriting.ts
diff --git a/inputmethods/handwriting/handwritingimpl.cpp b/inputmethods/handwriting/handwritingimpl.cpp
new file mode 100644
index 0000000..c39e1aa
--- a/dev/null
+++ b/inputmethods/handwriting/handwritingimpl.cpp
@@ -0,0 +1,113 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include <qapplication.h>
+#include <qwidget.h>
+#include <qpixmap.h>
+#include "qimpeninput.h"
+#include "handwritingimpl.h"
+
+/* XPM */
+static const char * pen_xpm[] = {
+"28 13 9 1",
+" c None",
+". c #000000",
+"+ c #FFE993",
+"@ c #8292FF",
+"# c #F7C500",
+"$ c #C69F00",
+"% c #0022FF",
+"& c #000F72",
+"* c #A3732C",
+" . ",
+" .+. ",
+" .@#$. ",
+" .@%&. ",
+" .@%&. ",
+" . .@%&. ",
+" . .@%&. ",
+" . .@%&. ",
+" ... ... .. .@%&. ",
+" . . . . . .*.&. ",
+" . . . . . .**. ",
+" ... ... .. ... ",
+" "};
+
+HandwritingImpl::HandwritingImpl()
+ : input(0), icn(0), ref(0)
+{
+}
+
+HandwritingImpl::~HandwritingImpl()
+{
+ delete input;
+ delete icn;
+}
+
+QWidget *HandwritingImpl::inputMethod( QWidget *parent, Qt::WFlags f )
+{
+ if ( !input )
+ input = new QIMPenInput( parent, "Handwriting", f );
+ return input;
+}
+
+void HandwritingImpl::resetState()
+{
+ if ( input )
+ input->resetState();
+}
+
+QPixmap *HandwritingImpl::icon()
+{
+ if ( !icn )
+ icn = new QPixmap( (const char **)pen_xpm );
+ return icn;
+}
+
+QString HandwritingImpl::name()
+{
+ return qApp->translate( "InputMethods", "Handwriting" );
+}
+
+void HandwritingImpl::onKeyPress( QObject *receiver, const char *slot )
+{
+ if ( input )
+ QObject::connect( input, SIGNAL(key(ushort,ushort,ushort,bool,bool)), receiver, slot );
+}
+
+#ifndef QT_NO_COMPONENT
+QRESULT HandwritingImpl::queryInterface( const QUuid &uuid, QUnknownInterface **iface )
+{
+ *iface = 0;
+ if ( uuid == IID_QUnknown )
+ *iface = this;
+ else if ( uuid == IID_InputMethod )
+ *iface = this;
+
+ if ( *iface )
+ (*iface)->addRef();
+ return QS_OK;
+}
+
+Q_EXPORT_INTERFACE()
+{
+ Q_CREATE_INSTANCE( HandwritingImpl )
+}
+#endif
diff --git a/inputmethods/handwriting/handwritingimpl.h b/inputmethods/handwriting/handwritingimpl.h
new file mode 100644
index 0000000..1215853
--- a/dev/null
+++ b/inputmethods/handwriting/handwritingimpl.h
@@ -0,0 +1,51 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#ifndef HANDWRITINGIMPL_H
+#define HANDWRITINGIMPL_H
+
+#include <qpe/inputmethodinterface.h>
+
+class QIMPenInput;
+class QPixmap;
+
+class HandwritingImpl : public InputMethodInterface
+{
+public:
+ HandwritingImpl();
+ virtual ~HandwritingImpl();
+
+#ifndef QT_NO_COMPONENT
+ QRESULT queryInterface( const QUuid&, QUnknownInterface** );
+ Q_REFCOUNT
+#endif
+
+ virtual QWidget *inputMethod( QWidget *parent, Qt::WFlags f );
+ virtual void resetState();
+ virtual QPixmap *icon();
+ virtual QString name();
+ virtual void onKeyPress( QObject *receiver, const char *slot );
+
+private:
+ QIMPenInput *input;
+ QPixmap *icn;
+ ulong ref;
+};
+
+#endif
diff --git a/inputmethods/handwriting/qimpenchar.cpp b/inputmethods/handwriting/qimpenchar.cpp
new file mode 100644
index 0000000..9c38ec9
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenchar.cpp
@@ -0,0 +1,505 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include <qfile.h>
+#include <qtl.h>
+#include <math.h>
+#include <limits.h>
+#include <errno.h>
+#include <qdatastream.h>
+#include "qimpencombining.h"
+#include "qimpenchar.h"
+
+#define QIMPEN_MATCH_THRESHOLD 200000
+
+const QIMPenSpecialKeys qimpen_specialKeys[] = {
+ { Qt::Key_Escape, "[Esc]" },
+ { Qt::Key_Tab, "[Tab]" },
+ { Qt::Key_Backspace, "[BackSpace]" },
+ { Qt::Key_Return, "[Return]" },
+ { QIMPenChar::Caps, "[Uppercase]" },
+ { QIMPenChar::CapsLock, "[Caps Lock]" },
+ { QIMPenChar::Shortcut, "[Shortcut]" },
+ { QIMPenChar::Punctuation, "[Punctuation]" },
+ { QIMPenChar::Symbol, "[Symbol]" },
+ { QIMPenChar::Extended, "[Extended]" },
+ { Qt::Key_unknown, 0 } };
+
+
+/*!
+ \class QIMPenChar qimpenchar.h
+
+ Handles a single character. Can calculate closeness of match to
+ another character.
+*/
+
+QIMPenChar::QIMPenChar()
+{
+ flags = 0;
+ strokes.setAutoDelete( TRUE );
+}
+
+QIMPenChar::QIMPenChar( const QIMPenChar &chr )
+{
+ strokes.setAutoDelete( TRUE );
+ ch = chr.ch;
+ flags = chr.flags;
+ d = chr.d;
+ QIMPenStrokeIterator it( chr.strokes );
+ while ( it.current() ) {
+ strokes.append( new QIMPenStroke( *it.current() ) );
+ ++it;
+ }
+}
+
+QIMPenChar &QIMPenChar::operator=( const QIMPenChar &chr )
+{
+ strokes.clear();
+ ch = chr.ch;
+ flags = chr.flags;
+ d = chr.d;
+ QIMPenStrokeIterator it( chr.strokes );
+ while ( it.current() ) {
+ strokes.append( new QIMPenStroke( *it.current() ) );
+ ++it;
+ }
+
+ return *this;
+}
+
+QString QIMPenChar::name() const
+{
+ QString n;
+
+ if ( (ch & 0x0000FFFF) == 0 ) {
+ int code = ch >> 16;
+ for ( int i = 0; qimpen_specialKeys[i].code != Qt::Key_unknown; i++ ) {
+ if ( qimpen_specialKeys[i].code == code ) {
+ n = qimpen_specialKeys[i].name;
+ break;
+ }
+ }
+ } else {
+ n = QChar( ch & 0x0000FFFF );
+ }
+
+ return n;
+}
+
+void QIMPenChar::clear()
+{
+ ch = 0;
+ flags = 0;
+ d = QString::null;
+ strokes.clear();
+}
+
+unsigned int QIMPenChar::strokeLength( int s ) const
+{
+ QIMPenStrokeIterator it( strokes );
+ while ( it.current() && s ) {
+ ++it;
+ --s;
+ }
+
+ if ( it.current() )
+ return it.current()->length();
+
+ return 0;
+}
+
+/*!
+ Add a stroke to the character
+*/
+void QIMPenChar::addStroke( QIMPenStroke *st )
+{
+ QIMPenStroke *stroke = new QIMPenStroke( *st );
+ strokes.append( stroke );
+}
+
+/*!
+ Return an indicator of the closeness of this character to \a pen.
+ Lower value is better.
+*/
+int QIMPenChar::match( QIMPenChar *pen )
+{
+/*
+ if ( strokes.count() > pen->strokes.count() )
+ return INT_MAX;
+*/
+ int err = 0;
+ int maxErr = 0;
+ int diff = 0;
+ QIMPenStrokeIterator it1( strokes );
+ QIMPenStrokeIterator it2( pen->strokes );
+ err = it1.current()->match( it2.current() );
+ if ( err > maxErr )
+ maxErr = err;
+ ++it1;
+ ++it2;
+ while ( err < 400000 && it1.current() && it2.current() ) {
+ QPoint p1 = it1.current()->boundingRect().center() -
+ strokes.getFirst()->boundingRect().center();
+ QPoint p2 = it2.current()->boundingRect().center() -
+ pen->strokes.getFirst()->boundingRect().center();
+ int xdiff = QABS( p1.x() - p2.x() ) - 6;
+ int ydiff = QABS( p1.y() - p2.y() ) - 5;
+ if ( xdiff < 0 )
+ xdiff = 0;
+ if ( ydiff < 0 )
+ ydiff = 0;
+ if ( xdiff > 10 || ydiff > 10 ) { // not a chance
+#ifdef DEBUG_QIMPEN
+ qDebug( "char %c, stroke starting pt diff excessive", pen->ch );
+#endif
+ return INT_MAX;
+ }
+ diff += xdiff*xdiff + ydiff*ydiff;
+ err = it1.current()->match( it2.current() );
+ if ( err > maxErr )
+ maxErr = err;
+ ++it1;
+ ++it2;
+ }
+
+ maxErr += diff * diff * 6; // magic weighting :)
+
+#ifdef DEBUG_QIMPEN
+ qDebug( "char: %c, maxErr %d, diff %d, (%d)", pen->ch, maxErr, diff, strokes.count() );
+#endif
+ return maxErr;
+}
+
+/*!
+ Return the bounding rect of this character. It may have sides with
+ negative coords since its origin is where the user started drawing
+ the character.
+*/
+QRect QIMPenChar::boundingRect()
+{
+ QRect br;
+ QIMPenStroke *st = strokes.first();
+ while ( st ) {
+ br |= st->boundingRect();
+ st = strokes.next();
+ }
+
+ return br;
+}
+
+
+/*!
+ Write the character's data to the stream.
+*/
+QDataStream &operator<< (QDataStream &s, const QIMPenChar &ws)
+{
+ s << ws.ch;
+ s << ws.flags;
+ if ( ws.flags & QIMPenChar::Data )
+ s << ws.d;
+ s << ws.strokes.count();
+ QIMPenStrokeIterator it( ws.strokes );
+ while ( it.current() ) {
+ s << *it.current();
+ ++it;
+ }
+
+ return s;
+}
+
+/*!
+ Read the character's data from the stream.
+*/
+QDataStream &operator>> (QDataStream &s, QIMPenChar &ws)
+{
+ s >> ws.ch;
+ s >> ws.flags;
+ if ( ws.flags & QIMPenChar::Data )
+ s >> ws.d;
+ unsigned size;
+ s >> size;
+ for ( unsigned i = 0; i < size; i++ ) {
+ QIMPenStroke *st = new QIMPenStroke();
+ s >> *st;
+ ws.strokes.append( st );
+ }
+
+ return s;
+}
+
+//===========================================================================
+
+bool QIMPenCharMatch::operator>( const QIMPenCharMatch &m )
+{
+ return error > m.error;
+}
+
+bool QIMPenCharMatch::operator<( const QIMPenCharMatch &m )
+{
+ return error < m.error;
+}
+
+bool QIMPenCharMatch::operator<=( const QIMPenCharMatch &m )
+{
+ return error <= m.error;
+}
+
+//===========================================================================
+
+/*!
+ \class QIMPenCharSet qimpenchar.h
+
+ Maintains a set of related characters.
+*/
+
+QIMPenCharSet::QIMPenCharSet()
+{
+ chars.setAutoDelete( TRUE );
+ desc = "Unnamed";
+ csTitle = "abc";
+ csType = Unknown;
+ maxStrokes = 0;
+}
+
+/*!
+ Construct and load a characters set from file \a fn.
+*/
+QIMPenCharSet::QIMPenCharSet( const QString &fn )
+{
+ chars.setAutoDelete( TRUE );
+ desc = "Unnamed";
+ csTitle = "abc";
+ csType = Unknown;
+ maxStrokes = 0;
+ load( fn, System );
+}
+
+const QString &QIMPenCharSet::filename( Domain d ) const
+{
+ if ( d == System )
+ return sysFilename;
+ else
+ return userFilename;
+}
+
+void QIMPenCharSet::setFilename( const QString &fn, Domain d )
+{
+ if ( d == System )
+ sysFilename = fn;
+ else if ( d == User )
+ userFilename = fn;
+}
+
+/*!
+ Load a character set from file \a fn.
+*/
+bool QIMPenCharSet::load( const QString &fn, Domain d )
+{
+ setFilename( fn, d );
+
+ bool ok = FALSE;
+ QFile file( fn );
+ if ( file.open( IO_ReadOnly ) ) {
+ QDataStream ds( &file );
+ QString version;
+ ds >> version;
+ ds >> csTitle;
+ ds >> desc;
+ int major = version.mid( 4, 1 ).toInt();
+ int minor = version.mid( 6 ).toInt();
+ if ( major >= 1 && minor > 0 ) {
+ ds >> (Q_INT8 &)csType;
+ } else {
+ if ( csTitle == "abc" )
+ csType = Lower;
+ else if ( csTitle == "ABC" )
+ csType = Upper;
+ else if ( csTitle == "123" )
+ csType = Numeric;
+ else if ( fn == "Combining" )
+ csType = Combining;
+ }
+ while ( !ds.atEnd() ) {
+ QIMPenChar *pc = new QIMPenChar;
+ ds >> *pc;
+ if ( d == User )
+ markDeleted( pc->character() ); // override system
+ addChar( pc );
+ }
+ if ( file.status() == IO_Ok )
+ ok = TRUE;
+ }
+
+ return ok;
+}
+
+/*!
+ Save this character set.
+*/
+bool QIMPenCharSet::save( Domain d )
+{
+ if ( filename( d ).isEmpty() )
+ return FALSE;
+
+ bool ok = FALSE;
+
+ QString fn = filename( d );
+ QString tmpFn = fn + ".new";
+ QFile file( tmpFn );
+ if ( file.open( IO_WriteOnly|IO_Raw ) ) {
+ QDataStream ds( &file );
+ ds << QString( "QPT 1.1" );
+ ds << csTitle;
+ ds << desc;
+ ds << (Q_INT8)csType;
+ QIMPenCharIterator ci( chars );
+ for ( ; ci.current(); ++ci ) {
+ QIMPenChar *pc = ci.current();
+ if ( ( (d == System) && pc->testFlag( QIMPenChar::System ) ) ||
+ ( (d == User) && !pc->testFlag( QIMPenChar::System ) ) ) {
+ ds << *pc;
+ }
+ if ( file.status() != IO_Ok )
+ break;
+ }
+ if ( file.status() == IO_Ok )
+ ok = TRUE;
+ }
+
+ if ( ok ) {
+ if ( ::rename( tmpFn.latin1(), fn.latin1() ) < 0 ) {
+ qWarning( "problem renaming file %s to %s, errno: %d",
+ tmpFn.latin1(), fn.latin1(), errno );
+ // remove the tmp file, otherwise, it will just lay around...
+ QFile::remove( tmpFn.latin1() );
+ ok = FALSE;
+ }
+ }
+
+ return ok;
+}
+
+QIMPenChar *QIMPenCharSet::at( int i )
+{
+ return chars.at(i);
+}
+
+void QIMPenCharSet::markDeleted( uint ch )
+{
+ QIMPenCharIterator ci( chars );
+ for ( ; ci.current(); ++ci ) {
+ QIMPenChar *pc = ci.current();
+ if ( pc->character() == ch && pc->testFlag( QIMPenChar::System ) )
+ pc->setFlag( QIMPenChar::Deleted );
+ }
+}
+
+/*!
+ Find the best matches for \a ch in this character set.
+*/
+QIMPenCharMatchList QIMPenCharSet::match( QIMPenChar *ch )
+{
+ QIMPenCharMatchList matches;
+
+ QIMPenCharIterator ci( chars );
+ for ( ; ci.current(); ++ci ) {
+ QIMPenChar *tmplChar = ci.current();
+ if ( tmplChar->testFlag( QIMPenChar::Deleted ) ) {
+ continue;
+ }
+ int err;
+ if ( ch->penStrokes().count() <= tmplChar->penStrokes().count() ) {
+ err = ch->match( tmplChar );
+ if ( err <= QIMPEN_MATCH_THRESHOLD ) {
+ if (tmplChar->penStrokes().count() != ch->penStrokes().count())
+ err = QIMPEN_MATCH_THRESHOLD;
+ QIMPenCharMatchList::Iterator it;
+ for ( it = matches.begin(); it != matches.end(); ++it ) {
+ if ( (*it).penChar->character() == tmplChar->character() &&
+ (*it).penChar->penStrokes().count() == tmplChar->penStrokes().count() ) {
+ if ( (*it).error > err )
+ (*it).error = err;
+ break;
+ }
+ }
+ if ( it == matches.end() ) {
+ QIMPenCharMatch m;
+ m.error = err;
+ m.penChar = tmplChar;
+ matches.append( m );
+ }
+ }
+ }
+ }
+ qHeapSort( matches );
+/*
+ QIMPenCharMatchList::Iterator it;
+ for ( it = matches.begin(); it != matches.end(); ++it ) {
+ qDebug( "Match: \'%c\', error %d, strokes %d", (*it).penChar->character(),
+ (*it).error, (*it).penChar->penStrokes().count() );
+ }
+*/
+ return matches;
+}
+
+/*!
+ Add a character \a ch to this set.
+ QIMPenCharSet will delete this character when it is no longer needed.
+*/
+void QIMPenCharSet::addChar( QIMPenChar *ch )
+{
+ if ( ch->penStrokes().count() > maxStrokes )
+ maxStrokes = ch->penStrokes().count();
+ chars.append( ch );
+}
+
+/*!
+ Remove a character by reference \a ch from this set.
+ QIMPenCharSet will delete this character.
+*/
+void QIMPenCharSet::removeChar( QIMPenChar *ch )
+{
+ chars.remove( ch );
+}
+
+/*!
+ Move the character up the list of characters.
+*/
+void QIMPenCharSet::up( QIMPenChar *ch )
+{
+ int idx = chars.findRef( ch );
+ if ( idx > 0 ) {
+ chars.take();
+ chars.insert( idx - 1, ch );
+ }
+}
+
+/*!
+ Move the character down the list of characters.
+*/
+void QIMPenCharSet::down( QIMPenChar *ch )
+{
+ int idx = chars.findRef( ch );
+ if ( idx >= 0 && idx < (int)chars.count() - 1 ) {
+ chars.take();
+ chars.insert( idx + 1, ch );
+ }
+}
+
diff --git a/inputmethods/handwriting/qimpenchar.h b/inputmethods/handwriting/qimpenchar.h
new file mode 100644
index 0000000..9a5f687
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenchar.h
@@ -0,0 +1,157 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef QIMPENCHAR_H_
+#define QIMPENCHAR_H_
+
+#include <qlist.h>
+#include <qvaluelist.h>
+#include <qcstring.h>
+#include "qimpenstroke.h"
+
+struct QIMPenSpecialKeys {
+ int code;
+ char *name;
+};
+
+extern const QIMPenSpecialKeys qimpen_specialKeys[];
+
+
+class QIMPenChar
+{
+public:
+ QIMPenChar();
+ QIMPenChar( const QIMPenChar & );
+
+ unsigned int character() const { return ch; }
+ void setCharacter( unsigned int c ) { ch = c; }
+
+ const QString &data() const { return d; }
+ void setData( const QString &ba ) { d = ba; }
+
+ QString name() const;
+ bool isEmpty() const { return strokes.isEmpty(); }
+ unsigned int strokeCount() const { return strokes.count(); }
+ unsigned int strokeLength( int s ) const;
+ void clear();
+ int match( QIMPenChar *ch );
+ const QIMPenStrokeList &penStrokes() { return strokes; }
+ QPoint startingPoint() const { return strokes.getFirst()->startingPoint(); }
+ QRect boundingRect();
+
+ void setFlag( int f ) { flags |= f; }
+ void clearFlag( int f ) { flags &= ~f; }
+ bool testFlag( int f ) { return flags & f; }
+
+ enum Flags { System=0x01, Deleted=0x02, CombineRight=0x04, Data=0x08 };
+ // Correspond to codes in template files. Do not change values.
+ enum Mode { ModeBase=0x4000, Caps=0x4001, Shortcut=0x4002, CapsLock=0x4003,
+ Punctuation=0x4004, Symbol=0x4005, Extended=0x4006 };
+
+ QIMPenChar &operator=( const QIMPenChar &s );
+
+ void addStroke( QIMPenStroke * );
+
+protected:
+ unsigned int ch;
+ QString d;
+ Q_UINT8 flags;
+ QIMPenStrokeList strokes;
+
+ friend QDataStream &operator<< (QDataStream &, const QIMPenChar &);
+ friend QDataStream &operator>> (QDataStream &, QIMPenChar &);
+};
+
+typedef QList<QIMPenChar> QIMPenCharList;
+typedef QListIterator<QIMPenChar> QIMPenCharIterator;
+
+QDataStream & operator<< (QDataStream & s, const QIMPenChar &ws);
+QDataStream & operator>> (QDataStream & s, QIMPenChar &ws);
+
+struct QIMPenCharMatch
+{
+ int error;
+ QIMPenChar *penChar;
+
+ bool operator>( const QIMPenCharMatch &m );
+ bool operator<( const QIMPenCharMatch &m );
+ bool operator<=( const QIMPenCharMatch &m );
+};
+
+typedef QValueList<QIMPenCharMatch> QIMPenCharMatchList;
+
+
+class QIMPenCharSet
+{
+public:
+ QIMPenCharSet();
+ QIMPenCharSet( const QString &fn );
+
+ bool isEmpty() const { return chars.isEmpty(); }
+ unsigned int count() const { return chars.count(); }
+ void clear() { chars.clear(); }
+
+ void setDescription( const QString &d ) { desc = d; }
+ QString description() const { return desc; }
+ void setTitle( const QString &t ) { csTitle = t; }
+ QString title() const { return csTitle; }
+
+ QIMPenCharMatchList match( QIMPenChar *ch );
+ void addChar( QIMPenChar *ch );
+ void removeChar( QIMPenChar *ch );
+ QIMPenChar *at( int i );
+
+ unsigned maximumStrokes() const { return maxStrokes; }
+
+ void up( QIMPenChar *ch );
+ void down( QIMPenChar *ch );
+
+ enum Domain { System, User };
+ enum Type { Unknown=0x00, Lower=0x01, Upper=0x02, Combining=0x04,
+ Numeric=0x08, Punctuation=0x10, Symbol=0x20, Shortcut=0x40 };
+
+ const QIMPenCharList &characters() const { return chars; }
+
+ void setType( Type t ) { csType = t; }
+ Type type() const { return csType; }
+
+ const QString &filename( Domain d ) const;
+ void setFilename( const QString &fn, Domain d=System );
+ bool load( const QString &fn, Domain d=System );
+ bool save( Domain d=System );
+
+protected:
+ void markDeleted( uint ch );
+
+protected:
+ QString csTitle;
+ QString desc;
+ QString sysFilename;
+ QString userFilename;
+ Type csType;
+ unsigned maxStrokes;
+ QIMPenCharList chars;
+ QIMPenCharMatchList matches;
+};
+
+typedef QList<QIMPenCharSet> QIMPenCharSetList;
+typedef QListIterator<QIMPenCharSet> QIMPenCharSetIterator;
+
+#endif
diff --git a/inputmethods/handwriting/qimpencombining.cpp b/inputmethods/handwriting/qimpencombining.cpp
new file mode 100644
index 0000000..30459e7
--- a/dev/null
+++ b/inputmethods/handwriting/qimpencombining.cpp
@@ -0,0 +1,141 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include <qfile.h>
+#include <qtl.h>
+#include <math.h>
+#include <limits.h>
+#include <qdatastream.h>
+#include "qimpencombining.h"
+
+static unsigned int combiningSymbols[] = { '\\', '/', '^', '~', '\"', 'o' };
+static unsigned int combiningChars[][7] = {
+ // \ / ^ ~ "
+ { 'A', 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5 },
+ { 'O', 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0000 },
+ { 'U', 0x00D9, 0x00DA, 0x00DB, 0x0000, 0x00DC, 0x0000 },
+ { 'E', 0x00C8, 0x00C9, 0x00CA, 0x0000, 0x00CB, 0x0000 },
+ { 'I', 0x00CC, 0x00CD, 0x00CE, 0x0000, 0x00CF, 0x0000 },
+ { 'a', 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5 },
+ { 'e', 0x00E8, 0x00E9, 0x00EA, 0x0000, 0x00EB, 0x0000 },
+ { 'i', 0x00EC, 0x00ED, 0x00EE, 0x0000, 0x00EF, 0x0000 },
+ { 'n', 0x0000, 0x0000, 0x0000, 0x00F1, 0x0000, 0x0000 },
+ { 'o', 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0000 },
+ { 'u', 0x00F9, 0x00FA, 0x00FB, 0x0000, 0x00FC, 0x0000 },
+ { 'y', 0x0000, 0x00FD, 0x0000, 0x0000, 0x00FF, 0x0000 },
+ { 0, 0, 0, 0, 0, 0, 0 }
+};
+
+
+QIMPenCombining::QIMPenCombining()
+{
+}
+
+QIMPenCombining::QIMPenCombining( const QString &fn )
+ : QIMPenCharSet( fn )
+{
+}
+
+void QIMPenCombining::addCombined( QIMPenCharSet *cs )
+{
+ unsigned int count = cs->count();
+ QIMPenCharIterator it( cs->characters() );
+ for ( ; it.current() && count; ++it, --count ) {
+ QIMPenChar *pc = it.current();
+ if ( pc->testFlag( QIMPenChar::Deleted ) )
+ continue;
+ int charIdx = findCombining( pc->character() );
+ if ( charIdx < 0 )
+ continue;
+ for ( int i = 0; i < 6; i++ ) {
+ if ( combiningChars[charIdx][i+1] ) {
+ QIMPenCharIterator cit( chars );
+ for ( ; cit.current(); ++cit ) {
+ QIMPenChar *accentPc = cit.current();
+ if ( accentPc->character() == combiningSymbols[i] ) {
+ QIMPenChar *combined = combine( pc, accentPc );
+ combined->setCharacter( combiningChars[charIdx][i+1] );
+ cs->addChar( combined );
+ }
+ }
+ }
+ }
+ }
+}
+
+int QIMPenCombining::findCombining( unsigned int ch ) const
+{
+ int i = 0;
+ while ( combiningChars[i][0] ) {
+ if ( combiningChars[i][0] == ch )
+ return i;
+ i++;
+ }
+
+ return -1;
+}
+
+QIMPenChar *QIMPenCombining::combine( QIMPenChar *base, QIMPenChar *accent )
+{
+ QRect brect = base->boundingRect();
+ QRect arect = accent->boundingRect();
+ int offset;
+ if ( accent->testFlag( QIMPenChar::CombineRight ) )
+ offset = brect.left() - arect.left() + brect.width() + 2;
+ else
+ offset = brect.left() - arect.left() + (brect.width() - arect.width())/2;
+ QIMPenChar *combined = 0;
+ if ( base->character() == 'i' ) {
+ // Hack to remove the dot from i's when combining.
+ if ( base->penStrokes().count() > 1 ) {
+ combined = new QIMPenChar;
+ QIMPenStrokeIterator it( base->penStrokes() );
+ for ( unsigned int i = 0; i < base->penStrokes().count()-1; ++it, i++ ) {
+ QIMPenStroke *st = new QIMPenStroke( *(it.current()) );
+ combined->addStroke( st );
+ }
+ combined->setFlag( QIMPenChar::System );
+ }
+ }
+ if ( !combined )
+ combined = new QIMPenChar( *base );
+ QIMPenStrokeIterator it( accent->penStrokes() );
+ for ( ; it.current(); ++it ) {
+ QIMPenStroke *st = new QIMPenStroke( *(it.current()) );
+ st->setStartingPoint( st->startingPoint() + QPoint(offset, 0 ));
+ combined->addStroke( st );
+ delete st;
+ }
+
+ return combined;
+}
+
+QIMPenChar *QIMPenCombining::penChar( int type )
+{
+ QIMPenCharIterator it( chars );
+ for ( ; it.current(); ++it ) {
+ QIMPenChar *pc = it.current();
+ if ( pc->character() == combiningSymbols[type] )
+ return pc;
+ }
+
+ return 0;
+}
+
diff --git a/inputmethods/handwriting/qimpencombining.h b/inputmethods/handwriting/qimpencombining.h
new file mode 100644
index 0000000..778cb8f
--- a/dev/null
+++ b/inputmethods/handwriting/qimpencombining.h
@@ -0,0 +1,41 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef QIMPENCOMBINING_H_
+#define QIMPENCOMBINING_H_
+
+#include <qlist.h>
+#include "qimpenchar.h"
+
+class QIMPenCombining : public QIMPenCharSet
+{
+public:
+ QIMPenCombining();
+ QIMPenCombining( const QString &fn );
+
+ void addCombined( QIMPenCharSet * );
+
+protected:
+ int findCombining( unsigned int ch ) const;
+ QIMPenChar *combine( QIMPenChar *base, QIMPenChar *accent );
+ QIMPenChar *penChar( int type );
+};
+
+#endif
diff --git a/inputmethods/handwriting/qimpenhelp.cpp b/inputmethods/handwriting/qimpenhelp.cpp
new file mode 100644
index 0000000..5ee46a2
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenhelp.cpp
@@ -0,0 +1,410 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include "qimpenwidget.h"
+#include "qimpencombining.h"
+#include "qimpenmatch.h"
+#include "qimpenhelp.h"
+
+#include <qpe/qpeapplication.h>
+#include <qpe/global.h>
+#include <qpe/config.h>
+#include <qpe/stringutil.h>
+
+#include <qtextview.h>
+#include <qlabel.h>
+#include <qlistbox.h>
+#include <qcombobox.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qtimer.h>
+#include <qtextstream.h>
+
+/* XPM */
+static const char * const left_xpm[] = {
+"16 16 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" . ",
+" .. ",
+" ... ",
+" .... ",
+" ..... ",
+" ...... ",
+" ..... ",
+" .... ",
+" ... ",
+" .. ",
+" . ",
+" ",
+" "};
+
+
+/* XPM */
+static const char * const right_xpm[] = {
+"16 16 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" . ",
+" .. ",
+" ... ",
+" .... ",
+" ..... ",
+" ...... ",
+" ..... ",
+" .... ",
+" ... ",
+" .. ",
+" . ",
+" ",
+" "};
+
+class CharListItem : public QListBoxText
+{
+public:
+ CharListItem( const QString &text, uint c )
+ : QListBoxText( text )
+ {
+ _code = c;
+ }
+
+ uint code() const { return _code; }
+
+protected:
+ uint _code;
+};
+
+HandwritingHelp::HandwritingHelp( QIMPenProfile *p, QWidget *parent, const char *name, WFlags f )
+ : QTabWidget( parent, name, f )
+{
+ setCaption( tr("Handwriting Help") );
+ QTextView *help = new QTextView( this );
+ help->setFrameStyle( QFrame::NoFrame );
+ help->setText(
+ tr( "<ul><li>When you start to use the handwriting recogniser "
+ "write slowly, accurately and firmly."
+ "<li>Use the guide lines when drawing your characters."
+ "<li>When drawing a character with multiple strokes, each "
+ "successive stroke must be drawn before the grayed strokes are erased."
+ "<li>Practice your handwriting using the handwriting trainer."
+ "<li>When adding your own character templates make sure they "
+ "are sufficiently different from other characters' templates."
+ "</ul>") );
+
+ addTab( help, tr("Tips") );
+
+ HandwritingTrainer *trainer = new HandwritingTrainer( p, this );
+ addTab( trainer, tr("Trainer") );
+}
+
+void HandwritingHelp::showEvent( QShowEvent * )
+{
+ Global::hideInputMethod();
+}
+
+void HandwritingHelp::hideEvent( QHideEvent * )
+{
+ Global::showInputMethod();
+}
+
+//---------------------------------------------------------------------------
+
+HandwritingTrainer::HandwritingTrainer( QIMPenProfile *p, QWidget *parent, const char *name )
+ : QWidget( parent, name ), profile(p)
+{
+ QGridLayout *gl = new QGridLayout( this, 5, 2, 0, 4 );
+ gl->setRowStretch( 1, 1 );
+ gl->setRowStretch( 2, 1 );
+ gl->setColStretch( 1, 1 );
+
+ charSetCombo = new QComboBox( this );
+ gl->addMultiCellWidget( charSetCombo, 0, 0, 0, 1 );
+ connect( charSetCombo, SIGNAL(activated(int)), SLOT(selectCharSet(int)));
+ QIMPenCharSetIterator it( profile->charSets() );
+ for ( ; it.current(); ++it ) {
+ charSetCombo->insertItem( it.current()->description() );
+ }
+
+ charList = new QListBox( this );
+ charList->setHScrollBarMode( QListBox::AlwaysOff );
+ charList->setFixedWidth( 80 );
+ connect( charList, SIGNAL(highlighted(int)), this, SLOT(selectChar(int)) );
+ gl->addMultiCellWidget( charList, 1, 2, 0, 0 );
+
+ QLabel *help = new QLabel( this );
+ help->setAlignment( AlignLeft | AlignVCenter | WordBreak );
+ gl->addWidget( help, 1, 1 );
+ help->setText(
+ tr( "Select a character from the list. The writing area on the left "
+ "shows the reference character. Practice writing in the area on "
+ "the right.") );
+
+ result = new QLabel( this );
+ gl->addMultiCellWidget( result, 2, 3, 1, 1 );
+
+ matcher = new QIMPenMatch( this );
+ matcher->setCharSet( currentSet );
+ connect( matcher, SIGNAL(noMatch()), this, SLOT(noMatch()) );
+ connect( matcher, SIGNAL(matchedCharacters(const QIMPenCharMatchList &)),
+ this, SLOT(matched(const QIMPenCharMatchList &)) );
+
+ QHBoxLayout *hb = new QHBoxLayout();
+ gl->addLayout( hb, 3, 0 );
+ prevBtn = new QPushButton( this );
+ prevBtn->setPixmap( QPixmap( (const char **)left_xpm ) );
+ connect( prevBtn, SIGNAL(clicked()), SLOT(prevChar()));
+ hb->addWidget( prevBtn );
+
+ nextBtn = new QPushButton( this );
+ nextBtn->setPixmap( QPixmap( (const char **)right_xpm ) );
+ connect( nextBtn, SIGNAL(clicked()), SLOT(nextChar()));
+ hb->addWidget( nextBtn );
+
+ refPw = new QIMPenWidget( this );
+ refPw->setReadOnly( TRUE );
+ gl->addWidget( refPw, 4, 0 );
+
+ pracPw = new QIMPenWidget( this );
+ connect( matcher, SIGNAL(removeStroke()), pracPw, SLOT(removeStroke()) );
+ connect( pracPw, SIGNAL(beginStroke()),
+ this, SLOT(beginStroke()) );
+ connect( pracPw, SIGNAL(stroke( QIMPenStroke * )),
+ this, SLOT(strokeEntered( QIMPenStroke * )) );
+ connect( pracPw, SIGNAL(beginStroke()),
+ matcher, SLOT(beginStroke()) );
+ connect( pracPw, SIGNAL(stroke( QIMPenStroke * )),
+ matcher, SLOT(strokeEntered( QIMPenStroke * )) );
+ gl->addWidget( pracPw, 4, 1 );
+
+ redrawTimer = new QTimer( this );
+ connect( redrawTimer, SIGNAL(timeout()), this, SLOT(redrawChar()) );
+ redrawTimer->start( 5000 );
+
+ currentSet = 0;
+ charSetCombo->setCurrentItem( 1 );
+ selectCharSet( 1 );
+}
+
+HandwritingTrainer::~HandwritingTrainer()
+{
+}
+
+void HandwritingTrainer::showEvent( QShowEvent * )
+{
+ redrawChar();
+ redrawTimer->start( 5000 );
+}
+
+void HandwritingTrainer::setCurrentChar( QIMPenChar *c )
+{
+ currentChar = c;
+ refPw->showCharacter( currentChar );
+ pracPw->clear();
+ if ( currentChar ) {
+ prevBtn->setEnabled( findPrev() != 0 );
+ nextBtn->setEnabled( findNext() != 0 );
+ }
+ result->setText( "" );
+ redrawTimer->start( 5000 );
+}
+
+void HandwritingTrainer::selectChar( int i )
+{
+ currentChar = 0;
+ currentCode = ((CharListItem *)charList->item(i))->code();
+ QIMPenCharIterator it(currentSet->characters() );
+ for ( ; it.current(); ++it ) {
+ if ( it.current()->character() == currentCode &&
+ !it.current()->testFlag( QIMPenChar::Deleted ) ) {
+ setCurrentChar( it.current() );
+ break;
+ }
+ }
+ if ( !it.current() )
+ setCurrentChar( 0 );
+}
+
+void HandwritingTrainer::selectCharSet( int i )
+{
+ if ( currentSet ) {
+ refPw->removeCharSet( 0 );
+ pracPw->removeCharSet( 0 );
+ }
+ currentSet = profile->charSets().at( i );
+ fillCharList();
+ refPw->insertCharSet( currentSet );
+ pracPw->insertCharSet( currentSet );
+ matcher->setCharSet( currentSet );
+ if ( charList->count() ) {
+ charList->setSelected( 0, TRUE );
+ selectChar(0);
+ }
+}
+
+void HandwritingTrainer::noMatch()
+{
+ result->setText( "No match" );
+}
+
+void HandwritingTrainer::matched( const QIMPenCharMatchList &ml )
+{
+ int maxErr = 20000 + (*ml.begin()).penChar->strokeLength(0) * 1000;
+ int baseErr = (*ml.begin()).penChar->strokeLength(0) * 250;
+ unsigned int numStrokes = (*ml.begin()).penChar->strokeCount();
+ QIMPenCharMatchList::ConstIterator it;
+ /*
+ for ( it = ml.begin(); it != ml.end(); ++it ) {
+ if ( (*it).penChar->strokeCount() == numStrokes ) {
+ if ( (*it).error > maxErr )
+ maxErr = (*it).error;
+ }
+ }
+ */
+ int i;
+ QString res;
+ QTextStream ts(&res, IO_WriteOnly);
+ ts << "<qt>" << tr("Matched: ");
+ for ( i = 0, it = ml.begin(); it != ml.end() && i < 4; ++it, i++ ) {
+ if ( (*it).penChar->strokeCount() == numStrokes ) {
+ int rate = 100 - ( ((*it).error - baseErr) * 100 ) / maxErr;
+ if ( it != ml.begin() ) {
+ if ( rate < -10 )
+ continue;
+ ts << "<br>";
+ ts << tr("Similar to: ");
+ }
+ ts << "<big>";
+ if ( (*it).penChar->character() == currentChar->character() )
+ ts << "<b>";
+ ts << Qtopia::escapeString((*it).penChar->name());
+ ts << " (" << rateString(rate) << ")";
+ if ( (*it).penChar->character() == currentChar->character() )
+ ts << "</b>";
+ ts << "</big>";
+ }
+ }
+ ts << "</qt>";
+ result->setText( res );
+}
+
+QString HandwritingTrainer::rateString( int rate ) const
+{
+ if ( rate < 1 )
+ rate = 1;
+ if ( rate > 100 )
+ rate = 100;
+ return tr("%1%").arg(rate);
+}
+
+void HandwritingTrainer::prevChar()
+{
+ QIMPenChar *pc = findPrev();
+ if ( pc )
+ setCurrentChar( pc );
+}
+
+void HandwritingTrainer::nextChar()
+{
+ QIMPenChar *pc = findNext();
+ if ( pc )
+ setCurrentChar( pc );
+}
+
+void HandwritingTrainer::redrawChar()
+{
+ if ( currentChar )
+ refPw->showCharacter( currentChar );
+}
+
+void HandwritingTrainer::beginStroke()
+{
+ redrawTimer->start( 5000 );
+}
+
+void HandwritingTrainer::strokeEntered( QIMPenStroke * )
+{
+ pracPw->greyStroke();
+}
+
+QIMPenChar *HandwritingTrainer::findPrev()
+{
+ if ( !currentChar )
+ return 0;
+ QIMPenCharIterator it( currentSet->characters() );
+ bool found = FALSE;
+ for ( it.toLast(); it.current(); --it ) {
+ if ( !found && it.current() == currentChar )
+ found = TRUE;
+ else if ( found && it.current()->character() == currentCode &&
+ !it.current()->testFlag( QIMPenChar::Deleted ) ) {
+ return it.current();
+ }
+ }
+
+ return 0;
+}
+
+QIMPenChar *HandwritingTrainer::findNext()
+{
+ if ( !currentChar )
+ return 0;
+ QIMPenCharIterator it( currentSet->characters() );
+ bool found = FALSE;
+ for ( ; it.current(); ++it ) {
+ if ( !found && it.current() == currentChar )
+ found = TRUE;
+ else if ( found && it.current()->character() == currentCode &&
+ !it.current()->testFlag( QIMPenChar::Deleted ) ) {
+ return it.current();
+ }
+ }
+
+ return 0;
+}
+
+void HandwritingTrainer::fillCharList()
+{
+ charList->clear();
+ QIMPenCharIterator it( currentSet->characters() );
+ CharListItem *li = 0;
+ for ( ; it.current(); ++it ) {
+ uint ch = it.current()->character();
+ QString n = it.current()->name();
+ if ( !n.isEmpty() )
+ li = new CharListItem( n, ch );
+ if ( li ) {
+ CharListItem *i = (CharListItem *)charList->findItem( li->text() );
+ if ( !i || i->code() != ch ) {
+ charList->insertItem( li );
+ } else {
+ delete li;
+ li = 0;
+ }
+ }
+ }
+ currentChar = 0;
+}
+
diff --git a/inputmethods/handwriting/qimpenhelp.h b/inputmethods/handwriting/qimpenhelp.h
new file mode 100644
index 0000000..07cb035
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenhelp.h
@@ -0,0 +1,85 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#include <qtabwidget.h>
+#include <qlist.h>
+#include "qimpenchar.h"
+#include "qimpenprofile.h"
+
+class QListBox;
+class QLabel;
+class QComboBox;
+class QPushButton;
+class QTimer;
+class QIMPenWidget;
+class QIMPenMatch;
+
+class HandwritingHelp : public QTabWidget
+{
+ Q_OBJECT
+public:
+ HandwritingHelp( QIMPenProfile *p, QWidget *parent=0, const char *name=0, WFlags f=0 );
+
+protected:
+ virtual void showEvent( QShowEvent * );
+ virtual void hideEvent( QHideEvent * );
+};
+
+class HandwritingTrainer : public QWidget
+{
+ Q_OBJECT
+public:
+ HandwritingTrainer( QIMPenProfile *p, QWidget *parent=0, const char *name=0 );
+ ~HandwritingTrainer();
+
+private slots:
+ void selectChar( int );
+ void selectCharSet( int );
+ void noMatch();
+ void matched( const QIMPenCharMatchList &ml );
+ void prevChar();
+ void nextChar();
+ void redrawChar();
+ void beginStroke();
+ void strokeEntered( QIMPenStroke * );
+
+private:
+ virtual void showEvent( QShowEvent * );
+ QString rateString( int rate ) const;
+ void setCurrentChar( QIMPenChar *c );
+ void fillCharList();
+ QIMPenChar *findPrev();
+ QIMPenChar *findNext();
+
+private:
+ QIMPenMatch *matcher;
+ QIMPenCharSet *currentSet;
+ QIMPenChar *currentChar;
+ QIMPenProfile *profile;
+ uint currentCode;
+ QIMPenWidget *refPw;
+ QIMPenWidget *pracPw;
+ QComboBox *charSetCombo;
+ QListBox *charList;
+ QLabel *result;
+ QPushButton *prevBtn;
+ QPushButton *nextBtn;
+ QTimer *redrawTimer;
+};
+
diff --git a/inputmethods/handwriting/qimpeninput.cpp b/inputmethods/handwriting/qimpeninput.cpp
new file mode 100644
index 0000000..6718b26
--- a/dev/null
+++ b/inputmethods/handwriting/qimpeninput.cpp
@@ -0,0 +1,515 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include "qimpenwidget.h"
+#include "qimpensetup.h"
+#include "qimpeninput.h"
+#include "qimpencombining.h"
+#include "qimpenwordpick.h"
+#include "qimpenmatch.h"
+#include "qimpenhelp.h"
+
+#include <qpe/qpeapplication.h>
+#include <qpe/qdawg.h>
+#include <qpe/config.h>
+#include <qpe/global.h>
+
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+#include <qtimer.h>
+#include <qdir.h>
+
+#include <limits.h>
+
+// We'll use little pixmaps for the buttons to save screen space.
+
+/* XPM */
+static const char * const pen_xpm[] = {
+"12 12 4 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+"@ c #808080",
+" . ",
+" .+. ",
+" ..@@.",
+" .+@.. ",
+" .+@@. ",
+" .+@@. ",
+" .+@@. ",
+" .@.@. ",
+" .@@. ",
+" .... ",
+" .. ",
+" "};
+
+
+/* XPM */
+static char * bs_xpm[] = {
+"12 12 5 1",
+" c None",
+". c #333333",
+"+ c #000000",
+"@ c #FFFFFF",
+"# c #666666",
+" ",
+" ",
+" ",
+" . ",
+" ++ ",
+" +@#+++++. ",
+" +@@@@@@@@+ ",
+" +@#+++++. ",
+" ++ ",
+" . ",
+" ",
+" "};
+
+
+/* XPM */
+static char * enter_xpm[] = {
+"12 12 5 1",
+" c None",
+". c #333333",
+"+ c #000000",
+"@ c #FFFFFF",
+"# c #666666",
+" ",
+" .+. ",
+" +@+ ",
+" . +@+ ",
+" ++ +@+ ",
+" +@#++++@+ ",
+" +@@@@@@@@+ ",
+" +@#+++++. ",
+" ++ ",
+" . ",
+" ",
+" "};
+
+
+
+/* XPM */
+static char * help_xpm[] = {
+"12 12 5 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+"@ c #666666",
+"# c #333333",
+" ",
+" ... ",
+" .+++. ",
+" .+..@+. ",
+" #.# .+. ",
+" .+. ",
+" .+. ",
+" .+. ",
+" .+. ",
+" #.# ",
+" .+. ",
+" #.# "};
+
+
+/*!
+ \class QIMPenInput qimpeninput.h
+
+ Pen input widget.
+*/
+QIMPenInput::QIMPenInput( QWidget *parent, const char *name, WFlags f )
+ : QFrame( parent, name, f ), helpDlg(0), profile(0)
+{
+ setFrameStyle( Box | Plain );
+
+ profileList.setAutoDelete( true );
+
+ matcher = new QIMPenMatch( this );
+ connect( matcher, SIGNAL(keypress(uint)), this, SLOT(keypress(uint)) );
+ connect( matcher, SIGNAL(erase()), this, SLOT(erase()) );
+
+ QGridLayout *gl = new QGridLayout( this, 5, 2, 1, 0 );
+ gl->setColStretch( 0, 1 );
+
+ wordPicker = new QIMPenWordPick( this );
+ connect( wordPicker, SIGNAL(wordClicked(const QString &)),
+ this, SLOT(wordPicked(const QString &)) );
+ connect( matcher, SIGNAL(matchedCharacters(const QIMPenCharMatchList &)),
+ this, SLOT(matchedCharacters(const QIMPenCharMatchList &)) );
+ connect( matcher, SIGNAL(matchedWords(const QIMPenMatch::MatchWordList&)),
+ wordPicker, SLOT(setWords(const QIMPenMatch::MatchWordList&)) );
+ QFont f("smallsmooth",9);
+ QFontInfo fi( f );
+ wordPicker->setFont( f );
+ wordPicker->setBackgroundColor( white );
+ gl->addMultiCellWidget( wordPicker, 0, 0, 0, 1 );
+ if ( !Global::fixedDawg().root() || !matcher->isWordMatchingEnabled() )
+ wordPicker->hide();
+
+ pw = new QIMPenWidget( this );
+ gl->addMultiCellWidget( pw, 1, 4, 0, 0 );
+
+ int bh = pw->sizeHint().height()/4;
+
+ QPushButton *b = new QPushButton( this );
+ b->setFocusPolicy( NoFocus );
+ b->setPixmap( QPixmap( (const char **)bs_xpm ) );
+ b->setFixedHeight(pw->sizeHint().height()-3*bh); // left-over space goes here
+ b->setAutoRepeat( TRUE );
+ gl->addWidget( b, 1, 1 );
+ connect( b, SIGNAL(clicked()), SLOT(backspace()));
+
+ b = new QPushButton( this );
+ b->setFocusPolicy( NoFocus );
+ b->setPixmap( QPixmap( (const char **)enter_xpm ) );
+ b->setFixedHeight(bh);
+ b->setAutoRepeat( TRUE );
+ gl->addWidget( b, 2, 1 );
+ connect( b, SIGNAL(clicked()), SLOT(enter()));
+
+ helpBtn = new QPushButton( this );
+ helpBtn->setFocusPolicy( NoFocus );
+ helpBtn->setPixmap( QPixmap( (const char **)help_xpm ) );
+ helpBtn->setFixedHeight(bh);
+ gl->addWidget( helpBtn, 3, 1 );
+ connect( helpBtn, SIGNAL(clicked()), SLOT(help()));
+
+ QPixmap pm( (const char **)pen_xpm );
+ setupBtn = new QPushButton( this );
+ setupBtn->setFocusPolicy( NoFocus );
+ setupBtn->setPixmap( pm );
+ setupBtn->setFixedHeight(bh);
+ gl->addWidget( setupBtn, 4, 1 );
+ connect( setupBtn, SIGNAL(clicked()), SLOT(setup()));
+
+ connect( matcher, SIGNAL(removeStroke()), pw, SLOT(removeStroke()) );
+ connect( pw, SIGNAL(changeCharSet( QIMPenCharSet * )),
+ matcher, SLOT(setCharSet( QIMPenCharSet * )) );
+ connect( pw, SIGNAL(changeCharSet( int )),
+ this, SLOT(selectCharSet( int )) );
+ connect( pw, SIGNAL(beginStroke()),
+ matcher, SLOT(beginStroke()) );
+ connect( pw, SIGNAL(stroke( QIMPenStroke * )),
+ this, SLOT(strokeEntered( QIMPenStroke * )) );
+ connect( pw, SIGNAL(stroke( QIMPenStroke * )),
+ matcher, SLOT(strokeEntered( QIMPenStroke * )) );
+
+ shortcutCharSet = 0;
+ currCharSet = 0;
+ setupDlg = 0;
+ profile = 0;
+ mode = Normal;
+
+ loadProfiles();
+}
+
+QIMPenInput::~QIMPenInput()
+{
+ delete (HandwritingHelp*) helpDlg;
+}
+
+QSize QIMPenInput::sizeHint() const
+{
+ int fw = frameWidth();
+ int ps = wordPicker->isHidden() ? 0 : wordPicker->sizeHint().height();
+ return pw->sizeHint() + QSize( fw*2, fw*2+ps );
+}
+
+void QIMPenInput::loadProfiles()
+{
+ profileList.clear();
+ profile = 0;
+ delete shortcutCharSet;
+ shortcutCharSet = new QIMPenCharSet();
+ shortcutCharSet->setTitle( "Shortcut" );
+ QString path = QPEApplication::qpeDir() + "etc/qimpen";
+ QDir dir( path, "*.conf" );
+ QStringList list = dir.entryList();
+ QStringList::Iterator it;
+ for ( it = list.begin(); it != list.end(); ++it ) {
+ QIMPenProfile *p = new QIMPenProfile( path + "/" + *it );
+ profileList.append( p );
+ if ( p->shortcut() ) {
+ QIMPenCharIterator it( p->shortcut()->characters() );
+ for ( ; it.current(); ++it ) {
+ shortcutCharSet->addChar( new QIMPenChar(*it.current()) );
+ }
+ }
+ }
+
+ Config config( "handwriting" );
+ config.setGroup( "Settings" );
+ QString prof = config.readEntry( "Profile", "Default" );
+ selectProfile( prof );
+}
+
+void QIMPenInput::selectProfile( const QString &name )
+{
+ QListIterator<QIMPenProfile> it( profileList );
+ for ( ; it.current(); ++it ) {
+ if ( it.current()->name() == name ) {
+ profile = it.current();
+ break;
+ }
+ }
+
+ if ( !it.current() )
+ return;
+
+ pw->clearCharSets();
+ baseSets.clear();
+
+ matcher->setMultiStrokeTimeout( profile->multiStrokeTimeout() );
+ matcher->setWordMatchingEnabled( profile->matchWords() );
+
+ if ( !Global::fixedDawg().root() || !matcher->isWordMatchingEnabled() )
+ wordPicker->hide();
+ else
+ wordPicker->show();
+
+ if ( profile->uppercase() && profile->style() == QIMPenProfile::BothCases ) {
+ baseSets.append( profile->uppercase() );
+ pw->insertCharSet( profile->uppercase() );
+ }
+
+ if ( profile->lowercase() ) {
+ baseSets.append( profile->lowercase() );
+ pw->insertCharSet( profile->lowercase(), profile->style() == QIMPenProfile::BothCases ? 1 : 2 );
+ }
+
+ if ( profile->numeric() ) {
+ baseSets.append( profile->numeric() );
+ pw->insertCharSet( profile->numeric() );
+ }
+
+ if ( helpDlg )
+ delete (HandwritingHelp*) helpDlg;
+}
+
+void QIMPenInput::wordPicked( const QString &w )
+{
+ int bs = matcher->word().length();
+ for ( int i = 0; i < bs; i++ )
+ keypress( Qt::Key_Backspace << 16 );
+
+ for ( unsigned int i = 0; i < w.length(); i++ )
+ keypress( w[i].unicode() );
+
+ matcher->resetState();
+ wordPicker->clear();
+}
+
+void QIMPenInput::selectCharSet( int idx )
+{
+ if ( mode == Switch ) {
+ //qDebug( "Switch back to normal" );
+ pw->changeCharSet( baseSets.at(currCharSet), currCharSet );
+ mode = Normal;
+ }
+ currCharSet = idx;
+}
+
+void QIMPenInput::beginStroke()
+{
+}
+
+void QIMPenInput::strokeEntered( QIMPenStroke * )
+{
+ pw->greyStroke();
+}
+
+void QIMPenInput::erase()
+{
+ keypress( Qt::Key_Backspace << 16 );
+}
+
+void QIMPenInput::matchedCharacters( const QIMPenCharMatchList &cl )
+{
+ const QIMPenChar *ch = cl.first().penChar;
+ int scan = ch->character() >> 16;
+
+ if ( scan < QIMPenChar::ModeBase )
+ return;
+
+ // We matched a special character...
+
+ switch ( scan ) {
+ case QIMPenChar::Caps:
+ if ( profile->style() == QIMPenProfile::ToggleCases ) {
+// qDebug( "Caps" );
+ if ( mode == SwitchLock ) {
+// qDebug( "Switch to normal" );
+ pw->changeCharSet( profile->lowercase(), currCharSet );
+ mode = Switch;
+ } else {
+// qDebug( "Switch to upper" );
+ pw->changeCharSet( profile->uppercase(), currCharSet );
+ mode = Switch;
+ }
+ }
+ break;
+ case QIMPenChar::CapsLock:
+ if ( profile->style() == QIMPenProfile::ToggleCases ) {
+// qDebug( "CapsLock" );
+ if ( mode == Switch &&
+ baseSets.at(currCharSet) == profile->uppercase() ) {
+// qDebug( "Switch to normal" );
+ pw->changeCharSet( profile->lowercase(), currCharSet );
+ // change our base set back to lower.
+ baseSets.remove( currCharSet );
+ baseSets.insert( currCharSet, profile->lowercase() );
+ mode = Normal;
+ } else {
+// qDebug( "Switch to caps lock" );
+ pw->changeCharSet( profile->uppercase(), currCharSet );
+ // change our base set to upper.
+ baseSets.remove( currCharSet );
+ baseSets.insert( currCharSet, profile->uppercase() );
+ mode = SwitchLock;
+ }
+ }
+ break;
+ case QIMPenChar::Punctuation:
+ if ( profile->punctuation() ) {
+ //qDebug( "Switch to punctuation" );
+ pw->changeCharSet( profile->punctuation(), currCharSet );
+ mode = Switch;
+ }
+ break;
+ case QIMPenChar::Symbol:
+ if ( profile->symbol() ) {
+ //qDebug( "Switch to symbol" );
+ pw->changeCharSet( profile->symbol(), currCharSet );
+ mode = Switch;
+ }
+ break;
+ case QIMPenChar::Shortcut:
+ if ( shortcutCharSet ) {
+ pw->changeCharSet( shortcutCharSet, currCharSet );
+ mode = Switch;
+ }
+ break;
+ case QIMPenChar::Extended:
+ handleExtended( ch->data() );
+ break;
+ }
+}
+
+void QIMPenInput::keypress( uint scan_uni )
+{
+ int scan = scan_uni >> 16;
+ if ( !scan ) {
+ if ( scan_uni >= 'a' && scan_uni <= 'z' ) {
+ scan = Qt::Key_A + scan_uni - 'a';
+ } else if ( scan_uni >= 'A' && scan_uni <= 'Z' ) {
+ scan = Qt::Key_A + scan_uni - 'A';
+ } else if ( scan_uni == ' ' ) {
+ scan = Qt::Key_Space;
+ }
+ }
+
+ switch ( scan ) {
+ case Key_Tab:
+ scan_uni = 9;
+ break;
+ case Key_Return:
+ scan_uni = 13;
+ break;
+ case Key_Backspace:
+ scan_uni = 8;
+ break;
+ case Key_Escape:
+ scan_uni = 27;
+ break;
+ default:
+ break;
+ }
+
+ if ( mode == Switch ) {
+// qDebug( "Switch back to normal" );
+ pw->changeCharSet( baseSets.at(currCharSet), currCharSet );
+ if ( baseSets.at(currCharSet) == profile->uppercase() )
+ mode = SwitchLock;
+ else
+ mode = Normal;
+ }
+
+ emit key( scan_uni&0xffff, scan, 0, true, false );
+ emit key( scan_uni&0xffff, scan, 0, false, false );
+}
+
+void QIMPenInput::handleExtended( const QString &ex )
+{
+ if ( ex.find( "Select" ) == 0 ) {
+ QString set = ex.mid( 7 );
+ qDebug( "Select new profile: %s", set.latin1() );
+ selectProfile( set );
+ }
+}
+
+void QIMPenInput::help()
+{
+ if ( helpDlg )
+ delete (HandwritingHelp*) helpDlg;
+ helpDlg = new HandwritingHelp( profile, 0, 0, WDestructiveClose );
+ helpDlg->showMaximized();
+ helpDlg->show();
+ helpDlg->raise();
+}
+
+/*!
+ Open the setup dialog
+*/
+void QIMPenInput::setup()
+{
+ if ( !setupDlg ) {
+ // We are working with our copy of the char sets here.
+ setupDlg = new QIMPenSetup( profile, 0, 0, TRUE );
+ setupDlg->editor()->selectCharSet( profile->charSets().at(1) ); // lower case? This is crap.
+ if ( qApp->desktop()->width() < 640 )
+ setupDlg->showMaximized();
+ Global::hideInputMethod();
+ setupDlg->exec();
+ loadProfiles();
+ delete setupDlg;
+ setupDlg = 0;
+ Global::showInputMethod();
+ } else {
+ setupDlg->raise();
+ }
+}
+
+void QIMPenInput::backspace()
+{
+ keypress( Qt::Key_Backspace << 16 );
+ matcher->backspace();
+}
+
+void QIMPenInput::enter()
+{
+ keypress( Qt::Key_Return << 16 );
+ matcher->resetState();
+}
+
+
+void QIMPenInput::resetState()
+{
+ matcher->resetState();
+}
diff --git a/inputmethods/handwriting/qimpeninput.h b/inputmethods/handwriting/qimpeninput.h
new file mode 100644
index 0000000..b4e4006
--- a/dev/null
+++ b/inputmethods/handwriting/qimpeninput.h
@@ -0,0 +1,94 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef _QIMPENINPUT_H_
+#define _QIMPENINPUT_H_
+
+#include "qimpenprofile.h"
+
+#include <qpe/qdawg.h>
+
+#include <qframe.h>
+#include <qlist.h>
+#include <qguardedptr.h>
+
+class QPushButton;
+class QTimer;
+class QIMPenWidget;
+class QIMPenSetup;
+class QIMPenWordPick;
+class QIMPenMatch;
+class HandwritingHelp;
+
+class QIMPenInput : public QFrame
+{
+ Q_OBJECT
+public:
+ QIMPenInput( QWidget *parent = 0, const char *name = 0, WFlags f = 0 );
+ virtual ~QIMPenInput();
+
+ void resetState();
+
+ QSize sizeHint() const;
+
+signals:
+ void key( ushort, ushort, ushort, bool, bool );
+
+private slots:
+ void wordPicked( const QString & );
+ void selectCharSet( int );
+ void beginStroke();
+ void strokeEntered( QIMPenStroke *st );
+ void matchedCharacters( const QIMPenCharMatchList &cl );
+ void keypress( uint scan_uni );
+ void erase();
+ void help();
+ void setup();
+ void backspace();
+ void enter();
+
+private:
+ void loadProfiles();
+ void selectProfile( const QString &name );
+ void handleExtended( const QString & );
+ void updateWordMatch( QIMPenCharMatchList &ml );
+ void matchWords();
+ void scanDict( const QDawg::Node* n, int ipos, const QString& str, int error );
+
+ enum Mode { Normal, Switch, SwitchLock };
+
+private:
+ Mode mode;
+ QRect prefRect;
+ QIMPenWidget *pw;
+ QPushButton *helpBtn;
+ QPushButton *setupBtn;
+ QIMPenSetup *setupDlg;
+ QIMPenMatch *matcher;
+ QGuardedPtr<HandwritingHelp> helpDlg;
+ QIMPenProfile *profile;
+ QList<QIMPenProfile> profileList;
+ QIMPenCharSet *shortcutCharSet;
+ QIMPenCharSetList baseSets;
+ int currCharSet;
+ QIMPenWordPick *wordPicker;
+};
+
+#endif // _QIMPENINPUT_H_
diff --git a/inputmethods/handwriting/qimpenmatch.cpp b/inputmethods/handwriting/qimpenmatch.cpp
new file mode 100644
index 0000000..0d3e25a
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenmatch.cpp
@@ -0,0 +1,365 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include "qimpenmatch.h"
+
+#include <qpe/qdawg.h>
+#include <qpe/global.h>
+
+#include <qapplication.h>
+#include <qtimer.h>
+
+#include <limits.h>
+
+#define ERROR_THRESHOLD 200000
+#define LOOKAHEAD_ERROR 2500
+//#define DEBUG_QIMPEN
+
+QIMPenMatch::QIMPenMatch( QObject *parent, const char *name )
+ : QObject( parent, name )
+{
+ strokes.setAutoDelete( TRUE );
+ wordChars.setAutoDelete( TRUE );
+ wordMatches.setAutoDelete( TRUE );
+
+ multiTimer = new QTimer( this );
+ connect( multiTimer, SIGNAL(timeout()), this, SLOT(endMulti()) );
+
+ prevMatchChar = 0;
+ prevMatchError = INT_MAX;
+ charSet = 0;
+ multiCharSet = 0;
+ multiTimeout = 500;
+ canErase = FALSE;
+ doWordMatching = true;
+}
+
+QIMPenMatch::~QIMPenMatch()
+{
+}
+
+void QIMPenMatch::setCharSet( QIMPenCharSet *cs )
+{
+ charSet = cs;
+}
+
+void QIMPenMatch::beginStroke()
+{
+ multiTimer->stop();
+}
+
+void QIMPenMatch::strokeEntered( QIMPenStroke *st )
+{
+#ifdef DEBUG_QIMPEN
+ qDebug( "---------- new stroke -------------" );
+#endif
+ strokes.append( new QIMPenStroke( *st ) );
+
+ QIMPenChar testChar;
+ QIMPenStrokeIterator it(strokes);
+ for ( ; it.current(); ++it ) {
+ testChar.addStroke( it.current() );
+ }
+
+ QIMPenCharMatchList ml;
+ if ( strokes.count() > 1 && multiCharSet ) {
+#ifdef DEBUG_QIMPEN
+ qDebug( "Matching against multi set" );
+#endif
+ ml = multiCharSet->match( &testChar );
+ } else {
+#ifdef DEBUG_QIMPEN
+ qDebug( "Matching against single set" );
+#endif
+ ml = charSet->match( &testChar );
+ }
+
+ processMatches( ml );
+}
+
+void QIMPenMatch::processMatches( QIMPenCharMatchList &ml )
+{
+#ifdef DEBUG_QIMPEN
+ qDebug( "Entering strokes.count() = %d", strokes.count() );
+#endif
+ QIMPenCharMatch candidate1 = { INT_MAX, 0 };
+ QIMPenCharMatch candidate2 = { INT_MAX, 0 };
+ QIMPenCharMatchList ml2;
+
+ if ( ml.count() ) {//&&
+// ml.first().penChar->penStrokes().count() == strokes.count() ) {
+ candidate1 = ml.first();
+#ifdef DEBUG_QIMPEN
+ qDebug( QString("Candidate1 = %1").arg(QChar(candidate1.penChar->character())) );
+#endif
+ }
+
+ if ( strokes.count() > 1 ) {
+ // See if the last stroke can match a new character
+ QIMPenChar testChar;
+ QIMPenStroke *st = strokes.at(strokes.count()-1);
+ testChar.addStroke( st );
+ ml2 = charSet->match( &testChar );
+ if ( ml2.count() ) {
+ candidate2 = ml2.first();
+#ifdef DEBUG_QIMPEN
+ qDebug( QString("Candidate2 = %1").arg(QChar(candidate2.penChar->character())) );
+#endif
+ }
+ }
+
+ bool eraseLast = FALSE;
+ bool output = TRUE;
+
+ if ( candidate1.penChar && candidate2.penChar ) {
+ // Hmmm, a multi-stroke or a new character are both possible.
+ // Bias the multi-stroke case.
+ if ( QMAX(candidate2.error, prevMatchError)*3 < candidate1.error ) {
+ int i = strokes.count()-1;
+ while ( i-- ) {
+ strokes.removeFirst();
+ emit removeStroke();
+ }
+ prevMatchChar = candidate2.penChar;
+ prevMatchError = candidate2.error;
+ multiCharSet = charSet;
+ ml = ml2;
+#ifdef DEBUG_QIMPEN
+ qDebug( "** Using Candidate2" );
+#endif
+ } else {
+ if ( (prevMatchChar->character() >> 16) != Qt::Key_Backspace &&
+ (prevMatchChar->character() >> 16) < QIMPenChar::ModeBase )
+ eraseLast = TRUE;
+ prevMatchChar = candidate1.penChar;
+ prevMatchError = candidate1.error;
+#ifdef DEBUG_QIMPEN
+ qDebug( "** Using Candidate1, with erase" );
+#endif
+ }
+ } else if ( candidate1.penChar ) {
+ if ( strokes.count() != 1 )
+ eraseLast = TRUE;
+ else
+ multiCharSet = charSet;
+ prevMatchChar = candidate1.penChar;
+ prevMatchError = candidate1.error;
+#ifdef DEBUG_QIMPEN
+ qDebug( "** Using Candidate1" );
+#endif
+ } else if ( candidate2.penChar ) {
+ int i = strokes.count()-1;
+ while ( i-- ) {
+ strokes.removeFirst();
+ emit removeStroke();
+ }
+ prevMatchChar = candidate2.penChar;
+ prevMatchError = candidate2.error;
+ multiCharSet = charSet;
+ ml = ml2;
+#ifdef DEBUG_QIMPEN
+ qDebug( "** Using Candidate2" );
+#endif
+ } else {
+ if ( !ml.count() ) {
+#ifdef DEBUG_QIMPEN
+ qDebug( "** Failed" );
+#endif
+ canErase = FALSE;
+ } else {
+#ifdef DEBUG_QIMPEN
+ qDebug( "Need more strokes" );
+#endif
+ if ( strokes.count() == 1 )
+ canErase = FALSE;
+ multiCharSet = charSet;
+ }
+ output = FALSE;
+ emit noMatch();
+ }
+
+ if ( eraseLast && canErase ) {
+#ifdef DEBUG_QIMPEN
+ qDebug( "deleting last" );
+#endif
+ emit erase();
+ wordChars.removeLast();
+ wordEntered.truncate( wordEntered.length() - 1 );
+ }
+
+ if ( output ) {
+ emit matchedCharacters( ml );
+ uint code = prevMatchChar->character() >> 16;
+ if ( code < QIMPenChar::ModeBase ) {
+ updateWordMatch( ml );
+ emit keypress( prevMatchChar->character() );
+ }
+ canErase = TRUE;
+ }
+
+ if ( strokes.count() )
+ multiTimer->start( multiTimeout, TRUE );
+}
+
+void QIMPenMatch::updateWordMatch( QIMPenCharMatchList &ml )
+{
+ if ( !ml.count() || !doWordMatching )
+ return;
+ int ch = ml.first().penChar->character();
+ QChar qch( ch );
+ int code = ch >> 16;
+ if ( qch.isPunct() || qch.isSpace() ||
+ code == Qt::Key_Enter || code == Qt::Key_Return ||
+ code == Qt::Key_Tab || code == Qt::Key_Escape ) {
+// qDebug( "Word Matching: Clearing word" );
+ wordChars.clear();
+ wordMatches.clear();
+ wordEntered = QString();
+ } else if ( code == Qt::Key_Backspace ) {
+ //qDebug( "Word Matching: Handle backspace" );
+ wordChars.removeLast();
+ wordEntered.truncate( wordEntered.length() - 1 );
+ matchWords();
+ } else {
+ QIMPenChar *matchCh;
+
+ wordChars.append( new QIMPenCharMatchList() );
+ wordEntered += ml.first().penChar->character();
+
+ QIMPenCharMatchList::Iterator it;
+ for ( it = ml.begin(); it != ml.end(); ++it ) {
+ matchCh = (*it).penChar;
+
+ if ( matchCh->penStrokes().count() == strokes.count() ) {
+ QChar ch(matchCh->character());
+ if ( !ch.isPunct() && !ch.isSpace() ) {
+ wordChars.last()->append( QIMPenCharMatch( (*it) ) );
+ }
+ }
+ }
+ matchWords();
+ }
+ if ( !wordMatches.count() || wordMatches.getFirst()->word != wordEntered )
+ wordMatches.prepend( new MatchWord( wordEntered, 0 ) );
+ emit matchedWords( wordMatches );
+}
+
+void QIMPenMatch::matchWords()
+{
+ if ( wordEntered.length() > 0 ) {
+ // more leaniency if we don't have many matches
+ if ( badMatches < 200 )
+ errorThreshold += (200 - badMatches) * 100;
+ } else
+ errorThreshold = ERROR_THRESHOLD;
+ wordMatches.clear();
+ goodMatches = 0;
+ badMatches = 0;
+ if ( wordChars.count() > 0 ) {
+ maxGuess = (int)wordChars.count() * 2;
+ if ( maxGuess < 3 )
+ maxGuess = 3;
+ QString str;
+ scanDict( Global::fixedDawg().root(), 0, str, 0 );
+/*
+ QListIterator<MatchWord> it( wordMatches);
+ for ( ; it.current(); ++it ) {
+ qDebug( QString("Match word: %1").arg(it.current()->word) );
+ }
+*/
+ }
+ //qDebug( "Possibles: Good %d, total %d", goodMatches, wordMatches.count() );
+ wordMatches.sort();
+}
+
+void QIMPenMatch::scanDict( const QDawg::Node* n, int ipos, const QString& str, int error )
+{
+ if ( !n )
+ return;
+ if ( error / (ipos+1) > errorThreshold )
+ return;
+
+ while (n) {
+ if ( goodMatches > 20 )
+ break;
+ if ( ipos < (int)wordChars.count() ) {
+ int i;
+ QChar testCh = QChar(n->letter());
+ QIMPenCharMatchList::Iterator it;
+ for ( i = 0, it = wordChars.at(ipos)->begin();
+ it != wordChars.at(ipos)->end() && i < 8; ++it, i++ ) {
+ QChar ch( (*it).penChar->character() );
+ if ( ch == testCh || ( !ipos && ch.lower() == testCh.lower() ) ) {
+ int newerr = error + (*it).error;
+ if ( testCh.category() == QChar::Letter_Uppercase )
+ ch = testCh;
+ QString newstr( str + ch );
+ if ( n->isWord() && ipos == (int)wordChars.count() - 1 ) {
+ wordMatches.append( new MatchWord( newstr, newerr ) );
+ goodMatches++;
+ }
+ scanDict( n->jump(), ipos+1, newstr, newerr );
+ }
+ }
+ } else if ( badMatches < 200 && ipos < maxGuess ) {
+ int d = ipos - wordChars.count();
+ int newerr = error + ERROR_THRESHOLD + LOOKAHEAD_ERROR*d;
+ QString newstr( str + n->letter() );
+ if ( n->isWord() ) {
+ wordMatches.append( new MatchWord( newstr, newerr ) );
+ badMatches++;
+ }
+ scanDict( n->jump(), ipos+1, newstr, newerr );
+ }
+ n = n->next();
+ }
+}
+
+void QIMPenMatch::backspace()
+{
+ wordChars.removeLast();
+ wordEntered.truncate( wordEntered.length() - 1 );
+ matchWords();
+ if ( !wordMatches.count() || wordMatches.getFirst()->word != wordEntered )
+ wordMatches.prepend( new MatchWord( wordEntered, 0 ) );
+ emit matchedWords( wordMatches );
+ if ( wordEntered.length() )
+ canErase = TRUE;
+}
+
+void QIMPenMatch::endMulti()
+{
+ int i = strokes.count();
+ while ( i-- )
+ emit removeStroke();
+ strokes.clear();
+ multiCharSet = 0;
+}
+
+void QIMPenMatch::resetState()
+{
+ if ( !wordEntered.isEmpty() ) {
+ wordChars.clear();
+ wordMatches.clear();
+ wordEntered = QString();
+ emit matchedWords( wordMatches );
+ canErase = FALSE;
+ }
+}
diff --git a/inputmethods/handwriting/qimpenmatch.h b/inputmethods/handwriting/qimpenmatch.h
new file mode 100644
index 0000000..d4a730e
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenmatch.h
@@ -0,0 +1,107 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef _QIMPENMATCH_H_
+#define _QIMPENMATCH_H_
+
+#include "qimpenchar.h"
+
+#include <qpe/qdawg.h>
+
+#include <qlist.h>
+
+class QTimer;
+class QIMPenWidget;
+class QIMPenSetup;
+class QIMPenWordPick;
+
+class QIMPenMatch : public QObject
+{
+ Q_OBJECT
+public:
+ QIMPenMatch( QObject *parent=0, const char *name=0 );
+ virtual ~QIMPenMatch();
+
+ void resetState();
+ void backspace();
+ void setMultiStrokeTimeout( int t ) { multiTimeout = t; }
+
+ const QString &word() const { return wordEntered; }
+
+ void setWordMatchingEnabled( bool e ) { doWordMatching = e; }
+ bool isWordMatchingEnabled() const { return doWordMatching; }
+
+ struct MatchWord {
+ MatchWord( const QString &w, int e ) { word = w; error = e; }
+ QString word;
+ int error;
+ };
+
+ class MatchWordList : public QList<MatchWord>
+ {
+ public:
+ int compareItems( QCollection::Item item1, QCollection::Item item2 ) {
+ MatchWord *m1 = (MatchWord *)item1;
+ MatchWord *m2 = (MatchWord *)item2;
+ return m1->error - m2->error;
+ }
+ };
+
+public slots:
+ void setCharSet( QIMPenCharSet * );
+ void beginStroke();
+ void strokeEntered( QIMPenStroke *st );
+
+signals:
+ void erase();
+ void noMatch();
+ void removeStroke();
+ void keypress( uint ch );
+ void matchedCharacters( const QIMPenCharMatchList & );
+ void matchedWords( const QIMPenMatch::MatchWordList & );
+
+protected slots:
+ void processMatches( QIMPenCharMatchList &ml );
+ void endMulti();
+
+protected:
+ void updateWordMatch( QIMPenCharMatchList &ml );
+ void matchWords();
+ void scanDict( const QDawg::Node* n, int ipos, const QString& str, int error );
+
+ QList<QIMPenStroke> strokes;
+ QIMPenChar *prevMatchChar;
+ int prevMatchError;
+ QIMPenCharSet *charSet;
+ QIMPenCharSet *multiCharSet;
+ QList<QIMPenCharMatchList> wordChars;
+ MatchWordList wordMatches;
+ QString wordEntered;
+ bool doWordMatching;
+ bool canErase;
+ int errorThreshold;
+ int goodMatches;
+ int badMatches;
+ int maxGuess;
+ QTimer *multiTimer;
+ int multiTimeout;
+};
+
+#endif // _QIMPENINPUT_H_
diff --git a/inputmethods/handwriting/qimpenprefbase.ui b/inputmethods/handwriting/qimpenprefbase.ui
new file mode 100644
index 0000000..1639d1a
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenprefbase.ui
@@ -0,0 +1,185 @@
+<!DOCTYPE UI><UI>
+<class>QIMPenPrefBase</class>
+<widget>
+ <class>QWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>QIMPenPrefBase</cstring>
+ </property>
+ <property stdset="1">
+ <name>geometry</name>
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>247</width>
+ <height>280</height>
+ </rect>
+ </property>
+ <property stdset="1">
+ <name>caption</name>
+ <string>Form1</string>
+ </property>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>11</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Multi-stroke character timeout:</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout2</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QSlider</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>multiStrokeSlider</cstring>
+ </property>
+ <property stdset="1">
+ <name>minValue</name>
+ <number>250</number>
+ </property>
+ <property stdset="1">
+ <name>maxValue</name>
+ <number>1000</number>
+ </property>
+ <property stdset="1">
+ <name>lineStep</name>
+ <number>10</number>
+ </property>
+ <property stdset="1">
+ <name>pageStep</name>
+ <number>50</number>
+ </property>
+ <property stdset="1">
+ <name>value</name>
+ <number>500</number>
+ </property>
+ <property stdset="1">
+ <name>orientation</name>
+ <enum>Horizontal</enum>
+ </property>
+ <property stdset="1">
+ <name>tickmarks</name>
+ <enum>Right</enum>
+ </property>
+ </widget>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>multiStrokeLabel</cstring>
+ </property>
+ <property stdset="1">
+ <name>minimumSize</name>
+ <size>
+ <width>45</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>ms</string>
+ </property>
+ <property stdset="1">
+ <name>alignment</name>
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property>
+ <name>hAlign</name>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget>
+ <class>QButtonGroup</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>inputStyle</cstring>
+ </property>
+ <property stdset="1">
+ <name>title</name>
+ <string>Input areas displayed</string>
+ </property>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>11</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QRadioButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>bothCasesRadio</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Upper and lower case areas</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QRadioButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>toggleCaseRadio</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Lower case (toggle Upper case)</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property>
+ <name>name</name>
+ <cstring>Spacer2</cstring>
+ </property>
+ <property stdset="1">
+ <name>orientation</name>
+ <enum>Vertical</enum>
+ </property>
+ <property stdset="1">
+ <name>sizeType</name>
+ <enum>Expanding</enum>
+ </property>
+ <property>
+ <name>sizeHint</name>
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+</UI>
diff --git a/inputmethods/handwriting/qimpenprofile.cpp b/inputmethods/handwriting/qimpenprofile.cpp
new file mode 100644
index 0000000..4b5bb83
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenprofile.cpp
@@ -0,0 +1,245 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include "qimpencombining.h"
+#include "qimpenprofile.h"
+
+#include <qpe/qpeapplication.h>
+#include <qpe/config.h>
+#include <qpe/global.h>
+
+
+QIMPenProfile::QIMPenProfile( const QString &fn )
+ : filename( fn )
+{
+ sets.setAutoDelete( true );
+
+ Config config( filename, Config::File );
+ config.setGroup( "Handwriting" );
+
+ pname = config.readEntry( "Name" );
+ pdesc = config.readEntry( "Description" );
+
+ tstyle = config.readBoolEntry( "CanSelectStyle", false );
+
+ wordMatch = config.readBoolEntry( "MatchWords", true );
+
+ config.setGroup( "Settings" );
+
+ pstyle = BothCases;
+ QString s = config.readEntry( "Style", "BothCases" );
+ if ( s == "ToggleCases" )
+ pstyle = ToggleCases;
+
+ msTimeout = config.readNumEntry( "MultiTimeout", 500 );
+
+ // Read user configuration
+ Config usrConfig( userConfig() );
+ usrConfig.setGroup( "Settings" );
+ msTimeout = usrConfig.readNumEntry( "MultiTimeout", msTimeout );
+
+ if ( tstyle && usrConfig.hasKey( "Style" ) ) {
+ pstyle = BothCases;
+ QString s = usrConfig.readEntry( "Style", "BothCases" );
+ if ( s == "ToggleCases" )
+ pstyle = ToggleCases;
+ }
+}
+
+void QIMPenProfile::setStyle( Style s )
+{
+ if ( tstyle && s != pstyle ) {
+ pstyle = s;
+ Config config( userConfig() );
+ config.setGroup( "Settings" );
+ QString s = pstyle == ToggleCases ? "ToggleCases" : "BothCases";
+ config.writeEntry( "Style", s );
+ }
+}
+
+void QIMPenProfile::setMultiStrokeTimeout( int t )
+{
+ if ( t != msTimeout ) {
+ msTimeout = t;
+ Config config( userConfig() );
+ config.setGroup( "Settings" );
+ config.writeEntry( "MultiTimeout", msTimeout );
+ }
+}
+
+QString QIMPenProfile::userConfig()
+{
+ QString un = filename;
+ int pos = un.findRev( '/' );
+ if ( pos >= 0 )
+ un = un.mid( pos + 1 );
+ pos = un.find( '.' );
+ if ( pos > 0 )
+ un.truncate( pos );
+
+ un = "handwriting-" + un;
+
+ return un;
+}
+
+void QIMPenProfile::loadData()
+{
+ Config config( filename, Config::File );
+ config.setGroup( "CharSets" );
+
+ QString baseDir = QPEApplication::qpeDir();
+ baseDir += "/etc/";
+ // accents
+ QIMPenCombining *combining = 0;
+ QString s = config.readEntry( "Combining" );
+ if ( !s.isEmpty() ) {
+ combining = new QIMPenCombining( baseDir + "qimpen/" + s );
+ if ( combining->isEmpty() ) {
+ delete combining;
+ combining = 0;
+ }
+ }
+ // uppercase latin1
+ QIMPenCharSet *cs = 0;
+ s = config.readEntry( "Uppercase" );
+ if ( !s.isEmpty() ) {
+ cs = new QIMPenCharSet( baseDir + "qimpen/" + s );
+ cs->load( Global::applicationFileName("qimpen",s), QIMPenCharSet::User );
+ if ( !cs->isEmpty() ) {
+ if ( combining )
+ combining->addCombined( cs );
+ sets.append( cs );
+ } else {
+ delete cs;
+ }
+ }
+ // lowercase latin1
+ s = config.readEntry( "Lowercase" );
+ if ( !s.isEmpty() ) {
+ cs = new QIMPenCharSet( baseDir + "qimpen/" + s );
+ cs->load( Global::applicationFileName("qimpen",s), QIMPenCharSet::User );
+ if ( !cs->isEmpty() ) {
+ if ( combining )
+ combining->addCombined( cs );
+ sets.append( cs );
+ } else {
+ delete cs;
+ }
+ }
+ // numeric (may comtain punctuation and symbols)
+ s = config.readEntry( "Numeric" );
+ if ( !s.isEmpty() ) {
+ cs = new QIMPenCharSet( baseDir + "qimpen/" + s );
+ cs->load( Global::applicationFileName("qimpen",s), QIMPenCharSet::User );
+ if ( !cs->isEmpty() ) {
+ sets.append( cs );
+ } else {
+ delete cs;
+ }
+ }
+ // punctuation
+ s = config.readEntry( "Punctuation" );
+ if ( !s.isEmpty() ) {
+ cs = new QIMPenCharSet( baseDir + "qimpen/" + s );
+ cs->load( Global::applicationFileName("qimpen",s), QIMPenCharSet::User );
+ if ( !cs->isEmpty() ) {
+ sets.append( cs );
+ } else {
+ delete cs;
+ }
+ }
+ // symbol
+ s = config.readEntry( "Symbol" );
+ if ( !s.isEmpty() ) {
+ cs = new QIMPenCharSet( baseDir + "qimpen/" + s );
+ cs->load( Global::applicationFileName("qimpen",s), QIMPenCharSet::User );
+ if ( !cs->isEmpty() ) {
+ sets.append( cs );
+ } else {
+ delete cs;
+ }
+ }
+ // shortcut
+ s = config.readEntry( "Shortcut" );
+ if ( !s.isEmpty() ) {
+ cs = new QIMPenCharSet( baseDir + "qimpen/" + s );
+ cs->load( Global::applicationFileName("qimpen",s), QIMPenCharSet::User );
+ if ( !cs->isEmpty() ) {
+ sets.append( cs );
+ } else {
+ delete cs;
+ }
+ }
+
+ if ( combining )
+ delete combining;
+}
+
+QIMPenCharSet *QIMPenProfile::uppercase()
+{
+ return find( QIMPenCharSet::Upper );
+}
+
+QIMPenCharSet *QIMPenProfile::lowercase()
+{
+ return find( QIMPenCharSet::Lower );
+}
+
+QIMPenCharSet *QIMPenProfile::numeric()
+{
+ return find( QIMPenCharSet::Numeric );
+}
+
+QIMPenCharSet *QIMPenProfile::punctuation()
+{
+ return find( QIMPenCharSet::Punctuation );
+}
+
+QIMPenCharSet *QIMPenProfile::symbol()
+{
+ return find( QIMPenCharSet::Symbol );
+}
+
+QIMPenCharSet *QIMPenProfile::shortcut()
+{
+ return find( QIMPenCharSet::Shortcut );
+}
+
+QIMPenCharSetList &QIMPenProfile::charSets()
+{
+ if ( sets.isEmpty() )
+ loadData();
+ return sets;
+}
+
+QIMPenCharSet *QIMPenProfile::find( QIMPenCharSet::Type t )
+{
+ if ( sets.isEmpty() )
+ loadData();
+ QIMPenCharSetIterator it( sets );
+ for ( ; it.current(); ++it ) {
+ if ( it.current()->type() == t )
+ return it.current();
+ }
+
+ return 0;
+}
+
+
diff --git a/inputmethods/handwriting/qimpenprofile.h b/inputmethods/handwriting/qimpenprofile.h
new file mode 100644
index 0000000..4ce4367
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenprofile.h
@@ -0,0 +1,70 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef QIMPENPROFILE_H_
+#define QIMPENPROFILE_H_
+
+#include "qimpenchar.h"
+
+class QIMPenProfile
+{
+public:
+ QIMPenProfile( const QString &fn );
+
+ const QString &name() const { return pname; }
+ const QString &description() const { return pdesc; }
+
+ enum Style { ToggleCases, BothCases };
+ Style style() const { return pstyle; }
+ void setStyle( Style s );
+
+ bool canSelectStyle() const { return tstyle; }
+
+ int multiStrokeTimeout() const { return msTimeout; }
+ void setMultiStrokeTimeout( int t );
+
+ bool matchWords() const { return wordMatch; }
+
+ QIMPenCharSet *uppercase();
+ QIMPenCharSet *lowercase();
+ QIMPenCharSet *numeric();
+ QIMPenCharSet *punctuation();
+ QIMPenCharSet *symbol();
+ QIMPenCharSet *shortcut();
+ QIMPenCharSet *find( QIMPenCharSet::Type t );
+
+ QIMPenCharSetList &charSets();
+
+private:
+ QString userConfig();
+ void loadData();
+
+private:
+ QIMPenCharSetList sets;
+ QString filename;
+ QString pname;
+ QString pdesc;
+ Style pstyle;
+ bool tstyle;
+ int msTimeout;
+ bool wordMatch;
+};
+
+#endif
diff --git a/inputmethods/handwriting/qimpensetup.cpp b/inputmethods/handwriting/qimpensetup.cpp
new file mode 100644
index 0000000..a6ae3a8
--- a/dev/null
+++ b/inputmethods/handwriting/qimpensetup.cpp
@@ -0,0 +1,656 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include "qimpenwidget.h"
+#include "qimpenprefbase.h"
+#include "qimpensetup.h"
+
+#include <qpe/qpeapplication.h>
+#include <qpe/config.h>
+
+#include <qcombobox.h>
+#include <qlistbox.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qpixmap.h>
+#include <qbuttongroup.h>
+#include <qslider.h>
+#include <qtabwidget.h>
+#include <qdir.h>
+#include <qmessagebox.h>
+
+
+/* XPM */
+static const char * const left_xpm[] = {
+"16 16 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" . ",
+" .. ",
+" ... ",
+" .... ",
+" ..... ",
+" ...... ",
+" ..... ",
+" .... ",
+" ... ",
+" .. ",
+" . ",
+" ",
+" "};
+
+
+/* XPM */
+static const char * const right_xpm[] = {
+"16 16 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" . ",
+" .. ",
+" ... ",
+" .... ",
+" ..... ",
+" ...... ",
+" ..... ",
+" .... ",
+" ... ",
+" .. ",
+" . ",
+" ",
+" "};
+
+
+
+QIMPenSetup::QIMPenSetup( QIMPenProfile *p, QWidget *parent,
+ const char *name, bool modal, int WFlags )
+ : QDialog( parent, name, modal, WFlags ), profileCombo(0), profile(p)
+{
+ setCaption( tr("Setup Handwriting Input") );
+
+ QVBoxLayout *vb = new QVBoxLayout( this );
+
+#if 0
+ profileList.setAutoDelete( true );
+ QHBoxLayout *hb = new QHBoxLayout( vb );
+ hb->setMargin( 6 );
+ QLabel *l = new QLabel( tr("Character Profile:"), this );
+ hb->addWidget( l );
+ profileCombo = new QComboBox( this );
+ connect( profileCombo, SIGNAL(activated(const QString &)),
+ this, SLOT(selectProfile(const QString &)) );
+ hb->addWidget( profileCombo );
+ loadProfiles();
+#else
+ profileList.append( profile );
+#endif
+
+ QTabWidget *tw = new QTabWidget( this );
+ vb->addWidget( tw );
+
+ pref = new QIMPenPrefBase( this );
+ tw->addTab( pref, tr("Preferences") );
+
+ pref->inputStyle->setExclusive( TRUE );
+
+ style = profile->style() == QIMPenProfile::ToggleCases ? 1 : 0;
+ pref->inputStyle->setButton( style );
+ connect( pref->inputStyle, SIGNAL(clicked(int)),
+ this, SLOT(styleClicked(int)) );
+ pref->inputStyle->setEnabled( profile->canSelectStyle() );
+
+ multiTimeout = profile->multiStrokeTimeout();
+ pref->multiStrokeSlider->setValue( multiTimeout );
+ multiTimeoutChanged( multiTimeout );
+ connect( pref->multiStrokeSlider, SIGNAL(valueChanged(int)),
+ this, SLOT(multiTimeoutChanged(int)) );
+
+ edit = new QIMPenEdit( p, tw );
+ tw->addTab( edit, tr("Customize") );
+}
+
+void QIMPenSetup::loadProfiles()
+{
+ QString path = QPEApplication::qpeDir() + "etc/qimpen";
+ QDir dir( path, "*.conf" );
+ QStringList list = dir.entryList();
+ QStringList::Iterator it;
+ for ( it = list.begin(); it != list.end(); ++it ) {
+ QIMPenProfile *p = new QIMPenProfile( path + "/" + *it );
+ profileList.append( p );
+ profileCombo->insertItem( p->name() );
+ if ( p->name() == profile->name() ) {
+ profileCombo->setCurrentItem( profileCombo->count()-1 );
+ profile = p;
+ }
+ }
+}
+
+void QIMPenSetup::styleClicked( int id )
+{
+ style = id;
+}
+
+void QIMPenSetup::multiTimeoutChanged( int v )
+{
+ multiTimeout = v;
+ pref->multiStrokeLabel->setText( tr("%1 ms").arg(v) );
+}
+
+void QIMPenSetup::selectProfile( const QString &p )
+{
+ if ( p == profile->name() )
+ return;
+
+ profile->setStyle( style ? QIMPenProfile::ToggleCases : QIMPenProfile::BothCases );
+ profile->setMultiStrokeTimeout( multiTimeout );
+
+ for ( int i = 0; i < (int)profileList.count(); i++ ) {
+ if ( profileList.at(i)->name() == p ) {
+ profile = profileList.at(i);
+ style = profile->style() == QIMPenProfile::ToggleCases ? 1 : 0;
+ pref->inputStyle->setButton( style );
+ pref->inputStyle->setEnabled( profile->canSelectStyle() );
+ multiTimeout = profile->multiStrokeTimeout();
+ pref->multiStrokeSlider->setValue( multiTimeout );
+ multiTimeoutChanged( multiTimeout );
+ edit->setProfile( profile );
+ break;
+ }
+ }
+}
+
+void QIMPenSetup::accept()
+{
+ profile->setStyle( style ? QIMPenProfile::ToggleCases : QIMPenProfile::BothCases );
+ profile->setMultiStrokeTimeout( multiTimeout );
+ // Save current profile
+ if ( profileCombo ) {
+ Config config( "handwriting" );
+ config.setGroup( "Settings" );
+ config.writeEntry( "Profile", profileCombo->currentText() );
+ }
+ // Save charsets
+ bool ok = TRUE;
+ for ( int i = 0; i < (int)profileList.count(); i++ ) {
+ QIMPenProfile *prof = profileList.at(i);
+ QIMPenCharSetIterator it(prof->charSets());
+ for ( ; it.current(); ++it ) {
+ if ( !(it.current()->save( QIMPenCharSet::User )) ) {
+ ok = FALSE;
+ break;
+ }
+ }
+ }
+ if ( !ok ) {
+ if ( QMessageBox::critical( 0, tr( "Out of space" ),
+ tr("Unable to save information.\n"
+ "Free up some space\n"
+ "and try again.\n"
+ "\nQuit anyway?"),
+ QMessageBox::Yes|QMessageBox::Escape,
+ QMessageBox::No|QMessageBox::Default )
+ != QMessageBox::No ) {
+ QDialog::accept();
+ }
+ } else {
+ QDialog::accept();
+ }
+}
+
+//---------------------------------------------------------------------------
+
+QIMPenInputCharDlg::QIMPenInputCharDlg( QWidget *parent, const char *name,
+ bool modal, int WFlags)
+ : QDialog( parent, name, modal, WFlags )
+{
+ setCaption( tr("Enter new character") );
+ uni = 0;
+
+ QVBoxLayout *vb = new QVBoxLayout( this, 10 );
+
+ QHBoxLayout *hb = new QHBoxLayout();
+ vb->addLayout( hb );
+
+ QLabel *label = new QLabel( "Character:", this );
+ hb->addWidget( label );
+
+ QComboBox *cb = new QComboBox( TRUE, this );
+ connect( cb, SIGNAL(activated(int)), SLOT(setSpecial(int)) );
+ connect( cb, SIGNAL(textChanged(const QString &)),
+ SLOT(setCharacter(const QString &)) );
+ addSpecial( cb );
+ cb->setEditText( "" );
+ hb->addWidget( cb );
+
+ hb = new QHBoxLayout();
+ vb->addLayout( hb );
+
+ QPushButton *pb = new QPushButton( "OK", this );
+ connect( pb, SIGNAL(clicked()), SLOT(accept()));
+ hb->addWidget( pb );
+ pb = new QPushButton( "Cancel", this );
+ connect( pb, SIGNAL(clicked()), SLOT(reject()));
+ hb->addWidget( pb );
+
+ cb->setFocus();
+}
+
+void QIMPenInputCharDlg::addSpecial( QComboBox *cb )
+{
+ int i = 0;
+ while ( qimpen_specialKeys[i].code != Key_unknown ) {
+ cb->insertItem( qimpen_specialKeys[i].name );
+ i++;
+ }
+}
+
+void QIMPenInputCharDlg::setSpecial( int sp )
+{
+ uni = qimpen_specialKeys[sp].code << 16;
+}
+
+void QIMPenInputCharDlg::setCharacter( const QString &string )
+{
+ uni = string[0].unicode();
+}
+
+//---------------------------------------------------------------------------
+
+class CharListItem : public QListBoxText
+{
+public:
+ CharListItem( const QString &text, uint c )
+ : QListBoxText( text )
+ {
+ _code = c;
+ }
+
+ uint code() const { return _code; }
+
+protected:
+ uint _code;
+};
+
+/*!
+ \class QIMPenEdit qimpensetup.h
+
+ Class to allow users to input totally useless character definitions
+ which could match any number of the default set.
+*/
+
+QIMPenEdit::QIMPenEdit( QIMPenProfile *p, QWidget *parent,
+ const char *name )
+ : QWidget( parent, name ), profile(p)
+{
+ currentChar = 0;
+ currentCode = 0;
+ inputChar = new QIMPenChar();
+
+ QVBoxLayout *tvb = new QVBoxLayout( this, 5 );
+
+ QGridLayout *gl = new QGridLayout( tvb, 4, 2 );
+ gl->setRowStretch( 1, 1 );
+ gl->addRowSpacing( 2, 35 );
+ gl->addRowSpacing( 3, 35 );
+
+ charSetCombo = new QComboBox( this );
+ gl->addMultiCellWidget( charSetCombo, 0, 0, 0, 1 );
+ connect( charSetCombo, SIGNAL(activated(int)), SLOT(selectCharSet(int)));
+ QIMPenCharSetIterator it( profile->charSets() );
+ for ( ; it.current(); ++it ) {
+ charSetCombo->insertItem( it.current()->description() );
+ }
+
+ charList = new QListBox( this );
+ charList->setMinimumHeight( charList->sizeHint().height() );
+ connect( charList, SIGNAL(highlighted(int)), SLOT(selectChar(int)) );
+ gl->addWidget( charList, 1, 0 );
+
+ pw = new QIMPenWidget( this );
+ pw->setFixedHeight( 75 );
+ gl->addMultiCellWidget( pw, 2, 3, 0, 0 );
+ connect( pw, SIGNAL(stroke(QIMPenStroke *)),
+ SLOT(newStroke(QIMPenStroke *)) );
+
+ QVBoxLayout *vb = new QVBoxLayout();
+ gl->addLayout( vb, 1, 1 );
+ newBtn = new QPushButton( tr("New..."), this );
+ connect( newBtn, SIGNAL(clicked()), SLOT(addNewChar()) );
+ vb->addWidget( newBtn );
+
+ addBtn = new QPushButton( tr("Add"), this );
+ connect( addBtn, SIGNAL(clicked()), SLOT(addChar()) );
+ vb->addWidget( addBtn );
+
+ removeBtn = new QPushButton( tr("Remove"), this );
+ connect( removeBtn, SIGNAL(clicked()), SLOT(removeChar()) );
+ vb->addWidget( removeBtn );
+
+ QPushButton *pb = new QPushButton( tr("Default"), this );
+ connect( pb, SIGNAL(clicked()), SLOT(defaultChars()) );
+ vb->addWidget( pb );
+
+ QHBoxLayout *hb = new QHBoxLayout();
+ gl->addLayout( hb, 2, 1 );
+ prevBtn = new QPushButton( this );
+ prevBtn->setPixmap( QPixmap( (const char **)left_xpm ) );
+ connect( prevBtn, SIGNAL(clicked()), SLOT(prevChar()));
+ hb->addWidget( prevBtn );
+
+ nextBtn = new QPushButton( this );
+ nextBtn->setPixmap( QPixmap( (const char **)right_xpm ) );
+ connect( nextBtn, SIGNAL(clicked()), SLOT(nextChar()));
+ hb->addWidget( nextBtn );
+
+ pb = new QPushButton( tr("Clear"), this );
+ connect( pb, SIGNAL(clicked()), SLOT(clearChar()) );
+ gl->addWidget( pb, 3, 1 );
+
+ //--
+#if !defined(Q_WS_QWS)
+ hb = new QHBoxLayout( tvb );
+ pb = new QPushButton( "OK", this );
+ connect( pb, SIGNAL(clicked()), SLOT(accept()) );
+ hb->addWidget( pb );
+
+ pb = new QPushButton( "Cancel", this );
+ connect( pb, SIGNAL(clicked()), SLOT(reject()) );
+ hb->addWidget( pb );
+#endif
+ selectCharSet( 0 );
+ charList->setFocus();
+
+ resize( minimumSize() );
+ enableButtons();
+}
+
+void QIMPenEdit::setProfile( QIMPenProfile *p )
+{
+ profile = p;
+ charSetCombo->clear();
+ QIMPenCharSetIterator it( profile->charSets() );
+ for ( ; it.current(); ++it ) {
+ charSetCombo->insertItem( it.current()->description() );
+ }
+ selectCharSet( 0 );
+ charList->setFocus();
+ enableButtons();
+}
+
+void QIMPenEdit::selectCharSet( QIMPenCharSet *c )
+{
+ int i = 0;
+ QIMPenCharSetIterator it( profile->charSets() );
+ for ( ; it.current(); ++it, i++ ) {
+ if ( it.current() == c ) {
+ charSetCombo->setCurrentItem( i );
+ selectCharSet( i );
+ }
+ }
+}
+
+
+/*!
+ Fill the character list box with the characters. Duplicates are not
+ inserted.
+*/
+void QIMPenEdit::fillCharList()
+{
+ charList->clear();
+ QIMPenCharIterator it( currentSet->characters() );
+ CharListItem *li = 0;
+ for ( ; it.current(); ++it ) {
+ uint ch = it.current()->character();
+ QString n = it.current()->name();
+ if ( !n.isEmpty() )
+ li = new CharListItem( n, ch );
+ if ( li ) {
+ CharListItem *i = (CharListItem *)charList->findItem( li->text() );
+ if ( !i || i->code() != ch ) {
+ charList->insertItem( li );
+ } else {
+ delete li;
+ li = 0;
+ }
+ }
+ }
+ currentChar = 0;
+}
+
+void QIMPenEdit::enableButtons()
+{
+ bool add = !inputChar->isEmpty();
+ newBtn->setEnabled( add );
+ addBtn->setEnabled( add );
+ removeBtn->setEnabled( currentChar );
+}
+
+/*!
+ Find the previous character with the same code as the current one.
+ returns 0 if there is no previous character.
+*/
+QIMPenChar *QIMPenEdit::findPrev()
+{
+ if ( !currentChar )
+ return 0;
+ QIMPenCharIterator it( currentSet->characters() );
+ bool found = FALSE;
+ for ( it.toLast(); it.current(); --it ) {
+ if ( !found && it.current() == currentChar )
+ found = TRUE;
+ else if ( found && it.current()->character() == currentCode &&
+ !it.current()->testFlag( QIMPenChar::Deleted ) ) {
+ return it.current();
+ }
+ }
+
+ return 0;
+}
+
+/*!
+ Find the next character with the same code as the current one.
+ returns 0 if there is no next character.
+*/
+QIMPenChar *QIMPenEdit::findNext()
+{
+ if ( !currentChar )
+ return 0;
+ QIMPenCharIterator it( currentSet->characters() );
+ bool found = FALSE;
+ for ( ; it.current(); ++it ) {
+ if ( !found && it.current() == currentChar )
+ found = TRUE;
+ else if ( found && it.current()->character() == currentCode &&
+ !it.current()->testFlag( QIMPenChar::Deleted ) ) {
+ return it.current();
+ }
+ }
+
+ return 0;
+}
+
+void QIMPenEdit::setCurrentChar( QIMPenChar *pc )
+{
+ currentChar = pc;
+ pw->showCharacter( currentChar );
+ if ( currentChar ) {
+ prevBtn->setEnabled( findPrev() != 0 );
+ nextBtn->setEnabled( findNext() != 0 );
+ }
+}
+
+void QIMPenEdit::prevChar()
+{
+ QIMPenChar *pc = findPrev();
+ if ( pc )
+ setCurrentChar( pc );
+}
+
+void QIMPenEdit::nextChar()
+{
+ QIMPenChar *pc = findNext();
+ if ( pc )
+ setCurrentChar( pc );
+}
+
+void QIMPenEdit::clearChar()
+{
+ inputChar->clear();
+ pw->clear();
+ enableButtons();
+}
+
+void QIMPenEdit::selectChar( int i )
+{
+ currentChar = 0;
+ currentCode = ((CharListItem *)charList->item(i))->code();
+ QIMPenCharIterator it(currentSet->characters() );
+ for ( ; it.current(); ++it ) {
+ if ( it.current()->character() == currentCode &&
+ !it.current()->testFlag( QIMPenChar::Deleted ) ) {
+ setCurrentChar( it.current() );
+ break;
+ }
+ }
+ if ( !it.current() )
+ setCurrentChar( 0 );
+ inputChar->clear();
+}
+
+void QIMPenEdit::selectCharSet( int i )
+{
+ if ( currentSet )
+ pw->removeCharSet( 0 );
+ currentSet = profile->charSets().at( i );
+ fillCharList();
+ pw->insertCharSet( currentSet );
+ inputChar->clear();
+ if ( charList->count() ) {
+ charList->setSelected( 0, TRUE );
+ selectChar(0);
+ }
+}
+
+void QIMPenEdit::addChar()
+{
+ if ( !inputChar->isEmpty() ) {
+ QIMPenChar *pc = new QIMPenChar( *inputChar );
+ pc->setCharacter( currentCode );
+
+ // User characters override all matching system characters.
+ // Copy and mark deleted identical system characters.
+ QIMPenCharIterator it(currentSet->characters() );
+ QIMPenChar *sc = 0;
+ while ( (sc = it.current()) != 0 ) {
+ ++it;
+ if ( sc->character() == currentCode &&
+ sc->testFlag( QIMPenChar::System ) &&
+ !sc->testFlag( QIMPenChar::Deleted ) ) {
+ QIMPenChar *cc = new QIMPenChar( *sc );
+ cc->clearFlag( QIMPenChar::System );
+ currentSet->addChar( cc );
+ sc->setFlag( QIMPenChar::Deleted );
+ }
+ }
+
+ currentSet->addChar( pc );
+ setCurrentChar( pc );
+ inputChar->clear();
+ }
+}
+
+void QIMPenEdit::addNewChar()
+{
+ if ( !inputChar->isEmpty() ) {
+ QIMPenInputCharDlg dlg( 0, 0, TRUE );
+ if ( dlg.exec() ) {
+ currentCode = dlg.unicode();
+ addChar();
+ fillCharList();
+ for ( unsigned int i = 0; i < charList->count(); i++ ) {
+ CharListItem *li = (CharListItem *)charList->item(i);
+ if ( li->code() == dlg.unicode() ) {
+ charList->setSelected( i, TRUE );
+ break;
+ }
+ }
+ }
+ }
+}
+
+void QIMPenEdit::removeChar()
+{
+ if ( currentChar ) {
+ QIMPenChar *pc = findPrev();
+ if ( !pc ) pc = findNext();
+ if ( currentChar->testFlag( QIMPenChar::System ) )
+ currentChar->setFlag( QIMPenChar::Deleted );
+ else
+ currentSet->removeChar( currentChar );
+ setCurrentChar( pc );
+ }
+}
+
+void QIMPenEdit::defaultChars()
+{
+ if ( currentCode ) {
+ currentChar = 0;
+ bool haveSystem = FALSE;
+ QIMPenCharIterator it(currentSet->characters() );
+ for ( ; it.current(); ++it ) {
+ if ( it.current()->character() == currentCode &&
+ it.current()->testFlag( QIMPenChar::System ) ) {
+ haveSystem = TRUE;
+ break;
+ }
+ }
+ if ( haveSystem ) {
+ it.toFirst();
+ while ( it.current() ) {
+ QIMPenChar *pc = it.current();
+ ++it;
+ if ( pc->character() == currentCode ) {
+ if ( pc->testFlag( QIMPenChar::System ) ) {
+ pc->clearFlag( QIMPenChar::Deleted );
+ if ( !currentChar )
+ currentChar = pc;
+ } else {
+ currentSet->removeChar( pc );
+ }
+ }
+ }
+ setCurrentChar( currentChar );
+ }
+ }
+}
+
+void QIMPenEdit::newStroke( QIMPenStroke *st )
+{
+ inputChar->addStroke( st );
+ enableButtons();
+}
+
diff --git a/inputmethods/handwriting/qimpensetup.h b/inputmethods/handwriting/qimpensetup.h
new file mode 100644
index 0000000..5d3064b
--- a/dev/null
+++ b/inputmethods/handwriting/qimpensetup.h
@@ -0,0 +1,124 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include <qdialog.h>
+#include <qlist.h>
+#include "qimpenprofile.h"
+
+class QListBox;
+class QPushButton;
+class QComboBox;
+class QIMPenWidget;
+class QIMPenEdit;
+class QIMPenPrefBase;
+
+class QIMPenSetup : public QDialog
+{
+ Q_OBJECT
+public:
+ QIMPenSetup( QIMPenProfile *p, QWidget *parent=0,
+ const char *name=0, bool modal=FALSE, int WFlags=0 );
+
+ QIMPenEdit *editor() { return edit; }
+
+protected:
+ void loadProfiles();
+ virtual void accept();
+
+private slots:
+ void styleClicked( int );
+ void multiTimeoutChanged( int );
+ void selectProfile( const QString &p );
+
+private:
+ QComboBox *profileCombo;
+ QIMPenEdit *edit;
+ QIMPenPrefBase *pref;
+ int style;
+ int multiTimeout;
+ QIMPenProfile *profile;
+ QList<QIMPenProfile> profileList;
+};
+
+class QIMPenInputCharDlg : public QDialog
+{
+ Q_OBJECT
+public:
+ QIMPenInputCharDlg( QWidget *parent = 0, const char *name = 0,
+ bool modal = FALSE, int WFlags = 0 );
+
+ unsigned int unicode() const { return uni; }
+
+protected:
+ void addSpecial( QComboBox *cb );
+
+protected slots:
+ void setSpecial( int sp );
+ void setCharacter( const QString &string );
+
+protected:
+ uint uni;
+};
+
+class QIMPenEdit : public QWidget
+{
+ Q_OBJECT
+public:
+ QIMPenEdit( QIMPenProfile *p, QWidget *parent=0,
+ const char *name=0 );
+
+ void setProfile( QIMPenProfile *p );
+ void selectCharSet( QIMPenCharSet *c );
+
+protected:
+ void fillCharList();
+ void enableButtons();
+ QIMPenChar *findPrev();
+ QIMPenChar *findNext();
+ void setCurrentChar( QIMPenChar * );
+
+protected slots:
+ void prevChar();
+ void nextChar();
+ void clearChar();
+ void selectChar( int );
+ void selectCharSet( int );
+ void addChar();
+ void addNewChar();
+ void removeChar();
+ void defaultChars();
+ void newStroke( QIMPenStroke * );
+
+protected:
+ QIMPenWidget *pw;
+ QComboBox *charSetCombo;
+ QListBox *charList;
+ QPushButton *newBtn;
+ QPushButton *addBtn;
+ QPushButton *removeBtn;
+ QPushButton *prevBtn;
+ QPushButton *nextBtn;
+ uint currentCode;
+ QIMPenChar *currentChar;
+ QIMPenChar *inputChar;
+ QIMPenCharSet *currentSet;
+ QIMPenProfile *profile;
+};
+
diff --git a/inputmethods/handwriting/qimpenstroke.cpp b/inputmethods/handwriting/qimpenstroke.cpp
new file mode 100644
index 0000000..3567d6d
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenstroke.cpp
@@ -0,0 +1,646 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include <qfile.h>
+#include <qtl.h>
+#include <math.h>
+#include <limits.h>
+#include <qdatastream.h>
+#include "qimpenstroke.h"
+
+#define QIMPEN_CORRELATION_POINTS 25
+//#define DEBUG_QIMPEN
+
+/*!
+ \class QIMPenStroke qimpenstroke.h
+
+ Handles a single stroke. Can calculate closeness of match to
+ another stroke.
+*/
+
+QIMPenStroke::QIMPenStroke()
+{
+}
+
+QIMPenStroke::QIMPenStroke( const QIMPenStroke &st )
+{
+ startPoint = st.startPoint;
+ lastPoint = st.lastPoint;
+ links = st.links.copy();
+}
+
+QIMPenStroke &QIMPenStroke::operator=( const QIMPenStroke &s )
+{
+ clear();
+ //qDebug( "copy strokes %d", s.links.count() );
+ startPoint = s.startPoint;
+ lastPoint = s.lastPoint;
+ links = s.links.copy();
+
+ return *this;
+}
+
+void QIMPenStroke::clear()
+{
+ startPoint = QPoint(0,0);
+ lastPoint = QPoint( 0, 0 );
+ links.resize( 0 );
+ tsig.resize( 0 );
+ dsig.resize( 0 );
+ asig.resize( 0 );
+}
+
+/*!
+ Begin inputting a new stroke.
+*/
+void QIMPenStroke::beginInput( QPoint p )
+{
+ clear();
+ startPoint = p;
+ bounding = QRect();
+ internalAddPoint( p );
+}
+
+/*!
+ Add a point to the stroke's shape.
+ Returns TRUE if the point was successfully added.
+*/
+bool QIMPenStroke::addPoint( QPoint p )
+{
+ if ( links.count() > 500 ) // sanity check (that the user is sane).
+ return FALSE;
+
+ int dx = p.x() - lastPoint.x();
+ int dy = p.y() - lastPoint.y();
+ if ( QABS( dx ) > 1 || QABS( dy ) > 1 ) {
+ // The point is not adjacent to the previous point, so we fill
+ // in with a straight line. Some kind of non-linear
+ // interpolation might be better.
+ int x = lastPoint.x();
+ int y = lastPoint.y();
+ int ix = 1;
+ int iy = 1;
+ if ( dx < 0 ) {
+ ix = -1;
+ dx = -dx;
+ }
+ if ( dy < 0 ) {
+ iy = -1;
+ dy = -dy;
+ }
+ int d = 0;
+ if ( dx < dy ) {
+ d = dx;
+ do {
+ y += iy;
+ d += dx;
+ if ( d > dy ) {
+ x += ix;
+ d -= dy;
+ }
+ internalAddPoint( QPoint( x, y ) );
+ } while ( y != p.y() );
+ } else {
+ d = dy;
+ do {
+ x += ix;
+ d += dy;
+ if ( d > dx ) {
+ y += iy;
+ d -= dx;
+ }
+ internalAddPoint( QPoint( x, y ) );
+ } while ( x != p.x() );
+ }
+ } else {
+ internalAddPoint( p );
+ }
+
+ return TRUE;
+}
+
+/*!
+ Finish inputting a stroke.
+*/
+void QIMPenStroke::endInput()
+{
+ if ( links.count() < 3 ) {
+ QIMPenGlyphLink gl;
+ links.resize(1);
+ gl.dx = 1;
+ gl.dy = 0;
+ links[0] = gl;
+ }
+
+ //qDebug("Points: %d", links.count() );
+}
+
+/*!
+ Return an indicator of the closeness of this stroke to \a pen.
+ Lower value is better.
+*/
+unsigned int QIMPenStroke::match( QIMPenStroke *pen )
+{
+ double lratio;
+
+ if ( links.count() > pen->links.count() )
+ lratio = (links.count()+2) / (pen->links.count()+2);
+ else
+ lratio = (pen->links.count()+2) / (links.count()+2);
+
+ lratio -= 1.0;
+
+ if ( lratio > 2.0 ) {
+#ifdef DEBUG_QIMPEN
+ qDebug( "stroke length too different" );
+#endif
+ return 400000;
+ }
+
+ createSignatures();
+ pen->createSignatures();
+
+ // Starting point offset
+ int vdiff = QABS(startPoint.y() - pen->startPoint.y());
+
+ // Insanely offset?
+ if ( vdiff > 18 ) {
+ return 400000;
+ }
+
+ vdiff -= 4;
+ if ( vdiff < 0 )
+ vdiff = 0;
+
+ // Ending point offset
+ int evdiff = QABS(lastPoint.y() - pen->lastPoint.y());
+ // Insanely offset?
+ if ( evdiff > 20 ) {
+ return 400000;
+ }
+
+ evdiff -= 5;
+ if ( evdiff < 0 )
+ evdiff = 0;
+
+ // do a correlation with the three available signatures.
+ int err1 = INT_MAX;
+ int err2 = INT_MAX;
+ int err3 = INT_MAX;
+
+ // base has extra points at the start and end to enable
+ // correlation of a sliding window with the pen supplied.
+ QArray<int> base = createBase( tsig, 2 );
+ for ( int i = 0; i < 4; i++ ) {
+ int e = calcError( base, pen->tsig, i, TRUE );
+ if ( e < err1 )
+ err1 = e;
+ }
+ if ( err1 > 40 ) { // no need for more matching
+#ifdef DEBUG_QIMPEN
+ qDebug( "tsig too great: %d", err1 );
+#endif
+ return 400000;
+ }
+
+ // maybe a sliding window is worthwhile for these too.
+ err2 = calcError( dsig, pen->dsig, 0, FALSE );
+ if ( err2 > 100 ) {
+#ifdef DEBUG_QIMPEN
+ qDebug( "dsig too great: %d", err2 );
+#endif
+ return 400000;
+ }
+
+ err3 = calcError( asig, pen->asig, 0, TRUE );
+ if ( err3 > 60 ) {
+#ifdef DEBUG_QIMPEN
+ qDebug( "asig too great: %d", err3 );
+#endif
+ return 400000;
+ }
+
+ // Some magic numbers here - the addition reduces the weighting of
+ // the error and compensates for the different error scales. I
+ // consider the tangent signature to be the best indicator, so it
+ // has the most weight. This ain't rocket science.
+ // Basically, these numbers are the tuning factors.
+ unsigned int err = (err1+1) * ( err2 + 60 ) * ( err3 + 20 ) +
+ vdiff * 1000 + evdiff * 500 +
+ (unsigned int)(lratio * 5000.0);
+
+#ifdef DEBUG_QIMPEN
+ qDebug( "err %d ( %d, %d, %d, %d)", err, err1, err2, err3, vdiff );
+#endif
+
+ return err;
+}
+
+/*!
+ Return the bounding rect of this stroke.
+*/
+QRect QIMPenStroke::boundingRect()
+{
+ if ( !bounding.isValid() ) {
+ int x = startPoint.x();
+ int y = startPoint.y();
+ bounding = QRect( x, y, 1, 1 );
+
+ for ( unsigned i = 0; i < links.count(); i++ ) {
+ x += links[i].dx;
+ y += links[i].dy;
+ if ( x < bounding.left() )
+ bounding.setLeft( x );
+ if ( x > bounding.right() )
+ bounding.setRight( x );
+ if ( y < bounding.top() )
+ bounding.setTop( y );
+ if ( y > bounding.bottom() )
+ bounding.setBottom( y );
+ }
+ }
+
+ return bounding;
+}
+
+
+/*!
+ Perform a correlation of the supplied arrays. \a base should have
+ win.count() + 2 * off points to enable sliding \a win over the
+ \a base data. If \a t is TRUE, the comparison takes into account
+ the circular nature of the angular data.
+ Returns the best (lowest error) match.
+*/
+
+int QIMPenStroke::calcError( const QArray<int> &base,
+ const QArray<int> &win, int off, bool t )
+{
+ int err = 0;
+
+ for ( unsigned i = 0; i < win.count(); i++ ) {
+ int d = QABS( base[i+off] - win[i] );
+ if ( t && d > 128 )
+ d -= 256;
+ err += QABS( d );
+ }
+
+ err /= win.count();
+
+ return err;
+}
+
+/*!
+ Creates signatures used in matching if not already created.
+*/
+void QIMPenStroke::createSignatures()
+{
+ if ( tsig.isEmpty() )
+ createTanSignature();
+ if ( asig.isEmpty() )
+ createAngleSignature();
+ if ( dsig.isEmpty() )
+ createDistSignature();
+}
+
+/*!
+ Create a signature of the tangents to the user's stroke.
+*/
+void QIMPenStroke::createTanSignature()
+{
+ int dist = 5; // number of points to include in calculation
+ if ( (int)links.count() <= dist ) {
+ tsig.resize(1);
+ int dx = 0;
+ int dy = 0;
+ for ( unsigned j = 0; j < links.count(); j++ ) {
+ dx += links[j].dx;
+ dy += links[j].dy;
+ }
+ tsig[0] = arcTan( dy, dx );
+ } else {
+ tsig.resize( (links.count()-dist+1) / 2 );
+ int idx = 0;
+ for ( unsigned i = 0; i < links.count() - dist; i += 2 ) {
+ int dx = 0;
+ int dy = 0;
+ for ( int j = 0; j < dist; j++ ) {
+ dx += links[i+j].dx;
+ dy += links[i+j].dy;
+ }
+ tsig[idx++] = arcTan( dy, dx );
+ }
+ }
+
+ tsig = scale( tsig, QIMPEN_CORRELATION_POINTS, TRUE );
+// smooth(tsig);
+}
+
+/*!
+ Create a signature of the change in angle.
+*/
+void QIMPenStroke::createAngleSignature()
+{
+ QPoint c = calcCenter();
+
+ int dist = 3; // number of points to include in calculation
+ if ( (int)links.count() <= dist ) {
+ asig.resize(1);
+ asig[0] = 1;
+ } else {
+ asig.resize( links.count() );
+ QPoint current(0, 0);
+ int idx = 0;
+ for ( unsigned i = 0; i < links.count(); i++ ) {
+ int dx = c.x() - current.x();
+ int dy = c.y() - current.y();
+ int md = QMAX( QABS(dx), QABS(dy) );
+ if ( md > 5 ) {
+ dx = dx * 5 / md;
+ dy = dy * 5 / md;
+ }
+ asig[idx++] = arcTan( dy, dx );
+ current += QPoint( links[i].dx, links[i].dy );
+ }
+ }
+
+ asig = scale( asig, QIMPEN_CORRELATION_POINTS, TRUE );
+
+/*
+ if ( tsig.isEmpty() )
+ createTanSignature();
+
+ if ( tsig.count() < 5 ) {
+ asig.resize( 1 );
+ asig[0] = 0;
+ } else {
+ asig.resize( tsig.count() - 5 );
+
+ for ( unsigned i = 0; i < asig.count(); i++ ) {
+ asig[i] = QABS(tsig[i] - tsig[i+5]);
+ }
+ }
+*/
+}
+
+/*!
+ Create a signature of the distance from the char's center of gravity
+ to its points.
+*/
+void QIMPenStroke::createDistSignature()
+{
+ dsig.resize( (links.count()+1)/2 );
+ QPoint c = calcCenter();
+ QPoint pt( 0, 0 );
+
+ int minval = INT_MAX;
+ int maxval = 0;
+ int idx = 0;
+ for ( unsigned i = 0; i < links.count(); i += 2 ) {
+ int dx = c.x() - pt.x();
+ int dy = c.y() - pt.y();
+ if ( dx == 0 && dy == 0 )
+ dsig[idx] = 0;
+ else
+ dsig[idx] = dx*dx + dy*dy;
+
+ if ( dsig[idx] > maxval )
+ maxval = dsig[idx];
+ if ( dsig[idx] < minval )
+ minval = dsig[idx];
+ pt.rx() += links[i].dx;
+ pt.ry() += links[i].dy;
+ idx++;
+ }
+
+ // normalise 0-255
+ int div = maxval - minval;
+ if ( div == 0 ) div = 1;
+ for ( unsigned i = 0; i < dsig.count(); i++ ) {
+ dsig[i] = (dsig[i] - minval ) * 255 / div;
+ }
+
+ dsig = scale( dsig, QIMPEN_CORRELATION_POINTS );
+}
+
+
+/*!
+ Scale the points in a array to \a count points.
+ This is braindead at the moment (no smooth scaling) and fixing this is
+ probably one of the simpler ways to improve performance.
+*/
+QArray<int> QIMPenStroke::scale( const QArray<int> &s, unsigned count, bool t )
+{
+ QArray<int> d(count);
+
+ unsigned si = 0;
+ if ( s.count() > count ) {
+ unsigned next = 0;
+ for ( unsigned i = 0; i < count; i++ ) {
+ next = (i+1) * s.count() / count;
+ int maxval = 0;
+ if ( t ) {
+ for ( unsigned j = si; j < next; j++ ) {
+ maxval = s[j] > maxval ? s[j] : maxval;
+ }
+ }
+ int sum = 0;
+ for ( unsigned j = si; j < next; j++ ) {
+ if ( t && maxval - s[j] > 128 )
+ sum += 256;
+ sum += s[j];
+ }
+ d[i] = sum / (next-si);
+ if ( t && d[i] > 256 )
+ d[i] %= 256;
+ si = next;
+ }
+ } else {
+ for ( unsigned i = 0; i < count; i++ ) {
+ si = i * s.count() / count;
+ d[i] = s[si];
+ }
+ }
+
+ return d;
+}
+
+/*!
+ Add another point to the stroke's shape.
+*/
+void QIMPenStroke::internalAddPoint( QPoint p )
+{
+ if ( p == lastPoint )
+ return;
+
+ if ( !lastPoint.isNull() ) {
+ QIMPenGlyphLink gl;
+ gl.dx = p.x() - lastPoint.x();
+ gl.dy = p.y() - lastPoint.y();
+ links.resize( links.size() + 1 ); //### resize by 1 is bad
+ links[links.size() - 1] = gl;
+ }
+
+ lastPoint = p;
+ bounding = QRect();
+}
+
+/*!
+ Calculate the center of gravity of the stroke.
+*/
+QPoint QIMPenStroke::calcCenter()
+{
+ QPoint pt( 0, 0 );
+ int ax = 0;
+ int ay = 0;
+
+ for ( unsigned i = 0; i < links.count(); i++ ) {
+ pt.rx() += links[i].dx;
+ pt.ry() += links[i].dy;
+ ax += pt.x();
+ ay += pt.y();
+ }
+
+ ax /= (int)links.count();
+ ay /= (int)links.count();
+
+ return QPoint( ax, ay );
+}
+
+/*!
+ Calculate the arctan of the lengths supplied.
+ The angle returned is in the range 0-255.
+ \a dy and \a dx MUST be in the range 0-5 - I dont even check :-P
+*/
+int QIMPenStroke::arcTan( int dy, int dx )
+{
+ if ( dx == 0 ) {
+ if ( dy >= 0 )
+ return 64;
+ else
+ return 192;
+ }
+
+ if ( dy == 0 ) {
+ if ( dx >= 0 )
+ return 0;
+ else
+ return 128;
+ }
+
+ static int table[5][5] = {
+ { 32, 19, 13, 10, 8 },
+ { 45, 32, 24, 19, 16 },
+ { 51, 40, 32, 26, 22 },
+ { 54, 45, 37, 32, 27 },
+ { 56, 49, 42, 37, 32 } };
+
+ if ( dy > 0 ) {
+ if ( dx > 0 )
+ return table[dy-1][dx-1];
+ else
+ return 128 - table[dy-1][QABS(dx)-1];
+ } else {
+ if ( dx > 0 )
+ return 256 - table[QABS(dy)-1][dx-1];
+ else
+ return 128 + table[QABS(dy)-1][QABS(dx)-1];
+ }
+
+ return 0;
+}
+
+
+/*!
+ Silly name. Create an array that has \a e points extra at the start and
+ end to enable a sliding correlation to be performed.
+*/
+QArray<int> QIMPenStroke::createBase( const QArray<int> a, int e )
+{
+ QArray<int> ra( a.count() + 2*e );
+
+ for ( int i = 0; i < e; i++ ) {
+ ra[i] = a[e - i - 1];
+ ra[a.count() + i] = a[a.count() - i - 1];
+ }
+ for ( unsigned i = 0; i < a.count(); i++ ) {
+ ra[i+e] = a[i];
+ }
+
+ return ra;
+}
+
+
+/*!
+ Smooth the points in an array. Probably a bad idea.
+*/
+void QIMPenStroke::smooth( QArray<int> &sig)
+{
+ QArray<int> nsig = sig.copy();
+
+ int a;
+ for ( unsigned i = 1; i < sig.count()-2; i++ ) {
+ a = 0;
+ for ( int j = -1; j <= 1; j++ ) {
+ a += sig[ i + j ];
+ }
+ nsig[i] = a / 3;
+ }
+
+ sig = nsig;
+}
+
+/*!
+ Write the character's data to the stream.
+*/
+QDataStream &operator<< (QDataStream &s, const QIMPenStroke &ws)
+{
+ s << ws.startPoint;
+ s << ws.links.count();
+ for ( unsigned i = 0; i < ws.links.count(); i++ ) {
+ s << (Q_INT8)ws.links[i].dx;
+ s << (Q_INT8)ws.links[i].dy;
+ }
+
+ return s;
+}
+
+/*!
+ Read the character's data from the stream.
+*/
+QDataStream &operator>> (QDataStream &s, QIMPenStroke &ws)
+{
+ Q_INT8 i8;
+ s >> ws.startPoint;
+ ws.lastPoint = ws.startPoint;
+ unsigned size;
+ s >> size;
+ ws.links.resize( size );
+ for ( unsigned i = 0; i < size; i++ ) {
+ s >> i8;
+ ws.links[i].dx = i8;
+ s >> i8;
+ ws.links[i].dy = i8;
+ ws.lastPoint += QPoint( ws.links[i].dx, ws.links[i].dy );
+ }
+
+ return s;
+}
+
+
diff --git a/inputmethods/handwriting/qimpenstroke.h b/inputmethods/handwriting/qimpenstroke.h
new file mode 100644
index 0000000..bd5ee0e
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenstroke.h
@@ -0,0 +1,91 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef QIMPENSTROKE_H_
+#define QIMPENSTROKE_H_
+
+#include <qobject.h>
+#include <qarray.h>
+#include <qlist.h>
+
+struct Q_PACKED QIMPenGlyphLink
+{
+ signed char dx;
+ signed char dy;
+};
+
+class QIMPenStroke
+{
+public:
+ QIMPenStroke();
+ QIMPenStroke( const QIMPenStroke & );
+
+ void clear();
+ bool isEmpty() const { return links.isEmpty(); }
+ unsigned int length() const { return links.count(); }
+ unsigned int match( QIMPenStroke *st );
+ const QArray<QIMPenGlyphLink> &chain() const { return links; }
+ QPoint startingPoint() const { return startPoint; }
+ void setStartingPoint( const QPoint &p ) { startPoint = p; }
+ QRect boundingRect();
+
+ QIMPenStroke &operator=( const QIMPenStroke &s );
+
+ void beginInput( QPoint p );
+ bool addPoint( QPoint p );
+ void endInput();
+
+ QArray<int> sig() { createTanSignature(); return tsig; } // for debugging
+
+protected:
+ void createSignatures();
+ void createTanSignature();
+ void createAngleSignature();
+ void createDistSignature();
+ int calcError( const QArray<int> &base, const QArray<int> &win,
+ int off, bool t );
+ QArray<int> scale( const QArray<int> &s, unsigned count, bool t = FALSE );
+ void internalAddPoint( QPoint p );
+ QPoint calcCenter();
+ int arcTan( int dy, int dx );
+ QArray<int> createBase( const QArray<int> a, int e );
+ void smooth( QArray<int> &);
+
+protected:
+ QPoint startPoint;
+ QPoint lastPoint;
+ QArray<QIMPenGlyphLink> links;
+ QArray<int> tsig;
+ QArray<int> asig;
+ QArray<int> dsig;
+ QRect bounding;
+
+ friend QDataStream &operator<< (QDataStream &, const QIMPenStroke &);
+ friend QDataStream &operator>> (QDataStream &, QIMPenStroke &);
+};
+
+typedef QList<QIMPenStroke> QIMPenStrokeList;
+typedef QListIterator<QIMPenStroke> QIMPenStrokeIterator;
+
+QDataStream & operator<< (QDataStream & s, const QIMPenStroke &ws);
+QDataStream & operator>> (QDataStream & s, const QIMPenStroke &ws);
+
+#endif
+
diff --git a/inputmethods/handwriting/qimpenwidget.cpp b/inputmethods/handwriting/qimpenwidget.cpp
new file mode 100644
index 0000000..8f8f582
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenwidget.cpp
@@ -0,0 +1,446 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include <qapplication.h>
+#include <qinputdialog.h>
+#include <qpainter.h>
+#include <qfile.h>
+#include <qdatastream.h>
+#include <qtimer.h>
+#include "qimpenchar.h"
+#include "qimpenwidget.h"
+
+#define TITLE_WIDTH 30 // ### magic
+
+/*!
+ \class QIMPenWidget qimpenwidget.h
+
+ Draws characters and allows input of characters.
+*/
+
+QIMPenWidget::QIMPenWidget( QWidget *parent )
+ : QWidget( parent )
+{
+ charSets.setAutoDelete( TRUE );
+ inputStroke = 0;
+ outputChar = 0;
+ outputStroke = 0;
+ mode = Waiting;
+ currCharSet = 0;
+ readOnly = FALSE;
+ strokes.setAutoDelete( TRUE );
+
+ timer = new QTimer(this);
+ connect( timer, SIGNAL(timeout()), SLOT(timeout()));
+
+ setBackgroundColor( qApp->palette().color( QPalette::Active,
+ QColorGroup::Base ) );
+ strokeColor = black;
+ setFixedHeight( 75 );
+}
+
+void QIMPenWidget::clear()
+{
+ timer->stop();
+ mode = Waiting;
+ QRect r( dirtyRect );
+ QIMPenStrokeIterator it( strokes );
+ while ( it.current() ) {
+ r |= it.current()->boundingRect();
+ ++it;
+ }
+ outputChar = 0;
+ outputStroke = 0;
+ strokes.clear();
+ if ( !r.isNull() ) {
+ r.moveBy( -2, -2 );
+ r.setSize( r.size() + QSize( 4, 4 ) );
+ repaint( r );
+ } else {
+ repaint();
+ }
+}
+
+void QIMPenWidget::removeStroke()
+{
+ QRect r( dirtyRect );
+ QIMPenStroke *st = strokes.getFirst();
+ QRect strokeRect;
+ if ( st )
+ strokeRect = st->boundingRect();
+ r |= strokeRect;
+ strokes.removeFirst();
+ if ( !r.isNull() ) {
+ r.moveBy( -2, -2 );
+ r.setSize( r.size() + QSize( 4, 4 ) );
+ repaint( r );
+ }
+}
+
+void QIMPenWidget::greyStroke()
+{
+ QRect r( dirtyRect );
+ QIMPenStroke *st = strokes.getLast();
+ QRect strokeRect;
+ if ( st )
+ strokeRect = st->boundingRect();
+ r |= strokeRect;
+ QColor oldCol = strokeColor;
+ strokeColor = gray;
+ if ( !r.isNull() ) {
+ r.moveBy( -2, -2 );
+ r.setSize( r.size() + QSize( 4, 4 ) );
+ repaint( r );
+ }
+ strokeColor = oldCol;
+}
+
+/*!
+ Insert a character set into the list.
+*/
+void QIMPenWidget::insertCharSet( QIMPenCharSet *cs, int stretch, int pos )
+{
+ CharSetEntry *e = new CharSetEntry;
+ e->cs = cs;
+ e->stretch = stretch;
+ if ( pos < 0 )
+ pos = charSets.count();
+ charSets.insert( pos, e );
+ currCharSet = 0;
+ emit changeCharSet( currCharSet );
+ emit changeCharSet( charSets.at(currCharSet)->cs );
+ totalStretch = 0;
+ CharSetEntryIterator it( charSets );
+ for ( ; it.current(); ++it )
+ totalStretch += it.current()->stretch;
+ update();
+}
+
+/*!
+ Remove a character set from the list.
+*/
+void QIMPenWidget::removeCharSet( int pos )
+{
+ if ( pos >= 0 && pos < (int)charSets.count() ) {
+ charSets.remove( pos );
+ currCharSet = 0;
+ if ( charSets.count() ) {
+ emit changeCharSet( currCharSet );
+ emit changeCharSet( charSets.at(currCharSet)->cs );
+ }
+ totalStretch = 0;
+ CharSetEntryIterator it( charSets );
+ for ( ; it.current(); ++it )
+ totalStretch += it.current()->stretch;
+ update();
+ }
+}
+
+void QIMPenWidget::changeCharSet( QIMPenCharSet *cs, int pos )
+{
+ if ( pos >= 0 && pos < (int)charSets.count() ) {
+ CharSetEntry *e = new CharSetEntry;
+ e->cs = cs;
+ e->stretch = charSets.at(pos)->stretch;
+ charSets.remove( pos );
+ charSets.insert( pos, e );
+ if ( pos == currCharSet ) {
+ emit changeCharSet( charSets.at(currCharSet)->cs );
+ }
+ update();
+ }
+}
+
+void QIMPenWidget::clearCharSets()
+{
+ charSets.clear();
+ currCharSet = 0;
+ update();
+}
+
+/*!
+ Display a character. \a speed determines how quickly the character is
+ drawn.
+*/
+void QIMPenWidget::showCharacter( QIMPenChar *ch, int speed )
+{
+ outputChar = 0;
+ outputStroke = 0;
+ strokes.clear();
+ mode = Output;
+ repaint();
+ if ( !ch || ch->isEmpty() ) {
+ mode = Waiting;
+ return;
+ }
+
+ outputChar = ch;
+ outputStroke = outputChar->penStrokes().getFirst();
+ if ( speed < 0 ) speed = 0;
+ if ( speed > 20 ) speed = 20;
+ speed = 50 - speed;
+ pointIndex = 0;
+ strokeIndex = 0;
+ lastPoint = outputStroke->startingPoint();
+ QRect br( outputChar->boundingRect() );
+ lastPoint.setX( (width() - br.width()) / 2 + (lastPoint.x () - br.left()) );
+ QPoint offset = lastPoint - outputStroke->startingPoint();
+ br.moveBy( offset.x(), offset.y() );
+ dirtyRect |= br;
+ timer->start( speed );
+}
+
+/*!
+ Handle drawing/clearing of characters.
+*/
+void QIMPenWidget::timeout()
+{
+ if ( mode == Output ) {
+ const QArray<QIMPenGlyphLink> &chain = outputStroke->chain();
+ if ( pointIndex < chain.count() ) {
+ QPainter paint( this );
+ paint.setBrush( Qt::black );
+ for ( unsigned i = 0; i < 3 && pointIndex < chain.count(); i++ ) {
+ lastPoint.rx() += chain[pointIndex].dx;
+ lastPoint.ry() += chain[pointIndex].dy;
+ pointIndex++;
+ paint.drawRect( lastPoint.x()-1, lastPoint.y()-1, 2, 2 );
+ }
+ }
+ if ( pointIndex >= chain.count() ) {
+ QIMPenStrokeList strokes = outputChar->penStrokes();
+ if ( strokeIndex < (int)strokes.count() - 1 ) {
+ pointIndex = 0;
+ strokeIndex++;
+ outputStroke = strokes.at( strokeIndex );
+ lastPoint = outputChar->startingPoint();
+ QRect br( outputChar->boundingRect() );
+ lastPoint.setX( (width() - br.width()) / 2
+ + (lastPoint.x () - br.left()) );
+ QPoint off = lastPoint - outputChar->startingPoint();
+ lastPoint = outputStroke->startingPoint() + off;
+ } else {
+ timer->stop();
+ mode = Waiting;
+ }
+ }
+ } else if ( mode == Waiting ) {
+ QRect r( dirtyRect );
+ if ( !r.isNull() ) {
+ r.moveBy( -2, -2 );
+ r.setSize( r.size() + QSize( 4, 4 ) );
+ repaint( r );
+ }
+ }
+}
+
+/*!
+ If the point \a p is over one of the character set titles, switch
+ to the set and return TRUE.
+*/
+bool QIMPenWidget::selectSet( QPoint p )
+{
+ if ( charSets.count() ) {
+ CharSetEntryIterator it( charSets );
+ int spos = 0;
+ int idx = 0;
+ for ( ; it.current(); ++it, idx++ ) {
+ int setWidth = width() * it.current()->stretch / totalStretch;
+ spos += setWidth;
+ if ( p.x() < spos ) {
+ if ( idx != currCharSet ) {
+ currCharSet = idx;
+ update( 0, 0, width(), 12 );
+ emit changeCharSet( currCharSet );
+ emit changeCharSet( charSets.at(currCharSet)->cs );
+ }
+ break;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/*!
+ Hopefully returns a sensible size.
+*/
+QSize QIMPenWidget::sizeHint()
+{
+ return QSize( TITLE_WIDTH * charSets.count(), 75 );
+}
+
+void QIMPenWidget::mousePressEvent( QMouseEvent *e )
+{
+ if ( !readOnly && e->button() == LeftButton && mode == Waiting ) {
+ // if selectSet returns false the click was not over the
+ // char set selectors.
+ if ( !selectSet( e->pos() ) ) {
+ // start of character input
+ timer->stop();
+ if ( outputChar ) {
+ outputChar = 0;
+ outputStroke = 0;
+ repaint();
+ }
+ mode = Input;
+ lastPoint = e->pos();
+ emit beginStroke();
+ inputStroke = new QIMPenStroke;
+ strokes.append( inputStroke );
+ inputStroke->beginInput( e->pos() );
+ QPainter paint( this );
+ paint.setBrush( Qt::black );
+ paint.drawRect( lastPoint.x()-1, lastPoint.y()-1, 2, 2 );
+ }
+ }
+}
+
+void QIMPenWidget::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( !readOnly && e->button() == LeftButton && mode == Input ) {
+ mode = Waiting;
+ inputStroke->endInput();
+ if ( charSets.count() )
+ emit stroke( inputStroke );
+ inputStroke = 0;
+ }
+}
+
+void QIMPenWidget::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( !readOnly && mode == Input ) {
+ int dx = QABS( e->pos().x() - lastPoint.x() );
+ int dy = QABS( e->pos().y() - lastPoint.y() );
+ if ( dx + dy > 1 ) {
+ if ( inputStroke->addPoint( e->pos() ) ) {
+ QPainter paint( this );
+ paint.setPen( Qt::black );
+ paint.setBrush( Qt::black );
+ const QArray<QIMPenGlyphLink> &chain = inputStroke->chain();
+ QPoint p( e->pos() );
+ for ( int i = (int)chain.count()-1; i >= 0; i-- ) {
+ paint.drawRect( p.x()-1, p.y()-1, 2, 2 );
+ p.rx() -= chain[i].dx;
+ p.ry() -= chain[i].dy;
+ if ( p == lastPoint )
+ break;
+ }
+
+ /* ### use this when thick lines work properly on all devices
+ paint.setPen( QPen( Qt::black, 2 ) );
+ paint.drawLine( lastPoint, e->pos() );
+ */
+ }
+ lastPoint = e->pos();
+ }
+ }
+}
+
+void QIMPenWidget::paintEvent( QPaintEvent * )
+{
+ QPainter paint( this );
+
+ // draw guidelines
+ paint.setPen( Qt::gray );
+ paint.drawLine( 0, 0, width(), 0 );
+ int y = height() / 3;
+ paint.drawLine( 0, y, width(), y );
+ y *= 2;
+ paint.setPen( blue );
+ paint.drawLine( 0, y, width(), y );
+ paint.setPen( Qt::gray );
+
+ if ( !charSets.count() )
+ return;
+
+ // draw the character set titles
+ QFont selFont( "helvetica", 8, QFont::Bold );
+ QFont font( "helvetica", 8 );
+ CharSetEntryIterator it( charSets );
+ int spos = 0;
+ for ( ; it.current(); ++it ) {
+ int setWidth = width() * it.current()->stretch / totalStretch;
+ spos += setWidth;
+ if ( it.current() != charSets.getLast() ) {
+ paint.drawLine( spos, 0, spos, 5 );
+ paint.drawLine( spos, height()-1, spos, height()-6 );
+ }
+ paint.setFont( font );
+ int w = paint.fontMetrics().width( it.current()->cs->title() );
+ int tpos = spos - setWidth / 2;
+ paint.drawText( tpos - w/2, 0, w, 12, QPainter::AlignCenter,
+ it.current()->cs->title() );
+ }
+
+ // draw any character that should be displayed when repainted.
+ QPoint off;
+ const QIMPenStrokeList *stk = 0;
+ if ( outputChar && mode == Waiting ) {
+ stk = &outputChar->penStrokes();
+ QPoint p( outputChar->startingPoint() );
+ QRect br( outputChar->boundingRect() );
+ p.setX( (width() - br.width()) / 2 + (p.x () - br.left()) );
+ off = p - outputChar->startingPoint();
+ } else if ( mode == Waiting ) {
+ stk = &strokes;
+ strokeColor = gray;
+ }
+
+ if ( stk && !stk->isEmpty() ) {
+ paint.setPen( strokeColor );
+ paint.setBrush( strokeColor );
+ QIMPenStrokeIterator it( *stk );
+ while ( it.current() ) {
+ QPoint p = it.current()->startingPoint() + off;
+ paint.drawRect( p.x()-1, p.y()-1, 2, 2 );
+ const QArray<QIMPenGlyphLink> &chain = it.current()->chain();
+ for ( unsigned i = 0; i < chain.count(); i++ ) {
+ p.rx() += chain[i].dx;
+ p.ry() += chain[i].dy;
+ paint.drawRect( p.x()-1, p.y()-1, 2, 2 );
+ }
+ ++it;
+ if ( it.atLast() && mode == Waiting )
+ strokeColor = black;
+ }
+ }
+
+ dirtyRect = QRect();
+
+ // debug
+/*
+ if ( input ) {
+ QArray<int> sig = input->sig();
+ for ( unsigned i = 0; i < sig.count(); i++ ) {
+ paint.drawPoint( 200 + i, height()/2 - sig[i] / 8 );
+ }
+ }
+*/
+}
+
+void QIMPenWidget::resizeEvent( QResizeEvent *e )
+{
+ if ( mode == Output )
+ showCharacter( outputChar, 0 );
+
+ QWidget::resizeEvent( e );
+}
+
diff --git a/inputmethods/handwriting/qimpenwidget.h b/inputmethods/handwriting/qimpenwidget.h
new file mode 100644
index 0000000..98d7f5c
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenwidget.h
@@ -0,0 +1,88 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include <qwidget.h>
+#include <qlist.h>
+#include "qimpenchar.h"
+
+class QIMPenWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ QIMPenWidget( QWidget *parent );
+
+ void clear();
+ void greyStroke();
+ void setReadOnly( bool r ) { readOnly = r; }
+
+ void insertCharSet( QIMPenCharSet *cs, int stretch=1, int pos=-1 );
+ void removeCharSet( int );
+ void changeCharSet( QIMPenCharSet *cs, int pos );
+ void clearCharSets();
+ void showCharacter( QIMPenChar *, int speed = 10 );
+ virtual QSize sizeHint();
+
+public slots:
+ void removeStroke();
+
+signals:
+ void changeCharSet( QIMPenCharSet *cs );
+ void changeCharSet( int );
+ void beginStroke();
+ void stroke( QIMPenStroke *ch );
+
+protected slots:
+ void timeout();
+
+protected:
+ enum Mode { Waiting, Input, Output };
+ bool selectSet( QPoint );
+ virtual void mousePressEvent( QMouseEvent *e );
+ virtual void mouseReleaseEvent( QMouseEvent *e );
+ virtual void mouseMoveEvent( QMouseEvent *e );
+ virtual void paintEvent( QPaintEvent *e );
+ virtual void resizeEvent( QResizeEvent *e );
+
+ struct CharSetEntry {
+ QIMPenCharSet *cs;
+ int stretch;
+ };
+ typedef QList<CharSetEntry> CharSetEntryList;
+ typedef QListIterator<CharSetEntry> CharSetEntryIterator;
+
+protected:
+ Mode mode;
+ bool autoHide;
+ bool readOnly;
+ QPoint lastPoint;
+ unsigned pointIndex;
+ int strokeIndex;
+ int currCharSet;
+ QTimer *timer;
+ QColor strokeColor;
+ QRect dirtyRect;
+ QIMPenChar *outputChar;
+ QIMPenStroke *outputStroke;
+ QIMPenStroke *inputStroke;
+ QIMPenStrokeList strokes;
+ CharSetEntryList charSets;
+ int totalStretch;
+};
+
diff --git a/inputmethods/handwriting/qimpenwordpick.cpp b/inputmethods/handwriting/qimpenwordpick.cpp
new file mode 100644
index 0000000..8ee103d
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenwordpick.cpp
@@ -0,0 +1,113 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include <qpainter.h>
+#include "qimpenwordpick.h"
+
+QIMPenWordPick::QIMPenWordPick( QWidget *parent, const char *name, WFlags f )
+ : QFrame( parent, name, f )
+{
+ clickWord = -1;
+ setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
+}
+
+void QIMPenWordPick::clear()
+{
+ words.clear();
+ repaint();
+}
+
+QSize QIMPenWordPick::sizeHint() const
+{
+ return QSize( -1, font().pixelSize()+2 );
+}
+
+void QIMPenWordPick::setWords( const QIMPenMatch::MatchWordList &w )
+{
+ words.clear();
+ QListIterator<QIMPenMatch::MatchWord> it( w );
+ for ( ; it.current(); ++it ) {
+ words.append( it.current()->word );
+ }
+ repaint();
+}
+
+int QIMPenWordPick::onWord( QPoint p )
+{
+ int x = 2;
+ int idx = 0;
+ for ( QStringList::Iterator it = words.begin(); it != words.end(); ++it ) {
+ QString word = *it;
+ int w = fontMetrics().width( word );
+ if ( x + w > width() )
+ break;
+ if ( p.x() > x-2 && p.x() < x + w + 2 )
+ return idx;
+ x += w + 5;
+ if ( !idx )
+ x += 3;
+ idx++;
+ }
+
+ return -1;
+}
+
+void QIMPenWordPick::paintEvent( QPaintEvent * )
+{
+ QPainter p(this);
+ int x = 2;
+ int h = p.fontMetrics().ascent() + 1;
+ int idx = 0;
+ for ( QStringList::Iterator it = words.begin(); it != words.end(); ++it ) {
+ QString word = *it;
+ int w = p.fontMetrics().width( word );
+ if ( x + w > width() )
+ break;
+ if ( idx == clickWord ) {
+ p.fillRect( x, 0, w, height(), black );
+ p.setPen( white );
+ } else {
+ p.setPen( colorGroup().text() );
+ }
+ p.drawText( x, h, word );
+ x += w + 5;
+ if ( !idx )
+ x += 3;
+ idx++;
+ }
+}
+
+void QIMPenWordPick::mousePressEvent( QMouseEvent *e )
+{
+ clickWord = onWord( e->pos() );
+ repaint();
+}
+
+void QIMPenWordPick::mouseReleaseEvent( QMouseEvent *e )
+{
+ int wordIdx = onWord( e->pos() );
+ if ( wordIdx >= 0 && wordIdx == clickWord ) {
+ //qDebug( "Clicked %s", words[wordIdx].latin1() );
+ emit wordClicked( words[wordIdx] );
+ }
+ clickWord = -1;
+ repaint();
+}
+
diff --git a/inputmethods/handwriting/qimpenwordpick.h b/inputmethods/handwriting/qimpenwordpick.h
new file mode 100644
index 0000000..376288e
--- a/dev/null
+++ b/inputmethods/handwriting/qimpenwordpick.h
@@ -0,0 +1,49 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include <qframe.h>
+#include "qimpenmatch.h"
+
+class QIMPenWordPick : public QFrame
+{
+ Q_OBJECT
+public:
+ QIMPenWordPick( QWidget *parent = 0, const char *name = 0, WFlags f = 0 );
+
+ void clear();
+ virtual QSize sizeHint() const;
+
+public slots:
+ void setWords( const QIMPenMatch::MatchWordList &w );
+
+signals:
+ void wordClicked( const QString & );
+
+protected:
+ int onWord( QPoint p );
+ virtual void paintEvent( QPaintEvent * );
+ virtual void mousePressEvent( QMouseEvent * );
+ virtual void mouseReleaseEvent( QMouseEvent * );
+
+private:
+ QStringList words;
+ int clickWord;
+};
+
diff --git a/inputmethods/handwriting/qpe-handwriting.control b/inputmethods/handwriting/qpe-handwriting.control
new file mode 100644
index 0000000..f1648c6
--- a/dev/null
+++ b/inputmethods/handwriting/qpe-handwriting.control
@@ -0,0 +1,9 @@
+Files: plugins/inputmethods/libqhandwriting.so*
+Priority: optional
+Section: qpe/inputmethods
+Maintainer: Martin Jones <mjones@trolltech.com>
+Architecture: arm
+Version: $QPE_VERSION-3
+Depends: qpe-base ($QPE_VERSION)
+Description: Handwriting input method
+ Handwriting recognition input method for the Qtopia environment.
diff --git a/inputmethods/handwriting/qpe-handwriting.postinst b/inputmethods/handwriting/qpe-handwriting.postinst
new file mode 100755
index 0000000..c254b01
--- a/dev/null
+++ b/inputmethods/handwriting/qpe-handwriting.postinst
@@ -0,0 +1,2 @@
+#!/bin/sh
+/opt/QtPalmtop/bin/qcop QPE/TaskBar "reloadInputMethods()"
diff --git a/inputmethods/handwriting/qpe-handwriting.postrm b/inputmethods/handwriting/qpe-handwriting.postrm
new file mode 100755
index 0000000..c254b01
--- a/dev/null
+++ b/inputmethods/handwriting/qpe-handwriting.postrm
@@ -0,0 +1,2 @@
+#!/bin/sh
+/opt/QtPalmtop/bin/qcop QPE/TaskBar "reloadInputMethods()"
diff --git a/inputmethods/keyboard/.cvsignore b/inputmethods/keyboard/.cvsignore
new file mode 100644
index 0000000..edfa921
--- a/dev/null
+++ b/inputmethods/keyboard/.cvsignore
@@ -0,0 +1,3 @@
+moc_*
+*.moc
+Makefile
diff --git a/inputmethods/keyboard/Makefile.in b/inputmethods/keyboard/Makefile.in
new file mode 100644
index 0000000..3631807
--- a/dev/null
+++ b/inputmethods/keyboard/Makefile.in
@@ -0,0 +1,151 @@
+#############################################################################
+
+####### Compiler, tools and options
+
+CXX = $(SYSCONF_CXX) $(QT_CXX_MT)
+CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) $(SYSCONF_CXXFLAGS_LIB)
+CC = $(SYSCONF_CC) $(QT_C_MT)
+CFLAGS = $(SYSCONF_CFLAGS) $(SYSCONF_CFLAGS_LIB)
+INCPATH = -I$(QPEDIR)/include
+LFLAGS = $(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT)
+LIBS = $(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS_QTAPP)
+MOC = $(SYSCONF_MOC)
+UIC = $(SYSCONF_UIC)
+
+####### Target
+
+DESTDIR = ../../plugins/inputmethods/
+VER_MAJ = 1
+VER_MIN = 0
+VER_PATCH = 0
+TARGET = qkeyboard
+TARGET1 = lib$(TARGET).so.$(VER_MAJ)
+
+####### Files
+
+HEADERS = keyboard.h \
+ ../pickboard/pickboardcfg.h \
+ ../pickboard/pickboardpicks.h \
+ keyboardimpl.h
+SOURCES = keyboard.cpp \
+ ../pickboard/pickboardcfg.cpp \
+ ../pickboard/pickboardpicks.cpp \
+ keyboardimpl.cpp
+OBJECTS = keyboard.o \
+ ../pickboard/pickboardcfg.o \
+ ../pickboard/pickboardpicks.o \
+ keyboardimpl.o
+INTERFACES =
+UICDECLS =
+UICIMPLS =
+SRCMOC = moc_keyboard.cpp \
+ ../pickboard/moc_pickboardcfg.cpp \
+ ../pickboard/moc_pickboardpicks.cpp
+OBJMOC = moc_keyboard.o \
+ ../pickboard/moc_pickboardcfg.o \
+ ../pickboard/moc_pickboardpicks.o
+
+
+####### Implicit rules
+
+.SUFFIXES: .cpp .cxx .cc .C .c
+
+.cpp.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.cxx.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.cc.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.C.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
+
+####### Build rules
+
+
+all: $(DESTDIR)$(SYSCONF_LINK_TARGET)
+
+$(DESTDIR)$(SYSCONF_LINK_TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS)
+ $(SYSCONF_LINK_LIB)
+
+moc: $(SRCMOC)
+
+tmake:
+ tmake keyboard.pro
+
+clean:
+ -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS)
+ -rm -f *~ core
+ -rm -f allmoc.cpp
+
+####### Extension Modules
+
+listpromodules:
+ @echo
+
+listallmodules:
+ @echo
+
+listaddonpromodules:
+ @echo
+
+listaddonentmodules:
+ @echo
+
+
+REQUIRES=
+
+####### Sub-libraries
+
+
+###### Combined headers
+
+
+
+####### Compile
+
+keyboard.o: keyboard.cpp \
+ keyboard.h \
+ ../pickboard/pickboardcfg.h \
+ ../pickboard/pickboardpicks.h
+
+../pickboard/pickboardcfg.o: ../pickboard/pickboardcfg.cpp \
+ ../pickboard/pickboardcfg.h \
+ ../pickboard/pickboardpicks.h
+
+../pickboard/pickboardpicks.o: ../pickboard/pickboardpicks.cpp \
+ ../pickboard/pickboardpicks.h \
+ ../pickboard/pickboardcfg.h
+
+keyboardimpl.o: keyboardimpl.cpp \
+ keyboard.h \
+ ../pickboard/pickboardcfg.h \
+ ../pickboard/pickboardpicks.h \
+ keyboardimpl.h
+
+moc_keyboard.o: moc_keyboard.cpp \
+ keyboard.h \
+ ../pickboard/pickboardcfg.h \
+ ../pickboard/pickboardpicks.h
+
+../pickboard/moc_pickboardcfg.o: ../pickboard/moc_pickboardcfg.cpp \
+ ../pickboard/pickboardcfg.h
+
+../pickboard/moc_pickboardpicks.o: ../pickboard/moc_pickboardpicks.cpp \
+ ../pickboard/pickboardpicks.h
+
+moc_keyboard.cpp: keyboard.h
+ $(MOC) keyboard.h -o moc_keyboard.cpp
+
+../pickboard/moc_pickboardcfg.cpp: ../pickboard/pickboardcfg.h
+ $(MOC) ../pickboard/pickboardcfg.h -o ../pickboard/moc_pickboardcfg.cpp
+
+../pickboard/moc_pickboardpicks.cpp: ../pickboard/pickboardpicks.h
+ $(MOC) ../pickboard/pickboardpicks.h -o ../pickboard/moc_pickboardpicks.cpp
+
+
diff --git a/inputmethods/keyboard/keyboard.cpp b/inputmethods/keyboard/keyboard.cpp
new file mode 100644
index 0000000..9dd24e4
--- a/dev/null
+++ b/inputmethods/keyboard/keyboard.cpp
@@ -0,0 +1,794 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include "keyboard.h"
+
+#include <qpe/global.h>
+
+#include <qwindowsystem_qws.h>
+#include <qpainter.h>
+#include <qfontmetrics.h>
+#include <qtimer.h>
+#include <ctype.h>
+
+
+#define USE_SMALL_BACKSPACE
+
+Keyboard::Keyboard(QWidget* parent, const char* name, WFlags f) :
+ QFrame(parent, name, f), shift(FALSE), lock(FALSE), ctrl(FALSE),
+ alt(FALSE), useLargeKeys(TRUE), useOptiKeys(0), pressedKey(-1),
+ unicode(-1), qkeycode(0), modifiers(0)
+{
+ // setPalette(QPalette(QColor(240,240,230))); // Beige!
+ // setFont( QFont( "Helvetica", 8 ) );
+// setPalette(QPalette(QColor(200,200,200))); // Gray
+ setPalette(QPalette(QColor(220,220,220))); // Gray
+
+ picks = new KeyboardPicks( this );
+ picks->setFont( QFont( "smallsmooth", 9 ) );
+ setFont( QFont( "smallsmooth", 9 ) );
+ picks->initialise();
+ QObject::connect( picks, SIGNAL(key(ushort,ushort,ushort,bool,bool) ),
+ this, SIGNAL(key(ushort,ushort,ushort,bool,bool)) );
+
+ repeatTimer = new QTimer( this );
+ connect( repeatTimer, SIGNAL(timeout()), this, SLOT(repeat()) );
+}
+
+void Keyboard::resizeEvent(QResizeEvent*)
+{
+ int ph = picks->sizeHint().height();
+ picks->setGeometry( 0, 0, width(), ph );
+ keyHeight = (height()-ph)/5;
+ int nk;
+ if ( useOptiKeys ) {
+ nk = 15;
+ } else if ( useLargeKeys ) {
+ nk = 15;
+ } else {
+ nk = 19;
+ }
+ defaultKeyWidth = width()/nk;
+ xoffs = (width()-defaultKeyWidth*nk)/2;
+}
+
+void KeyboardPicks::initialise()
+{
+ setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed));
+ mode = 0;
+ dc = new KeyboardConfig(this);
+ configs.append(dc);
+}
+
+QSize KeyboardPicks::sizeHint() const
+{
+ return QSize(240,fontMetrics().lineSpacing());
+}
+
+
+void KeyboardConfig::generateText(const QString &s)
+{
+#if defined(Q_WS_QWS) || defined(_WS_QWS_)
+ for (int i=0; i<(int)backspaces; i++) {
+ parent->emitKey( 0, Qt::Key_Backspace, 0, true, false );
+ parent->emitKey( 0, Qt::Key_Backspace, 0, false, false );
+ }
+ for (int i=0; i<(int)s.length(); i++) {
+ parent->emitKey( s[i].unicode(), 0, 0, true, false );
+ parent->emitKey( s[i].unicode(), 0, 0, false, false );
+ }
+ parent->emitKey( 0, Qt::Key_Space, 0, true, false );
+ parent->emitKey( 0, Qt::Key_Space, 0, false, false );
+ backspaces = 0;
+#endif
+}
+
+
+//PC keyboard layout and scancodes
+
+/*
+ Format: length, code, length, code, ..., 0
+
+ length is measured in half the width of a standard key.
+ If code < 0x80 we have length/2 consecutive standard keys,
+ starting with scancode code.
+
+ Special keys are hardcoded, one at a time, with length of key
+ and code >= 0x80, these are NOT standard PC scancodes, but are looked
+ up in specialM[]. (The special keys are not keymappable.)
+
+ */
+
+static const uchar * const keyboard_opti[5] = {
+ (const uchar *const) "\001\223\003\240\002\20\002\41\002\26\002\62\002\56\002\45\002\54\003\200\001\223\002\226\002\235\002\234\002\236",
+ (const uchar *const) "\001\223\003\201\004\207\002\30\002\24\002\43\004\207\003\203\001\223\006\002\002\065",
+ (const uchar *const) "\001\223\003\202\002\60\002\37\002\23\002\22\002\36\002\21\002\55\003\203\001\223\006\005\002\055",
+ (const uchar *const) "\001\223\003\205\004\207\002\27\002\61\002\40\004\207\003\204\001\223\006\010\002\014",
+ (const uchar *const) "\001\223\003\206\002\44\002\31\002\57\002\42\002\46\002\25\002\207\003\204\001\223\002\013\002\064\002\015\002\230"
+};
+
+
+static const uchar * const keyboard_standard[5] = {
+
+#ifdef USE_SMALL_BACKSPACE
+ (const uchar *const)"\002\240\002`\0021\0022\0023\0024\0025\0026\0027\0028\0029\0020\002-\002=\002\200\002\223\002\215\002\216\002\217",
+#else
+ (const uchar *const)"\002\051\0021\0022\0023\0024\0025\0026\0027\0028\0029\0020\002-\002=\004\200\002\223\002\215\002\216\002\217",
+#endif
+ //~ + 123...+ BACKSPACE //+ INSERT + HOME + PGUP
+
+ (const uchar *const)"\003\201\002q\002w\002e\002r\002t\002y\002u\002i\002o\002p\002[\002]\002\\\001\224\002\223\002\221\002\220\002\222",
+ //TAB + qwerty.. + backslash //+ DEL + END + PGDN
+
+ (const uchar *const)"\004\202\002a\002s\002d\002f\002g\002h\002j\002k\002l\002;\002'\004\203",
+ //CAPS + asdf.. + RETURN
+
+ (const uchar *const)"\005\204\002z\002x\002c\002v\002b\002n\002m\002,\002.\002/\005\204\002\223\002\223\002\211",
+ //SHIFT + zxcv... //+ UP
+
+ (const uchar *const)"\003\205\003\206\022\207\003\206\003\205\002\223\002\212\002\213\002\214"
+ //CTRL + ALT + SPACE //+ LEFT + DOWN + RIGHT
+
+};
+
+
+struct ShiftMap {
+ char normal;
+ char shifted;
+};
+
+
+static const ShiftMap shiftMap[] = {
+ { '`', '~' },
+ { '1', '!' },
+ { '2', '@' },
+ { '3', '#' },
+ { '4', '$' },
+ { '5', '%' },
+ { '6', '^' },
+ { '7', '&' },
+ { '8', '*' },
+ { '9', '(' },
+ { '0', ')' },
+ { '-', '_' },
+ { '=', '+' },
+ { '\\', '|' },
+ { '[', '{' },
+ { ']', '}' },
+ { ';', ':' },
+ { '\'', '"' },
+ { ',', '<' },
+ { '.', '>' },
+ { '/', '?' }
+};
+
+
+/* XPM */
+static const char * const uparrow_xpm[]={
+"9 9 2 1",
+"a c #000000",
+". c None",
+".........",
+"....a....",
+"...aaa...",
+"..aaaaa..",
+"....a....",
+"....a....",
+"....a....",
+"....a....",
+"........."};
+/* XPM */
+static const char * const leftarrow_xpm[]={
+"9 9 2 1",
+"a c #000000",
+". c None",
+".........",
+".........",
+"...a.....",
+"..aa.....",
+".aaaaaaa.",
+"..aa.....",
+"...a.....",
+".........",
+"........."};
+/* XPM */
+static const char * const downarrow_xpm[]={
+"9 9 2 1",
+"a c #000000",
+". c None",
+".........",
+"....a....",
+"....a....",
+"....a....",
+"....a....",
+"..aaaaa..",
+"...aaa...",
+"....a....",
+"........."};
+/* XPM */
+static const char * const rightarrow_xpm[]={
+"9 9 2 1",
+"a c #000000",
+". c None",
+".........",
+".........",
+".....a...",
+".....aa..",
+".aaaaaaa.",
+".....aa..",
+".....a...",
+".........",
+"........."};
+/* XPM */
+static const char * const insert_xpm[]={
+"9 9 2 1",
+"a c #000000",
+". c None",
+".........",
+"a........",
+"a.aaa.aaa",
+"a.a.a.a..",
+"a.a.a..a.",
+"a.a.a...a",
+"a.a.a.aaa",
+".........",
+"........."};
+/* XPM */
+static const char * const delete_xpm[]={
+"9 9 2 1",
+"a c #000000",
+". c None",
+".........",
+"aa......a",
+"a.a.aaa.a",
+"a.a.a.a.a",
+"a.a.aaa.a.",
+"a.a.a...a",
+"aaa.aaa.a",
+".........",
+"........."};
+/* XPM */
+static const char * const home_xpm[]={
+"9 9 2 1",
+"a c #000000",
+". c None",
+"....a....",
+"...a.a...",
+"..a...a..",
+".a.....a.",
+"aa.aaa.aa",
+".a.a.a.a.",
+".a.a.a.a.",
+".aaaaaaa.",
+"........."};
+/* XPM */
+static const char * const end_xpm[]={
+"10 9 2 1",
+"a c #000000",
+". c None",
+"..........",
+"aa.......a",
+"a..aaa.aaa",
+"aa.a.a.a.a",
+"a..a.a.a.a",
+"a..a.a.a.a",
+"aa.a.a.aaa",
+"..........",
+".........."};
+/* XPM */
+static const char * const pageup_xpm[]={
+"9 9 2 1",
+"a c #000000",
+". c None",
+".aaa.aaa.",
+".a.a.a.a.",
+".aaa..aa.",
+".a...aaa.",
+".........",
+".a.a.aaa.",
+".a.a.a.a.",
+".aaa.aaa.",
+".....a..."};
+/* XPM */
+static const char * const pagedown_xpm[]={
+"9 9 2 1",
+"a c #000000",
+". c None",
+".aaa.aaa.",
+".a.a.a.a.",
+".aaa..aa.",
+".a...aaa.",
+".........",
+"...a.....",
+".aaa.aaa.",
+".a.a.a.a.",
+".aaa.a.a."};
+/* XPM */
+static const char * const expand_xpm[]={
+"4 9 2 1",
+"a c #408040",
+". c None",
+"a...",
+"aa..",
+"aaa.",
+"aaaa",
+"aaaa",
+"aaaa",
+"aaa.",
+"aa..",
+"a..."};
+/* XPM */
+#ifdef USE_SMALL_BACKSPACE
+static const char * const backspace_xpm[]={
+"9 9 2 1",
+"a c #000000",
+". c None",
+".........",
+".........",
+"...a.....",
+"..aa.....",
+".aaaaaaaa",
+"..aa.....",
+"...a.....",
+".........",
+"........."};
+#else
+static const char * const backspace_xpm[]={
+"21 9 2 1",
+"a c #000000",
+". c None",
+".....................",
+".....................",
+".....aaa..a..........",
+".a...a..a.a.a.aaa.aaa",
+"aaaa.aaa..aa..aa..a.a",
+".a...a..a.aaa..aa.a.a",
+".....aaaa.a.a.aaa.aa.",
+"..................a..",
+"....................."};
+#endif
+/* XPM */
+static const char * const escape_xpm[]={
+"9 9 2 1",
+"a c #000000",
+". c None",
+".........",
+".........",
+".aa.aa.aa",
+".a..a..a.",
+".aa.aa.a.",
+".a...a.a.",
+".aa.aa.aa",
+".........",
+"........."};
+
+
+enum { BSCode = 0x80, TabCode, CapsCode, RetCode,
+ ShiftCode, CtrlCode, AltCode, SpaceCode, BackSlash,
+ UpCode, LeftCode, DownCode, RightCode, Blank, Expand,
+ Opti, ResetDict,
+ Divide, Multiply, Add, Subtract, Decimal, Equal,
+ Percent, Sqrt, Inverse, Escape };
+
+typedef struct SpecialMap {
+ int qcode;
+ ushort unicode;
+ const char * label;
+ const char * const * xpm;
+};
+
+
+static const SpecialMap specialM[] = {
+ { Qt::Key_Backspace, 8, "<", backspace_xpm },
+ { Qt::Key_Tab, 9, "Tab", NULL },
+ { Qt::Key_CapsLock, 0, "Caps", NULL },
+ { Qt::Key_Return, 13, "Ret", NULL },
+ { Qt::Key_Shift, 0, "Shift", NULL },
+ { Qt::Key_Control, 0, "Ctrl", NULL },
+ { Qt::Key_Alt, 0, "Alt", NULL },
+ { Qt::Key_Space, ' ', "", NULL },
+ { BackSlash, 43, "\\", NULL },
+
+ // Need images?
+ { Qt::Key_Up, 0, "^", uparrow_xpm },
+ { Qt::Key_Left, 0, "<", leftarrow_xpm },
+ { Qt::Key_Down, 0, "v", downarrow_xpm },
+ { Qt::Key_Right, 0, ">", rightarrow_xpm },
+ { Qt::Key_Insert, 0, "I", insert_xpm },
+ { Qt::Key_Home, 0, "H", home_xpm },
+ { Qt::Key_PageUp, 0, "U", pageup_xpm },
+ { Qt::Key_End, 0, "E", end_xpm },
+ { Qt::Key_Delete, 0, "X", delete_xpm },
+ { Qt::Key_PageDown, 0, "D", pagedown_xpm },
+ { Blank, 0, " ", NULL },
+ { Expand, 0, "->", expand_xpm },
+ { Opti, 0, "#", NULL },
+ { ResetDict, 0, "R", NULL },
+
+ // number pad stuff
+ { Divide, 0, "/", NULL },
+ { Multiply, 0, "*", NULL },
+ { Add, 0, "+", NULL },
+ { Subtract, 0, "-", NULL },
+ { Decimal, 0, ".", NULL },
+ { Equal, 0, "=", NULL },
+ { Percent, 0, "%", NULL },
+ { Sqrt, 0, "^1/2", NULL },
+ { Inverse, 0, "1/x", NULL },
+
+ { Escape, 27, "ESC", escape_xpm }
+};
+
+
+static int keycode( int i2, int j, const uchar **keyboard )
+{
+ if ( j <0 || j >= 5 )
+ return 0;
+
+ const uchar *row = keyboard[j];
+
+ while ( *row && *row <= i2 ) {
+ i2 -= *row;
+ row += 2;
+ }
+
+ if ( !*row ) return 0;
+
+ int k;
+ if ( row[1] >= 0x80 ) {
+ k = row[1];
+ } else {
+ k = row[1]+i2/2;
+ }
+
+ return k;
+}
+
+
+/*
+ return scancode and width of first key in row \a j if \a j >= 0,
+ or next key on current row if \a j < 0.
+
+*/
+
+int Keyboard::getKey( int &w, int j ) {
+ static const uchar *row = 0;
+ static int key_i = 0;
+ static int scancode = 0;
+ static int half = 0;
+
+ if ( j >= 0 && j < 5 ) {
+ if (useOptiKeys)
+ row = keyboard_opti[j];
+ else
+ row = keyboard_standard[j];
+ half=0;
+ }
+
+ if ( !row || !*row ) {
+ return 0;
+ } else if ( row[1] >= 0x80 ) {
+ scancode = row[1];
+ w = (row[0] * w + (half++&1)) / 2;
+ row += 2;
+ return scancode;
+ } else if ( key_i <= 0 ) {
+ key_i = row[0]/2;
+ scancode = row[1];
+ }
+ key_i--;
+ if ( key_i <= 0 )
+ row += 2;
+ return scancode++;
+}
+
+
+void Keyboard::paintEvent(QPaintEvent* e)
+{
+ QPainter painter(this);
+ painter.setClipRect(e->rect());
+ drawKeyboard( painter );
+ picks->dc->draw( &painter );
+}
+
+
+/*
+ Draw the keyboard.
+
+ If key >= 0, only the specified key is drawn.
+*/
+void Keyboard::drawKeyboard( QPainter &p, int key )
+{
+ const bool threeD = FALSE;
+ const QColorGroup& cg = colorGroup();
+ QColor keycolor = // cg.background();
+ QColor(240,240,230); // Beige!
+ QColor keycolor_pressed = cg.mid();
+ QColor keycolor_lo = cg.dark();
+ QColor keycolor_hi = cg.light();
+ QColor textcolor = QColor(0,0,0); // cg.text();
+
+ int margin = threeD ? 1 : 0;
+
+// p.fillRect( 0, , kw-1, keyHeight-2, keycolor_pressed );
+
+ for ( int j = 0; j < 5; j++ ) {
+ int y = j * keyHeight + picks->height() + 1;
+ int x = xoffs;
+ int kw = defaultKeyWidth;
+ int k= getKey( kw, j );
+ while ( k ) {
+ if ( key < 0 || k == key ) {
+ QString s;
+ bool pressed = (k == pressedKey);
+ bool blank = (k == 0223);
+ const char * const * xpm = NULL;
+
+ if ( k >= 0x80 ) {
+ s = specialM[k - 0x80].label;
+
+ xpm = specialM[k - 0x80].xpm;
+
+ if ( k == ShiftCode ) {
+ pressed = shift;
+ } else if ( k == CapsCode ) {
+ pressed = lock;
+ } else if ( k == CtrlCode ) {
+ pressed = ctrl;
+ } else if ( k == AltCode ) {
+ pressed = alt;
+ }
+ } else {
+#if defined(Q_WS_QWS) || defined(_WS_QWS_)
+/*
+ s = QChar( shift^lock ? QWSServer::keyMap()[k].shift_unicode :
+ QWSServer::keyMap()[k].unicode);
+*/
+ // ### Fixme, bad code, needs improving, whole thing needs to
+ // be re-coded to get rid of the way it did things with scancodes etc
+ char shifted = k;
+ if ( !isalpha( k ) ) {
+ for ( unsigned i = 0; i < sizeof(shiftMap)/sizeof(ShiftMap); i++ )
+ if ( shiftMap[i].normal == k )
+ shifted = shiftMap[i].shifted;
+ } else {
+ shifted = toupper( k );
+ }
+ s = QChar( shift^lock ? shifted : k );
+#endif
+ }
+
+ if (!blank) {
+ if ( pressed )
+ p.fillRect( x+margin, y+margin, kw-margin, keyHeight-margin-1, keycolor_pressed );
+ else
+ p.fillRect( x+margin, y+margin, kw-margin, keyHeight-margin-1, keycolor );
+
+ if ( threeD ) {
+ p.setPen(pressed ? keycolor_lo : keycolor_hi);
+ p.drawLine( x, y+1, x, y+keyHeight-2 );
+ p.drawLine( x+1, y+1, x+1, y+keyHeight-3 );
+ p.drawLine( x+1, y+1, x+1+kw-2, y+1 );
+ } else if ( j == 0 ) {
+ p.setPen(pressed ? keycolor_hi : keycolor_lo);
+ p.drawLine( x, y, x+kw, y );
+ }
+
+ // right
+ p.setPen(pressed ? keycolor_hi : keycolor_lo);
+ p.drawLine( x+kw-1, y, x+kw-1, y+keyHeight-2 );
+
+ if ( threeD ) {
+ p.setPen(keycolor_lo.light());
+ p.drawLine( x+kw-2, y+keyHeight-2, x+kw-2, y+1 );
+ p.drawLine( x+kw-2, y+keyHeight-2, x+1, y+keyHeight-2 );
+ }
+
+ if (xpm) {
+ p.drawPixmap( x + 1, y + 2, QPixmap((const char**)xpm) );
+ } else {
+ p.setPen(textcolor);
+ p.drawText( x - 1, y, kw, keyHeight-2, AlignCenter, s );
+ }
+
+ if ( threeD ) {
+ p.setPen(keycolor_hi);
+ p.drawLine( x, y, x+kw-1, y );
+ }
+
+ // bottom
+ p.setPen(keycolor_lo);
+ p.drawLine( x, y+keyHeight-1, x+kw-1, y+keyHeight-1 );
+
+ } else {
+ p.fillRect( x, y, kw, keyHeight, cg.background() );
+ }
+ }
+
+ x += kw;
+ kw = defaultKeyWidth;
+ k = getKey( kw );
+ }
+ }
+}
+
+
+void Keyboard::mousePressEvent(QMouseEvent *e)
+{
+ clearHighlight(); // typing fast?
+
+ int i2 = ((e->x() - xoffs) * 2) / defaultKeyWidth;
+ int j = (e->y() - picks->height()) / keyHeight;
+
+ int k = keycode( i2, j, (const uchar **)((useOptiKeys) ? keyboard_opti : keyboard_standard) );
+ bool need_repaint = FALSE;
+ unicode = -1;
+ qkeycode = 0;
+ if ( k >= 0x80 ) {
+ if ( k == ShiftCode ) {
+ shift = !shift;
+ need_repaint = TRUE;
+ } else if ( k == AltCode ){
+ alt = !alt;
+ need_repaint = TRUE;
+ } else if ( k == CapsCode ) {
+ lock = !lock;
+ need_repaint = TRUE;
+ } else if ( k == CtrlCode ) {
+ ctrl = !ctrl;
+ need_repaint = TRUE;
+ } else if ( k == 0224 /* Expand */ ) {
+ useLargeKeys = !useLargeKeys;
+ resizeEvent(0);
+ repaint( TRUE ); // need it to clear first
+ } else if ( k == 0225 /* Opti/Toggle */ ) {
+ useOptiKeys = !useOptiKeys;
+ resizeEvent(0);
+ repaint( TRUE ); // need it to clear first
+ } else {
+ qkeycode = specialM[ k - 0x80 ].qcode;
+ unicode = specialM[ k - 0x80 ].unicode;
+ }
+ } else {
+#if defined(Q_WS_QWS) || defined(_WS_QWS_)
+/*
+ qk = QWSServer::keyMap()[k].key_code;
+ if ( qk != Key_unknown ) {
+ if ( ctrl )
+ u = QWSServer::keyMap()[k].ctrl_unicode;
+ else if ( shift^lock )
+ u = QWSServer::keyMap()[k].shift_unicode;
+ else
+ u = QWSServer::keyMap()[k].unicode;
+ }
+*/
+ char shifted = k;
+ if ( !isalpha( k ) ) {
+ // ### Fixme, bad code, needs improving, whole thing needs to
+ // be re-coded to get rid of the way it did things with scancodes etc
+ for ( unsigned i = 0; i < sizeof(shiftMap)/sizeof(ShiftMap); i++ )
+ if ( shiftMap[i].normal == k )
+ shifted = shiftMap[i].shifted;
+ } else {
+ shifted = toupper( k );
+ }
+ QChar tempChar( shift^lock ? shifted : k );
+ unicode = tempChar.unicode();
+#endif
+ }
+ if ( unicode != -1 ) {
+ modifiers = (shift ? Qt::ShiftButton : 0) | (ctrl ? Qt::ControlButton : 0) |
+ (alt ? Qt::AltButton : 0);
+#if defined(Q_WS_QWS) || defined(_WS_QWS_)
+ emit key( unicode, qkeycode, modifiers, true, false );
+ repeatTimer->start( 500 );
+#endif
+ need_repaint = shift || alt || ctrl;
+ shift = alt = ctrl = FALSE;
+ //qDebug( "pressed %d -> %04x ('%c')", k, u, u&0xffff < 256 ? u&0xff : 0 );
+
+ KeyboardConfig *dc = picks->dc;
+
+ if (dc) {
+ if (qkeycode == Qt::Key_Backspace) {
+ dc->input.remove(dc->input.last()); // remove last input
+ dc->decBackspaces();
+ } else if ( k == 0226 || qkeycode == Qt::Key_Return ||
+ qkeycode == Qt::Key_Space ||
+ QChar(unicode).isPunct() ) {
+ dc->input.clear();
+ dc->resetBackspaces();
+ } else {
+ dc->add(QString(QChar(unicode)));
+ dc->incBackspaces();
+ }
+ }
+
+ picks->repaint();
+
+ }
+ pressedKey = k;
+ if ( need_repaint ) {
+ repaint( FALSE );
+ } else {
+ QPainter p(this);
+ drawKeyboard( p, pressedKey );
+ }
+ pressTid = startTimer(80);
+ pressed = TRUE;
+}
+
+
+void Keyboard::mouseReleaseEvent(QMouseEvent*)
+{
+ if ( pressTid == 0 )
+ clearHighlight();
+#if defined(Q_WS_QWS) || defined(_WS_QWS_)
+ if ( unicode != -1 ) {
+ emit key( unicode, qkeycode, modifiers, false, false );
+ repeatTimer->stop();
+ }
+#endif
+ pressed = FALSE;
+}
+
+void Keyboard::timerEvent(QTimerEvent* e)
+{
+ if ( e->timerId() == pressTid ) {
+ killTimer(pressTid);
+ pressTid = 0;
+ if ( !pressed )
+ clearHighlight();
+ }
+}
+
+void Keyboard::repeat()
+{
+ repeatTimer->start( 150 );
+ emit key( unicode, qkeycode, modifiers, true, true );
+}
+
+void Keyboard::clearHighlight()
+{
+ if ( pressedKey >= 0 ) {
+ int tmp = pressedKey;
+ pressedKey = -1;
+ QPainter p(this);
+ drawKeyboard( p, tmp );
+ }
+}
+
+
+QSize Keyboard::sizeHint() const
+{
+ QFontMetrics fm=fontMetrics();
+ int keyHeight = fm.lineSpacing()+2;
+
+ if (useOptiKeys)
+ keyHeight += 1;
+
+ return QSize( 320, keyHeight * 5 + picks->sizeHint().height() + 1 );
+}
+
+
+void Keyboard::resetState()
+{
+ picks->resetState();
+}
diff --git a/inputmethods/keyboard/keyboard.h b/inputmethods/keyboard/keyboard.h
new file mode 100644
index 0000000..38ae338
--- a/dev/null
+++ b/inputmethods/keyboard/keyboard.h
@@ -0,0 +1,103 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#include <qframe.h>
+#include "../pickboard/pickboardcfg.h"
+#include "../pickboard/pickboardpicks.h"
+
+class QTimer;
+
+class KeyboardConfig : public DictFilterConfig
+{
+public:
+ KeyboardConfig(PickboardPicks* p) : DictFilterConfig(p), backspaces(0) { nrows = 1; }
+ virtual void generateText(const QString &s);
+ void decBackspaces() { if (backspaces) backspaces--; }
+ void incBackspaces() { backspaces++; }
+ void resetBackspaces() { backspaces = 0; }
+private:
+ int backspaces;
+};
+
+
+class KeyboardPicks : public PickboardPicks
+{
+ Q_OBJECT
+public:
+ KeyboardPicks(QWidget* parent=0, const char* name=0, WFlags f=0)
+ : PickboardPicks(parent, name, f) { }
+ void initialise();
+ virtual QSize sizeHint() const;
+ KeyboardConfig *dc;
+};
+
+class Keyboard : public QFrame
+{
+ Q_OBJECT
+public:
+ Keyboard( QWidget* parent=0, const char* name=0, WFlags f=0 );
+
+ void resetState();
+
+ void mousePressEvent(QMouseEvent*);
+ void mouseReleaseEvent(QMouseEvent*);
+ void resizeEvent(QResizeEvent*);
+ void paintEvent(QPaintEvent* e);
+ void timerEvent(QTimerEvent* e);
+ void drawKeyboard( QPainter &p, int key = -1 );
+
+ void setMode(int mode) { useOptiKeys = mode; }
+
+ QSize sizeHint() const;
+
+signals:
+ void key( ushort scancode, ushort unicode, ushort modifiers, bool, bool );
+
+private slots:
+ void repeat();
+
+private:
+ int getKey( int &w, int j = -1 );
+ void clearHighlight();
+
+ uint shift:1;
+ uint lock:1;
+ uint ctrl:1;
+ uint alt:1;
+ uint useLargeKeys:1;
+ uint useOptiKeys:1;
+
+ int pressedKey;
+
+ KeyboardPicks *picks;
+
+ int keyHeight;
+ int defaultKeyWidth;
+ int xoffs;
+
+ int unicode;
+ int qkeycode;
+ int modifiers;
+
+ int pressTid;
+ bool pressed;
+
+ QTimer *repeatTimer;
+};
+
diff --git a/inputmethods/keyboard/keyboard.pro b/inputmethods/keyboard/keyboard.pro
new file mode 100644
index 0000000..87c838e
--- a/dev/null
+++ b/inputmethods/keyboard/keyboard.pro
@@ -0,0 +1,18 @@
+TEMPLATE = lib
+CONFIG += qt warn_on release
+HEADERS = keyboard.h \
+ ../pickboard/pickboardcfg.h \
+ ../pickboard/pickboardpicks.h \
+ keyboardimpl.h
+SOURCES = keyboard.cpp \
+ ../pickboard/pickboardcfg.cpp \
+ ../pickboard/pickboardpicks.cpp \
+ keyboardimpl.cpp
+TARGET = qkeyboard
+DESTDIR = ../../plugins/inputmethods
+INCLUDEPATH += $(QPEDIR)/include
+DEPENDPATH += ../$(QPEDIR)/include ../../taskbar
+LIBS += -lqpe
+VERSION = 1.0.0
+
+TRANSLATIONS += ../../i18n/de/libqkeyboard.ts
diff --git a/inputmethods/keyboard/keyboardimpl.cpp b/inputmethods/keyboard/keyboardimpl.cpp
new file mode 100644
index 0000000..ea61272
--- a/dev/null
+++ b/inputmethods/keyboard/keyboardimpl.cpp
@@ -0,0 +1,131 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#include <qapplication.h>
+#include <qpixmap.h>
+#include "keyboard.h"
+#include "keyboardimpl.h"
+
+/* XPM */
+static const char * kb_xpm[] = {
+"28 13 4 1",
+" c None",
+". c #4C4C4C",
+"+ c #FFF7DD",
+"@ c #D6CFBA",
+" .......................... ",
+" .+++.+++.+++.+++.+++.++++. ",
+" .+@@.+@@.+@@.+@@.+@@.+@@@. ",
+" .......................... ",
+" .+++++.+++.+++.+++.++++++. ",
+" .+@@@@.+@@.+@@.+@@.+@@@@@. ",
+" .......................... ",
+" .++++++.+++.+++.+++.+++++. ",
+" .+@@@@@.+@@.+@@.+@@.+@@@@. ",
+" .......................... ",
+" .++++.++++++++++++++.++++. ",
+" .+@@@.+@@@@@@@@@@@@@.+@@@. ",
+" .......................... "};
+
+
+/* XPM */
+static char * opti_xpm[] = {
+"28 13 4 1",
+" c None",
+". c #4C4C4C",
+"+ c #FFF7DD",
+"@ c #D6CFBA",
+" ......................... ",
+" .+++.+++.+++.+++.+++.+++. ",
+" .+@@.+@@.+@@.+@@.+@@.+@@. ",
+" ......................... ",
+" .+++.+++.+++.+++.+++.+++. ",
+" .+@@.+@@.+@@.+@@.+@@.+@@. ",
+" ......................... ",
+" .+++.+++.+++.+++.+++.+++. ",
+" .+@@.+@@.+@@.+@@.+@@.+@@. ",
+" ......................... ",
+" .+++.+++.+++.+++.+++.+++. ",
+" .+@@.+@@.+@@.+@@.+@@.+@@. ",
+" ......................... "};
+
+
+
+KeyboardImpl::KeyboardImpl()
+ : input(0), icn(0), ref(0)
+{
+}
+
+KeyboardImpl::~KeyboardImpl()
+{
+ delete input;
+ delete icn;
+}
+
+QWidget *KeyboardImpl::inputMethod( QWidget *parent, Qt::WFlags f )
+{
+ if ( !input )
+ input = new Keyboard( parent, "Keyboard", f );
+ return input;
+}
+
+void KeyboardImpl::resetState()
+{
+ if ( input )
+ input->resetState();
+}
+
+QPixmap *KeyboardImpl::icon()
+{
+ if ( !icn )
+ icn = new QPixmap( (const char **)kb_xpm );
+ return icn;
+}
+
+QString KeyboardImpl::name()
+{
+ return qApp->translate( "InputMethods", "Keyboard" );
+// return qApp->translate( "InputMethods", "Opti" );
+}
+
+void KeyboardImpl::onKeyPress( QObject *receiver, const char *slot )
+{
+ if ( input )
+ QObject::connect( input, SIGNAL(key(ushort,ushort,ushort,bool,bool)), receiver, slot );
+}
+
+#ifndef QT_NO_COMPONENT
+QRESULT KeyboardImpl::queryInterface( const QUuid &uuid, QUnknownInterface **iface )
+{
+ *iface = 0;
+ if ( uuid == IID_QUnknown )
+ *iface = this;
+ else if ( uuid == IID_InputMethod )
+ *iface = this;
+
+ if ( *iface )
+ (*iface)->addRef();
+ return QS_OK;
+}
+
+Q_EXPORT_INTERFACE()
+{
+ Q_CREATE_INSTANCE( KeyboardImpl )
+}
+#endif
diff --git a/inputmethods/keyboard/keyboardimpl.h b/inputmethods/keyboard/keyboardimpl.h
new file mode 100644
index 0000000..e756364
--- a/dev/null
+++ b/inputmethods/keyboard/keyboardimpl.h
@@ -0,0 +1,51 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#ifndef KEYBOARDIMPL_H
+#define KEYBOARDIMPL_H
+
+#include <qpe/inputmethodinterface.h>
+
+class Keyboard;
+class QPixmap;
+
+class KeyboardImpl : public InputMethodInterface
+{
+public:
+ KeyboardImpl();
+ virtual ~KeyboardImpl();
+
+#ifndef QT_NO_COMPONENT
+ QRESULT queryInterface( const QUuid&, QUnknownInterface** );
+ Q_REFCOUNT
+#endif
+
+ virtual QWidget *inputMethod( QWidget *parent, Qt::WFlags f );
+ virtual void resetState();
+ virtual QPixmap *icon();
+ virtual QString name();
+ virtual void onKeyPress( QObject *receiver, const char *slot );
+
+private:
+ Keyboard *input;
+ QPixmap *icn;
+ ulong ref;
+};
+
+#endif
diff --git a/inputmethods/keyboard/qpe-keyboard.control b/inputmethods/keyboard/qpe-keyboard.control
new file mode 100644
index 0000000..dae67f9
--- a/dev/null
+++ b/inputmethods/keyboard/qpe-keyboard.control
@@ -0,0 +1,9 @@
+Files: plugins/inputmethods/libqkeyboard.so*
+Priority: optional
+Section: qpe/inputmethods
+Maintainer: Martin Jones <mjones@trolltech.com>
+Architecture: arm
+Version: $QPE_VERSION-3
+Depends: qpe-base ($QPE_VERSION)
+Description: Keyboard input method
+ Keyboard input method for the Qtopia environment.
diff --git a/inputmethods/keyboard/qpe-keyboard.postinst b/inputmethods/keyboard/qpe-keyboard.postinst
new file mode 100755
index 0000000..c254b01
--- a/dev/null
+++ b/inputmethods/keyboard/qpe-keyboard.postinst
@@ -0,0 +1,2 @@
+#!/bin/sh
+/opt/QtPalmtop/bin/qcop QPE/TaskBar "reloadInputMethods()"
diff --git a/inputmethods/keyboard/qpe-keyboard.postrm b/inputmethods/keyboard/qpe-keyboard.postrm
new file mode 100755
index 0000000..c254b01
--- a/dev/null
+++ b/inputmethods/keyboard/qpe-keyboard.postrm
@@ -0,0 +1,2 @@
+#!/bin/sh
+/opt/QtPalmtop/bin/qcop QPE/TaskBar "reloadInputMethods()"
diff --git a/inputmethods/pickboard/.cvsignore b/inputmethods/pickboard/.cvsignore
new file mode 100644
index 0000000..edfa921
--- a/dev/null
+++ b/inputmethods/pickboard/.cvsignore
@@ -0,0 +1,3 @@
+moc_*
+*.moc
+Makefile
diff --git a/inputmethods/pickboard/Makefile.in b/inputmethods/pickboard/Makefile.in
new file mode 100644
index 0000000..d72e82d
--- a/dev/null
+++ b/inputmethods/pickboard/Makefile.in
@@ -0,0 +1,147 @@
+#############################################################################
+
+####### Compiler, tools and options
+
+CXX = $(SYSCONF_CXX) $(QT_CXX_MT)
+CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) $(SYSCONF_CXXFLAGS_LIB)
+CC = $(SYSCONF_CC) $(QT_C_MT)
+CFLAGS = $(SYSCONF_CFLAGS) $(SYSCONF_CFLAGS_LIB)
+INCPATH = -I$(QPEDIR)/include
+LFLAGS = $(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT)
+LIBS = $(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS_QTAPP)
+MOC = $(SYSCONF_MOC)
+UIC = $(SYSCONF_UIC)
+
+####### Target
+
+DESTDIR = ../../plugins/inputmethods/
+VER_MAJ = 1
+VER_MIN = 0
+VER_PATCH = 0
+TARGET = qpickboard
+TARGET1 = lib$(TARGET).so.$(VER_MAJ)
+
+####### Files
+
+HEADERS = pickboard.h \
+ pickboardcfg.h \
+ pickboardimpl.h \
+ pickboardpicks.h
+SOURCES = pickboard.cpp \
+ pickboardcfg.cpp \
+ pickboardimpl.cpp \
+ pickboardpicks.cpp
+OBJECTS = pickboard.o \
+ pickboardcfg.o \
+ pickboardimpl.o \
+ pickboardpicks.o
+INTERFACES =
+UICDECLS =
+UICIMPLS =
+SRCMOC = moc_pickboard.cpp \
+ moc_pickboardcfg.cpp \
+ moc_pickboardpicks.cpp
+OBJMOC = moc_pickboard.o \
+ moc_pickboardcfg.o \
+ moc_pickboardpicks.o
+
+
+####### Implicit rules
+
+.SUFFIXES: .cpp .cxx .cc .C .c
+
+.cpp.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.cxx.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.cc.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.C.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
+
+####### Build rules
+
+
+all: $(DESTDIR)$(SYSCONF_LINK_TARGET)
+
+$(DESTDIR)$(SYSCONF_LINK_TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS)
+ $(SYSCONF_LINK_LIB)
+
+moc: $(SRCMOC)
+
+tmake:
+ tmake pickboard.pro
+
+clean:
+ -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS)
+ -rm -f *~ core
+ -rm -f allmoc.cpp
+
+####### Extension Modules
+
+listpromodules:
+ @echo
+
+listallmodules:
+ @echo
+
+listaddonpromodules:
+ @echo
+
+listaddonentmodules:
+ @echo
+
+
+REQUIRES=
+
+####### Sub-libraries
+
+
+###### Combined headers
+
+
+
+####### Compile
+
+pickboard.o: pickboard.cpp \
+ pickboard.h \
+ pickboardpicks.h \
+ pickboardcfg.h
+
+pickboardcfg.o: pickboardcfg.cpp \
+ pickboardcfg.h \
+ pickboardpicks.h
+
+pickboardimpl.o: pickboardimpl.cpp \
+ pickboard.h \
+ pickboardimpl.h
+
+pickboardpicks.o: pickboardpicks.cpp \
+ pickboardpicks.h \
+ pickboardcfg.h
+
+moc_pickboard.o: moc_pickboard.cpp \
+ pickboard.h
+
+moc_pickboardcfg.o: moc_pickboardcfg.cpp \
+ pickboardcfg.h
+
+moc_pickboardpicks.o: moc_pickboardpicks.cpp \
+ pickboardpicks.h
+
+moc_pickboard.cpp: pickboard.h
+ $(MOC) pickboard.h -o moc_pickboard.cpp
+
+moc_pickboardcfg.cpp: pickboardcfg.h
+ $(MOC) pickboardcfg.h -o moc_pickboardcfg.cpp
+
+moc_pickboardpicks.cpp: pickboardpicks.h
+ $(MOC) pickboardpicks.h -o moc_pickboardpicks.cpp
+
+
diff --git a/inputmethods/pickboard/pickboard.cpp b/inputmethods/pickboard/pickboard.cpp
new file mode 100644
index 0000000..087144e
--- a/dev/null
+++ b/inputmethods/pickboard/pickboard.cpp
@@ -0,0 +1,89 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#include "pickboard.h"
+#include "pickboardpicks.h"
+#include "pickboardcfg.h"
+
+#include <qpe/global.h>
+
+#include <qpainter.h>
+#include <qlist.h>
+#include <qbitmap.h>
+#include <qlayout.h>
+#include <qvbox.h>
+#include <qdialog.h>
+#include <qscrollview.h>
+#include <qpopupmenu.h>
+#include <qhbuttongroup.h>
+#include <qpushbutton.h>
+#include <qmessagebox.h>
+#include <qwindowsystem_qws.h>
+
+/* XPM */
+static const char * const menu_xpm[]={
+"9 9 2 1",
+"a c #000000",
+". c None",
+".........",
+".........",
+".........",
+"....a....",
+"...aaa...",
+"..aaaaa..",
+".aaaaaaa.",
+".........",
+"........."};
+
+class PickboardPrivate {
+public:
+ PickboardPrivate(Pickboard* parent)
+ {
+ picks = new PickboardPicks(parent);
+ picks->initialise();
+ menu = new QPushButton(parent);
+ menu->setSizePolicy(QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Expanding));
+ menu->setPixmap(QPixmap((const char **)menu_xpm));
+ QObject::connect(menu,SIGNAL(clicked()),picks,SLOT(doMenu()));
+ QObject::connect(picks,SIGNAL(key(ushort,ushort,ushort,bool,bool)),
+ parent,SIGNAL(key(ushort,ushort,ushort,bool,bool)));
+ }
+
+ PickboardPicks* picks;
+ QPushButton* menu;
+};
+
+Pickboard::Pickboard(QWidget* parent, const char* name, WFlags f) :
+ QFrame(parent,name,f)
+{
+ (new QHBoxLayout(this))->setAutoAdd(TRUE);
+ d = new PickboardPrivate(this);
+ setFont( QFont( "smallsmooth", 9 ) );
+}
+
+Pickboard::~Pickboard()
+{
+ delete d;
+}
+
+void Pickboard::resetState()
+{
+ d->picks->resetState();
+}
+
diff --git a/inputmethods/pickboard/pickboard.h b/inputmethods/pickboard/pickboard.h
new file mode 100644
index 0000000..5fff875
--- a/dev/null
+++ b/inputmethods/pickboard/pickboard.h
@@ -0,0 +1,43 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#ifndef PICKBOARD_H
+#define PICKBOARD_H
+
+#include <qframe.h>
+
+class PickboardPrivate;
+
+class Pickboard : public QFrame
+{
+ Q_OBJECT
+public:
+ Pickboard(QWidget* parent=0, const char* name=0, WFlags f=0);
+ ~Pickboard();
+
+ void resetState();
+
+signals:
+ void key( ushort, ushort, ushort, bool, bool );
+
+private:
+ PickboardPrivate* d;
+};
+
+#endif
diff --git a/inputmethods/pickboard/pickboard.pro b/inputmethods/pickboard/pickboard.pro
new file mode 100644
index 0000000..50bc342
--- a/dev/null
+++ b/inputmethods/pickboard/pickboard.pro
@@ -0,0 +1,12 @@
+TEMPLATE = lib
+CONFIG += qt warn_on release
+HEADERS = pickboard.h pickboardcfg.h pickboardimpl.h pickboardpicks.h
+SOURCES = pickboard.cpp pickboardcfg.cpp pickboardimpl.cpp pickboardpicks.cpp
+TARGET = qpickboard
+DESTDIR = ../../plugins/inputmethods
+INCLUDEPATH += $(QPEDIR)/include
+DEPENDPATH += ../$(QPEDIR)/include ../../taskbar
+LIBS += -lqpe
+VERSION = 1.0.0
+
+TRANSLATIONS += ../../i18n/de/libqpickboard.ts
diff --git a/inputmethods/pickboard/pickboardcfg.cpp b/inputmethods/pickboard/pickboardcfg.cpp
new file mode 100644
index 0000000..e8b47cb
--- a/dev/null
+++ b/inputmethods/pickboard/pickboardcfg.cpp
@@ -0,0 +1,731 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include "pickboardcfg.h"
+#include "pickboardpicks.h"
+
+#include <qpe/global.h>
+
+#include <qpainter.h>
+#include <qlist.h>
+#include <qbitmap.h>
+#include <qlayout.h>
+#include <qvbox.h>
+#include <qdialog.h>
+#include <qscrollview.h>
+#include <qpopupmenu.h>
+#include <qhbuttongroup.h>
+#include <qpushbutton.h>
+#include <qmessagebox.h>
+#include <qwindowsystem_qws.h>
+
+static const char * pickboard_help =
+ "<h1>The Pickboard</h1>"
+ "<i>The smallest and fastest way to type.</i>"
+ "<p>"
+ "Enter a word by tapping letter-groups and picking the word."
+ "<br>Enter spaces with \"Space\", or other keys through \"KEY\"."
+ "<br>Use \"Shift\" to capitalize words that are not normally capitalized."
+ "<br>Press \"Shift\" twice for an all-capitals word."
+ "<br>Add custom words by picking them, then selecting \"Add...\" from the menu on the right."
+ ;
+
+const int intermatchmargin=5;
+
+
+PickboardConfig::~PickboardConfig() { }
+
+void PickboardConfig::updateRows(int from, int to)
+{
+ if ( from != to ) { // (all)
+ parent->update();
+ } else {
+ QFontMetrics fm = parent->fontMetrics();
+ parent->update(QRect(0,1+fm.descent() + from * fm.lineSpacing(), parent->width(),
+ fm.lineSpacing()));
+ }
+}
+
+void PickboardConfig::updateItem(int r, int)
+{
+ updateRows(r,r);
+}
+
+void PickboardConfig::changeMode(int m)
+{
+ parent->setMode(m);
+}
+void PickboardConfig::generateText(const QString& s)
+{
+#if defined(Q_WS_QWS) || defined(_WS_QWS_)
+ for (int i=0; i<(int)s.length(); i++) {
+ parent->emitKey(s[i].unicode(), 0, 0, true, false);
+ parent->emitKey(s[i].unicode(), 0, 0, false, false);
+ }
+#endif
+}
+void PickboardConfig::generateKey( int k )
+{
+#if defined(Q_WS_QWS) || defined(_WS_QWS_)
+ parent->emitKey(0, k, 0, true, false);
+ parent->emitKey(0, k, 0, false, false);
+#endif
+}
+
+void PickboardConfig::pickPoint(const QPoint& p, bool press)
+{
+ if ( press ) {
+ int ls=parent->height()/nrows;
+ int y=0;
+ pressx = -1;
+ for (int r=0; r<nrows; r++) {
+ if ( p.y() >= y && p.y() < y+ls ) {
+ pressrow = r;
+ pressx = p.x();
+ pickInRow( pressrow, pressx, TRUE );
+ return;
+ }
+ y += ls;
+ }
+ } else if ( pressx >= 0 ) {
+ pickInRow( pressrow, pressx, FALSE );
+ pressx = -1;
+ }
+}
+
+void PickboardConfig::fillMenu(QPopupMenu& menu)
+{
+ menu.insertItem("Reset",100);
+ menu.insertSeparator();
+ menu.insertItem("Help",1);
+}
+
+void PickboardConfig::doMenu(int i)
+{
+ switch (i) {
+ case 100:
+ if ( parent->currentMode() ) {
+ changeMode(0);
+ updateRows(0,1);
+ }
+ break;
+ case 1: {
+ QMessageBox help("Pickboard Help", pickboard_help,
+ QMessageBox::NoIcon, 1, 0, 0);
+ help.showMaximized();
+ help.exec();
+ }
+ }
+}
+
+void StringConfig::draw(QPainter* p)
+{
+ QFontMetrics fm = p->fontMetrics();
+
+ for (int r=0; r<nrows; r++) {
+ p->translate(0,fm.lineSpacing());
+ p->setPen(rowColor(r));
+
+ int tw=0;
+ QString s;
+ int i=0;
+ for (; !(s=text(r,i)).isNull(); ++i) {
+ int w = fm.width(s);
+ tw += w;
+ }
+ bool spread = spreadRow(r);// && parent->width() > tw;
+ int xw = spread ? (parent->width()-tw)/(i-1) : 3;
+ int x = spread ? (parent->width()-tw-xw*(i-1))/2 : 2;
+
+ i=0;
+ for (; !(s=text(r,i)).isNull(); ++i) {
+ int w = fm.width(s)+xw;
+ if ( highlight(r,i) ) {
+ p->fillRect(x-xw/2,1+fm.descent()-fm.lineSpacing(),w,fm.lineSpacing(),Qt::black);
+ p->setPen(Qt::white);
+ }else{
+ p->setPen(Qt::black);
+ }
+ p->drawText(x,-fm.descent()-1,s);
+ x += w;
+ }
+ }
+}
+
+void StringConfig::pickInRow(int r, int xpos, bool press)
+{
+ QFontMetrics fm = parent->fontMetrics();
+
+ int tw=0;
+ QString s;
+ int i=0;
+ for (; !(s=text(r,i)).isNull(); ++i) {
+ int w = fm.width(s);
+ tw += w;
+ }
+ bool spread = spreadRow(r) && parent->width() > tw;
+ int xw = spread ? (parent->width()-tw)/(i-1) : 3;
+ int x = spread ? (parent->width()-tw-xw*(i-1))/2 : 2;
+
+ i=0;
+ for (; !(s=text(r,i)).isNull(); ++i) {
+ int x2 = x + fm.width(s)+xw;
+ if ( xpos >= x && xpos < x2 ) {
+ pick(press, r, i);
+ return;
+ }
+ x = x2;
+ }
+}
+
+void StringConfig::updateItem(int r, int item)
+{
+ QFontMetrics fm = parent->fontMetrics();
+
+ int y = r * fm.lineSpacing();
+
+ int tw=0;
+ QString s;
+ int i=0;
+ for (; !(s=text(r,i)).isNull(); ++i) {
+ int w = fm.width(s);
+ tw += w;
+ }
+ bool spread = spreadRow(r) && parent->width() > tw;
+ int xw = spread ? (parent->width()-tw)/(i-1) : 3;
+ int x = spread ? (parent->width()-tw-xw*(i-1))/2 : 2;
+
+ i=0;
+ for (; !(s=text(r,i)).isNull(); ++i) {
+ int w = fm.width(s)+xw;
+ if ( i == item ) {
+ parent->update(QRect(x-xw/2,y+1+fm.descent(),w,fm.lineSpacing()));
+ return;
+ }
+ x += w;
+ }
+}
+
+bool StringConfig::highlight(int,int) const
+{
+ return FALSE;
+}
+
+LetterButton::LetterButton(const QChar& letter, QWidget* parent) :
+ QPushButton(letter,parent)
+{
+ setToggleButton(TRUE);
+ setAutoDefault(FALSE);
+ connect(this,SIGNAL(clicked()),this,SLOT(toggleCase()));
+ skip=TRUE;
+}
+
+void LetterButton::toggleCase()
+{
+ if ( skip ) {
+ // Don't toggle case the first time
+ skip=FALSE;
+ return;
+ }
+
+ QChar ch = text()[0];
+ QChar nch = ch.lower();
+ if ( ch == nch )
+ nch = ch.upper();
+ setText(nch);
+}
+
+LetterChoice::LetterChoice(QWidget* parent, const QString& set) :
+ QButtonGroup(parent)
+{
+ QHBoxLayout *l = new QHBoxLayout(this);
+ setFrameStyle(0);
+ setExclusive(TRUE);
+ for (int i=0; i<(int)set.length(); i++) {
+ LetterButton* b = new LetterButton(set[i],this);
+ l->addWidget(b,1,AlignCenter);
+ connect(b,SIGNAL(clicked()),this,SLOT(change()));
+ }
+}
+
+void LetterChoice::change()
+{
+ LetterButton* b = (LetterButton*)sender();
+ ch = b->text()[0];
+ emit changed();
+}
+
+
+PickboardAdd::PickboardAdd(QWidget* owner, const QStringList& setlist) :
+ QDialog( owner, 0, TRUE )
+{
+ QVBoxLayout* l = new QVBoxLayout(this);
+ l->setAutoAdd(TRUE);
+
+ QScrollView *sv = new QScrollView(this);
+ sv->setResizePolicy(QScrollView::AutoOneFit);
+ setMaximumHeight(200); // ### QDialog shouldn't allow us to be bigger than the screen
+ QVBox *letters = new QVBox(sv);
+ letters->setSpacing(0);
+ lc = new LetterChoice*[setlist.count()];
+ nlc = (int)setlist.count();
+ for (int i=0; i<nlc; i++) {
+ lc[i] = new LetterChoice(letters,setlist[i]);
+ connect(lc[i],SIGNAL(changed()),this,SLOT(checkAllDone()));
+ }
+ sv->addChild(letters);
+ QHBox* hb = new QHBox(this);
+ hb->setSpacing(0);
+ yes = new QPushButton("OK",hb);
+ yes->setEnabled(FALSE);
+ QPushButton *no = new QPushButton("Cancel",hb);
+ connect(yes, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(no, SIGNAL(clicked()), this, SLOT(reject()));
+}
+
+PickboardAdd::~PickboardAdd()
+{
+ delete [] lc;
+}
+
+QString PickboardAdd::word() const
+{
+ QString str;
+ for (int i=0; i<nlc; i++) {
+ str += lc[i]->choice();
+ }
+ return str;
+}
+
+bool PickboardAdd::exec()
+{
+ QPoint pos = parentWidget()->mapToGlobal(QPoint(0,0));
+ pos.ry() -= height();
+ if ( QDialog::exec() ) {
+ Global::addWords(QStringList(word()));
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+void PickboardAdd::checkAllDone()
+{
+ if ( !yes->isEnabled() ) {
+ for (int i=0; i<nlc; i++) {
+ if ( lc[i]->choice().isNull() )
+ return;
+ }
+ yes->setEnabled(TRUE);
+ }
+}
+
+
+void DictFilterConfig::doMenu(int i)
+{
+ switch (i) {
+ case 300:
+ if ( input.count() == 0 ) {
+ QMessageBox::information(0, "Adding Words",
+ "To add words, pick the letters,\nthen "
+ "open the Add dialog. In that\ndialog, tap "
+ "the correct letters\nfrom the list "
+ "(tap twice for\ncapitals).");
+ } else {
+ PickboardAdd add(parent,capitalize(input));
+ if ( add.exec() )
+ generateText(add.word());
+ input.clear();
+ matches.clear();
+ updateRows(0,0);
+ }
+ break;
+ case 100:
+ if ( !input.isEmpty() ) {
+ input.clear();
+ matches.clear();
+ StringConfig::doMenu(i);
+ updateRows(0,1);
+ break;
+ } // else fall through
+ default:
+ StringConfig::doMenu(i);
+ }
+ shift = 0;
+ lit0 = -1;
+}
+
+QString DictFilterConfig::text(int r, int i)
+{
+ QStringList l = r ? sets : input.isEmpty() ? othermodes : matches;
+ return i < (int)l.count() ?
+ (input.isEmpty() ? l[i] : capitalize(l[i]))
+ : QString::null;
+}
+
+bool DictFilterConfig::spreadRow(int r)
+{
+ return r ? TRUE : input.isEmpty() ? TRUE : FALSE;
+}
+
+QStringList DictFilterConfig::capitalize(const QStringList& l)
+{
+ switch ( shift ) {
+ case 1: {
+ QStringList r;
+ QStringList::ConstIterator it = l.begin();
+ r.append((*it).upper());
+ for (++it; it != l.end(); ++it)
+ r.append(*it);
+ return r;
+ } case 2: {
+ QStringList r;
+ for (QStringList::ConstIterator it = l.begin(); it != l.end(); ++it)
+ r.append((*it).upper());
+ return r;
+ }
+ }
+ return l;
+}
+
+QString DictFilterConfig::capitalize(const QString& s)
+{
+ switch ( shift ) {
+ case 1: {
+ QString u = s;
+ u[0] = u[0].upper();
+ return u;
+ break;
+ } case 2:
+ return s.upper();
+ break;
+ }
+ return s;
+}
+
+void DictFilterConfig::pick(bool press, int row, int item)
+{
+ if ( row == 0 ) {
+ if ( press ) {
+ if ( input.isEmpty() ) {
+ lit0 = item;
+ if ( othermodes[item] == "Space" ) {
+ updateItem(row,item);
+ generateText(" ");
+ } else if ( othermodes[item] == "Back" ) {
+ updateItem(row,item);
+ generateKey(Qt::Key_Backspace);
+ } else if ( othermodes[item] == "Enter" ) {
+ updateItem(row,item);
+ generateKey(Qt::Key_Return);
+ } else if ( othermodes[item] == "Shift" ) {
+ updateItem(row,item);
+ shift = (shift+1)%3;
+ }
+ }
+ } else {
+ if ( !input.isEmpty() ) {
+ input.clear();
+ if ( item>=0 ) {
+ generateText(capitalize(matches[item]));
+ }
+ shift = 0;
+ matches.clear();
+ updateRows(0,0);
+ } else if ( item < 3 ) {
+ lit0 = -1;
+ changeMode(item+1); // I'm mode 0! ####
+ updateRows(0,1);
+ }
+ if ( lit0 >= 0 ) {
+ if ( !shift || othermodes[lit0] != "Shift" ) {
+ updateItem(0,lit0);
+ lit0 = -1;
+ }
+ }
+ }
+ } else {
+ lit0 = -1;
+ if ( press && item >= 0 ) {
+ lit1 = item;
+ add(sets[item]);
+ updateItem(1,item);
+ updateRows(0,0);
+ } else {
+ updateItem(1,lit1);
+ lit1 = -1;
+ }
+ }
+}
+
+bool DictFilterConfig::scanMatch(const QString& set, const QChar& l) const
+{
+ return set == "?" || set == "*" || set.contains(l);
+}
+
+//static int visit=0;
+//static int lvisit=0;
+
+void DictFilterConfig::scan(const QDawg::Node* n, int ipos, const QString& str, int length, bool extend)
+{
+ if ( n ) {
+ do {
+//visit++;
+ bool pastend = ipos >= (int)input.count();
+ if ( pastend && extend || !pastend && scanMatch(input[ipos],n->letter().lower()) ) {
+ if ( length>1 ) {
+ if ( !pastend && input[ipos] == "*" ) {
+ scan(n->jump(),ipos+1,str+n->letter(),length-1,FALSE);
+ scan(n->jump(),ipos,str+n->letter(),length,FALSE);
+ } else {
+ scan(n->jump(),ipos+1,str+n->letter(),length-1,extend);
+ }
+ } else {
+ if ( n->isWord() ) {
+ matches.append(str+n->letter());
+ }
+ }
+ }
+ n = n->next();
+ } while (n);
+ }
+}
+
+void DictFilterConfig::scanLengths(const QDawg::Node* n, int ipos, int& length_bitarray)
+{
+ if ( n ) {
+ do {
+//lvisit++;
+ bool pastend = ipos >= (int)input.count();
+ if ( pastend || scanMatch(input[ipos],n->letter().lower()) ) {
+ scanLengths(n->jump(),ipos+1,length_bitarray);
+ if ( n->isWord() )
+ length_bitarray |= (1<<(ipos+1));
+ }
+ n = n->next();
+ } while (n);
+ }
+}
+
+void DictFilterConfig::add(const QString& set)
+{
+ QFontMetrics fm = parent->fontMetrics();
+ input.append(set.lower());
+ matches.clear();
+//visit=0;
+//lvisit=0;
+ int length_bitarray = 0;
+ if ( input.count() > 4 ) {
+ scanLengths(Global::addedDawg().root(),0,length_bitarray);
+ scanLengths(Global::fixedDawg().root(),0,length_bitarray);
+ } else {
+ length_bitarray = 0xffffffff;
+ }
+ for (int len=input.count(); len<22 /* 32 */; ++len) {
+ if ( length_bitarray & (1<<len) ) {
+ scan(Global::addedDawg().root(),0,"",len,TRUE);
+ scan(Global::fixedDawg().root(),0,"",len,TRUE);
+ int x = 2;
+ for (QStringList::Iterator it=matches.begin(); it!=matches.end(); ++it) {
+ x += fm.width(*it)+intermatchmargin;
+ if ( x >= parent->width() ) {
+//qDebug("%d+%d visits",lvisit,visit);
+ return; // RETURN - No point finding more
+ }
+ }
+ }
+ if ( len == 1 && input.count() == 1 ) {
+ // Allow all single-characters to show as "matches"
+ for ( int i=0; i<(int)set.length(); i++ ) {
+ QChar ch = set[i].lower();
+ matches.append(ch);
+ }
+ }
+ }
+//qDebug("%d+%d visits",lvisit,visit);
+}
+
+bool DictFilterConfig::highlight(int r,int c) const
+{
+ return r == 0 ? c == lit0 : c == lit1;
+}
+
+
+void DictFilterConfig::addSet(const QString& s)
+{
+ sets.append(s);
+}
+
+void DictFilterConfig::addMode(const QString& s)
+{
+ othermodes.append(s);
+}
+
+void DictFilterConfig::fillMenu(QPopupMenu& menu)
+{
+ menu.insertItem("Add...",300);
+ StringConfig::fillMenu(menu);
+}
+
+QValueList<QPixmap> KeycodeConfig::row(int i)
+{
+ return i ? keypm2 : keypm1;
+}
+
+void KeycodeConfig::pickInRow(int r, int xpos, bool press)
+{
+ QValueList<QPixmap> pl = row(r);
+ QValueList<QPixmap>::Iterator it;
+ int item=0;
+ int x=xmarg;
+ for (it=pl.begin(); it!=pl.end(); ++it) {
+ int x2 = x + (*it).width();
+ if ( (*it).height() > 1 )
+ x2 += xw;
+ if ( xpos >= x && xpos < x2 ) {
+ pick(press, r, item);
+ return;
+ }
+ x = x2;
+ item++;
+ }
+}
+
+void KeycodeConfig::pick(bool press, int row, int item)
+{
+ if ( !press ) {
+ if ( item >= 0 ) {
+ int k = row == 0 ? keys1[item] : keys2[item];
+ if ( k )
+ generateKey(k);
+ }
+ changeMode(0);
+ updateRows(0,1);
+ }
+}
+
+void KeycodeConfig::draw(QPainter* p)
+{
+ int y=3;
+ QValueList<QPixmap>::Iterator it;
+ for (int r=0; r<nrows; r++) {
+ QValueList<QPixmap> pl = row(r);
+ int x = xmarg;
+ for (it=pl.begin(); it!=pl.end(); ++it) {
+ if ( (*it).height() == 1 ) {
+ // just a gap
+ x += (*it).width();
+ } else {
+ p->drawPixmap(x,y,*it);
+ x += (*it).width()+xw;
+ }
+ }
+ y += parent->height()/nrows;
+ }
+}
+
+
+void KeycodeConfig::addKey(int r, const QPixmap& pm, int code)
+{
+ if ( r == 0 ) {
+ keypm1.append(pm);
+ keys1.append(code);
+ } else {
+ keypm2.append(pm);
+ keys2.append(code);
+ }
+}
+void KeycodeConfig::addGap(int r, int w)
+{
+ QBitmap pm(w,1); // ick.
+ addKey(r,pm,0);
+}
+
+QString CharConfig::text(int r, int i)
+{
+ QStringList l = r ? chars2 : chars1;
+ return i < (int)l.count() ? l[i] : QString::null;
+}
+bool CharConfig::spreadRow(int)
+{
+ return TRUE;
+}
+
+void CharConfig::pick(bool press, int row, int item)
+{
+ if ( !press ) {
+ if ( item >= 0 ) {
+ generateText(row == 0 ? chars1[item] : chars2[item]);
+ }
+ changeMode(0);
+ updateRows(0,1);
+ }
+}
+
+void CharConfig::addChar(int r, const QString& s)
+{
+ if ( r ) chars2.append(s); else chars1.append(s);
+}
+
+QString CharStringConfig::text(int r, int i)
+{
+ QStringList l = r ? chars : QStringList(input);
+ return i < (int)l.count() ? l[i] : QString::null;
+}
+
+bool CharStringConfig::spreadRow(int i)
+{
+ return i ? TRUE : FALSE;
+}
+
+void CharStringConfig::pick(bool press, int row, int item)
+{
+ if ( row == 0 ) {
+ if ( !press ) {
+ if ( item>=0 ) {
+ generateText(input);
+ }
+ input = "";
+ changeMode(0);
+ updateRows(0,1);
+ }
+ } else {
+ if ( press && item >= 0 ) {
+ input.append(chars[item]);
+ updateRows(0,0);
+ }
+ }
+}
+
+void CharStringConfig::addChar(const QString& s)
+{
+ chars.append(s);
+}
+
+void CharStringConfig::doMenu(int i)
+{
+ if ( i == 100 ) {
+ input = "";
+ updateRows(0,0);
+ }
+
+ StringConfig::doMenu(i);
+}
+
diff --git a/inputmethods/pickboard/pickboardcfg.h b/inputmethods/pickboard/pickboardcfg.h
new file mode 100644
index 0000000..e0dc0dd
--- a/dev/null
+++ b/inputmethods/pickboard/pickboardcfg.h
@@ -0,0 +1,213 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#ifndef PICKBOARDCFG_H
+#define PICKBOARDCFG_H
+
+#include <qpe/qdawg.h>
+
+#include <qpushbutton.h>
+#include <qhbuttongroup.h>
+#include <qdialog.h>
+#include <qlist.h>
+
+// Internal stuff...
+
+class PickboardPicks;
+
+class LetterButton : public QPushButton {
+ Q_OBJECT
+public:
+ LetterButton(const QChar& letter, QWidget* parent);
+private slots:
+ void toggleCase();
+private:
+ bool skip;
+};
+
+class LetterChoice : public QButtonGroup {
+ Q_OBJECT
+public:
+ LetterChoice(QWidget* parent, const QString& set);
+
+ QChar choice() { return ch; }
+
+signals:
+ void changed();
+
+private slots:
+ void change();
+
+private:
+ QChar ch;
+};
+
+class PickboardAdd : public QDialog {
+ Q_OBJECT
+public:
+ PickboardAdd(QWidget* owner, const QStringList& setlist);
+ ~PickboardAdd();
+
+ QString word() const;
+ bool exec();
+
+private slots:
+ void checkAllDone();
+
+private:
+ QPushButton *yes;
+ LetterChoice **lc;
+ int nlc;
+};
+
+class PickboardConfig : QObject {
+public:
+ PickboardConfig(PickboardPicks* p) : parent(p), nrows(2), pressx(-1) { }
+ virtual ~PickboardConfig();
+ virtual void pickPoint(const QPoint& p, bool press);
+ virtual void draw(QPainter*)=0;
+ virtual void fillMenu(QPopupMenu&);
+ virtual void doMenu(int);
+
+protected:
+ void updateRows(int from, int to);
+ virtual void updateItem(int r, int i);
+ virtual void pickInRow(int r, int xpos, bool press)=0;
+
+ void changeMode(int m);
+ virtual void generateText(const QString& s);
+ void generateKey( int k );
+
+ virtual void pick(bool press, int row, int item)=0;
+
+protected:
+ PickboardPicks* parent;
+ int nrows;
+private:
+ int pressrow, pressx;
+};
+
+class StringConfig : public PickboardConfig {
+public:
+ StringConfig(PickboardPicks* p) : PickboardConfig(p) { }
+
+ void draw(QPainter* p);
+
+protected:
+ virtual QString text(int r, int i)=0;
+ virtual bool spreadRow(int i)=0;
+ virtual QColor rowColor(int) { return Qt::black; }
+ virtual void pickInRow(int r, int xpos, bool press);
+ virtual void updateItem(int r, int i);
+ virtual bool highlight(int,int) const;
+};
+
+class CharStringConfig : public StringConfig {
+ QString input;
+ QStringList chars;
+public:
+ CharStringConfig(PickboardPicks* p) : StringConfig(p) { }
+
+ void addChar(const QString& s);
+ virtual void doMenu(int);
+
+protected:
+ QString text(int r, int i);
+ bool spreadRow(int i);
+ void pick(bool press, int row, int item);
+};
+
+class DictFilterConfig : public StringConfig {
+ QStringList matches;
+ QStringList sets;
+ QStringList othermodes;
+ int lit0;
+ int lit1;
+ int shift;
+ QString capitalize(const QString& s);
+ QStringList capitalize(const QStringList& s);
+
+public:
+ QStringList input;
+ DictFilterConfig(PickboardPicks* p) : StringConfig(p)
+ {
+ shift = 0;
+ lit0 = -1;
+ lit1 = -1;
+ }
+
+ void addSet(const QString& s);
+ void addMode(const QString& s);
+
+ void fillMenu(QPopupMenu& menu);
+ void doMenu(int i);
+
+ void add(const QString& set);
+
+protected:
+ QString text(int r, int i);
+
+ bool spreadRow(int i);
+
+ void pick(bool press, int row, int item);
+
+ bool scanMatch(const QString& set, const QChar& l) const;
+ void scan(const QDawg::Node* n, int ipos, const QString& str, int length, bool extend);
+ void scanLengths(const QDawg::Node* n, int ipos, int& bitarray);
+
+ bool highlight(int r,int c) const;
+};
+
+class CharConfig : public StringConfig {
+ QStringList chars1;
+ QStringList chars2;
+public:
+ CharConfig(PickboardPicks* p) : StringConfig(p) { }
+ void addChar(int r, const QString& s);
+
+protected:
+ QString text(int r, int i);
+ bool spreadRow(int);
+ void pick(bool press, int row, int item);
+};
+
+class KeycodeConfig : public PickboardConfig {
+ QValueList<int> keys1;
+ QValueList<int> keys2;
+ QValueList<QPixmap> keypm1;
+ QValueList<QPixmap> keypm2;
+ static const int xw = 8;
+ static const int xmarg = 8;
+
+public:
+ KeycodeConfig(PickboardPicks* p) : PickboardConfig(p) { }
+ void addKey(int r, const QPixmap& pm, int code);
+ void addGap(int r, int w);
+
+ void draw(QPainter* p);
+
+protected:
+ void pickInRow(int r, int xpos, bool press);
+ QValueList<QPixmap> row(int i);
+
+ void pick(bool press, int row, int item);
+};
+
+
+#endif
diff --git a/inputmethods/pickboard/pickboardimpl.cpp b/inputmethods/pickboard/pickboardimpl.cpp
new file mode 100644
index 0000000..a4e8f02
--- a/dev/null
+++ b/inputmethods/pickboard/pickboardimpl.cpp
@@ -0,0 +1,101 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#include <qapplication.h>
+#include <qobject.h>
+#include <qpixmap.h>
+#include "pickboard.h"
+#include "pickboardimpl.h"
+
+/* XPM */
+static const char * pb_xpm[]={
+"28 7 2 1",
+"# c #303030",
+" c None",
+" ########################## ",
+" # # # # # # # ",
+" # # # # # # # ",
+" ########################## ",
+" # # # # # # ",
+" # # # # # # ",
+" ########################## "};
+
+
+PickboardImpl::PickboardImpl()
+ : pickboard(0), icn(0), ref(0)
+{
+}
+
+PickboardImpl::~PickboardImpl()
+{
+ delete pickboard;
+ delete icn;
+}
+
+QWidget *PickboardImpl::inputMethod( QWidget *parent, Qt::WFlags f )
+{
+ if ( !pickboard )
+ pickboard = new Pickboard( parent, "pickboard", f );
+ return pickboard;
+}
+
+void PickboardImpl::resetState()
+{
+ if ( pickboard )
+ pickboard->resetState();
+}
+
+QPixmap *PickboardImpl::icon()
+{
+ if ( !icn )
+ icn = new QPixmap( (const char **)pb_xpm );
+ return icn;
+}
+
+QString PickboardImpl::name()
+{
+ return qApp->translate( "InputMethods", "Pickboard" );
+}
+
+void PickboardImpl::onKeyPress( QObject *receiver, const char *slot )
+{
+ if ( pickboard )
+ QObject::connect( pickboard, SIGNAL(key(ushort,ushort,ushort,bool,bool)), receiver, slot );
+}
+
+#ifndef QT_NO_COMPONENT
+QRESULT PickboardImpl::queryInterface( const QUuid &uuid, QUnknownInterface **iface )
+{
+ *iface = 0;
+ if ( uuid == IID_QUnknown )
+ *iface = this;
+ else if ( uuid == IID_InputMethod )
+ *iface = this;
+
+ if ( *iface )
+ (*iface)->addRef();
+ return QS_OK;
+}
+
+Q_EXPORT_INTERFACE()
+{
+ Q_CREATE_INSTANCE( PickboardImpl )
+}
+#endif
+
diff --git a/inputmethods/pickboard/pickboardimpl.h b/inputmethods/pickboard/pickboardimpl.h
new file mode 100644
index 0000000..4f23665
--- a/dev/null
+++ b/inputmethods/pickboard/pickboardimpl.h
@@ -0,0 +1,51 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#ifndef PICKBOARDIMPL_H
+#define PICKBOARDIMPL_H
+
+#include <qpe/inputmethodinterface.h>
+
+class Pickboard;
+class QPixmap;
+
+class PickboardImpl : public InputMethodInterface
+{
+public:
+ PickboardImpl();
+ virtual ~PickboardImpl();
+
+#ifndef QT_NO_COMPONENT
+ QRESULT queryInterface( const QUuid&, QUnknownInterface** );
+ Q_REFCOUNT
+#endif
+
+ virtual QWidget *inputMethod( QWidget *parent, Qt::WFlags f );
+ virtual void resetState();
+ virtual QPixmap *icon();
+ virtual QString name();
+ virtual void onKeyPress( QObject *receiver, const char *slot );
+
+private:
+ Pickboard *pickboard;
+ QPixmap *icn;
+ ulong ref;
+};
+
+#endif
diff --git a/inputmethods/pickboard/pickboardpicks.cpp b/inputmethods/pickboard/pickboardpicks.cpp
new file mode 100644
index 0000000..a80bbf8
--- a/dev/null
+++ b/inputmethods/pickboard/pickboardpicks.cpp
@@ -0,0 +1,418 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#include "pickboardpicks.h"
+#include "pickboardcfg.h"
+
+#include <qpe/global.h>
+
+#include <qpainter.h>
+#include <qlist.h>
+#include <qbitmap.h>
+#include <qlayout.h>
+#include <qvbox.h>
+#include <qdialog.h>
+#include <qscrollview.h>
+#include <qpopupmenu.h>
+#include <qhbuttongroup.h>
+#include <qpushbutton.h>
+#include <qmessagebox.h>
+#include <qwindowsystem_qws.h>
+
+void PickboardPicks::doMenu()
+{
+ QWidget* cause = (QWidget*)sender(); // evil
+
+ QPopupMenu popup(this);
+ config()->fillMenu(popup);
+
+ QPoint pos = cause->mapToGlobal(cause->rect().topRight());
+ QSize sz = popup.sizeHint();
+ pos.ry() -= sz.height();
+ pos.rx() -= sz.width();
+ popup.move(pos);
+ config()->doMenu(popup.exec());
+}
+
+static const char *BS_xpm[] = {
+"5 7 2 1",
+"a c #000000",
+". c None",
+"...aa",
+"..aaa",
+".aaaa",
+"aaaaa",
+".aaaa",
+"..aaa",
+"...aa",
+};
+static const char *Del_xpm[] = {
+"14 7 2 1",
+"a c #000000",
+". c None",
+"aaa..aaaa.a...",
+"a..a.a....a...",
+"a..a.a....a...",
+"a..a.aaa..a...",
+"a..a.a....a...",
+"a..a.a....a...",
+"aaa..aaaa.aaaa"
+};
+static const char *Home_xpm[] = {
+"20 7 2 1",
+"a c #000000",
+". c None",
+"a..a..aa..a...a.aaaa",
+"a..a.a..a.aa.aa.a...",
+"a..a.a..a.a.a.a.a...",
+"aaaa.a..a.a.a.a.aaa.",
+"a..a.a..a.a...a.a...",
+"a..a.a..a.a...a.a...",
+"a..a..aa..a...a.aaaa"
+};
+static const char *PgUp_xpm[] = {
+"20 7 2 1",
+"a c #000000",
+". c None",
+"aaa.......a..a......",
+"a..a......a..a......",
+"a..a.aa...a..a.aaa..",
+"aaa.a.....a..a.a..a.",
+"a...a.aa..a..a.aaa..",
+"a...a..a..a..a.a....",
+"a....aaa...aa..a...."
+};
+static const char *PgDn_xpm[] = {
+"20 7 2 1",
+"a c #000000",
+". c None",
+"aaa.......aaa.......",
+"a..a......a..a......",
+"a..a.aa...a..a.a..a.",
+"aaa.a.....a..a.aa.a.",
+"a...a.aa..a..a.a.aa.",
+"a...a..a..a..a.a..a.",
+"a....aaa..aaa..a..a."
+};
+static const char *End_xpm[] = {
+"14 7 2 1",
+"a c #000000",
+". c None",
+"aaaa.a..a.aaa.",
+"a....aa.a.a..a",
+"a....a.aa.a..a",
+"aaa..a..a.a..a",
+"a....a..a.a..a",
+"a....a..a.a..a",
+"aaaa.a..a.aaa."
+};
+static const char *Enter_xpm[] = {
+"14 7 2 1",
+"a c #000000",
+". c None",
+".............a",
+".............a",
+"..a..........a",
+".aa.........a.",
+"aaaaaaaaaaaa..",
+".aa...........",
+"..a..........."
+};
+static const char *Esc_xpm[] = {
+"14 7 2 1",
+"a c #000000",
+". c None",
+"aaaa..aa...aa.",
+"a....a..a.a..a",
+"a....a....a...",
+"aaa...aa..a...",
+"a.......a.a...",
+"a....a..a.a..a",
+"aaaa..aa...aa."
+};
+static const char *Ins_xpm[] = {
+"13 7 2 1",
+"a c #000000",
+". c None",
+"aaa.a..a..aa.",
+".a..aa.a.a..a",
+".a..a.aa.a...",
+".a..a..a..aa.",
+".a..a..a....a",
+".a..a..a.a..a",
+"aaa.a..a..aa."
+};
+static const char *Up_xpm[] = {
+"7 7 2 1",
+"a c #000000",
+". c None",
+"...a...",
+"..aaa..",
+".a.a.a.",
+"a..a..a",
+"...a...",
+"...a...",
+"...a..."
+};
+static const char *Left_xpm[] = {
+"7 7 2 1",
+"a c #000000",
+". c None",
+"...a...",
+"..a....",
+".a.....",
+"aaaaaaa",
+".a.....",
+"..a....",
+"...a..."
+};
+static const char *Down_xpm[] = {
+"7 7 2 1",
+"a c #000000",
+". c None",
+"...a...",
+"...a...",
+"...a...",
+"a..a..a",
+".a.a.a.",
+"..aaa..",
+"...a..."
+};
+static const char *Right_xpm[] = {
+"7 7 2 1",
+"a c #000000",
+". c None",
+"...a...",
+"....a..",
+".....a.",
+"aaaaaaa",
+".....a.",
+"....a..",
+"...a..."
+};
+static const char *BackTab_xpm[] = {
+"8 7 2 1",
+"a c #000000",
+". c None",
+"a.......",
+"a..a....",
+"a.aa....",
+"aaaaaaaa",
+"a.aa....",
+"a..a....",
+"a......."
+};
+static const char *Tab_xpm[] = {
+"8 7 2 1",
+"a c #000000",
+". c None",
+".......a",
+"....a..a",
+"....aa.a",
+"aaaaaaaa",
+"....aa.a",
+"....a..a",
+".......a"
+};
+static const char *Space_xpm[] = {
+"9 9 2 1",
+"a c #000000",
+". c None",
+"aaaaaaaaa",
+"a.......a",
+"a.......a",
+"a.......a",
+"a.......a",
+"a.......a",
+"a.......a",
+"a.......a",
+"aaaaaaaaa"
+};
+
+PickboardPicks::PickboardPicks(QWidget* parent, const char* name, WFlags f ) :
+ QFrame(parent,name,f)
+{
+}
+
+void PickboardPicks::initialise(void)
+{
+ setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed));
+ mode = 0;
+
+ DictFilterConfig* dc = new DictFilterConfig(this);
+ dc->addSet("ABC");
+ dc->addSet("DEF");
+ dc->addSet("GHI");
+ dc->addSet("JKL");
+ dc->addSet("MNO");
+ dc->addSet("PQR");
+ dc->addSet("STU");
+ dc->addSet("VWX");
+ dc->addSet("YZ-'");
+ dc->addMode("123");
+ dc->addMode("@*!?");
+ dc->addMode("KEY");
+ dc->addMode("Space");
+ dc->addMode("Back");
+ dc->addMode("Enter");
+ dc->addMode("Shift");
+ configs.append(dc);
+
+ CharStringConfig* number = new CharStringConfig(this);
+ number->addChar("0");
+ number->addChar("1");
+ number->addChar("2");
+ number->addChar("3");
+ number->addChar("4");
+ number->addChar("5");
+ number->addChar("6");
+ number->addChar("7");
+ number->addChar("8");
+ number->addChar("9");
+ number->addChar("."); // #### or "," in some locales
+ configs.append(number);
+
+ CharConfig* punc = new CharConfig(this);
+
+ punc->addChar(0,"\"");
+ punc->addChar(0,"`");
+ punc->addChar(0,"'");
+ punc->addChar(0,"\253");
+ punc->addChar(0,"\273");
+ punc->addChar(0,"\277");
+ punc->addChar(1,"(");
+ punc->addChar(1,")");
+ punc->addChar(1,"[");
+ punc->addChar(1,"]");
+ punc->addChar(1,"{");
+ punc->addChar(1,"}");
+
+ punc->addChar(0,"+");
+ punc->addChar(0,"-");
+ punc->addChar(0,"*");
+ punc->addChar(0,"/");
+ punc->addChar(0,"=");
+ punc->addChar(0,"_");
+ punc->addChar(0,"$");
+ punc->addChar(0,"&");
+ punc->addChar(1,"|");
+ punc->addChar(1,"@");
+ punc->addChar(1,"\\");
+ punc->addChar(1,"#");
+ punc->addChar(1,"^");
+ punc->addChar(1,"~");
+ punc->addChar(1,"<");
+ punc->addChar(1,">");
+
+ punc->addChar(0,".");
+ punc->addChar(0,"?");
+ punc->addChar(0,"!");
+ punc->addChar(0,",");
+ punc->addChar(0,";");
+ punc->addChar(1,":");
+ punc->addChar(1,"\267");
+ punc->addChar(1,"\277");
+ punc->addChar(1,"\241");
+ punc->addChar(1,"\367");
+
+ punc->addChar(0,"$");
+ punc->addChar(0,"\242");
+ punc->addChar(0,"\245");
+ punc->addChar(1,"\243");
+ punc->addChar(1,"\244");
+ punc->addChar(1,"\260");
+
+ configs.append(punc);
+
+ KeycodeConfig* keys = new KeycodeConfig(this);
+ keys->addKey(0,QPixmap(Esc_xpm),Key_Escape);
+ keys->addKey(0,QPixmap(BS_xpm),Key_Backspace);
+ keys->addGap(0,10);
+
+ keys->addKey(0,QPixmap(Ins_xpm),Key_Insert);
+ keys->addKey(0,QPixmap(Home_xpm),Key_Home);
+ keys->addKey(0,QPixmap(PgUp_xpm),Key_PageUp);
+
+ keys->addGap(0,25);
+ keys->addKey(0,QPixmap(Up_xpm),Key_Up);
+ keys->addGap(0,15);
+
+ keys->addKey(1,QPixmap(BackTab_xpm),Key_Tab);
+ keys->addGap(1,3);
+ keys->addKey(1,QPixmap(Tab_xpm),Key_Tab);
+ keys->addGap(1,10);
+
+ keys->addKey(1,QPixmap(Del_xpm),Key_Delete);
+ keys->addGap(1,2);
+ keys->addKey(1,QPixmap(End_xpm),Key_End);
+ keys->addGap(1,3);
+ keys->addKey(1,QPixmap(PgDn_xpm),Key_PageDown);
+
+ keys->addGap(1,10);
+ keys->addKey(1,QPixmap(Left_xpm),Key_Left);
+ keys->addKey(1,QPixmap(Down_xpm),Key_Down);
+ keys->addKey(1,QPixmap(Right_xpm),Key_Right);
+
+ keys->addGap(1,13);
+ keys->addKey(1,QPixmap(Space_xpm),Key_Space);
+
+ keys->addGap(0,10);
+ keys->addKey(0,QPixmap(Enter_xpm),Key_Return);
+
+ configs.append(keys);
+}
+
+PickboardPicks::~PickboardPicks()
+{
+}
+
+QSize PickboardPicks::sizeHint() const
+{
+ return QSize(240,fontMetrics().lineSpacing()*2+3);
+}
+
+void PickboardPicks::drawContents(QPainter* p)
+{
+ config()->draw(p);
+}
+
+void PickboardPicks::mousePressEvent(QMouseEvent* e)
+{
+ config()->pickPoint(e->pos(),TRUE);
+}
+
+void PickboardPicks::mouseDoubleClickEvent(QMouseEvent* e)
+{
+ config()->pickPoint(e->pos(),TRUE);
+}
+
+void PickboardPicks::mouseReleaseEvent(QMouseEvent* e)
+{
+ config()->pickPoint(e->pos(),FALSE);
+}
+
+void PickboardPicks::setMode(int m)
+{
+ mode = m;
+}
+
+void PickboardPicks::resetState()
+{
+ config()->doMenu(100);
+}
diff --git a/inputmethods/pickboard/pickboardpicks.h b/inputmethods/pickboard/pickboardpicks.h
new file mode 100644
index 0000000..1881e92
--- a/dev/null
+++ b/inputmethods/pickboard/pickboardpicks.h
@@ -0,0 +1,66 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#ifndef PICKBOARDPICKS_H
+#define PICKBOARDPICKS_H
+
+#include <qframe.h>
+#include <qlist.h>
+
+// Internal stuff...
+
+class PickboardConfig;
+
+class PickboardPicks : public QFrame {
+ Q_OBJECT
+public:
+ PickboardPicks(QWidget* parent=0, const char* name=0, WFlags f=0);
+ ~PickboardPicks();
+ QSize sizeHint() const;
+ void initialise();
+ void setMode(int);
+ int currentMode() const { return mode; }
+
+ void mousePressEvent(QMouseEvent*);
+
+ void emitKey( ushort scan, ushort uni, ushort mod, bool press, bool repeat )
+ { key(scan,uni,mod,press, repeat); }
+ void resetState();
+
+signals:
+ void key( ushort scan, ushort uni, ushort mod, bool, bool );
+
+public slots:
+ void doMenu();
+
+protected:
+ void drawContents( QPainter * );
+ void mouseDoubleClickEvent(QMouseEvent*);
+ void mouseReleaseEvent(QMouseEvent*);
+
+protected:
+ int mode;
+ QList<PickboardConfig> configs;
+
+private:
+ PickboardConfig* config() { return configs.at(mode); }
+};
+
+
+#endif
diff --git a/inputmethods/pickboard/qpe-pickboard.control b/inputmethods/pickboard/qpe-pickboard.control
new file mode 100644
index 0000000..8d12181
--- a/dev/null
+++ b/inputmethods/pickboard/qpe-pickboard.control
@@ -0,0 +1,9 @@
+Files: plugins/inputmethods/libqpickboard.so*
+Priority: optional
+Section: qpe/inputmethods
+Maintainer: Warwick Allison <warwick@trolltech.com>
+Architecture: arm
+Version: $QPE_VERSION-3
+Depends: qpe-base ($QPE_VERSION)
+Description: Pickboard input method
+ Pickboard dictionary-based input method for the Qtopia environment.
diff --git a/inputmethods/pickboard/qpe-pickboard.postinst b/inputmethods/pickboard/qpe-pickboard.postinst
new file mode 100755
index 0000000..c254b01
--- a/dev/null
+++ b/inputmethods/pickboard/qpe-pickboard.postinst
@@ -0,0 +1,2 @@
+#!/bin/sh
+/opt/QtPalmtop/bin/qcop QPE/TaskBar "reloadInputMethods()"
diff --git a/inputmethods/pickboard/qpe-pickboard.postrm b/inputmethods/pickboard/qpe-pickboard.postrm
new file mode 100755
index 0000000..c254b01
--- a/dev/null
+++ b/inputmethods/pickboard/qpe-pickboard.postrm
@@ -0,0 +1,2 @@
+#!/bin/sh
+/opt/QtPalmtop/bin/qcop QPE/TaskBar "reloadInputMethods()"
diff --git a/inputmethods/unikeyboard/.cvsignore b/inputmethods/unikeyboard/.cvsignore
new file mode 100644
index 0000000..edfa921
--- a/dev/null
+++ b/inputmethods/unikeyboard/.cvsignore
@@ -0,0 +1,3 @@
+moc_*
+*.moc
+Makefile
diff --git a/inputmethods/unikeyboard/Makefile.in b/inputmethods/unikeyboard/Makefile.in
new file mode 100644
index 0000000..ebbab50
--- a/dev/null
+++ b/inputmethods/unikeyboard/Makefile.in
@@ -0,0 +1,115 @@
+#############################################################################
+
+####### Compiler, tools and options
+
+CXX = $(SYSCONF_CXX) $(QT_CXX_MT)
+CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) $(SYSCONF_CXXFLAGS_LIB)
+CC = $(SYSCONF_CC) $(QT_C_MT)
+CFLAGS = $(SYSCONF_CFLAGS) $(SYSCONF_CFLAGS_LIB)
+INCPATH = -I$(QPEDIR)/include
+LFLAGS = $(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT)
+LIBS = $(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS_QTAPP)
+MOC = $(SYSCONF_MOC)
+UIC = $(SYSCONF_UIC)
+
+####### Target
+
+DESTDIR = ../../plugins/inputmethods/
+VER_MAJ = 1
+VER_MIN = 0
+VER_PATCH = 0
+TARGET = qunikeyboard
+TARGET1 = lib$(TARGET).so.$(VER_MAJ)
+
+####### Files
+
+HEADERS = unikeyboard.h \
+ unikeyboardimpl.h
+SOURCES = unikeyboard.cpp \
+ unikeyboardimpl.cpp
+OBJECTS = unikeyboard.o \
+ unikeyboardimpl.o
+INTERFACES =
+UICDECLS =
+UICIMPLS =
+SRCMOC = moc_unikeyboard.cpp
+OBJMOC = moc_unikeyboard.o
+
+
+####### Implicit rules
+
+.SUFFIXES: .cpp .cxx .cc .C .c
+
+.cpp.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.cxx.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.cc.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.C.o:
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
+
+####### Build rules
+
+
+all: $(DESTDIR)$(SYSCONF_LINK_TARGET)
+
+$(DESTDIR)$(SYSCONF_LINK_TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS)
+ $(SYSCONF_LINK_LIB)
+
+moc: $(SRCMOC)
+
+tmake:
+ tmake unikeyboard.pro
+
+clean:
+ -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS)
+ -rm -f *~ core
+ -rm -f allmoc.cpp
+
+####### Extension Modules
+
+listpromodules:
+ @echo
+
+listallmodules:
+ @echo
+
+listaddonpromodules:
+ @echo
+
+listaddonentmodules:
+ @echo
+
+
+REQUIRES=
+
+####### Sub-libraries
+
+
+###### Combined headers
+
+
+
+####### Compile
+
+unikeyboard.o: unikeyboard.cpp \
+ unikeyboard.h
+
+unikeyboardimpl.o: unikeyboardimpl.cpp \
+ unikeyboard.h \
+ unikeyboardimpl.h
+
+moc_unikeyboard.o: moc_unikeyboard.cpp \
+ unikeyboard.h
+
+moc_unikeyboard.cpp: unikeyboard.h
+ $(MOC) unikeyboard.h -o moc_unikeyboard.cpp
+
+
diff --git a/inputmethods/unikeyboard/qpe-unikeyboard.control b/inputmethods/unikeyboard/qpe-unikeyboard.control
new file mode 100644
index 0000000..a8c9bd3
--- a/dev/null
+++ b/inputmethods/unikeyboard/qpe-unikeyboard.control
@@ -0,0 +1,9 @@
+Files: plugins/inputmethods/libqunikeyboard.so*
+Priority: optional
+Section: qpe/inputmethods
+Maintainer: Warwick Allison <warwick@trolltech.com>
+Architecture: arm
+Version: $QPE_VERSION-3
+Depends: qpe-base ($QPE_VERSION)
+Description: Unicode input method
+ Basic unicode input method for the Qtopia environment.
diff --git a/inputmethods/unikeyboard/qpe-unikeyboard.postinst b/inputmethods/unikeyboard/qpe-unikeyboard.postinst
new file mode 100755
index 0000000..c254b01
--- a/dev/null
+++ b/inputmethods/unikeyboard/qpe-unikeyboard.postinst
@@ -0,0 +1,2 @@
+#!/bin/sh
+/opt/QtPalmtop/bin/qcop QPE/TaskBar "reloadInputMethods()"
diff --git a/inputmethods/unikeyboard/qpe-unikeyboard.postrm b/inputmethods/unikeyboard/qpe-unikeyboard.postrm
new file mode 100755
index 0000000..c254b01
--- a/dev/null
+++ b/inputmethods/unikeyboard/qpe-unikeyboard.postrm
@@ -0,0 +1,2 @@
+#!/bin/sh
+/opt/QtPalmtop/bin/qcop QPE/TaskBar "reloadInputMethods()"
diff --git a/inputmethods/unikeyboard/unikeyboard.cpp b/inputmethods/unikeyboard/unikeyboard.cpp
new file mode 100644
index 0000000..aa74c66
--- a/dev/null
+++ b/inputmethods/unikeyboard/unikeyboard.cpp
@@ -0,0 +1,278 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include "unikeyboard.h"
+
+#include <qpe/fontmanager.h>
+
+#include <qpainter.h>
+#include <qfontmetrics.h>
+#include <qcombobox.h>
+#if defined(Q_WS_QWS) || defined(_WS_QWS_)
+#include <qwindowsystem_qws.h>
+#endif
+
+static const int nw = 8;
+
+typedef struct BlockMap {
+ ushort start;
+ ushort stop;
+ const char *name;
+};
+
+//# Start Code; Block Name
+
+static const BlockMap blockMap[] =
+{
+{0x0000, 0x007F, "Basic Latin"},
+{0x0080, 0x00FF, "Latin-1 Supplement"},
+{0x0100, 0x017F, "Latin Extended-A"},
+{0x0180, 0x024F, "Latin Extended-B"},
+{0x0250, 0x02AF, "IPA Extensions"},
+{0x02B0, 0x02FF, "Spacing Modifier Letters"},
+{0x0300, 0x036F, "Combining Diacritical Marks"},
+{0x0370, 0x03FF, "Greek"},
+{0x0400, 0x04FF, "Cyrillic"},
+{0x0530, 0x058F, "Armenian"},
+{0x0590, 0x05FF, "Hebrew"},
+{0x0600, 0x06FF, "Arabic"},
+{0x0700, 0x074F, "Syriac "},
+{0x0780, 0x07BF, "Thaana"},
+{0x0900, 0x097F, "Devanagari"},
+{0x0980, 0x09FF, "Bengali"},
+{0x0A00, 0x0A7F, "Gurmukhi"},
+{0x0A80, 0x0AFF, "Gujarati"},
+{0x0B00, 0x0B7F, "Oriya"},
+{0x0B80, 0x0BFF, "Tamil"},
+{0x0C00, 0x0C7F, "Telugu"},
+{0x0C80, 0x0CFF, "Kannada"},
+{0x0D00, 0x0D7F, "Malayalam"},
+{0x0D80, 0x0DFF, "Sinhala"},
+{0x0E00, 0x0E7F, "Thai"},
+{0x0E80, 0x0EFF, "Lao"},
+{0x0F00, 0x0FFF, "Tibetan"},
+{0x1000, 0x109F, "Myanmar "},
+{0x10A0, 0x10FF, "Georgian"},
+{0x1100, 0x11FF, "Hangul Jamo"},
+{0x1200, 0x137F, "Ethiopic"},
+{0x13A0, 0x13FF, "Cherokee"},
+{0x1400, 0x167F, "Unified Canadian Aboriginal Syllabics"},
+{0x1680, 0x169F, "Ogham"},
+{0x16A0, 0x16FF, "Runic"},
+{0x1780, 0x17FF, "Khmer"},
+{0x1800, 0x18AF, "Mongolian"},
+{0x1E00, 0x1EFF, "Latin Extended Additional"},
+{0x1F00, 0x1FFF, "Greek Extended"},
+{0x2000, 0x206F, "General Punctuation"},
+{0x2070, 0x209F, "Superscripts and Subscripts"},
+{0x20A0, 0x20CF, "Currency Symbols"},
+{0x20D0, 0x20FF, "Combining Marks for Symbols"},
+{0x2100, 0x214F, "Letterlike Symbols"},
+{0x2150, 0x218F, "Number Forms"},
+{0x2190, 0x21FF, "Arrows"},
+{0x2200, 0x22FF, "Mathematical Operators"},
+{0x2300, 0x23FF, "Miscellaneous Technical"},
+{0x2400, 0x243F, "Control Pictures"},
+{0x2440, 0x245F, "Optical Character Recognition"},
+{0x2460, 0x24FF, "Enclosed Alphanumerics"},
+{0x2500, 0x257F, "Box Drawing"},
+{0x2580, 0x259F, "Block Elements"},
+{0x25A0, 0x25FF, "Geometric Shapes"},
+{0x2600, 0x26FF, "Miscellaneous Symbols"},
+{0x2700, 0x27BF, "Dingbats"},
+{0x2800, 0x28FF, "Braille Patterns"},
+{0x2E80, 0x2EFF, "CJK Radicals Supplement"},
+{0x2F00, 0x2FDF, "Kangxi Radicals"},
+{0x2FF0, 0x2FFF, "Ideographic Description Characters"},
+{0x3000, 0x303F, "CJK Symbols and Punctuation"},
+{0x3040, 0x309F, "Hiragana"},
+{0x30A0, 0x30FF, "Katakana"},
+{0x3100, 0x312F, "Bopomofo"},
+{0x3130, 0x318F, "Hangul Compatibility Jamo"},
+{0x3190, 0x319F, "Kanbun"},
+{0x31A0, 0x31BF, "Bopomofo Extended"},
+{0x3200, 0x32FF, "Enclosed CJK Letters and Months"},
+{0x3300, 0x33FF, "CJK Compatibility"},
+{0x3400, 0x4DB5, "CJK Unified Ideographs Extension A"},
+{0x4E00, 0x9FFF, "CJK Unified Ideographs"},
+{0xA000, 0xA48F, "Yi Syllables"},
+{0xA490, 0xA4CF, "Yi Radicals"},
+{0xAC00, 0xD7A3, "Hangul Syllables"},
+{0xD800, 0xDB7F, "High Surrogates"},
+{0xDB80, 0xDBFF, "High Private Use Surrogates"},
+{0xDC00, 0xDFFF, "Low Surrogates"},
+{0xE000, 0xF8FF, "Private Use"},
+{0xF900, 0xFAFF, "CJK Compatibility Ideographs"},
+{0xFB00, 0xFB4F, "Alphabetic Presentation Forms"},
+{0xFB50, 0xFDFF, "Arabic Presentation Forms-A"},
+{0xFE20, 0xFE2F, "Combining Half Marks"},
+{0xFE30, 0xFE4F, "CJK Compatibility Forms"},
+{0xFE50, 0xFE6F, "Small Form Variants"},
+{0xFE70, 0xFEFE, "Arabic Presentation Forms-B"},
+{0xFF00, 0xFEFF, "Halfwidth and Fullwidth Forms"},
+{0xFFF0, 0xFFEF, "Specials"},
+{0xFFFF, 0xFFFF, 0} };
+
+
+UniScrollview::UniScrollview(QWidget* parent, const char* name, int f) :
+ QScrollView(parent, name, f)
+{
+ // smallFont.setRawName( "-adobe-courier-medium-r-normal--10-100-75-75-m-60-iso8859-1" ); //######
+ smallFont = QFont( "Helvetica", 8 );
+ QFontMetrics sfm( smallFont );
+ xoff = sfm.width( "AAA" );
+ setFont( FontManager::unicodeFont( FontManager::Fixed ) );
+ QFontMetrics fm( font() );
+ cellsize = fm.lineSpacing() + 2;
+ resizeContents( cellsize*nw, cellsize*65536/nw );
+ verticalScrollBar()->setLineStep(cellsize);
+
+ viewport()->setBackgroundMode( QWidget::PaletteBase );
+}
+
+
+
+void UniScrollview::contentsMousePressEvent(QMouseEvent* e)
+{
+ if ( e->x() < xoff || e->x() > xoff + nw*cellsize )
+ return;
+ int row = e->y()/cellsize;
+ int col = (e->x()-xoff)/cellsize;
+ int u = row*nw+col;
+#if defined(Q_WS_QWS) || defined(_WS_QWS_)
+ emit key( u, 0, 0, true, false );
+ emit key( u, 0, 0, false, false );
+#endif
+}
+
+
+void UniScrollview::contentsMouseReleaseEvent(QMouseEvent*)
+{
+}
+
+void UniScrollview::scrollTo( int unicode )
+{
+ int row = unicode / nw;
+ setContentsPos( 0, row*cellsize );
+}
+
+
+void UniScrollview::drawContents( QPainter *p, int /*cx*/, int cy, int /*cw*/, int ch )
+{
+ QFontMetrics fm = fontMetrics();
+ int row = cy / cellsize;
+ int y = row*cellsize;
+ while ( y < cy+ch ) {
+ p->drawLine( xoff, y, xoff+nw*cellsize, y );
+ if ( row*nw%16 == 0 ) {
+ p->setFont( smallFont );
+ QString s;
+ s.sprintf( "%03X", row*nw/16 );
+ p->drawText( 0, y, xoff, cellsize, AlignLeft, s );
+ p->setFont( font() );
+ }
+ for ( int i = 0; i < nw; i++ ) {
+ p->drawLine( xoff+i*cellsize, y, xoff+i*cellsize, y+cellsize );
+ QChar u = row*nw + i;
+ if ( fm.inFont( u ) )
+ p->drawText( xoff+i*cellsize, y, cellsize, cellsize, AlignCenter,
+ u );
+ }
+ p->drawLine( xoff+nw*cellsize, y, xoff+nw*cellsize, y+cellsize );
+ row++;
+ y += cellsize;
+ }
+}
+
+
+
+
+UniKeyboard::UniKeyboard(QWidget* parent, const char* name, int f )
+ : QFrame( parent, name, f )
+{
+ setFrameStyle( NoFrame );
+ sv = new UniScrollview( this );
+ cb = new QComboBox( FALSE, this );
+ currentBlock = 0;
+ QFontMetrics fm = sv->fontMetrics();
+ cbmap = new int[sizeof(blockMap)/sizeof(blockMap[0])];
+ for ( int i = 0; blockMap[i].name; i++ ) {
+ bool any=FALSE;
+ for ( int c=blockMap[i].start; !any && c<=blockMap[i].stop; c++ )
+ any = fm.inFont(QChar(c));
+ if ( any ) {
+ cbmap[cb->count()]=i;
+ cb->insertItem( blockMap[i].name );
+ }
+ }
+ connect( cb, SIGNAL( activated(int)), this, SLOT( handleCombo(int)) );
+ connect( sv, SIGNAL( contentsMoving(int,int)), this, SLOT( svMove(int,int)) );
+ connect( sv, SIGNAL( key(ushort,ushort,ushort,bool,bool)),
+ this, SIGNAL( key(ushort,ushort,ushort,bool,bool)) );
+}
+
+UniKeyboard::~UniKeyboard()
+{
+ delete [] cbmap;
+}
+
+void UniKeyboard::resizeEvent(QResizeEvent *)
+{
+ int d = frameWidth();
+ cb->setGeometry( d, d, width()-2*d, cb->sizeHint().height() );
+ sv->setGeometry( d, cb->height()+d, width()-2*d, height()-cb->height()-2*d );
+}
+
+void UniKeyboard::svMove( int /*x*/, int y )
+{
+ int cs = sv->cellSize();
+ int u = ((y+cs-1)/cs) * nw;
+ int i = currentBlock;
+ while ( i > 0 && blockMap[i].start > u ) {
+ i--;
+ }
+ while ( blockMap[i+1].name && blockMap[i+1].start < u ) {
+ i++;
+ }
+ if ( i != currentBlock ) {
+ currentBlock = i;
+ for (int ind=0; ind<cb->count(); ind++) {
+ if ( cbmap[ind] == i ) {
+ cb->setCurrentItem( ind );
+ break;
+ }
+ }
+ }
+}
+
+void UniKeyboard::handleCombo( int i )
+{
+ currentBlock = cbmap[i];
+ sv->scrollTo( blockMap[currentBlock].start );
+}
+
+void UniKeyboard::resetState()
+{
+}
+
+QSize UniKeyboard::sizeHint() const
+{
+ return QSize( 240, 2+sv->cellSize()*4+cb->sizeHint().height() );
+}
diff --git a/inputmethods/unikeyboard/unikeyboard.h b/inputmethods/unikeyboard/unikeyboard.h
new file mode 100644
index 0000000..1a716c0
--- a/dev/null
+++ b/inputmethods/unikeyboard/unikeyboard.h
@@ -0,0 +1,77 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#include <qscrollview.h>
+
+class QComboBox;
+
+class UniScrollview : public QScrollView {
+ Q_OBJECT
+public:
+ UniScrollview(QWidget* parent=0, const char* name=0, int f=0);
+ int cellSize() const { return cellsize; }
+
+signals:
+ void key( ushort unicode, ushort scancode, ushort modifiers, bool, bool );
+
+public slots:
+ void scrollTo( int unicode );
+
+protected:
+ void contentsMousePressEvent(QMouseEvent*);
+ void contentsMouseReleaseEvent(QMouseEvent*);
+ void drawContents( QPainter *, int cx, int cy, int cw, int ch ) ;
+
+private:
+ int cellsize;
+ QFont smallFont;
+ int xoff;
+};
+
+
+class UniKeyboard : public QFrame
+{
+ Q_OBJECT
+public:
+ UniKeyboard(QWidget* parent=0, const char* name=0, int f=0);
+ ~UniKeyboard();
+
+ void resetState();
+
+ QSize sizeHint() const;
+
+signals:
+ void key( ushort, ushort, ushort, bool, bool );
+
+protected:
+ void resizeEvent(QResizeEvent *);
+
+private slots:
+ void handleCombo( int );
+ void svMove( int, int );
+
+private:
+ UniScrollview *sv;
+ QComboBox *cb;
+ int currentBlock;
+ int* cbmap;
+};
+
+
+
diff --git a/inputmethods/unikeyboard/unikeyboard.pro b/inputmethods/unikeyboard/unikeyboard.pro
new file mode 100644
index 0000000..c0aad42
--- a/dev/null
+++ b/inputmethods/unikeyboard/unikeyboard.pro
@@ -0,0 +1,12 @@
+TEMPLATE = lib
+CONFIG += qt warn_on release
+HEADERS = unikeyboard.h unikeyboardimpl.h
+SOURCES = unikeyboard.cpp unikeyboardimpl.cpp
+TARGET = qunikeyboard
+DESTDIR = ../../plugins/inputmethods
+INCLUDEPATH += $(QPEDIR)/include
+DEPENDPATH += ../$(QPEDIR)/include ../../taskbar
+LIBS += -lqpe
+VERSION = 1.0.0
+
+TRANSLATIONS += ../../i18n/de/libqunikeyboard.ts
diff --git a/inputmethods/unikeyboard/unikeyboardimpl.cpp b/inputmethods/unikeyboard/unikeyboardimpl.cpp
new file mode 100644
index 0000000..fe601e0
--- a/dev/null
+++ b/inputmethods/unikeyboard/unikeyboardimpl.cpp
@@ -0,0 +1,105 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#include <qapplication.h>
+#include <qobject.h>
+#include <qpixmap.h>
+#include "unikeyboard.h"
+#include "unikeyboardimpl.h"
+
+/* XPM */
+static const char * uni_xpm[]={
+"28 13 2 1",
+"# c #000000",
+". c None",
+"............................",
+"...####....#####.....####...",
+"...####....######....####...",
+"...####....#######..........",
+"...####....########..####...",
+"...####....####.####.####...",
+"...####....####..########...",
+"...####....####...#######...",
+"...####....####....######...",
+"...#####..#####.....#####...",
+"....##########.......####...",
+"......######..........###...",
+"............................"};
+
+UniKeyboardImpl::UniKeyboardImpl()
+ : input(0), icn(0), ref(0)
+{
+}
+
+UniKeyboardImpl::~UniKeyboardImpl()
+{
+ delete input;
+ delete icn;
+}
+
+QWidget *UniKeyboardImpl::inputMethod( QWidget *parent, Qt::WFlags f )
+{
+ if ( !input )
+ input = new UniKeyboard( parent, "UniKeyboard", f );
+ return input;
+}
+
+void UniKeyboardImpl::resetState()
+{
+ if ( input )
+ input->resetState();
+}
+
+QPixmap *UniKeyboardImpl::icon()
+{
+ if ( !icn )
+ icn = new QPixmap( (const char **)uni_xpm );
+ return icn;
+}
+
+QString UniKeyboardImpl::name()
+{
+ return qApp->translate( "InputMethods", "Unicode" );
+}
+
+void UniKeyboardImpl::onKeyPress( QObject *receiver, const char *slot )
+{
+ if ( input )
+ QObject::connect( input, SIGNAL(key(ushort,ushort,ushort,bool,bool)), receiver, slot );
+}
+
+QRESULT UniKeyboardImpl::queryInterface( const QUuid &uuid, QUnknownInterface **iface )
+{
+ *iface = 0;
+ if ( uuid == IID_QUnknown )
+ *iface = this;
+ else if ( uuid == IID_InputMethod )
+ *iface = this;
+
+ if ( *iface )
+ (*iface)->addRef();
+ return QS_OK;
+}
+
+Q_EXPORT_INTERFACE()
+{
+ Q_CREATE_INSTANCE( UniKeyboardImpl )
+}
+
+
diff --git a/inputmethods/unikeyboard/unikeyboardimpl.h b/inputmethods/unikeyboard/unikeyboardimpl.h
new file mode 100644
index 0000000..97b1ff6
--- a/dev/null
+++ b/inputmethods/unikeyboard/unikeyboardimpl.h
@@ -0,0 +1,49 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#ifndef UNIKEYBOARDIMPL_H
+#define UNIKEYBOARDIMPL_H
+
+#include <qpe/inputmethodinterface.h>
+
+class UniKeyboard;
+class QPixmap;
+
+class UniKeyboardImpl : public InputMethodInterface
+{
+public:
+ UniKeyboardImpl();
+ virtual ~UniKeyboardImpl();
+
+ QRESULT queryInterface( const QUuid&, QUnknownInterface** );
+ Q_REFCOUNT
+
+ virtual QWidget *inputMethod( QWidget *parent, Qt::WFlags f );
+ virtual void resetState();
+ virtual QPixmap *icon();
+ virtual QString name();
+ virtual void onKeyPress( QObject *receiver, const char *slot );
+
+private:
+ UniKeyboard *input;
+ QPixmap *icn;
+ ulong ref;
+};
+
+#endif