00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "lljoystickbutton.h"
00035
00036
00037 #include "llcoord.h"
00038 #include "indra_constants.h"
00039
00040
00041 #include "llui.h"
00042 #include "llagent.h"
00043 #include "llviewerimage.h"
00044 #include "llviewerimagelist.h"
00045 #include "llviewerwindow.h"
00046 #include "llmoveview.h"
00047
00048 #include "llglheaders.h"
00049
00050 const F32 NUDGE_TIME = 0.25f;
00051 const F32 ORBIT_NUDGE_RATE = 0.05f;
00052
00053
00054
00055
00056 LLJoystick::LLJoystick(
00057 const LLString& name,
00058 LLRect rect,
00059 const LLString &default_image,
00060 const LLString &selected_image,
00061 EJoystickQuadrant initial_quadrant )
00062 :
00063 LLButton(name, rect, default_image, selected_image, NULL, NULL),
00064 mInitialQuadrant(initial_quadrant),
00065 mInitialOffset(0, 0),
00066 mLastMouse(0, 0),
00067 mFirstMouse(0, 0),
00068 mVertSlopNear(0),
00069 mVertSlopFar(0),
00070 mHorizSlopNear(0),
00071 mHorizSlopFar(0),
00072 mHeldDown(FALSE),
00073 mHeldDownTimer()
00074 {
00075 mHeldDownCallback = &LLJoystick::onHeldDown;
00076 mCallbackUserData = this;
00077 }
00078
00079
00080 void LLJoystick::updateSlop()
00081 {
00082 mVertSlopNear = mRect.getHeight();
00083 mVertSlopFar = mRect.getHeight() * 2;
00084
00085 mHorizSlopNear = mRect.getWidth();
00086 mHorizSlopFar = mRect.getWidth() * 2;
00087
00088
00089
00090 switch (mInitialQuadrant)
00091 {
00092 case JQ_ORIGIN:
00093 mInitialOffset.set(0, 0);
00094 break;
00095
00096 case JQ_UP:
00097 mInitialOffset.mX = 0;
00098 mInitialOffset.mY = (mVertSlopNear + mVertSlopFar) / 2;
00099 break;
00100
00101 case JQ_DOWN:
00102 mInitialOffset.mX = 0;
00103 mInitialOffset.mY = - (mVertSlopNear + mVertSlopFar) / 2;
00104 break;
00105
00106 case JQ_LEFT:
00107 mInitialOffset.mX = - (mHorizSlopNear + mHorizSlopFar) / 2;
00108 mInitialOffset.mY = 0;
00109 break;
00110
00111 case JQ_RIGHT:
00112 mInitialOffset.mX = (mHorizSlopNear + mHorizSlopFar) / 2;
00113 mInitialOffset.mY = 0;
00114 break;
00115
00116 default:
00117 llerrs << "LLJoystick::LLJoystick() - bad switch case" << llendl;
00118 break;
00119 }
00120
00121 return;
00122 }
00123
00124
00125 BOOL LLJoystick::handleMouseDown(S32 x, S32 y, MASK mask)
00126 {
00127
00128
00129 mLastMouse.set(x, y);
00130 mFirstMouse.set(x, y);
00131
00132 mMouseDownTimer.reset();
00133 return LLButton::handleMouseDown(x, y, mask);
00134 }
00135
00136
00137 BOOL LLJoystick::handleMouseUp(S32 x, S32 y, MASK mask)
00138 {
00139
00140
00141 if( hasMouseCapture() )
00142 {
00143 mLastMouse.set(x, y);
00144 mHeldDown = FALSE;
00145 onMouseUp();
00146 }
00147
00148 return LLButton::handleMouseUp(x, y, mask);
00149 }
00150
00151
00152 BOOL LLJoystick::handleHover(S32 x, S32 y, MASK mask)
00153 {
00154 if( hasMouseCapture() )
00155 {
00156 mLastMouse.set(x, y);
00157 }
00158
00159 return LLButton::handleHover(x, y, mask);
00160 }
00161
00162 F32 LLJoystick::getElapsedHeldDownTime()
00163 {
00164 if( mHeldDown )
00165 {
00166 return mMouseDownTimer.getElapsedTimeF32();
00167 }
00168 else
00169 {
00170 return 0.f;
00171 }
00172 }
00173
00174
00175 void LLJoystick::onHeldDown(void *userdata)
00176 {
00177 LLJoystick *self = (LLJoystick *)userdata;
00178
00179
00180
00181
00182
00183 self->mHeldDown = TRUE;
00184 self->onHeldDown();
00185 }
00186
00187 EJoystickQuadrant LLJoystick::selectQuadrant(LLXMLNodePtr node)
00188 {
00189
00190 EJoystickQuadrant quadrant = JQ_RIGHT;
00191
00192 if (node->hasAttribute("quadrant"))
00193 {
00194 LLString quadrant_name;
00195 node->getAttributeString("quadrant", quadrant_name);
00196
00197 quadrant = quadrantFromName(quadrant_name.c_str());
00198 }
00199 return quadrant;
00200 }
00201
00202
00203 LLString LLJoystick::nameFromQuadrant(EJoystickQuadrant quadrant)
00204 {
00205 if (quadrant == JQ_ORIGIN) return LLString("origin");
00206 else if (quadrant == JQ_UP) return LLString("up");
00207 else if (quadrant == JQ_DOWN) return LLString("down");
00208 else if (quadrant == JQ_LEFT) return LLString("left");
00209 else if (quadrant == JQ_RIGHT) return LLString("right");
00210 else return LLString();
00211 }
00212
00213
00214 EJoystickQuadrant LLJoystick::quadrantFromName(const LLString& sQuadrant)
00215 {
00216 EJoystickQuadrant quadrant = JQ_RIGHT;
00217
00218 if (sQuadrant == "origin")
00219 {
00220 quadrant = JQ_ORIGIN;
00221 }
00222 else if (sQuadrant == "up")
00223 {
00224 quadrant = JQ_UP;
00225 }
00226 else if (sQuadrant == "down")
00227 {
00228 quadrant = JQ_DOWN;
00229 }
00230 else if (sQuadrant == "left")
00231 {
00232 quadrant = JQ_LEFT;
00233 }
00234 else if (sQuadrant == "right")
00235 {
00236 quadrant = JQ_RIGHT;
00237 }
00238
00239 return quadrant;
00240 }
00241
00242
00243 LLXMLNodePtr LLJoystick::getXML(bool save_children) const
00244 {
00245 LLXMLNodePtr node = LLUICtrl::getXML();
00246
00247 node->createChild("halign", TRUE)->setStringValue(LLFontGL::nameFromHAlign(mHAlign));
00248 node->createChild("quadrant", TRUE)->setStringValue(nameFromQuadrant(mInitialQuadrant));
00249
00250 addImageAttributeToXML(node,mImageUnselectedName,mImageUnselectedID,"image_unselected");
00251 addImageAttributeToXML(node,mImageSelectedName,mImageSelectedID,"image_selected");
00252
00253 node->createChild("scale_image", TRUE)->setBoolValue(mScaleImage);
00254
00255 return node;
00256 }
00257
00258
00259
00260
00261
00262
00263
00264 void LLJoystickAgentTurn::onHeldDown()
00265 {
00266 F32 time = getElapsedHeldDownTime();
00267 updateSlop();
00268
00269
00270
00271 S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX;
00272 S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY;
00273
00274 float m = (float) (dx)/abs(dy);
00275
00276 if (m > 1) {
00277 m = 1;
00278 }
00279 else if (m < -1) {
00280 m = -1;
00281 }
00282 gAgent.moveYaw(-LLFloaterMove::getYawRate(time)*m);
00283
00284
00285
00286 if (dy > mVertSlopFar)
00287 {
00288
00289 gAgent.moveAt(1);
00290 }
00291 else if (dy > mVertSlopNear)
00292 {
00293 if( time < NUDGE_TIME )
00294 {
00295 gAgent.moveAtNudge(1);
00296 }
00297 else
00298 {
00299
00300
00301 gAgent.moveAt(1);
00302 }
00303 }
00304 else if (dy < -mVertSlopFar)
00305 {
00306
00307 gAgent.moveAt(-1);
00308 }
00309 else if (dy < -mVertSlopNear)
00310 {
00311 if( time < NUDGE_TIME )
00312 {
00313 gAgent.moveAtNudge(-1);
00314 }
00315 else
00316 {
00317
00318
00319 gAgent.moveAt(-1);
00320 }
00321 }
00322 }
00323
00324 LLView* LLJoystickAgentTurn::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
00325 {
00326 LLString name("button");
00327 node->getAttributeString("name", name);
00328
00329 LLString image_unselected;
00330 if (node->hasAttribute("image_unselected")) node->getAttributeString("image_unselected",image_unselected);
00331
00332 LLString image_selected;
00333 if (node->hasAttribute("image_selected")) node->getAttributeString("image_selected",image_selected);
00334
00335 EJoystickQuadrant quad = JQ_ORIGIN;
00336 if (node->hasAttribute("quadrant")) quad = selectQuadrant(node);
00337
00338 LLJoystickAgentTurn *button = new LLJoystickAgentTurn(name,
00339 LLRect(),
00340 image_unselected,
00341 image_selected,
00342 quad);
00343
00344 if (node->hasAttribute("halign"))
00345 {
00346 LLFontGL::HAlign halign = selectFontHAlign(node);
00347 button->setHAlign(halign);
00348 }
00349
00350 if (node->hasAttribute("scale_image"))
00351 {
00352 BOOL needsScale = FALSE;
00353 node->getAttributeBOOL("scale_image",needsScale);
00354 button->setScaleImage( needsScale );
00355 }
00356
00357 button->initFromXML(node, parent);
00358
00359 return button;
00360 }
00361
00362
00363
00364
00365
00366
00367
00368 void LLJoystickAgentSlide::onMouseUp()
00369 {
00370 F32 time = getElapsedHeldDownTime();
00371 if( time < NUDGE_TIME )
00372 {
00373 switch (mInitialQuadrant)
00374 {
00375 case JQ_LEFT:
00376 gAgent.moveLeftNudge(1);
00377 break;
00378
00379 case JQ_RIGHT:
00380 gAgent.moveLeftNudge(-1);
00381 break;
00382
00383 default:
00384 break;
00385 }
00386 }
00387 }
00388
00389 void LLJoystickAgentSlide::onHeldDown()
00390 {
00391
00392
00393 updateSlop();
00394
00395 S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX;
00396 S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY;
00397
00398
00399 if (dx > mHorizSlopNear)
00400 {
00401 gAgent.moveLeft(-1);
00402 }
00403 else if (dx < -mHorizSlopNear)
00404 {
00405 gAgent.moveLeft(1);
00406 }
00407
00408
00409 if (dy > mVertSlopFar)
00410 {
00411
00412 gAgent.moveAt(1);
00413 }
00414 else if (dy > mVertSlopNear)
00415 {
00416
00417 gAgent.moveAtNudge(1);
00418 }
00419 else if (dy < -mVertSlopFar)
00420 {
00421
00422 gAgent.moveAt(-1);
00423 }
00424 else if (dy < -mVertSlopNear)
00425 {
00426
00427 gAgent.moveAtNudge(-1);
00428 }
00429 }
00430
00431
00432
00433 LLView* LLJoystickAgentSlide::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
00434 {
00435 LLString name("button");
00436 node->getAttributeString("name", name);
00437
00438 LLString image_unselected;
00439 if (node->hasAttribute("image_unselected")) node->getAttributeString("image_unselected",image_unselected);
00440
00441 LLString image_selected;
00442 if (node->hasAttribute("image_selected")) node->getAttributeString("image_selected",image_selected);
00443
00444
00445 EJoystickQuadrant quad = JQ_ORIGIN;
00446 if (node->hasAttribute("quadrant")) quad = selectQuadrant(node);
00447
00448 LLJoystickAgentSlide *button = new LLJoystickAgentSlide(name,
00449 LLRect(),
00450 image_unselected,
00451 image_selected,
00452 quad);
00453
00454 if (node->hasAttribute("halign"))
00455 {
00456 LLFontGL::HAlign halign = selectFontHAlign(node);
00457 button->setHAlign(halign);
00458 }
00459
00460 if (node->hasAttribute("scale_image"))
00461 {
00462 BOOL needsScale = FALSE;
00463 node->getAttributeBOOL("scale_image",needsScale);
00464 button->setScaleImage( needsScale );
00465 }
00466
00467 button->initFromXML(node, parent);
00468
00469 return button;
00470 }
00471
00472
00473
00474
00475
00476
00477 LLJoystickCameraRotate::LLJoystickCameraRotate(const LLString& name, LLRect rect, const LLString &out_img, const LLString &in_img)
00478 :
00479 LLJoystick(name, rect, out_img, in_img, JQ_ORIGIN),
00480 mInLeft( FALSE ),
00481 mInTop( FALSE ),
00482 mInRight( FALSE ),
00483 mInBottom( FALSE )
00484 { }
00485
00486
00487 void LLJoystickCameraRotate::updateSlop()
00488 {
00489
00490
00491
00492 mVertSlopNear = 16;
00493 mVertSlopFar = 32;
00494
00495 mHorizSlopNear = 16;
00496 mHorizSlopFar = 32;
00497
00498 return;
00499 }
00500
00501
00502 BOOL LLJoystickCameraRotate::handleMouseDown(S32 x, S32 y, MASK mask)
00503 {
00504 updateSlop();
00505
00506
00507 S32 horiz_center = mRect.getWidth() / 2;
00508 S32 vert_center = mRect.getHeight() / 2;
00509
00510 S32 dx = x - horiz_center;
00511 S32 dy = y - vert_center;
00512
00513 if (dy > dx && dy > -dx)
00514 {
00515
00516 mInitialOffset.mX = 0;
00517 mInitialOffset.mY = (mVertSlopNear + mVertSlopFar) / 2;
00518 mInitialQuadrant = JQ_UP;
00519 }
00520 else if (dy > dx && dy <= -dx)
00521 {
00522
00523 mInitialOffset.mX = - (mHorizSlopNear + mHorizSlopFar) / 2;
00524 mInitialOffset.mY = 0;
00525 mInitialQuadrant = JQ_LEFT;
00526 }
00527 else if (dy <= dx && dy <= -dx)
00528 {
00529
00530 mInitialOffset.mX = 0;
00531 mInitialOffset.mY = - (mVertSlopNear + mVertSlopFar) / 2;
00532 mInitialQuadrant = JQ_DOWN;
00533 }
00534 else
00535 {
00536
00537 mInitialOffset.mX = (mHorizSlopNear + mHorizSlopFar) / 2;
00538 mInitialOffset.mY = 0;
00539 mInitialQuadrant = JQ_RIGHT;
00540 }
00541
00542 return LLJoystick::handleMouseDown(x, y, mask);
00543 }
00544
00545
00546 void LLJoystickCameraRotate::onHeldDown()
00547 {
00548 updateSlop();
00549
00550 S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX;
00551 S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY;
00552
00553
00554 if (dx > mHorizSlopNear)
00555 {
00556 gAgent.unlockView();
00557 gAgent.setOrbitLeftKey(getOrbitRate());
00558 }
00559 else if (dx < -mHorizSlopNear)
00560 {
00561 gAgent.unlockView();
00562 gAgent.setOrbitRightKey(getOrbitRate());
00563 }
00564
00565
00566 if (dy > mVertSlopNear)
00567 {
00568 gAgent.unlockView();
00569 gAgent.setOrbitUpKey(getOrbitRate());
00570 }
00571 else if (dy < -mVertSlopNear)
00572 {
00573 gAgent.unlockView();
00574 gAgent.setOrbitDownKey(getOrbitRate());
00575 }
00576 }
00577
00578 F32 LLJoystickCameraRotate::getOrbitRate()
00579 {
00580 F32 time = getElapsedHeldDownTime();
00581 if( time < NUDGE_TIME )
00582 {
00583 F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME;
00584
00585 return rate;
00586 }
00587 else
00588 {
00589 return 1;
00590 }
00591 }
00592
00593
00594
00595 void LLJoystickCameraRotate::setToggleState( BOOL left, BOOL top, BOOL right, BOOL bottom )
00596 {
00597 mInLeft = left;
00598 mInTop = top;
00599 mInRight = right;
00600 mInBottom = bottom;
00601 }
00602
00603 void LLJoystickCameraRotate::draw()
00604 {
00605
00606 if( getVisible() )
00607 {
00608 LLGLSUIDefault gls_ui;
00609
00610 gl_draw_image( 0, 0, mImageUnselected );
00611
00612 if( mInTop )
00613 {
00614 drawRotatedImage( mImageSelected, 0 );
00615 }
00616
00617 if( mInRight )
00618 {
00619 drawRotatedImage( mImageSelected, 1 );
00620 }
00621
00622 if( mInBottom )
00623 {
00624 drawRotatedImage( mImageSelected, 2 );
00625 }
00626
00627 if( mInLeft )
00628 {
00629 drawRotatedImage( mImageSelected, 3 );
00630 }
00631
00632 if (sDebugRects)
00633 {
00634 drawDebugRect();
00635 }
00636 }
00637 }
00638
00639
00640 void LLJoystickCameraRotate::drawRotatedImage( LLImageGL* image, S32 rotations )
00641 {
00642 S32 width = image->getWidth();
00643 S32 height = image->getHeight();
00644
00645 F32 uv[][2] =
00646 {
00647 { 1.f, 1.f },
00648 { 0.f, 1.f },
00649 { 0.f, 0.f },
00650 { 1.f, 0.f }
00651 };
00652
00653 image->bind();
00654
00655 glColor4fv(UI_VERTEX_COLOR.mV);
00656
00657 glBegin(GL_QUADS);
00658 {
00659 glTexCoord2fv( uv[ (rotations + 0) % 4]);
00660 glVertex2i(width, height );
00661
00662 glTexCoord2fv( uv[ (rotations + 1) % 4]);
00663 glVertex2i(0, height );
00664
00665 glTexCoord2fv( uv[ (rotations + 2) % 4]);
00666 glVertex2i(0, 0);
00667
00668 glTexCoord2fv( uv[ (rotations + 3) % 4]);
00669 glVertex2i(width, 0);
00670 }
00671 glEnd();
00672 }
00673
00674
00675
00676
00677
00678
00679
00680
00681 void LLJoystickCameraTrack::onHeldDown()
00682 {
00683 updateSlop();
00684
00685 S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX;
00686 S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY;
00687
00688 if (dx > mVertSlopNear)
00689 {
00690 gAgent.unlockView();
00691 gAgent.setPanRightKey(getOrbitRate());
00692 }
00693 else if (dx < -mVertSlopNear)
00694 {
00695 gAgent.unlockView();
00696 gAgent.setPanLeftKey(getOrbitRate());
00697 }
00698
00699
00700 if (dy > mVertSlopNear)
00701 {
00702 gAgent.unlockView();
00703 gAgent.setPanUpKey(getOrbitRate());
00704 }
00705 else if (dy < -mVertSlopNear)
00706 {
00707 gAgent.unlockView();
00708 gAgent.setPanDownKey(getOrbitRate());
00709 }
00710 }
00711
00712
00713
00714
00715
00716
00717
00718 LLJoystickCameraZoom::LLJoystickCameraZoom(const LLString& name, LLRect rect, const LLString &out_img, const LLString &plus_in_img, const LLString &minus_in_img)
00719 :
00720 LLJoystick(name, rect, out_img, "", JQ_ORIGIN),
00721 mInTop( FALSE ),
00722 mInBottom( FALSE )
00723 {
00724 mPlusInImage = gImageList.getImage(LLUI::findAssetUUIDByName(plus_in_img), MIPMAP_FALSE, TRUE);
00725 mMinusInImage = gImageList.getImage(LLUI::findAssetUUIDByName(minus_in_img), MIPMAP_FALSE, TRUE);
00726 }
00727
00728
00729 BOOL LLJoystickCameraZoom::handleMouseDown(S32 x, S32 y, MASK mask)
00730 {
00731 BOOL handled = LLJoystick::handleMouseDown(x, y, mask);
00732
00733 if( handled )
00734 {
00735 if (mFirstMouse.mY > mRect.getHeight() / 2)
00736 {
00737 mInitialQuadrant = JQ_UP;
00738 }
00739 else
00740 {
00741 mInitialQuadrant = JQ_DOWN;
00742 }
00743 }
00744 return handled;
00745 }
00746
00747
00748 void LLJoystickCameraZoom::onHeldDown()
00749 {
00750 updateSlop();
00751
00752 const F32 FAST_RATE = 2.5f;
00753
00754 S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY;
00755
00756 if (dy > mVertSlopFar)
00757 {
00758
00759 gAgent.unlockView();
00760 gAgent.setOrbitInKey(FAST_RATE);
00761 }
00762 else if (dy > mVertSlopNear)
00763 {
00764
00765 gAgent.unlockView();
00766 gAgent.setOrbitInKey(getOrbitRate());
00767 }
00768 else if (dy < -mVertSlopFar)
00769 {
00770
00771 gAgent.unlockView();
00772 gAgent.setOrbitOutKey(FAST_RATE);
00773 }
00774 else if (dy < -mVertSlopNear)
00775 {
00776
00777 gAgent.unlockView();
00778 gAgent.setOrbitOutKey(getOrbitRate());
00779 }
00780 }
00781
00782
00783 void LLJoystickCameraZoom::setToggleState( BOOL top, BOOL bottom )
00784 {
00785 mInTop = top;
00786 mInBottom = bottom;
00787 }
00788
00789 void LLJoystickCameraZoom::draw()
00790 {
00791 if( getVisible() )
00792 {
00793 if( mInTop )
00794 {
00795 gl_draw_image( 0, 0, mPlusInImage );
00796 }
00797 else
00798 if( mInBottom )
00799 {
00800 gl_draw_image( 0, 0, mMinusInImage );
00801 }
00802 else
00803 {
00804 gl_draw_image( 0, 0, mImageUnselected );
00805 }
00806
00807 if (sDebugRects)
00808 {
00809 drawDebugRect();
00810 }
00811 }
00812 }
00813
00814 void LLJoystickCameraZoom::updateSlop()
00815 {
00816 mVertSlopNear = mRect.getHeight() / 4;
00817 mVertSlopFar = mRect.getHeight() / 2;
00818
00819 mHorizSlopNear = mRect.getWidth() / 4;
00820 mHorizSlopFar = mRect.getWidth() / 2;
00821
00822
00823
00824 switch (mInitialQuadrant)
00825 {
00826 case JQ_ORIGIN:
00827 mInitialOffset.set(0, 0);
00828 break;
00829
00830 case JQ_UP:
00831 mInitialOffset.mX = 0;
00832 mInitialOffset.mY = (mVertSlopNear + mVertSlopFar) / 2;
00833 break;
00834
00835 case JQ_DOWN:
00836 mInitialOffset.mX = 0;
00837 mInitialOffset.mY = - (mVertSlopNear + mVertSlopFar) / 2;
00838 break;
00839
00840 case JQ_LEFT:
00841 mInitialOffset.mX = - (mHorizSlopNear + mHorizSlopFar) / 2;
00842 mInitialOffset.mY = 0;
00843 break;
00844
00845 case JQ_RIGHT:
00846 mInitialOffset.mX = (mHorizSlopNear + mHorizSlopFar) / 2;
00847 mInitialOffset.mY = 0;
00848 break;
00849
00850 default:
00851 llerrs << "LLJoystick::LLJoystick() - bad switch case" << llendl;
00852 break;
00853 }
00854
00855 return;
00856 }
00857
00858
00859 F32 LLJoystickCameraZoom::getOrbitRate()
00860 {
00861 F32 time = getElapsedHeldDownTime();
00862 if( time < NUDGE_TIME )
00863 {
00864 F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME;
00865
00866 return rate;
00867 }
00868 else
00869 {
00870 return 1;
00871 }
00872 }