diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ae2a03c2941bf92573f89b88ef73f8aa842bea0a (patch) | |
tree | 3566563f3fb6ac3cb3496669d8f233062d3091bc /kodo/kodometer.cpp | |
download | tdetoys-ae2a03c2941bf92573f89b88ef73f8aa842bea0a.tar.gz tdetoys-ae2a03c2941bf92573f89b88ef73f8aa842bea0a.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdetoys@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kodo/kodometer.cpp')
-rw-r--r-- | kodo/kodometer.cpp | 600 |
1 files changed, 600 insertions, 0 deletions
diff --git a/kodo/kodometer.cpp b/kodo/kodometer.cpp new file mode 100644 index 0000000..aea6f47 --- /dev/null +++ b/kodo/kodometer.cpp @@ -0,0 +1,600 @@ +/* + * Mouspedometa + * Based on the original Xodometer VMS/Motif sources. + * + * Written by Armen Nakashian + * Compaq Computer Corporation + * Houston TX + * 22 May 1998 + * + * If you make improvements or enhancements to Mouspedometa, please send + * them back to the author at any of the following addresses: + * + * armen@nakashian.com + * + * Thanks to Mark Granoff for writing the original Xodometer, and + * the whole KDE team for making such a nice environment to write + * programs in. + * + * + * This software is provided as is with no warranty of any kind, + * expressed or implied. Neither Digital Equipment Corporation nor + * Armen Nakashian will be held accountable for your use of this + * software. + */ + +#include "kodometer.h" + +const double speedInterval = 500.0; +const double distanceInterval = 10.0; +const int speedSamples = 10; + +static struct conversionEntry ConversionTable[MAX_UNIT] = { + {inch, I18N_NOOP("inch"), I18N_NOOP("inches"), 12.0, 2.54, + I18N_NOOP("cm"), I18N_NOOP("cm"), 100.0, 3}, + {foot, I18N_NOOP("foot"), I18N_NOOP("feet"), 5280.0, 0.3048, + I18N_NOOP("meter"), I18N_NOOP("meters"), 1000.0, 4}, + {mile, I18N_NOOP("mile"), I18N_NOOP("miles"), -1.0, 1.609344, + I18N_NOOP("km"), I18N_NOOP("km"), -1.0, 5}}; + +/* + * Set the program up, do lots of ugly initialization. + * Note that we use installEventFilter on the two KImageNumber's + * to make clicks on them bring up the context-menu. + */ +Kodometer::Kodometer(QWidget* parent, const char* name) + : QFrame(parent, name), + dontRefresh(false), + speed(0.0), + lastDistance(0.0), + XCoord(0), YCoord(0), + lastXCoord(0), lastYCoord(0), + pointerScreen(-1), + lastPointerScreen(-1), + Enabled(true), + cyclesSinceLastSave(0), + pollInterval(10), + saveFrequency(10) +{ + display = KApplication::kApplication()->getDisplay(); + FindAllScreens(); + + root = RootWindow(display, DefaultScreen(display)); + + readSettings(); + if(AutoReset) { + dontRefresh = true; + resetTrip(); + dontRefresh = false; + } + + lastDistance = Distance; + + lastDUnit = distanceUnit; + lastTUnit = tripDistanceUnit; + + totalLabel = new KImageNumber(locate("appdata", "numbers.png"), this); + tripLabel = new KImageNumber(locate("appdata", "numbers.png"), this); + + totalLabel->installEventFilter(this); + tripLabel->installEventFilter(this); + + // setup help menu + help = new KHelpMenu(this, KGlobal::instance()->aboutData(), false); + KPopupMenu* helpMnu = help->menu(); + + // Make the popup menu + menu = new KPopupMenu(); + + menu->insertTitle(kapp->miniIcon(), KGlobal::instance()->aboutData()->programName()); + + enabledID = menu->insertItem(i18n("&Enable"), this, SLOT(toggleEnabled())); + metricID = menu->insertItem(i18n("&Metric Display"), this, + SLOT(toggleUnits())); + autoResetID = menu->insertItem(i18n("Auto &Reset Trip"), this, + SLOT(toggleAutoReset())); + menu->insertItem(i18n("Reset &Trip"), this, SLOT(resetTrip())); + menu->insertItem(i18n("Reset &Odometer"), this, SLOT(resetTotal())); + menu->insertSeparator(); + + menu->insertItem(SmallIconSet("help"), i18n("&Help"), helpMnu); + + menu->insertItem(SmallIconSet("exit"), i18n("&Quit"), this, SLOT(quit())); + menu->setCheckable(true); + + menu->setItemChecked(enabledID, Enabled); + menu->setItemChecked(metricID, UseMetric); + menu->setItemChecked(autoResetID, AutoReset); + + //start the timers that will rifresh the counter + distanceID = startTimer((int)distanceInterval); + speedID = startTimer((int)speedInterval); + + tripLabel->move(0, totalLabel->height()); + setFixedSize(tripLabel->width(), + totalLabel->height() + tripLabel->height()); + + UseMetric =! UseMetric; + toggleUnits(); + + refresh(); +} + +/* + * Now I'm not really sure what this does. I assume its here to find + * all the displays on your system, and measure them. During the mouse + * tracking phase, we use the information stored here to determine how + * far the mouse moved on a given screen. + * + * The point is, since you might have one 17" screen and on 21" screen, + * lets measure them differently. Surely this level of accurasy is + * only provide to prove that the original author was a man's man. + */ +void Kodometer::FindAllScreens(void) +{ + int Dh, DhMM, Dw, DwMM; + double vPixelsPerMM, hPixelsPerMM; + + screenCount = ScreenCount(display); +// kdDebug() << "Display has " << screenCount << +// " screen" << (screenCount == 1 ? "" : "s") << endl; + + for(int i = 0; i < screenCount; i++) { +// kdDebug() << "Screen " << i << endl; + screenInfo[i].root = RootWindow(display, i); + screenInfo[i].scr = XScreenOfDisplay(display, i); + + screenInfo[i].height = Dh = HeightOfScreen(screenInfo[i].scr); + DhMM = HeightMMOfScreen(screenInfo[i].scr); + screenInfo[i].width = Dw = WidthOfScreen(screenInfo[i].scr); + DwMM = WidthMMOfScreen(screenInfo[i].scr); +// kdDebug() << " Height is " << Dh << " pixels (" << DhMM << +// "mm)" << endl; +// kdDebug() << " Width is " << Dw << " pixels (" << DwMM << +// "mm)" << endl; + + vPixelsPerMM = (double)Dh / (double)DhMM; + hPixelsPerMM = (double)Dw / (double)DwMM; + screenInfo[i].PixelsPerMM = (vPixelsPerMM + hPixelsPerMM) / 2.0; +// kdDebug() << " Vertical pixels/mm are " << vPixelsPerMM << +// "mm" << endl; +// kdDebug() << " Horizontal pixels/mm are " << hPixelsPerMM << +// "mm" << endl; +// kdDebug() << " Average pixels/mm are " << +// screenInfo[i].PixelsPerMM << "mm" << endl; + } +} + +/* + * Here's where we override events to the KImgNum's to display + * the context menu + */ +bool Kodometer::eventFilter( QObject *, QEvent *e ) +{ + if ( e->type() == QEvent::MouseButtonPress ) { + mousePressEvent((QMouseEvent*)e); + return true; + } + return false; +} + +/* + * Show the context menu + */ +void Kodometer::mousePressEvent(QMouseEvent* e) +{ + //FIXME fix this! + //dontRefresh = true; + menu->popup(mapToGlobal(e->pos())); +} + +/* + * Called when the timer expires to query the pointer position, + * compare it to the last known position, and then to calculate + * the distance moved. + */ +void Kodometer::timerEvent(QTimerEvent* e) +{ + if (Enabled) { + if(e->timerId() == distanceID) { + lastPointerScreen = pointerScreen; + lastXCoord = XCoord; + lastYCoord = YCoord; + XQueryPointer (display, root, &RootIDRet, &ChildIDRet, &XCoord, + &YCoord, &WinX, &WinY, &StateMask); + if (CalcDistance()) { +// kdDebug() << "Mouse moved" << endl; + if (!dontRefresh) { + refresh(); + cyclesSinceLastSave++; + } + } + } + } +} + +// Guess! +void Kodometer::toggleEnabled() +{ + Enabled = !Enabled; + menu->setItemChecked(enabledID,Enabled); + refresh(); +} + +// Try again! +void Kodometer::toggleAutoReset() +{ + AutoReset = !AutoReset; + menu->setItemChecked(autoResetID,AutoReset); + refresh(); +} + + +// You're getting warm! +void Kodometer::toggleUnits() +{ + UseMetric =! UseMetric; + + menu->setItemChecked(metricID, UseMetric); + + QToolTip::remove(totalLabel); + QToolTip::remove(tripLabel); + if(!UseMetric) { + QToolTip::add(totalLabel, + i18n(ConversionTable[distanceUnit].fromUnitTagPlural)); + QToolTip::add(tripLabel, + i18n(ConversionTable[tripDistanceUnit].fromUnitTagPlural)); + } else { + QToolTip::add(totalLabel, + i18n(ConversionTable[distanceUnit].toUnitTagPlural)); + QToolTip::add(tripLabel, + i18n(ConversionTable[tripDistanceUnit].toUnitTagPlural)); + } + refresh(); +} + + +// Were you dropped on your head as a child? +void Kodometer::resetTrip() +{ + TripDistance = 0.0; + tripDistanceUnit = inch; + if (!dontRefresh) + refresh(); +} + +// I was! +void Kodometer::resetTotal() +{ + resetTrip(); + + Distance = 0.0; + distanceUnit = inch; + + TripDistance = 0.0; + tripDistanceUnit = inch; + refresh(); +} + +/* + * Set the values in all the KImgNums, do metric conversions, + * and make the screen look like reality. + */ +void Kodometer::refresh(void) +{ + if(distanceUnit != lastDUnit) { + lastDUnit = distanceUnit; + QToolTip::remove(totalLabel); + if(!UseMetric) + QToolTip::add(totalLabel, + i18n(ConversionTable[distanceUnit].fromUnitTagPlural)); + else + QToolTip::add(totalLabel, + i18n(ConversionTable[distanceUnit].toUnitTagPlural)); + } + + if(tripDistanceUnit != lastTUnit) { + lastTUnit = tripDistanceUnit; + QToolTip::remove(tripLabel); + if(!UseMetric) + QToolTip::add(tripLabel, + i18n(ConversionTable[tripDistanceUnit].fromUnitTagPlural)); + else + QToolTip::add(tripLabel, + i18n(ConversionTable[tripDistanceUnit].toUnitTagPlural)); + } + + //now draw everything + QString distance_s; + QString trip_s; + double distance_d = 0; + double trip_d = 0; + + if (Enabled) { + distance_d = Distance; + distance_s = FormatDistance(distance_d, distanceUnit); + trip_d = TripDistance; + trip_s = FormatDistance(trip_d, tripDistanceUnit); + } else { + distance_s = "------"; + trip_s = "------"; + } + + totalLabel->setValue(distance_d); + tripLabel->setValue(trip_d); +} + +/* + * Not sure what this does, its from the original program. + */ +double Kodometer::multiplier(Units unit) +{ + double m = 10; + + switch (unit) { + case mile : m *= 10.0; + case foot : m *= 10.0; + case inch : m *= 10.0; break; + } + return m; +} + +/* + * This is the bitch function where the _real_ work is done. I + * could have re-invented the query_pointer code, but this one is a best. + * + * This is code from the original program, responsible for converting the + * number of pixels traveled into a real-world coordinates. + */ +int Kodometer::CalcDistance(void) +{ + double dist, sum; + int X, Y; + double distMM, distInches, finalNewDist; + double oldDistance, oldTripDistance; + double newDistance, newTripDistance; + int i, j, finalScreen, increment; + Units oldDistanceUnit, oldTripDistanceUnit, currentUnit; + int distanceChanged, tripDistanceChanged; + + int screenOrientation = K_Left; + + i = j = finalScreen = increment = 0; + + if ((lastXCoord == 0) && (lastYCoord == 0)) + return false; + + if ((lastXCoord == XCoord) && (lastYCoord == YCoord)) + return false; + + //Figure out which screen the pointer is on + if (screenCount > 1) { + while (i < screenCount) + if (RootIDRet == screenInfo[i].root) + break; + else + i++; + } + + pointerScreen = i; + +// kdDebug() << "CalcDistance: screen: " << pointerScreen << +// " x: " << XCoord << " y: " << YCoord << endl; + + // Adjust XCoord or YCoord for the screen its on, relative to screen 0 + // and screenOrientation. + + if (lastPointerScreen != -1 && pointerScreen != lastPointerScreen) { + switch (screenOrientation) { + case K_Left: + case K_Top: + finalScreen = 0; + j = QMAX(pointerScreen,lastPointerScreen) - 1; + increment = -1; + break; + case K_Right: + case K_Bottom: + finalScreen = QMAX(pointerScreen,lastPointerScreen) - 1; + j = 0; + increment = 1; + break; + } + do { + switch (screenOrientation) { + case K_Left: + case K_Right: + if (pointerScreen > lastPointerScreen) + XCoord += screenInfo[j].width; + else + lastXCoord += screenInfo[j].width; + break; + case K_Top: + case K_Bottom: + if (pointerScreen > lastPointerScreen) + YCoord += screenInfo[j].height; + else + lastYCoord += screenInfo[j].height; + break; + } + if (j != finalScreen) + j += increment; + } while (j != finalScreen); +// kdDebug() << " Adjusted for screen ch: x: " << XCoord << +// " y: " << YCoord << endl; + } + +// kdDebug() << "In: Distance: " << Distance << +// " Trip Distance: " << TripDistance << endl; + + // Calculate distance in pixels first + // using Pitagora + + X = XCoord - lastXCoord; + X = X*X; + + Y = YCoord - lastYCoord; + Y = Y*Y; + + sum = (double)X + (double)Y; + dist = sqrt(sum); + + // Convert to millimeters + distMM = dist / screenInfo[pointerScreen].PixelsPerMM; + + // Convert to inches + distInches = distMM * 0.04; + + // Add an appropriate value to Distance, which may be + // in a unit other than inches + currentUnit = inch; + finalNewDist = distInches; + + while (currentUnit < distanceUnit) { + finalNewDist = + finalNewDist / ConversionTable[currentUnit].maxFromBeforeNext; + currentUnit++; +// kdDebug() << " New dist: " << dist << "p, " << distMM << "mm, " << +// distInches << "in, " << finalNewDist << " " << +// ConversionTable[currentUnit+1].fromUnitTagPlural << endl; + } + +// kdDebug() << " Next part" << endl; + + oldDistance = Distance * multiplier(distanceUnit); + + Distance += finalNewDist; + oldDistanceUnit = distanceUnit; + + if (ConversionTable[distanceUnit].maxFromBeforeNext != -1.0 && + Distance >= ConversionTable[distanceUnit].maxFromBeforeNext) + { + Distance = Distance / ConversionTable[distanceUnit].maxFromBeforeNext; + distanceUnit++; + } + + newDistance = Distance * multiplier(distanceUnit); + distanceChanged = (distanceUnit != oldDistanceUnit || + (unsigned int)oldDistance != (unsigned int)newDistance); + + // Add an appropriate value to TripDistance, which may be + // in a unit other than inches + currentUnit = inch; + finalNewDist = distInches; + + while (currentUnit < tripDistanceUnit) { + finalNewDist = finalNewDist / + ConversionTable[currentUnit].maxFromBeforeNext; + currentUnit++; + } + + oldTripDistance = TripDistance * multiplier(tripDistanceUnit); + TripDistance += finalNewDist; + oldTripDistanceUnit = tripDistanceUnit; + + if (ConversionTable[tripDistanceUnit].maxFromBeforeNext != -1.0 && + TripDistance >= ConversionTable[tripDistanceUnit].maxFromBeforeNext) + { + TripDistance = TripDistance / + ConversionTable[tripDistanceUnit].maxFromBeforeNext; + tripDistanceUnit++; + } + + newTripDistance = TripDistance * multiplier(tripDistanceUnit); + tripDistanceChanged = ((tripDistanceUnit != oldTripDistanceUnit) || + ((unsigned int)oldTripDistance != (unsigned int)newTripDistance)); + + +// kdDebug() << "Out: Distance: " << Distance << +// "Trip Distance: " << TripDistance << endl; + + if ((distanceChanged) || (tripDistanceChanged)) + return true; + else + return false; +} + +/* + * This code can probably go away. Its doing conversions from inches to + * other units. Its ugly C-style stuff, that should't be done in a + * pretty OO world. + */ +#define THERE_IS_A_NEXT (ConversionTable[unit].maxToBeforeNext != -1.0) +QString Kodometer::FormatDistance(double &dist, Units unit) +{ + QString string; + const char *tag; + int precision; + + if (UseMetric) { + dist = dist * ConversionTable[unit].conversionFactor; + if ((THERE_IS_A_NEXT) && + (dist > ConversionTable[unit].maxToBeforeNext)) + { + dist = dist / ConversionTable[unit].maxToBeforeNext; + unit++; + } + if (dist == 1.0) + tag = ConversionTable[unit].toUnitTag; + else + tag = ConversionTable[unit].toUnitTagPlural; + } else { + if (dist == 1.0) + tag = ConversionTable[unit].fromUnitTag; + else + tag = ConversionTable[unit].fromUnitTagPlural; + } + precision = ConversionTable[unit].printPrecision; + + string.sprintf ("%.*f %s", precision, dist, tag); + return string; +} + +/* + * Use KConfig to read all settings from disk. Note that whatever + * happens here overrides the defaults, but there's not much + * sanity-checking. + */ +void Kodometer::readSettings(void) +{ + KConfig* config = KGlobal::config(); + config->setGroup("Settings"); + + UseMetric = config->readNumEntry("UseMetric", false); + AutoReset = config->readNumEntry("AutoReset", true); + + TripDistance = config->readDoubleNumEntry("Trip", 0.0); + Distance = config->readDoubleNumEntry("Distance", 0.0); + + distanceUnit = config->readNumEntry("DistanceUnit", inch); + tripDistanceUnit = config->readNumEntry("TripUnit", inch); +} + + +/* + * Save reality for use in the next session. + */ +void Kodometer::saveSettings(void) +{ + KConfig* config = KGlobal::config(); + config->setGroup("Settings"); + + config->writeEntry("UseMetric", UseMetric); + config->writeEntry("AutoReset", AutoReset); + + config->writeEntry("Trip", TripDistance); + config->writeEntry("Distance", Distance); + + config->writeEntry("TripUnit", tripDistanceUnit); + config->writeEntry("DistanceUnit", distanceUnit); + + config->sync(); +} + +// What in the world can this do? +void Kodometer::quit() +{ + saveSettings(); + kapp->quit(); +} + +#include "kodometer.moc" |