Added support for UTF-8 keyboard entry and completion of location labels.
parent
5e3d7f157b
commit
ed0a3aa3dd
|
@ -620,7 +620,7 @@ Body* PlanetarySystem::find(string _name, bool deepSearch) const
|
|||
for (vector<Body*>::const_iterator iter = satellites.begin();
|
||||
iter != satellites.end(); iter++)
|
||||
{
|
||||
if (compareIgnoringCase((*iter)->getName(), _name) == 0)
|
||||
if (UTF8StringCompare((*iter)->getName(), _name) == 0)
|
||||
{
|
||||
return *iter;
|
||||
}
|
||||
|
@ -657,10 +657,11 @@ bool PlanetarySystem::traverse(TraversalFunc func, void* info) const
|
|||
std::vector<std::string> PlanetarySystem::getCompletion(const std::string& _name, bool rec) const
|
||||
{
|
||||
std::vector<std::string> completion;
|
||||
|
||||
for (vector<Body*>::const_iterator iter = satellites.begin();
|
||||
iter != satellites.end(); iter++)
|
||||
{
|
||||
if (compareIgnoringCase((*iter)->getName(), _name, _name.length()) == 0)
|
||||
if (UTF8StringCompare((*iter)->getName(), _name, _name.length()) == 0)
|
||||
{
|
||||
completion.push_back((*iter)->getName());
|
||||
}
|
||||
|
|
|
@ -449,13 +449,21 @@ Selection Simulation::findObjectFromPath(string s)
|
|||
}
|
||||
|
||||
|
||||
std::vector<std::string> Simulation::getObjectCompletion(string s)
|
||||
std::vector<std::string> Simulation::getObjectCompletion(string s, bool withLocations)
|
||||
{
|
||||
Selection path[2];
|
||||
int nPathEntries = 0;
|
||||
|
||||
if (!selection.empty())
|
||||
path[nPathEntries++] = selection;
|
||||
if (!selection.empty()) {
|
||||
if (selection.getType() == Selection::Type_Location)
|
||||
{
|
||||
path[nPathEntries++] = Selection(selection.location()->getParentBody());
|
||||
}
|
||||
else
|
||||
{
|
||||
path[nPathEntries++] = selection;
|
||||
}
|
||||
}
|
||||
|
||||
if (closestSolarSystem != NULL &&
|
||||
closestSolarSystem != universe->getSolarSystem(selection))
|
||||
|
@ -463,7 +471,7 @@ std::vector<std::string> Simulation::getObjectCompletion(string s)
|
|||
path[nPathEntries++] = Selection(closestSolarSystem->getStar());
|
||||
}
|
||||
|
||||
return universe->getCompletionPath(s, path, nPathEntries);
|
||||
return universe->getCompletionPath(s, path, nPathEntries, withLocations);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ class Simulation
|
|||
void selectPlanet(int);
|
||||
Selection findObject(std::string s);
|
||||
Selection findObjectFromPath(std::string s);
|
||||
std::vector<std::string> getObjectCompletion(std::string s);
|
||||
std::vector<std::string> getObjectCompletion(std::string s, bool withLocations = false);
|
||||
void gotoSelection(double gotoTime,
|
||||
Vec3f up, astro::CoordinateSystem upFrame);
|
||||
void gotoSelection(double gotoTime, double distance,
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <celutil/util.h>
|
||||
#include <celutil/debug.h>
|
||||
#include <celutil/utf8.h>
|
||||
#include "celestia.h"
|
||||
#include "star.h"
|
||||
#include "starname.h"
|
||||
|
@ -97,7 +98,7 @@ std::vector<std::string> StarNameDatabase::getCompletion(const std::string& name
|
|||
for (NameIndex::const_iterator iter = nameIndex.begin();
|
||||
iter != nameIndex.end() ; iter++)
|
||||
{
|
||||
if (!compareIgnoringCase(iter->first, name, name.length()))
|
||||
if (!UTF8StringCompare(iter->first, name, name.length()))
|
||||
{
|
||||
completion.push_back(iter->first);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <celmath/mathlib.h>
|
||||
#include <celmath/vecmath.h>
|
||||
#include <celmath/intersect.h>
|
||||
#include <celutil/utf8.h>
|
||||
#include "astro.h"
|
||||
#include "3dsmesh.h"
|
||||
#include "meshmanager.h"
|
||||
|
@ -818,7 +819,7 @@ Selection Universe::find(const string& s,
|
|||
for (DeepSkyCatalog::const_iterator iter = deepSkyCatalog->begin();
|
||||
iter != deepSkyCatalog->end(); iter++)
|
||||
{
|
||||
if (compareIgnoringCase((*iter)->getName(), s) == 0)
|
||||
if (UTF8StringCompare((*iter)->getName(), s) == 0)
|
||||
return Selection(*iter);
|
||||
}
|
||||
}
|
||||
|
@ -879,13 +880,24 @@ Selection Universe::findPath(const string& s,
|
|||
|
||||
std::vector<std::string> Universe::getCompletion(const string& s,
|
||||
Selection* contexts,
|
||||
int nContexts)
|
||||
int nContexts,
|
||||
bool withLocations)
|
||||
{
|
||||
std::vector<std::string> completion;
|
||||
|
||||
// solar bodies first
|
||||
for (int i = 0; i < nContexts; i++)
|
||||
{
|
||||
if (withLocations && contexts[i].getType() == Selection::Type_Body) {
|
||||
std::vector<Location*>* locations = contexts[i].body()->getLocations();
|
||||
for (vector<Location*>::const_iterator iter = locations->begin();
|
||||
iter != locations->end(); iter++)
|
||||
{
|
||||
if (!UTF8StringCompare(s, (*iter)->getName(), s.length()))
|
||||
completion.push_back((*iter)->getName());
|
||||
}
|
||||
}
|
||||
|
||||
SolarSystem* sys = getSolarSystem(contexts[i]);
|
||||
if (sys != NULL)
|
||||
{
|
||||
|
@ -905,7 +917,7 @@ std::vector<std::string> Universe::getCompletion(const string& s,
|
|||
for (DeepSkyCatalog::const_iterator iter = deepSkyCatalog->begin();
|
||||
iter != deepSkyCatalog->end(); iter++)
|
||||
{
|
||||
if (compareIgnoringCase((*iter)->getName(), s, s.length()) == 0)
|
||||
if (UTF8StringCompare((*iter)->getName(), s, s.length()) == 0)
|
||||
completion.push_back(Selection(*iter).getName());
|
||||
}
|
||||
}
|
||||
|
@ -919,13 +931,16 @@ std::vector<std::string> Universe::getCompletion(const string& s,
|
|||
|
||||
std::vector<std::string> Universe::getCompletionPath(const string& s,
|
||||
Selection* contexts,
|
||||
int nContexts)
|
||||
int nContexts,
|
||||
bool withLocations)
|
||||
{
|
||||
std::vector<std::string> completion;
|
||||
std::vector<std::string> locationCompletion;
|
||||
|
||||
string::size_type pos = s.rfind('/', s.length());
|
||||
|
||||
if (pos == string::npos)
|
||||
return getCompletion(s, contexts, nContexts);
|
||||
return getCompletion(s, contexts, nContexts, withLocations);
|
||||
|
||||
string base(s, 0, pos);
|
||||
Selection sel = findPath(base, contexts, nContexts);
|
||||
|
@ -943,6 +958,16 @@ std::vector<std::string> Universe::getCompletionPath(const string& s,
|
|||
if (sel.getType() == Selection::Type_Body)
|
||||
{
|
||||
worlds = sel.body()->getSatellites();
|
||||
if (withLocations) {
|
||||
std::vector<Location*>* locations = sel.body()->getLocations();
|
||||
string search = s.substr(pos + 1);
|
||||
for (vector<Location*>::const_iterator iter = locations->begin();
|
||||
iter != locations->end(); iter++)
|
||||
{
|
||||
if (!UTF8StringCompare(search, (*iter)->getName(), search.length()))
|
||||
locationCompletion.push_back((*iter)->getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sel.getType() == Selection::Type_Star)
|
||||
{
|
||||
|
@ -953,7 +978,8 @@ std::vector<std::string> Universe::getCompletionPath(const string& s,
|
|||
|
||||
if (worlds != NULL)
|
||||
{
|
||||
return worlds->getCompletion(s.substr(pos + 1), false);
|
||||
completion = worlds->getCompletion(s.substr(pos + 1), false);
|
||||
completion.insert(completion.end(), locationCompletion.begin(), locationCompletion.end());
|
||||
}
|
||||
|
||||
return completion;
|
||||
|
|
|
@ -62,10 +62,12 @@ class Universe
|
|||
|
||||
std::vector<std::string> getCompletion(const std::string& s,
|
||||
Selection* contexts = NULL,
|
||||
int nContexts = 0);
|
||||
int nContexts = 0,
|
||||
bool withLocations = false);
|
||||
std::vector<std::string> getCompletionPath(const std::string& s,
|
||||
Selection* contexts = NULL,
|
||||
int nContexts = 0);
|
||||
int nContexts = 0,
|
||||
bool withLocations = false);
|
||||
|
||||
|
||||
SolarSystem* getNearestSolarSystem(const UniversalCoord& position) const;
|
||||
|
|
|
@ -1021,9 +1021,19 @@ void CelestiaCore::keyUp(int key, int)
|
|||
}
|
||||
|
||||
void CelestiaCore::charEntered(char c)
|
||||
{
|
||||
char C[2];
|
||||
C[0] = c;
|
||||
C[1] = '\0';
|
||||
charEntered(C);
|
||||
}
|
||||
|
||||
void CelestiaCore::charEntered(const char *c_p)
|
||||
{
|
||||
Observer* observer = sim->getActiveObserver();
|
||||
|
||||
char c = *c_p;
|
||||
|
||||
#ifdef CELX
|
||||
if (celxScript != NULL && (textEnterMode & KbPassToScript))
|
||||
{
|
||||
|
@ -1036,10 +1046,12 @@ void CelestiaCore::charEntered(char c)
|
|||
|
||||
if (textEnterMode & KbAutoComplete)
|
||||
{
|
||||
if ( c == ' ' || isalpha(c) || isdigit(c) || ispunct(c))
|
||||
wchar_t wc = NULL;
|
||||
UTF8Decode(c_p, 0, strlen(c_p), wc);
|
||||
if ( wc && (iswalpha(wc) || iswdigit(wc) || iswpunct(c)) )
|
||||
{
|
||||
typedText += c;
|
||||
typedTextCompletion = sim->getObjectCompletion(typedText);
|
||||
typedText += std::string(c_p);
|
||||
typedTextCompletion = sim->getObjectCompletion(typedText, renderer->getLabelMode() & Renderer::LocationLabels);
|
||||
typedTextCompletionIdx = -1;
|
||||
#ifdef AUTO_COMPLETION
|
||||
if (typedTextCompletion.size() == 1)
|
||||
|
@ -1061,10 +1073,16 @@ void CelestiaCore::charEntered(char c)
|
|||
do
|
||||
{
|
||||
#endif
|
||||
// We remove bytes like b10xxx xxxx at the end of typeText
|
||||
// these are guarantied to not be the first byte of a UTF-8 char
|
||||
while (typedText.size() && ((typedText[typedText.size() - 1] & 0xC0) == 0x80)) {
|
||||
typedText = string(typedText, 0, typedText.size() - 1);
|
||||
}
|
||||
// We then remove the first byte of the last UTF-8 char of typedText.
|
||||
typedText = string(typedText, 0, typedText.size() - 1);
|
||||
if (typedText.size() > 0)
|
||||
{
|
||||
typedTextCompletion = sim->getObjectCompletion(typedText);
|
||||
typedTextCompletion = sim->getObjectCompletion(typedText, renderer->getLabelMode() & Renderer::LocationLabels);
|
||||
} else {
|
||||
typedTextCompletion.clear();
|
||||
}
|
||||
|
|
|
@ -180,6 +180,7 @@ class CelestiaCore // : public Watchable<CelestiaCore>
|
|||
void setHistoryCurrent(std::vector<Url>::size_type curr);
|
||||
|
||||
// event processing methods
|
||||
void charEntered(const char*);
|
||||
void charEntered(char);
|
||||
void keyDown(int key, int modifiers = 0);
|
||||
void keyUp(int key, int modifiers = 0);
|
||||
|
|
|
@ -116,7 +116,7 @@ void CelestialBrowser::slotRefresh()
|
|||
{
|
||||
char buf[20];
|
||||
const Star *star=(Star *)(*i);
|
||||
QString name((stardb->getStarName(*star)).c_str());
|
||||
QString name = QString::fromUtf8((stardb->getStarName(*star)).c_str());
|
||||
|
||||
Point3f starPos = star->getPosition();
|
||||
Vec3d v(starPos.x - obsPos.x,
|
||||
|
@ -154,7 +154,7 @@ void CelestialBrowser::slotRefresh()
|
|||
sprintf(buf, " %.2f au", starBodyDist / KM_PER_AU);
|
||||
QString distStarBody(buf);
|
||||
|
||||
CelListViewItem *planetItem = new CelListViewItem(starItem, QString(body->getName().c_str()),
|
||||
CelListViewItem *planetItem = new CelListViewItem(starItem, QString::fromUtf8(body->getName().c_str()),
|
||||
distStarBody, "", "", getClassification(body->getClassification()));
|
||||
|
||||
const PlanetarySystem* satellites = body->getSatellites();
|
||||
|
@ -171,7 +171,7 @@ void CelestialBrowser::slotRefresh()
|
|||
QString distBodySat(buf);
|
||||
|
||||
new CelListViewItem(planetItem,
|
||||
QString(sat->getName().c_str()),
|
||||
QString::fromUtf8(sat->getName().c_str()),
|
||||
distBodySat, "", "", getClassification(sat->getClassification()));
|
||||
|
||||
}
|
||||
|
|
|
@ -208,6 +208,25 @@ void KdeWatcher::notifyChange(CelestiaCore * core, int property)
|
|||
kdeapp->resyncVerbosity();
|
||||
else if (property & CelestiaCore::HistoryChanged)
|
||||
kdeapp->resyncHistory();
|
||||
|
||||
if (property == CelestiaCore::TextEnterModeChanged) {
|
||||
static std::vector<KAction*> actions;
|
||||
if (kdeapp->appCore->getTextEnterMode() != CelestiaCore::KbNormal) {
|
||||
for (unsigned int n=0; n < kdeapp->getActionCollection()->count(); n++) {
|
||||
if (kdeapp->getActionCollection()->action(n)->shortcut().count() > 0
|
||||
&& (kdeapp->getActionCollection()->action(n)->shortcut().seq(0).key(0).modFlags()
|
||||
& (KKey::CTRL | KKey::ALT | KKey::WIN )) == 0 ) {
|
||||
actions.push_back(kdeapp->getActionCollection()->action(n));
|
||||
kdeapp->getActionCollection()->action(n)->setEnabled(false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (std::vector<KAction*>::iterator n=actions.begin(); n<actions.end(); n++) {
|
||||
(*n)->setEnabled(true);
|
||||
}
|
||||
actions.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KdeApp::resyncHistory() {
|
||||
|
@ -841,7 +860,7 @@ void KdeApp::slotPreferences() {
|
|||
void KdeApp::slotSetTime() {
|
||||
KdePreferencesDialog dlg(this, appCore);
|
||||
|
||||
dlg.showPage(1);
|
||||
dlg.showPage(2);
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ public:
|
|||
void openBookmarkURL(const QString& _url);
|
||||
Url currentUrl(Url::UrlType type = Url::Absolute) const ;
|
||||
QString currentIcon() const;
|
||||
const KActionCollection* getActionCollection() { return actionCollection(); }
|
||||
|
||||
public slots:
|
||||
void celestia_tick() { appCore->tick(); glWidget->updateGL(); }
|
||||
|
|
|
@ -383,18 +383,9 @@ bool KdeGlWidget::handleSpecialKey(QKeyEvent* e, bool down)
|
|||
void KdeGlWidget::keyPressEvent( QKeyEvent* e )
|
||||
{
|
||||
static bool inputMode = false;
|
||||
static std::vector<KAction*> actions;
|
||||
switch (e->key())
|
||||
{
|
||||
case Key_Escape:
|
||||
if (inputMode)
|
||||
{
|
||||
for (unsigned int n=0; n<actionColl->count(); n++) {
|
||||
if (actionColl->action(n)->shortcut().seq(0).key(0).modFlags()==0)
|
||||
actionColl->action(n)->setEnabled(true);
|
||||
}
|
||||
inputMode = !inputMode;
|
||||
}
|
||||
appCore->charEntered('\033');
|
||||
break;
|
||||
case Key_BackTab:
|
||||
|
@ -408,38 +399,14 @@ void KdeGlWidget::keyPressEvent( QKeyEvent* e )
|
|||
// Intentional fallthrough if *not* Ctrl-Q
|
||||
|
||||
default:
|
||||
if (!handleSpecialKey(e, true))
|
||||
if (appCore->getTextEnterMode() != CelestiaCore::KbNormal || !handleSpecialKey(e, true))
|
||||
{
|
||||
if ((e->text() != 0) && (e->text() != ""))
|
||||
{
|
||||
for (unsigned int i=0; i<e->text().length(); i++)
|
||||
{
|
||||
char c = e->text().at(i).latin1();
|
||||
if (c == 0x0D || c=='\033') {
|
||||
if (!inputMode) { // entering input mode
|
||||
for (unsigned int n=0; n<actionColl->count(); n++) {
|
||||
if (actionColl->action(n)->shortcut().count() > 0
|
||||
&& (actionColl->action(n)->shortcut().seq(0).key(0).modFlags()
|
||||
& (KKey::CTRL | KKey::ALT | KKey::WIN )) == 0 ) {
|
||||
actions.push_back(actionColl->action(n));
|
||||
actionColl->action(n)->setEnabled(false);
|
||||
}
|
||||
}
|
||||
} else { // living input mode
|
||||
for (std::vector<KAction*>::iterator n=actions.begin(); n<actions.end(); n++) {
|
||||
(*n)->setEnabled(true);
|
||||
}
|
||||
actions.clear();
|
||||
}
|
||||
inputMode = !inputMode;
|
||||
}
|
||||
if (c >= 0x20 || c == 0x0D || c== 0x08 || c=='\011') appCore->charEntered(c);
|
||||
}
|
||||
appCore->charEntered(e->text().utf8().data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -552,6 +552,47 @@ int UTF8StringCompare(const std::string& s0, const std::string& s1)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int UTF8StringCompare(const std::string& s0, const std::string& s1, size_t n)
|
||||
{
|
||||
int len0 = s0.length();
|
||||
int len1 = s1.length();
|
||||
int i0 = 0;
|
||||
int i1 = 0;
|
||||
while (i0 < len0 && i1 < len1 && n > 0)
|
||||
{
|
||||
wchar_t ch0 = 0;
|
||||
wchar_t ch1 = 0;
|
||||
if (!UTF8Decode(s0, i0, ch0))
|
||||
return 1;
|
||||
if (!UTF8Decode(s1, i1, ch1))
|
||||
return -1;
|
||||
|
||||
i0 += UTF8EncodedSize(ch0);
|
||||
i1 += UTF8EncodedSize(ch1);
|
||||
ch0 = UTF8Normalize(ch0);
|
||||
ch1 = UTF8Normalize(ch1);
|
||||
|
||||
if (ch0 < ch1)
|
||||
return -1;
|
||||
else if (ch0 > ch1)
|
||||
return 1;
|
||||
|
||||
n--;
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
len0 = UTF8Length(s0);
|
||||
len1 = UTF8Length(s1);
|
||||
if (len0 > len1)
|
||||
return 1;
|
||||
else if (len0 < len1)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Currently incomplete, but could be a helpful class for dealing with
|
||||
// UTF-8 streams
|
||||
|
|
|
@ -20,6 +20,7 @@ bool UTF8Decode(const std::string& str, int pos, wchar_t& ch);
|
|||
bool UTF8Decode(const char* str, int pos, int length, wchar_t& ch);
|
||||
int UTF8Encode(wchar_t ch, char* s);
|
||||
int UTF8StringCompare(const std::string& s0, const std::string& s1);
|
||||
int UTF8StringCompare(const std::string& s0, const std::string& s1, size_t length);
|
||||
int UTF8Length(const std::string& s);
|
||||
|
||||
inline int UTF8EncodedSize(wchar_t ch)
|
||||
|
|
Loading…
Reference in New Issue