# qwt_scale_widget.cpp

    00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
    00002  * Qwt Widget Library
    00003  * Copyright (C) 1997   Josef Wilgen
    00004  * Copyright (C) 2002   Uwe Rathmann
    00005  *
    00006  * This library is free software; you can redistribute it and/or
    00007  * modify it under the terms of the Qwt License, Version 1.0
    00008  *****************************************************************************/
    00009
    00010 // vim: expandtab
    00011
    00012 #include <qpainter.h>
    00013 #include <qevent.h>
    00014 #include "qwt_painter.h"
    00015 #include "qwt_color_map.h"
    00016 #include "qwt_scale_widget.h"
    00017 #include "qwt_scale_map.h"
    00018 #include "qwt_math.h"
    00019 #include "qwt_paint_buffer.h"
    00020 #include "qwt_scale_div.h"
    00021 #include "qwt_text.h"
    00022
    00023 class QwtScaleWidget::PrivateData
    00024 {
    00025 public:
    00026     PrivateData():
    00027         scaleDraw(NULL)
    00028     {
    00029         colorBar.colorMap = NULL;
    00030         colorBar.width = 10;
    00031     }
    00032
    00033     ~PrivateData()
    00034     {
    00035         delete scaleDraw;
    00036         delete colorBar.colorMap;
    00037     }
    00038
    00039     QwtScaleDraw *scaleDraw;
    00040
    00041     int borderDist[2];
    00042     int minBorderDist[2];
    00043     int scaleLength;
    00044     int margin;
    00045     int penWidth;
    00046
    00047     int titleOffset;
    00048     int spacing;
    00049     QwtText title;
    00050
    00051     struct t_colorBar
    00052     {
    00053         bool isEnabled;
    00054         int width;
    00055         QwtDoubleInterval interval;
    00056         QwtColorMap *colorMap;
    00057     } colorBar;
    00058 };
    00059
    00064 QwtScaleWidget::QwtScaleWidget(QWidget *parent):
    00065     QWidget(parent)
    00066 {
    00067     initScale(QwtScaleDraw::LeftScale);
    00068 }
    00069
    00070 #if QT_VERSION < 0x040000
    00071
    00076 QwtScaleWidget::QwtScaleWidget(QWidget *parent, const char *name):
    00077     QWidget(parent, name)
    00078 {
    00079     initScale(QwtScaleDraw::LeftScale);
    00080 }
    00081 #endif
    00082
    00088 QwtScaleWidget::QwtScaleWidget(
    00089         QwtScaleDraw::Alignment align, QWidget *parent):
    00090     QWidget(parent)
    00091 {
    00092     initScale(align);
    00093 }
    00094
    00096 QwtScaleWidget::~QwtScaleWidget()
    00097 {
    00098     delete d_data;
    00099 }
    00100
    00102 void QwtScaleWidget::initScale(QwtScaleDraw::Alignment align)
    00103 {
    00104     d_data = new PrivateData;
    00105
    00106 #if QT_VERSION < 0x040000
    00107     setWFlags(Qt::WNoAutoErase);
    00108 #endif
    00109
    00110     d_data->borderDist[0] = 0;
    00111     d_data->borderDist[1] = 0;
    00112     d_data->minBorderDist[0] = 0;
    00113     d_data->minBorderDist[1] = 0;
    00114     d_data->margin = 4;
    00115     d_data->penWidth = 0;
    00116     d_data->titleOffset = 0;
    00117     d_data->spacing = 2;
    00118
    00119     d_data->scaleDraw = new QwtScaleDraw;
    00120     d_data->scaleDraw->setAlignment(align);
    00121     d_data->scaleDraw->setLength(10);
    00122
    00123     d_data->colorBar.colorMap = new QwtLinearColorMap();
    00124     d_data->colorBar.isEnabled = false;
    00125     d_data->colorBar.width = 10;
    00126
    00127     const int flags = Qt::AlignHCenter
    00128 #if QT_VERSION < 0x040000
    00129         | Qt::WordBreak | Qt::ExpandTabs;
    00130 #else
    00131         | Qt::TextExpandTabs | Qt::TextWordWrap;
    00132 #endif
    00133     d_data->title.setRenderFlags(flags);
    00134     d_data->title.setFont(font());
    00135
    00136     QSizePolicy policy(QSizePolicy::MinimumExpanding,
    00137         QSizePolicy::Fixed);
    00138     if ( d_data->scaleDraw->orientation() == Qt::Vertical )
    00139         policy.transpose();
    00140
    00141     setSizePolicy(policy);
    00142
    00143 #if QT_VERSION >= 0x040000
    00144     setAttribute(Qt::WA_WState_OwnSizePolicy, false);
    00145 #else
    00146     clearWState( WState_OwnSizePolicy );
    00147 #endif
    00148
    00149 }
    00150
    00151 void QwtScaleWidget::setTitle(const QString &title)
    00152 {
    00153     if ( d_data->title.text() != title )
    00154     {
    00155         d_data->title.setText(title);
    00156         layoutScale();
    00157     }
    00158 }
    00159
    00168 void QwtScaleWidget::setTitle(const QwtText &title)
    00169 {
    00170     QwtText t = title;
    00171     const int flags = title.renderFlags() & ~(Qt::AlignTop | Qt::AlignBottom);
    00172     t.setRenderFlags(flags);
    00173
    00174     if (t != d_data->title)
    00175     {
    00176         d_data->title = t;
    00177         layoutScale();
    00178     }
    00179 }
    00180
    00187 void QwtScaleWidget::setAlignment(QwtScaleDraw::Alignment alignment)
    00188 {
    00189 #if QT_VERSION >= 0x040000
    00190     if ( !testAttribute(Qt::WA_WState_OwnSizePolicy) )
    00191 #else
    00192     if ( !testWState( WState_OwnSizePolicy ) )
    00193 #endif
    00194     {
    00195         QSizePolicy policy(QSizePolicy::MinimumExpanding,
    00196             QSizePolicy::Fixed);
    00197         if ( d_data->scaleDraw->orientation() == Qt::Vertical )
    00198             policy.transpose();
    00199         setSizePolicy(policy);
    00200
    00201 #if QT_VERSION >= 0x040000
    00202         setAttribute(Qt::WA_WState_OwnSizePolicy, false);
    00203 #else
    00204         clearWState( WState_OwnSizePolicy );
    00205 #endif
    00206     }
    00207
    00208     if (d_data->scaleDraw)
    00209         d_data->scaleDraw->setAlignment(alignment);
    00210     layoutScale();
    00211 }
    00212
    00213
    00218 QwtScaleDraw::Alignment QwtScaleWidget::alignment() const
    00219 {
    00220     if (!scaleDraw())
    00221         return QwtScaleDraw::LeftScale;
    00222
    00223     return scaleDraw()->alignment();
    00224 }
    00225
    00234 void QwtScaleWidget::setBorderDist(int dist1, int dist2)
    00235 {
    00236     if ( dist1 != d_data->borderDist[0] || dist2 != d_data->borderDist[1] )
    00237     {
    00238         d_data->borderDist[0] = dist1;
    00239         d_data->borderDist[1] = dist2;
    00240         layoutScale();
    00241     }
    00242 }
    00243
    00249 void QwtScaleWidget::setMargin(int margin)
    00250 {
    00251     margin = qwtMax( 0, margin );
    00252     if ( margin != d_data->margin )
    00253     {
    00254         d_data->margin = margin;
    00255         layoutScale();
    00256     }
    00257 }
    00258
    00264 void QwtScaleWidget::setSpacing(int spacing)
    00265 {
    00266     spacing = qwtMax( 0, spacing );
    00267     if ( spacing != d_data->spacing )
    00268     {
    00269         d_data->spacing = spacing;
    00270         layoutScale();
    00271     }
    00272 }
    00273
    00279 void QwtScaleWidget::setPenWidth(int width)
    00280 {
    00281     if ( width < 0 )
    00282         width = 0;
    00283
    00284     if ( width != d_data->penWidth )
    00285     {
    00286         d_data->penWidth = width;
    00287         layoutScale();
    00288     }
    00289 }
    00290
    00296 #if QT_VERSION < 0x040000
    00297 void QwtScaleWidget::setLabelAlignment(int alignment)
    00298 #else
    00299 void QwtScaleWidget::setLabelAlignment(Qt::Alignment alignment)
    00300 #endif
    00301 {
    00302     d_data->scaleDraw->setLabelAlignment(alignment);
    00303     layoutScale();
    00304 }
    00305
    00311 void QwtScaleWidget::setLabelRotation(double rotation)
    00312 {
    00313     d_data->scaleDraw->setLabelRotation(rotation);
    00314     layoutScale();
    00315 }
    00316
    00322 void QwtScaleWidget::setScaleDraw(QwtScaleDraw *sd)
    00323 {
    00324     if ( sd == NULL || sd == d_data->scaleDraw )
    00325         return;
    00326
    00327     if ( d_data->scaleDraw )
    00328         sd->setAlignment(d_data->scaleDraw->alignment());
    00329
    00330     delete d_data->scaleDraw;
    00331     d_data->scaleDraw = sd;
    00332
    00333     layoutScale();
    00334 }
    00335
    00340 const QwtScaleDraw *QwtScaleWidget::scaleDraw() const
    00341 {
    00342     return d_data->scaleDraw;
    00343 }
    00344
    00349 QwtScaleDraw *QwtScaleWidget::scaleDraw()
    00350 {
    00351     return d_data->scaleDraw;
    00352 }
    00353
    00358 QwtText QwtScaleWidget::title() const
    00359 {
    00360     return d_data->title;
    00361 }
    00362
    00367 int QwtScaleWidget::startBorderDist() const
    00368 {
    00369     return d_data->borderDist[0];
    00370 }
    00371
    00376 int QwtScaleWidget::endBorderDist() const
    00377 {
    00378     return d_data->borderDist[1];
    00379 }
    00380
    00385 int QwtScaleWidget::margin() const
    00386 {
    00387     return d_data->margin;
    00388 }
    00389
    00394 int QwtScaleWidget::spacing() const
    00395 {
    00396     return d_data->spacing;
    00397 }
    00398
    00403 int QwtScaleWidget::penWidth() const
    00404 {
    00405     return d_data->penWidth;
    00406 }
    00410 void QwtScaleWidget::paintEvent(QPaintEvent *e)
    00411 {
    00412     const QRect &ur = e->rect();
    00413     if ( ur.isValid() )
    00414     {
    00415 #if QT_VERSION < 0x040000
    00416         QwtPaintBuffer paintBuffer(this, ur);
    00417         draw(paintBuffer.painter());
    00418 #else
    00419         QPainter painter(this);
    00420         draw(&painter);
    00421 #endif
    00422     }
    00423 }
    00424
    00428 void QwtScaleWidget::draw(QPainter *painter) const
    00429 {
    00430     painter->save();
    00431
    00432     QPen scalePen = painter->pen();
    00433     scalePen.setWidth(d_data->penWidth);
    00434     painter->setPen(scalePen);
    00435
    00436 #if QT_VERSION < 0x040000
    00437     d_data->scaleDraw->draw(painter, colorGroup());
    00438 #else
    00439     d_data->scaleDraw->draw(painter, palette());
    00440 #endif
    00441     painter->restore();
    00442
    00443     if ( d_data->colorBar.isEnabled && d_data->colorBar.width > 0 &&
    00444         d_data->colorBar.interval.isValid() )
    00445     {
    00446         drawColorBar(painter, colorBarRect(rect()));
    00447     }
    00448
    00449     QRect r = rect();
    00450     if ( d_data->scaleDraw->orientation() == Qt::Horizontal )
    00451     {
    00452         r.setLeft(r.left() + d_data->borderDist[0]);
    00453         r.setWidth(r.width() - d_data->borderDist[1]);
    00454     }
    00455     else
    00456     {
    00457         r.setTop(r.top() + d_data->borderDist[0]);
    00458         r.setHeight(r.height() - d_data->borderDist[1]);
    00459     }
    00460
    00461     if ( !d_data->title.isEmpty() )
    00462     {
    00463         QRect tr = r;
    00464         switch(d_data->scaleDraw->alignment())
    00465         {
    00466             case QwtScaleDraw::LeftScale:
    00467                 tr.setRight( r.right() - d_data->titleOffset );
    00468                 break;
    00469
    00470             case QwtScaleDraw::RightScale:
    00471                 tr.setLeft( r.left() + d_data->titleOffset );
    00472                 break;
    00473
    00474             case QwtScaleDraw::BottomScale:
    00475                 tr.setTop( r.top() + d_data->titleOffset );
    00476                 break;
    00477
    00478             case QwtScaleDraw::TopScale:
    00479             default:
    00480                 tr.setBottom( r.bottom() - d_data->titleOffset );
    00481                 break;
    00482         }
    00483
    00484         drawTitle(painter, d_data->scaleDraw->alignment(), tr);
    00485     }
    00486 }
    00487
    00488 QRect QwtScaleWidget::colorBarRect(const QRect& rect) const
    00489 {
    00490     QRect cr = rect;
    00491
    00492     if ( d_data->scaleDraw->orientation() == Qt::Horizontal )
    00493     {
    00494         cr.setLeft(cr.left() + d_data->borderDist[0]);
    00495         cr.setWidth(cr.width() - d_data->borderDist[1]);
    00496     }
    00497     else
    00498     {
    00499         cr.setTop(cr.top() + d_data->borderDist[0]);
    00500         cr.setHeight(cr.height() - d_data->borderDist[1]);
    00501     }
    00502
    00503     switch(d_data->scaleDraw->alignment())
    00504     {
    00505         case QwtScaleDraw::LeftScale:
    00506         {
    00507             cr.setLeft( cr.right() - d_data->spacing
    00508                 - d_data->colorBar.width + 1 );
    00509             cr.setWidth(d_data->colorBar.width);
    00510             break;
    00511         }
    00512
    00513         case QwtScaleDraw::RightScale:
    00514         {
    00515             cr.setLeft( cr.left() + d_data->spacing );
    00516             cr.setWidth(d_data->colorBar.width);
    00517             break;
    00518         }
    00519
    00520         case QwtScaleDraw::BottomScale:
    00521         {
    00522             cr.setTop( cr.top() + d_data->spacing );
    00523             cr.setHeight(d_data->colorBar.width);
    00524             break;
    00525         }
    00526
    00527         case QwtScaleDraw::TopScale:
    00528         {
    00529             cr.setTop( cr.bottom() - d_data->spacing
    00530                 - d_data->colorBar.width + 1 );
    00531             cr.setHeight(d_data->colorBar.width);
    00532             break;
    00533         }
    00534     }
    00535
    00536     return cr;
    00537 }
    00538
    00542 void QwtScaleWidget::resizeEvent(QResizeEvent *)
    00543 {
    00544     layoutScale(false);
    00545 }
    00546
    00548 //  the current rect and fonts.
    00549 //  \param update_geometry   notify the layout system and call update
    00550 //         to redraw the scale
    00551
    00552 void QwtScaleWidget::layoutScale( bool update_geometry )
    00553 {
    00554     int bd0, bd1;
    00555     getBorderDistHint(bd0, bd1);
    00556     if ( d_data->borderDist[0] > bd0 )
    00557         bd0 = d_data->borderDist[0];
    00558     if ( d_data->borderDist[1] > bd1 )
    00559         bd1 = d_data->borderDist[1];
    00560
    00561     int colorBarWidth = 0;
    00562     if ( d_data->colorBar.isEnabled && d_data->colorBar.interval.isValid() )
    00563         colorBarWidth = d_data->colorBar.width + d_data->spacing;
    00564
    00565     const QRect r = rect();
    00566     int x, y, length;
    00567
    00568     if ( d_data->scaleDraw->orientation() == Qt::Vertical )
    00569     {
    00570         y = r.top() + bd0;
    00571         length = r.height() - (bd0 + bd1);
    00572
    00573         if ( d_data->scaleDraw->alignment() == QwtScaleDraw::LeftScale )
    00574             x = r.right() - d_data->margin - colorBarWidth;
    00575         else
    00576             x = r.left() + d_data->margin + colorBarWidth;
    00577     }
    00578     else
    00579     {
    00580         x = r.left() + bd0;
    00581         length = r.width() - (bd0 + bd1);
    00582
    00583         if ( d_data->scaleDraw->alignment() == QwtScaleDraw::BottomScale )
    00584             y = r.top() + d_data->margin + colorBarWidth;
    00585         else
    00586             y = r.bottom() - d_data->margin - colorBarWidth;
    00587     }
    00588
    00589     d_data->scaleDraw->move(x, y);
    00590     d_data->scaleDraw->setLength(length);
    00591
    00592     d_data->titleOffset = d_data->margin + d_data->spacing +
    00593         colorBarWidth +
    00594         d_data->scaleDraw->extent(QPen(Qt::black, d_data->penWidth), font());
    00595
    00596     if ( update_geometry )
    00597     {
    00598       updateGeometry();
    00599       update();
    00600     }
    00601 }
    00602
    00603 void QwtScaleWidget::drawColorBar(QPainter *painter, const QRect& rect) const
    00604 {
    00605     if ( !d_data->colorBar.interval.isValid() )
    00606         return;
    00607
    00608     const QwtScaleDraw* sd = d_data->scaleDraw;
    00609
    00610     QwtPainter::drawColorBar(painter, *d_data->colorBar.colorMap,
    00611         d_data->colorBar.interval.normalized(), sd->map(),
    00612         sd->orientation(), rect);
    00613 }
    00614
    00622 void QwtScaleWidget::drawTitle(QPainter *painter,
    00623     QwtScaleDraw::Alignment align, const QRect &rect) const
    00624 {
    00625     QRect r;
    00626     double angle;
    00627     int flags = d_data->title.renderFlags() &
    00628         ~(Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter);
    00629
    00630     switch(align)
    00631     {
    00632         case QwtScaleDraw::LeftScale:
    00633             flags |= Qt::AlignTop;
    00634             angle = -90.0;
    00635             r.setRect(rect.left(), rect.bottom(), rect.height(), rect.width());
    00636             break;
    00637         case QwtScaleDraw::RightScale:
    00638             flags |= Qt::AlignTop;
    00639             angle = 90.0;
    00640             r.setRect(rect.right(), rect.top(), rect.height(), rect.width());
    00641             break;
    00642         case QwtScaleDraw::TopScale:
    00643             flags |= Qt::AlignTop;
    00644             angle = 0.0;
    00645             r = rect;
    00646             break;
    00647         case QwtScaleDraw::BottomScale:
    00648         default:
    00649             flags |= Qt::AlignBottom;
    00650             angle = 0.0;
    00651             r = rect;
    00652             break;
    00653     }
    00654
    00655     painter->save();
    00656     painter->setFont(font());
    00657 #if QT_VERSION < 0x040000
    00658     painter->setPen(colorGroup().color(QColorGroup::Text));
    00659 #else
    00660     painter->setPen(palette().color(QPalette::Text));
    00661 #endif
    00662
    00663     painter->translate(r.x(), r.y());
    00664     if (angle != 0.0)
    00665         painter->rotate(angle);
    00666
    00667     QwtText title = d_data->title;
    00668     title.setRenderFlags(flags);
    00669     title.draw(painter, QRect(0, 0, r.width(), r.height()));
    00670
    00671     painter->restore();
    00672 }
    00673
    00682 void QwtScaleWidget::scaleChange()
    00683 {
    00684     layoutScale();
    00685 }
    00686
    00690 QSize QwtScaleWidget::sizeHint() const
    00691 {
    00692     return minimumSizeHint();
    00693 }
    00694
    00698 QSize QwtScaleWidget::minimumSizeHint() const
    00699 {
    00700     const Qt::Orientation o = d_data->scaleDraw->orientation();
    00701
    00702     // Border Distance cannot be less than the scale borderDistHint
    00703     // Note, the borderDistHint is already included in minHeight/minWidth
    00704     int length = 0;
    00705     int mbd1, mbd2;
    00706     getBorderDistHint(mbd1, mbd2);
    00707     length += qwtMax( 0, d_data->borderDist[0] - mbd1 );
    00708     length += qwtMax( 0, d_data->borderDist[1] - mbd2 );
    00709     length += d_data->scaleDraw->minLength(
    00710         QPen(Qt::black, d_data->penWidth), font());
    00711
    00712     int dim = dimForLength(length, font());
    00713     if ( length < dim )
    00714     {
    00715         // compensate for long titles
    00716         length = dim;
    00717         dim = dimForLength(length, font());
    00718     }
    00719
    00720     QSize size(length + 2, dim);
    00721     if ( o == Qt::Vertical )
    00722         size.transpose();
    00723
    00724     return size;
    00725 }
    00726
    00733 int QwtScaleWidget::titleHeightForWidth(int width) const
    00734 {
    00735     return d_data->title.heightForWidth(width, font());
    00736 }
    00737
    00747 int QwtScaleWidget::dimForLength(int length, const QFont &scaleFont) const
    00748 {
    00749     int dim = d_data->margin;
    00750     dim += d_data->scaleDraw->extent(
    00751         QPen(Qt::black, d_data->penWidth), scaleFont);
    00752
    00753     if ( !d_data->title.isEmpty() )
    00754         dim += titleHeightForWidth(length) + d_data->spacing;
    00755
    00756     if ( d_data->colorBar.isEnabled && d_data->colorBar.interval.isValid() )
    00757         dim += d_data->colorBar.width + d_data->spacing;
    00758
    00759     return dim;
    00760 }
    00761
    00775 void QwtScaleWidget::getBorderDistHint(int &start, int &end) const
    00776 {
    00777     d_data->scaleDraw->getBorderDistHint(font(), start, end);
    00778
    00779     if ( start < d_data->minBorderDist[0] )
    00780         start = d_data->minBorderDist[0];
    00781
    00782     if ( end < d_data->minBorderDist[1] )
    00783         end = d_data->minBorderDist[1];
    00784 }
    00785
    00794 void QwtScaleWidget::setMinBorderDist(int start, int end)
    00795 {
    00796     d_data->minBorderDist[0] = start;
    00797     d_data->minBorderDist[1] = end;
    00798 }
    00799
    00806 void QwtScaleWidget::getMinBorderDist(int &start, int &end) const
    00807 {
    00808     start = d_data->minBorderDist[0];
    00809     end = d_data->minBorderDist[1];
    00810 }
    00811
    00812 #if QT_VERSION < 0x040000
    00813
    00822 void QwtScaleWidget::fontChange(const QFont &oldFont)
    00823 {
    00824     QWidget::fontChange( oldFont );
    00825     layoutScale();
    00826 }
    00827
    00828 #endif
    00829
    00840 void QwtScaleWidget::setScaleDiv(
    00841     QwtScaleTransformation *transformation,
    00842     const QwtScaleDiv &scaleDiv)
    00843 {
    00844     QwtScaleDraw *sd = d_data->scaleDraw;
    00845     if (sd->scaleDiv() != scaleDiv ||
    00846         sd->map().transformation()->type() != transformation->type() )
    00847     {
    00848         sd->setTransformation(transformation);
    00849         sd->setScaleDiv(scaleDiv);
    00850         layoutScale();
    00851
    00852         emit scaleDivChanged();
    00853     }
    00854     else
    00855         delete transformation;
    00856 }
    00857
    00858 void QwtScaleWidget::setColorBarEnabled(bool on)
    00859 {
    00860     if ( on != d_data->colorBar.isEnabled )
    00861     {
    00862         d_data->colorBar.isEnabled = on;
    00863         layoutScale();
    00864     }
    00865 }
    00866
    00867 bool QwtScaleWidget::isColorBarEnabled() const
    00868 {
    00869     return d_data->colorBar.isEnabled;
    00870 }
    00871
    00872
    00873 void QwtScaleWidget::setColorBarWidth(int width)
    00874 {
    00875     if ( width != d_data->colorBar.width )
    00876     {
    00877         d_data->colorBar.width = width;
    00878         if ( isColorBarEnabled() )
    00879             layoutScale();
    00880     }
    00881 }
    00882
    00883 int QwtScaleWidget::colorBarWidth() const
    00884 {
    00885     return d_data->colorBar.width;
    00886 }
    00887
    00888 QwtDoubleInterval QwtScaleWidget::colorBarInterval() const
    00889 {
    00890     return d_data->colorBar.interval;
    00891 }
    00892
    00893 void QwtScaleWidget::setColorMap(const QwtDoubleInterval &interval,
    00894     const QwtColorMap &colorMap)
    00895 {
    00896     d_data->colorBar.interval = interval;
    00897
    00898     delete d_data->colorBar.colorMap;
    00899     d_data->colorBar.colorMap = colorMap.copy();
    00900
    00901     if ( isColorBarEnabled() )
    00902         layoutScale();
    00903 }
    00904
    00905 const QwtColorMap &QwtScaleWidget::colorMap() const
    00906 {
    00907     return *d_data->colorBar.colorMap;
    00908 }